# Prevent FetchContent\_MakeAvailable to execute CMakeLists.txt

**URL:** https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704
**Category:** Usage
**Created:** [October 7, 2024, 5:02pm UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704 "2024-10-07T17:02:03Z")
**Posts on this page:** 16
**Page:** 1

<div class="post-metadata">

### Author: ![fry](https://discourse.cmake.org/user_avatar/discourse.cmake.org/fry/32/613_2.png) [@fry](https://discourse.cmake.org/u/fry)
#### Post date: [October 7, 2024, 5:02pm UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/1 "2024-10-07T17:02:03Z")

</div>

After seeing the deprecation warnings for `FetchContent_Populate` I replaced it with `FetchContent_MakeAvailable` but now my project is failing.

I use to do this (in a nutshell)

```cmake
# ...
FetchContent_Declare(re-logging ...)
FetchContent_Populate(re-logging)
include("${re-logging_ROOT_DIR}/re-logging.cmake")

```

The issue I am facing with replacing `FetchContent_Populate` with `FetchContent_MakeAvailable` is that `FetchContent_MakeAvailable` seems to automatically “execute” `CMakeLists.txt` included in re-logging but I don’t want this to happen. `FetchContent_Populate` did not do that.

I want to load `re-logging.cmake` instead.

Is there a way to do this?

---

<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: [October 7, 2024, 9:03pm UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/3 "2024-10-07T21:03:33Z")

</div>

Use the `SOURCE_SUBDIR` option and set it to a path that doesn’t exist. [Issue 26220](https://gitlab.kitware.com/cmake/cmake/-/issues/26220) asks for a dedicated keyword to say “don’t add the subdirectory, only populate it”.

---

<div class="post-metadata">

### Author: ![fry](https://discourse.cmake.org/user_avatar/discourse.cmake.org/fry/32/613_2.png) [@fry](https://discourse.cmake.org/u/fry)
#### Post date: [October 8, 2024, 4:51pm UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/4 "2024-10-08T16:51:52Z")

</div>

Thank you for the workaround.

---

<div class="post-metadata">

### Author: ![rookie86](https://discourse.cmake.org/user_avatar/discourse.cmake.org/rookie86/32/5146_2.png) [@rookie86](https://discourse.cmake.org/u/rookie86)
#### Post date: [November 29, 2024, 5:54pm UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/5 "2024-11-29T17:54:05Z")

</div>

We went away from CMake after this decision. To replace a working function with such a workaround is simply unprofessional.

---

<div class="post-metadata">

### Author: ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)
#### Post date: [November 30, 2024, 3:26am UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/6 "2024-11-30T03:26:24Z")

</div>

So [populating content without adding it to the build](https://cmake.org/cmake/help/latest/module/FetchContent.html#populating-content-without-adding-it-to-the-build) does not work?

I though there is a [DOWNLOAD\_ONLY](https://github.com/cpm-cmake/CPM.cmake?tab=readme-ov-file#usage) option as `CPM.cmake` has?

---

<div class="post-metadata">

### Author: ![rookie86](https://discourse.cmake.org/user_avatar/discourse.cmake.org/rookie86/32/5146_2.png) [@rookie86](https://discourse.cmake.org/u/rookie86)
#### Post date: [November 30, 2024, 6:51am UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/7 "2024-11-30T06:51:07Z")

</div>

FetchContent\_Populate works like a charm but is deprecated now. And thats the problem.

---

<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: [November 30, 2024, 7:44am UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/8 "2024-11-30T07:44:49Z")

</div>

Many open source projects continued to use `FetchContent_Populate()` long after `FetchContent_MakeAvailable()` replaced it as the recommended way to populate content. That prevented those projects from being handled by dependency providers. The deprecation is a clear signal that projects relying on `FetchContent_Populate()` need to migrate. Everything you could do with `FetchContent_Populate()` before, you can do with `FetchContent_MakeAvailable()` now. My [earlier comment](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/3) explains how to use `SOURCE_SUBDIR` to prevent calling `add_subdirectory()` for those who were using `FetchContent_Populate()` to only download things but not add them to the project. That comment also linked to an issue that discusses that use case in more detail.

---

<div class="post-metadata">

### Author: ![ClausKlein](https://discourse.cmake.org/user_avatar/discourse.cmake.org/clausklein/32/352_2.png) [@ClausKlein](https://discourse.cmake.org/u/ClausKlein)
#### Post date: [November 30, 2024, 7:55am UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/9 "2024-11-30T07:55:44Z")

</div>

Is the documentation wrong?  
Quote from [https://cmake.org/cmake/help/latest/module/FetchContent.html#populating-content-without-adding-it-to-the-build](https://cmake.org/cmake/help/latest/module/FetchContent.html#populating-content-without-adding-it-to-the-build)

```quote
Projects don't always need to add the populated content to the build.
 Sometimes the project just wants to make the downloaded content 
available at a predictable location. 
...

```

---

<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: [November 30, 2024, 7:58am UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/10 "2024-11-30T07:58:48Z")

</div>

It’s not wrong, it just doesn’t cover the case specifically being discussed here. That example assumes there is no `CMakeLists.txt` in the top level of the toolchains project. If I find time, I’ll update that example to make things clearer.

I also just added a comment to the linked issue to give more clarity on my thinking around the requested feature.

---

<div class="post-metadata">

### Author: ![fry](https://discourse.cmake.org/user_avatar/discourse.cmake.org/fry/32/613_2.png) [@fry](https://discourse.cmake.org/u/fry)
#### Post date: [November 30, 2024, 1:30pm UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/11 "2024-11-30T13:30:48Z")

</div>

Maybe I am missing something, but I have another project that was using `FetchContent_Declare` and `FetchContent_Populate`.

[Old code](https://github.com/pongasoft/vst-sam-spl-64/blob/af474c810f775d0a5463276705e5e92e8c59cbb0/fetch_jamba.cmake):

```cmake
FetchContent_Declare(jamba
      GIT_REPOSITORY ${JAMBA_GIT_REPO}
      GIT_TAG ${JAMBA_GIT_TAG}
      GIT_CONFIG advice.detachedHead=false
      GIT_SHALLOW true
      SOURCE_DIR "${CMAKE_BINARY_DIR}/jamba"
      BINARY_DIR "${CMAKE_BINARY_DIR}/jamba-build"
      CONFIGURE_COMMAND ""
      BUILD_COMMAND ""
      INSTALL_COMMAND ""
      TEST_COMMAND ""
      )

FetchContent_GetProperties(jamba)

if(NOT jamba_POPULATED)

  if(FETCHCONTENT_SOURCE_DIR_JAMBA)
    message(STATUS "Using jamba from local ${FETCHCONTENT_SOURCE_DIR_JAMBA}")
  else()
    message(STATUS "Fetching jamba ${JAMBA_GIT_REPO}/tree/${JAMBA_GIT_TAG}")
  endif()

  FetchContent_Populate(jamba)

```

[New code](https://github.com/pongasoft/vst-sam-spl-64/blob/e5200783b7d44ffa844d090d213bfee610475d11/fetch_jamba.cmake), does **not** use `FetchContent_Declare` and instead uses the other form of `FetchContent_Populate`

```cmake
if(JAMBA_ROOT_DIR)
  message(STATUS "Using jamba from local ${JAMBA_ROOT_DIR}")
  FetchContent_Populate(jamba
      QUIET
      SOURCE_DIR "${JAMBA_ROOT_DIR}"
      BINARY_DIR "${CMAKE_BINARY_DIR}/jamba-build"
  )
else()
  if(JAMBA_DOWNLOAD_URL STREQUAL "" OR JAMBA_DOWNLOAD_URL_HASH STREQUAL "")
    message(STATUS "Fetching jamba from ${JAMBA_GIT_REPO}/tree/${JAMBA_GIT_TAG}")
    FetchContent_Populate(jamba
        QUIET
        GIT_REPOSITORY ${JAMBA_GIT_REPO}
        GIT_TAG ${JAMBA_GIT_TAG}
        GIT_CONFIG advice.detachedHead=false
        GIT_SHALLOW true
        SOURCE_DIR "${CMAKE_BINARY_DIR}/jamba"
        BINARY_DIR "${CMAKE_BINARY_DIR}/jamba-build"
    )
  else()
    message(STATUS "Fetching jamba from ${JAMBA_DOWNLOAD_URL}")
    FetchContent_Populate(jamba
        QUIET
        URL "${JAMBA_DOWNLOAD_URL}"
        URL_HASH "${JAMBA_DOWNLOAD_URL_HASH}"
        DOWNLOAD_EXTRACT_TIMESTAMP true
        SOURCE_DIR "${CMAKE_BINARY_DIR}/jamba"
        BINARY_DIR "${CMAKE_BINARY_DIR}/jamba-build"
    )
  endif()
endif()

```

and I am simply **not** calling `FetchContent_MakeAvailable`.

Unless I am wrong it is not `FetchContent_Populate` that is deprecated, it is `FetchContent_Populate(<name>)` with a single argument: per the documentation

```plaintext
FetchContent_Populate(<name>)
Changed in version 3.30: This form is deprecated. Policy CMP0169 provides backward compatibility for projects that still need to use this form, but projects should be updated to use FetchContent_MakeAvailable() instead.

```

Can you please confirm? I am not sure why the “workaround” that was suggested was to use a hack when it seems to me that the proper and not hacky way is simply to not use `FetchContent_Declare` and use the other form of `FetchContent_Populate` which is **not** deprecated.

---

<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 1, 2024, 2:42am UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/12 "2024-12-01T02:42:47Z")

</div>

Switching to the multi-argument form of `FetchContent_Populate()` is not the right choice. Using that form in project code is almost always wrong. That multi-argument form exists almost exclusively for use in CMake script mode. Using the multi-argument form in projects still prevents dependency providers from being used, and it bypasses all the logic that allows the developer to use their own local override with CMake variables of the form `FETCHCONTENT_SOURCE_DIR_<uppercaseDepName>`.

The right change is to keep the call to `FetchContent_Declare()`, and replace your call to `FetchContent_Populate(jamba)` with `FetchContent_MakeAvailable(jamba)`. If you want to prevent `FetchContent_MakeAvailable(jamba)` from adding the `jamba` source directory to the build, add a `SOURCE_SUBDIR` argument to your `FetchContent_Declare()` call and set it to a path that does not exist in the `jamba` sources.

You can decide whether you want to still keep the `message()` output, but personally I’d remove it. A good rule of thumb is to only log output if something goes wrong. When you have a lot of output, it trains developers to ignore all output and then they frequently miss things that are actually important. If you follow this advice, your project could be just this:

```cmake
FetchContent_Declare(jamba
      GIT_REPOSITORY ${JAMBA_GIT_REPO}
      GIT_TAG ${JAMBA_GIT_TAG}
      GIT_CONFIG advice.detachedHead=false
      GIT_SHALLOW true
      SOURCE_DIR "${CMAKE_BINARY_DIR}/jamba"
      BINARY_DIR "${CMAKE_BINARY_DIR}/jamba-build"
      SOURCE_SUBDIR pathThatDoesNotExist
)
FetchContent_MakeAvailable(jamba)

```

All the `CONFIGURE_COMMAND`, `BUILD_COMMAND`, `INSTALL_COMMAND` and `TEST_COMMAND` keywords are useless and can be removed. They have no meaning for FetchContent and the values you were setting is what FetchContent enforces internally anyway.

There’s also not much point specifying `BINARY_DIR` if you’re going to prevent `FetchContent_MakeAvailable()` from adding the dependency to the project. The binary directory won’t be used in that case.

---

<div class="post-metadata">

### Author: ![fry](https://discourse.cmake.org/user_avatar/discourse.cmake.org/fry/32/613_2.png) [@fry](https://discourse.cmake.org/u/fry)
#### Post date: [December 1, 2024, 2:09pm UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/13 "2024-12-01T14:09:56Z")

</div>

Craig, thank you for the detailed explanation. I am going to try your suggestion with the invalid `SOURCE_SUBDIR`. That being said, I have a few questions:

- what do you mean by: “_Using the multi-argument form in projects still prevents dependency providers from being used_”?
- when you say, “the logic that allows developer to … `FETCHCONTENT_SOURCE_DIR_<uppercaseDepName>`.” I believe this is what I am offering to the developer: if they specify `JAMBA_ROOT_DIR`, then it does not download it, and simply use the one that is local.

At the end of the day, the logic that I want, is to be able to fetch the content, period. Which is what the module `FetchContent` is supposed to do. I think the `MakeAvailable` part is not what the name `FetchContent` implies, but somehow you have to use `FetchContent_MakeAvailable` in order for the content fetching to happen.

As an analogy, when I “download” something with my browser, I am **not** expecting the browser to “execute” it…

---

<div class="post-metadata">

### Author: ![fry](https://discourse.cmake.org/user_avatar/discourse.cmake.org/fry/32/613_2.png) [@fry](https://discourse.cmake.org/u/fry)
#### Post date: [December 1, 2024, 4:40pm UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/14 "2024-12-01T16:40:49Z")

</div>

I also wanted to add a little bit of background about this project (Jamba).

Jamba is a **framework** not a library. As such you “fetch” it and then you use it. And by using it, you `include` a file. Something like:

```cmake
# Step 1: fetch Jamba (either via GIT TAG or DOWNLOAD URL or use local version)
# => ${JAMBA_ROOT_DIR} now contains the location of the framework

# Step 2: include the framework, which sets up a bunch of variables and cmake functions
include(${JAMBA_ROOT_DIR}/jamba.cmake)

# Step 3: use the framework
jamba_add_vst_plugin(....)

```

I feel like the module `FetchContent` should allow to do what its name suggest: fetching content and stop there. I understand that using `SOURCE_SUBDIR` with an invalid path will do just that when then invoking `FetchContent_MakeAvailable` but this is really twisting things into a pretzel to achieve what should be (and was without warning) possible.

---

<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 1, 2024, 9:26pm UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/15 "2024-12-01T21:26:08Z")

</div>

> [@fry](#):
>
> what do you mean by: “_Using the multi-argument form in projects still prevents dependency providers from being used_”?

`FetchContent_Populate()` has two forms, as you’ve already discovered. The form that takes a single argument (a dependency name) requires an earlier call to `FetchContent_Declare()` to define how to populate that dependency. This one-argument form is what `FetchContent_MakeAvailable()` replaces (and extends with additional capabilities). Dependency providers can intercept calls to `FetchContent_MakeAvailable()` and populate the dependency in whatever way they like, using the information given in `FetchContent_Declare()`, or ignoring that information and choosing to populate it some other way (e.g. the [cmake-conan](https://github.com/conan-io/cmake-conan) dependency provider takes the information from your `conanfile.py` or other equivalent Conan-specific files).

The other form of `FetchContent_Populate()` takes more than one argument. It does not expect or use any information from an earlier call to `FetchContent_Declare()`, it is its own standalone call. It was only ever intended for use by standalone CMake scripts, executed in CMake script mode (i.e. `cmake -P scriptName`). It should not be used in project code. Such calls cannot be intercepted by dependency providers, and this is a pain point for open source projects that ignore this advice and use it anyway. It forces consumers who want to get their dependencies a different way to have to modify that project. Dependency providers give that flexible capability without having to modify projects, but it requires projects to follow the recommended way of doing things.

> [@fry](#):
>
> when you say, “the logic that allows developer to … `FETCHCONTENT_SOURCE_DIR_<uppercaseDepName>`.” I believe this is what I am offering to the developer: if they specify `JAMBA_ROOT_DIR`, then it does not download it, and simply use the one that is local.

Yes, but it is using a different variable to the official one FetchContent provides and that developers would already know how to use. And your implementation reimplements functionality you can already get for free just by using `FetchContent_MakeAvailable()` instead.

> [@fry](#):
>
> At the end of the day, the logic that I want, is to be able to fetch the content, period. Which is what the module `FetchContent` is supposed to do. I think the `MakeAvailable` part is not what the name `FetchContent` implies, but somehow you have to use `FetchContent_MakeAvailable` in order for the content fetching to happen.
> 
> As an analogy, when I “download” something with my browser, I am **not** expecting the browser to “execute” it…

There’s a lot of history here. When FetchContent was first added to CMake, `FetchContent_MakeAvailable()` wasn’t part of the picture. It didn’t take long for folks to complain there were too many calls involved in populating content when following the canonical pattern. `FetchContent_MakeAvailable()` was added to simplify things down to the minimum two calls (`FetchContent_Declare()` being the other call). A few CMake releases later, `FetchContent_MakeAvailable()` was made more flexible by allowing it to download content that had no `CMakeLists.txt` file in their top level. That essentially enhanced the command’s behavior to become “add it to the project if you can, but it’s not an error if you can’t”. Later on, dependency providers were added, and those take advantage of this consolidation by intercepting `FetchContent_MakeAvailable()`. This still allows projects to specify how things should happen if there is no dependency provider (the `FetchContent_Declare()` call defines that).

The name `FetchContent_MakeAvailable()` was chosen carefully. It doesn’t say anything about how the dependency is “made available”. I was thinking forward to likely features that would be added later, and those did end up being added, as described above. The phrase “make available” can mean adding it to the project (the default behavior), or it could mean only downloading it (which is what happens if the content doesn’t have a `CMakeLists.txt` at the top level, or if a `SOURCE_SUBDIR` points it somewhere else that doesn’t exist).

Naming is hard. Sometimes names are constrained by what names are already in use. That has been the case for FetchContent. I can only encourage folks to consider the considerable gain in flexibility for their consumers by adopting `FetchContent_MakeAvailable()`, even if it isn’t the perfect name for your particular use case (there never will be a perfect name for something that covers the broad set of use cases that `FetchContent_MakeAvailable()` does).

---

<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 1, 2024, 9:28pm UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/16 "2024-12-01T21:28:21Z")

</div>

> [@fry](#):
>
> I feel like the module `FetchContent` should allow to do what its name suggest: fetching content and stop there. I understand that using `SOURCE_SUBDIR` with an invalid path will do just that when then invoking `FetchContent_MakeAvailable` but this is really twisting things into a pretzel to achieve what should be (and was without warning) possible.

See the issue I linked in [my earlier comment](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/3). The new keyword proposed there would be pretty clear.

---

<div class="post-metadata">

### Author: ![fry](https://discourse.cmake.org/user_avatar/discourse.cmake.org/fry/32/613_2.png) [@fry](https://discourse.cmake.org/u/fry)
#### Post date: [December 2, 2024, 1:25pm UTC](https://discourse.cmake.org/t/prevent-fetchcontent-makeavailable-to-execute-cmakelists-txt/12704/17 "2024-12-02T13:25:23Z")

</div>

Thank you for providing the very detailed explanation including history.

I have now changed my code to use `FetchContent_Declare` + `SOURCE_SUBDIR` / `FetchContent_MakeAvailable`.

Due to how my framework is being used, I would rather keep the simpler way to customize it from a user point of view even if it means I am re-implementing some of the features that `FetchContent_MakeAvailable` offers (note that my project was created prior to `FetchContent_MakeAvailable` existing so did not have a choice at the time).

As long as this is the official way to achieve what I need (and I do see that it is documented on the website) and it is not a hacky workaround that will be removed in an upcoming release, then I am fine with the changes.
