waLBerlaFunctions.cmake 17.7 KB
Newer Older
1 2 3 4 5
include ( waLBerlaHelperFunctions         )
include ( waLBerlaModuleDependencySystem  )


set ( WALBERLA_GLOB_FILES *.cpp
6 7 8
                          *.c
                          *.h
                          *.cu
9 10 11 12 13 14
      CACHE INTERNAL "File endings to glob for source files" )


#######################################################################################################################
#
# Creates a walberla module library
15
#
16 17 18 19 20 21
#
# Keywords:
#   DEPENDS [required]   list of modules, that this module depends on
#   FILES   [optional]   list of all source and header files belonging to that module
#                        if this is not given, all source and header files in the directory are added.
#                        Careful: when file was added or deleted, cmake has to be run again
22
#   EXCLUDE [optional]   Files that should not be included in the module (but are located in module directory).
23 24 25
#                        This makes only sense if FILES was not specified, and all files have been added automatically.
#   BUILD_ONLY_IF_FOUND  Before building the module test if all libraries specified here are availbable.
#   [optional]           This is done using the ${arg}_FOUND variable.
26
#                        Example: waLBerla_add_module( DEPENDS someModule BUILD_ONLY_IF_FOUND pe)
27 28 29 30 31 32 33 34 35
#                                 This module is only built if PE_FOUND is true.
#
#######################################################################################################################

function ( waLBerla_add_module )
    set( options )
    set( oneValueArgs )
    set( multiValueArgs DEPENDS EXCLUDE FILES BUILD_ONLY_IF_FOUND )
    cmake_parse_arguments( ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
36

37 38 39
    # Module name is the directory relative to WALBERLA_MODULE_DIRS
    get_current_module_name ( moduleName )
    get_module_library_name ( moduleLibraryName ${moduleName} )
40

41 42 43 44 45 46 47 48 49 50
    # Test if all required libraries are available
    # this is detected using the _FOUND variable
    foreach ( externalName ${ARG_BUILD_ONLY_IF_FOUND} )
        string( TOUPPER ${externalName} externalNameUpper )
        if ( NOT ${externalNameUpper}_FOUND )
            message ( STATUS "Module ${moduleName} is not built, because ${externalName} not available" )
            return()
        endif()
    endforeach()

51
    # Take source files either from parameter or search all source files
52 53 54 55 56 57 58 59 60 61
    file ( GLOB_RECURSE allFiles "*" )  # Find all files
    if ( ARG_FILES )
        foreach( sourceFile ${ARG_FILES} )
           get_filename_component( sourceFile ${sourceFile} ABSOLUTE )
           list( APPEND sourceFiles ${sourceFile} )
        endforeach()
    else()
        file ( GLOB_RECURSE sourceFiles ${WALBERLA_GLOB_FILES} )  # Find all source files
    endif()

62
    # Remove exclude files from the sources
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
    if ( ARG_EXCLUDE )
        foreach ( fileToExclude ${ARG_EXCLUDE} )
            get_filename_component( fileToExclude ${fileToExclude} ABSOLUTE )
            list (REMOVE_ITEM sourceFiles ${fileToExclude} )
        endforeach()
    endif()

    list_minus ( otherFiles LIST1 ${allFiles} LIST2 ${sourceFiles} )
    set_source_files_properties( ${otherFiles} PROPERTIES HEADER_FILE_ONLY ON )

    if ( WALBERLA_GROUP_FILES )
       group_files( "Other Files"  FILES ${otherFiles}  )
       group_files( "Source Files" FILES ${sourceFiles} )
    endif ( )

    # Dependency Check
79
    check_dependencies( missingDeps additionalDeps FILES ${sourceFiles} EXPECTED_DEPS ${ARG_DEPENDS} ${moduleName} )
80 81 82 83
    if ( missingDeps )
        message ( WARNING "The module ${moduleName} depends on ${missingDeps} which are not listed as dependencies!" )
    endif()

84 85
    set( hasSourceFiles FALSE )
 	foreach ( sourceFile ${sourceFiles} )
Martin Bauer's avatar
Martin Bauer committed
86
 	   if ( ${sourceFile} MATCHES "\\.(c|cpp|cu)" )
87 88 89
 	      set( hasSourceFiles TRUE )
 	   endif( )
 	endforeach( )
90

91
    if ( hasSourceFiles )
92 93
        set( generatedSourceFiles )
        set( generatorSourceFiles )
94
        handle_python_codegen(sourceFiles generatedSourceFiles generatorSourceFiles codeGenRequired "default_codegen" ${sourceFiles})
95 96 97 98 99 100
        if( NOT WALBERLA_BUILD_WITH_CODEGEN AND codeGenRequired)
            message(STATUS "Skipping ${ARG_NAME} since pystencils code generation is not enabled")
            return()
        endif()

        if ( CUDA_FOUND )
101
            cuda_add_library( ${moduleLibraryName} STATIC ${sourceFiles} ${generatedSourceFiles} ${generatorSourceFiles} ${otherFiles} )
Martin Bauer's avatar
Martin Bauer committed
102
        else()
103
            add_library( ${moduleLibraryName} STATIC ${sourceFiles} ${generatedSourceFiles} ${generatorSourceFiles} ${otherFiles} )
Martin Bauer's avatar
Martin Bauer committed
104
        endif( CUDA_FOUND )
105

106
        set_source_files_properties( ${generatedSourceFiles} PROPERTIES GENERATED TRUE )
107 108 109
 	else( )
 	   add_custom_target( ${moduleLibraryName} SOURCES ${sourceFiles} ${generatedSourceFiles} ${otherFiles} )  # dummy IDE target
 	endif( )
110

111 112
    waLBerla_register_dependency ( ${moduleName} ${ARG_DEPENDS} )

113 114
    set_property( TARGET ${moduleName} PROPERTY CXX_STANDARD 14 )

115 116 117 118
    # This property is needed for visual studio to group modules together
    if( WALBERLA_GROUP_PROJECTS )
       set_property( TARGET  ${moduleLibraryName}  PROPERTY  FOLDER  "SRC" )
    endif()
119

120 121
    # Install rule for library
    get_target_property( module_type ${moduleLibraryName} TYPE )
122
    if( ${module_type} MATCHES LIBRARY )
123 124 125 126
       install ( TARGETS ${moduleLibraryName}  RUNTIME DESTINATION bin
                                               LIBRARY DESTINATION lib
                                               ARCHIVE DESTINATION lib )
    endif( )
127

128 129 130 131
    if( codeGenRequired)
        target_include_directories(${ARG_NAME} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/default_codegen")
    endif()

132
    # Install rule for header
133 134
    install ( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/
              DESTINATION "walberla/${moduleName}"
135
              FILES_MATCHING PATTERN "*.h"
136
              PATTERN "*.in.h"     EXCLUDE
137
              PATTERN "CMakeFiles" EXCLUDE )
138 139 140 141 142

    # Install generated headers if necessary
    if ( NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR} )
        install ( DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/
                  DESTINATION "walberla/${moduleName}"
143
                  FILES_MATCHING PATTERN "*.h"
144
                  PATTERN "*.in.h"     EXCLUDE
145
                  PATTERN "CMakeFiles" EXCLUDE )
146 147 148
    endif()


149 150 151
    # Report module statistics - which is later on written out to a json file
    # This file is used in the doxygen documentation to display a module graph
    #waLBerla_module_statistics ( FILES ${sourceFiles} DEPENDS ${ARG_DEPENDS} )
152

153 154 155 156 157 158 159 160 161 162 163 164 165
endfunction ( waLBerla_add_module )
#######################################################################################################################





#######################################################################################################################
#
# Compiles an application either from given source files, or otherwise globs all files in the current folder.
# The application is linked against all waLBerla modules that are listed after DEPENDS
#
#
166 167 168 169 170 171 172
#   NAME    [required]    Name of application
#   GROUP   [optional]    IDE group name (e.g. VS)
#   DEPENDS [required]    list of modules, that this application depends on
#   FILES   [optional]    list of all source and header files belonging to that application
#                         if this is not given, all source and header files in the directory are added.
#                         Careful: when file was added or deleted, cmake has to be run again
#   CODGEN_CFG [optional] string passed to code generation scripts
173 174 175 176 177 178 179
#
#  Example:
#     waLBerla_compile_app ( NAME myApp DEPENDS core field lbm/boundary )
#######################################################################################################################

function ( waLBerla_add_executable )
    set( options )
180 181
    set( oneValueArgs NAME GROUP CODEGEN_CFG)
    set( multiValueArgs FILES DEPENDS)
182 183 184
    cmake_parse_arguments( ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )

    if( NOT ARG_NAME )
185
      message ( FATAL_ERROR "waLBerla_add_executable called without a NAME" )
186
    endif()
187

188 189 190 191
    if( NOT ARG_CODEGEN_CFG)
        set(ARG_CODEGEN_CFG "default_codegen")
    endif()

192 193 194 195
    # Skip this app, if it depends on modules that have not been built ( because they for example depend on PE)
    foreach ( depMod ${ARG_DEPENDS} )
        get_module_library_name ( depModLibraryName ${depMod} )
        if( NOT TARGET ${depModLibraryName} )
196 197 198
            if( WALBERLA_LOG_SKIPPED )
               message ( STATUS "Skipping ${ARG_NAME} since dependent module ${depMod} was not built" )
            endif()
199 200 201
            return()
        endif()
    endforeach()
202 203

    # Take source files either from parameter or search all source files
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
    set( sourceFiles )
    if ( ARG_FILES )
        foreach( sourceFile ${ARG_FILES} )
           get_filename_component( sourceFile ${sourceFile} ABSOLUTE )
           list( APPEND sourceFiles ${sourceFile} )
        endforeach()
        if ( WALBERLA_GROUP_FILES )
           group_files( "Source Files" FILES ${sourceFiles} )
        endif ( )
    else()
        file ( GLOB_RECURSE sourceFiles ${WALBERLA_GLOB_FILES} )  # Find all source files
        if ( WALBERLA_GROUP_FILES )
           file ( GLOB_RECURSE allFiles  "*" )  # Find all files
           list_minus ( otherFiles LIST1 ${allFiles} LIST2 ${sourceFiles} )
           group_files( "Source Files" FILES ${sourceFiles} )
           group_files( "Other Files" FILES ${otherFiles} )
        endif ( )
    endif()

223 224
    set( generatedSourceFiles )
    set( generatorSourceFiles )
225 226
    handle_python_codegen(sourceFiles generatedSourceFiles generatorSourceFiles
                          codeGenRequired ${ARG_CODEGEN_CFG} ${sourceFiles} )
227

228
    if( NOT WALBERLA_BUILD_WITH_CODEGEN AND codeGenRequired)
229 230 231
        if( WALBERLA_LOG_SKIPPED )
           message(STATUS "Skipping ${ARG_NAME} since pystencils code generation is not enabled")
        endif()
232 233
        return()
    endif()
234

235 236
    if ( WALBERLA_BUILD_WITH_CUDA )
        cuda_add_executable( ${ARG_NAME} ${sourceFiles} ${generatedSourceFiles} )
Martin Bauer's avatar
Martin Bauer committed
237
    else()
238
        add_executable( ${ARG_NAME} ${sourceFiles} ${generatedSourceFiles}  )
Martin Bauer's avatar
Martin Bauer committed
239
    endif()
240

241
    set_source_files_properties( ${generatedSourceFiles} PROPERTIES GENERATED TRUE )
Martin Bauer's avatar
Martin Bauer committed
242

243
    target_link_modules  ( ${ARG_NAME} ${ARG_DEPENDS}  )
244
    target_link_libraries( ${ARG_NAME} ${WALBERLA_LINK_LIBRARIES_KEYWORD} ${SERVICE_LIBS} )
245
    set_property( TARGET ${ARG_NAME} PROPERTY CXX_STANDARD 14 )
246 247 248 249 250 251 252

    if( WALBERLA_GROUP_PROJECTS )
        if( NOT ARG_GROUP )
            set( ARG_GROUP "APPS" )
        endif()
        set_property( TARGET  ${ARG_NAME}  PROPERTY  FOLDER  ${ARG_GROUP} )
    endif()
253

254 255 256 257
    if( codeGenRequired )
        target_include_directories(${ARG_NAME} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/${ARG_CODEGEN_CFG}")
    endif()

258 259 260 261 262 263 264
endfunction ( waLBerla_add_executable )

#######################################################################################################################




Martin Bauer's avatar
Martin Bauer committed
265 266 267 268 269
#######################################################################################################################
#
# Function to tell CMake which C/C++/CUDA files are generated by a python file
#
# Example:
270
#    waLBerla_python_file_generates(MyPythonCodeGenScript.py Sweep1.cpp Sweep2.cu)
Martin Bauer's avatar
Martin Bauer committed
271 272 273 274
#
#
#######################################################################################################################
function( waLBerla_python_file_generates pythonFile )
275 276 277 278 279 280 281
    set(generatedFiles "")
    foreach(element ${ARGN})
        string(REGEX REPLACE "\\.[^.]*$" "" elementWithoutExtension ${element})
        list(APPEND generatedFiles ${element})
        list(APPEND generatedFiles "${elementWithoutExtension}.h")
    endforeach()
    list(REMOVE_DUPLICATES generatedFiles)
Martin Bauer's avatar
Martin Bauer committed
282
    get_filename_component(pythonFileAbsolutePath ${pythonFile} ABSOLUTE)
283
    set( "WALBERLA_CODEGEN_INFO_${pythonFileAbsolutePath}" ${generatedFiles}
Martin Bauer's avatar
Martin Bauer committed
284 285 286 287 288
            CACHE INTERNAL "Files generated by python script ${pythonFile}" FORCE)
endfunction(waLBerla_python_file_generates)



289 290 291 292 293 294 295 296 297 298 299
#######################################################################################################################
#
# Adds a  waLBerla module test executable.
#
#######################################################################################################################

function ( waLBerla_compile_test )
    set( options )
    set( oneValueArgs NAME )
    set( multiValueArgs FILES DEPENDS )
    cmake_parse_arguments( ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
300

301 302
    # Module name is the directory relative to WALBERLA_MODULE_DIRS
    get_current_module_name ( moduleName )
303

304 305 306 307 308
    # Filename of first source file is used as name for testcase if no name was given
    if( NOT ARG_NAME )
        list( GET ARG_FILES 0 ARG_NAME )
        get_filename_component( ARG_NAME ${ARG_NAME} NAME_WE )
    endif()
309 310

    waLBerla_add_executable ( NAME ${ARG_NAME} GROUP "TESTS/${moduleName}"
311
                              DEPENDS ${ARG_DEPENDS} ${moduleName} FILES ${ARG_FILES} )
312 313


314 315 316 317 318 319 320 321 322
endfunction ( waLBerla_compile_test )
#######################################################################################################################




#######################################################################################################################
#
# Links all files in current source dir matching a globbing expression to the build directory
323
#
324
# first parameter is glob expression
325
#
326 327 328 329 330
# Typical usage: link all parameter files in same folder as the binary was produced
#                Assuming the parameter files end with prm, write this to your CMakeLists in the
#                app or test folder:
#                waLBerla_link_files_to_builddir( "*.prm" )
#
331
# Symlinking works only under linux, on windows the files are copied. For in-source builds this does nothing.
332 333 334 335
#
#######################################################################################################################

function ( waLBerla_link_files_to_builddir globExpression )
336

337 338 339 340
    # don't need links for in-source builds
    if( CMAKE_CURRENT_SOURCE_DIR STREQUAL "${CMAKE_CURRENT_BINARY_DIR}" )
        return()
    endif()
341

342
    file( GLOB filesToLink RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${globExpression} )
343 344

    foreach( f ${filesToLink} )
345 346 347 348 349 350 351
        if( CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows" )
            configure_file( ${f} ${f} COPYONLY )
        else()
            execute_process( COMMAND ${CMAKE_COMMAND} -E create_symlink
                             ${CMAKE_CURRENT_SOURCE_DIR}/${f}
                             ${CMAKE_CURRENT_BINARY_DIR}/${f} )
        endif()
352

353
    endforeach()
354

355 356 357 358 359 360 361
endfunction ( waLBerla_link_files_to_builddir )




#######################################################################################################################
#
362 363
# Adds an executable to CTest.
#
364 365 366 367
# Wrapper around add_test, that handles test labels and parallel runs
# Adds the module name as test label, plus optional user defined labels.
#
#   NAME      [required] Name of test
368
#   PROCESSES [optional] Number of MPI processes, that are used to start this test.
369 370 371
#                        If walberla is built without MPI, and PROCESSES > 1, the test is not added
#                        Defaults to 1
#   COMMAND   [optional] The command that is executed. Use this to start with parameter files or other
372
#                        command line options.
373
#                        Defaults to $<TARGET_FILE:${NAME}> (for this syntax see cmake documentation of add_test )
374
#   LABELS    [optional] Additional test labels.
375 376 377 378
#
#######################################################################################################################

function ( waLBerla_execute_test )
379

380 381
   set( options NO_MODULE_LABEL )
   set( oneValueArgs NAME PROCESSES )
382
   set( multiValueArgs COMMAND LABELS CONFIGURATIONS DEPENDS_ON_TARGETS )
383 384 385
   cmake_parse_arguments( ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )

   if( NOT ARG_NAME )
386
      message ( FATAL_ERROR "waLBerla_execute_test called without a NAME" )
387
   endif()
388

389
   if( NOT ARG_COMMAND AND NOT TARGET ${ARG_NAME} )
390 391 392
      if( WALBERLA_LOG_SKIPPED )
         message ( STATUS "Skipping test ${ARG_NAME} since the corresponding target is not built" )
      endif()
393
      return()
394
   endif()
395 396 397

   foreach( dependency_target ${ARG_DEPENDS_ON_TARGETS} )
      if( NOT TARGET ${dependency_target} )
398 399 400
         if( WALBERLA_LOG_SKIPPED )
            message ( STATUS "Skipping test ${ARG_NAME} since the target ${dependency_target} is not built" )
         endif()
401 402 403
         return()
      endif()
   endforeach( dependency_target )
404

405 406 407 408 409 410 411 412 413 414 415
   if( NOT ARG_PROCESSES )
      set ( numProcesses 1 )
   else()
      set ( numProcesses ${ARG_PROCESSES} )
   endif()

   if ( NOT ARG_COMMAND )
       set ( ARG_COMMAND $<TARGET_FILE:${ARG_NAME}> )
   endif()

   if( WALBERLA_BUILD_WITH_MPI )
416 417 418 419
      if( CMAKE_VERSION VERSION_LESS 3.10.0 )
	set ( MPIEXEC_EXECUTABLE ${MPIEXEC} )
      endif()
      list( INSERT  ARG_COMMAND  0  ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${numProcesses} ${MPIEXEC_PREFLAGS} )
420 421
   elseif( numProcesses GREATER 1 )
      return()
422 423
   endif()

424 425 426 427 428
   if( ARG_CONFIGURATIONS )
      add_test( NAME ${ARG_NAME} ${ARG_UNPARSED_ARGUMENTS} COMMAND ${ARG_COMMAND} CONFIGURATIONS ${ARG_CONFIGURATIONS} )
   else()
      add_test( NAME ${ARG_NAME} ${ARG_UNPARSED_ARGUMENTS} COMMAND ${ARG_COMMAND} )
   endif()
429

430 431 432
   if( ARG_NO_MODULE_LABEL )
      set_tests_properties ( ${ARG_NAME} PROPERTIES LABELS "${ARG_LABELS}" )
   else()
433
      get_current_module_name ( moduleName  )
434 435 436 437
      set_tests_properties ( ${ARG_NAME} PROPERTIES LABELS "${moduleName} ${ARG_LABELS}" )
   endif()

   set_tests_properties ( ${ARG_NAME} PROPERTIES PROCESSORS ${numProcesses} )
438

439 440
endfunction ( waLBerla_execute_test )
#######################################################################################################################