FetchContent (CMake 3.11+)

Often, you would like to do your download of data or packages as part of the configure instead of the build. This was invented several times in third party modules, but was finally added to CMake itself as part of CMake 3.11 as the FetchContent module.

The FetchContent module has excellent documentation that I won’t try to repeat. The key ideas are:

  • Use FetchContent_Declare(MyName) to get data or a package. You can set URLs, Git repositories, and more.
  • Use FetchContent_GetProperties(MyName) on the name you picked in the first step to get MyName_* variables.
  • Check MyName_POPULATED, and if not populated, use FetchContent_Populate(MyName) (and if a package, add_subdirectory("${MyName_SOURCE_DIR}" "${MyName_BINARY_DIR}"))

For example, to download Catch2:

  1. FetchContent_Declare(
  2. catch
  3. GIT_REPOSITORY https://github.com/catchorg/Catch2.git
  4. GIT_TAG v2.13.0
  5. )
  6. # CMake 3.14+
  7. FetchContent_MakeAvailable(catch)

If you can’t use CMake 3.14+, the classic way to prepare code was:

  1. # CMake 3.11+
  2. FetchContent_GetProperties(catch)
  3. if(NOT catch_POPULATED)
  4. FetchContent_Populate(catch)
  5. add_subdirectory(${catch_SOURCE_DIR} ${catch_BINARY_DIR})
  6. endif()

Of course, you could bundled this up into a macro:

  1. if(${CMAKE_VERSION} VERSION_LESS 3.14)
  2. macro(FetchContent_MakeAvailable NAME)
  3. FetchContent_GetProperties(${NAME})
  4. if(NOT ${NAME}_POPULATED)
  5. FetchContent_Populate(${NAME})
  6. add_subdirectory(${${NAME}_SOURCE_DIR} ${${NAME}_BINARY_DIR})
  7. endif()
  8. endmacro()
  9. endif()

Now you have the CMake 3.14+ syntax in CMake 3.11+.

See the example here.