From 2c245d468cb21f6125a857f7a55a48453ca88959 Mon Sep 17 00:00:00 2001 From: Allison Vacanti Date: Thu, 21 May 2020 20:57:38 -0400 Subject: [PATCH] Enable multiconfig builds. See #1159. --- CMakeLists.txt | 432 ++------------------------------ cmake/ThrustHeaderTesting.cmake | 119 +++++++++ cmake/ThrustTargetConfig.cmake | 275 ++++++++++++++++++++ cmake/ThrustUtilities.cmake | 12 + cmake/common_variables.cmake | 2 +- cmake/header_test.in | 2 +- cmake/run_example.cmake | 2 +- cmake/wrap_source_file.cpp.in | 1 + examples/CMakeLists.txt | 105 ++++++++ testing/CMakeLists.txt | 151 +++++++++++ 10 files changed, 690 insertions(+), 411 deletions(-) create mode 100644 cmake/ThrustHeaderTesting.cmake create mode 100644 cmake/ThrustTargetConfig.cmake create mode 100644 cmake/ThrustUtilities.cmake create mode 100644 cmake/wrap_source_file.cpp.in create mode 100644 examples/CMakeLists.txt create mode 100644 testing/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index a4f1cf0985..f1243be478 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,9 @@ cmake_minimum_required(VERSION 3.10) project(Thrust NONE) -set(THRUST_SOURCE "${CMAKE_SOURCE_DIR}") include(cmake/common_variables.cmake) +include(cmake/ThrustUtilities.cmake) +include(cmake/ThrustTargetConfig.cmake) if ("" STREQUAL "${CMAKE_BUILD_TYPE}") set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build." FORCE) @@ -18,7 +19,7 @@ if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) set(CMAKE_CONFIGURE_DEPENDS CONFIGURE_DEPENDS) endif () -list(INSERT CMAKE_MODULE_PATH 0 "${PROJECT_SOURCE_DIR}/cmake") +list(INSERT CMAKE_MODULE_PATH 0 "${Thrust_SOURCE_DIR}/cmake") include(AppendOptionIfAvailable) # Please note this also sets the default for the CUDA C++ version; see the comment below. @@ -71,36 +72,14 @@ if (NOT "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") set(CMAKE_CUDA_HOST_COMPILER "${CMAKE_CXX_COMPILER}") endif () -set(THRUST_TARGET_FLAGS) -macro(add_flag_option flag docstring default) - set(opt "THRUST_${flag}") - option(${opt} "${docstring}" "${default}") - mark_as_advanced(${opt}) - if (${${opt}}) - list(APPEND THRUST_TARGET_FLAGS ${flag}) - endif() -endmacro() -add_flag_option(IGNORE_DEPRECATED_CPP_DIALECT "Don't warn about any deprecated C++ standards and compilers." OFF) -add_flag_option(IGNORE_DEPRECATED_CPP_11 "Don't warn about deprecated C++11." OFF) -add_flag_option(IGNORE_DEPRECATED_COMPILER "Don't warn about deprecated COMPILERS." OFF) -add_flag_option(IGNORE_CUB_VERSION_CHECK "Don't warn about mismatched CUB versions." OFF) - -# Use our find_package config to assemble the Thrust library components we need: -find_package(Thrust REQUIRED CONFIG - NO_DEFAULT_PATH # Only check the explicit HINTS below: - HINTS - "${CMAKE_CURRENT_LIST_DIR}" -) -thrust_create_target(Thrust FROM_OPTIONS ${THRUST_TARGET_FLAGS}) -thrust_debug_target(Thrust "${THRUST_VERSION}") - +thrust_build_target_list() thrust_update_system_found_flags() message(STATUS "CPP system found? ${THRUST_CPP_FOUND}") message(STATUS "CUDA system found? ${THRUST_CUDA_FOUND}") message(STATUS "TBB system found? ${THRUST_TBB_FOUND}") message(STATUS "OMP system found? ${THRUST_OMP_FOUND}") -if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") +if (THRUST_CUDA_FOUND) enable_language(CUDA) # Force CUDA C++ standard to be the same as the C++ standard used. @@ -189,7 +168,7 @@ if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") message("-- Enabled CUDA architectures:${COMPUTE_MESSAGE}") endif () -if ("TBB" STREQUAL "${THRUST_DEVICE_SYSTEM}") +if (THRUST_TBB_FOUND) # There's a ton of these in the TBB backend, even though the code is correct. # TODO: silence these warnings in code instead append_option_if_available("-Wno-unused-parameter" THRUST_CXX_WARNINGS) @@ -301,7 +280,7 @@ foreach (CXX_OPTION IN LISTS THRUST_CXX_WARNINGS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_OPTION}") endforeach () -if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") +if (THRUST_CUDA_FOUND) if ("NVIDIA" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") foreach (CXX_OPTION IN LISTS THRUST_CXX_WARNINGS) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler=${CXX_OPTION}") @@ -311,387 +290,24 @@ if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") endif () endif () -# For every public header, build a translation unit containing `#include
` -# to let the compiler try to figure out warnings in that header if it is not otherwise -# included in tests, and also to verify if the headers are modular enough. -# .inl files are not globbed for, because they are not supposed to be used as public -# entrypoints. -list(APPEND THRUST_HEADER_GLOBS thrust/*.h) -list(APPEND THRUST_HEADER_EXCLUDE_SYSTEMS_GLOBS thrust/system/*/*) - -string(TOLOWER ${THRUST_HOST_SYSTEM} THRUST_HOST_SYSTEM_LOWERCASE) -list(APPEND THRUST_HEADER_SYSTEMS_GLOBS thrust/system/${THRUST_HOST_SYSTEM_LOWERCASE}/*) - -string(TOLOWER ${THRUST_DEVICE_SYSTEM} THRUST_DEVICE_SYSTEM_LOWERCASE) -list(APPEND THRUST_HEADER_SYSTEMS_GLOBS thrust/system/${THRUST_DEVICE_SYSTEM_LOWERCASE}/*) - -list(APPEND THRUST_HEADER_EXCLUDE_DETAILS_GLOBS thrust/detail/*) -list(APPEND THRUST_HEADER_EXCLUDE_DETAILS_GLOBS thrust/*/detail/*) -list(APPEND THRUST_HEADER_EXCLUDE_DETAILS_GLOBS thrust/*/*/detail/*) - -# Get all .h files... -file( - GLOB_RECURSE THRUST_HEADERS - RELATIVE ${PROJECT_SOURCE_DIR}/thrust - ${CMAKE_CONFIGURE_DEPENDS} - ${THRUST_HEADER_GLOBS} -) - -# ...then remove all system specific headers... -file( - GLOB_RECURSE THRUST_HEADER_EXCLUDE_SYSTEMS - RELATIVE ${PROJECT_SOURCE_DIR}/thrust - ${CMAKE_CONFIGURE_DEPENDS} - ${THRUST_HEADER_EXCLUDE_SYSTEMS_GLOBS} -) -list(REMOVE_ITEM THRUST_HEADERS ${THRUST_HEADER_EXCLUDE_SYSTEMS}) - -# ...then add all headers specific to the selected host and device systems back again... -file( - GLOB_RECURSE THRUST_SYSTEMS_HEADERS - RELATIVE ${PROJECT_SOURCE_DIR}/thrust - ${CMAKE_CONFIGURE_DEPENDS} - ${THRUST_HEADER_SYSTEMS_GLOBS} -) -list(APPEND THRUST_HEADERS ${THRUST_SYSTEMS_HEADERS}) - -# ...and remove all the detail headers (also removing the detail headers from the selected systems). -file( - GLOB_RECURSE THRUST_HEADER_EXCLUDE_DETAILS - RELATIVE ${PROJECT_SOURCE_DIR}/thrust - ${CMAKE_CONFIGURE_DEPENDS} - ${THRUST_HEADER_EXCLUDE_DETAILS_GLOBS} -) -list(REMOVE_ITEM THRUST_HEADERS ${THRUST_HEADER_EXCLUDE_DETAILS}) - -# List of headers that aren't implemented for all backends, but are implemented for CUDA. -set(THRUST_PARTIALLY_IMPLEMENTED_HEADERS_CUDA - async/copy.h - async/for_each.h - async/reduce.h - async/sort.h - async/transform.h - event.h - future.h -) - -# List of headers that aren't implemented for all backends, but are implemented for CPP. -set(THRUST_PARTIALLY_IMPLEMENTED_HEADERS_CPP -) - -# List of headers that aren't implemented for all backends, but are implemented for TBB. -set(THRUST_PARTIALLY_IMPLEMENTED_HEADERS_TBB -) - -# List of headers that aren't implemented for all backends, but are implemented for OMP. -set(THRUST_PARTIALLY_IMPLEMENTED_HEADERS_OMP -) - -# List of all partially implemented headers. -set(THRUST_PARTIALLY_IMPLEMENTED_HEADERS - emptylistguard - ${THRUST_PARTIALLY_IMPLEMENTED_HEADERS_CUDA} - ${THRUST_PARTIALLY_IMPLEMENTED_HEADERS_CPP} - ${THRUST_PARTIALLY_IMPLEMENTED_HEADERS_TBB} - ${THRUST_PARTIALLY_IMPLEMENTED_HEADERS_OMP} -) - -list(REMOVE_DUPLICATES THRUST_PARTIALLY_IMPLEMENTED_HEADERS) - -foreach (THRUST_HEADER IN LISTS THRUST_HEADERS) - if ("${THRUST_HEADER}" IN_LIST THRUST_PARTIALLY_IMPLEMENTED_HEADERS) - # This header is partially implemented on _some_ backends... - if (NOT "${THRUST_HEADER}" IN_LIST THRUST_PARTIALLY_IMPLEMENTED_HEADERS_${THRUST_DEVICE_SYSTEM}) - # ...but not on the selected one. - continue() - endif () - endif () - - set(THRUST_HEADER_TEST_EXT .cpp) - if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - set(THRUST_HEADER_TEST_EXT .cu) - endif () - - set(SOURCE_NAME headers/${THRUST_HEADER}${THRUST_HEADER_TEST_EXT}) - configure_file(cmake/header_test.in ${SOURCE_NAME}) - - list(APPEND THRUST_HEADER_TEST_SOURCES ${SOURCE_NAME}) -endforeach () - -add_library(header-test OBJECT ${THRUST_HEADER_TEST_SOURCES}) -target_link_libraries(header-test PUBLIC Thrust) - -include(CTest) -enable_testing() - -# Handle tests. - -set(THRUST_TEST_RUN_ARGUMENTS - -DTHRUST_SOURCE=${CMAKE_SOURCE_DIR} - -P "${CMAKE_SOURCE_DIR}/cmake/run_test.cmake") - -list(APPEND THRUST_TESTFRAMEWORK_FILES testing/unittest/testframework.cu) -if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - list(APPEND THRUST_TESTFRAMEWORK_FILES testing/unittest/cuda/testframework.cu) -else () - # When CUDA is disabled, explain to CMake that testframework.cu is actually a C++ file. - set_source_files_properties(testing/unittest/testframework.cu - PROPERTIES - LANGUAGE CXX - COMPILE_FLAGS "${THRUST_TREAT_FILE_AS_CXX}") -endif () - -add_library(thrust_testframework STATIC ${THRUST_TESTFRAMEWORK_FILES}) -target_link_libraries(thrust_testframework PUBLIC Thrust) -target_include_directories( - thrust_testframework - PRIVATE ${PROJECT_SOURCE_DIR}/testing -) - -if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}" AND "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - set_target_properties(thrust_testframework - PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS OFF) -endif () - -list(APPEND THRUST_TEST_GLOBS testing/*.cu) -list(APPEND THRUST_TEST_GLOBS testing/*.cpp) - -if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - list(APPEND THRUST_TEST_GLOBS testing/cuda/*.cu) -elseif ("CPP" STREQUAL "${THRUST_DEVICE_SYSTEM}") - list(APPEND THRUST_TEST_GLOBS testing/cpp/*.cu) - list(APPEND THRUST_TEST_GLOBS testing/cpp/*.cpp) -elseif ("OMP" STREQUAL "${THRUST_DEVICE_SYSTEM}") - list(APPEND THRUST_TEST_GLOBS testing/omp/*.cu) - list(APPEND THRUST_TEST_GLOBS testing/omp/*.cpp) -endif () - -file( - GLOB THRUST_TESTS - RELATIVE ${PROJECT_SOURCE_DIR}/testing - ${CMAKE_CONFIGURE_DEPENDS} - ${THRUST_TEST_GLOBS} -) - -# List of tests that aren't implemented for all backends, but are implemented for CUDA. -set(THRUST_PARTIALLY_IMPLEMENTED_CUDA - async_copy - async_for_each - async_reduce - async_reduce_into - async_sort - async_transform - event - future -) - -# List of tests that aren't implemented for all backends, but are implemented for CPP. -set(THRUST_PARTIALLY_IMPLEMENTED_CPP -) - -# List of tests that aren't implemented for all backends, but are implemented for TBB. -set(THRUST_PARTIALLY_IMPLEMENTED_TBB -) - -# List of tests that aren't implemented for all backends, but are implemented for OMP. -set(THRUST_PARTIALLY_IMPLEMENTED_OMP -) - -# List of all partially implemented tests. -set(THRUST_PARTIALLY_IMPLEMENTED - ${THRUST_PARTIALLY_IMPLEMENTED_CUDA} - ${THRUST_PARTIALLY_IMPLEMENTED_CPP} - ${THRUST_PARTIALLY_IMPLEMENTED_TBB} - ${THRUST_PARTIALLY_IMPLEMENTED_OMP} -) - -list(REMOVE_DUPLICATES THRUST_PARTIALLY_IMPLEMENTED) - -# Handle tests. - -foreach (THRUST_TEST_SOURCE IN LISTS THRUST_TESTS) - # TODO: Per-test flags. - - set(THRUST_TEST_CREATION_ADDITIONAL) - set(THRUST_TEST_ADD_TO_CTEST ON) - - get_filename_component(THRUST_TEST_CATEGORY ${THRUST_TEST_SOURCE} DIRECTORY) - if (NOT ("" STREQUAL "${THRUST_TEST_CATEGORY}")) - set(THRUST_TEST_CATEGORY "${THRUST_TEST_CATEGORY}.") - endif () - - get_filename_component(THRUST_TEST_NAME ${THRUST_TEST_SOURCE} NAME_WE) - - if ("${THRUST_TEST_NAME}" IN_LIST THRUST_PARTIALLY_IMPLEMENTED) - # This test is partially implemented on _some_ backends... - if (NOT "${THRUST_TEST_NAME}" IN_LIST THRUST_PARTIALLY_IMPLEMENTED_${THRUST_DEVICE_SYSTEM}) - # ...but not on the selected one. - set(THRUST_TEST_CREATION_ADDITIONAL EXCLUDE_FROM_ALL) - set(THRUST_TEST_ADD_TO_CTEST OFF) - endif () - endif () - - set(THRUST_TEST "thrust.test.${THRUST_TEST_CATEGORY}${THRUST_TEST_NAME}") - - if (NOT "CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - # Test files are generally .cu; if CUDA is not enabled, CMake doesn't know what to - # do with them. But since they are pretty much just C++, we can compile them with - # non-nvcc C++ compilers... but we need to tell CMake that they are, in fact, just C++. - set_source_files_properties(${PROJECT_SOURCE_DIR}/testing/${THRUST_TEST_SOURCE} - PROPERTIES - LANGUAGE CXX - COMPILE_FLAGS "${THRUST_TREAT_FILE_AS_CXX}") - endif () - - add_executable( - ${THRUST_TEST} - ${THRUST_TEST_CREATION_ADDITIONAL} - # THRUST_TEST_CREATION_ADDITIONAL is actually a CMake keyword (sometimes). - ${PROJECT_SOURCE_DIR}/testing/${THRUST_TEST_SOURCE} - ) - - target_include_directories( - ${THRUST_TEST} - PRIVATE ${PROJECT_SOURCE_DIR}/testing - ) - - target_link_libraries(${THRUST_TEST} thrust_testframework) - - if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}" AND "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - set_target_properties(${THRUST_TEST} - PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS OFF) - endif () - - # All the CUDA-specific ones will test device-side launch (aka calling parallel - # algorithms from device code), which requires the CUDA device-side runtime, - # which requires RDC, so these always need to be built with RDC. - if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}" AND - (THRUST_ENABLE_TESTS_WITH_RDC OR "${THRUST_TEST_CATEGORY}" STREQUAL "cuda")) - if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - set_target_properties(${THRUST_TEST} - PROPERTIES COMPILE_FLAGS "-gpu=rdc") - else () - set_target_properties(${THRUST_TEST} - PROPERTIES CUDA_SEPARABLE_COMPILATION ON) - endif () - endif () - - if (THRUST_TEST_ADD_TO_CTEST) - add_test(NAME ${THRUST_TEST} - COMMAND ${CMAKE_COMMAND} - -DTHRUST_BINARY=$ - ${THRUST_TEST_RUN_ARGUMENTS}) - endif () -endforeach () - -# Handle examples. - -option(THRUST_EXAMPLE_FILECHECK_PATH "Path to the LLVM FileCheck utility." "") - -set(THRUST_EXAMPLE_FILECHECK_ENABLED OFF) -if (NOT "" STREQUAL "${THRUST_EXAMPLE_FILECHECK_PATH}") - execute_process( - COMMAND "${THRUST_EXAMPLE_FILECHECK_PATH}" "${THRUST_FILECHECK_DATA_PATH}/thrust.sanity.filecheck" - INPUT_FILE "${CMAKE_SOURCE_DIR}/cmake/sanity" - RESULT_VARIABLE THRUST_FILECHECK_RESULT - ) - - if ("0" STREQUAL "${THRUST_FILECHECK_RESULT}") - set(THRUST_EXAMPLE_FILECHECK_ENABLED ON) - message("-- FileCheck enabled: ${THRUST_EXAMPLE_FILECHECK_PATH}") - endif () -endif () - -list(APPEND THRUST_EXAMPLE_GLOBS examples/*.cu) -list(APPEND THRUST_EXAMPLE_GLOBS examples/*.cpp) - -if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - list(APPEND THRUST_EXAMPLE_GLOBS examples/cuda/*.cu) -elseif ("OMP" STREQUAL "${THRUST_DEVICE_SYSTEM}") - list(APPEND THRUST_EXAMPLE_GLOBS examples/omp/*.cu) - list(APPEND THRUST_EXAMPLE_GLOBS examples/omp/*.cpp) -endif () - -if (CMAKE_VERSION VERSION_LESS 3.12) - file( - GLOB THRUST_EXAMPLES - RELATIVE ${PROJECT_SOURCE_DIR}/examples - ${THRUST_EXAMPLE_GLOBS} - CONFIGURE_DEPENDS - ) -else () - file( - GLOB THRUST_EXAMPLES - RELATIVE ${PROJECT_SOURCE_DIR}/examples - ${THRUST_EXAMPLE_GLOBS} - ) -endif () - -set(THRUST_EXAMPLE_RUN_ARGUMENTS - -DTHRUST_SOURCE=${CMAKE_SOURCE_DIR} - -DTHRUST_FILECHECK_ENABLED=${THRUST_EXAMPLE_FILECHECK_ENABLED} - -DTHRUST_FILECHECK=${THRUST_EXAMPLE_FILECHECK_PATH} - -P "${CMAKE_SOURCE_DIR}/cmake/run_example.cmake") - -foreach (THRUST_EXAMPLE_SOURCE IN LISTS THRUST_EXAMPLES) - # TODO: Per-example flags. - - get_filename_component(THRUST_EXAMPLE_CATEGORY ${THRUST_EXAMPLE_SOURCE} DIRECTORY) - if (NOT ("" STREQUAL "${THRUST_EXAMPLE_CATEGORY}")) - set(THRUST_EXAMPLE_CATEGORY "${THRUST_EXAMPLE_CATEGORY}.") - endif () - - get_filename_component(THRUST_EXAMPLE_NAME ${THRUST_EXAMPLE_SOURCE} NAME_WE) +option(THRUST_ENABLE_HEADER_TESTING "Test that all public headers compile." "ON") +option(THRUST_ENABLE_TESTING "Build Thrust testing suite." "ON") +option(THRUST_ENABLE_EXAMPLES "Build Thrust examples." "ON") - set(THRUST_EXAMPLE "thrust.example.${THRUST_EXAMPLE_CATEGORY}${THRUST_EXAMPLE_NAME}") +if (THRUST_ENABLE_HEADER_TESTING) + include(cmake/ThrustHeaderTesting.cmake) +endif() - if (NOT "CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}") - # Example files are generally .cu; if CUDA is not enabled, CMake doesn't know what to - # do with them. But since they are pretty much just C++, we can compile them with - # non-nvcc C++ compilers... but we need to tell CMake that they are, in fact, just C++. - set_source_files_properties(${PROJECT_SOURCE_DIR}/examples/${THRUST_EXAMPLE_SOURCE} - PROPERTIES - LANGUAGE CXX - COMPILE_FLAGS "${THRUST_TREAT_FILE_AS_CXX}") - endif () +# Both testing and examples use ctest +if (THRUST_ENABLE_TESTING OR THRUST_ENABLE_EXAMPLES) + include(CTest) + enable_testing() +endif() - add_executable( - ${THRUST_EXAMPLE} - ${PROJECT_SOURCE_DIR}/examples/${THRUST_EXAMPLE_SOURCE} - ) - - target_include_directories( - ${THRUST_EXAMPLE} - PRIVATE ${PROJECT_SOURCE_DIR}/examples - ) +if (THRUST_ENABLE_TESTING) + add_subdirectory(testing) +endif() - target_link_libraries(${THRUST_EXAMPLE} Thrust) - - if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}" AND "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - set_target_properties(${THRUST_EXAMPLE} - PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS OFF) - endif () - - if ("CUDA" STREQUAL "${THRUST_DEVICE_SYSTEM}" AND THRUST_ENABLE_EXAMPLES_WITH_RDC) - if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") - set_target_properties(${THRUST_EXAMPLE} - PROPERTIES COMPILE_FLAGS "-gpu=rdc") - else () - set_target_properties(${THRUST_EXAMPLE} - PROPERTIES CUDA_SEPARABLE_COMPILATION ON) - endif () - endif () - - if ("MSVC" STREQUAL "${CMAKE_CXX_COMPILER_ID}") - # Some examples use unsafe APIs (e.g. fopen) that MSVC will complain about - # unless this is set: - set_target_properties(${THRUST_EXAMPLE} - PROPERTIES COMPILE_DEFINITIONS "_CRT_SECURE_NO_WARNINGS") - endif() - - add_test(NAME ${THRUST_EXAMPLE} - COMMAND ${CMAKE_COMMAND} - -DTHRUST_EXAMPLE=${THRUST_EXAMPLE} - -DTHRUST_BINARY=$ - ${THRUST_EXAMPLE_RUN_ARGUMENTS}) -endforeach () +if (THRUST_ENABLE_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/cmake/ThrustHeaderTesting.cmake b/cmake/ThrustHeaderTesting.cmake new file mode 100644 index 0000000000..0e40e6c295 --- /dev/null +++ b/cmake/ThrustHeaderTesting.cmake @@ -0,0 +1,119 @@ +# For every public header, build a translation unit containing `#include
` +# to let the compiler try to figure out warnings in that header if it is not otherwise +# included in tests, and also to verify if the headers are modular enough. +# .inl files are not globbed for, because they are not supposed to be used as public +# entrypoints. + +foreach(thrust_target IN LISTS THRUST_TARGETS) + thrust_get_target_property(config_host ${thrust_target} HOST) + thrust_get_target_property(config_device ${thrust_target} DEVICE) + thrust_get_target_property(config_prefix ${thrust_target} PREFIX) + + string(TOLOWER "${config_host}" host_lower) + string(TOLOWER "${config_device}" device_lower) + + # GLOB ALL THE THINGS + set(headers_globs thrust/*.h) + set(headers_exclude_systems_globs thrust/system/*/*) + set(headers_systems_globs + thrust/system/${host_lower}/* + thrust/system/${device_lower}/* + ) + set(headers_exclude_details_globs + thrust/detail/* + thrust/*/detail/* + thrust/*/*/detail/* + ) + + # Get all .h files... + file(GLOB_RECURSE headers + RELATIVE "${Thrust_SOURCE_DIR}/thrust" + ${CMAKE_CONFIGURE_DEPENDS} + ${headers_globs} + ) + + # ...then remove all system specific headers... + file(GLOB_RECURSE headers_exclude_systems + RELATIVE "${Thrust_SOURCE_DIR}/thrust" + ${CMAKE_CONFIGURE_DEPENDS} + ${headers_exclude_systems_globs} + ) + list(REMOVE_ITEM headers ${headers_exclude_systems}) + + # ...then add all headers specific to the selected host and device systems back again... + file(GLOB_RECURSE headers_systems + RELATIVE ${Thrust_SOURCE_DIR}/thrust + ${CMAKE_CONFIGURE_DEPENDS} + ${headers_systems_globs} + ) + list(APPEND headers ${headers_systems}) + + # ...and remove all the detail headers (also removing the detail headers from the selected systems). + file(GLOB_RECURSE headers_exclude_details + RELATIVE "${Thrust_SOURCE_DIR}/thrust" + ${CMAKE_CONFIGURE_DEPENDS} + ${headers_exclude_details_globs} + ) + list(REMOVE_ITEM headers ${headers_exclude_details}) + + # List of headers that aren't implemented for all backends, but are implemented for CUDA. + set(partially_implemented_CUDA + async/copy.h + async/for_each.h + async/reduce.h + async/sort.h + async/transform.h + event.h + future.h + ) + + # List of headers that aren't implemented for all backends, but are implemented for CPP. + set(partially_implemented_CPP + ) + + # List of headers that aren't implemented for all backends, but are implemented for TBB. + set(partially_implemented_TBB + ) + + # List of headers that aren't implemented for all backends, but are implemented for OMP. + set(partially_implemented_OMP + ) + + # List of all partially implemented headers. + set(partially_implemented + ${partially_implemented_CUDA} + ${partially_implemented_CPP} + ${partially_implemented_TBB} + ${partially_implemented_OMP} + ) + list(REMOVE_DUPLICATES partially_implemented) + + set(headertest_srcs) + + foreach (header IN LISTS headers) + if ("${header}" IN_LIST partially_implemented) + # This header is partially implemented on _some_ backends... + if (NOT "${header}" IN_LIST partially_implemented_${config_device}) + # ...but not on the selected one. + continue() + endif() + endif() + + set(headertest_src_ext .cpp) + if ("CUDA" STREQUAL "${config_device}") + set(headertest_src_ext .cu) + endif() + + set(headertest_src "headers/${config_prefix}/${header}${headertest_src_ext}") + configure_file("${Thrust_SOURCE_DIR}/cmake/header_test.in" "${headertest_src}") + + list(APPEND headertest_srcs "${headertest_src}") + endforeach() + + set(headertest_target ${config_prefix}.headers) + add_library(${headertest_target} OBJECT ${headertest_srcs}) + target_link_libraries(${headertest_target} PUBLIC ${thrust_target}) + thrust_clone_target_properties(${headertest_target} ${thrust_target}) + + add_dependencies(${config_prefix}.meta ${headertest_target}) +endforeach() diff --git a/cmake/ThrustTargetConfig.cmake b/cmake/ThrustTargetConfig.cmake new file mode 100644 index 0000000000..3bd6544b32 --- /dev/null +++ b/cmake/ThrustTargetConfig.cmake @@ -0,0 +1,275 @@ +# This file handles thrust target creation and multiconfig. +# +# - Target names: (example) Thrust.cpp.cuda.cpp14 for multiconfig, or +# Thrust for single config +# - Target properties: +# - _THRUST_HOST: {CPP, OMP, TBB} +# - _THRUST_DEVICE: {CUDA, CPP, OMP, TBB} +# - _THRUST_DIALECT: {11, 14, 17} +# - _THRUST_PREFIX: (example) "thrust.cpp.cuda.cpp14" for multiconfig, or +# "thrust" for single config +# - THRUST_TARGETS list stores target names for each requested config +# + +# Multiconfig setup: +option(THRUST_ENABLE_MULTICONFIG "Enable multiconfig options for coverage testing." OFF) + +if (THRUST_ENABLE_MULTICONFIG) + # Dialects: + set(THRUST_MULTICONFIG_DIALECT_OPTIONS 11 14 17) + option(THRUST_MULTICONFIG_ENABLE_DIALECT_CPP11 "Generate C++11 build configurations." OFF) + option(THRUST_MULTICONFIG_ENABLE_DIALECT_CPP14 "Generate C++14 build configurations." ON) + option(THRUST_MULTICONFIG_ENABLE_DIALECT_CPP17 "Generate C++17 build configurations." OFF) + + # Default to CPP14 if all are disabled + if (NOT THRUST_MULTICONFIG_ENABLE_DIALECT_CPP11 AND + NOT THRUST_MULTICONFIG_ENABLE_DIALECT_CPP14 AND + NOT THRUST_MULTICONFIG_ENABLE_DIALECT_CPP17) + set(THRUST_MULTICONFIG_ENABLE_DIALECT_CPP14 ON) + endif() + + # Systems: + option(THRUST_MULTICONFIG_ENABLE_SYSTEM_CPP "Generate build configurations that use CPP." ON) + option(THRUST_MULTICONFIG_ENABLE_SYSTEM_CUDA "Generate build configurations that use CUDA." ON) + option(THRUST_MULTICONFIG_ENABLE_SYSTEM_OMP "Generate build configurations that use OpenMP." OFF) + option(THRUST_MULTICONFIG_ENABLE_SYSTEM_TBB "Generate build configurations that use TBB." OFF) + + # Workload: + # - `FULL`: [12 configs] The complete cross product of all possible build configurations. + # - `LARGE`: [7 configs] All configurations that have likely usecases. + # - `MEDIUM`: [5 configs] Removes somewhat redundant cases. + # - `SMALL`: [3 configs] Minimal validation of each device system against the `CPP` host. + # + # Config | Workloads | Note + # -------------------------------------------------------------------- + # CPP/CUDA | F L M S | Essential: validates CUDA against CPP + # CPP/TBB | F L M S | Essential: validates TBB against CPP + # CPP/OMP | F L M S | Essential: validates OMP against CPP + # TBB/CUDA | F L M | Important: validates TBB/CUDA interop + # OMP/CUDA | F L M | Important: validates OMP/CUDA interop + # TBB/TBB | F L | Somewhat redundant with CPP/TBB and TBB/CUDA + # OMP/OMP | F L | Somewhat redundant with CPP/OMP and OMP/CUDA + # CPP/CPP | F | Very unlikely + # TBB/CPP | F | Very unlikely + # OMP/CPP | F | Very unlikely + # TBB/OMP | F | Very unlikely + # OMP/TBB | F | Very unlikely + set(THRUST_MULTICONFIG_WORKLOAD SMALL CACHE STRING + "Limit host/device configs: SMALL (up to 3 h/d combos), MEDIUM(5), LARGE(7), FULL(12)" + ) + set_property(CACHE THRUST_MULTICONFIG_WORKLOAD PROPERTY STRINGS + SMALL MEDIUM LARGE FULL + ) + set(THRUST_MULTICONFIG_WORKLOAD_SMALL_CONFIGS + CPP_CUDA CPP_TBB CPP_OMP + ) + set(THRUST_MULTICONFIG_WORKLOAD_MEDIUM_CONFIGS + ${THRUST_MULTICONFIG_WORKLOAD_SMALL_CONFIGS} + TBB_CUDA OMP_CUDA + ) + set(THRUST_MULTICONFIG_WORKLOAD_LARGE_CONFIGS + ${THRUST_MULTICONFIG_WORKLOAD_MEDIUM_CONFIGS} + TBB_TBB OMP_OMP + ) + set(THRUST_MULTICONFIG_WORKLOAD_FULL_CONFIGS + ${THRUST_MULTICONFIG_WORKLOAD_LARGE_CONFIGS} + CPP_CPP TBB_CPP OMP_CPP TBB_OMP OMP_TBB + ) +endif() + +# These are used with the targets we create to store useful metadata for generic +# target handling +define_property(TARGET PROPERTY _THRUST_HOST + BRIEF_DOCS "A target's host system: CPP, TBB, or OMP." + FULL_DOCS "A target's host system: CPP, TBB, or OMP." +) +define_property(TARGET PROPERTY _THRUST_DEVICE + BRIEF_DOCS "A target's device system: CUDA, CPP, TBB, or OMP." + FULL_DOCS "A target's device system: CUDA, CPP, TBB, or OMP." +) +define_property(TARGET PROPERTY _THRUST_DIALECT + BRIEF_DOCS "A target's C++ dialect: 11, 14, or 17." + FULL_DOCS "A target's C++ dialect: 11, 14, or 17." +) +define_property(TARGET PROPERTY _THRUST_PREFIX + BRIEF_DOCS "A prefix describing the config, eg. 'thrust.cpp.cuda.cpp14'." + FULL_DOCS "A prefix describing the config, eg. 'thrust.cpp.cuda.cpp14'." +) + +function(thrust_set_target_properties target_name host device dialect prefix) + set_property(TARGET ${target_name} PROPERTY _THRUST_HOST ${host}) + set_property(TARGET ${target_name} PROPERTY _THRUST_DEVICE ${device}) + set_property(TARGET ${target_name} PROPERTY _THRUST_DIALECT ${dialect}) + set_property(TARGET ${target_name} PROPERTY _THRUST_PREFIX ${prefix}) + + get_target_property(type ${target_name} TYPE) + if (NOT ${type} STREQUAL "INTERFACE_LIBRARY") + set_property(TARGET ${target_name} PROPERTY CXX_STANDARD ${dialect}) + set_property(TARGET ${target_name} PROPERTY CUDA_STANDARD ${dialect}) + endif() +endfunction() + +# Get a thrust property from a target and store it in var_name +# thrust_get_target_property( [HOST|DEVICE|DIALECT|PREFIX] +macro(thrust_get_target_property prop_var target_name prop) + get_property(${prop_var} TARGET ${target_name} PROPERTY _THRUST_${prop}) +endmacro() + +# Defines the following string variables in the caller's scope: +# - ${target_name}_HOST +# - ${target_name}_DEVICE +# - ${target_name}_DIALECT +# - ${target_name}_PREFIX +macro(thrust_get_target_properties target_name) + thrust_get_target_property(${target_name}_HOST ${target_name} HOST) + thrust_get_target_property(${target_name}_DEVICE ${target_name} DEVICE) + thrust_get_target_property(${target_name}_DIALECT ${target_name} DIALECT) + thrust_get_target_property(${target_name}_PREFIX ${target_name} PREFIX) +endmacro() + +# Set one target's THRUST_* properties to match another target +function(thrust_clone_target_properties dst_target src_target) + thrust_get_target_properties(${src_target}) + thrust_set_target_properties(${dst_target} + ${${src_target}_HOST} + ${${src_target}_DEVICE} + ${${src_target}_DIALECT} + ${${src_target}_PREFIX} + ) +endfunction() + +# Set _THRUST_CONFIG_VALID to TRUE or FALSE in the caller's scope +function(_thrust_is_config_valid host device dialect) + if (THRUST_MULTICONFIG_ENABLE_SYSTEM_${host} AND + THRUST_MULTICONFIG_ENABLE_SYSTEM_${device} AND + THRUST_MULTICONFIG_ENABLE_DIALECT_CPP${dialect} AND + "${host}_${device}" IN_LIST THRUST_MULTICONFIG_WORKLOAD_${THRUST_MULTICONFIG_WORKLOAD}_CONFIGS) + set(_THRUST_CONFIG_VALID TRUE PARENT_SCOPE) + else() + set(_THRUST_CONFIG_VALID FALSE PARENT_SCOPE) + endif() +endfunction() + +function(_thrust_init_target_list) + set(THRUST_TARGETS "" CACHE INTERNAL "" FORCE) +endfunction() + +function(_thrust_add_target_to_target_list target_name) + set(THRUST_TARGETS ${THRUST_TARGETS} ${target_name} CACHE INTERNAL "" FORCE) +endfunction() + +function(_thrust_build_target_list_multiconfig) + # Hide the single config options if they exist: + if (DEFINED THRUST_HOST_SYSTEM) + set_property(CACHE THRUST_HOST_SYSTEM PROPERTY TYPE INTERNAL) + set_property(CACHE THRUST_DEVICE_SYSTEM PROPERTY TYPE INTERNAL) + endif() + + set(req_systems) + if (THRUST_MULTICONFIG_ENABLE_SYSTEM_CUDA) + list(APPEND req_systems CUDA) + endif() + if (THRUST_MULTICONFIG_ENABLE_SYSTEM_CPP) + list(APPEND req_systems CPP) + endif() + if (THRUST_MULTICONFIG_ENABLE_SYSTEM_TBB) + list(APPEND req_systems TBB) + endif() + if (THRUST_MULTICONFIG_ENABLE_SYSTEM_OMP) + list(APPEND req_systems OMP) + endif() + + find_package(Thrust REQUIRED CONFIG + NO_DEFAULT_PATH # Only check the explicit path in HINTS: + HINTS "${Thrust_SOURCE_DIR}" + COMPONENTS ${req_systems} + ) + + # Build THRUST_TARGETS + foreach(host IN LISTS THRUST_HOST_SYSTEM_OPTIONS) + foreach(device IN LISTS THRUST_DEVICE_SYSTEM_OPTIONS) + foreach(dialect IN LISTS THRUST_MULTICONFIG_DIALECT_OPTIONS) + _thrust_is_config_valid(${host} ${device} ${dialect}) + if (_THRUST_CONFIG_VALID) + set(label "${host}.${device}.cpp${dialect}") + string(TOLOWER "${label}" label) + + message(STATUS "Initializing configuration: ${label}") + + set(target_name "Thrust.${label}") + thrust_create_target(${target_name} + HOST ${host} + DEVICE ${device} + ${THRUST_TARGET_FLAGS} + ) + + set(prefix "thrust.${label}") + thrust_set_target_properties(${target_name} ${host} ${device} ${dialect} ${prefix}) + _thrust_add_target_to_target_list(${target_name}) + endif() + endforeach() # dialects + endforeach() # devices + endforeach() # hosts + + list(LENGTH THRUST_TARGETS count) + message(STATUS "${count} unique host.device.dialect configurations generated") +endfunction() + +function(_thrust_build_target_list_singleconfig) + # Restore system option visibility if these cache options already exist: + if (DEFINED THRUST_HOST_SYSTEM) + set_property(CACHE THRUST_HOST_SYSTEM PROPERTY TYPE STRING) + set_property(CACHE THRUST_DEVICE_SYSTEM PROPERTY TYPE STRING) + endif() + + # Use our find_package config to assemble the Thrust library components we need: + find_package(Thrust REQUIRED CONFIG + NO_DEFAULT_PATH # Only check the explicit path in HINTS: + HINTS "${Thrust_SOURCE_DIR}" + ) + + thrust_create_target(Thrust FROM_OPTIONS ${THRUST_TARGET_FLAGS}) + thrust_debug_target(Thrust "${THRUST_VERSION}") + + set(host ${THRUST_HOST_SYSTEM}) + set(device ${THRUST_DEVICE_SYSTEM}) + set(dialect ${CMAKE_CXX_STANDARD}) + set(prefix "thrust") # single config + + thrust_set_target_properties(Thrust ${host} ${device} ${dialect} ${prefix}) + _thrust_add_target_to_target_list(Thrust) +endfunction() + +# Build a ${THRUST_TARGETS} list containing target names for all +# requested configurations +function(thrust_build_target_list) + # Clear the list of targets: + _thrust_init_target_list() + + # Generic config flags: + set(THRUST_TARGET_FLAGS) + macro(add_flag_option flag docstring default) + set(opt "THRUST_${flag}") + option(${opt} "${docstring}" "${default}") + mark_as_advanced(${opt}) + if (${${opt}}) + list(APPEND THRUST_TARGET_FLAGS ${flag}) + endif() + endmacro() + add_flag_option(IGNORE_DEPRECATED_CPP_DIALECT "Don't warn about any deprecated C++ standards and compilers." OFF) + add_flag_option(IGNORE_DEPRECATED_CPP_11 "Don't warn about deprecated C++11." OFF) + add_flag_option(IGNORE_DEPRECATED_COMPILER "Don't warn about deprecated COMPILERS." OFF) + add_flag_option(IGNORE_CUB_VERSION_CHECK "Don't warn about mismatched CUB versions." OFF) + + if (THRUST_ENABLE_MULTICONFIG) + _thrust_build_target_list_multiconfig() + else() + _thrust_build_target_list_singleconfig() + endif() + + # Create meta targets for each config: + foreach(thrust_target IN LISTS THRUST_TARGETS) + thrust_get_target_property(config_prefix ${thrust_target} PREFIX) + add_custom_target(${config_prefix}.meta) + endforeach() +endfunction() diff --git a/cmake/ThrustUtilities.cmake b/cmake/ThrustUtilities.cmake new file mode 100644 index 0000000000..870b450f95 --- /dev/null +++ b/cmake/ThrustUtilities.cmake @@ -0,0 +1,12 @@ +# Given a cu_file (e.g. foo/bar.cu) relative to CMAKE_CURRENT_SOURCE_DIR +# and a thrust_target, create a cpp file that includes the .cu file, and set +# ${cpp_file_var} in the parent scope to the full path of the new file. The new +# file will be generated in: +# ${CMAKE_CURRENT_BINARY_DIR}//${cu_file}.cpp +function(thrust_wrap_cu_in_cpp cpp_file_var cu_file thrust_target) + thrust_get_target_property(prefix ${thrust_target} PREFIX) + set(wrapped_source_file "${CMAKE_CURRENT_SOURCE_DIR}/${cu_file}") + set(cpp_file "${CMAKE_CURRENT_BINARY_DIR}/${prefix}/${cu_file}.cpp") + configure_file("${Thrust_SOURCE_DIR}/cmake/wrap_source_file.cpp.in" "${cpp_file}") + set(${cpp_file_var} "${cpp_file}" PARENT_SCOPE) +endfunction() diff --git a/cmake/common_variables.cmake b/cmake/common_variables.cmake index 2ff72eb53f..cdbff53667 100644 --- a/cmake/common_variables.cmake +++ b/cmake/common_variables.cmake @@ -1 +1 @@ -set(THRUST_FILECHECK_DATA_PATH "${THRUST_SOURCE}/internal/test") +set(THRUST_FILECHECK_DATA_PATH "${Thrust_SOURCE_DIR}/internal/test") diff --git a/cmake/header_test.in b/cmake/header_test.in index 4c8ec00f55..c9d7104d48 100644 --- a/cmake/header_test.in +++ b/cmake/header_test.in @@ -1,3 +1,3 @@ #define THRUST_CPP11_REQUIRED_NO_ERROR #define THRUST_MODERN_GCC_REQUIRED_NO_ERROR -#include +#include diff --git a/cmake/run_example.cmake b/cmake/run_example.cmake index d51152d1e2..24c9174b58 100644 --- a/cmake/run_example.cmake +++ b/cmake/run_example.cmake @@ -1,4 +1,4 @@ -include("${THRUST_SOURCE}/cmake/common_variables.cmake") +include("${Thrust_SOURCE_DIR}/cmake/common_variables.cmake") if (THRUST_FILECHECK_ENABLED) set(DATA_FILE "${THRUST_FILECHECK_DATA_PATH}/${THRUST_EXAMPLE}.filecheck") diff --git a/cmake/wrap_source_file.cpp.in b/cmake/wrap_source_file.cpp.in new file mode 100644 index 0000000000..3015238cc6 --- /dev/null +++ b/cmake/wrap_source_file.cpp.in @@ -0,0 +1 @@ +#include <${wrapped_source_file}> diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000000..c6d8f23dc8 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,105 @@ +option(THRUST_EXAMPLE_FILECHECK_PATH "Path to the LLVM FileCheck utility." "") + +set(THRUST_EXAMPLE_FILECHECK_ENABLED OFF) +if (NOT "" STREQUAL "${THRUST_EXAMPLE_FILECHECK_PATH}") + execute_process( + COMMAND "${THRUST_EXAMPLE_FILECHECK_PATH}" "${THRUST_FILECHECK_DATA_PATH}/thrust.sanity.filecheck" + INPUT_FILE "${Thrust_SOURCE_DIR}/cmake/sanity" + RESULT_VARIABLE THRUST_FILECHECK_RESULT + ) + + if ("0" STREQUAL "${THRUST_FILECHECK_RESULT}") + set(THRUST_EXAMPLE_FILECHECK_ENABLED ON) + message("-- FileCheck enabled: ${THRUST_EXAMPLE_FILECHECK_PATH}") + endif() +endif() + +foreach(thrust_target IN LISTS THRUST_TARGETS) + thrust_get_target_property(config_device ${thrust_target} DEVICE) + thrust_get_target_property(config_prefix ${thrust_target} PREFIX) + + set(example_globs + *.cu + *.cpp + ) + + if ("CUDA" STREQUAL "${config_device}") + list(APPEND example_globs cuda/*.cu) + elseif ("CPP" STREQUAL "${config_device}") + list(APPEND example_globs cpp/*.cu cpp/*.cpp) + elseif ("OMP" STREQUAL "${config_device}") + list(APPEND example_globs omp/*.cu omp/*.cpp) + elseif ("TBB" STREQUAL "${config_device}") + list(APPEND example_globs tbb/*.cu tbb/*.cpp) + endif() + + file(GLOB example_srcs + RELATIVE "${CMAKE_CURRENT_LIST_DIR}" + ${CMAKE_CONFIGURE_DEPENDS} + ${example_globs} + ) + + set(meta_target ${config_prefix}.example.meta) + add_custom_target(${meta_target}) + add_dependencies(${config_prefix}.meta ${meta_target}) + + foreach(example_src IN LISTS example_srcs) + get_filename_component(example_subdir "${example_src}" DIRECTORY) + if (example_subdir) + string(APPEND example_subdir ".") + endif() + + get_filename_component(example_name ${example_src} NAME_WE) + set(example_target "${config_prefix}.example.${example_subdir}${example_name}") + + if ("CUDA" STREQUAL "${config_device}") + set(real_example_src "${example_src}") + else() + # Wrap the .cu file in .cpp for non-CUDA backends + thrust_wrap_cu_in_cpp(real_example_src "${example_src}" ${thrust_target}) + endif() + + add_executable(${example_target} ${real_example_src}) + target_link_libraries(${example_target} ${thrust_target}) + target_include_directories(${example_target} PRIVATE "${Thrust_SOURCE_DIR}/examples") + thrust_clone_target_properties(${example_target} ${thrust_target}) + add_dependencies(${meta_target} ${example_target}) + + if ("CUDA" STREQUAL "${config_device}" AND + "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + set_target_properties(${example_target} PROPERTIES + CUDA_RESOLVE_DEVICE_SYMBOLS OFF + ) + endif() + + if ("CUDA" STREQUAL "${config_device}" AND THRUST_ENABLE_EXAMPLES_WITH_RDC) + if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + set_target_properties(${example_target} PROPERTIES + COMPILE_FLAGS "-gpu=rdc" + ) + else() + set_target_properties(${example_target} PROPERTIES + CUDA_SEPARABLE_COMPILATION ON + ) + endif() + endif() + + # TODO remove this after refactoring examples to remove unsafe APIs + if ("MSVC" STREQUAL "${CMAKE_CXX_COMPILER_ID}") + # Some examples use unsafe APIs (e.g. fopen) that MSVC will complain about + # unless this is set: + set_target_properties(${example_target} PROPERTIES + COMPILE_DEFINITIONS "_CRT_SECURE_NO_WARNINGS") + endif() + + add_test(NAME ${example_target} + COMMAND "${CMAKE_COMMAND}" + "-DTHRUST_EXAMPLE=${example_target}" + "-DTHRUST_BINARY=$" + "-DTHRUST_SOURCE=${Thrust_SOURCE_DIR}" + "-DTHRUST_FILECHECK_ENABLED=${THRUST_EXAMPLE_FILECHECK_ENABLED}" + "-DTHRUST_FILECHECK=${THRUST_EXAMPLE_FILECHECK_PATH}" + -P "${Thrust_SOURCE_DIR}/cmake/run_example.cmake" + ) + endforeach() +endforeach() diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt new file mode 100644 index 0000000000..04c72aa87f --- /dev/null +++ b/testing/CMakeLists.txt @@ -0,0 +1,151 @@ +function(thrust_create_framework_target target_name thrust_target) + thrust_get_target_property(config_device ${thrust_target} DEVICE) + + if ("CUDA" STREQUAL "${config_device}") + set(framework_srcs + "unittest/testframework.cu" + "unittest/cuda/testframework.cu" + ) + else() + # Wrap the cu file inside a .cpp file for non-CUDA builds + thrust_wrap_cu_in_cpp(framework_srcs "unittest/testframework.cu" ${thrust_target}) + endif() + + add_library(${target_name} STATIC ${framework_srcs}) + target_link_libraries(${target_name} PUBLIC ${thrust_target}) + target_include_directories(${target_name} PRIVATE "${Thrust_SOURCE_DIR}/testing") + thrust_clone_target_properties(${target_name} ${thrust_target}) + + if ("CUDA" STREQUAL "${config_device}" AND + "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + set_target_properties(${target_name} PROPERTIES + CUDA_RESOLVE_DEVICE_SYMBOLS OFF) + endif() +endfunction() + +foreach(thrust_target IN LISTS THRUST_TARGETS) + thrust_get_target_property(config_device ${thrust_target} DEVICE) + thrust_get_target_property(config_prefix ${thrust_target} PREFIX) + + set(framework_target ${config_prefix}.test.framework) + thrust_create_framework_target(${framework_target} ${thrust_target}) + + set(test_globs + *.cu + *.cpp + ) + + if ("CUDA" STREQUAL "${config_device}") + list(APPEND test_globs cuda/*.cu) + elseif ("CPP" STREQUAL "${config_device}") + list(APPEND test_globs cpp/*.cu cpp/*.cpp) + elseif ("OMP" STREQUAL "${config_device}") + list(APPEND test_globs omp/*.cu omp/*.cpp) + elseif ("TBB" STREQUAL "${config_device}") + list(APPEND test_globs tbb/*.cu tbb/*.cpp) + endif() + + file(GLOB test_srcs + RELATIVE "${CMAKE_CURRENT_LIST_DIR}" + ${CMAKE_CONFIGURE_DEPENDS} + ${test_globs} + ) + + # List of tests that aren't implemented for all backends, but are implemented for CUDA. + set(partially_implemented_CUDA + async_copy + async_for_each + async_reduce + async_reduce_into + async_sort + async_transform + event + future + ) + + # List of tests that aren't implemented for all backends, but are implemented for CPP. + set(partially_implemented_CPP + ) + + # List of tests that aren't implemented for all backends, but are implemented for TBB. + set(partially_implemented_TBB + ) + + # List of tests that aren't implemented for all backends, but are implemented for OMP. + set(partially_implemented_OMP + ) + + # List of all partially implemented tests. + set(partially_implemented + ${partially_implemented_CUDA} + ${partially_implemented_CPP} + ${partially_implemented_TBB} + ${partially_implemented_OMP} + ) + list(REMOVE_DUPLICATES partially_implemented) + + set(meta_target ${config_prefix}.test.meta) + add_custom_target(${meta_target}) + add_dependencies(${config_prefix}.meta ${meta_target}) + + foreach(test_src IN LISTS test_srcs) + get_filename_component(test_name ${test_src} NAME_WE) + if ("${test_name}" IN_LIST partially_implemented) + # This test is partially implemented on _some_ backends... + if (NOT "${test_name}" IN_LIST partially_implemented_${config_device}) + # ...but not on the selected one. + continue() + endif() + endif() + + get_filename_component(test_subdir "${test_src}" DIRECTORY) + if (test_subdir) + string(APPEND test_subdir ".") + endif() + + if ("CUDA" STREQUAL "${config_device}") + set(real_test_src "${test_src}") + else() + # Wrap the .cu file in .cpp for non-CUDA backends + thrust_wrap_cu_in_cpp(real_test_src "${test_src}" ${thrust_target}) + endif() + + set(test_target "${config_prefix}.test.${test_subdir}${test_name}") + + add_executable(${test_target} "${real_test_src}") + target_link_libraries(${test_target} ${framework_target}) + target_include_directories(${test_target} PRIVATE "${Thrust_SOURCE_DIR}/testing") + thrust_clone_target_properties(${test_target} ${thrust_target}) + add_dependencies(${meta_target} ${test_target}) + + if ("CUDA" STREQUAL "${config_device}" AND + "Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + set_target_properties(${test_target} PROPERTIES + CUDA_RESOLVE_DEVICE_SYMBOLS OFF + ) + endif() + + # All the CUDA-specific ones will test device-side launch (aka calling parallel + # algorithms from device code), which requires the CUDA device-side runtime, + # which requires RDC, so these always need to be built with RDC. + if ("CUDA" STREQUAL "${config_device}" AND + (THRUST_ENABLE_TESTS_WITH_RDC OR "${test_subdir}" STREQUAL "cuda")) + if ("Feta" STREQUAL "${CMAKE_CUDA_COMPILER_ID}") + set_target_properties(${test_target} PROPERTIES + COMPILE_FLAGS "-gpu=rdc" + ) + else() + set_target_properties(${test_target} PROPERTIES + CUDA_SEPARABLE_COMPILATION ON + ) + endif() + endif() + + add_test(NAME "${test_target}" + COMMAND "${CMAKE_COMMAND}" + "-DTHRUST_BINARY=$" + "-DTHRUST_SOURCE=${Thrust_SOURCE_DIR}" + -P "${Thrust_SOURCE_DIR}/cmake/run_test.cmake" + ) + endforeach() +endforeach()