-
Notifications
You must be signed in to change notification settings - Fork 203
CMake option name clashes with FetchContent #4618
Description
This is a follow-up to the dev-meeting discussion about name clashes when including external libraries with FetchContent.
CMake target name clashes
ESPResSo CMake target names cannot clash with included libraries thanks to the use of a unique prefix:
add_library(espresso_core SHARED)
add_library(espresso::core ALIAS espresso_core)
target_sources(espresso_core PRIVATE cells.cpp ...)
target_link_libraries(espresso_core PRIVATE espresso::config ...)
install(TARGETS espresso_core
LIBRARY DESTINATION ${ESPRESSO_INSTALL_PYTHON}/espressomd)Advantages:
- no name clashes for shared objects: files always prefixed by
espresso_- this was also necessary for Cython:
shapes.pyno longer clashes withshapes.so(renamed toespresso_shapes.so)
- this was also necessary for Cython:
- no name clashes for CMake targets: targets always prefixed by
espresso_- all modifiers have to use the
espresso_target:target_sources(),target_link_libraries(),install() - all consumers have to use the
espresso::alias, including any parent CMake project
- all modifiers have to use the
- if a consumer tries to link against a non-existing
espresso::target_name, CMake throws an error; linking against a non-existingespresso_target_namedoesn't throw an error, instead the string is passed to the linker, which may or may not throw an error
CMake project option clashes
Regarding CMake project options, to my knowledge there isn't a built-in way to namespace them. Contrary to ExternalProject, which provides CMAKE_ARGS and CMAKE_CACHE_ARGS to pass CMake options to the external CMake project, FetchContent doesn't allow providing different CMake options, because the CMakeCache.txt of the subproject is merged into the root project. There have been several discussions about improving FetchContent, see discussions in cmake/cmake#23710 (comment) and cmake/cmake#22687, but none of them addresses this situation.
There are several workarounds.
The first one consists in defining a subset of common CMake options that can be safely inherited from a parent project, and automatically disable all other options. The MWE below is adapted from
Preparing libraries for CMake FetchContent by Jonathan:
project(ESPRESSO LANGUAGES CXX)
# define common build options that are inherited from parent projects
option(WITH_COVERAGE "Enable code coverage instrumentation" OFF)
add_subdirectory(src)
# define build options specific to this project, that
# cannot be activated if this project is a subproject
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
# we're in the root, define additional targets for developers.
option(ESPRESSO_WITH_TESTS "Enable tests" ON)
if(ESPRESSO_WITH_TESTS)
add_subdirectory(tests)
endif()
endif()The downside is, some project-specific options shouldn't be hidden, e.g. WITH_HDF5, but at the same time they may clash with parent projects.
The second workaround consists in setting the CMake options before the add_subdirectory() command, while taking care of stashing the root project variables and unstashing them later with the same properties (cache, docstring) to avoid issues with variable lifetime and ccmake, and making sure these properties are always manually updated whenever the original option declarations change. The MWE below is adapted from Using FetchContent_Declare together with CMAKE_ARGS by Tsyvarev:
if(NOT librepa_POPULATED)
FetchContent_Populate(librepa)
set(WITH_TESTS_OLD ${WITH_TESTS})
set(WITH_TESTS OFF CACHE INTERNAL "")
add_subdirectory(${librepa_SOURCE_DIR} ${librepa_BINARY_DIR})
set(WITH_TESTS ${WITH_TESTS_OLD} CACHE BOOL "Enable tests" FORCE)
endif()The third method consists in manually prefixing all CMake options with the project name, i.e.
cmake .. -D ESPRESSO_WITH_HDF5=ON -D ESPRESSO_WITH_TESTS=ONThis is the solution taken by the waLBerla project.
In my opinion, the third method is the safest and most sustainable strategy. We would need to add a prefix to our own CMake options to avoid name collisions, and rely on these options instead of e.g. FFTW_FOUND variables that can be inherited from a parent project that includes ESPResSo. We should also convince library developers to do the same in their projects (SC-SGS/repa#51, walberla/walberla#191).
Originally posted by @jngrad in #4474 (comment)