|
23 | 23 | # Meta target for all header builds: |
24 | 24 | add_custom_target(cuco.all.headers) |
25 | 25 |
|
26 | | -find_package(CUDAToolkit) |
27 | | - |
28 | | -# Custom header test template content |
29 | | -set(CUCO_HEADER_TEST_TEMPLATE_CONTENT |
30 | | -"// This source file checks that: |
31 | | -// 1) Header <@header@> compiles without error. |
32 | | -// 2) Common macro collisions with platform/system headers are avoided. |
33 | | -
|
34 | | -// Define CUCO_HEADER_MACRO_CHECK(macro, header), which emits a diagnostic indicating |
35 | | -// a potential macro collision and halts. |
36 | | -// |
37 | | -// Hacky way to build a string, but it works on all tested platforms. |
38 | | -#define CUCO_HEADER_MACRO_CHECK(MACRO, HEADER) \\ |
39 | | - CUCO_HEADER_MACRO_CHECK_IMPL( \\ |
40 | | - Identifier MACRO should not be used from cuco headers due to conflicts with HEADER macros.) |
41 | | -
|
42 | | -// Use raw platform macros instead of the CCCL macros since we |
43 | | -// don't want to #include any headers other than the one being tested. |
44 | | -// |
45 | | -// This is implemented for GCC/Clang (cuco doesn't support MSVC). |
46 | | -#if defined(__clang__) || defined(__GNUC__) |
47 | | -
|
48 | | -// GCC/clang implementation: |
49 | | -# define CUCO_HEADER_MACRO_CHECK_IMPL(msg) CUCO_HEADER_MACRO_CHECK_IMPL0(GCC error #msg) |
50 | | -# define CUCO_HEADER_MACRO_CHECK_IMPL0(expr) _Pragma(#expr) |
51 | | -
|
52 | | -#else |
53 | | -# error \"Unsupported compiler for cuco header testing\" |
54 | | -#endif |
55 | | -
|
56 | | -// May be defined to skip macro check for certain configurations. |
57 | | -#ifndef CUCO_IGNORE_HEADER_MACRO_CHECKS |
58 | | -
|
59 | | -// complex.h conflicts |
60 | | -# define I CUCO_HEADER_MACRO_CHECK('I', complex.h) |
61 | | -
|
62 | | -// windows.h conflicts |
63 | | -# define small CUCO_HEADER_MACRO_CHECK('small', windows.h) |
64 | | -
|
65 | | -# ifdef _WIN32 |
66 | | -// On Windows, make sure any include of Windows.h (e.g. via NVTX) does not define the checked macros |
67 | | -# define WIN32_LEAN_AND_MEAN |
68 | | -# endif // _WIN32 |
69 | | -
|
70 | | -// termios.h conflicts (NVIDIA/thrust#1547) |
71 | | -# define B0 CUCO_HEADER_MACRO_CHECK(\"B0\", termios.h) |
72 | | -
|
73 | | -#endif // CUCO_IGNORE_HEADER_MACRO_CHECKS |
74 | | -
|
75 | | -#include <@header@> |
76 | | -
|
77 | | -// No main function - this is compiled as an object file for link checking |
78 | | -") |
79 | | - |
80 | | -function(cuco_generate_header_tests target_name headers lang) |
81 | | - # Configure header templates: |
82 | | - set(header_srcs) |
83 | | - foreach (header IN LISTS headers) |
84 | | - if(lang STREQUAL "CUDA") |
85 | | - set(header_src "${CMAKE_CURRENT_BINARY_DIR}/headers/${target_name}/${header}.cu") |
86 | | - else() |
87 | | - set(header_src "${CMAKE_CURRENT_BINARY_DIR}/headers/${target_name}/${header}.cpp") |
88 | | - endif() |
89 | | - |
90 | | - # Create the directory if it doesn't exist |
91 | | - get_filename_component(header_dir "${header_src}" DIRECTORY) |
92 | | - file(MAKE_DIRECTORY "${header_dir}") |
93 | | - |
94 | | - # Configure the template |
95 | | - string(CONFIGURE "${CUCO_HEADER_TEST_TEMPLATE_CONTENT}" header_content @ONLY) |
96 | | - file(WRITE "${header_src}" "${header_content}") |
97 | | - list(APPEND header_srcs ${header_src}) |
98 | | - endforeach() |
99 | | - |
100 | | - # Object library that compiles each header: |
101 | | - add_library(${target_name} OBJECT ${header_srcs}) |
102 | | - |
103 | | - # Set language-specific properties |
104 | | - if(lang STREQUAL "CUDA") |
105 | | - set_target_properties(${target_name} PROPERTIES |
106 | | - CUDA_SEPARABLE_COMPILATION ON |
107 | | - CUDA_RESOLVE_DEVICE_SYMBOLS ON |
108 | | - ) |
109 | | - |
110 | | - # Set CUDA architectures |
111 | | - if(CMAKE_CUDA_ARCHITECTURES) |
112 | | - set_target_properties(${target_name} PROPERTIES |
113 | | - CUDA_ARCHITECTURES "${CMAKE_CUDA_ARCHITECTURES}" |
114 | | - ) |
115 | | - endif() |
116 | | - |
117 | | - # Add required CUDA compiler flags for cuco |
118 | | - target_compile_options(${target_name} PRIVATE |
119 | | - $<$<COMPILE_LANGUAGE:CUDA>:--expt-extended-lambda> |
120 | | - ) |
121 | | - endif() |
122 | | - |
123 | | - target_link_libraries(${target_name} PUBLIC cuco::cuco) |
124 | | - |
125 | | - # Check that all functions in headers are either template functions or inline: |
126 | | - set(link_target ${target_name}.link_check) |
127 | | - if(lang STREQUAL "CUDA") |
128 | | - add_executable(${link_target} "${CMAKE_CURRENT_BINARY_DIR}/link_check_main_${target_name}.cu") |
129 | | - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/link_check_main_${target_name}.cu" |
130 | | - "int main() { return 0; }") |
131 | | - else() |
132 | | - add_executable(${link_target} "${CMAKE_CURRENT_BINARY_DIR}/link_check_main_${target_name}.cpp") |
133 | | - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/link_check_main_${target_name}.cpp" |
134 | | - "int main() { return 0; }") |
135 | | - endif() |
136 | | - |
137 | | - target_link_libraries(${link_target} PUBLIC cuco::cuco) |
138 | | - |
139 | | - # Linking both ${target_name} and $<TARGET_OBJECTS:${target_name}> forces CMake to |
140 | | - # link the same objects twice. The compiler will complain about duplicate symbols if |
141 | | - # any functions are missing inline markup. |
142 | | - target_link_libraries(${link_target} PRIVATE |
143 | | - ${target_name} |
144 | | - $<TARGET_OBJECTS:${target_name}> |
145 | | - ) |
146 | | -endfunction() |
147 | | - |
148 | 26 | function(cuco_add_header_test label definitions) |
149 | 27 | set(config_prefix "cuco") |
150 | 28 |
|
151 | | - # Get all .cuh and .hpp files... |
152 | | - file(GLOB_RECURSE all_headers |
| 29 | + # GLOB ALL THE THINGS - similar to Thrust's approach, including detail headers |
| 30 | + # Use GLOB_RECURSE to find all headers recursively |
| 31 | + file(GLOB_RECURSE headers |
153 | 32 | RELATIVE "${CUCO_SOURCE_DIR}/include" |
154 | 33 | CONFIGURE_DEPENDS |
155 | 34 | "${CUCO_SOURCE_DIR}/include/cuco/*.cuh" |
156 | 35 | "${CUCO_SOURCE_DIR}/include/cuco/*.hpp" |
157 | 36 | ) |
158 | | - |
159 | | - # ...and remove all the detail headers |
160 | | - file(GLOB_RECURSE headers_exclude_details |
161 | | - RELATIVE "${CUCO_SOURCE_DIR}/include" |
162 | | - CONFIGURE_DEPENDS |
163 | | - "${CUCO_SOURCE_DIR}/include/cuco/detail/*" |
164 | | - "${CUCO_SOURCE_DIR}/include/cuco/*/detail/*" |
165 | | - "${CUCO_SOURCE_DIR}/include/cuco/*/*/detail/*" |
166 | | - ) |
167 | 37 |
|
168 | | - set(headers ${all_headers}) |
169 | | - if(headers_exclude_details) |
170 | | - list(REMOVE_ITEM headers ${headers_exclude_details}) |
171 | | - endif() |
| 38 | + # Debug: Print found headers |
| 39 | + list(LENGTH headers headers_count) |
| 40 | + message(STATUS "Found ${headers_count} headers for testing: ${headers}") |
172 | 41 |
|
173 | 42 | # List of headers that have known issues or are not meant to be included directly |
174 | 43 | set(excluded_headers |
175 | | - # Add any headers that should be excluded from testing here |
176 | | - # Example: cuco/internal_header.cuh |
| 44 | + # Headers with circular dependencies that are not meant to be included directly |
| 45 | + cuco/detail/static_map/helpers.cuh |
177 | 46 | ) |
178 | 47 |
|
179 | 48 | # Remove excluded headers |
180 | 49 | if(excluded_headers) |
181 | 50 | list(REMOVE_ITEM headers ${excluded_headers}) |
| 51 | + list(LENGTH headers headers_count_after_exclusion) |
| 52 | + message(STATUS "After exclusion: ${headers_count_after_exclusion} headers remaining") |
182 | 53 | endif() |
183 | 54 |
|
184 | | - # Separate headers by type for different language compilation |
185 | | - set(cuda_headers) |
186 | | - set(cpp_headers) |
187 | | - |
188 | | - foreach(header IN LISTS headers) |
189 | | - if(header MATCHES "\\.cuh$") |
190 | | - list(APPEND cuda_headers ${header}) |
191 | | - elseif(header MATCHES "\\.hpp$") |
192 | | - list(APPEND cpp_headers ${header}) |
193 | | - list(APPEND cuda_headers ${header}) # .hpp files can also be compiled with CUDA |
194 | | - endif() |
| 55 | + # Only test with CUDA compiler since cuco is device-only |
| 56 | + set(headertest_target ${config_prefix}.headers.${label}) |
| 57 | + |
| 58 | + # Generate header test sources (simple approach since CCCL utilities aren't available) |
| 59 | + set(header_srcs) |
| 60 | + foreach (header IN LISTS headers) |
| 61 | + set(header_src "${CMAKE_CURRENT_BINARY_DIR}/headers/${headertest_target}/${header}.cu") |
| 62 | + |
| 63 | + # Create the directory if it doesn't exist |
| 64 | + get_filename_component(header_dir "${header_src}" DIRECTORY) |
| 65 | + file(MAKE_DIRECTORY "${header_dir}") |
| 66 | + |
| 67 | + # Write simple test file that includes the header |
| 68 | + file(WRITE "${header_src}" "#include <${header}>\nint main() { return 0; }\n") |
| 69 | + list(APPEND header_srcs ${header_src}) |
195 | 70 | endforeach() |
196 | 71 |
|
197 | | - # Compile headers with both host and cuda compilers |
198 | | - set(langs CXX CUDA) |
| 72 | + # Create object library that compiles each header |
| 73 | + add_library(${headertest_target} OBJECT ${header_srcs}) |
| 74 | + target_link_libraries(${headertest_target} PUBLIC cuco::cuco) |
| 75 | + if (definitions) |
| 76 | + target_compile_definitions(${headertest_target} PRIVATE ${definitions}) |
| 77 | + endif() |
199 | 78 |
|
200 | | - foreach (lang IN LISTS langs) |
201 | | - set(headertest_target ${config_prefix}.headers.${label}) |
202 | | - if (lang STREQUAL "CXX") |
203 | | - # Append .cxx to the header test target name when compiling with C++ compiler |
204 | | - set(headertest_target ${headertest_target}.cxx) |
205 | | - set(test_headers ${cpp_headers}) |
206 | | - else() |
207 | | - set(test_headers ${cuda_headers}) |
208 | | - endif() |
| 79 | + # Add required CUDA compiler flags for cuco |
| 80 | + target_compile_options(${headertest_target} PRIVATE |
| 81 | + $<$<COMPILE_LANGUAGE:CUDA>:--expt-extended-lambda> |
| 82 | + ) |
209 | 83 |
|
210 | | - if(test_headers) |
211 | | - cuco_generate_header_tests(${headertest_target} "${test_headers}" ${lang}) |
212 | | - |
213 | | - if (definitions) |
214 | | - target_compile_definitions(${headertest_target} PRIVATE ${definitions}) |
215 | | - endif() |
216 | | - |
217 | | - # Disable macro checks for now since cuco has known issues with 'I' identifier |
218 | | - # This should be removed once the macro collision issues are fixed |
219 | | - target_compile_definitions(${headertest_target} PRIVATE CUCO_IGNORE_HEADER_MACRO_CHECKS) |
| 84 | + # Disable macro checks for now since cuco has known issues with 'I' identifier |
| 85 | + # This should be removed once the macro collision issues are fixed |
| 86 | + target_compile_definitions(${headertest_target} PRIVATE CUCO_IGNORE_HEADER_MACRO_CHECKS) |
220 | 87 |
|
221 | | - add_dependencies(cuco.all.headers ${headertest_target}) |
222 | | - endif() |
223 | | - endforeach() |
| 88 | + add_dependencies(cuco.all.headers ${headertest_target}) |
224 | 89 | endfunction() |
225 | 90 |
|
226 | 91 | # Base header test - ensure all headers compile cleanly |
|
0 commit comments