Skip to content

Commit 1976597

Browse files
committed
defer cythonization until cuda-bindings is installed
1 parent 7557967 commit 1976597

2 files changed

Lines changed: 42 additions & 31 deletions

File tree

cuda_core/build_hooks.py

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,25 @@
66
# - https://peps.python.org/pep-0517/
77
# - https://setuptools.pypa.io/en/latest/build_meta.html#dynamic-build-dependencies-and-other-build-meta-tweaks
88
# Specifically, there are 5 APIs required to create a proper build backend, see below.
9-
# For now it's mostly a pass-through to setuptools, except that we need to determine
10-
# some dependencies at build time.
119
#
1210
# TODO: also implement PEP-660 API hooks
1311

12+
import functools
13+
import glob
1414
import os
1515
import re
1616
import subprocess # nosec: B404
1717

18+
from Cython.Build import cythonize
19+
from setuptools import Extension
1820
from setuptools import build_meta as _build_meta
1921

2022
prepare_metadata_for_build_wheel = _build_meta.prepare_metadata_for_build_wheel
21-
build_wheel = _build_meta.build_wheel
2223
build_sdist = _build_meta.build_sdist
2324
get_requires_for_build_sdist = _build_meta.get_requires_for_build_sdist
2425

2526

27+
@functools.cache
2628
def _get_proper_cuda_bindings_major_version() -> str:
2729
# for local development (with/without build isolation)
2830
try:
@@ -51,8 +53,40 @@ def _get_proper_cuda_bindings_major_version() -> str:
5153
return "13"
5254

5355

54-
# Note: this function returns a list of *build-time* dependencies, so it's not affected
55-
# by "--no-deps" based on the PEP-517 design.
56+
# used later by setup()
57+
_extensions = None
58+
59+
60+
def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
61+
# Customizing this hook is needed because we must defer cythonization until cuda-bindings,
62+
# now a required build-time dependency that's dynamically installed via the other hook below,
63+
# is installed. Otherwise, cimport any cuda.bindings modules would fail!
64+
65+
# It seems setuptools' wildcard support has problems for namespace packages,
66+
# so we explicitly spell out all Extension instances.
67+
root_module = "cuda.core.experimental"
68+
root_path = f"{os.path.sep}".join(root_module.split(".")) + os.path.sep
69+
ext_files = glob.glob(f"{root_path}/**/*.pyx", recursive=True)
70+
71+
def strip_prefix_suffix(filename):
72+
return filename[len(root_path) : -4]
73+
74+
module_names = (strip_prefix_suffix(f) for f in ext_files)
75+
ext_modules = tuple(
76+
Extension(
77+
f"cuda.core.experimental.{mod.replace(os.path.sep, '.')}",
78+
sources=[f"cuda/core/experimental/{mod}.pyx"],
79+
language="c++",
80+
)
81+
for mod in module_names
82+
)
83+
84+
global _extensions
85+
_extensions = cythonize(ext_modules, verbose=True, language_level=3, compiler_directives={"embedsignature": True})
86+
87+
return _build_meta.build_wheel(wheel_directory, config_settings, metadata_directory)
88+
89+
5690
def get_requires_for_build_wheel(config_settings=None):
5791
cuda_major = _get_proper_cuda_bindings_major_version()
5892
cuda_bindings_require = [f"cuda-bindings=={cuda_major}.*"]

cuda_core/setup.py

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,23 @@
22
#
33
# SPDX-License-Identifier: Apache-2.0
44

5-
import glob
65
import os
76

8-
from Cython.Build import cythonize
9-
from setuptools import Extension, setup
7+
import build_hooks # our build backend
8+
from setuptools import setup
109
from setuptools.command.build_ext import build_ext as _build_ext
1110

1211
nthreads = int(os.environ.get("CUDA_PYTHON_PARALLEL_LEVEL", os.cpu_count() // 2))
1312

1413

15-
# It seems setuptools' wildcard support has problems for namespace packages,
16-
# so we explicitly spell out all Extension instances.
17-
root_module = "cuda.core.experimental"
18-
root_path = f"{os.path.sep}".join(root_module.split(".")) + os.path.sep
19-
ext_files = glob.glob(f"{root_path}/**/*.pyx", recursive=True)
20-
21-
22-
def strip_prefix_suffix(filename):
23-
return filename[len(root_path) : -4]
24-
25-
26-
module_names = (strip_prefix_suffix(f) for f in ext_files)
27-
ext_modules = tuple(
28-
Extension(
29-
f"cuda.core.experimental.{mod.replace(os.path.sep, '.')}",
30-
sources=[f"cuda/core/experimental/{mod}.pyx"],
31-
language="c++",
32-
)
33-
for mod in module_names
34-
)
35-
36-
3714
class build_ext(_build_ext):
3815
def build_extensions(self):
3916
self.parallel = nthreads
4017
super().build_extensions()
4118

4219

4320
setup(
44-
ext_modules=cythonize(ext_modules, verbose=True, language_level=3, compiler_directives={"embedsignature": True}),
21+
ext_modules=build_hooks._extensions,
4522
cmdclass={
4623
"build_ext": build_ext,
4724
},

0 commit comments

Comments
 (0)