CMake CUDA opinions

This is a cross post from the CUDA discourse, it was suggested that I ask here instead.

I have a repository that is structured in this way, following the example from ModernCMake - Extended example. I’m replacing with ... extra information.

├── apps
│   ├── CMakeLists.txt
│   └── main.cpp
├── CMakeLists.txt
├── include
│   └── cuda_path_tracer
│       ├── error.cuh
│       ├── image.hpp
│       ...
├── Makefile
├── src
│   ├── CMakeLists.txt
│   ├── error.cu
│   ├── image.cpp
│   ...
└── tests
    ├── CMakeLists.txt
    ├── test_error.cpp
    ...

Can somebody help me figure out if I’m doing things correctly in the CMake configuration? I seem to keep getting errors and never seem to get to a configuration that just works. At the moment it compiles and runs fine with nvcc, but with clang++ it throws some

clang++-20: error: no such file or directory: 'CUDA'
clang++-20: error: no such file or directory: 'devices'
clang++-20: error: no such file or directory: 'found.'
clang++-20: error: no such file or directory: 'CUDA'
clang++-20: error: no such file or directory: 'devices'
clang++-20: error: no such file or directory: 'found.'
clang++-20: warning: CUDA version 12.6 is only partially supported [-Wunknown-cuda-version]
clang++-20: error: unsupported CUDA gpu architecture: sm_No

I’m compiling the project with the following commands:

CC := cmake
override FLAGS := -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
	-DCMAKE_CUDA_COMPILER=clang++-20 \
	-DCMAKE_CXX_COMPILER=clang++-20 \
	-DCMAKE_CUDA_ARCHITECTURES=native
# override FLAGS := -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
# 	-DCMAKE_CUDA_COMPILER=nvcc \
# 	-DCMAKE_CXX_COMPILER=g++
TARGET := cuda_path_tracer

.PHONY: build run clean test

build:
	$(CC) -S . -B build $(FLAGS)
	$(CC) --build build

test: build
	./build/tests/tests

run: build
	./build/apps/$(TARGET)

clean:
	rm -rf *build* 

my root CMakeList.txt is

cmake_minimum_required(VERSION 3.27...3.31)

if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
  set(CMAKE_CUDA_ARCHITECTURES 90)
endif()

project(
    cuda_path_tracer
    VERSION 1.0
    LANGUAGES CXX CUDA
)

# Only set these properties if this is the main project, not included as a library
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
    set(CMAKE_CXX_EXTENSIONS OFF)
    set_property(GLOBAL PROPERTY USE_FOLDERS ON)
    include(CTest)
endif()

include(FetchContent)

add_subdirectory(src)
add_subdirectory(apps)

if((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR CUDA_PATH_TRACER_CMAKE_BUILD_TESTING)
    AND BUILD_TESTING)
    add_subdirectory(tests)
endif()

the one in the src folder is

set(HEADER_LIST
    "${cuda_path_tracer_SOURCE_DIR}/include/cuda_path_tracer/error.cuh"
    "${cuda_path_tracer_SOURCE_DIR}/include/cuda_path_tracer/image.hpp"
    ...
)

add_library(cuda_path_tracer_lib
    error.cu
    image.cpp
    ...
    ${HEADER_LIST}
)

target_include_directories(cuda_path_tracer_lib
    PUBLIC
    ${CMAKE_SOURCE_DIR}/include
    ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES} 
)

target_compile_features(cuda_path_tracer_lib PUBLIC cxx_std_20)

set_target_properties(cuda_path_tracer_lib
    PROPERTIES
    CUDA_SEPARABLE_COMPILATION ON
    CUDA_RESOLVE_DEVICE_SYMBOLS ON
)

source_group(
    TREE "${PROJECT_SOURCE_DIR}/include"
    PREFIX "Header Files"
    FILES ${HEADER_LIST}
)

The one in the apps is

add_executable(cuda_path_tracer main.cpp)

set_target_properties(cuda_path_tracer
    PROPERTIES
    CUDA_SEPARABLE_COMPILATION ON
    CUDA_RESOLVE_DEVICE_SYMBOLS ON
)

target_compile_features(cuda_path_tracer PRIVATE cxx_std_20)

target_link_libraries(cuda_path_tracer PRIVATE cuda_path_tracer_lib)

while the one in tests is:

FetchContent_Declare(
  Catch2
  GIT_REPOSITORY https://github.com/catchorg/Catch2.git
  GIT_TAG v3.7.1
)

FetchContent_MakeAvailable(Catch2)

add_executable(tests
  test_error.cpp
  ...
)

include(Catch)

catch_discover_tests(tests)

set_target_properties(tests
  PROPERTIES
  CUDA_SEPARABLE_COMPILATION ON
)

target_compile_features(tests PRIVATE cxx_std_20)

target_link_libraries(tests PRIVATE cuda_path_tracer_lib Catch2::Catch2WithMain)

add_test(NAME test_all COMMAND tests)

Is there something that I’m doing wrong/that can be improved? Initially I had CUDA_ARCHITECTURES defined in the set_target_properties of the inner CMakeList.txt, but this lead to correct compilation both with nvcc and clang++ but errors at runtime due to library linkage issues.

I’m sorry if it’s such an open-ended question, but I’m new to CMake and I want to learn it right