Skip to content

Commit 3e1e6e0

Browse files
[FEA]: Introduce Python module with CCCL headers (#3201)
* Add cccl/python/cuda_cccl directory and use from cuda_parallel, cuda_cooperative * Run `copy_cccl_headers_to_aude_include()` before `setup()` * Create python/cuda_cccl/cuda/_include/__init__.py, then simply import cuda._include to find the include path. * Add cuda.cccl._version exactly as for cuda.cooperative and cuda.parallel * Bug fix: cuda/_include only exists after shutil.copytree() ran. * Use `f"cuda-cccl @ file://{cccl_path}/python/cuda_cccl"` in setup.py * Remove CustomBuildCommand, CustomWheelBuild in cuda_parallel/setup.py (they are equivalent to the default functions) * Replace := operator (needs Python 3.8+) * Fix oversights: remove `pip3 install ./cuda_cccl` lines from README.md * Restore original README.md: `pip3 install -e` now works on first pass. * cuda_cccl/README.md: FOR INTERNAL USE ONLY * Remove `$pymajor.$pyminor.` prefix in cuda_cccl _version.py (as suggested under #3201 (comment)) Command used: ci/update_version.sh 2 8 0 * Modernize pyproject.toml, setup.py Trigger for this change: * #3201 (comment) * #3201 (comment) * Install CCCL headers under cuda.cccl.include Trigger for this change: * #3201 (comment) Unexpected accidental discovery: cuda.cooperative unit tests pass without CCCL headers entirely. * Factor out cuda_cccl/cuda/cccl/include_paths.py * Reuse cuda_cccl/cuda/cccl/include_paths.py from cuda_cooperative * Add missing Copyright notice. * Add missing __init__.py (cuda.cccl) * Add `"cuda.cccl"` to `autodoc.mock_imports` * Move cuda.cccl.include_paths into function where it is used. (Attempt to resolve Build and Verify Docs failure.) * Add # TODO: move this to a module-level import * Modernize cuda_cooperative/pyproject.toml, setup.py * Convert cuda_cooperative to use hatchling as build backend. * Revert "Convert cuda_cooperative to use hatchling as build backend." This reverts commit 61637d6. * Move numpy from [build-system] requires -> [project] dependencies * Move pyproject.toml [project] dependencies -> setup.py install_requires, to be able to use CCCL_PATH * Remove copy_license() and use license_files=["../../LICENSE"] instead. * Further modernize cuda_cccl/setup.py to use pathlib * Trivial simplifications in cuda_cccl/pyproject.toml * Further simplify cuda_cccl/pyproject.toml, setup.py: remove inconsequential code * Make cuda_cooperative/pyproject.toml more similar to cuda_cccl/pyproject.toml * Add taplo-pre-commit to .pre-commit-config.yaml * taplo-pre-commit auto-fixes * Use pathlib in cuda_cooperative/setup.py * CCCL_PYTHON_PATH in cuda_cooperative/setup.py * Modernize cuda_parallel/pyproject.toml, setup.py * Use pathlib in cuda_parallel/setup.py * Add `# TOML lint & format` comment. * Replace MANIFEST.in with `[tool.setuptools.package-data]` section in pyproject.toml * Use pathlib in cuda/cccl/include_paths.py * pre-commit autoupdate (EXCEPT clang-format, which was manually restored) * Fixes after git merge main * Resolve warning: AttributeError: '_Reduce' object has no attribute 'build_result' ``` =========================================================================== warnings summary =========================================================================== tests/test_reduce.py::test_reduce_non_contiguous /home/coder/cccl/python/devenv/lib/python3.12/site-packages/_pytest/unraisableexception.py:85: PytestUnraisableExceptionWarning: Exception ignored in: <function _Reduce.__del__ at 0x7bf123139080> Traceback (most recent call last): File "/home/coder/cccl/python/cuda_parallel/cuda/parallel/experimental/algorithms/reduce.py", line 132, in __del__ bindings.cccl_device_reduce_cleanup(ctypes.byref(self.build_result)) ^^^^^^^^^^^^^^^^^ AttributeError: '_Reduce' object has no attribute 'build_result' warnings.warn(pytest.PytestUnraisableExceptionWarning(msg)) -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html ============================================================= 1 passed, 93 deselected, 1 warning in 0.44s ============================================================== ``` * Move `copy_cccl_headers_to_cuda_cccl_include()` functionality to `class CustomBuildPy` * Introduce cuda_cooperative/constraints.txt * Also add cuda_parallel/constraints.txt * Add `--constraint constraints.txt` in ci/test_python.sh * Update Copyright dates * Switch to https://github.com/ComPWA/taplo-pre-commit (the other repo has been archived by the owner on Jul 1, 2024) For completeness: The other repo took a long time to install into the pre-commit cache; so long it lead to timeouts in the CCCL CI. * Remove unused cuda_parallel jinja2 dependency (noticed by chance). * Remove constraints.txt files, advertise running `pip install cuda-cccl` first instead. * Make cuda_cooperative, cuda_parallel testing completely independent. * Run only test_python.sh [skip-rapids][skip-matx][skip-docs][skip-vdc] * Try using another runner (because V100 runners seem to be stuck) [skip-rapids][skip-matx][skip-docs][skip-vdc] * Fix sign-compare warning (#3408) [skip-rapids][skip-matx][skip-docs][skip-vdc] * Revert "Try using another runner (because V100 runners seem to be stuck) [skip-rapids][skip-matx][skip-docs][skip-vdc]" This reverts commit ea33a21. Error message: #3201 (comment) * Try using A100 runner (because V100 runners still seem to be stuck) [skip-rapids][skip-matx][skip-docs][skip-vdc] * Also show cuda-cooperative site-packages, cuda-parallel site-packages (after pip install) [skip-rapids][skip-matx][skip-docs][skip-vdc] * Try using l4 runner (because V100 runners still seem to be stuck) [skip-rapids][skip-matx][skip-docs][skip-vdc] * Restore original ci/matrix.yaml [skip-rapids] * Use for loop in test_python.sh to avoid code duplication. * Run only test_python.sh [skip-rapids][skip-matx][skip-docs][skip-vdc][skip pre-commit.ci] * Comment out taplo-lint in pre-commit config [skip-rapids][skip-matx][skip-docs][skip-vdc] * Revert "Run only test_python.sh [skip-rapids][skip-matx][skip-docs][skip-vdc][skip pre-commit.ci]" This reverts commit ec206fd. * Implement suggestion by @shwina (#3201 (review)) * Address feedback by @leofang --------- Co-authored-by: Bernhard Manfred Gruber <bernhardmgruber@gmail.com>
1 parent a128d86 commit 3e1e6e0

File tree

24 files changed

+288
-271
lines changed

24 files changed

+288
-271
lines changed

.pre-commit-config.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ repos:
4343
hooks:
4444
- id: ruff # linter
4545
- id: ruff-format # formatter
46+
47+
# TOML lint & format
48+
- repo: https://github.com/ComPWA/taplo-pre-commit
49+
rev: v0.9.3
50+
hooks:
51+
# See https://github.com/NVIDIA/cccl/issues/3426
52+
# - id: taplo-lint
53+
# exclude: "^docs/"
54+
- id: taplo-format
55+
exclude: "^docs/"
56+
4657
- repo: https://github.com/codespell-project/codespell
4758
rev: v2.3.0
4859
hooks:

ci/test_python.sh

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,28 @@ print_environment_details
88

99
fail_if_no_gpu
1010

11-
readonly prefix="${BUILD_DIR}/python/"
12-
export PYTHONPATH="${prefix}:${PYTHONPATH:-}"
11+
begin_group "⚙️ Existing site-packages"
12+
pip freeze
13+
end_group "⚙️ Existing site-packages"
1314

14-
pushd ../python/cuda_cooperative >/dev/null
15+
for module in cuda_parallel cuda_cooperative; do
1516

16-
run_command "⚙️ Pip install cuda_cooperative" pip install --force-reinstall --upgrade --target "${prefix}" .[test]
17-
run_command "🚀 Pytest cuda_cooperative" python -m pytest -v ./tests
17+
pushd "../python/${module}" >/dev/null
1818

19-
popd >/dev/null
19+
TEMP_VENV_DIR="/tmp/${module}_venv"
20+
rm -rf "${TEMP_VENV_DIR}"
21+
python -m venv "${TEMP_VENV_DIR}"
22+
. "${TEMP_VENV_DIR}/bin/activate"
23+
echo 'cuda-cccl @ file:///home/coder/cccl/python/cuda_cccl' > /tmp/cuda-cccl_constraints.txt
24+
run_command "⚙️ Pip install ${module}" pip install -c /tmp/cuda-cccl_constraints.txt .[test]
25+
begin_group "⚙️ ${module} site-packages"
26+
pip freeze
27+
end_group "⚙️ ${module} site-packages"
28+
run_command "🚀 Pytest ${module}" python -m pytest -v ./tests
29+
deactivate
2030

21-
pushd ../python/cuda_parallel >/dev/null
31+
popd >/dev/null
2232

23-
# Temporarily install the package twice to populate include directory as part of the first installation
24-
# and to let manifest discover these includes during the second installation. Do not forget to remove the
25-
# second installation after https://github.com/NVIDIA/cccl/issues/2281 is addressed.
26-
run_command "⚙️ Pip install cuda_parallel once" pip install --force-reinstall --upgrade --target "${prefix}" .[test]
27-
run_command "⚙️ Pip install cuda_parallel twice" pip install --force-reinstall --upgrade --target "${prefix}" .[test]
28-
run_command "🚀 Pytest cuda_parallel" python -m pytest -v ./tests
29-
30-
popd >/dev/null
33+
done
3134

3235
print_time_summary

ci/update_version.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ CUB_CMAKE_VERSION_FILE="lib/cmake/cub/cub-config-version.cmake"
3737
LIBCUDACXX_CMAKE_VERSION_FILE="lib/cmake/libcudacxx/libcudacxx-config-version.cmake"
3838
THRUST_CMAKE_VERSION_FILE="lib/cmake/thrust/thrust-config-version.cmake"
3939
CUDAX_CMAKE_VERSION_FILE="lib/cmake/cudax/cudax-config-version.cmake"
40+
CUDA_CCCL_VERSION_FILE="python/cuda_cccl/cuda/cccl/_version.py"
4041
CUDA_COOPERATIVE_VERSION_FILE="python/cuda_cooperative/cuda/cooperative/_version.py"
4142
CUDA_PARALLEL_VERSION_FILE="python/cuda_parallel/cuda/parallel/_version.py"
4243

@@ -110,6 +111,7 @@ update_file "$CUDAX_CMAKE_VERSION_FILE" "set(cudax_VERSION_MAJOR \([0-9]\+\))" "
110111
update_file "$CUDAX_CMAKE_VERSION_FILE" "set(cudax_VERSION_MINOR \([0-9]\+\))" "set(cudax_VERSION_MINOR $minor)"
111112
update_file "$CUDAX_CMAKE_VERSION_FILE" "set(cudax_VERSION_PATCH \([0-9]\+\))" "set(cudax_VERSION_PATCH $patch)"
112113

114+
update_file "$CUDA_CCCL_VERSION_FILE" "^__version__ = \"\([0-9.]\+\)\"" "__version__ = \"$major.$minor.$patch\""
113115
update_file "$CUDA_COOPERATIVE_VERSION_FILE" "^__version__ = \"\([0-9.]\+\)\"" "__version__ = \"$pymajor.$pyminor.$major.$minor.$patch\""
114116
update_file "$CUDA_PARALLEL_VERSION_FILE" "^__version__ = \"\([0-9.]\+\)\"" "__version__ = \"$pymajor.$pyminor.$major.$minor.$patch\""
115117

docs/repo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ autodoc.mock_imports = [
347347
"numba",
348348
"pynvjitlink",
349349
"cuda.bindings",
350+
"cuda.cccl",
350351
"llvmlite",
351352
"numpy",
352353
]

python/cuda_cccl/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
cuda/cccl/include
2+
*egg-info

python/cuda_cccl/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## Note
2+
3+
This package is currently FOR INTERNAL USE ONLY and not meant to be used/installed explicitly.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2+
#
3+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
from cuda.cccl._version import __version__
6+
from cuda.cccl.include_paths import get_include_paths
7+
8+
__all__ = ["__version__", "get_include_paths"]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2+
#
3+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
# This file is generated by ci/update_version.sh
6+
# Do not edit this file manually.
7+
__version__ = "2.8.0"
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2+
#
3+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
import os
6+
import shutil
7+
from dataclasses import dataclass
8+
from functools import lru_cache
9+
from pathlib import Path
10+
from typing import Optional
11+
12+
13+
def _get_cuda_path() -> Optional[Path]:
14+
cuda_path = os.environ.get("CUDA_PATH")
15+
if cuda_path:
16+
cuda_path = Path(cuda_path)
17+
if cuda_path.exists():
18+
return cuda_path
19+
20+
nvcc_path = shutil.which("nvcc")
21+
if nvcc_path:
22+
return Path(nvcc_path).parent.parent
23+
24+
default_path = Path("/usr/local/cuda")
25+
if default_path.exists():
26+
return default_path
27+
28+
return None
29+
30+
31+
@dataclass
32+
class IncludePaths:
33+
cuda: Optional[Path]
34+
libcudacxx: Optional[Path]
35+
cub: Optional[Path]
36+
thrust: Optional[Path]
37+
38+
def as_tuple(self):
39+
# Note: higher-level ... lower-level order:
40+
return (self.thrust, self.cub, self.libcudacxx, self.cuda)
41+
42+
43+
@lru_cache()
44+
def get_include_paths() -> IncludePaths:
45+
# TODO: once docs env supports Python >= 3.9, we
46+
# can move this to a module-level import.
47+
from importlib.resources import as_file, files
48+
49+
cuda_incl = None
50+
cuda_path = _get_cuda_path()
51+
if cuda_path is not None:
52+
cuda_incl = cuda_path / "include"
53+
54+
with as_file(files("cuda.cccl.include")) as f:
55+
cccl_incl = Path(f)
56+
assert cccl_incl.exists()
57+
58+
return IncludePaths(
59+
cuda=cuda_incl,
60+
libcudacxx=cccl_incl / "libcudacxx",
61+
cub=cccl_incl,
62+
thrust=cccl_incl,
63+
)

python/cuda_cccl/pyproject.toml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
2+
#
3+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
[build-system]
6+
requires = ["setuptools>=61.0.0"]
7+
build-backend = "setuptools.build_meta"
8+
9+
[project]
10+
name = "cuda-cccl"
11+
description = "Experimental Package with CCCL headers to support JIT compilation"
12+
authors = [{ name = "NVIDIA Corporation" }]
13+
classifiers = [
14+
"Programming Language :: Python :: 3 :: Only",
15+
"Environment :: GPU :: NVIDIA CUDA",
16+
"License :: OSI Approved :: Apache Software License",
17+
]
18+
requires-python = ">=3.9"
19+
dynamic = ["version", "readme"]
20+
21+
[project.urls]
22+
Homepage = "https://github.com/NVIDIA/cccl"
23+
24+
[tool.setuptools.dynamic]
25+
version = { attr = "cuda.cccl._version.__version__" }
26+
readme = { file = ["README.md"], content-type = "text/markdown" }
27+
28+
[tool.setuptools.package-data]
29+
cuda = ["cccl/include/**/*"]

0 commit comments

Comments
 (0)