1# Copyright (c) 2017-2021, Lawrence Livermore National Security, LLC and 2# other BLT Project Developers. See the top-level LICENSE file for details 3# 4# SPDX-License-Identifier: (BSD-3-Clause) 5 6include(CMakeParseArguments) 7 8## Internal BLT CMake Macros 9 10 11##----------------------------------------------------------------------------- 12## blt_determine_scope(TARGET <target> 13## SCOPE <PUBLIC (Default)| INTERFACE | PRIVATE> 14## OUT <out variable name>) 15## 16## Returns the normalized scope string for a given SCOPE and TARGET to be used 17## in BLT macros. 18## 19## TARGET - Name of CMake Target that the property is being added to 20## Note: the only real purpose of this parameter is to make sure we aren't 21## adding returning other than INTERFACE for Interface Libraries 22## SCOPE - case-insensitive scope string, defaults to PUBLIC 23## OUT - variable that is filled with the uppercased scope 24## 25##----------------------------------------------------------------------------- 26macro(blt_determine_scope) 27 28 set(options) 29 set(singleValueArgs TARGET SCOPE OUT) 30 set(multiValueArgs ) 31 32 # Parse the arguments 33 cmake_parse_arguments(arg "${options}" "${singleValueArgs}" 34 "${multiValueArgs}" ${ARGN} ) 35 36 # Convert to upper case and strip white space 37 string(TOUPPER "${arg_SCOPE}" _uppercaseScope) 38 string(STRIP "${_uppercaseScope}" _uppercaseScope ) 39 40 if("${_uppercaseScope}" STREQUAL "") 41 # Default to public 42 set(_uppercaseScope PUBLIC) 43 elseif(NOT ("${_uppercaseScope}" STREQUAL "PUBLIC" OR 44 "${_uppercaseScope}" STREQUAL "INTERFACE" OR 45 "${_uppercaseScope}" STREQUAL "PRIVATE")) 46 message(FATAL_ERROR "Given SCOPE (${arg_SCOPE}) is not valid, valid options are:" 47 "PUBLIC, INTERFACE, or PRIVATE") 48 endif() 49 50 if(TARGET ${arg_TARGET}) 51 get_property(_targetType TARGET ${arg_TARGET} PROPERTY TYPE) 52 if(${_targetType} STREQUAL "INTERFACE_LIBRARY") 53 # Interface targets can only set INTERFACE 54 if("${_uppercaseScope}" STREQUAL "PUBLIC" OR 55 "${_uppercaseScope}" STREQUAL "INTERFACE") 56 set(${arg_OUT} INTERFACE) 57 else() 58 message(FATAL_ERROR "Cannot set PRIVATE scope to Interface Library." 59 "Change to Scope to INTERFACE.") 60 endif() 61 else() 62 set(${arg_OUT} ${_uppercaseScope}) 63 endif() 64 else() 65 set(${arg_OUT} ${_uppercaseScope}) 66 endif() 67 68 unset(_targetType) 69 unset(_uppercaseScope) 70 71endmacro(blt_determine_scope) 72 73 74##----------------------------------------------------------------------------- 75## blt_error_if_target_exists() 76## 77## Checks if target already exists in CMake project and errors out with given 78## error_msg. 79##----------------------------------------------------------------------------- 80function(blt_error_if_target_exists target_name error_msg) 81 if (TARGET ${target_name}) 82 message(FATAL_ERROR "${error_msg}Duplicate target name: ${target_name}") 83 endif() 84endfunction() 85 86##----------------------------------------------------------------------------- 87## blt_fix_fortran_openmp_flags(<target name>) 88## 89## Fixes the openmp flags for a Fortran target if they are different from the 90## corresponding C/C++ OpenMP flags. 91##----------------------------------------------------------------------------- 92function(blt_fix_fortran_openmp_flags target_name) 93 94 if (ENABLE_FORTRAN AND ENABLE_OPENMP AND BLT_OPENMP_FLAGS_DIFFER) 95 96 # The OpenMP interface library will have been added as a direct 97 # link dependency instead of via flags 98 get_target_property(target_link_libs ${target_name} LINK_LIBRARIES) 99 if ( target_link_libs ) 100 # Since this is only called on executable targets we can safely convert 101 # from a "real" target back to a "fake" one as this is a sink vertex in 102 # the DAG. Only the link flags need to be modified. 103 list(FIND target_link_libs "openmp" _omp_index) 104 if(${_omp_index} GREATER -1) 105 message(STATUS "Fixing OpenMP Flags for target[${target_name}]") 106 107 # Remove openmp from libraries 108 list(REMOVE_ITEM target_link_libs "openmp") 109 set_target_properties( ${target_name} PROPERTIES 110 LINK_LIBRARIES "${target_link_libs}" ) 111 112 # Add openmp compile flags verbatim w/ generator expression 113 get_target_property(omp_compile_flags openmp INTERFACE_COMPILE_OPTIONS) 114 target_compile_options(${target_name} PUBLIC ${omp_compile_flags}) 115 116 # Change CXX flags to Fortran flags 117 118 # These are set through blt_add_target_link_flags which needs to use 119 # the link_libraries for interface libraries in CMake < 3.13 120 if( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13.0" ) 121 get_target_property(omp_link_flags openmp INTERFACE_LINK_OPTIONS) 122 else() 123 get_target_property(omp_link_flags openmp INTERFACE_LINK_LIBRARIES) 124 endif() 125 126 string( REPLACE "${OpenMP_CXX_FLAGS}" "${OpenMP_Fortran_FLAGS}" 127 correct_omp_link_flags 128 "${omp_link_flags}" 129 ) 130 if( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13.0" ) 131 target_link_options(${target_name} PRIVATE "${correct_omp_link_flags}") 132 else() 133 set_property(TARGET ${target_name} APPEND PROPERTY LINK_FLAGS "${correct_omp_link_flags}") 134 endif() 135 endif() 136 137 # Handle registered library general case 138 139 # OpenMP is an interface library which doesn't have a LINK_FLAGS property 140 # in versions < 3.13 141 set(_property_name LINK_FLAGS) 142 if( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13.0" ) 143 # In CMake 3.13+, LINK_FLAGS was converted to LINK_OPTIONS. 144 set(_property_name LINK_OPTIONS) 145 endif() 146 get_target_property(target_link_flags ${target_name} ${_property_name}) 147 if ( target_link_flags ) 148 149 string( REPLACE "${OpenMP_CXX_FLAGS}" "${OpenMP_Fortran_FLAGS}" 150 correct_link_flags 151 "${target_link_flags}" 152 ) 153 set_target_properties( ${target_name} PROPERTIES ${_property_name} 154 "${correct_link_flags}" ) 155 endif() 156 endif() 157 158 endif() 159 160endfunction() 161 162##----------------------------------------------------------------------------- 163## blt_find_executable(NAME <name of program to find> 164## EXECUTABLES [exe1 [exe2 ...]]) 165## 166## This macro attempts to find the given executable via either a previously defined 167## <UPPERCASE_NAME>_EXECUTABLE or using find_program with the given EXECUTABLES. 168## if EXECUTABLES is left empty, then NAME is used. This macro will only attempt 169## to locate the executable if <UPPERCASE_NAME>_ENABLED is TRUE. 170## 171## If successful the following variables will be defined: 172## <UPPERCASE_NAME>_FOUND 173## <UPPERCASE_NAME>_EXECUTABLE 174##----------------------------------------------------------------------------- 175macro(blt_find_executable) 176 177 set(options) 178 set(singleValueArgs NAME) 179 set(multiValueArgs EXECUTABLES) 180 181 # Parse the arguments 182 cmake_parse_arguments(arg "${options}" "${singleValueArgs}" 183 "${multiValueArgs}" ${ARGN} ) 184 185 # Check arguments 186 if ( NOT DEFINED arg_NAME ) 187 message( FATAL_ERROR "Must provide a NAME argument to the 'blt_find_executable' macro" ) 188 endif() 189 190 string(TOUPPER ${arg_NAME} _ucname) 191 192 message(STATUS "${arg_NAME} support is ${ENABLE_${_ucname}}") 193 if (${ENABLE_${_ucname}}) 194 set(_exes ${arg_NAME}) 195 if (DEFINED arg_EXECUTABLES) 196 set(_exes ${arg_EXECUTABLES}) 197 endif() 198 199 if (${_ucname}_EXECUTABLE) 200 if (NOT EXISTS ${${_ucname}_EXECUTABLE}) 201 message(FATAL_ERROR "User defined ${_ucname}_EXECUTABLE does not exist. Fix/unset variable or set ENABLE_${_ucname} to OFF.") 202 endif() 203 else() 204 find_program(${_ucname}_EXECUTABLE 205 NAMES ${_exes} 206 DOC "Path to ${arg_NAME} executable") 207 endif() 208 209 # Handle REQUIRED and QUIET arguments 210 # this will also set ${_ucname}_FOUND to true if ${_ucname}_EXECUTABLE exists 211 include(FindPackageHandleStandardArgs) 212 find_package_handle_standard_args(${arg_NAME} 213 "Failed to locate ${arg_NAME} executable" 214 ${_ucname}_EXECUTABLE) 215 endif() 216endmacro(blt_find_executable) 217 218 219##------------------------------------------------------------------------------ 220## blt_inherit_target_info( TO <target> 221## FROM <target> 222## OBJECT [TRUE|FALSE]) 223## 224## The purpose of this macro is if you want to grab all the inheritable info 225## from the FROM target but don't want to make the TO target depend on it. 226## Which is useful if you don't want to export the FROM target. 227## 228## The OBJECT parameter is because object libraries can only inherit certain 229## properties. 230## 231## This inherits the following properties: 232## INTERFACE_COMPILE_DEFINITIONS 233## INTERFACE_INCLUDE_DIRECTORIES 234## INTERFACE_LINK_DIRECTORIES 235## INTERFACE_LINK_LIBRARIES 236## INTERFACE_SYSTEM_INCLUDE_DIRECTORIES 237##------------------------------------------------------------------------------ 238macro(blt_inherit_target_info) 239 set(options) 240 set(singleValueArgs TO FROM OBJECT) 241 set(multiValueArgs) 242 243 # Parse the arguments 244 cmake_parse_arguments(arg "${options}" "${singleValueArgs}" 245 "${multiValueArgs}" ${ARGN} ) 246 247 # Check arguments 248 if ( NOT DEFINED arg_TO ) 249 message( FATAL_ERROR "Must provide a TO argument to the 'blt_inherit_target' macro" ) 250 endif() 251 252 if ( NOT DEFINED arg_FROM ) 253 message( FATAL_ERROR "Must provide a FROM argument to the 'blt_inherit_target' macro" ) 254 endif() 255 256 blt_determine_scope(TARGET ${arg_TO} OUT _scope) 257 258 get_target_property(_interface_system_includes 259 ${arg_FROM} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) 260 if ( _interface_system_includes ) 261 target_include_directories(${arg_TO} SYSTEM ${_scope} ${_interface_system_includes}) 262 endif() 263 264 get_target_property(_interface_includes 265 ${arg_FROM} INTERFACE_INCLUDE_DIRECTORIES) 266 if ( _interface_includes ) 267 target_include_directories(${arg_TO} ${_scope} ${_interface_includes}) 268 endif() 269 270 get_target_property(_interface_defines 271 ${arg_FROM} INTERFACE_COMPILE_DEFINITIONS) 272 if ( _interface_defines ) 273 target_compile_definitions( ${arg_TO} ${_scope} ${_interface_defines}) 274 endif() 275 276 if( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13.0" ) 277 get_target_property(_interface_link_options 278 ${arg_FROM} INTERFACE_LINK_OPTIONS) 279 if ( _interface_link_options ) 280 target_link_options( ${arg_TO} ${_scope} ${_interface_link_options}) 281 endif() 282 endif() 283 284 get_target_property(_interface_compile_options 285 ${arg_FROM} INTERFACE_COMPILE_OPTIONS) 286 if ( _interface_compile_options ) 287 target_compile_options( ${arg_TO} ${_scope} ${_interface_compile_options}) 288 endif() 289 290 if ( NOT arg_OBJECT ) 291 get_target_property(_interface_link_directories 292 ${arg_FROM} INTERFACE_LINK_DIRECTORIES) 293 if ( _interface_link_directories ) 294 target_link_directories( ${arg_TO} ${_scope} ${_interface_link_directories}) 295 endif() 296 297 get_target_property(_interface_link_libraries 298 ${arg_FROM} INTERFACE_LINK_LIBRARIES) 299 if ( _interface_link_libraries ) 300 target_link_libraries( ${arg_TO} ${_scope} ${_interface_link_libraries}) 301 endif() 302 endif() 303 304endmacro(blt_inherit_target_info) 305 306##------------------------------------------------------------------------------ 307## blt_expand_depends( DEPENDS_ON [dep1 ...] 308## RESULT [variable] ) 309##------------------------------------------------------------------------------ 310macro(blt_expand_depends) 311 set(options) 312 set(singleValueArgs RESULT) 313 set(multiValueArgs DEPENDS_ON) 314 315 # Parse the arguments 316 cmake_parse_arguments(arg "${options}" "${singleValueArgs}" 317 "${multiValueArgs}" ${ARGN} ) 318 319 # Expand dependency list 320 set(_deps_to_process ${arg_DEPENDS_ON}) 321 set(_expanded_DEPENDS_ON) 322 while(_deps_to_process) 323 # Copy the current set of dependencies to process 324 set(_current_deps_to_process ${_deps_to_process}) 325 # and add them to the full expanded list 326 list(APPEND _expanded_DEPENDS_ON ${_deps_to_process}) 327 # Then clear it so we can check if new ones were added 328 set(_deps_to_process) 329 foreach( dependency ${_current_deps_to_process} ) 330 string(TOUPPER ${dependency} uppercase_dependency ) 331 if ( DEFINED _BLT_${uppercase_dependency}_DEPENDS_ON ) 332 foreach(new_dependency ${_BLT_${uppercase_dependency}_DEPENDS_ON}) 333 # Don't add duplicates 334 if (NOT ${new_dependency} IN_LIST _expanded_DEPENDS_ON) 335 list(APPEND _deps_to_process ${new_dependency}) 336 endif() 337 endforeach() 338 endif() 339 endforeach() 340 endwhile() 341 342 # Write the output to the requested variable 343 set(${arg_RESULT} ${_expanded_DEPENDS_ON}) 344endmacro() 345 346 347##------------------------------------------------------------------------------ 348## blt_setup_target( NAME [name] 349## DEPENDS_ON [dep1 ...] 350## OBJECT [TRUE | FALSE]) 351##------------------------------------------------------------------------------ 352macro(blt_setup_target) 353 354 set(options) 355 set(singleValueArgs NAME OBJECT) 356 set(multiValueArgs DEPENDS_ON) 357 358 # Parse the arguments 359 cmake_parse_arguments(arg "${options}" "${singleValueArgs}" 360 "${multiValueArgs}" ${ARGN} ) 361 362 # Check arguments 363 if ( NOT DEFINED arg_NAME ) 364 message( FATAL_ERROR "Must provide a NAME argument to the 'blt_setup_target' macro" ) 365 endif() 366 367 # Default to "real" scope, unless it's an interface library 368 set(_private_scope PRIVATE) 369 set(_public_scope PUBLIC) 370 get_target_property(_target_type ${arg_NAME} TYPE) 371 if("${_target_type}" STREQUAL "INTERFACE_LIBRARY") 372 set(_private_scope INTERFACE) 373 set(_public_scope INTERFACE) 374 endif() 375 376 # Expand dependency list - avoid "recalculating" if the information already exists 377 set(_expanded_DEPENDS_ON) 378 if(NOT "${_target_type}" STREQUAL "INTERFACE_LIBRARY") 379 get_target_property(_expanded_DEPENDS_ON ${arg_NAME} BLT_EXPANDED_DEPENDENCIES) 380 endif() 381 if(NOT _expanded_DEPENDS_ON) 382 blt_expand_depends(DEPENDS_ON ${arg_DEPENDS_ON} RESULT _expanded_DEPENDS_ON) 383 endif() 384 385 # Add dependency's information 386 foreach( dependency ${_expanded_DEPENDS_ON} ) 387 string(TOUPPER ${dependency} uppercase_dependency ) 388 389 if ( NOT arg_OBJECT AND _BLT_${uppercase_dependency}_IS_OBJECT_LIBRARY ) 390 target_sources(${arg_NAME} ${_private_scope} $<TARGET_OBJECTS:${dependency}>) 391 endif() 392 393 if ( DEFINED _BLT_${uppercase_dependency}_INCLUDES ) 394 if ( _BLT_${uppercase_dependency}_TREAT_INCLUDES_AS_SYSTEM ) 395 target_include_directories( ${arg_NAME} SYSTEM ${_public_scope} 396 ${_BLT_${uppercase_dependency}_INCLUDES} ) 397 else() 398 target_include_directories( ${arg_NAME} ${_public_scope} 399 ${_BLT_${uppercase_dependency}_INCLUDES} ) 400 endif() 401 endif() 402 403 if ( DEFINED _BLT_${uppercase_dependency}_FORTRAN_MODULES ) 404 target_include_directories( ${arg_NAME} ${_public_scope} 405 ${_BLT_${uppercase_dependency}_FORTRAN_MODULES} ) 406 endif() 407 408 if ( arg_OBJECT ) 409 # Object libraries need to inherit info from their CMake targets listed 410 # in their LIBRARIES 411 foreach( _library ${_BLT_${uppercase_dependency}_LIBRARIES} ) 412 if(TARGET ${_library}) 413 blt_inherit_target_info(TO ${arg_NAME} 414 FROM ${_library} 415 OBJECT ${arg_OBJECT}) 416 endif() 417 endforeach() 418 endif() 419 420 if ( arg_OBJECT OR _BLT_${uppercase_dependency}_IS_OBJECT_LIBRARY ) 421 # We want object libraries to inherit the vital info but not call 422 # target_link_libraries() otherwise you have to install the object 423 # files associated with the object library which noone wants. 424 if ( TARGET ${dependency} ) 425 blt_inherit_target_info(TO ${arg_NAME} 426 FROM ${dependency} 427 OBJECT ${arg_OBJECT}) 428 endif() 429 elseif (DEFINED _BLT_${uppercase_dependency}_LIBRARIES) 430 # This prevents cmake from adding -l<library name> to the 431 # command line for BLT registered libraries which are not 432 # actual CMake targets 433 if(NOT "${_BLT_${uppercase_dependency}_LIBRARIES}" 434 STREQUAL "BLT_NO_LIBRARIES" ) 435 target_link_libraries( ${arg_NAME} ${_public_scope} 436 ${_BLT_${uppercase_dependency}_LIBRARIES} ) 437 endif() 438 else() 439 target_link_libraries( ${arg_NAME} ${_public_scope} ${dependency} ) 440 endif() 441 442 if ( DEFINED _BLT_${uppercase_dependency}_DEFINES ) 443 target_compile_definitions( ${arg_NAME} ${_public_scope} 444 ${_BLT_${uppercase_dependency}_DEFINES} ) 445 endif() 446 447 if ( DEFINED _BLT_${uppercase_dependency}_COMPILE_FLAGS ) 448 blt_add_target_compile_flags(TO ${arg_NAME} 449 FLAGS ${_BLT_${uppercase_dependency}_COMPILE_FLAGS} ) 450 endif() 451 452 if ( NOT arg_OBJECT AND DEFINED _BLT_${uppercase_dependency}_LINK_FLAGS ) 453 blt_add_target_link_flags(TO ${arg_NAME} 454 FLAGS ${_BLT_${uppercase_dependency}_LINK_FLAGS} ) 455 endif() 456 457 if(TARGET ${dependency}) 458 # If it's an interface library CMake doesn't even allow us to query the property 459 get_target_property(_dep_type ${dependency} TYPE) 460 if(NOT "${_dep_type}" STREQUAL "INTERFACE_LIBRARY") 461 # Propagate the overridden linker language, if applicable 462 get_target_property(_blt_link_lang ${dependency} INTERFACE_BLT_LINKER_LANGUAGE_OVERRIDE) 463 # TODO: Do we need to worry about overwriting? Should only ever be HIP or CUDA 464 if(_blt_link_lang) 465 set_target_properties(${arg_NAME} PROPERTIES INTERFACE_BLT_LINKER_LANGUAGE_OVERRIDE ${_blt_link_lang}) 466 endif() 467 endif() 468 469 # Check if a separate device link is needed 470 if(ENABLE_CUDA AND "${_dep_type}" STREQUAL "OBJECT_LIBRARY") 471 get_target_property(_device_link ${dependency} CUDA_RESOLVE_DEVICE_SYMBOLS) 472 if(_device_link AND CUDA_LINK_WITH_NVCC) 473 set(_dlink_obj "${dependency}_device_link${CMAKE_CUDA_OUTPUT_EXTENSION}") 474 # Make sure a target wasn't already added 475 get_source_file_property(_generated ${_dlink_obj} GENERATED) 476 if(NOT _generated) 477 # Convert string to list as it will be expanded 478 string(REPLACE " " ";" _cuda_flags ${CMAKE_CUDA_FLAGS}) 479 add_custom_command( 480 OUTPUT ${_dlink_obj} 481 COMMAND ${CMAKE_CUDA_COMPILER} --device-link ${_cuda_flags} $<TARGET_OBJECTS:${dependency}> -o ${_dlink_obj} 482 DEPENDS $<TARGET_OBJECTS:${dependency}> 483 COMMAND_EXPAND_LISTS 484 ) 485 endif() 486 target_sources(${arg_NAME} PRIVATE ${_dlink_obj}) 487 endif() 488 endif() 489 endif() 490 endforeach() 491 492endmacro(blt_setup_target) 493 494 495##------------------------------------------------------------------------------ 496## blt_setup_cuda_target(NAME <name of target> 497## SOURCES <list of sources> 498## DEPENDS_ON <list of dependencies> 499## LIBRARY_TYPE <STATIC, SHARED, OBJECT, or blank for executables>) 500##------------------------------------------------------------------------------ 501macro(blt_setup_cuda_target) 502 503 set(options) 504 set(singleValueArgs NAME LIBRARY_TYPE) 505 set(multiValueArgs SOURCES DEPENDS_ON) 506 507 # Parse the arguments 508 cmake_parse_arguments(arg "${options}" "${singleValueArgs}" 509 "${multiValueArgs}" ${ARGN} ) 510 511 # Check arguments 512 if ( NOT DEFINED arg_NAME ) 513 message( FATAL_ERROR "Must provide a NAME argument to the 'blt_setup_cuda_target' macro") 514 endif() 515 516 if ( NOT DEFINED arg_SOURCES ) 517 message( FATAL_ERROR "Must provide SOURCES to the 'blt_setup_cuda_target' macro") 518 endif() 519 520 # Determine if cuda or cuda_runtime are in DEPENDS_ON 521 list(FIND arg_DEPENDS_ON "cuda" _cuda_index) 522 set(_depends_on_cuda FALSE) 523 if(${_cuda_index} GREATER -1) 524 set(_depends_on_cuda TRUE) 525 endif() 526 list(FIND arg_DEPENDS_ON "cuda_runtime" _cuda_runtime_index) 527 set(_depends_on_cuda_runtime FALSE) 528 if(${_cuda_runtime_index} GREATER -1) 529 set(_depends_on_cuda_runtime TRUE) 530 endif() 531 532 if (${_depends_on_cuda_runtime} OR ${_depends_on_cuda}) 533 if (CUDA_LINK_WITH_NVCC) 534 set_target_properties( ${arg_NAME} PROPERTIES LINKER_LANGUAGE CUDA) 535 # This will be propagated up to executable targets that depend on this 536 # library, which will need the HIP linker 537 set_target_properties( ${arg_NAME} PROPERTIES INTERFACE_BLT_LINKER_LANGUAGE_OVERRIDE CUDA) 538 endif() 539 endif() 540 541 if (${_depends_on_cuda}) 542 # if cuda is in depends_on, flag each file's language as CUDA 543 # instead of leaving it up to CMake to decide 544 # Note: we don't do this when depending on just 'cuda_runtime' 545 set(_cuda_sources) 546 set(_non_cuda_sources) 547 blt_split_source_list_by_language(SOURCES ${arg_SOURCES} 548 C_LIST _cuda_sources 549 Fortran_LIST _non_cuda_sources) 550 551 set_source_files_properties( ${_cuda_sources} PROPERTIES 552 LANGUAGE CUDA) 553 554 if (CUDA_SEPARABLE_COMPILATION) 555 set_source_files_properties( ${_cuda_sources} PROPERTIES 556 CUDA_SEPARABLE_COMPILATION ON) 557 set_target_properties( ${arg_NAME} PROPERTIES 558 CUDA_SEPARABLE_COMPILATION ON) 559 endif() 560 561 if (DEFINED arg_LIBRARY_TYPE) 562 if (${arg_LIBRARY_TYPE} STREQUAL "static") 563 set_target_properties( ${arg_NAME} PROPERTIES 564 CMAKE_CUDA_CREATE_STATIC_LIBRARY ON) 565 else() 566 set_target_properties( ${arg_NAME} PROPERTIES 567 CMAKE_CUDA_CREATE_STATIC_LIBRARY OFF) 568 endif() 569 endif() 570 571 # Replicate the behavior of CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS 572 if(${CMAKE_VERSION} VERSION_LESS "3.16.0" AND CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS) 573 set_target_properties( ${arg_NAME} PROPERTIES 574 CUDA_RESOLVE_DEVICE_SYMBOLS ON) 575 endif() 576 endif() 577endmacro(blt_setup_cuda_target) 578 579##------------------------------------------------------------------------------ 580## blt_cleanup_hip_globals(FROM_TARGET <target>) 581## 582## Needed as the SetupHIP macros (specifically, HIP_PREPARE_TARGET_COMMANDS) 583## "pollutes" the global HIP_HIPCC_FLAGS with target-specific options. This 584## macro removes the target-specific generator expressions from the global flags 585## which have already been copied to source-file-specific instances of the 586## run_hipcc script. Other global flags in HIP_HIPCC_FLAGS, e.g., those set by 587## the user, are left untouched. 588##------------------------------------------------------------------------------ 589macro(blt_cleanup_hip_globals) 590 set(options) 591 set(singleValueArgs FROM_TARGET) 592 set(multiValueArgs) 593 594 # Parse the arguments 595 cmake_parse_arguments(arg "${options}" "${singleValueArgs}" 596 "${multiValueArgs}" ${ARGN} ) 597 598 # Check arguments 599 if ( NOT DEFINED arg_FROM_TARGET ) 600 message( FATAL_ERROR "Must provide a FROM_TARGET argument to the 'blt_cleanup_hip_globals' macro") 601 endif() 602 603 # Remove the compile definitions generator expression 604 # This must be copied verbatim from HIP_PREPARE_TARGET_COMMANDS, 605 # which would have just added it to HIP_HIPCC_FLAGS 606 set(_defines_genexpr "$<TARGET_PROPERTY:${arg_FROM_TARGET},COMPILE_DEFINITIONS>") 607 set(_defines_flags_genexpr "$<$<BOOL:${_defines_genexpr}>:-D$<JOIN:${_defines_genexpr}, -D>>") 608 list(REMOVE_ITEM HIP_HIPCC_FLAGS ${_defines_flags_genexpr}) 609endmacro(blt_cleanup_hip_globals) 610 611##------------------------------------------------------------------------------ 612## blt_add_hip_library(NAME <libname> 613## SOURCES [source1 [source2 ...]] 614## HEADERS [header1 [header2 ...]] 615## DEPENDS_ON [dep1 ...] 616## LIBRARY_TYPE <STATIC, SHARED, or OBJECT> 617##------------------------------------------------------------------------------ 618macro(blt_add_hip_library) 619 620 set(options) 621 set(singleValueArgs NAME LIBRARY_TYPE) 622 set(multiValueArgs SOURCES HEADERS DEPENDS_ON) 623 624 # Parse the arguments 625 cmake_parse_arguments(arg "${options}" "${singleValueArgs}" 626 "${multiValueArgs}" ${ARGN} ) 627 628 # Check arguments 629 if ( NOT DEFINED arg_NAME ) 630 message( FATAL_ERROR "Must provide a NAME argument to the 'blt_add_hip_library' macro") 631 endif() 632 633 if ( NOT DEFINED arg_SOURCES ) 634 message( FATAL_ERROR "Must provide SOURCES to the 'blt_add_hip_library' macro") 635 endif() 636 637 # Determine if hip or hip_runtime are in DEPENDS_ON 638 list(FIND arg_DEPENDS_ON "hip" _hip_index) 639 set(_depends_on_hip FALSE) 640 if(${_hip_index} GREATER -1) 641 set(_depends_on_hip TRUE) 642 endif() 643 list(FIND arg_DEPENDS_ON "hip_runtime" _hip_runtime_index) 644 set(_depends_on_hip_runtime FALSE) 645 if(${_hip_runtime_index} GREATER -1) 646 set(_depends_on_hip_runtime TRUE) 647 endif() 648 649 if (${_depends_on_hip}) 650 # if hip is in depends_on, flag each file's language as HIP 651 # instead of leaving it up to CMake to decide 652 # Note: we don't do this when depending on just 'hip_runtime' 653 set(_hip_sources) 654 set(_non_hip_sources) 655 blt_split_source_list_by_language(SOURCES ${arg_SOURCES} 656 C_LIST _hip_sources 657 Fortran_LIST _non_hip_sources) 658 659 set_source_files_properties( ${_hip_sources} 660 PROPERTIES 661 HIP_SOURCE_PROPERTY_FORMAT TRUE) 662 663 hip_add_library( ${arg_NAME} ${arg_SOURCES} ${arg_LIBRARY_TYPE} ) 664 blt_cleanup_hip_globals(FROM_TARGET ${arg_NAME}) 665 # Link to the hip_runtime target so it gets pulled in by targets 666 # depending on this target 667 target_link_libraries(${arg_NAME} PUBLIC hip_runtime) 668 else() 669 add_library( ${arg_NAME} ${arg_LIBRARY_TYPE} ${arg_SOURCES} ${arg_HEADERS} ) 670 endif() 671 672 if (${_depends_on_hip_runtime} OR ${_depends_on_hip}) 673 # This will be propagated up to executable targets that depend on this 674 # library, which will need the HIP linker 675 set_target_properties( ${arg_NAME} PROPERTIES INTERFACE_BLT_LINKER_LANGUAGE_OVERRIDE HIP) 676 endif() 677 678endmacro(blt_add_hip_library) 679 680##------------------------------------------------------------------------------ 681## blt_add_hip_executable(NAME <libname> 682## SOURCES [source1 [source2 ...]] 683## HEADERS [header1 [header2 ...]] 684## DEPENDS_ON [dep1 ...] 685##------------------------------------------------------------------------------ 686macro(blt_add_hip_executable) 687 688 set(options) 689 set(singleValueArgs NAME) 690 set(multiValueArgs HEADERS SOURCES DEPENDS_ON) 691 692 # Parse the arguments 693 cmake_parse_arguments(arg "${options}" "${singleValueArgs}" 694 "${multiValueArgs}" ${ARGN} ) 695 696 # Check arguments 697 if ( NOT DEFINED arg_NAME ) 698 message( FATAL_ERROR "Must provide a NAME argument to the 'blt_add_hip_executable' macro") 699 endif() 700 701 if ( NOT DEFINED arg_SOURCES ) 702 message( FATAL_ERROR "Must provide SOURCES to the 'blt_add_hip_executable' macro") 703 endif() 704 705 # Determine if hip or hip_runtime are in DEPENDS_ON 706 list(FIND arg_DEPENDS_ON "hip" _hip_index) 707 set(_depends_on_hip FALSE) 708 if(${_hip_index} GREATER -1) 709 set(_depends_on_hip TRUE) 710 endif() 711 list(FIND arg_DEPENDS_ON "hip_runtime" _hip_runtime_index) 712 set(_depends_on_hip_runtime FALSE) 713 if(${_hip_runtime_index} GREATER -1) 714 set(_depends_on_hip_runtime TRUE) 715 endif() 716 717 blt_expand_depends(DEPENDS_ON ${arg_DEPENDS_ON} RESULT _expanded_DEPENDS_ON) 718 foreach( dependency ${_expanded_DEPENDS_ON} ) 719 if(TARGET ${dependency}) 720 get_target_property(_dep_type ${dependency} TYPE) 721 if(NOT "${_dep_type}" STREQUAL "INTERFACE_LIBRARY") 722 # Propagate the overridden linker language, if applicable 723 get_target_property(_blt_link_lang ${dependency} INTERFACE_BLT_LINKER_LANGUAGE_OVERRIDE) 724 if(_blt_link_lang STREQUAL "HIP") 725 set(_depends_on_hip_runtime TRUE) 726 endif() 727 endif() 728 endif() 729 endforeach() 730 731 if (${_depends_on_hip} OR ${_depends_on_hip_runtime}) 732 # if hip is in depends_on, flag each file's language as HIP 733 # instead of leaving it up to CMake to decide 734 # Note: we don't do this when depending on just 'hip_runtime' 735 set(_hip_sources) 736 set(_non_hip_sources) 737 blt_split_source_list_by_language(SOURCES ${arg_SOURCES} 738 C_LIST _hip_sources 739 Fortran_LIST _non_hip_sources) 740 741 set_source_files_properties( ${_hip_sources} 742 PROPERTIES 743 HIP_SOURCE_PROPERTY_FORMAT TRUE) 744 745 hip_add_executable( ${arg_NAME} ${arg_SOURCES} ) 746 blt_cleanup_hip_globals(FROM_TARGET ${arg_NAME}) 747 else() 748 add_executable( ${arg_NAME} ${arg_SOURCES} ${arg_HEADERS}) 749 endif() 750 751 # Save the expanded dependencies to avoid recalculating later 752 set_target_properties(${arg_NAME} PROPERTIES 753 BLT_EXPANDED_DEPENDENCIES "${_expanded_DEPENDS_ON}") 754 755endmacro(blt_add_hip_executable) 756 757##------------------------------------------------------------------------------ 758## blt_split_source_list_by_language( SOURCES <sources> 759## C_LIST <list name> 760## Fortran_LIST <list name> 761## Python_LIST <list name>) 762## CMAKE_LIST <list name>) 763## 764## Filters source list by file extension into C/C++, Fortran, Python, and 765## CMake source lists based on BLT_C_FILE_EXTS, BLT_Fortran_FILE_EXTS, 766## and BLT_CMAKE_FILE_EXTS (global BLT variables). Files named 767## "CMakeLists.txt" are also filtered here. Files with no extension 768## or generator expressions that are not object libraries (of the form 769## "$<TARGET_OBJECTS:nameofobjectlibrary>") will throw fatal errors. 770## ------------------------------------------------------------------------------ 771macro(blt_split_source_list_by_language) 772 773 set(options) 774 set(singleValueArgs C_LIST Fortran_LIST Python_LIST CMAKE_LIST) 775 set(multiValueArgs SOURCES) 776 777 # Parse the arguments 778 cmake_parse_arguments(arg "${options}" "${singleValueArgs}" 779 "${multiValueArgs}" ${ARGN} ) 780 781 # Check arguments 782 if ( NOT DEFINED arg_SOURCES ) 783 message( FATAL_ERROR "Must provide a SOURCES argument to the 'blt_split_source_list_by_language' macro" ) 784 endif() 785 786 # Generate source lists based on language 787 foreach(_file ${arg_SOURCES}) 788 # Allow CMake object libraries but disallow generator expressions 789 # in source lists due to this causing all sorts of bad side effects 790 if("${_file}" MATCHES "^\\$<TARGET_OBJECTS:") 791 continue() 792 elseif("${_file}" MATCHES "^\\$<") 793 message(FATAL_ERROR "blt_split_source_list_by_language macro does not support generator expressions because CMake does not provide a way to evaluate them. Given generator expression: ${_file}") 794 endif() 795 796 get_filename_component(_ext "${_file}" EXT) 797 if("${_ext}" STREQUAL "") 798 message(FATAL_ERROR "blt_split_source_list_by_language given source file with no extension: ${_file}") 799 endif() 800 801 get_filename_component(_name "${_file}" NAME) 802 803 string(TOLOWER "${_ext}" _ext_lower) 804 805 if("${_ext_lower}" IN_LIST BLT_C_FILE_EXTS) 806 if (DEFINED arg_C_LIST) 807 list(APPEND ${arg_C_LIST} "${_file}") 808 endif() 809 elseif("${_ext_lower}" IN_LIST BLT_Fortran_FILE_EXTS) 810 if (DEFINED arg_Fortran_LIST) 811 list(APPEND ${arg_Fortran_LIST} "${_file}") 812 endif() 813 elseif("${_ext_lower}" IN_LIST BLT_Python_FILE_EXTS) 814 if (DEFINED arg_Python_LIST) 815 list(APPEND ${arg_Python_LIST} "${_file}") 816 endif() 817 elseif("${_ext_lower}" IN_LIST BLT_CMAKE_FILE_EXTS OR "${_name}" STREQUAL "CMakeLists.txt") 818 if (DEFINED arg_CMAKE_LIST) 819 list(APPEND ${arg_CMAKE_LIST} "${_file}") 820 endif() 821 else() 822 message(FATAL_ERROR "blt_split_source_list_by_language given source file with unknown file extension. Add the missing extension to the corresponding list (BLT_C_FILE_EXTS, BLT_Fortran_FILE_EXTS, BLT_Python_FILE_EXTS, or BLT_CMAKE_FILE_EXTS).\n Unknown file: ${_file}") 823 endif() 824 endforeach() 825 826endmacro(blt_split_source_list_by_language) 827 828 829##------------------------------------------------------------------------------ 830## blt_update_project_sources( TARGET_SOURCES <sources> ) 831##------------------------------------------------------------------------------ 832macro(blt_update_project_sources) 833 834 set(options) 835 set(singleValueArgs) 836 set(multiValueArgs TARGET_SOURCES) 837 838 # Parse the arguments 839 cmake_parse_arguments(arg "${options}" "${singleValueArgs}" 840 "${multiValueArgs}" ${ARGN} ) 841 842 # Check arguments 843 if ( NOT DEFINED arg_TARGET_SOURCES ) 844 message( FATAL_ERROR "Must provide target sources" ) 845 endif() 846 847 ## append the target source to the all project sources 848 foreach( src ${arg_TARGET_SOURCES} ) 849 if(IS_ABSOLUTE ${src}) 850 list(APPEND "${PROJECT_NAME}_ALL_SOURCES" "${src}") 851 else() 852 list(APPEND "${PROJECT_NAME}_ALL_SOURCES" 853 "${CMAKE_CURRENT_SOURCE_DIR}/${src}") 854 endif() 855 endforeach() 856 857 set( "${PROJECT_NAME}_ALL_SOURCES" "${${PROJECT_NAME}_ALL_SOURCES}" 858 CACHE STRING "" FORCE ) 859 mark_as_advanced("${PROJECT_NAME}_ALL_SOURCES") 860 861endmacro(blt_update_project_sources) 862 863 864##------------------------------------------------------------------------------ 865## blt_filter_list( TO <list_var> REGEX <string> OPERATION <string> ) 866## 867## This macro provides the same functionality as cmake's list(FILTER ) 868## which is only available in cmake-3.6+. 869## 870## The TO argument (required) is the name of a list variable. 871## The REGEX argument (required) is a string containing a regex. 872## The OPERATION argument (required) is a string that defines the macro's operation. 873## Supported values are "include" and "exclude" 874## 875## The filter is applied to the input list, which is modified in place. 876##------------------------------------------------------------------------------ 877macro(blt_filter_list) 878 879 set(options ) 880 set(singleValueArgs TO REGEX OPERATION) 881 set(multiValueArgs ) 882 883 # Parse arguments 884 cmake_parse_arguments(arg "${options}" "${singleValueArgs}" 885 "${multiValueArgs}" ${ARGN} ) 886 887 # Check arguments 888 if( NOT DEFINED arg_TO ) 889 message(FATAL_ERROR "blt_filter_list macro requires a TO <list> argument") 890 endif() 891 892 if( NOT DEFINED arg_REGEX ) 893 message(FATAL_ERROR "blt_filter_list macro requires a REGEX <string> argument") 894 endif() 895 896 # Ensure OPERATION argument is provided with value "include" or "exclude" 897 set(_exclude) 898 if( NOT DEFINED arg_OPERATION ) 899 message(FATAL_ERROR "blt_filter_list macro requires a OPERATION <string> argument") 900 elseif(NOT arg_OPERATION MATCHES "^(include|exclude)$") 901 message(FATAL_ERROR "blt_filter_list macro's OPERATION argument must be either 'include' or 'exclude'") 902 else() 903 if(${arg_OPERATION} MATCHES "exclude") 904 set(_exclude TRUE) 905 else() 906 set(_exclude FALSE) 907 endif() 908 endif() 909 910 # Filter the list 911 set(_resultList) 912 foreach(elem ${${arg_TO}}) 913 if(elem MATCHES ${arg_REGEX}) 914 if(NOT ${_exclude}) 915 list(APPEND _resultList ${elem}) 916 endif() 917 else() 918 if(${_exclude}) 919 list(APPEND _resultList ${elem}) 920 endif() 921 endif() 922 endforeach() 923 924 # Copy result back to input list variable 925 set(${arg_TO} ${_resultList}) 926 927 unset(_exclude) 928 unset(_resultList) 929endmacro(blt_filter_list) 930 931 932##------------------------------------------------------------------------------ 933## blt_clean_target( TARGET <target name> ) 934## 935## This macro removes duplicates in a small subset of target properties that are 936## safe to do so. 937##------------------------------------------------------------------------------ 938macro(blt_clean_target) 939 940 set(options ) 941 set(singleValueArgs TARGET) 942 set(multiValueArgs ) 943 944 # Parse arguments 945 cmake_parse_arguments(arg "${options}" "${singleValueArgs}" 946 "${multiValueArgs}" ${ARGN} ) 947 948 # Properties to remove duplicates from 949 set(_dup_properties 950 INCLUDE_DIRECTORIES 951 INTERFACE_COMPILE_DEFINITIONS 952 INTERFACE_INCLUDE_DIRECTORIES 953 INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) 954 955 foreach(_prop ${_dup_properties}) 956 get_target_property(_values ${arg_TARGET} ${_prop}) 957 if ( _values ) 958 list(REMOVE_DUPLICATES _values) 959 set_property(TARGET ${arg_TARGET} PROPERTY ${_prop} ${_values}) 960 endif() 961 endforeach() 962 963endmacro(blt_clean_target) 964