Skip to content

Commit 22e49a9

Browse files
committed
fix(rules-cuda): the clang route also names the CCCL payload
curand_mtgp32_kernel.h includes <nv/target> from CCCL, which the 12.x toolkits ship as the separate cuda-cccl package and which the host's /usr/include had supplied silently as well. The rule adds the payload's include directory (and include/cccl for the 13.x layout) and refuses the clang route without it, naming both entries; the fixture declares it.
1 parent 665fa48 commit 22e49a9

2 files changed

Lines changed: 25 additions & 7 deletions

File tree

rules/cuda.cppm

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,10 @@ struct toolkit {
147147
// cannot compile any device unit without them. Measured 2026-09-05: on a
148148
// developer machine the header was found in the HOST's /usr/include and
149149
// the leak went unnoticed until a runner with no host CUDA refused it.
150-
std::string curand_root;
150+
// The same header then includes <nv/target> from CCCL (libcu++), which the
151+
// 12.x toolkits ship as the separate `cuda-cccl` package, and which the
152+
// host's /usr/include had supplied in the same way.
153+
std::string curand_root, cccl_root;
151154
std::string nvcc() const { return nvcc_root + "/bin/nvcc"; }
152155
std::string host_config() const {
153156
for (auto const* r : { &crt_root, &nvcc_root, &cudart_root }) {
@@ -159,11 +162,19 @@ struct toolkit {
159162
}
160163
std::vector<std::string> include_dirs() const {
161164
std::vector<std::string> out;
162-
for (auto const* r : { &cudart_root, &crt_root, &nvcc_root, &curand_root })
165+
for (auto const* r : { &cudart_root, &crt_root, &nvcc_root, &cccl_root, &curand_root })
163166
if (!r->empty() && std::filesystem::is_directory(*r + "/include"))
164167
out.push_back(*r + "/include");
168+
// The 13.x CCCL payload nests its tree one directory down.
169+
if (!cccl_root.empty() && std::filesystem::is_directory(cccl_root + "/include/cccl"))
170+
out.push_back(cccl_root + "/include/cccl");
165171
return out;
166172
}
173+
bool has_cccl() const {
174+
return !cccl_root.empty()
175+
&& (std::filesystem::exists(cccl_root + "/include/nv/target")
176+
|| std::filesystem::exists(cccl_root + "/include/cccl/nv/target"));
177+
}
167178
std::vector<std::string> lib_dirs() const {
168179
std::vector<std::string> out;
169180
for (auto const* r : { &cudart_root, &nvcc_root })
@@ -185,6 +196,7 @@ inline std::optional<toolkit> find_toolkit() {
185196
t.cudart_root = xpkg("cuda-cudart");
186197
t.crt_root = xpkg("cuda-crt");
187198
t.curand_root = xpkg("libcurand");
199+
t.cccl_root = xpkg("cuda-cccl");
188200
t.driver_dir = xpkg("libcuda-host-link");
189201
if (t.nvcc_root.empty() || t.cudart_root.empty()) {
190202
std::println(std::cerr,
@@ -444,13 +456,16 @@ inline std::vector<edge> plan(std::span<const std::string> sources, options opt
444456
// would fail on belongs to a payload the project has to name, and the
445457
// diagnostic names it. A host copy is never searched for -- that is
446458
// how the leak above survived every local build.
447-
if (tk->curand_root.empty()
448-
|| !std::filesystem::exists(tk->curand_root + "/include/curand_mtgp32_kernel.h")) {
459+
const bool curand_ok = !tk->curand_root.empty()
460+
&& std::filesystem::exists(tk->curand_root + "/include/curand_mtgp32_kernel.h");
461+
if (!curand_ok || !tk->has_cccl()) {
449462
std::println(std::cerr,
450463
"mcpp.rules.cuda: the clang route needs cuRAND's headers, which clang's CUDA "
451-
"wrapper includes unconditionally.\n"
452-
" Name the payload under [xlings.workspace] and mcpp provisions it on first use:\n"
453-
" \"xim:libcurand\" = \"10.3.10.19\" (the 12.9 line; 10.4.x pairs with 13.x)");
464+
"wrapper includes unconditionally, and CCCL's, which they include in turn.\n"
465+
" Name the payloads under [xlings.workspace] and mcpp provisions them on first use:\n"
466+
" \"xim:cuda-cccl\" = \"12.9.27\" (the 12.9 line; 13.x pairs with 13.x)\n"
467+
" \"xim:libcurand\" = \"10.3.10.19\" (the 12.9 line; 10.4.x pairs with 13.x)\n"
468+
" (found cccl: '{}', curand: '{}')", tk->cccl_root, tk->curand_root);
454469
return out;
455470
}
456471
front = { driver_cc, "-x", "cuda", "-std=c++17", "-O2", "-fPIC",

tests/cuda-consumer/mcpp.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ cuda-runtime = "2026.09.05"
4242
# every device unit, so the clang route needs them even when nothing calls
4343
# cuRAND. The 10.3.x line pairs with CUDA 12.x.
4444
"xim:libcurand" = "10.3.10.19"
45+
# CCCL (libcu++, cub, thrust): cuRAND's header includes <nv/target> from it.
46+
# The 12.x toolkits ship it as a separate package; 12.9.27 is the 12.9 line.
47+
"xim:cuda-cccl" = "12.9.27"
4548
"xim:libcuda-host-link" = { linux = "0.0.1" }
4649

4750
[build]

0 commit comments

Comments
 (0)