1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
# Check all source files for various issues that can be detected using pattern
# matching.
#
# This is run as a ctest test named `thrust.test.cmake.check_source_files`, or
# manually with:
# cmake -D "Thrust_SOURCE_DIR=<thrust project root>" -P check_source_files.cmake
cmake_minimum_required(VERSION 3.15)
function(count_substrings input search_regex output_var)
string(REGEX MATCHALL "${search_regex}" matches "${input}")
list(LENGTH matches num_matches)
set(${output_var} ${num_matches} PARENT_SCOPE)
endfunction()
set(found_errors 0)
file(GLOB_RECURSE thrust_srcs
RELATIVE "${Thrust_SOURCE_DIR}"
"${Thrust_SOURCE_DIR}/thrust/*.h"
"${Thrust_SOURCE_DIR}/thrust/*.inl"
)
################################################################################
# Namespace checks.
# Check all files in thrust to make sure that they use
# THRUST_NAMESPACE_BEGIN/END instead of bare `namespace thrust {}` declarations.
set(namespace_exclusions
# This defines the macros and must have bare namespace declarations:
thrust/detail/config/namespace.h
)
set(bare_ns_regex "namespace[ \n\r\t]+thrust[ \n\r\t]*\\{")
# Validation check for the above regex:
count_substrings([=[
namespace thrust{
namespace thrust {
namespace thrust {
namespace thrust {
namespace thrust
{
namespace
thrust
{
]=]
${bare_ns_regex} valid_count)
if (NOT valid_count EQUAL 6)
message(FATAL_ERROR "Validation of bare namespace regex failed: "
"Matched ${valid_count} times, expected 6.")
endif()
################################################################################
# stdpar header checks.
# Check all files in Thrust to make sure that they aren't including <algorithm>
# or <memory>, both of which will cause circular dependencies in nvc++'s
# stdpar library.
#
# The headers following headers should be used instead:
# <algorithm> -> <thrust/detail/algorithm_wrapper.h>
# <memory> -> <thrust/detail/memory_wrapper.h>
#
set(stdpar_header_exclusions
# The wrappers are allowed to include the unwrapped headers
thrust/detail/algorithm_wrapper.h
thrust/detail/memory_wrapper.h
thrust/detail/numeric_wrapper.h
)
set(algorithm_regex "#[ \t]*include[ \t]+<algorithm>")
set(memory_regex "#[ \t]*include[ \t]+<memory>")
set(numeric_regex "#[ \t]*include[ \t]+<numeric>")
# Validation check for the above regex pattern:
count_substrings([=[
#include <algorithm>
# include <algorithm>
#include <algorithm>
# include <algorithm>
# include <algorithm> // ...
]=]
${algorithm_regex} valid_count)
if (NOT valid_count EQUAL 5)
message(FATAL_ERROR "Validation of stdpar header regex failed: "
"Matched ${valid_count} times, expected 5.")
endif()
################################################################################
# Legacy macro checks.
# Check all files in Thrust to make sure that they aren't using the legacy
# CUB_RUNTIME_ENABLED and __THRUST_HAS_CUDART__ macros.
#
# These macros depend on __CUDA_ARCH__ and are not compatible with NV_IF_TARGET.
# They are provided for legacy purposes and should be replaced with
# [THRUST|CUB]_RDC_ENABLED and NV_IF_TARGET in Thrust/CUB code.
#
#
set(legacy_macro_header_exclusions
# This header defines a legacy CUDART macro:
thrust/system/cuda/config.h
)
set(cub_legacy_macro_regex "CUB_RUNTIME_ENABLED")
set(thrust_legacy_macro_regex "__THRUST_HAS_CUDART__")
################################################################################
# Read source files:
foreach(src ${thrust_srcs})
file(READ "${Thrust_SOURCE_DIR}/${src}" src_contents)
if (NOT ${src} IN_LIST namespace_exclusions)
count_substrings("${src_contents}" "${bare_ns_regex}" bare_ns_count)
count_substrings("${src_contents}" THRUST_NS_PREFIX prefix_count)
count_substrings("${src_contents}" THRUST_NS_POSTFIX postfix_count)
count_substrings("${src_contents}" THRUST_NAMESPACE_BEGIN begin_count)
count_substrings("${src_contents}" THRUST_NAMESPACE_END end_count)
count_substrings("${src_contents}" "#include <thrust/detail/config.h>" header_count)
if (NOT bare_ns_count EQUAL 0)
message("'${src}' contains 'namespace thrust {...}'. Replace with THRUST_NAMESPACE macros.")
set(found_errors 1)
endif()
if (NOT prefix_count EQUAL 0)
message("'${src}' contains 'THRUST_NS_PREFIX'. Replace with THRUST_NAMESPACE macros.")
set(found_errors 1)
endif()
if (NOT postfix_count EQUAL 0)
message("'${src}' contains 'THRUST_NS_POSTFIX'. Replace with THRUST_NAMESPACE macros.")
set(found_errors 1)
endif()
if (NOT begin_count EQUAL end_count)
message("'${src}' namespace macros are unbalanced:")
message(" - THRUST_NAMESPACE_BEGIN occurs ${begin_count} times.")
message(" - THRUST_NAMESPACE_END occurs ${end_count} times.")
set(found_errors 1)
endif()
if (begin_count GREATER 0 AND header_count EQUAL 0)
message("'${src}' uses Thrust namespace macros, but does not (directly) `#include <thrust/detail/config.h>`.")
set(found_errors 1)
endif()
endif()
if (NOT ${src} IN_LIST stdpar_header_exclusions)
count_substrings("${src_contents}" "${algorithm_regex}" algorithm_count)
count_substrings("${src_contents}" "${memory_regex}" memory_count)
count_substrings("${src_contents}" "${numeric_regex}" numeric_count)
if (NOT algorithm_count EQUAL 0)
message("'${src}' includes the <algorithm> header. Replace with <thrust/detail/algorithm_wrapper.h>.")
set(found_errors 1)
endif()
if (NOT memory_count EQUAL 0)
message("'${src}' includes the <memory> header. Replace with <thrust/detail/memory_wrapper.h>.")
set(found_errors 1)
endif()
if (NOT numeric_count EQUAL 0)
message("'${src}' includes the <numeric> header. Replace with <thrust/detail/numeric_wrapper.h>.")
set(found_errors 1)
endif()
endif()
if (NOT ${src} IN_LIST legacy_macro_header_exclusions)
count_substrings("${src_contents}" "${thrust_legacy_macro_regex}" thrust_count)
count_substrings("${src_contents}" "${cub_legacy_macro_regex}" cub_count)
if (NOT thrust_count EQUAL 0)
message("'${src}' uses __THRUST_HAS_CUDART__. Replace with THRUST_RDC_ENABLED and NV_IF_TARGET.")
set(found_errors 1)
endif()
if (NOT cub_count EQUAL 0)
message("'${src}' uses CUB_RUNTIME_ENABLED. Replace with CUB_RDC_ENABLED and NV_IF_TARGET.")
set(found_errors 1)
endif()
endif()
endforeach()
if (NOT found_errors EQUAL 0)
message(FATAL_ERROR "Errors detected.")
endif()
|