Make the CUDA build compile under nvcc - #254
Merged
Merged
Conversation
14 tasks
zfergus
force-pushed
the
feature/cuda-build
branch
from
September 8, 2026 04:08
c0066b3 to
7ba0e3a
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #254 +/- ##
=======================================
Coverage 96.70% 96.71%
=======================================
Files 191 191
Lines 17294 17295 +1
Branches 927 928 +1
=======================================
+ Hits 16724 16726 +2
+ Misses 570 569 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
15 tasks
The dev container covers interactive work; build-cuda.sh is the batch counterpart, building the same image and compiling the project with CUDA enabled so a machine without an NVIDIA GPU (or CI) can keep the CUDA build green. The source is mounted read-only and rsynced into a named volume, so a run never writes into the host working tree and ninja can still build incrementally.
nvcc's device front-end (EDG) chokes on two things in the fmt that spdlog bundles: a compile-time /utf-8 probe that misfires because the front-end never sees the flag, and a char32_t table using hex escapes with the high bit set. Neither is reachable from a compiler flag, so we patch both behind __CUDACC__. The spdlog include also moves ahead of the CCD dependencies. Scalable CCD carries its own spdlog recipe guarded on `if(TARGET spdlog::spdlog)`, so whichever runs first wins -- and if that is Scalable CCD's, the unpatched spdlog is the one CPM registers and the patch never applies.
- TinyAD: guards /bigobj by compile language so a bare flag no longer leaks into nvcc, which would treat it as an input file. - Scalable CCD: fixes the MSVC + CUDA 13.3 build and bumps its own dependencies.
MSVC-style flags passed bare are interpreted by nvcc as input file names, so /FS and the SIMD /arch flags now carry a COMPILE_LANGUAGE guard. CMake already forwards /FS to the host compiler for CUDA targets via -Xcompiler, and device code has no use for CPU SIMD, so neither needs a CUDA equivalent. The xsimd include in simd.hpp is guarded on __CUDACC__ for the same reason: the batch types and their operations are host-only.
Device code reaches std::numeric_limits and std::array, whose members are constexpr but not marked __device__. --expt-relaxed-constexpr lets nvcc accept them. PUBLIC so downstream CUDA consumers, the tests included, inherit it.
zfergus
force-pushed
the
feature/cuda-build
branch
from
September 8, 2026 16:24
7ba0e3a to
415a8bb
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Makes the existing
IPC_TOOLKIT_WITH_CUDA=ONconfiguration compile under nvcc. No CUDA code is added — this is the build layer the GPU work sits on, split out so it can be reviewed on its own./utf-8probe that misfires because the front-end never sees the flag, and achar32_ttable using hex escapes with the high bit set. Neither is reachable from a compiler flag, so both are patched behind__CUDACC__via CPM'sPATCHES./FSand the SIMD/archflags now carry aCOMPILE_LANGUAGEguard. CMake already forwards/FSto the host compiler for CUDA targets via-Xcompiler, and device code has no use for CPU SIMD, so neither needs a CUDA equivalent.ipc/utils/simd.hppare guarded on__CUDACC__; the batch types and their operations are host-only.--expt-relaxed-constexpr— device code reachesstd::numeric_limitsandstd::array, whose members areconstexprbut not__device__.PUBLICso downstream CUDA consumers, the tests included, inherit it..devcontainer/cuda/mirrors the existing.devcontainer/, based on NVIDIA's CUDAdevelimage so nvcc is available.build-cuda.shis the batch counterpart: it builds the same image and compiles the project with CUDA on, so a machine with no NVIDIA GPU can check the CUDA build. The source is mounted read-only and rsynced into a named volume, so a run never writes into the host tree.Dependency bumps
Both are existing dependencies moving to a newer pin — no new packages, same fetch mechanism (CPM), same licenses.
/bigobjby compile language so a bare flag no longer leaks into nvcc.Effect on the default (CUDA off) build
Most of this is inert without nvcc, but three pieces are not, and are worth a reviewer's attention:
if(TARGET spdlog::spdlog), so whichever recipe runs first wins — and if that is Scalable CCD's, the unpatched spdlog is the one CPM registers and the patch never applies. Reordering changes which recipe registers spdlog in all builds, not just CUDA ones.target_compile_options(ipc_toolkit PUBLIC ${SIMD_CXX_FLAGS})becomesPUBLIC "$<$<COMPILE_LANGUAGE:CXX>:${SIMD_CXX_FLAGS}>". A C++-only build should receive exactly the same flags, but the list now expands inside a generator expression, so this is the one change that could silently alter the default build rather than fail loudly.How Has This Been Tested?
CMAKE_CUDA_ARCHITECTURES=86— 525/525 targets including the device-link step. This exercises everything this PR adds: the patched fmt is what lets nvcc parse spdlog at all,--expt-relaxed-constexpris what lets device code reachstd::numeric_limits/std::array, and the flag guards are what keep-march=nativeout of nvcc's argument list. Built at the tip of the stack (Add the host/device shared source mechanism #255, Make the low-level math callable from device code #257), which contains this PR — not standalone.CUDA (Debug)andCUDA (Release)both pass, building library, tests, and Python bindings with nvcc on x86 Linux.SIMD_CXX_FLAGSgenerator expression still delivers the flags — a list expanding inside a genex could have silently dropped them rather than failing loudly, and-march=nativeis present on the compile line.Not tested:
/FSand the SIMD/archflags only exist for MSVC, and nothing in a Linux container or in CI reaches them — there is no MSVC + CUDA job. Those two hunks are reviewed by reading.build-cuda.shitself. The CUDA build above was run natively on a Linux box with the toolkit installed, not through the container. The Dockerfile and the script remain unexercised.Note for reviewers: the Scalable CCD bump
Running the GPU tests turned up an order-dependent illegal memory access in Scalable CCD's narrow phase (
cuda/narrow_phase/root_finder.cu), reached by the pre-existingtest_gpu_ccdtests. It poisons the CUDA context, so every latercudaMallocin the process returns 700.This bump does not cause it. I built both pins and ran four fixed seeds against each; the failure counts are identical on
c80af01(before) and8f9347c(after). The root cause is thatMAX_UNIT_SIZEis sized from currently-free GPU memory whileroot_finder.cusetsm_tailfromd_data.size()independently, so when memory is tight the buffer's tail exceeds its capacity. It is pre-existing, upstream, and deserves its own issue. CI has never caught it becausecuda.ymlbuilds but never runs the tests — the runners have no GPU.Test Configuration:
CMAKE_BUILD_TYPE=ReleaseChecklist