Skip to content

Commit eea34c1

Browse files
committed
fix(example): the clang route passes NVIDIA's own libc++ escape
A device unit that includes <cuda_runtime.h> stops on crt/host_defines.h:67: error: "libc++ is not supported on x86 system" whenever the toolchain is LLVM, which is the toolchain the clang route exists for. The guard is `#if defined(__CUDACC__) && … && defined(_LIBCPP_VERSION)`, and clang defines `__CUDACC__` when it compiles CUDA itself, so the refusal — which is about nvcc's host pass — lands on a compiler it was not written about. The escape hatch is upstream's own and is passed only on the clang route: nvcc really does break against libc++, and nothing here weakens that refusal. Found on ggml's CUDA backend. The example's own kernel never showed it because a bare kernel includes no toolkit header at all — which is worth knowing about the example: it exercises the plumbing, not the headers.
1 parent 91d5222 commit eea34c1

1 file changed

Lines changed: 32 additions & 6 deletions

File tree

examples/09-cuda-kernel/rules-cuda/src/rules-cuda.cppm

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,15 @@ enum class route { automatic, clang, nvcc };
5151

5252
struct options {
5353
route which = route::automatic;
54-
// Header search paths for the island, relative to the package root. The
55-
// island's own interface lives in one of these, and a device compiler is a
56-
// separate driver that inherits nothing from the C++ side's include
57-
// configuration.
54+
// Header search paths for the island. Relative entries resolve against the
55+
// package root; an ABSOLUTE entry is passed through unchanged.
56+
//
57+
// ⭐ THE ABSOLUTE FORM IS FOR A DEPENDENCY'S HEADERS. A device compiler is
58+
// a separate driver and inherits nothing from the C++ side's include
59+
// configuration, so a package whose device code includes a dependency's
60+
// header -- ggml's CUDA backend includes `cublas_v2.h` -- has to name that
61+
// dependency's directory here, and it knows it only as the absolute path
62+
// `mcpp::dep_dir` answered with.
5863
std::vector<std::string> includes;
5964
std::string out_dir = std::string(mcpp::out_dir());
6065
};
@@ -428,7 +433,26 @@ inline std::vector<edge> plan(std::span<const std::string> sources, options opt
428433
return out;
429434
}
430435
front = { driver_cc, "-x", "cuda", "-std=c++17", "-O2", "-fPIC",
431-
"--cuda-path=" + tk->nvcc_root, "-Wno-unknown-cuda-version" };
436+
"--cuda-path=" + tk->nvcc_root, "-Wno-unknown-cuda-version",
437+
// ⚠️ NVIDIA'S HEADER REFUSES libc++, AND THE REFUSAL IS
438+
// ABOUT nvcc RATHER THAN ABOUT THIS COMPILER.
439+
//
440+
// crt/host_defines.h:67: error: "libc++ is not supported
441+
// on x86 system"
442+
//
443+
// The guard is `#if defined(__CUDACC__) && … &&
444+
// defined(_LIBCPP_VERSION)`, and clang defines `__CUDACC__`
445+
// when it compiles CUDA itself — so a device unit that
446+
// includes <cuda_runtime.h> stops here on any LLVM
447+
// toolchain, which is the toolchain this route exists for.
448+
// Measured on ggml's CUDA backend; the CUDA example's own
449+
// kernel never showed it because a bare kernel includes no
450+
// toolkit header at all.
451+
//
452+
// The escape hatch is upstream's own, and it is passed only
453+
// on this route: nvcc's host pass really does break against
454+
// libc++, and nothing here weakens that.
455+
"-D_ALLOW_UNSUPPORTED_LIBCPP" };
432456
for (auto const& inc : tk->include_dirs()) front.push_back("-I" + inc);
433457
for (auto const& a : tg.archs) front.push_back("--cuda-gpu-arch=" + a);
434458
// clang checks ptxas and fatbinary itself; say so before it does.
@@ -550,7 +574,9 @@ inline std::vector<edge> plan(std::span<const std::string> sources, options opt
550574
e.id = "cuda:" + stem;
551575
e.description = (r == route::clang ? "clang -x cuda " : "nvcc ") + src;
552576
e.command = front;
553-
for (auto const& inc : opt.includes) e.command.push_back("-I" + root + "/" + inc);
577+
for (auto const& inc : opt.includes)
578+
e.command.push_back("-I" + (std::filesystem::path(inc).is_absolute()
579+
? inc : root + "/" + inc));
554580
e.command.insert(e.command.end(), { "-c", root + "/" + src, "-o", obj });
555581
e.inputs = { root + "/" + src };
556582
e.outputs = { obj };

0 commit comments

Comments
 (0)