Fix and add test for cmake config install rules.
Needed to move some bits around to be able to include GNUInstallDirs,
and along the way all of the compiler hacks got moved into their own
file.
ADD
cmake/ThrustCompilerHacks.cmake
+# Set up compiler paths and apply temporary hacks to support NVC++ (Feta).
+# This file must be included before enabling any languages.
+
+# Temporary hacks to make Feta work; this requires you to define
+# `CMAKE_CUDA_COMPILER_ID=Feta` and `CMAKE_CUDA_COMPILER_FORCED`.
+if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}")
+ # If using Feta, don't set CXX compiler
+ if (NOT "${CMAKE_CXX_COMPILER}" STREQUAL "")
+ unset(CMAKE_CXX_COMPILER CACHE)
+ message(FATAL_ERROR "You are using Feta as your CUDA C++ compiler, but have"
+ " specified a different ISO C++ compiler; Feta acts as both, so please"
+ " unset the CMAKE_CXX_COMPILER variable."
+ )
+ endif()
+
+ # We don't set CMAKE_CUDA_HOST_COMPILER for Feta; if we do, CMake tries to
+ # pass `-ccbin ${CMAKE_CUDA_HOST_COMPILER}` to Feta, which it doesn't
+ # understand.
+ if (NOT "${CMAKE_CUDA_HOST_COMPILER}" STREQUAL "")
+ unset(CMAKE_CUDA_HOST_COMPILER CACHE)
+ message(FATAL_ERROR "You are using Feta as your CUDA C++ compiler, but have"
+ " specified a different host ISO C++ compiler; Feta acts as both, so"
+ " please unset the CMAKE_CUDA_HOST_COMPILER variable."
+ )
+ endif()
+
+ set(CMAKE_CXX_COMPILER "${CMAKE_CUDA_COMPILER}")
+ set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -stdpar")
+ set(CMAKE_CUDA_HOST_LINK_LAUNCHER "${CMAKE_CUDA_COMPILER}")
+ set(CMAKE_CUDA_LINK_EXECUTABLE
+ "<CMAKE_CUDA_HOST_LINK_LAUNCHER> ${CMAKE_CUDA_FLAGS} <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
+endif ()
+
+# We don't set CMAKE_CUDA_HOST_COMPILER for Feta; if we do, CMake tries to
+# pass `-ccbin ${CMAKE_CUDA_HOST_COMPILER}` to Feta, which it doesn't
+# understand.
+if ((NOT "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}"))
+ if (NOT ("${CMAKE_CUDA_HOST_COMPILER}" STREQUAL "" OR
+ "${CMAKE_CUDA_HOST_COMPILER}" STREQUAL "${CMAKE_CXX_COMPILER}"))
+ set(tmp "${CMAKE_CUDA_HOST_COMPILER}")
+ unset(CMAKE_CUDA_HOST_COMPILER CACHE)
+ message(FATAL_ERROR
+ "For convenience, Thrust's test harness uses CMAKE_CXX_COMPILER for the "
+ "CUDA host compiler. Refusing to overwrite specified "
+ "CMAKE_CUDA_HOST_COMPILER -- please reconfigure without setting this "
+ "variable. Currently:\n"
+ "CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\n"
+ "CMAKE_CUDA_HOST_COMPILER=${tmp}"
+ )
+ endif ()
+ set(CMAKE_CUDA_HOST_COMPILER "${CMAKE_CXX_COMPILER}")
+endif ()
+
+# Temporary hacks to make Feta work; this requires you to define
+# `CMAKE_CUDA_COMPILER_ID=Feta` and `CMAKE_CUDA_COMPILER_FORCED`.
+if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}")
+ # Need 3.17 for the properties used below.
+ cmake_minimum_required(VERSION 3.17)
+
+ set(CMAKE_CUDA_STANDARD_DEFAULT 03)
+
+ set(CMAKE_CUDA03_STANDARD_COMPILE_OPTION "-std=c++03")
+ set(CMAKE_CUDA03_EXTENSION_COMPILE_OPTION "-std=c++03")
+ set(CMAKE_CUDA03_STANDARD__HAS_FULL_SUPPORT TRUE)
+ set_property(GLOBAL PROPERTY CMAKE_CUDA03_KNOWN_FEATURES)
+
+ set(CMAKE_CUDA11_STANDARD_COMPILE_OPTION "-std=c++11")
+ set(CMAKE_CUDA11_EXTENSION_COMPILE_OPTION "-std=c++11")
+ set(CMAKE_CUDA11_STANDARD__HAS_FULL_SUPPORT TRUE)
+ set_property(GLOBAL PROPERTY CMAKE_CUDA11_KNOWN_FEATURES)
+
+ set(CMAKE_CUDA14_STANDARD_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_CUDA14_EXTENSION_COMPILE_OPTION "-std=c++14")
+ set(CMAKE_CUDA14_STANDARD__HAS_FULL_SUPPORT TRUE)
+ set_property(GLOBAL PROPERTY CMAKE_CUDA14_KNOWN_FEATURES)
+
+ set(CMAKE_CUDA17_STANDARD_COMPILE_OPTION "-std=c++17")
+ set(CMAKE_CUDA17_EXTENSION_COMPILE_OPTION "-std=c++17")
+ set(CMAKE_CUDA17_STANDARD__HAS_FULL_SUPPORT TRUE)
+ set_property(GLOBAL PROPERTY CMAKE_CUDA17_KNOWN_FEATURES)
+
+ cmake_record_cuda_compile_features()
+
+ set(CMAKE_CUDA_COMPILE_FEATURES
+ ${CMAKE_CUDA03_COMPILE_FEATURES}
+ ${CMAKE_CUDA11_COMPILE_FEATURES}
+ ${CMAKE_CUDA14_COMPILE_FEATURES}
+ ${CMAKE_CUDA17_COMPILE_FEATURES}
+ ${CMAKE_CUDA20_COMPILE_FEATURES}
+ )
+endif ()

ADD
testing/cmake/CMakeLists.txt
+thrust_update_system_found_flags()
+
+if (THRUST_CPP_FOUND AND THRUST_CUDA_FOUND)
+ # Test that we can use `find_package` on an installed Thrust:
+ add_test(
+ NAME thrust.test.cmake.test_install
+ COMMAND "${CMAKE_COMMAND}"
+ --log-level=VERBOSE
+ -G "${CMAKE_GENERATOR}"
+ -S "${CMAKE_CURRENT_SOURCE_DIR}/test_install"
+ -B "${CMAKE_CURRENT_BINARY_DIR}/test_install"
+ -D "THRUST_BINARY_DIR=${Thrust_BINARY_DIR}"
+ -D "CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
+ -D "CMAKE_CUDA_COMPILER=${CMAKE_CUDA_COMPILER}"
+ -D "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
+ )
+endif()

ADD
testing/cmake/test_install/CMakeLists.txt
+# Test that an installation of the project can be located by find_package() call
+# with appropriate prefix settings.
+#
+# Expects THRUST_BINARY_DIR to be set to an existing thrust build directory.
+
+cmake_minimum_required(VERSION 3.15)
+
+project(ThrustTestInstall CXX CUDA)
+
+# This will eventually get deleted recursively -- keep that in mind if modifying
+set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/install_prefix/")
+
+function(do_manual_install)
+ # Inspired by the VTK-m install tests, we can just glob up all of the
+ # cmake_install.cmake, include (ie. run) them, and they'll effectively
+ # install the project into the current value of CMAKE_INSTALL_PREFIX.
+
+ # Gather all of the install files from Thrust's root:
+ file(GLOB_RECURSE install_files
+ LIST_DIRECTORIES False
+ "${THRUST_BINARY_DIR}/cmake_install.cmake"
+ )
+
+ message(STATUS "Locating install files...")
+ foreach (install_file IN LISTS install_files)
+ message(STATUS " * ${install_file}")
+ endforeach()
+
+ message(STATUS "Building install tree...")
+ foreach(install_file IN LISTS install_files)
+ include("${install_file}")
+ endforeach()
+endfunction()
+
+function(do_cleanup)
+ message(STATUS "Removing ${CMAKE_INSTALL_PREFIX}")
+ file(REMOVE_RECURSE "${CMAKE_INSTALL_PREFIX}")
+endfunction()
+
+function(assert_boolean var_name expect)
+ if (expect)
+ if (NOT ${var_name})
+ message(FATAL_ERROR "'${var_name}' is false, expected true.")
+ endif()
+ else()
+ if (${var_name})
+ message(FATAL_ERROR "'${var_name}' is true, expected false.")
+ endif()
+ endif()
+endfunction()
+
+function(assert_target target_name)
+ if (NOT TARGET "${target_name}")
+ message(FATAL_ERROR "Target '${target_name}' not defined.")
+ endif()
+endfunction()
+
+function(find_installed_project)
+ set(CMAKE_PREFIX_PATH "${CMAKE_INSTALL_PREFIX}")
+ find_package(Thrust CONFIG COMPONENTS CPP CUDA)
+
+ if (NOT Thrust_FOUND)
+ message(FATAL_ERROR
+ "find_package(Thrust) failed. "
+ "CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}"
+ )
+ endif()
+
+ # Test some internal config vars to check that this is the expected install:
+ # TODO The cmake_path (3.19) command will provide more robust ways to do this
+
+ # Escape regex special characters in the install prefix, see
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/18580
+ string(REGEX REPLACE "([][+.*()^])" "\\\\\\1"
+ prefix_regex
+ "${CMAKE_INSTALL_PREFIX}"
+ )
+ if (NOT _THRUST_INCLUDE_DIR MATCHES "^${prefix_regex}")
+ message(FATAL_ERROR
+ "Found Thrust in unexpected location: "
+ " * _THRUST_INCLUDE_DIR=${_THRUST_INCLUDE_DIR} "
+ " * ExpectedPrefix=${CMAKE_INSTALL_DIR}"
+ )
+ endif()
+ if (NOT _CUB_INCLUDE_DIR MATCHES "^${prefix_regex}")
+ message(FATAL_ERROR
+ "Found CUB in unexpected location: "
+ " * _CUB_INCLUDE_DIR=${_CUB_INCLUDE_DIR} "
+ " * ExpectedPrefix=${CMAKE_INSTALL_DIR}"
+ )
+ endif()
+
+ thrust_create_target(Thrust)
+ assert_target(Thrust)
+ assert_target(CUB::CUB)
+ assert_target(Thrust::CPP::Host)
+ assert_target(Thrust::CUDA::Device)
+
+ thrust_update_system_found_flags()
+ assert_boolean(THRUST_CPP_FOUND TRUE)
+ assert_boolean(THRUST_CUDA_FOUND TRUE)
+ assert_boolean(THRUST_OMP_FOUND FALSE)
+ assert_boolean(THRUST_TBB_FOUND FALSE)
+
+endfunction()
+
+do_cleanup() # Prepare for new installation
+do_manual_install()
+find_installed_project()
+do_cleanup() # Clean up if successful

MODIFY
thrust/cmake/thrust-config-version.cmake
thrust/cmake/thrust-config-version.cmake
# Parse version information from version.h:
-file(READ "${CMAKE_CURRENT_LIST_DIR}/../../../include/thrust/version.h" THRUST_VERSION_HEADER)
+unset(_THRUST_VERSION_INCLUDE_DIR CACHE) # Clear old result to force search
+find_path(_THRUST_VERSION_INCLUDE_DIR thrust/version.h
+ NO_DEFAULT_PATH # Only search explicit paths below:
+ PATHS
+ ${CMAKE_CURRENT_LIST_DIR}/../.. # Source tree
+ ${CMAKE_CURRENT_LIST_DIR}/../../../include # Install tree
+)
+file(READ "${_THRUST_VERSION_INCLUDE_DIR}/thrust/version.h" THRUST_VERSION_HEADER)
string(REGEX MATCH "#define[ \t]+THRUST_VERSION[ \t]+([0-9]+)" DUMMY "${THRUST_VERSION_HEADER}")
set(THRUST_VERSION_FLAT ${CMAKE_MATCH_1})
# Note that Thrust calls this the PATCH number, CMake calls it the TWEAK number:

MODIFY
thrust/cmake/thrust-config.cmake
thrust/cmake/thrust-config.cmake
@@ -497,7 +497,7 @@ macro(_thrust_find_CUDA required)
NO_DEFAULT_PATH # Only check the explicit HINTS below:
HINTS
"${_THRUST_INCLUDE_DIR}/dependencies/cub" # Source layout
- "${_THRUST_INCLUDE_DIR}" # Install layout
+ "${_THRUST_INCLUDE_DIR}/.." # Install layout
)
if (TARGET CUB::CUB)
@@ -624,11 +624,11 @@ set(_THRUST_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "Location of th
# Internal target that actually holds the Thrust interface. Used by all other Thrust targets.
if (NOT TARGET Thrust::Thrust)
_thrust_declare_interface_alias(Thrust::Thrust _Thrust_Thrust)
- # Strip out the 'thrust/cmake/' from '[thrust_include_path]/thrust/cmake/':
- get_filename_component(_THRUST_INCLUDE_DIR "../../../include" ABSOLUTE BASE_DIR "${_THRUST_CMAKE_DIR}")
- set(_THRUST_INCLUDE_DIR "${_THRUST_INCLUDE_DIR}"
- CACHE INTERNAL "Location of thrust headers."
+ # Pull in the include dir detected by thrust-config-version.cmake
+ set(_THRUST_INCLUDE_DIR "${_THRUST_VERSION_INCLUDE_DIR}"
+ CACHE INTERNAL "Location of Thrust headers."
)
+ unset(_THRUST_VERSION_INCLUDE_DIR CACHE) # Clear tmp variable from cache
target_include_directories(_Thrust_Thrust INTERFACE "${_THRUST_INCLUDE_DIR}")
thrust_debug_target(Thrust::Thrust "${THRUST_VERSION}" internal)
endif()

Fix and add test for cmake config install rules.

Needed to move some bits around to be able to include GNUInstallDirs,
and along the way all of the compiler hacks got moved into their own
file.