cmakeexternal-projectfetchcontent

cmake FetchContent SOURCE_DIR


I am trying to use a small subproject in a cmake master project using the FetchContent method. Specifically, in the CMakeLists.txt of my master project, I have the lines

include(FetchContent)
FetchContent_Declare(subproject GIT_REPOSITORY https://url/to/my_subproject)
FetchContent_MakeAvailable(subproject)

When I enter cmake in the master project, the subproject is cloned, but the configuration fails.

Specifically, the ${CMAKE_SOURCE_DIR} variable in the subproject contains the source directory of the master project, rather than that of the subproject, so directories relative to it are incorrect. The ${PROJECT_SOURCE_DIR} variable correctly points to the subproject root, and the ${CMAKE_CURRENT_SOURCE_DIR} variable correctly points to the current directory in the subproject.

My questions are:


Solution

  • Unlike to ExternalProject_Add function, which configures a subproject as a separate CMake project, the FetchContent_MakeAvailable effectively calls

    add_subdirectory(<subproject_source_dir> <binary_dir>)
    

    So, when a subproject is configured, it accesses master variables. Exception is a variable which is set by the subproject itself, or a variable which is automatically set by CMake according to the scope (like CMAKE_CURRENT_SOURCE_DIR).

    While ability for a project to be used via FetchContent is useful, not all CMake projects are developed to support such usage. That is, you may fill an issue for a project which uses CMAKE_SOURCE_DIR variable in its calculations. But please mark that issue as a "feature request", not a "bug". (Unless the project's documentation explicitly describes the usage via FetchContent).

    Is there a workaround for the master project?

    Since the variable CMAKE_SOURCE_DIR cannot be set manually, the master project has no other choice than including modified subproject.

    When call FetchContent_Declare, you could specify some executable as PATCH_COMMAND option (the option is described in ExternalProject). That way you may run not only patch, but e.g. a sed script which replaces CMAKE_SOURCE_DIR with some other "scoped" variable.