1##============================================================================ 2## Copyright (c) Kitware, Inc. 3## All rights reserved. 4## See LICENSE.txt for details. 5## This software is distributed WITHOUT ANY WARRANTY; without even 6## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 7## PURPOSE. See the above copyright notice for more information. 8## 9## Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS). 10## Copyright 2014 UT-Battelle, LLC. 11## Copyright 2014 Los Alamos National Security. 12## 13## Under the terms of Contract DE-NA0003525 with NTESS, 14## the U.S. Government retains certain rights in this software. 15## 16## Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National 17## Laboratory (LANL), the U.S. Government retains certain rights in 18## this software. 19##============================================================================ 20 21include(CMakeParseArguments) 22 23include(VTKmDeviceAdapters) 24include(VTKmCPUVectorization) 25 26#----------------------------------------------------------------------------- 27# Utility to build a kit name from the current directory. 28function(vtkm_get_kit_name kitvar) 29 # Will this always work? It should if ${CMAKE_CURRENT_SOURCE_DIR} is 30 # built from ${VTKm_SOURCE_DIR}. 31 string(REPLACE "${VTKm_SOURCE_DIR}/" "" dir_prefix ${CMAKE_CURRENT_SOURCE_DIR}) 32 string(REPLACE "/" "_" kit "${dir_prefix}") 33 set(${kitvar} "${kit}" PARENT_SCOPE) 34 # Optional second argument to get dir_prefix. 35 if (${ARGC} GREATER 1) 36 set(${ARGV1} "${dir_prefix}" PARENT_SCOPE) 37 endif (${ARGC} GREATER 1) 38endfunction(vtkm_get_kit_name) 39 40#----------------------------------------------------------------------------- 41function(vtkm_pyexpander_generated_file generated_file_name) 42 # If pyexpander is available, add targets to build and check 43 if(PYEXPANDER_FOUND AND PYTHONINTERP_FOUND) 44 add_custom_command( 45 OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${generated_file_name}.checked 46 COMMAND ${CMAKE_COMMAND} 47 -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE} 48 -DPYEXPANDER_COMMAND=${PYEXPANDER_COMMAND} 49 -DSOURCE_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${generated_file_name} 50 -DGENERATED_FILE=${CMAKE_CURRENT_BINARY_DIR}/${generated_file_name} 51 -P ${VTKm_CMAKE_MODULE_PATH}/VTKmCheckPyexpander.cmake 52 MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/${generated_file_name}.in 53 DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${generated_file_name} 54 COMMENT "Checking validity of ${generated_file_name}" 55 ) 56 add_custom_target(check_${generated_file_name} ALL 57 DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${generated_file_name}.checked 58 ) 59 endif() 60endfunction(vtkm_pyexpander_generated_file) 61 62#----------------------------------------------------------------------------- 63function(vtkm_compile_as_cuda output) 64 # We can't use set_source_files_properties(<> PROPERTIES LANGUAGE "CUDA") 65 # for the following reasons: 66 # 67 # 1. As of CMake 3.10 MSBuild cuda language support has a bug where files 68 # aren't passed to nvcc with the explicit '-x cu' flag which will cause 69 # them to be compiled without CUDA actually enabled. 70 # 2. If the source file is used by multiple targets(libraries/executable) 71 # they will all see the source file marked as being CUDA. This will cause 72 # tests / examples that reuse sources with different backends to use CUDA 73 # by mistake 74 # 75 # The result of this is that instead we will use file(GENERATE ) to construct 76 # a proxy cu file 77 set(_cuda_srcs ) 78 foreach(_to_be_cuda_file ${ARGN}) 79 get_filename_component(_fname_ext "${_to_be_cuda_file}" EXT) 80 if(_fname_ext STREQUAL ".cu") 81 list(APPEND _cuda_srcs "${_to_be_cuda_file}") 82 else() 83 get_filename_component(_cuda_fname "${_to_be_cuda_file}" NAME_WE) 84 get_filename_component(_not_cuda_fullpath "${_to_be_cuda_file}" ABSOLUTE) 85 list(APPEND _cuda_srcs "${CMAKE_CURRENT_BINARY_DIR}/${_cuda_fname}.cu") 86 file(GENERATE 87 OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_cuda_fname}.cu 88 CONTENT "#include \"${_not_cuda_fullpath}\"") 89 endif() 90 endforeach() 91 set(${output} ${_cuda_srcs} PARENT_SCOPE) 92endfunction() 93 94#----------------------------------------------------------------------------- 95function(vtkm_add_header_build_test name dir_prefix use_cuda) 96 set(hfiles ${ARGN}) 97 98 set(ext "cxx") 99 if(use_cuda) 100 set(ext "cu") 101 endif() 102 103 set(srcs) 104 foreach (header ${hfiles}) 105 get_source_file_property(cant_be_tested ${header} VTKm_CANT_BE_HEADER_TESTED) 106 if( NOT cant_be_tested ) 107 get_filename_component(headername ${header} NAME_WE) 108 get_filename_component(headerextension ${header} EXT) 109 string(SUBSTRING ${headerextension} 1 -1 headerextension) 110 set(src ${CMAKE_CURRENT_BINARY_DIR}/TB_${headername}_${headerextension}.${ext}) 111 112 #By using file generate we will not trigger CMake execution when 113 #a header gets touched 114 file(GENERATE 115 OUTPUT ${src} 116 CONTENT " 117//mark that we are including headers as test for completeness. 118//This is used by headers that include thrust to properly define a proper 119//device backend / system 120#define VTKM_TEST_HEADER_BUILD 121#include <${dir_prefix}/${headername}.${headerextension}> 122int ${headername}_${headerextension}_testbuild_symbol;" 123 ) 124 list(APPEND srcs ${src}) 125 endif() 126 endforeach() 127 128 set_source_files_properties(${hfiles} 129 PROPERTIES HEADER_FILE_ONLY TRUE 130 ) 131 132 #only attempt to add a test build executable if we have any headers to 133 #test. this might not happen when everything depends on thrust. 134 list(LENGTH srcs num_srcs) 135 if (${num_srcs} EQUAL 0) 136 return() 137 endif() 138 139 if(TARGET TestBuild_${name}) 140 #If the target already exists just add more sources to it 141 target_sources(TestBuild_${name} PRIVATE ${srcs}) 142 else() 143 add_library(TestBuild_${name} STATIC ${srcs} ${hfiles}) 144 # Send the libraries created for test builds to their own directory so as to 145 # not pollute the directory with useful libraries. 146 set_property(TARGET TestBuild_${name} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH}/testbuilds) 147 set_property(TARGET TestBuild_${name} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH}/testbuilds) 148 149 target_link_libraries(TestBuild_${name} PRIVATE vtkm_compiler_flags vtkm_taotuple) 150 151 if(TARGET vtkm::tbb) 152 #make sure that we have the tbb include paths when tbb is enabled. 153 target_link_libraries(TestBuild_${name} PRIVATE vtkm::tbb) 154 endif() 155 156 if(TARGET vtkm_diy) 157 target_link_libraries(TestBuild_${name} PRIVATE vtkm_diy) 158 endif() 159 160 if(TARGET vtkm_rendering_gl_context) 161 target_link_libraries(TestBuild_${name} PRIVATE vtkm_rendering_gl_context) 162 endif() 163 164 165 endif() 166 167endfunction() 168 169#----------------------------------------------------------------------------- 170function(vtkm_generate_export_header lib_name) 171 # Get the location of this library in the directory structure 172 # export headers work on the directory structure more than the lib_name 173 vtkm_get_kit_name(kit_name dir_prefix) 174 175 # Now generate a header that holds the macros needed to easily export 176 # template classes. This 177 string(TOUPPER ${kit_name} BASE_NAME_UPPER) 178 set(EXPORT_MACRO_NAME "${BASE_NAME_UPPER}") 179 180 set(EXPORT_IS_BUILT_STATIC 0) 181 get_target_property(is_static ${lib_name} TYPE) 182 if(${is_static} STREQUAL "STATIC_LIBRARY") 183 #If we are building statically set the define symbol 184 set(EXPORT_IS_BUILT_STATIC 1) 185 endif() 186 unset(is_static) 187 188 get_target_property(EXPORT_IMPORT_CONDITION ${lib_name} DEFINE_SYMBOL) 189 if(NOT EXPORT_IMPORT_CONDITION) 190 #set EXPORT_IMPORT_CONDITION to what the DEFINE_SYMBOL would be when 191 #building shared 192 set(EXPORT_IMPORT_CONDITION ${kit_name}_EXPORTS) 193 endif() 194 195 196 configure_file( 197 ${VTKm_SOURCE_DIR}/CMake/VTKmExportHeaderTemplate.h.in 198 ${VTKm_BINARY_DIR}/include/${dir_prefix}/${kit_name}_export.h 199 @ONLY) 200 201 if(NOT VTKm_INSTALL_ONLY_LIBRARIES) 202 install(FILES ${VTKm_BINARY_DIR}/include/${dir_prefix}/${kit_name}_export.h 203 DESTINATION ${VTKm_INSTALL_INCLUDE_DIR}/${dir_prefix} 204 ) 205 endif() 206 207endfunction(vtkm_generate_export_header) 208 209function(vtkm_install_headers dir_prefix) 210 if(NOT VTKm_INSTALL_ONLY_LIBRARIES) 211 set(hfiles ${ARGN}) 212 install(FILES ${hfiles} 213 DESTINATION ${VTKm_INSTALL_INCLUDE_DIR}/${dir_prefix} 214 ) 215 endif() 216endfunction(vtkm_install_headers) 217 218 219#----------------------------------------------------------------------------- 220function(vtkm_declare_headers) 221 #TODO: look at the testable and cuda options 222 set(options CUDA) 223 set(oneValueArgs TESTABLE) 224 set(multiValueArgs EXCLUDE_FROM_TESTING) 225 cmake_parse_arguments(VTKm_DH "${options}" 226 "${oneValueArgs}" "${multiValueArgs}" 227 ${ARGN} 228 ) 229 230 #The testable keyword allows the caller to turn off the header testing, 231 #mainly used so that backends can be installed even when they can't be 232 #built on the machine. 233 #Since this is an optional property not setting it means you do want testing 234 if(NOT DEFINED VTKm_DH_TESTABLE) 235 set(VTKm_DH_TESTABLE ON) 236 endif() 237 238 set(hfiles ${VTKm_DH_UNPARSED_ARGUMENTS} ${VTKm_DH_EXCLUDE_FROM_TESTING}) 239 vtkm_get_kit_name(name dir_prefix) 240 241 #only do header testing if enable testing is turned on 242 if (VTKm_ENABLE_TESTING AND VTKm_DH_TESTABLE) 243 set_source_files_properties(${VTKm_DH_EXCLUDE_FROM_TESTING} 244 PROPERTIES VTKm_CANT_BE_HEADER_TESTED TRUE 245 ) 246 247 vtkm_add_header_build_test( 248 "${name}" "${dir_prefix}" "${VTKm_DH_CUDA}" ${hfiles}) 249 endif() 250 251 vtkm_install_headers("${dir_prefix}" ${hfiles}) 252endfunction(vtkm_declare_headers) 253 254#----------------------------------------------------------------------------- 255# Add a VTK-m library. The name of the library will match the "kit" name 256# (e.g. vtkm_rendering) unless the NAME argument is given. 257# 258# vtkm_library( 259# [NAME <name>] 260# SOURCES <source_list> 261# TEMPLATE_SOURCES <.hxx > 262# HEADERS <header list> 263# [WRAP_FOR_CUDA <source_list>] 264# ) 265function(vtkm_library) 266 set(oneValueArgs NAME) 267 set(multiValueArgs SOURCES HEADERS TEMPLATE_SOURCES WRAP_FOR_CUDA) 268 cmake_parse_arguments(VTKm_LIB 269 "${options}" "${oneValueArgs}" "${multiValueArgs}" 270 ${ARGN} 271 ) 272 273 if(NOT VTKm_LIB_NAME) 274 message(FATAL_ERROR "vtkm library must have an explicit name") 275 endif() 276 set(lib_name ${VTKm_LIB_NAME}) 277 278 if(TARGET vtkm::cuda) 279 vtkm_compile_as_cuda(cu_srcs ${VTKm_LIB_WRAP_FOR_CUDA}) 280 set(VTKm_LIB_WRAP_FOR_CUDA ${cu_srcs}) 281 endif() 282 283 284 add_library(${lib_name} 285 ${VTKm_LIB_SOURCES} 286 ${VTKm_LIB_HEADERS} 287 ${VTKm_LIB_TEMPLATE_SOURCES} 288 ${VTKm_LIB_WRAP_FOR_CUDA} 289 ) 290 291 #specify where to place the built library 292 set_property(TARGET ${lib_name} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH}) 293 set_property(TARGET ${lib_name} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH}) 294 set_property(TARGET ${lib_name} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${VTKm_EXECUTABLE_OUTPUT_PATH}) 295 296 if(NOT VTKm_USE_DEFAULT_SYMBOL_VISIBILITY) 297 set_property(TARGET ${lib_name} PROPERTY CUDA_VISIBILITY_PRESET "hidden") 298 set_property(TARGET ${lib_name} PROPERTY CXX_VISIBILITY_PRESET "hidden") 299 endif() 300 301 # allow the static cuda runtime find the driver (libcuda.dyllib) at runtime. 302 if(APPLE) 303 set_property(TARGET ${lib_name} PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES}) 304 endif() 305 306 # Setup the SOVERSION and VERSION information for this vtkm library 307 set_property(TARGET ${lib_name} PROPERTY VERSION 1) 308 set_property(TARGET ${lib_name} PROPERTY SOVERSION 1) 309 310 # Support custom library suffix names, for other projects wanting to inject 311 # their own version numbers etc. 312 if(DEFINED VTKm_CUSTOM_LIBRARY_SUFFIX) 313 set(_lib_suffix "${VTKm_CUSTOM_LIBRARY_SUFFIX}") 314 else() 315 set(_lib_suffix "-${VTKm_VERSION_MAJOR}.${VTKm_VERSION_MINOR}") 316 endif() 317 set_property(TARGET ${lib_name} PROPERTY OUTPUT_NAME ${lib_name}${_lib_suffix}) 318 319 #generate the export header and install it 320 vtkm_generate_export_header(${lib_name}) 321 322 #test and install the headers 323 vtkm_declare_headers(${VTKm_LIB_HEADERS} 324 EXCLUDE_FROM_TESTING ${VTKm_LIB_TEMPLATE_SOURCES} 325 ) 326 327 #install the library itself 328 install(TARGETS ${lib_name} 329 EXPORT ${VTKm_EXPORT_NAME} 330 ARCHIVE DESTINATION ${VTKm_INSTALL_LIB_DIR} 331 LIBRARY DESTINATION ${VTKm_INSTALL_LIB_DIR} 332 RUNTIME DESTINATION ${VTKm_INSTALL_BIN_DIR} 333 ) 334 335endfunction(vtkm_library) 336 337#----------------------------------------------------------------------------- 338# Declare unit tests, which should be in the same directory as a kit 339# (package, module, whatever you call it). Usage: 340# 341# vtkm_unit_tests( 342# NAME 343# SOURCES <source_list> 344# BACKEND <type> 345# LIBRARIES <dependent_library_list> 346# TEST_ARGS <argument_list> 347# MPI 348# <options> 349# ) 350# 351# [BACKEND]: mark all source files as being compiled with the proper defines 352# to make this backend the default backend 353# If the backend is specified as CUDA it will also imply all 354# sources should be treated as CUDA sources 355# The backend name will also be added to the executable name 356# so you can test multiple backends easily 357# 358# [LIBRARIES] : extra libraries that this set of tests need to link too 359# 360# [TEST_ARGS] : arguments that should be passed on the command line to the 361# test executable 362# 363# [MPI] : when specified, the tests should be run in parallel if 364# MPI is enabled. 365# 366function(vtkm_unit_tests) 367 if (NOT VTKm_ENABLE_TESTING) 368 return() 369 endif() 370 371 set(options) 372 set(global_options ${options} MPI) 373 set(oneValueArgs BACKEND NAME) 374 set(multiValueArgs SOURCES LIBRARIES TEST_ARGS) 375 cmake_parse_arguments(VTKm_UT 376 "${global_options}" "${oneValueArgs}" "${multiValueArgs}" 377 ${ARGN} 378 ) 379 vtkm_parse_test_options(VTKm_UT_SOURCES "${options}" ${VTKm_UT_SOURCES}) 380 381 set(test_prog ) 382 set(backend ${VTKm_UT_BACKEND}) 383 384 if(VTKm_UT_NAME) 385 set(test_prog "${VTKm_UT_NAME}") 386 else() 387 vtkm_get_kit_name(kit) 388 set(test_prog "UnitTests_${kit}") 389 endif() 390 if(backend) 391 set(test_prog "${test_prog}_${backend}") 392 endif() 393 394 if(VTKm_UT_MPI) 395 # for MPI tests, suffix test name and add MPI_Init/MPI_Finalize calls. 396 set(test_prog "${test_prog}_mpi") 397 set(extraArgs EXTRA_INCLUDE "vtkm/cont/testing/Testing.h" 398 FUNCTION "vtkm::cont::testing::Environment env") 399 else() 400 set(extraArgs) 401 endif() 402 403 #the creation of the test source list needs to occur before the labeling as 404 #cuda. This is so that we get the correctly named entry points generated 405 create_test_sourcelist(test_sources ${test_prog}.cxx ${VTKm_UT_SOURCES} ${extraArgs}) 406 if(backend STREQUAL "CUDA") 407 vtkm_compile_as_cuda(cu_srcs ${VTKm_UT_SOURCES}) 408 set(VTKm_UT_SOURCES ${cu_srcs}) 409 endif() 410 411 add_executable(${test_prog} ${test_prog}.cxx ${VTKm_UT_SOURCES}) 412 set_property(TARGET ${test_prog} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH}) 413 set_property(TARGET ${test_prog} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${VTKm_LIBRARY_OUTPUT_PATH}) 414 set_property(TARGET ${test_prog} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${VTKm_EXECUTABLE_OUTPUT_PATH}) 415 416 target_link_libraries(${test_prog} PRIVATE vtkm_cont ${VTKm_UT_LIBRARIES}) 417 if(backend) 418 target_compile_definitions(${test_prog} PRIVATE "VTKM_DEVICE_ADAPTER=VTKM_DEVICE_ADAPTER_${backend}") 419 endif() 420 421 #determine the timeout for all the tests based on the backend. CUDA tests 422 #generally require more time because of kernel generation. 423 set(timeout 180) 424 set(run_serial False) 425 if(backend STREQUAL "CUDA") 426 set(timeout 1500) 427 elseif(backend STREQUAL "OPENMP") 428 #We need to have all OpenMP tests run serially as they 429 #will uses all the system cores, and we will cause a N*N thread 430 #explosion which causes the tests to run slower than when run 431 #serially 432 set(run_serial True) 433 endif() 434 435 436 foreach (test ${VTKm_UT_SOURCES}) 437 get_filename_component(tname ${test} NAME_WE) 438 if(VTKm_UT_MPI AND VTKm_ENABLE_MPI) 439 add_test(NAME ${tname}${backend} 440 COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 3 ${MPIEXEC_PREFLAGS} 441 $<TARGET_FILE:${test_prog}> ${tname} ${VTKm_UT_TEST_ARGS} 442 ${MPIEXEC_POSTFLAGS} 443 ) 444 else() 445 add_test(NAME ${tname}${backend} 446 COMMAND ${test_prog} ${tname} ${VTKm_UT_TEST_ARGS} 447 ) 448 endif() 449 set_tests_properties("${tname}${backend}" PROPERTIES 450 TIMEOUT ${timeout} 451 RUN_SERIAL ${run_serial} 452 ) 453 endforeach (test) 454 455endfunction(vtkm_unit_tests) 456 457# ----------------------------------------------------------------------------- 458# vtkm_parse_test_options(varname options) 459# INTERNAL: Parse options specified for individual tests. 460# 461# Parses the arguments to separate out options specified after the test name 462# separated by a comma e.g. 463# 464# TestName,Option1,Option2 465# 466# For every option in options, this will set _TestName_Option1, 467# _TestName_Option2, etc in the parent scope. 468# 469function(vtkm_parse_test_options varname options) 470 set(names) 471 foreach(arg IN LISTS ARGN) 472 set(test_name ${arg}) 473 set(test_options) 474 if(test_name AND "x${test_name}" MATCHES "^x([^,]*),(.*)$") 475 set(test_name "${CMAKE_MATCH_1}") 476 string(REPLACE "," ";" test_options "${CMAKE_MATCH_2}") 477 endif() 478 foreach(opt IN LISTS test_options) 479 list(FIND options "${opt}" index) 480 if(index EQUAL -1) 481 message(WARNING "Unknown option '${opt}' specified for test '${test_name}'") 482 else() 483 set(_${test_name}_${opt} TRUE PARENT_SCOPE) 484 endif() 485 endforeach() 486 list(APPEND names ${test_name}) 487 endforeach() 488 set(${varname} ${names} PARENT_SCOPE) 489endfunction() 490