Skip to content
Merged
97 changes: 61 additions & 36 deletions scripts/_build_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,11 @@
import sys


def run(cmd, env=None, cwd=None):
print("+", " ".join(cmd))
subprocess.check_call(
cmd, env=env or os.environ.copy(), cwd=cwd or os.getcwd()
)


def warn(msg: str):
print(f"[build_locally][error] {msg}", file=sys.stderr)


def err(msg: str):
print(f"[build_locally][error] {msg}", file=sys.stderr)


def resolve_compilers(
oneapi: bool, c_compiler: str, cxx_compiler: str, compiler_root: str
oneapi: bool,
c_compiler: str,
cxx_compiler: str,
compiler_root: str,
):
is_linux = "linux" in sys.platform

Expand All @@ -45,10 +33,14 @@ def resolve_compilers(
):
return "icx", ("icpx" if is_linux else "icx")

if not compiler_root or not os.path.exists(compiler_root):
if (
(c_compiler is None or not os.path.isabs(c_compiler))
and (cxx_compiler is None or not os.path.isabs(cxx_compiler))
and (not compiler_root or not os.path.exists(compiler_root))
):
raise RuntimeError(
"--compiler-root option must be set when using non-default DPC++ "
"layout"
"layout unless absolute paths are provided for both compilers"
)

# default values
Expand All @@ -61,34 +53,54 @@ def resolve_compilers(
(c_compiler, "--c-compiler"),
(cxx_compiler, "--cxx-compiler"),
):
path = (
name if os.path.exists(name) else os.path.join(compiler_root, name)
)
if os.path.isabs(name):
path = name
else:
path = os.path.join(compiler_root, name)
if not os.path.exists(path):
raise RuntimeError(f"{opt_name} value {name} not found")
return c_compiler, cxx_compiler


def run(cmd: list[str], env: dict[str, str] = None, cwd: str = None):
print("+", " ".join(cmd))
subprocess.check_call(
cmd, env=env or os.environ.copy(), cwd=cwd or os.getcwd()
)


def get_output(cmd: list[str], cwd: str = None):
print("+", " ".join(cmd))
return (
subprocess.check_output(cmd, cwd=cwd or os.getcwd())
.decode("utf-8")
.strip("\n")
)


def warn(msg: str, script: str):
print(f"[{script}][warning] {msg}", file=sys.stderr)


def err(msg: str, script: str):
print(f"[{script}][error] {msg}", file=sys.stderr)


def make_cmake_args(
build_type="Release",
c_compiler=None,
cxx_compiler=None,
level_zero=True,
glog=False,
generator=None,
verbose=False,
other_opts="",
c_compiler: str = None,
cxx_compiler: str = None,
level_zero: bool = True,
glog: bool = False,
verbose: bool = False,
other_opts: str = None,
):
args = [
f"-DCMAKE_BUILD_TYPE={build_type}",
f"-DCMAKE_C_COMPILER:PATH={c_compiler}" if c_compiler else "",
f"-DCMAKE_CXX_COMPILER:PATH={cxx_compiler}" if cxx_compiler else "",
f"-DDPCTL_ENABLE_L0_PROGRAM_CREATION={'ON' if level_zero else 'OFF'}",
f"-DDPTL_ENABLE_GLOG:BOOL={'ON' if glog else 'OFF'}",
]

if generator:
args.append(f"-G{generator}")
if verbose:
args.append("-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON")
if other_opts:
Expand All @@ -97,15 +109,28 @@ def make_cmake_args(
return " ".join(filter(None, args))


def build_extension(setup_dir, env):
def build_extension(
setup_dir: str,
env: dict[str, str],
cmake_executable: str = None,
generator: str = None,
build_type: str = None,
):
cmd = [sys.executable, "setup.py", "build_ext", "--inplace"]
if cmake_executable:
cmd.append(f"--cmake-executable={cmake_executable}")
if generator:
cmd.append(f"--generator={generator}")
if build_type:
cmd.append(f"--build-type={build_type}")
run(
[sys.executable, "setup.py", "build_ext", "--inplace"],
cmd,
env=env,
cwd=setup_dir,
)


def install_editable(setup_dir, env):
def install_editable(setup_dir: str, env: dict[str, str]):
run(
[
sys.executable,
Expand All @@ -121,7 +146,7 @@ def install_editable(setup_dir, env):
)


def clean_build_dir(setup_dir):
def clean_build_dir(setup_dir: str = None):
target = os.path.join(setup_dir or os.getcwd(), "_skbuild")
if os.path.exists(target):
print(f"Cleaning build directory: {target}")
Expand Down
23 changes: 15 additions & 8 deletions scripts/build_locally.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def parse_args():
p.add_argument(
"--clean",
action="store_true",
help="Remove build dir before rebuild (default: False)",
help="Remove build dir before rebuild",
)
p.add_argument(
"--skip-editable",
Expand All @@ -137,7 +137,7 @@ def parse_args():

def main():
if sys.platform not in ["cygwin", "win32", "linux"]:
err(f"{sys.platform} not supported")
err(f"{sys.platform} not supported", "build_locally")
args = parse_args()
setup_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

Expand All @@ -150,7 +150,10 @@ def main():
clean_build_dir(setup_dir)

if args.no_level_zero and args.target_level_zero:
err("Cannot combine --no-level-zero and --target-level-zero")
err(
"Cannot combine --no-level-zero and --target-level-zero",
"build_locally",
)

# Level Zero state (on unless explicitly disabled)
if args.no_level_zero:
Expand All @@ -161,19 +164,17 @@ def main():
level_zero_enabled = True

cmake_args = make_cmake_args(
build_type=args.build_type,
c_compiler=c_compiler,
cxx_compiler=cxx_compiler,
level_zero=level_zero_enabled,
glog=args.glog,
generator=args.generator,
verbose=args.verbose,
other_opts=args.cmake_opts,
)

# handle architecture conflicts
if args.target_hip is not None and not args.target_hip.strip():
err("--target-hip requires an explicit architecture")
err("--target-hip requires an explicit architecture", "build_locally")

# CUDA/HIP targets
if args.target_cuda:
Expand All @@ -190,15 +191,21 @@ def main():

# ignore pre-existing CMAKE_ARGS for determinism in build driver
if "CMAKE_ARGS" in env and env["CMAKE_ARGS"].strip():
warn("Ignoring pre-existing CMAKE_ARGS in environment")
warn("Ignoring pre-existing CMAKE_ARGS in environment", "build_locally")
del env["CMAKE_ARGS"]

env["CMAKE_ARGS"] = cmake_args
print(f"[build_locally] CMake args:\n {cmake_args}")

print("[build_locally] Building extensions in-place...")

build_extension(setup_dir, env)
build_extension(
setup_dir,
env,
cmake_executable=args.cmake_executable,
generator=args.generator,
build_type=args.build_type,
)
if not args.skip_editable:
install_editable(setup_dir, env)
else:
Expand Down
Loading
Loading