Thrust allows for one to specify different backends at cmake configure time via the THRUST_DEVICE_SYSTEM
flag. My problem is that I have a bunch of .cu
files that I want to be compiled as regular c++ files when a user runs cmake with -DTHRUST_DEVICE_SYSTEM=OMP
(for example). If I change the extension of the .cu
files to .cpp
they compile fine (indicating that I just need tell cmake to use the c++ compiler on the .cu
files). But if I add .cu
to CMAKE_CXX_SOURCE_FILE_EXTENSIONS
then I get a CMake Error: Cannot determine link language for target "cuda_kernels"
. Here's a minimal cmake example:
cmake_minimum_required(VERSION 3.19)
project(kernels LANGUAGES C CXX Fortran)
set(KERNELS_USE_OMP OFF)
if ("${THRUST_DEVICE_SYSTEM}" STREQUAL "OMP")
set(KERNELS_USE_OMP ON)
endif()
# verify CUDA support
include(CheckLanguage)
check_language(CUDA)
if (CMAKE_CUDA_COMPILER AND NOT KERNELS_USE_OMP)
enable_language(CUDA)
else()
list(PREPEND CMAKE_CXX_SOURCE_FILE_EXTENSIONS "cu;CU")
endif()
message(STATUS "${CMAKE_CXX_SOURCE_FILE_EXTENSIONS}")
find_package(Thrust REQUIRED CONFIG)
thrust_create_target(Thrust FROM_OPTIONS)
add_library(cuda_kernels my_kernels.cu)
target_link_libraries(cuda_kernels Thrust)
The output of the message
command on my system is: -- cu;CU;C;M;c++;cc;cpp;cxx;mm;mpp;CPP;ixx;cppm
Why is cmake not respecting my CMAKE_CXX_SOURCE_FILE_EXTENSIONS
changes?
Why is cmake not respecting my
CMAKE_CXX_SOURCE_FILE_EXTENSIONS
changes?
The extension-to-language for <LANG>
is set as soon as <LANG>
is enabled by inspecting the value of the CMAKE_<LANG>_SOURCE_FILE_EXTENSIONS
variable when the language detection module exits.
Unfortunately, there is no blessed way to override this list for CXX
as it is hard-coded in Modules/CMakeCXXCompiler.cmake.in
.
Perhaps the best way of working around the actual error would be to use the LANGUAGE
source file property to tell CMake how to compile the individual CUDA files, like so:
cmake_minimum_required(VERSION 3.19)
project(kernels LANGUAGES CXX)
find_package(Thrust REQUIRED)
thrust_create_target(Thrust FROM_OPTIONS)
thrust_is_cuda_system_found(USE_CUDA)
if (USE_CUDA)
enable_language(CUDA)
endif()
set(cuda_kernel_sources my_kernels.cu)
add_library(cuda_kernels ${cuda_kernel_sources})
target_link_libraries(cuda_kernels PRIVATE Thrust)
if (NOT USE_CUDA)
set_source_files_properties(
${cuda_kernel_sources}
PROPERTIES
LANGUAGE CXX
)
endif ()
This will certainly be friendlier to other projects that might try to add_subdirectory
yours.
However, if we want to be very naughty, we can do this:
cmake_minimum_required(VERSION 3.19)
project(kernels LANGUAGES NONE)
###
# Hacky language extension override
function(add_cuda_extensions variable access value current_list_file stack)
if (NOT cu IN_LIST value)
list(PREPEND "${variable}" "cu" "CU")
set("${variable}" "${${variable}}" PARENT_SCOPE)
endif ()
endfunction()
# verify CUDA support
include(CheckLanguage)
check_language(CUDA)
if (CMAKE_CUDA_COMPILER AND NOT THRUST_DEVICE_SYSTEM STREQUAL "OMP")
enable_language(CUDA)
enable_language(CXX)
else()
variable_watch(CMAKE_CXX_SOURCE_FILE_EXTENSIONS add_cuda_extensions)
enable_language(CXX)
endif()
###
# Normal project code starts here
message(STATUS "${CMAKE_CXX_SOURCE_FILE_EXTENSIONS}")
find_package(Thrust REQUIRED)
thrust_create_target(Thrust FROM_OPTIONS)
add_library(cuda_kernels my_kernels.cu)
target_link_libraries(cuda_kernels PRIVATE Thrust)
This waits for the platform module to try to write CMAKE_CXX_SOURCE_FILE_EXTENSIONS
and then any time it's accessed, quickly inserts the cu
and CU
extensions to the list.