Skip to content

Commit 20e776c

Browse files
committed
Remove CMake < 3.18 support and modernise CMake
CMake < 3.18 was already deprecated as 3.18 is required for c++17 CUDA + Updates the readme version requirements + Updates CMake Minimum required statements + Removes workarounds for old CMake versions + Use FindCUDAToolkit now it is always available + Switch to linking against the shared cuda runtime library, rather than implicit default of static on some platforms + Create INTERFACE library targets for header only libraries. This enforces the use of SYSTEM on includes + Create ALIAS library targets for 3rd party dependencies, for consistency + Stops the modification of CMAKE_<LANGUAGE>_FLAGS which is poor form + Switches from global defines/includes/links to per-target through the use of target specific functions + Ensure packages are available where they are used + Prevent in-source CMake builds + Use PUBLIC/INTERFACE/PRIVATE for link libraries etc. This may currently be excessivly public + Inherit visualisation dependency from target, required vis repo update. + Cmake organisation + Adjusts swig/python CMake to re-use components from elsewhere more + This file could do with work still + Misc other CMake changes
1 parent 9c24720 commit 20e776c

34 files changed

+733
-637
lines changed

CMakeLists.txt

+8-10
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
# CMake 3.15+ for Thrust/Cub support
2-
cmake_minimum_required(VERSION VERSION 3.15 FATAL_ERROR)
1+
# Minimum CMake version 3.18 for CUDA --std=c++17
2+
cmake_minimum_required(VERSION VERSION 3.18 FATAL_ERROR)
33

4-
# Emit a deprecation warning if CMAKE < 3.18 which is required for c++17 in the future.
5-
set(CMAKE_MINIMUM_SUPPORTED_VERSION 3.18)
6-
if(${CMAKE_VERSION} VERSION_LESS ${CMAKE_MINIMUM_SUPPORTED_VERSION})
7-
message(DEPRECATION "Support for CMake < ${CMAKE_MINIMUM_SUPPORTED_VERSION} is deprecated and will be removed in a future release.")
8-
endif()
4+
project(FLAMEGPU LANGUAGES NONE)
95

6+
# Find the root directory
7+
get_filename_component(FLAMEGPU_ROOT ${CMAKE_CURRENT_SOURCE_DIR} REALPATH)
108

11-
project(FLAMEGPU LANGUAGES NONE)
9+
# Ensure this is not an in-source build
10+
include(${FLAMEGPU_ROOT}/cmake/OutOfSourceOnly.cmake)
1211

1312
# Don't create installation scripts (and hide CMAKE_INSTALL_PREFIX from cmake-gui)
1413
set(CMAKE_SKIP_INSTALL_RULES TRUE)
@@ -69,8 +68,7 @@ endif()
6968
# If CUDA is not available, or the minimum version is too low only build the docs.
7069
if(DOCUMENTATION_ONLY_BUILD)
7170
# Not able to build code, so just make docs
72-
get_filename_component(FLAMEGPU_ROOT ${CMAKE_CURRENT_SOURCE_DIR} REALPATH)
73-
include(./cmake/doxygen.cmake)
71+
include(./cmake/dependencies/doxygen.cmake)
7472
if(${BUILD_API_DOCUMENTATION})
7573
create_doxygen_target("${FLAMEGPU_ROOT}" "${CMAKE_CURRENT_BINARY_DIR}" "")
7674
endif()

README.md

-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ This is used to build the FLAMEGPU2 library, examples, tests and documentation.
5555
Building FLAME GPU has the following requirements. There are also optional dependencies which are required for some components, such as Documentation or Python bindings.
5656

5757
+ [CMake](https://cmake.org/download/) `>= 3.18`
58-
+ CMake `>= 3.15` currently works, but support will be dropped in a future release.
5958
+ [CUDA](https://developer.nvidia.com/cuda-downloads) `>= 11.0` and a [Compute Capability](https://developer.nvidia.com/cuda-gpus) `>= 3.5` NVIDIA GPU.
6059
+ CUDA `>= 10.0` currently works, but support will be dropped in a future release.
6160
+ C++17 capable C++ compiler (host), compatible with the installed CUDA version

cmake/OutOfSourceOnly.cmake

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Define a cmake function which emits a fatal error if the source directory and binary directory are the same.
2+
function(EnforceOutOfSourceBuilds)
3+
# Resolve paths before comparioson to ensure comparions are accurate
4+
get_filename_component(source_dir "${CMAKE_SOURCE_DIR}" REALPATH)
5+
get_filename_component(binary_dir "${CMAKE_BINARY_DIR}" REALPATH)
6+
7+
if("${source_dir}" STREQUAL "${binary_dir}")
8+
message(FATAL_ERROR
9+
" In-source CMake builds are not allowed.\n"
10+
" Use a build directory i.e. cmake -B build.\n"
11+
" You may have to clear/delete the generated CMakeCache.txt and CMakeFiles/:\n"
12+
" ${binary_dir}/CMakeCache.txt\n"
13+
" ${binary_dir}/CMakeFiles/\n")
14+
endif()
15+
endfunction()
16+
17+
# Call the function imediately, so the file only needs to be included.
18+
EnforceOutOfSourceBuilds()
19+

cmake/common.cmake

+130-266
Large diffs are not rendered by default.

cmake/cuda_arch.cmake

+123-109
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,134 @@
1-
# Build a list of gencode arguments, based on CUDA verison.
2-
# Accepts user override via CUDA_ARCH
3-
4-
# CMAKE > 3.18 introduces CUDA_ARCHITECTURES as a cmake-native way of generating gencodes (Policy CMP0104). Set the value to OFF to prevent errors for it being not provided.
5-
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.18")
6-
set(CMAKE_CUDA_ARCHITECTURES "OFF")
7-
endif()
8-
9-
10-
# Check if any have been provided by the users
11-
string(LENGTH "${CUDA_ARCH}" CUDA_ARCH_LENGTH)
12-
13-
# Define the default compute capabilites incase not provided by the user
14-
set(DEFAULT_CUDA_ARCH "35;50;60;70;80;")
15-
16-
# Get the valid options for the current compiler.
17-
# Run nvcc --help to get the help string which contains all valid compute_ sm_ for that version.
18-
execute_process(COMMAND ${CMAKE_CUDA_COMPILER} "--help" OUTPUT_VARIABLE NVCC_HELP_STR ERROR_VARIABLE NVCC_HELP_STR)
19-
# Match all comptue_XX or sm_XXs
20-
string(REGEX MATCHALL "'(sm|compute)_[0-9]+'" SUPPORTED_CUDA_ARCH "${NVCC_HELP_STR}" )
21-
# Strip just the numeric component
22-
string(REGEX REPLACE "'(sm|compute)_([0-9]+)'" "\\2" SUPPORTED_CUDA_ARCH "${SUPPORTED_CUDA_ARCH}" )
23-
# Remove dupes and sort to build the correct list of supported CUDA_ARCH.
24-
list(REMOVE_DUPLICATES SUPPORTED_CUDA_ARCH)
25-
list(REMOVE_ITEM SUPPORTED_CUDA_ARCH "")
26-
list(SORT SUPPORTED_CUDA_ARCH)
27-
28-
# Update defaults to only be those supported
29-
# @todo might be better to instead do a dry run compilation with each gencode to validate?
30-
foreach(ARCH IN LISTS DEFAULT_CUDA_ARCH)
31-
if (NOT ARCH IN_LIST SUPPORTED_CUDA_ARCH)
32-
list(REMOVE_ITEM DEFAULT_CUDA_ARCH "${ARCH}")
1+
# Provides a per target function to set gencode compiler options.
2+
# Function to suppress compiler warnings for a given target
3+
# If the cmake variable CUDA_ARCH is set, to a non emtpy list or space separated string this will be used instead.
4+
# @todo - find a way to warn about deprecated architectures once and only once (at cmake time?) Might need to just try compiling with old warnings and capture / post process the output.
5+
# @todo - figure out how to do this once and only once as a function rather than a macro.
6+
macro(SetCUDAGencodes)
7+
# @todo - only get the available gencodes from nvcc once, rather than per target.
8+
9+
# Parse the expected arguments, prefixing variables.
10+
cmake_parse_arguments(
11+
SCG
12+
""
13+
"TARGET"
14+
""
15+
${ARGN}
16+
)
17+
# Ensure that a target has been passed, and that it is a valid target.
18+
if(NOT SCG_TARGET)
19+
message( FATAL_ERROR "SetCUDAGencodes: 'TARGET' argument required." )
20+
elseif(NOT TARGET ${SCG_TARGET} )
21+
message( FATAL_ERROR "SetCUDAGencodes: TARGET '${SCG_TARGET}' is not a valid target" )
3322
endif()
34-
list(REMOVE_DUPLICATES CUDA_ARCH)
35-
list(REMOVE_ITEM CUDA_ARCH "")
36-
list(SORT CUDA_ARCH)
37-
endforeach()
3823

39-
40-
if(NOT CUDA_ARCH_LENGTH EQUAL 0)
41-
# Convert user provided string argument to a list.
42-
string (REPLACE " " ";" CUDA_ARCH "${CUDA_ARCH}")
43-
string (REPLACE "," ";" CUDA_ARCH "${CUDA_ARCH}")
44-
45-
# Remove duplicates, empty items and sort.
46-
list(REMOVE_DUPLICATES CUDA_ARCH)
47-
list(REMOVE_ITEM CUDA_ARCH "")
48-
list(SORT CUDA_ARCH)
49-
50-
# Validate the list.
51-
foreach(ARCH IN LISTS CUDA_ARCH)
52-
if (NOT ARCH IN_LIST SUPPORTED_CUDA_ARCH)
53-
message(WARNING
54-
" CUDA_ARCH '${ARCH}' not supported by CUDA ${CMAKE_CUDA_COMPILER_VERSION} and is being ignored.\n"
55-
" Choose from: ${SUPPORTED_CUDA_ARCH}")
56-
list(REMOVE_ITEM CUDA_ARCH "${ARCH}")
57-
endif()
58-
endforeach()
59-
60-
# @todo - validate that the CUDA_ARCH provided are supported by the compiler
61-
endif()
62-
63-
# If the list is empty post validation, set it to the (validated) defaults
64-
list(LENGTH CUDA_ARCH CUDA_ARCH_LENGTH)
65-
if(CUDA_ARCH_LENGTH EQUAL 0)
66-
set(CUDA_ARCH ${DEFAULT_CUDA_ARCH})
67-
endif()
68-
69-
# Propagate the validated values to the parent scope, to reduce warning duplication.
70-
get_directory_property(hasParent PARENT_DIRECTORY)
71-
if(hasParent)
72-
set(CUDA_ARCH ${CUDA_ARCH} PARENT_SCOPE)
73-
endif()
74-
# If the list is somehow empty now, do not set any gencodes arguments, instead using the compiler defaults.
75-
list(LENGTH CUDA_ARCH CUDA_ARCH_LENGTH)
76-
if(NOT CUDA_ARCH_LENGTH EQUAL 0)
77-
# Only do this if required.I.e. CUDA_ARCH is the same as the last time this file was included
78-
if(NOT CUDA_ARCH_APPLIED EQUAL CUDA_ARCH)
79-
message(STATUS "Generating Compute Capabilities: ${CUDA_ARCH}")
24+
# CMAKE > 3.18 introduces CUDA_ARCHITECTURES as a cmake-native way of generating gencodes (Policy CMP0104). Set the value to OFF to prevent errors for it being not provided.
25+
# We manually set gencode arguments, so we can (potentially) use LTO and are not restricted to CMake's availble options.
26+
set_property(TARGET ${SCG_TARGET} PROPERTY CUDA_ARCHITECTURES OFF)
27+
28+
# Define the default compute capabilites incase not provided by the user
29+
set(DEFAULT_CUDA_ARCH "35;50;60;70;80;")
30+
31+
# Determine if the user has provided a non default CUDA_ARCH value
32+
string(LENGTH "${CUDA_ARCH}" CUDA_ARCH_LENGTH)
33+
34+
# Query NVCC in order to filter the provided list.
35+
# @todo only do this once, and re-use the output for a given cmake configure?
36+
37+
# Get the valid options for the current compiler.
38+
# Run nvcc --help to get the help string which contains all valid compute_ sm_ for that version.
39+
if(NOT DEFINED SUPPORTED_CUDA_ARCH)
40+
execute_process(COMMAND ${CMAKE_CUDA_COMPILER} "--help" OUTPUT_VARIABLE NVCC_HELP_STR ERROR_VARIABLE NVCC_HELP_STR)
41+
# Match all comptue_XX or sm_XXs
42+
string(REGEX MATCHALL "'(sm|compute)_[0-9]+'" SUPPORTED_CUDA_ARCH "${NVCC_HELP_STR}" )
43+
# Strip just the numeric component
44+
string(REGEX REPLACE "'(sm|compute)_([0-9]+)'" "\\2" SUPPORTED_CUDA_ARCH "${SUPPORTED_CUDA_ARCH}" )
45+
# Remove dupes and sort to build the correct list of supported CUDA_ARCH.
46+
list(REMOVE_DUPLICATES SUPPORTED_CUDA_ARCH)
47+
list(REMOVE_ITEM SUPPORTED_CUDA_ARCH "")
48+
list(SORT SUPPORTED_CUDA_ARCH)
49+
50+
# Store the supported arch's once and only once. This could be a cache var given the cuda compiler should not be able to change without clearing th cache?
51+
get_directory_property(hasParent PARENT_DIRECTORY)
8052
if(hasParent)
81-
set(CUDA_ARCH_APPLIED "${CUDA_ARCH}" PARENT_SCOPE )
53+
set(SUPPORTED_CUDA_ARCH ${SUPPORTED_CUDA_ARCH} PARENT_SCOPE)
8254
endif()
8355
endif()
84-
set(GENCODES_FLAGS)
85-
set(MIN_CUDA_ARCH)
86-
# Convert to gencode arguments
87-
88-
foreach(ARCH IN LISTS CUDA_ARCH)
89-
set(GENCODES_FLAGS "${GENCODES_FLAGS} -gencode arch=compute_${ARCH},code=sm_${ARCH}")
56+
57+
58+
# Update defaults to only be those supported
59+
# @todo might be better to instead do a dry run compilation with each gencode to validate?
60+
foreach(ARCH IN LISTS DEFAULT_CUDA_ARCH)
61+
if (NOT ARCH IN_LIST SUPPORTED_CUDA_ARCH)
62+
list(REMOVE_ITEM DEFAULT_CUDA_ARCH "${ARCH}")
63+
endif()
64+
list(REMOVE_DUPLICATES CUDA_ARCH)
65+
list(REMOVE_ITEM CUDA_ARCH "")
66+
list(SORT CUDA_ARCH)
9067
endforeach()
9168

92-
# Add the last arch again as compute_, compute_ to enable forward looking JIT
93-
list(GET CUDA_ARCH -1 LAST_ARCH)
94-
set(GENCODES_FLAGS "${GENCODES_FLAGS} -gencode arch=compute_${LAST_ARCH},code=compute_${LAST_ARCH}")
95-
96-
# Get the minimum device architecture to pass through to nvcc to enable graceful failure prior to cuda execution.
97-
list(GET CUDA_ARCH 0 MIN_CUDA_ARCH)
98-
99-
# Set the gencode flags on NVCC
100-
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} ${GENCODES_FLAGS}")
69+
if(NOT CUDA_ARCH_LENGTH EQUAL 0)
70+
# Convert user provided string argument to a list.
71+
string (REPLACE " " ";" CUDA_ARCH "${CUDA_ARCH}")
72+
string (REPLACE "," ";" CUDA_ARCH "${CUDA_ARCH}")
73+
74+
# Remove duplicates, empty items and sort.
75+
list(REMOVE_DUPLICATES CUDA_ARCH)
76+
list(REMOVE_ITEM CUDA_ARCH "")
77+
list(SORT CUDA_ARCH)
78+
79+
# Validate the list.
80+
foreach(ARCH IN LISTS CUDA_ARCH)
81+
if (NOT ARCH IN_LIST SUPPORTED_CUDA_ARCH)
82+
message(WARNING
83+
" CUDA_ARCH '${ARCH}' not supported by CUDA ${CMAKE_CUDA_COMPILER_VERSION} and is being ignored.\n"
84+
" Choose from: ${SUPPORTED_CUDA_ARCH}")
85+
list(REMOVE_ITEM CUDA_ARCH "${ARCH}")
86+
endif()
87+
endforeach()
88+
endif()
10189

102-
# Set the minimum arch flags for all compilers
103-
set(CMAKE_CC_FLAGS "${CMAKE_C_FLAGS} -DMIN_CUDA_ARCH=${MIN_CUDA_ARCH}")
104-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMIN_CUDA_ARCH=${MIN_CUDA_ARCH}")
105-
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -DMIN_CUDA_ARCH=${MIN_CUDA_ARCH}")
106-
else()
107-
message(STATUS "Generating default CUDA Compute Capabilities ${CUDA_ARCH}")
108-
endif()
10990

110-
# Supress deprecated architecture warnings, as they are not fitered out by checking against nvcc help.
111-
# Ideally a warning would be output once at config time (i.e. above) and not at every file compilation.
112-
# But this is challenging due to multiline string detection.
113-
# Could potentially compile a simple program, without this flag to detect if its valid/deprecated? Would likely increase build time.
114-
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
91+
# If the list is empty post validation, set it to the (validated) defaults
92+
list(LENGTH CUDA_ARCH CUDA_ARCH_LENGTH)
93+
if(CUDA_ARCH_LENGTH EQUAL 0)
94+
set(CUDA_ARCH ${DEFAULT_CUDA_ARCH})
95+
endif()
11596

116-
# If CUDA 11.2+, can build multiple architectures in parallel. Note this will be multiplicative against the number of threads launched for parallel cmake build, which may anger some systems.
117-
if(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "11.2" AND USE_NVCC_THREADS AND DEFINED NVCC_THREADS AND NVCC_THREADS GREATER_EQUAL 0)
118-
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --threads ${NVCC_THREADS}")
119-
endif()
97+
# Propagate the validated values to the parent scope, to reduce warning duplication.
98+
get_directory_property(hasParent PARENT_DIRECTORY)
99+
if(hasParent)
100+
set(CUDA_ARCH ${CUDA_ARCH} PARENT_SCOPE)
101+
endif()
120102

103+
# If the list is somehow empty now, do not set any gencodes arguments, instead using the compiler defaults.
104+
list(LENGTH CUDA_ARCH CUDA_ARCH_LENGTH)
105+
if(NOT CUDA_ARCH_LENGTH EQUAL 0)
106+
# Only do this if required.I.e. CUDA_ARCH is the same as the last time this file was included
107+
if(NOT CUDA_ARCH_APPLIED EQUAL CUDA_ARCH)
108+
message(STATUS "Generating Compute Capabilities: ${CUDA_ARCH}")
109+
if(hasParent)
110+
set(CUDA_ARCH_APPLIED "${CUDA_ARCH}" PARENT_SCOPE )
111+
endif()
112+
endif()
113+
set(MIN_CUDA_ARCH)
114+
# Convert to gencode arguments
115+
116+
foreach(ARCH IN LISTS CUDA_ARCH)
117+
target_compile_options(${SCG_TARGET} PRIVATE "$<$<COMPILE_LANGUAGE:CUDA>:SHELL:-gencode arch=compute_${ARCH}$<COMMA>code=sm_${ARCH}>")
118+
target_link_options(${SCG_TARGET} PRIVATE "$<DEVICE_LINK:SHELL:-gencode arch=compute_${ARCH}$<COMMA>code=sm_${ARCH}>")
119+
endforeach()
120+
121+
# Add the last arch again as compute_, compute_ to enable forward looking JIT
122+
list(GET CUDA_ARCH -1 LAST_ARCH)
123+
target_compile_options(${SCG_TARGET} PRIVATE "$<$<COMPILE_LANGUAGE:CUDA>:SHELL:-gencode arch=compute_${LAST_ARCH}$<COMMA>code=compute_${LAST_ARCH}>")
124+
target_link_options(${SCG_TARGET} PRIVATE "$<DEVICE_LINK:SHELL:-gencode arch=compute_${LAST_ARCH}$<COMMA>code=compute_${LAST_ARCH}>")
125+
126+
# Get the minimum device architecture to pass through to nvcc to enable graceful failure prior to cuda execution.
127+
list(GET CUDA_ARCH 0 MIN_CUDA_ARCH)
128+
129+
# Set the minimum arch flags for all compilers
130+
target_compile_definitions(${SCG_TARGET} PRIVATE -DMIN_CUDA_ARCH=${MIN_CUDA_ARCH})
131+
else()
132+
message(STATUS "Generating default CUDA Compute Capabilities ${CUDA_ARCH}")
133+
endif()
134+
endmacro()

cmake/cxxstd.cmake

+4-11
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,10 @@ if(NOT FLAMEGPU_CXX_STD)
33
# FLAME GPU is c++14, however due to MSVC 16.10 regressions we build as 17 if possible, else 14.
44
# 14 Support is still required (CUDA 10.x, swig?).
55
# Start by assuming both should be availble.
6+
# No need to check CMake version, as our minimum (3.18) supports CUDA c++17
67
set(CXX17_SUPPORTED ON)
7-
# CMake 3.18 adds CUDA CXX 17, 20
8-
# CMake 3.10 adds CUDA CXX 14
9-
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.18)
10-
# 17 OK
11-
elseif(CMAKE_VERSION VERSION_GREATER_EQUAL 3.10)
12-
# No need for deprecation warning here, already warning about CMAKE < 3.18 being deprecated elsewhere.
13-
set(CXX17_SUPPORTED OFF)
14-
else()
15-
message(FATAL_ERROR "CMAKE ${CMAKE_VERSION} does not support -std=c++14")
16-
endif()
8+
9+
# Check the CU
1710
# CUDA 11.0 adds CXX 17
1811
# CUDA 9.0 adds CXX 14
1912
if(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 11.0.0)
@@ -34,7 +27,7 @@ if(NOT FLAMEGPU_CXX_STD)
3427
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29)
3528
# 17 required.
3629
if(NOT CXX17_SUPPORTED)
37-
message(FATAL_ERROR "MSVC >= 19.29 requires CMake >= 3.18 and CUDA >= 11.0")
30+
message(FATAL_ERROR "MSVC >= 19.29 requires CUDA >= 11.0")
3831
endif()
3932
elseif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.11)
4033
# 17 available?

cmake/Jitify.cmake cmake/dependencies/Jitify.cmake

+4-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ FetchContent_GetProperties(jitify)
1919
if(NOT jitify_POPULATED)
2020
FetchContent_Populate(jitify)
2121
# Jitify is not a cmake project, so cannot use add_subdirectory, use custom find_package.
22-
set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};${jitify_SOURCE_DIR}/..")
23-
find_package(Jitify REQUIRED)
24-
# Include path is ${Jitify_INCLUDE_DIRS}
2522
endif()
23+
24+
set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};${jitify_SOURCE_DIR}/..")
25+
# Always find the package, even if jitify is already populated.
26+
find_package(Jitify REQUIRED)
File renamed without changes.

0 commit comments

Comments
 (0)