FetchContent_Declare with CMAKE_ARGS does not work

Consider this example.

FetchContent_Declare(
    glfw
    GIT_REPOSITORY  https://github.com/glfw/glfw.git
    GIT_TAG         "master"
    SOURCE_DIR      "${CMAKE_CURRENT_SOURCE_DIR}/glfw-src"
    GIT_SHALLOW     TRUE
    CMAKE_ARGS
        -DGLFW_BUILD_WAYLAND=ON
        -DGLFW_BUILD_X11=OFF
)

But from within the project, GLFW_BUILD_X11 is reported as ON. The docs do not completely make it clear to me this is how CMAKE_ARGS is supposed to be used. Did I get this right? Why is camke not setting GLFW_BUILD_X11 to OFF when building glfw?

There are some tests found in cmake git repo:

bash-5.2$ cd Downloads/cmake/Tests/
bash-5.2$ grep -rw CMAKE_ARGS
./ExternalProjectSubdir/CMakeLists.txt:  CMAKE_ARGS -DNORMAL_VAR=NORMAL_VALUE -DGENEX_VAR=$<1:GENEX_VALUE>
./LinkDirectory/CMakeLists.txt:  CMAKE_ARGS "-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${LinkDirectory_BINARY_DIR}/bin"
./ExternalProjectLocal/CMakeLists.txt:CMAKE_ARGS -G ${CMAKE_GENERATOR} <SOURCE_DIR>
./ExternalProjectLocal/CMakeLists.txt:CMAKE_ARGS --install-prefix=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
./ExternalProjectLocal/CMakeLists.txt:CMAKE_ARGS --install-prefix=<INSTALL_DIR>  -G ${CMAKE_GENERATOR} <SOURCE_DIR>
./ExternalProjectLocal/CMakeLists.txt:CMAKE_ARGS --install-prefix=<INSTALL_DIR>  -G ${CMAKE_GENERATOR} <SOURCE_DIR>
./ExternalProjectLocal/CMakeLists.txt:  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
./ExternalProjectLocal/CMakeLists.txt:  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
./ExternalProjectLocal/CMakeLists.txt:  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
./ExternalProjectLocal/CMakeLists.txt:  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>

But I can confirm, it does not work with cmake v3.30?

1 Like

A full example from ProfessionalCMake book:

  ExternalProject_Add(Firmware
      SOURCE_DIR  ${CMAKE_CURRENT_LIST_DIR}/Firmware
      INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/Firmware-artifacts
      CMAKE_ARGS
          -D CMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_LIST_DIR}/fwtoolchain.cmake
          -D CMAKE_BUILD_TYPE=Release
          -D CMAKE_INSTALL_PREFIX=<INSTALL_DIR>
)

@craig.scott do you have any idea what goes wrong?

Thank you for verifying this, appreciate it!

Thought I was going crazy for a while haha.

@ClausKlein The original post is about FetchContent, not ExternalProject.

@buildtool Note the following from the documentation of the FetchContent_Declare() command:

FetchContent_Declare(
 <name>
 <contentOptions>...
 [EXCLUDE_FROM_ALL]
 [SYSTEM]
 [OVERRIDE_FIND_PACKAGE |
  FIND_PACKAGE_ARGS args...]
)

…(some docs omitted)…

The <contentOptions> can be any of the download, update, or patch options that the ExternalProject_Add() command understands. The configure, build, install, and test steps are explicitly disabled, so options related to those steps will be ignored.

The CMAKE_ARGS keyword relates to the configure step and is therefore ignored. If you want variables like GLFW_BUILD_WAYLAND and GLFW_BUILD_X11 set to particular values when glfw is added to the main project, you need to set them in the main project before the call to FetchContent_MakeAvailable(glfw). Also note that even if you do that, if something else in the build has already added glfw to the build (by calling FetchContent_MakeAvailable(glfw) earlier), setting those variables will have no effect. Depending on the project, you might or might not have full control over when FetchContent_MakeAvailable(glfw) is called first.

1 Like

But as of cmake 3.30, the single arg FetchContent_Populate has been deprecated, instead asking me to use FetchContent_Declare.

How am I to set cmake configure args for this? As classic workflows (that I had to scrape off the internet, and not present in the docs) does not work anymore

include(FetchContent)

FetchContent_Declare(
    glfw
    GIT_REPOSITORY  https://github.com/glfw/glfw.git
    SOURCE_DIR      "${CMAKE_CURRENT_SOURCE_DIR}/glfw-src"
    GIT_TAG         "master"
    GIT_SHALLOW     TRUE
)

FetchContent_GetProperties(glfw)

if(NOT glfw_POPULATED)
    FetchContent_Populate(glfw)
    set(GLFW_BUILD_WAYLAND  ON  CACHE INTERNAL BOOL)
    set(GLFW_BUILD_X11      OFF CACHE INTERNAL BOOL)
endif()

CMAKE_ARGS has never been supported for any version of FetchContent. Regardless of whether you were using FetchContent_Populate() or FetchContent_MakeAvailable(), the configure step has never been invoked by the sub-build. Whatever you were expecting CMAKE_ARGS to do, it wasn’t having any effect and at best was being silently ignored (and continues to be).

How am I to set cmake configure args for this?

I explained what you need to do in my previous reply. It would look something like this (with the caveats as noted in that previous reply):

include(FetchContent)

FetchContent_Declare(
    glfw
    GIT_REPOSITORY  https://github.com/glfw/glfw.git
    SOURCE_DIR      "${CMAKE_CURRENT_SOURCE_DIR}/glfw-src"
    GIT_TAG         "master"
    GIT_SHALLOW     TRUE
)
set(GLFW_BUILD_WAYLAND  ON)
set(GLFW_BUILD_X11      OFF)
FetchContent_MakeAvailable(glfw)

Great, thank you!

Can I set cmake general options such as CMAKE_BUILD_TYPE and CMAKE_CXX_FLAGS too? Would they apply only to glfw, in this example, or for the whole project?

include(FetchContent)

FetchContent_Declare(
    glfw
    GIT_REPOSITORY  https://github.com/glfw/glfw.git
    SOURCE_DIR      "${CMAKE_CURRENT_SOURCE_DIR}/glfw-src"
    GIT_TAG         "master"
    GIT_SHALLOW     TRUE
)
set(GLFW_BUILD_WAYLAND  ON)
set(GLFW_BUILD_X11      OFF)
set(CMAKE_BUILD_TYPE Release)
FetchContent_MakeAvailable(glfw)

caveats as noted in that previous reply

What’s the “correct” approach here then?