I'm using cmake v3.13 and I want to change my ExternalProject_Add()
for the SEAL library to:
include(FetchContent)
# Get the seal library
set(SEAL "seal")
FetchContent_Declare(
${SEAL}
GIT_REPOSITORY https://github.com/microsoft/SEAL
GIT_TAG v3.5.2
)
FetchContent_GetProperties(${SEAL})
if(NOT ${SEAL}_POPULATED)
FetchContent_Populate(${SEAL})
add_subdirectory(${${SEAL}_SOURCE_DIR} ${${SEAL}_BINARY_DIR})
endif()
When I was using ExternalProject_Add()
I've used CMAKE_ARGS -DBUILD_SHARED_LIBS=ON
and this doesn't work with FetchContent_Declare()
that only downloads the library.
The SEAL v3.5.2 CMakeLists.txt uses this to check if a shared library needs to be built:
# Should we build also the shared library?
set(BUILD_SHARED_LIBS_STR "Build shared library")
option(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_STR} OFF)
if(MSVC AND BUILD_SHARED_LIBS)
message(WARNING "This build system only supports a static build; disabling `BUILD_SHARED_LIBS`")
set(BUILD_SHARED_LIBS OFF CACHE BOOL ${BUILD_SHARED_LIBS_STR} FORCE)
endif()
# Conditionally build the shared library
if(BUILD_SHARED_LIBS)
add_library(seal_shared SHARED $<TARGET_OBJECTS:seal_obj>)
set_target_properties(seal_shared PROPERTIES OUTPUT_NAME seal)
seal_set_version(seal_shared)
seal_set_soversion(seal_shared)
seal_set_language(seal_shared)
seal_set_include_directories(seal_shared)
seal_link_threads(seal_shared)
# Conditionally add MSGSL include directory to build interface
if(SEAL_USE_MSGSL AND NOT MSVC)
target_include_directories(seal_shared PUBLIC $<BUILD_INTERFACE:${MSGSL_INCLUDE_DIR}>)
endif()
if(SEAL_USE_ZLIB AND NOT MSVC)
# In the shared build we link zlibstatic into the shared library
target_link_libraries(seal_shared PRIVATE zlibstatic)
endif()
seal_install_target(seal_shared SEALTargets)
endif()
Is there a way to download the SEAL library using FetchContent_Declare()
and then use some CMakeLists setting to pass the CMAKE_ARGS -DBUILD_SHARED_LIBS=ON
argument to the downloaded library when building it?
When build some project at the top-level, you may pass a parameter to it using command line option
-D<VARIABLE>=<VALUE>
(ExternalProject_Add
builds the project "as if" top-level, so the option passing is technically the same).
When build some project as a subproject using add_subdirectory
approach, you may use the same command line option
-D<VARIABLE>=<VALUE>
for top-level project, and this parameter will be propagated to the subproject too.
If passing the parameter to the top-level project is not desired, then you may emulate the parameter setting inside CMakeLists.txt
using set(CACHE INTERNAL) command flow:
set(<PARAMETER> <VALUE> CACHE INTERNAL "<some description>")
Make sure this line is issued before add_subdirectory()
call (otherwise it won't affect the subproject).
So in your case you may use following code:
if(NOT ${SEAL}_POPULATED)
FetchContent_Populate(${SEAL})
# Make subproject to use 'BUILD_SHARED_LIBS=ON' setting.
set(BUILD_SHARED_LIBS ON CACHE INTERNAL "Build SHARED libraries")
add_subdirectory(${${SEAL}_SOURCE_DIR} ${${SEAL}_BINARY_DIR})
endif()
All above works perfectly when top-level project doesn't use the parameter set for subproject.
If both top-level project and subproject are affected by the same parameter, and you want to hardcode the parameter for the subdproject only, then things become more complicated. You need to restore the parameter after add_subdirectory
call:
if(NOT ${SEAL}_POPULATED)
FetchContent_Populate(${SEAL})
# Store the old value of the 'BUILD_SHARED_LIBS'
set(BUILD_SHARED_LIBS_OLD ${BUILD_SHARED_LIBS})
# Make subproject to use 'BUILD_SHARED_LIBS=ON' setting.
set(BUILD_SHARED_LIBS ON CACHE INTERNAL "Build SHARED libraries")
add_subdirectory(${${SEAL}_SOURCE_DIR} ${${SEAL}_BINARY_DIR})
# Restore the old value of the parameter
set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_OLD} CACHE BOOL "Type of libraries to build" FORCE)
endif()
# ...
# The library will be created according to "original" value for BUILD_SHARED_LIBS option.
add_library(top_lib top_lib.c)
Note, that in case of restoring parameter, set(CACHE TYPE FORCE)
command flow is used instead of set(CACHE INTERNAL)
. This restores not only a value of the CACHE variable, but also its type, which is shown in CMake GUI.