It makes a project buildable with just CMake and a compiler, which is ideal for small dependencies and test frameworks.
FetchContent downloads a dependency at configure time and adds it to your build as if it were a subdirectory. Its targets then exist in your project:
include(FetchContent)
FetchContent_Declare(fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 11.1.4)
FetchContent_MakeAvailable(fmt)
target_link_libraries(app PRIVATE fmt::fmt)Good practice:
- Pin an exact tag or, better, a commit hash. Downloading a URL archive with
URL_HASH SHA256=...is faster than cloning and verifiable. - Add
FIND_PACKAGE_ARGS(3.24+) soFetchContent_MakeAvailablefirst triesfind_packageand only downloads when the package isn't installed. Distributions and package managers can then supply their own copy. FETCHCONTENT_FULLY_DISCONNECTED=ONorFETCHCONTENT_SOURCE_DIR_<NAME>let offline builds and local checkouts override the download.
Trade-offs: the dependency is built from source in every fresh build tree, its options and warnings mix with yours, and two dependencies fetching different versions of a third library will conflict (the first declaration wins).
For a few small libraries and test frameworks (GoogleTest, Catch2) FetchContent is great. For many or heavy dependencies (Boost, Qt, OpenSSL) use a package manager like vcpkg or Conan, with find_package in the CMakeLists.
Example
cmake_minimum_required(VERSION 3.25)
project(cli LANGUAGES CXX)
include(FetchContent)
FetchContent_Declare(fmt
URL https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz
FIND_PACKAGE_ARGS 11) # use an installed fmt >= 11 if there is one
FetchContent_Declare(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.16.0
GIT_SHALLOW TRUE)
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) # options of the dependency
FetchContent_MakeAvailable(fmt googletest)
add_executable(cli main.cpp)
target_link_libraries(cli PRIVATE fmt::fmt)
add_executable(cli_test test.cpp)
target_link_libraries(cli_test PRIVATE GTest::gtest_main)Remember
- FetchContent_Declare + FetchContent_MakeAvailable add a dependency's targets to your build
- Pin versions; FIND_PACKAGE_ARGS prefers an installed copy
- Use a package manager for many or heavy dependencies
Watch out for
- Fetching a branch name like main, so builds change silently whenever upstream pushes.