简体   繁体   中英

Dealing with nested cmake projects using FetchContent_

I am looking to automate the compilation of a given c++ library (in this case, cpprestsdk). I am looking to build the library using cmake. Like many other projects, this has dependencies. Namely, it requires OpenSSL, Boost, ZLIB and websocketpp.

I'm looking for a way in which I can provide a CMakeLists file that will fetch and build all of the prerequisites and allow cpprestsdk to build without necessarily having the libraries pre-installed on a computer.

The way I am fetching cpprestsdk is as follows:

FetchContent_Declare(cpprestsdk
                    GIT_REPOSITORY https://github.com/microsoft/cpprestsdk.git
                    GIT_TAG        master)
FetchContent_GetProperties(cpprestsdk)
if(NOT cpprestsdk_POPULATED)
    FetchContent_Populate(cpprestsdk)
    add_subdirectory(${cpprestsdk_SOURCE_DIR} ${cpprestsdk_BINARY_DIR})
endif()

Of course, since this does not populate it's own dependencies, it will not be able to build. Although websocketpp has an embedded release, it is only used if not found. For this reason, I will use it as an example.

FetchContent_Declare(websocketpp
                    GIT_REPOSITORY https://github.com/zaphoyd/websocketpp.git
                    GIT_TAG        master
                    )

FetchContent_GetProperties(websocketpp)

if(NOT websocketpp_POPULATED)
    FetchContent_Populate(websocketpp)
    add_subdirectory(${cpprestsdk_SOURCE_DIR} ${cpprestsdk_BINARY_DIR})
endif()

This will fetch websocketpp, but as it is only the configure stage, nothing will be built. For this reason, cpprestsdk will not be able to find the dependency and instead fallback to the embedded release.

My question is therefore: Is there any way I can force a build after fetching a package? Or remove the library requirement during the configure stage? I think this may be possible using ExternalProject instead, however I'm not too sure how I would set that up either.

You are looking forExternalProject_add

I often use this approach to build externals projects, it provides me automatic control over external projects that are inserted in my projects.

You can include like this:

ExternalProject_add(cpprestsdkDownload    
        GIT_REPOSITORY  https://github.com/microsoft/cpprestsdk   
        GIT_TAG         master   
        CMAKE_ARGS
        -DWERROR:BOOL="0"
        -DBUILD_SAMPLES:BOOL="0"
        -DBUILD_TESTS:BOOL="0" )

You can use your custom configure,build and install commands to ! Have Fun !

I use a subroutine to fetch the source code, then use execute_process to build and install the target.

After this, even find_package can locate the library.

Fetch subroutine:

cmake_minimum_required(VERSION 3.16)

# suppress CMP0042
cmake_policy(SET CMP0042 NEW)
set(CMAKE_MACOSX_RPATH 1)

# this must exist or cmake will complain about not presenting a project()
project(${PK_NAME}_download NONE)

include(FetchContent)

FetchContent_Declare(
        ${PK_NAME}
        GIT_REPOSITORY  "${PK_GIT}"
        GIT_TAG         "${PK_GIT_TAG}"
        PREFIX          "${@PK_NAME@_ROOT}"
)

if(NOT ${PK_NAME}_POPULATED)
    FetchContent_MakeAvailable(${PK_NAME})
endif()

Download, build and install:

# copy the template to place
configure_file(${CMAKE_CURRENT_LIST_DIR}/FetchLib.cmake ${${PK_NAME}_ROOT}/CMakeLists.txt)

# download source code
execute_process(
        COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" -DCMAKE_INSTALL_PREFIX:PATH=${${PK_NAME}_ROOT} ${SUB_PARAM}
        .
        RESULT_VARIABLE result
        WORKING_DIRECTORY ${${PK_NAME}_ROOT}
)

if(result)
    message(FATAL_ERROR "CMake step for ${PK_NAME} failed: ${result}")
endif()

set(CMAKE_INSTALL_PREFIX "${${PK_NAME}_ROOT}")

# build
execute_process(
        COMMAND ${CMAKE_COMMAND} --build .
        RESULT_VARIABLE result
        WORKING_DIRECTORY ${${PK_NAME}_ROOT}
)

if(result)
    message(FATAL_ERROR "Build step for ${PK_NAME} failed: ${result}")
endif()

# install
execute_process(
        COMMAND ${CMAKE_COMMAND} --install .
        RESULT_VARIABLE result
        WORKING_DIRECTORY ${${PK_NAME}_ROOT}
)

if(result)
    message(FATAL_ERROR "Install step for ${PK_NAME} failed: ${result}")
endif()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM