Skip to content
Snippets Groups Projects
Commit 6bceb786 authored by Steffen Müthing's avatar Steffen Müthing
Browse files

[CMake] Clean up dune_enable_all_packages() and fix library handling

dune_enable_all_packages() doesn't really work if a module contains
libraries (it triggers CMP022 and CMP038). This patch works around that
problem and also adds a number of convenience features to the overall
mechanism. In particular:

- dune_enable_all_packages() now accepts optional lists of additional
  include directories and compile definitions that will be applied to
  all targets in the module. There is a new option APPEND that controls
  the placement of those compiler arguments, analogous to
  dune_register_package_flags().

- Libraries need special handling to work around the problem with the
  two CMake policies listed above. Those get triggered because libraries
  defined in the module ended up linking to themselves, and newer
  versions of CMake really don't like that. We can avoid this problem by
  exploiting the fact that the set of libraries contained in
  link_libraries is evaluated only once, at the point when a target is
  created. So we only have to make sure that libraries inside the module
  are created before they are added to link_libraries(). But we have to
  be careful to make sure that link_libraries() is called before the
  user creates any targets that depend on the module library.
  In order to minimize the risk of user error, I have integrated those
  two tasks (creating the library and adding it to link_libraries())
  into the dune_enable_all_packages() macro. So this macro now accepts a
  list of library names (as the multi argument MODULE_LIBRARIES). These
  are automatically created using dune_add_library() (placing them in
  lib/) in the order that they are listed and added to link_libraries()
  afterwards. Users MUST use this mechanism if they want the library to
  be linked automatically to programs in the module. On the other hand,
  you can still manually create libraries, but then you have to link to
  them manually (e.g. the Alberta libs in dune-grid).

- There is a new macro dune_library_add_sources() that can be used to add
  source files to libraries created with the help of
  dune_enable_all_packages(). That macro can be called repeatedly and in
  any subdirectory of the source tree. Using this facility, I think we
  can mostly get rid of OBJECT libraries. :-)

- CMake doesn't like to create a target without any source files, so the
  patch generates a small stub source for each library that contains two
  functions that are named after the library and return the version of
  the associated dune module.
parent e68c8651
No related branches found
No related tags found
No related merge requests found
...@@ -10,17 +10,31 @@ ...@@ -10,17 +10,31 @@
# #
# This module provides the following macros: # This module provides the following macros:
# #
# dune_enable_all_packages([VERBOSE]) # dune_enable_all_packages(INCLUDE_DIRS [include_dirs]
# COMPILE_DEFINITIONS [compile_definitions]
# MODULE_LIBRARIES [libraries]
# [VERBOSE] [APPEND]
# )
# #
# Adds all flags and all libraries to all executables that are added in the directory # Adds all flags and all libraries to all executables that are subsequently added in the directory
# from where this macro is called and from all its subdirectories (recursively). # from where this macro is called and from all its subdirectories (recursively).
# Typically, a user would add the call to this macro to his top level CMakeLists.txt # If used, this macro MUST be called in the top level CMakeLists.txt BEFORE adding any subdirectories!
# You can optionally add additional include dirs and compile definitions that will also be applied to
# all targets in the module.
# Finally, if your module contains libraries as well as programs and if the programs should automatically
# link to those libraries, you MUST list these libraries in MODULE_LIBRARIES. Those libraries will be
# automatically created by dune_enable_all_packages (which internally calls dune_add_library()) and placed
# in the lib/ directory. The order of the libraries matters: if one library depends on another one, it must
# be listed after its dependency. This special handling of the libraries is due to the way newer CMake
# versions handle linking (in particular CMP022 and CMP038). You can later add source files to the library
# anywhere in the source tree by calling dune_library_add_sources().
# For a description of the APPEND option, see the documentation of dune_register_package_flags().
# With the VERBOSE option being set, the list of flags is printed during configure. # With the VERBOSE option being set, the list of flags is printed during configure.
# #
# dune_register_package_flags(COMPILE_DEFINITIONS flags # dune_register_package_flags(COMPILE_DEFINITIONS flags
# INCLUDE_DIRS includes # INCLUDE_DIRS includes
# LIBRARIES libs # LIBRARIES libs
# [PREPEND] # [APPEND]
# ) # )
# #
# To implement above feature, the compile flags, include paths and link flags of all # To implement above feature, the compile flags, include paths and link flags of all
...@@ -28,33 +42,16 @@ ...@@ -28,33 +42,16 @@
# that do link against additional libraries which are not supported by the dune core modules. # that do link against additional libraries which are not supported by the dune core modules.
# Call this at the end of every find module. If you are using an external find module which # Call this at the end of every find module. If you are using an external find module which
# you cannot alter, call it after the call find_package(). # you cannot alter, call it after the call find_package().
# The PREPEND parameter prepends the given flags to the global list instead of appending. # The APPEND parameter appends the given flags to the global list instead of prepending.
# Only use it, if you know what you are doing. # Only use it, if you know what you are doing.
#
macro(dune_enable_all_packages) # dune_library_add_sources(module_library
include(CMakeParseArguments) # SOURCES [sources]
cmake_parse_arguments(ENABLE_ALL_PACKAGES VERBOSE "" "" ${ARGN}) # )
#
get_property(all_incs GLOBAL PROPERTY ALL_PKG_INCS) # Adds the source files listed in [sources] to the module library module_library created by an earlier
include_directories(${all_incs}) # call to dune_enable_all_packages.
if(ENABLE_ALL_PACKAGES_VERBOSE) #
message("Include directories for this project: ${all_incs}")
endif(ENABLE_ALL_PACKAGES_VERBOSE)
get_property(all_libs GLOBAL PROPERTY ALL_PKG_LIBS)
link_libraries(${DUNE_LIBS} ${all_libs})
if(ENABLE_ALL_PACKAGES_VERBOSE)
message("Libraries for this project: ${all_libs}")
endif(ENABLE_ALL_PACKAGES_VERBOSE)
get_property(all_defs GLOBAL PROPERTY ALL_PKG_DEFS)
foreach(def ${all_defs})
add_definitions("-D${def}")
endforeach(def in ${all_defs})
if(ENABLE_ALL_PACKAGES_VERBOSE)
message("Compile definitions for this project: ${all_defs}")
endif(ENABLE_ALL_PACKAGES_VERBOSE)
endmacro(dune_enable_all_packages)
function(dune_register_package_flags) function(dune_register_package_flags)
include(CMakeParseArguments) include(CMakeParseArguments)
...@@ -80,3 +77,109 @@ function(dune_register_package_flags) ...@@ -80,3 +77,109 @@ function(dune_register_package_flags)
set_property(GLOBAL PROPERTY ALL_PKG_DEFS "${REGISTRY_COMPILE_DEFINITIONS}" "${all_defs}") set_property(GLOBAL PROPERTY ALL_PKG_DEFS "${REGISTRY_COMPILE_DEFINITIONS}" "${all_defs}")
endif(REGISTRY_APPEND) endif(REGISTRY_APPEND)
endfunction(dune_register_package_flags) endfunction(dune_register_package_flags)
macro(dune_enable_all_packages)
include(CMakeParseArguments)
set(OPTIONS APPEND VERBOSE)
set(SINGLEARGS)
set(MULTIARGS COMPILE_DEFINITIONS INCLUDE_DIRS MODULE_LIBRARIES)
cmake_parse_arguments(ENABLE_ALL_PACKAGES "${OPTIONS}" "${SINGLEARGS}" "${MULTIARGS}" ${ARGN})
if(ENABLE_ALL_PACKAGES_UNPARSED_ARGUMENTS)
message(WARNING "Unrecognized arguments for dune_enable_all_packages!")
endif()
# handle additional include dirs specified in dune_enable_all_packages
if(ENABLE_ALL_PACKAGES_INCLUDE_DIRS)
if(ENABLE_ALL_PACKAGES_APPEND)
set_property(GLOBAL APPEND PROPERTY ALL_PKG_INCS "${ENABLE_ALL_PACKAGES_INCLUDE_DIRS}")
else(ENABLE_ALL_PACKAGES_APPEND)
get_property(all_incs GLOBAL PROPERTY ALL_PKG_INCS)
set_property(GLOBAL PROPERTY ALL_PKG_INCS "${ENABLE_ALL_PACKAGES_INCLUDE_DIRS}" "${all_incs}")
endif(ENABLE_ALL_PACKAGES_APPEND)
endif(ENABLE_ALL_PACKAGES_INCLUDE_DIRS)
# add include dirs to all targets in module
get_property(all_incs GLOBAL PROPERTY ALL_PKG_INCS)
include_directories(${all_incs})
# verbose output of include dirs
if(ENABLE_ALL_PACKAGES_VERBOSE)
message("Include directories for this project: ${all_incs}")
endif(ENABLE_ALL_PACKAGES_VERBOSE)
# handle additional compile definitions specified in dune_enable_all_packages
if(ENABLE_ALL_PACKAGES_COMPILE_DEFINITIONS)
if(ENABLE_ALL_PACKAGES_COMPILE_DEFINITIONS)
set_property(GLOBAL APPEND PROPERTY ALL_PKG_DEFS "${ENABLE_ALL_PACKAGES_COMPILE_DEFINITIONS}")
else(ENABLE_ALL_PACKAGES_APPEND)
get_property(all_defs GLOBAL PROPERTY ALL_PKG_DEFS)
set_property(GLOBAL PROPERTY ALL_PKG_DEFS "${ENABLE_ALL_PACKAGES_COMPILE_DEFINITIONS}" "${all_defs}")
endif(ENABLE_ALL_PACKAGES_APPEND)
endif(ENABLE_ALL_PACKAGES_COMPILE_DEFINITIONS)
# add compile definitions to all targets in module
get_property(all_defs GLOBAL PROPERTY ALL_PKG_DEFS)
foreach(def ${all_defs})
add_definitions("-D${def}")
endforeach(def in ${all_defs})
# verbose output of compile definitions
if(ENABLE_ALL_PACKAGES_VERBOSE)
message("Compile definitions for this project: ${all_defs}")
endif(ENABLE_ALL_PACKAGES_VERBOSE)
# handle libraries
# this is a little tricky because the libraries defined within the current module require special
# handling to avoid tripping over CMake policies CMP022 and CMP038
# first add all libraries of upstream Dune modules and of external dependencies
get_property(all_libs GLOBAL PROPERTY ALL_PKG_LIBS)
link_libraries(${DUNE_LIBS} ${all_libs})
# now we have to do a little dance: Newer versions of CMake complain if a target links to itself,
# so we have to create all targets for libraries inside the module before adding them to the set
# of default libraries to link to. That works because calling link_libraries does not affect targets
# which already exist.
# Moroever, CMake generates a warning when creating a library without any source files, and the linker
# does the same if we add an empty dummy file. We work around that problem by autogenerating a library-specific
# stub source file with two functions ${lib_name}_version() and ${lib_name}_version_string() and add that
# as an initial source file.
# After creating the library with dune_add_library(), we add it to all future targets with a call to
# link_libraries(). The user can then add the real source files by calling dune_library_add_sources()
# throughout the module.
if(ENABLE_ALL_PACKAGES_MODULE_LIBRARIES)
# make sure the /lib directory exists - we need it to create the stub source file in there
file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
# figure out the location of the stub source template
dune_common_script_dir(script_dir)
foreach(module_lib ${ENABLE_ALL_PACKAGES_MODULE_LIBRARIES})
# create the stub source file in the output directory...
configure_file("${script_dir}/module_library.cc.in" "${PROJECT_BINARY_DIR}/lib/lib${module_lib}_stub.cc")
# ...and create the library...
dune_add_library(${module_lib} SOURCES "${PROJECT_BINARY_DIR}/lib/lib${module_lib}_stub.cc")
# ...and add it to all future targets in the module
link_libraries(${module_lib})
endforeach(module_lib ${ENABLE_ALL_PACKAGES_MODULE_LIBRARIES})
endif(ENABLE_ALL_PACKAGES_MODULE_LIBRARIES)
if(ENABLE_ALL_PACKAGES_VERBOSE)
get_property(all_libs GLOBAL PROPERTY ALL_PKG_LIBS)
message("Libraries for this project: ${all_libs}")
endif(ENABLE_ALL_PACKAGES_VERBOSE)
endmacro(dune_enable_all_packages)
macro(dune_library_add_sources lib)
include(CMakeParseArguments)
cmake_parse_arguments(DUNE_LIB "" "" "SOURCES" ${ARGN})
if(DUNE_LIB_UNPARSED_ARGUMENTS)
message(WARNING "Unrecognized arguments for dune_library_add_sources!")
endif()
foreach(source ${DUNE_LIB_SOURCES})
target_sources(${lib} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${source})
endforeach()
endmacro()
#include <string>
std::size_t ${module_lib}_version()
{
return ${ProjectVersionMajor} * 10000 + ${ProjectVersionMinor} * 100 + ${ProjectVersionRevision};
}
std::string ${module_lib}_version_string()
{
return "${ProjectVersion}";
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment