# FetchContent and cache variables collisions

**URL:** <https://discourse.cmake.org/t/fetchcontent-and-cache-variables-collisions/13236>\
**Category:** Code\
**Created:** [December 19, 2024, 9:20pm UTC](https://discourse.cmake.org/t/fetchcontent-and-cache-variables-collisions/13236 "2024-12-19T21:20:55Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![petk](https://discourse.cmake.org/user_avatar/discourse.cmake.org/petk/32/4555_2.png) [@petk](https://discourse.cmake.org/u/petk)\
**Post date:** [December 19, 2024, 9:20pm UTC](https://discourse.cmake.org/t/fetchcontent-and-cache-variables-collisions/13236/1 "2024-12-19T21:20:56Z")

</div>

Hello,

as far as I understand, when using the `FetchContent` module and populating the fetched package, all the cache variables are combined together with the top level project into a single `CMakeCache.txt` file.

Are in practice any major issues with this and cache variable often collide?

What would be a way to solve such issue when wanting to add many packages with `FetchContent`?

I’m thinking here about issues like this:

```cmake
# Top level project checks for getcwd symbol:
check_symbol_exists(getcwd "unistd.h" HAVE_GETCWD)

# The fetched project checks for something else and stores the result to a
# variable with the same name HAVE_GETCWD:
check_source_compiles(C "..." HAVE_GETCWD)

```

Is there perhaps some rule of a thumb regarding using `FetchContent`?

Thank you.

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [December 20, 2024, 11:35pm UTC](https://discourse.cmake.org/t/fetchcontent-and-cache-variables-collisions/13236/2 "2024-12-20T23:35:33Z")

</div>

If a project wants to be consumable via FetchContent (or via `add_subdirectory()` as a git submodule, it’s effectively the same use case), that project should avoid using names for things that are too generic. Some strategies to help with that:

- Use CMake target names that incorporate the project name, such as `MyProj_Thing`. This will avoid name collisions when absorbing the project into a larger project’s build.
- Use exported target names like `MyProj::Thing`, creating an ALIAS target with that exported name so that consumers can just use `MyProj::Thing` everywhere and not care whether the project is brought in using FetchContent, or via an installed package.
- Follow recommended naming conventions for cache variables used as result variables of `find_...()` commands. For example, for executables, use names like `THING_EXECUTABLE`. The [Standard Variable Names](https://cmake.org/cmake/help/latest/manual/cmake-developer.7.html#standard-variable-names) section of the developer docs lays out the recommended naming conventions (it’s for Find modules, but projects should ideally follow the same conventions).
- For other cache variables, prefix them with the project name, capitalised. This will also have the handy benefit of collecting all project-specific variables together in GUI applications that show the cache variables in a list, or grouped by prefix (CMake GUI does this). For example, I typically name all boolean option variables following the form `MYPROJ_ENABLE_THING`.

If a dependency doesn’t follow guidelines like those mentioned above, you’re at the mercy of what they define. Some projects simply can’t be used with FetchContent because they do things that cause name clashes with other projects (target names like `documentation`, or use of variables like `CMAKE_SOURCE_DIR` and `CMAKE_BINARY_DIR` are common problems).

You may also be interested in [this issue](https://gitlab.kitware.com/cmake/cmake/-/issues/22687), which proposes a namespace feature for projects. If implemented, it would address a large chunk of problems related to name clashes.

---

<div class="post-metadata">

**Author:** ![petk](https://discourse.cmake.org/user_avatar/discourse.cmake.org/petk/32/4555_2.png) [@petk](https://discourse.cmake.org/u/petk)\
**Post date:** [January 5, 2025, 10:19pm UTC](https://discourse.cmake.org/t/fetchcontent-and-cache-variables-collisions/13236/3 "2025-01-05T22:19:24Z")

</div>

I really think the bar for packages out there is too high. I still unfortunately haven’t encountered a single CMake project that is able to fully follow these conventions. Yes, otherwise, theoretically, following very very very strict conventions goes through ok. But in reality, this is not the case yet.

Issues are mostly related not so much to targets but to cache variables. Also, for example build types are clashing heavily. At some point I thought some new CMake integrated ASAN build type and ASAN compile options by default 🙂 and then I saw that the dependency did that.

---

<div class="post-metadata">

**Author:** ![petk](https://discourse.cmake.org/user_avatar/discourse.cmake.org/petk/32/4555_2.png) [@petk](https://discourse.cmake.org/u/petk)\
**Post date:** [July 19, 2025, 4:12pm UTC](https://discourse.cmake.org/t/fetchcontent-and-cache-variables-collisions/13236/4 "2025-07-19T16:12:09Z")

</div>

I’ll add a bit of further information in case someone will be facing similar issues and concerns.

What I’ve missed previously and haven’t looked into details sooner: FetchContent module can also be used (at the time of writing at least) to download 3rd party dependency and not run the configuration phase of the dependency using the `SOURCE_SUBIDR` option (pointing it to any relative path that doesn’t exist). For that, for example, the ExternaProject module can be used to configure and build the dependency in isolation without joining the cache variables. A very simplified example:

```cmake
include(ExternalProject)
include(FetchContent)

FetchContent_Declare(
  ZLIB
  URL https://github.com/madler/zlib/archive/refs/tags/v1.3.1.tar.gz
  SOURCE_SUBDIR non-existing
  OVERRIDE_FIND_PACKAGE
)

FetchContent_MakeAvailable(ZLIB)

ExternalProject_Add(
  ZLIB
  STEP_TARGETS build install
  SOURCE_DIR ${zlib_SOURCE_DIR}
  BINARY_DIR ${zlib_BINARY_DIR}
  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> -DZLIB_BUILD_TESTING=OFF
  INSTALL_DIR ${FETCHCONTENT_BASE_DIR}/zlib-install
  INSTALL_BYPRODUCTS <INSTALL_DIR>/lib/libz${CMAKE_STATIC_LIBRARY_SUFFIX}
)

ExternalProject_Get_Property(ZLIB INSTALL_DIR)

# Bypass missing directory error for the imported target below.
file(MAKE_DIRECTORY ${INSTALL_DIR}/include)

add_library(ZLIB::ZLIB STATIC IMPORTED GLOBAL)
add_dependencies(ZLIB::ZLIB ZLIB-install)
set_target_properties(
  ZLIB::ZLIB
  PROPERTIES
    INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include
    IMPORTED_LOCATION ${INSTALL_DIR}/lib/libz${CMAKE_STATIC_LIBRARY_SUFFIX}
)

```
