Clang/CUDA: Support the llvm23+ offload linker model

Fixes: #26120, #26810
This commit is contained in:
Robert Maynard
2026-09-03 13:26:45 -04:00
parent 8eb3e61e5c
commit ce3d0af576
13 changed files with 91 additions and 22 deletions
@@ -0,0 +1,6 @@
clang-cuda-offload-linker
-------------------------
* Clang compiler version 20 and above use a new offload linker
model for CUDA where device linking is performed as part of the host link
phase.
+4
View File
@@ -34,6 +34,10 @@ set(CMAKE_CUDA_COMPILER_LOADED 1)
set(CMAKE_CUDA_COMPILER_ID_RUN 1)
set(CMAKE_CUDA_SOURCE_FILE_EXTENSIONS cu)
set(CMAKE_CUDA_LINKER_PREFERENCE 15)
if(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang" AND
CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 20.0)
set(CMAKE_CUDA_LINKER_PREFERENCE 90)
endif()
set(CMAKE_CUDA_LINKER_PREFERENCE_PROPAGATES 1)
set(CMAKE_CUDA_LINKER_DEPFILE_SUPPORTED @CMAKE_CUDA_LINKER_DEPFILE_SUPPORTED@)
set(CMAKE_LINKER_PUSHPOP_STATE_SUPPORTED @CMAKE_LINKER_PUSHPOP_STATE_SUPPORTED@)
+2 -1
View File
@@ -54,6 +54,7 @@ endif()
# any makefiles or projects.
if(NOT CMAKE_CUDA_COMPILER_WORKS)
PrintTestCompilerStatus("CUDA")
__TestCompiler_setTryCompileTargetType()
string(CONCAT __TestCompiler_testCudaCompilerSource
"#ifndef __CUDACC__\n"
"# error \"The CMAKE_CUDA_COMPILER is set to an invalid CUDA compiler\"\n"
@@ -69,7 +70,7 @@ if(NOT CMAKE_CUDA_COMPILER_WORKS)
NO_CACHE
OUTPUT_VARIABLE __CMAKE_CUDA_COMPILER_OUTPUT)
unset(__TestCompiler_testCudaCompilerSource)
__TestCompiler_restoreTryCompileTargetType()
if(NOT CMAKE_CUDA_COMPILER_WORKS)
PrintTestCompilerResult(CHECK_FAIL "broken")
string(REPLACE "\n" "\n " _output "${__CMAKE_CUDA_COMPILER_OUTPUT}")
+8
View File
@@ -21,6 +21,14 @@ macro(__TestCompiler_setTryCompileTargetType)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
set(__CMAKE_TEST_COMPILER_TARGET_TYPE_RESTORE 1)
endif()
if(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang" AND
CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 20.0 AND
CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 23.0)
# https://github.com/llvm/llvm-project/issues/191041
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
set(__CMAKE_TEST_COMPILER_TARGET_TYPE_RESTORE 1)
endif()
endif()
endmacro()
+8 -2
View File
@@ -22,6 +22,12 @@ set(_CMAKE_CUDA_WHOLE_FLAG "-c")
set(_CMAKE_CUDA_RDC_FLAG "-fgpu-rdc")
set(_CMAKE_CUDA_PTX_FLAG "--cuda-device-only -S")
if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 20.0)
# Starting in 20.0, clang supports device linking as part of the host link phase
set(CMAKE_CUDA_COMPILER_HAS_DEVICE_LINK_PHASE FALSE)
set(_CMAKE_CUDA_RDC_LINK_FLAG "--offload-link")
endif()
# Device linking is just regular linking so these are the same.
set(CMAKE_CUDA_DEVICE_LINKER_WRAPPER_FLAG ${CMAKE_CUDA_LINKER_WRAPPER_FLAG})
set(CMAKE_CUDA_DEVICE_LINKER_WRAPPER_FLAG_SEP ${CMAKE_CUDA_LINKER_WRAPPER_FLAG_SEP})
@@ -29,8 +35,8 @@ set(CMAKE_CUDA_DEVICE_LINKER_WRAPPER_FLAG_SEP ${CMAKE_CUDA_LINKER_WRAPPER_FLAG_S
set(CMAKE_CUDA_DEVICE_LINK_MODE DRIVER)
# RulePlaceholderExpander expands crosscompile variables like sysroot and target only for CMAKE_<LANG>_COMPILER. Override the default.
set(CMAKE_CUDA_LINK_EXECUTABLE "<CMAKE_CUDA_COMPILER> <FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
set(CMAKE_CUDA_CREATE_SHARED_LIBRARY "<CMAKE_CUDA_COMPILER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
set(CMAKE_CUDA_LINK_EXECUTABLE "<CMAKE_CUDA_COMPILER> <FLAGS> <LINK_FLAGS> ${_CMAKE_CUDA_RDC_LINK_FLAG} <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
set(CMAKE_CUDA_CREATE_SHARED_LIBRARY "<CMAKE_CUDA_COMPILER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${_CMAKE_CUDA_RDC_LINK_FLAG} <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC")
set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC "cudadevrt;cudart_static")
@@ -12,6 +12,12 @@ function(cmake_cuda_architectures_all lang lang_var_)
# Initial set based on CUDA 13.0.
set(CMAKE_CUDA_ARCHITECTURES_ALL 75 80 86 87 88 89 90 100 103 110 120 121)
set(CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 75 80 90 100 110 120)
if((CMAKE_${lang}_COMPILER_ID STREQUAL "Clang" AND CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 23.0))
list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL 110)
list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 110)
endif()
else()
# Initial set based on CUDA 7.0.
set(CMAKE_CUDA_ARCHITECTURES_ALL 20 21 30 35 37 50 52 53)
+31 -10
View File
@@ -2838,19 +2838,40 @@ void cmGeneratorTarget::AddCUDAArchitectureFlagsImpl(cmBuildStep compileOrLink,
flags += "]\"";
}
} else if (compiler == "Clang" && compileOrLink == cmBuildStep::Compile) {
for (CudaArchitecture& architecture : architectures) {
flags =
cmStrCat(std::move(flags), " --cuda-gpu-arch=sm_", architecture.name);
if (cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
this->Makefile->GetDefinition(cmStrCat(
"CMAKE_", lang, "_COMPILER_VERSION")),
"20.0")) {
for (CudaArchitecture& architecture : architectures) {
flags =
cmStrCat(std::move(flags), " --offload-arch=sm_", architecture.name);
if (!architecture.real) {
this->Makefile->IssueMessage(
MessageType::WARNING,
"Clang doesn't support disabling CUDA real code generation.");
if (!architecture.real) {
this->Makefile->IssueMessage(
MessageType::WARNING,
"Clang doesn't support disabling CUDA real code generation.");
}
if (architecture.virtual_) {
flags = cmStrCat(std::move(flags), " --cuda-include-ptx=sm_",
architecture.name);
}
}
if (!architecture.virtual_) {
flags = cmStrCat(std::move(flags), " --no-cuda-include-ptx=sm_",
} else {
for (CudaArchitecture& architecture : architectures) {
flags = cmStrCat(std::move(flags), " --cuda-gpu-arch=sm_",
architecture.name);
if (!architecture.real) {
this->Makefile->IssueMessage(
MessageType::WARNING,
"Clang doesn't support disabling CUDA real code generation.");
}
if (!architecture.virtual_) {
flags = cmStrCat(std::move(flags), " --no-cuda-include-ptx=sm_",
architecture.name);
}
}
}
}
+2 -1
View File
@@ -9,7 +9,8 @@ add_cuda_test_macro(Cuda.ObjectLibrary CudaObjectLibrary)
add_cuda_test_macro(Cuda.MixedStandardLevels1 MixedStandardLevels1)
add_cuda_test_macro(Cuda.MixedStandardLevels2 MixedStandardLevels2)
add_cuda_test_macro(Cuda.MixedStandardLevels3 MixedStandardLevels3)
if(NOT WIN32 OR NOT CMake_TEST_CUDA STREQUAL "Clang") # MSVC std lib needs C++14
if(NOT WIN32 AND CMake_TEST_CUDA STREQUAL "NVIDIA")
# MSVC std lib, and newer clang needs C++14
add_cuda_test_macro(Cuda.MixedStandardLevels4 MixedStandardLevels4)
add_cuda_test_macro(Cuda.MixedStandardLevels5 MixedStandardLevels5)
endif()
+4 -2
View File
@@ -13,7 +13,8 @@ add_cuda_test_macro(CudaOnly.EnableStandard CudaOnlyEnableStandard)
add_cuda_test_macro(CudaOnly.ExportPTX CudaOnlyExportPTX)
add_cuda_test_macro(CudaOnly.SharedRuntimePlusToolkit CudaOnlySharedRuntimePlusToolkit)
add_cuda_test_macro(CudaOnly.StaticRuntimePlusToolkit CudaOnlyStaticRuntimePlusToolkit)
if(NOT WIN32 OR NOT CMake_TEST_CUDA STREQUAL "Clang") # MSVC std lib needs C++14
if(NOT WIN32 AND CMake_TEST_CUDA STREQUAL "NVIDIA")
# MSVC std lib, and newer clang needs C++14
add_cuda_test_macro(CudaOnly.Standard98 CudaOnlyStandard98)
endif()
set(CudaOnly.Toolkit_BUILD_OPTIONS -DHAS_CUPTI:BOOL=${CMake_TEST_CUDA_CUPTI})
@@ -24,12 +25,13 @@ add_cuda_test_macro(CudaOnly.TryCompileTargetStatic CudaOnlyTryCompileTargetStat
add_cuda_test_macro(CudaOnly.Unity CudaOnlyUnity)
add_cuda_test_macro(CudaOnly.WithDefs CudaOnlyWithDefs)
add_cuda_test_macro(CudaOnly.CircularLinkLine CudaOnlyCircularLinkLine)
add_cuda_test_macro(CudaOnly.ResolveDeviceSymbols CudaOnlyResolveDeviceSymbols)
add_cuda_test_macro(CudaOnly.SeparateCompilation main/CudaOnlySeparateCompilation)
add_cuda_test_macro(CudaOnly.SeparateCompilationPTX CudaOnlySeparateCompilationPTX)
add_cuda_test_macro(CudaOnly.SeparateCompilationTargetObjects CudaOnlySeparateCompilationTargetObjects)
if(CMake_TEST_CUDA AND NOT CMake_TEST_CUDA STREQUAL "Clang")
add_cuda_test_macro(CudaOnly.ResolveDeviceSymbols CudaOnlyResolveDeviceSymbols)
# Clang doesn't have flags for selecting the runtime.
add_cuda_test_macro(CudaOnly.SharedRuntimeViaCUDAFlags CudaOnlySharedRuntimeViaCUDAFlags)
@@ -4,6 +4,13 @@
#include "embedded_objs.h"
#if defined(CUDA_VERSION) && \
CUDA_VERSION >= 13000 // get version from cuda.h header (clang cuda)
# define CUDA_13_OR_GREATER
#elif defined(__CUDACC_VER_MAJOR__) && \
__CUDACC_VER_MAJOR__ >= 13 // get version from nvcc compiler defines
# define CUDA_13_OR_GREATER
#endif
int main()
{
cuInit(0);
@@ -18,7 +25,7 @@ int main()
cuDeviceGet(&device, 0);
CUcontext context;
#if defined(__CUDACC_VER_MAJOR__) && __CUDACC_VER_MAJOR__ >= 13
#if defined(CUDA_13_OR_GREATER)
CUctxCreateParams params = {};
params.execAffinityParams = nullptr;
params.numExecAffinityParams = 0;
@@ -61,14 +61,19 @@ if (NOT CMAKE_C_COMPILER_ID STREQUAL "Intel")
run_cmake_target(genex_LINK_LANG_AND_ID exe LinkOptions_exe --config Release)
run_cmake(genex_DEVICE_LINK)
if (CMake_TEST_CUDA)
include("${RunCMake_BINARY_DIR}/genex_DEVICE_LINK-build/info.cmake" OPTIONAL)
endif()
run_cmake_target(genex_DEVICE_LINK interface LinkOptions_shared_interface --config Release)
run_cmake_target(genex_DEVICE_LINK private LinkOptions_private --config Release)
if (CMake_TEST_CUDA)
run_cmake_target(genex_DEVICE_LINK CMP0105_UNSET LinkOptions_CMP0105_UNSET --config Release)
run_cmake_target(genex_DEVICE_LINK CMP0105_OLD LinkOptions_CMP0105_OLD --config Release)
run_cmake_target(genex_DEVICE_LINK CMP0105_NEW LinkOptions_CMP0105_NEW --config Release)
run_cmake_target(genex_DEVICE_LINK device LinkOptions_device --config Release)
if (CMAKE_CUDA_COMPILER_HAS_DEVICE_LINK_PHASE)
run_cmake_target(genex_DEVICE_LINK CMP0105_NEW LinkOptions_CMP0105_NEW --config Release)
run_cmake_target(genex_DEVICE_LINK device LinkOptions_device --config Release)
endif()
if (RunCMake_GENERATOR MATCHES "(Ninja|Unix Makefiles)")
run_cmake_target(genex_DEVICE_LINK host_link_options LinkOptions_host_link_options --config Release ${VERBOSE})
@@ -36,7 +36,6 @@ if (CMake_TEST_CUDA)
target_link_options(LinkOptions_CMP0105_OLD PRIVATE $<DEVICE_LINK:${pre}BADFLAG_DEVICE_LINK${obj}>)
cmake_policy(SET CMP0105 NEW)
add_executable(LinkOptions_CMP0105_NEW LinkOptionsDevice.cu)
set_property(TARGET LinkOptions_CMP0105_NEW PROPERTY CUDA_SEPARABLE_COMPILATION ON)
target_link_options(LinkOptions_CMP0105_NEW PRIVATE $<DEVICE_LINK:${pre}BADFLAG_DEVICE_LINK${obj}>)
@@ -45,7 +44,6 @@ if (CMake_TEST_CUDA)
set_property(TARGET LinkOptions_device PROPERTY CUDA_SEPARABLE_COMPILATION ON)
target_link_options(LinkOptions_device PRIVATE $<DEVICE_LINK:${pre}BADFLAG_DEVICE_LINK${obj}>
$<HOST_LINK:${pre}BADFLAG_NORMAL_LINK${obj}>)
add_executable(LinkOptions_host_link_options LinkOptionsDevice.cu)
set_property(TARGET LinkOptions_host_link_options PROPERTY CUDA_SEPARABLE_COMPILATION ON)
if(CMake_TEST_CUDA STREQUAL "NVIDIA")
@@ -57,4 +55,8 @@ if (CMake_TEST_CUDA)
add_executable(LinkOptions_no_device LinkOptionsDevice.cu)
target_link_options(LinkOptions_no_device PRIVATE $<DEVICE_LINK:${pre}BADFLAG_DEVICE_LINK${obj}>
$<HOST_LINK:${pre}BADFLAG_NORMAL_LINK${obj}>)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake"
"set(CMAKE_CUDA_COMPILER_HAS_DEVICE_LINK_PHASE \"${CMAKE_CUDA_COMPILER_HAS_DEVICE_LINK_PHASE}\")\n"
)
endif()
@@ -1,4 +1,4 @@
^CMake Error at .*/Tests/RunCMake/try_compile/CudaStandard-build/CMakeFiles/CMake(Tmp|Scratch/TryCompile-[^/]+)/CMakeLists\.txt:[0-9]+ \(add_executable\):
^CMake Error at .*/Tests/RunCMake/try_compile/CudaStandard-build/CMakeFiles/CMake(Tmp|Scratch/TryCompile-[^/]+)/CMakeLists\.txt:[0-9]+ \(.*\):
CUDA_STANDARD is set to invalid value '4'
+
CMake Error at CudaStandard\.cmake:[0-9]+ \(try_compile\):