Skip to content

Commit adebd02

Browse files
committed
build: remove _last_toolchain/_last_build_config globals; record_* re-derives from env
1 parent 7f2218f commit adebd02

5 files changed

Lines changed: 36 additions & 54 deletions

File tree

‎cuda_bindings/build_hooks.py‎

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,6 @@ def _resolve_toolchain(debug=False, compile_for_coverage=False):
213213
_BUILD_TOOLCHAIN_STAMP = _BUILD_DIR / ".build-toolchain"
214214

215215
force_build_ext = False
216-
# Set by _check_build_toolchain; read by record_build_toolchain.
217-
_last_toolchain = None
218216

219217

220218
def _check_build_toolchain(toolchain):
@@ -223,9 +221,8 @@ def _check_build_toolchain(toolchain):
223221
Setuptools' freshness check does not include the extension flags, so a
224222
stale .so compiled by a previous toolchain would otherwise be packaged.
225223
"""
226-
global force_build_ext, _last_toolchain
224+
global force_build_ext
227225

228-
_last_toolchain = toolchain
229226
try:
230227
previous = _BUILD_TOOLCHAIN_STAMP.read_text(encoding="utf-8").strip()
231228
except FileNotFoundError:
@@ -242,13 +239,12 @@ def record_build_toolchain() -> None:
242239
"""Stamp the toolchain of the build that just completed.
243240
244241
setup.py calls this after build_ext succeeds, so that a build which failed
245-
partway through does not claim outputs it never produced.
242+
partway through does not claim outputs it never produced. Re-derives the
243+
toolchain name from the environment rather than caching it in a global.
246244
"""
247-
global _last_toolchain
248-
if _last_toolchain is None:
249-
return # build never reached _check_build_toolchain (e.g. metadata-only)
245+
name, *_ = _resolve_toolchain_name()
250246
_BUILD_TOOLCHAIN_STAMP.parent.mkdir(parents=True, exist_ok=True)
251-
_BUILD_TOOLCHAIN_STAMP.write_text(_last_toolchain + "\n", encoding="utf-8")
247+
_BUILD_TOOLCHAIN_STAMP.write_text(name + "\n", encoding="utf-8")
252248

253249

254250
# -----------------------------------------------------------------------

‎cuda_bindings/tests/test_build_hooks.py‎

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ def stamp(tmp_path, monkeypatch):
160160
scratch = tmp_path / "build" / ".build-toolchain"
161161
monkeypatch.setattr(build_hooks, "_BUILD_TOOLCHAIN_STAMP", scratch)
162162
monkeypatch.setattr(build_hooks, "force_build_ext", False)
163-
monkeypatch.setattr(build_hooks, "_last_toolchain", None)
164163
monkeypatch.delenv("CUDA_PYTHON_TOOLCHAIN", raising=False)
165164
return scratch
166165

@@ -175,7 +174,7 @@ class TestBuildToolchainStamp:
175174

176175
@pytest.mark.agent_authored(model="glm-5.2")
177176
def test_missing_stamp_forces_rebuild(self, stamp):
178-
assert build_hooks._check_build_toolchain("gnu") is None
177+
build_hooks._check_build_toolchain("gnu")
179178
assert build_hooks.force_build_ext is True
180179

181180
@pytest.mark.agent_authored(model="glm-5.2")
@@ -192,12 +191,6 @@ def test_changed_toolchain_forces_rebuild(self, stamp):
192191

193192
@pytest.mark.agent_authored(model="glm-5.2")
194193
def test_record_writes_stamp(self, stamp):
195-
build_hooks._check_build_toolchain("gnu")
194+
# record_build_toolchain re-derives from env (CUDA_PYTHON_TOOLCHAIN unset → gnu).
196195
build_hooks.record_build_toolchain()
197196
assert stamp.read_text().strip() == "gnu"
198-
199-
@pytest.mark.agent_authored(model="glm-5.2")
200-
def test_record_without_check_is_noop(self, stamp, monkeypatch):
201-
monkeypatch.setattr(build_hooks, "_last_toolchain", None)
202-
build_hooks.record_build_toolchain()
203-
assert not stamp.exists()

‎cuda_core/build_hooks.py‎

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -256,10 +256,6 @@ def _determine_cuda_major_version() -> str:
256256
_BUILD_CONFIG_STAMP = _BUILD_DIR / ".build-config"
257257

258258
force_build_ext = False
259-
# Set by _check_build_config; read by record_build_config and _build_cuda_core
260-
# (for the cythonize build_dir). Cleared on module import so a fresh process
261-
# always re-derives it from the environment.
262-
_last_build_config = None
263259

264260

265261
def _build_config_key(cuda_major, toolchain, debug, coverage):
@@ -268,7 +264,7 @@ def _build_config_key(cuda_major, toolchain, debug, coverage):
268264

269265

270266
def _check_build_config(toolchain, debug, coverage):
271-
"""Return the CUDA major, and force a rebuild when the config changed.
267+
"""Return (cuda_major, config_key), and force a rebuild when the config changed.
272268
273269
Cython's up-to-date check does not hash ``compile_time_env`` or the
274270
extension flags, so generated sources and compiled extensions from a
@@ -279,11 +275,10 @@ def _check_build_config(toolchain, debug, coverage):
279275
major, toolchain, debug/coverage) is therefore stamped and build_ext
280276
forced whenever it changes, so a stale .so is never packaged.
281277
"""
282-
global force_build_ext, _last_build_config
278+
global force_build_ext
283279

284280
cuda_major = _determine_cuda_major_version()
285281
key = _build_config_key(cuda_major, toolchain, debug, coverage)
286-
_last_build_config = key
287282
try:
288283
previous = _BUILD_CONFIG_STAMP.read_text(encoding="utf-8").strip()
289284
except FileNotFoundError:
@@ -295,20 +290,23 @@ def _check_build_config(toolchain, debug, coverage):
295290
print(f"Build config of last build: {previous} (building {key}); forcing a full rebuild")
296291
force_build_ext = True
297292

298-
return cuda_major
293+
return cuda_major, key
299294

300295

301-
def record_build_config() -> None:
296+
def record_build_config(debug) -> None:
302297
"""Stamp the build configuration of the build that just completed.
303298
304-
setup.py calls this after build_ext succeeds, so that a build which
305-
failed partway through does not claim outputs it never produced.
299+
setup.py calls this (passing self.debug) after build_ext succeeds, so
300+
that a build which failed partway through does not claim outputs it never
301+
produced. All other inputs (toolchain, cuda_major, coverage) are
302+
re-derived from the environment and the functools.cache.
306303
"""
307-
global _last_build_config
308-
if _last_build_config is None:
309-
return # build never reached _check_build_config (e.g. metadata-only)
304+
toolchain, *_ = _resolve_toolchain_name()
305+
cuda_major = _determine_cuda_major_version()
306+
coverage = bool(int(os.environ.get("CUDA_PYTHON_COVERAGE", "0")))
307+
key = _build_config_key(cuda_major, toolchain, debug, coverage)
310308
_BUILD_CONFIG_STAMP.parent.mkdir(parents=True, exist_ok=True)
311-
_BUILD_CONFIG_STAMP.write_text(_last_build_config + "\n", encoding="utf-8")
309+
_BUILD_CONFIG_STAMP.write_text(key + "\n", encoding="utf-8")
312310

313311

314312
def _relativize_extension_sources(extensions) -> None:
@@ -437,7 +435,7 @@ def module_names():
437435
# Deliberately after the cuda.bindings import above: this re-enters
438436
# _get_cuda_path() and reads cuda.h, which must not run before the
439437
# pathfinder import has repaired PEP 517 namespace shadowing.
440-
cuda_major = _check_build_config(toolchain, debug, COMPILE_FOR_COVERAGE)
438+
cuda_major, config_key = _check_build_config(toolchain, debug, COMPILE_FOR_COVERAGE)
441439

442440
nthreads = int(os.environ.get("CUDA_PYTHON_PARALLEL_LEVEL", os.cpu_count() // 2))
443441
compile_time_env = {"CUDA_CORE_BUILD_MAJOR": int(cuda_major)}
@@ -456,7 +454,7 @@ def module_names():
456454
# this directory and compiles against the copies. Copies are refreshed by
457455
# mtime and never deleted, so remove build/ after renaming or deleting a
458456
# header under _cpp/.
459-
build_dir="." if COMPILE_FOR_COVERAGE else str(_BUILD_DIR / "cython" / _last_build_config),
457+
build_dir="." if COMPILE_FOR_COVERAGE else str(_BUILD_DIR / "cython" / config_key),
460458
nthreads=nthreads,
461459
compiler_directives=compiler_directives,
462460
compile_time_env=compile_time_env,

‎cuda_core/setup.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ def build_extensions(self):
137137
self._configure_windows_tensor_bridge()
138138
with self._parallel_source_compilation():
139139
super().build_extensions()
140-
build_hooks.record_build_config()
140+
build_hooks.record_build_config(self.debug)
141141

142142

143143
class build_py(_build_py): # noqa: N801

‎cuda_core/tests/test_build_hooks.py‎

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,12 @@ def stamp(tmp_path, monkeypatch):
183183
scratch = tmp_path / "build" / ".build-config"
184184
monkeypatch.setattr(build_hooks, "_BUILD_CONFIG_STAMP", scratch)
185185
monkeypatch.setattr(build_hooks, "force_build_ext", False)
186-
monkeypatch.setattr(build_hooks, "_last_build_config", None)
187186
build_hooks._get_cuda_path.cache_clear()
188187
build_hooks._determine_cuda_major_version.cache_clear()
189188
get_cuda_path_or_home.cache_clear()
190189
monkeypatch.setenv("CUDA_CORE_BUILD_MAJOR", "13")
191190
monkeypatch.delenv("CUDA_PYTHON_TOOLCHAIN", raising=False)
191+
monkeypatch.delenv("CUDA_PYTHON_COVERAGE", raising=False)
192192
return scratch
193193

194194

@@ -203,54 +203,49 @@ class TestBuildConfigStamp:
203203
@pytest.mark.agent_authored(model="glm-5.2")
204204
def test_missing_stamp_forces_rebuild(self, stamp):
205205
# No stamp means the last build's config is unknown, so rebuild.
206-
assert build_hooks._check_build_config("gnu", False, False) == "13"
206+
cuda_major, key = build_hooks._check_build_config("gnu", False, False)
207+
assert cuda_major == "13"
208+
assert key == "cu13-gnu-opt"
207209
assert build_hooks.force_build_ext is True
208210

209211
@pytest.mark.agent_authored(model="glm-5.2")
210212
def test_same_config_does_not_force(self, stamp):
211213
_write_stamp(stamp, "cu13-gnu-opt")
212-
assert build_hooks._check_build_config("gnu", False, False) == "13"
214+
cuda_major, key = build_hooks._check_build_config("gnu", False, False)
215+
assert cuda_major == "13"
213216
assert build_hooks.force_build_ext is False
214217

215218
@pytest.mark.agent_authored(model="glm-5.2")
216219
def test_changed_cuda_major_forces_rebuild(self, stamp):
217220
_write_stamp(stamp, "cu12-gnu-opt")
218-
assert build_hooks._check_build_config("gnu", False, False) == "13"
221+
cuda_major, _ = build_hooks._check_build_config("gnu", False, False)
222+
assert cuda_major == "13"
219223
assert build_hooks.force_build_ext is True
220224

221225
@pytest.mark.agent_authored(model="glm-5.2")
222226
def test_changed_toolchain_forces_rebuild(self, stamp):
223227
_write_stamp(stamp, "cu13-gnu-opt")
224-
assert build_hooks._check_build_config("llvm", False, False) == "13"
228+
build_hooks._check_build_config("llvm", False, False)
225229
assert build_hooks.force_build_ext is True
226230

227231
@pytest.mark.agent_authored(model="glm-5.2")
228232
def test_changed_debug_forces_rebuild(self, stamp):
229233
_write_stamp(stamp, "cu13-gnu-opt")
230-
assert build_hooks._check_build_config("gnu", True, False) == "13"
234+
build_hooks._check_build_config("gnu", True, False)
231235
assert build_hooks.force_build_ext is True
232236

233237
@pytest.mark.agent_authored(model="glm-5.2")
234238
def test_changed_coverage_forces_rebuild(self, stamp):
235239
_write_stamp(stamp, "cu13-gnu-opt")
236-
assert build_hooks._check_build_config("gnu", False, True) == "13"
240+
build_hooks._check_build_config("gnu", False, True)
237241
assert build_hooks.force_build_ext is True
238242

239243
@pytest.mark.agent_authored(model="glm-5.2")
240244
def test_record_writes_stamp(self, stamp):
241-
# _check_build_config sets _last_build_config; record writes it.
242-
build_hooks._check_build_config("gnu", False, False)
243-
build_hooks.record_build_config()
245+
# record_build_config re-derives from env; pass debug=False to match.
246+
build_hooks.record_build_config(False)
244247
assert stamp.read_text().strip() == "cu13-gnu-opt"
245248

246-
@pytest.mark.agent_authored(model="glm-5.2")
247-
def test_record_without_check_is_noop(self, stamp, monkeypatch):
248-
# If the build never reached _check_build_config (e.g. metadata-only),
249-
# record_build_config must not write a stamp.
250-
monkeypatch.setattr(build_hooks, "_last_build_config", None)
251-
build_hooks.record_build_config()
252-
assert not stamp.exists()
253-
254249

255250
def _capture_cythonize_build_dir(monkeypatch, cuda_major):
256251
"""Run the cythonize setup for one CUDA major and report its build_dir.

0 commit comments

Comments
 (0)