include ( waLBerlaHelperFunctions ) include ( waLBerlaModuleDependencySystem ) set ( WALBERLA_GLOB_FILES *.cpp *.c *.h *.cu CACHE INTERNAL "File endings to glob for source files" ) ####################################################################################################################### # # Creates a walberla module library # # # 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 # EXCLUDE [optional] Files that should not be included in the module (but are located in module directory). # 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. # Example: waLBerla_add_module( DEPENDS someModule BUILD_ONLY_IF_FOUND pe) # 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} ) # Module name is the directory relative to WALBERLA_MODULE_DIRS get_current_module_name ( moduleName ) get_module_library_name ( moduleLibraryName ${moduleName} ) # 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() # Take source files either from parameter or search all source files 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() # Remove exclude files from the sources 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 check_dependencies( missingDeps additionalDeps FILES ${sourceFiles} EXPECTED_DEPS ${ARG_DEPENDS} ${moduleName} ) if ( missingDeps ) message ( WARNING "The module ${moduleName} depends on ${missingDeps} which are not listed as dependencies!" ) endif() set( hasSourceFiles FALSE ) foreach ( sourceFile ${sourceFiles} ) if ( ${sourceFile} MATCHES "\\.(c|cpp|cu)" ) set( hasSourceFiles TRUE ) endif( ) endforeach( ) if ( hasSourceFiles ) set( generatedSourceFiles ) set( generatorSourceFiles ) handle_python_codegen(sourceFiles generatedSourceFiles generatorSourceFiles codeGenRequired ${sourceFiles}) 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 ) cuda_add_library( ${moduleLibraryName} STATIC ${sourceFiles} ${generatedSourceFiles} ${generatorSourceFiles} ${otherFiles} ) else() add_library( ${moduleLibraryName} STATIC ${sourceFiles} ${generatedSourceFiles} ${generatorSourceFiles} ${otherFiles} ) endif( CUDA_FOUND ) set_source_files_properties( ${generatedSourceFiles} PROPERTIES GENERATED TRUE ) else( ) add_custom_target( ${moduleLibraryName} SOURCES ${sourceFiles} ${generatedSourceFiles} ${otherFiles} ) # dummy IDE target endif( ) waLBerla_register_dependency ( ${moduleName} ${ARG_DEPENDS} ) set_property( TARGET ${moduleName} PROPERTY CXX_STANDARD 14 ) # This property is needed for visual studio to group modules together if( WALBERLA_GROUP_PROJECTS ) set_property( TARGET ${moduleLibraryName} PROPERTY FOLDER "SRC" ) endif() # Install rule for library get_target_property( module_type ${moduleLibraryName} TYPE ) if( ${module_type} MATCHES LIBRARY ) install ( TARGETS ${moduleLibraryName} RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib ) endif( ) # Install rule for header install ( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION "walberla/${moduleName}" FILES_MATCHING PATTERN "*.h" PATTERN "*.in.h" EXCLUDE PATTERN "CMakeFiles" EXCLUDE ) # 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}" FILES_MATCHING PATTERN "*.h" PATTERN "*.in.h" EXCLUDE PATTERN "CMakeFiles" EXCLUDE ) endif() # 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} ) 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 # # # 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 # # Example: # waLBerla_compile_app ( NAME myApp DEPENDS core field lbm/boundary ) ####################################################################################################################### function ( waLBerla_add_executable ) set( options ) set( oneValueArgs NAME GROUP ) set( multiValueArgs FILES DEPENDS ) cmake_parse_arguments( ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) if( NOT ARG_NAME ) message ( FATAL_ERROR "waLBerla_add_executable called without a NAME" ) endif() # 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} ) message ( STATUS "Skipping ${ARG_NAME} since dependent module ${depMod} was not built" ) return() endif() endforeach() # Take source files either from parameter or search all source files 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() set( generatedSourceFiles ) set( generatorSourceFiles ) handle_python_codegen(sourceFiles generatedSourceFiles generatorSourceFiles codeGenRequired ${sourceFiles}) if( NOT WALBERLA_BUILD_WITH_CODEGEN AND codeGenRequired) message(STATUS "Skipping ${ARG_NAME} since pystencils code generation is not enabled") return() endif() if ( WALBERLA_BUILD_WITH_CUDA ) cuda_add_executable( ${ARG_NAME} ${sourceFiles} ${generatedSourceFiles} ) else() add_executable( ${ARG_NAME} ${sourceFiles} ${generatedSourceFiles} ) endif() set_source_files_properties( ${generatedSourceFiles} PROPERTIES GENERATED TRUE ) target_link_modules ( ${ARG_NAME} ${ARG_DEPENDS} ) target_link_libraries( ${ARG_NAME} ${WALBERLA_LINK_LIBRARIES_KEYWORD} ${SERVICE_LIBS} ) set_property( TARGET ${ARG_NAME} PROPERTY CXX_STANDARD 14 ) if( WALBERLA_GROUP_PROJECTS ) if( NOT ARG_GROUP ) set( ARG_GROUP "APPS" ) endif() set_property( TARGET ${ARG_NAME} PROPERTY FOLDER ${ARG_GROUP} ) endif() endfunction ( waLBerla_add_executable ) ####################################################################################################################### ####################################################################################################################### # # Function to tell CMake which C/C++/CUDA files are generated by a python file # # Example: # waLBerla_python_file_generates(MyPythonCodeGenScript.py Sweep1.cpp Sweep1.h Sweep2.h Sweep2.cu) # # ####################################################################################################################### function( waLBerla_python_file_generates pythonFile ) get_filename_component(pythonFileAbsolutePath ${pythonFile} ABSOLUTE) set( "WALBERLA_CODEGEN_INFO_${pythonFileAbsolutePath}" ${ARGN} CACHE INTERNAL "Files generated by python script ${pythonFile}" FORCE) endfunction(waLBerla_python_file_generates) ####################################################################################################################### # # 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} ) # Module name is the directory relative to WALBERLA_MODULE_DIRS get_current_module_name ( moduleName ) # 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() waLBerla_add_executable ( NAME ${ARG_NAME} GROUP "TESTS/${moduleName}" DEPENDS ${ARG_DEPENDS} ${moduleName} FILES ${ARG_FILES} ) endfunction ( waLBerla_compile_test ) ####################################################################################################################### ####################################################################################################################### # # Links all files in current source dir matching a globbing expression to the build directory # # first parameter is glob expression # # 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" ) # # Symlinking works only under linux, on windows the files are copied. For in-source builds this does nothing. # ####################################################################################################################### function ( waLBerla_link_files_to_builddir globExpression ) # don't need links for in-source builds if( CMAKE_CURRENT_SOURCE_DIR STREQUAL "${CMAKE_CURRENT_BINARY_DIR}" ) return() endif() file( GLOB filesToLink RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${globExpression} ) foreach( f ${filesToLink} ) 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() endforeach() endfunction ( waLBerla_link_files_to_builddir ) ####################################################################################################################### # # Adds an executable to CTest. # # 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 # PROCESSES [optional] Number of MPI processes, that are used to start this test. # 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 # command line options. # Defaults to $<TARGET_FILE:${NAME}> (for this syntax see cmake documentation of add_test ) # LABELS [optional] Additional test labels. # ####################################################################################################################### function ( waLBerla_execute_test ) set( options NO_MODULE_LABEL ) set( oneValueArgs NAME PROCESSES ) set( multiValueArgs COMMAND LABELS CONFIGURATIONS DEPENDS_ON_TARGETS ) cmake_parse_arguments( ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) if( NOT ARG_NAME ) message ( FATAL_ERROR "waLBerla_execute_test called without a NAME" ) endif() if( NOT ARG_COMMAND AND NOT TARGET ${ARG_NAME} ) message ( STATUS "Skipping test ${ARG_NAME} since the corresponding target is not built" ) return() endif() foreach( dependency_target ${ARG_DEPENDS_ON_TARGETS} ) if( NOT TARGET ${dependency_target} ) message ( STATUS "Skipping test ${ARG_NAME} since the target ${dependency_target} is not built" ) return() endif() endforeach( dependency_target ) 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 ) 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} ) elseif( numProcesses GREATER 1 ) return() endif() 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() if( ARG_NO_MODULE_LABEL ) set_tests_properties ( ${ARG_NAME} PROPERTIES LABELS "${ARG_LABELS}" ) else() get_current_module_name ( moduleName ) set_tests_properties ( ${ARG_NAME} PROPERTIES LABELS "${moduleName} ${ARG_LABELS}" ) endif() set_tests_properties ( ${ARG_NAME} PROPERTIES PROCESSORS ${numProcesses} ) endfunction ( waLBerla_execute_test ) #######################################################################################################################