Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions cuda_core/build_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,31 @@
build_sdist = _build_meta.build_sdist
get_requires_for_build_sdist = _build_meta.get_requires_for_build_sdist

COMPILE_FOR_COVERAGE = bool(int(os.environ.get("CUDA_PYTHON_COVERAGE", "0")))

def env_int(name: str, default: int) -> int:
"""Read an integer build knob from the environment.

Unset and empty mean the same thing. ``CUDA_PYTHON_COVERAGE= pip install .``
(and the equivalent empty value in a Dockerfile ``ENV`` or a CI job spec) is
how a variable gets neutralised, and it must not abort the build -- a bare
``int()`` here raises while the PEP 517 backend module is still being
imported, so the failure arrives before any build output.

A value that is set to something non-integer is a typo worth stopping for:
silently ignoring ``CUDA_PYTHON_COVERAGE=yes`` would hand back a build with
no coverage instrumentation. It is reported with the variable's name rather
than as an anonymous ``invalid literal for int()``.
"""
raw = os.environ.get(name, "").strip()
if not raw:
return default
try:
return int(raw)
except ValueError:
raise ValueError(f"environment variable {name}={os.environ[name]!r} must be an integer") from None


COMPILE_FOR_COVERAGE = bool(env_int("CUDA_PYTHON_COVERAGE", 0))


# Please keep in sync with the copy in cuda_bindings/build_hooks.py.
Expand Down Expand Up @@ -219,7 +243,9 @@ def get_sources(mod_name):
for mod in module_names()
)

nthreads = int(os.environ.get("CUDA_PYTHON_PARALLEL_LEVEL", os.cpu_count() // 2))
# ``os.cpu_count()`` is documented to return None when it cannot be
# determined; fall back to a serial build rather than a TypeError.
nthreads = env_int("CUDA_PYTHON_PARALLEL_LEVEL", (os.cpu_count() or 1) // 2)
compile_time_env = {"CUDA_CORE_BUILD_MAJOR": int(_determine_cuda_major_version())}
compiler_directives = {"embedsignature": True, "warn.deprecated.IF": False, "freethreading_compatible": True}
_CythonOptions.warning_errors = True
Expand Down
6 changes: 4 additions & 2 deletions cuda_core/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
from setuptools.command.build_ext import build_ext as _build_ext
from setuptools.command.build_py import build_py as _build_py

nthreads = int(os.environ.get("CUDA_PYTHON_PARALLEL_LEVEL", os.cpu_count() // 2))
coverage_mode = bool(int(os.environ.get("CUDA_PYTHON_COVERAGE", "0")))
# Shared with build_hooks so the two build entry points parse these knobs
# identically (see build_hooks.env_int for why a bare int() is not enough).
nthreads = build_hooks.env_int("CUDA_PYTHON_PARALLEL_LEVEL", (os.cpu_count() or 1) // 2)
coverage_mode = bool(build_hooks.env_int("CUDA_PYTHON_COVERAGE", 0))
_ROOT_DIR = Path(__file__).resolve().parent
_AOTI_SHIM_DEF_FILE = _ROOT_DIR / "cuda" / "core" / "_include" / "aoti_shim.def"
_AOTI_SHIM_LIB_FILE = _ROOT_DIR / "build" / "aoti_shim.lib"
Expand Down
46 changes: 46 additions & 0 deletions cuda_core/tests/test_build_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,49 @@ def test_missing_cuda_path_raises_error(self):
pytest.raises(RuntimeError, match="CUDA_PATH or CUDA_HOME"),
):
build_hooks._determine_cuda_major_version()


class TestEnvInt:
"""Integer build knobs read from the environment."""

@pytest.mark.agent_authored(model="claude-opus-5")
@pytest.mark.parametrize(
("value", "expected"),
[
pytest.param(None, 7, id="unset"),
# `VAR= pip install .` is how a shell neutralizes a variable, and
# the same shape appears in Dockerfile ENV and CI job specs.
pytest.param("", 7, id="empty"),
pytest.param(" ", 7, id="whitespace-only"),
pytest.param("0", 0, id="zero"),
pytest.param("4", 4, id="positive"),
pytest.param(" 4 ", 4, id="padded"),
],
)
def test_env_int_reads_the_value_or_falls_back(self, value, expected):
env = {} if value is None else {"CUDA_PYTHON_TEST_KNOB": value}
with mock.patch.dict(os.environ, env, clear=True):
assert build_hooks.env_int("CUDA_PYTHON_TEST_KNOB", 7) == expected

@pytest.mark.agent_authored(model="claude-opus-5")
def test_env_int_names_the_variable_for_a_non_integer(self):
with (
mock.patch.dict(os.environ, {"CUDA_PYTHON_TEST_KNOB": "yes"}, clear=True),
pytest.raises(ValueError, match=r"CUDA_PYTHON_TEST_KNOB='yes' must be an integer"),
):
build_hooks.env_int("CUDA_PYTHON_TEST_KNOB", 7)

@pytest.mark.agent_authored(model="claude-opus-5")
@pytest.mark.parametrize("value", ["", " "], ids=["empty", "whitespace-only"])
def test_backend_imports_with_an_empty_coverage_flag(self, value):
"""An empty CUDA_PYTHON_COVERAGE must not break the PEP 517 backend.

COMPILE_FOR_COVERAGE is evaluated at module scope, so a bare int() there
raised while the build backend was still being imported -- pip reported
`ValueError: invalid literal for int() with base 10: ''` before any
build output appeared.
"""
with mock.patch.dict(os.environ, {"CUDA_PYTHON_COVERAGE": value}, clear=True):
reloaded = _load_build_hooks()

assert reloaded.COMPILE_FOR_COVERAGE is False
Loading