# FetchContent or ExternalProject or other choices for non-CMake libraries

**URL:** <https://discourse.cmake.org/t/fetchcontent-or-externalproject-or-other-choices-for-non-cmake-libraries/7687>\
**Category:** Usage\
**Tags:** os:linux\
**Created:** [March 16, 2023, 1:00am UTC](https://discourse.cmake.org/t/fetchcontent-or-externalproject-or-other-choices-for-non-cmake-libraries/7687 "2023-03-16T01:00:56Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![magisu](https://discourse.cmake.org/user_avatar/discourse.cmake.org/magisu/32/3260_2.png) [@magisu](https://discourse.cmake.org/u/magisu)\
**Post date:** [March 16, 2023, 1:00am UTC](https://discourse.cmake.org/t/fetchcontent-or-externalproject-or-other-choices-for-non-cmake-libraries/7687/1 "2023-03-16T01:00:56Z")

</div>

Since CMake 3.24 it seems possible to implement the following feature within the CMake framework:

- First, look for a local pre-compiled library in the system or a specific position using CMake `find_package` tool.
- If it is unavailable, download the library from a specific position, e.g. github or some other repositories, build it, and provide the target.

This looks fantastic, yet when I am trying to import some non-CMake libraries, e.g. jemalloc, I notice that the FetchContent will properly download the code in the config part and ignore the CONFIGURE\_COMMAND, BUILD\_COMMAND and INSTALL\_COMMAND. They are also expected. Now here is the hard part:

- `find_package` will not find jemalloc in a clean docker environment.
- Then, `FetchContent` will be triggered and download the code
- Yet, `FetchContent_MakeAvailable` will only populate the directories, not targets.
- I still need something, maybe `ExternalProject` or `execute_process`, to build the code.
- It seems vcpkg, conan or other package managers cannot be introduced to our CMake system for reasons I do not know.

Our situation looks like this:

- Internally, we build the code in a Docker environment for various reasons. Inside the environment, every library must be pre-built. CMake should use `find_package` to locate the corresponding targets.
- For people outside our company, in convenience CMake should download the libraries if they are not found or not the correct version. The libraries include jemalloc, boost, and others that are not CMake-ready.

I am wondering about the right approach for this situation; maybe `FetchContent` first and then `ExternalProject_Add`? I have other thoughts, e.g. use `add_custom_command` after `FetchContent_MakeAvailable`.

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [March 16, 2023, 6:42pm UTC](https://discourse.cmake.org/t/fetchcontent-or-externalproject-or-other-choices-for-non-cmake-libraries/7687/2 "2023-03-16T18:42:03Z")

</div>

@craig.scott

---

<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:** [March 17, 2023, 1:08am UTC](https://discourse.cmake.org/t/fetchcontent-or-externalproject-or-other-choices-for-non-cmake-libraries/7687/4 "2023-03-17T01:08:31Z")

</div>

> [@magisu](#):
>
> yet when I am trying to import some non-CMake libraries, e.g. jemalloc, I notice that the FetchContent will properly download the code in the config part and ignore the CONFIGURE\_COMMAND, BUILD\_COMMAND and INSTALL\_COMMAND. They are also expected.

No, the `CONFIGURE_COMMAND`, `BUILD_COMMAND`, etc. are explicitly documented as not supported by FetchContent. It discards any such options and forces them to be empty strings. An explicit goal of FetchContent is to avoid building at configure time. You’re incorrectly expecting FetchContent to have all the capabilities of ExternalProject, but they have different goals and are aimed at different use cases. FetchContent can only add CMake-based projects directly to the main project. If you use it with a non-CMake dependency, all FetchContent can do for you in that case is download the sources, but not add it to your main project’s build, which is what you’ve observed. A non-CMake dependency can really only be added using ExternalProject.

Based on your scenario, it sounds like your internal Docker environment builds are fine, but builds by people outside your company are where you’re hitting problems. For those, I’d advise don’t try to do too much and leave those users to decide which approach for providing the dependencies works best for them. Just have the `find_package()` calls in your project. Let the end user decide how those should be satisfied. They might choose to use a package manager, or they might pre-build them and make them available by modifying `CMAKE_PREFIX_PATH`. Or they might implement their own wrapper to build them with scripts. Or… whatever other esoteric approach works for them. For dependencies that _do_ build with CMake, there’s nothing wrong with your project calling `FetchContent_Declare()` with the `FIND_PACKAGE_ARGS` keyword and calling `FetchContent_MakeAvailable()`. That still leaves all options open for your non-internal users to provide the dependency using their preferred method. For the non-CMake dependencies though, I don’t think FetchContent is what you should be using in this situation.

---

<div class="post-metadata">

**Author:** ![magisu](https://discourse.cmake.org/user_avatar/discourse.cmake.org/magisu/32/3260_2.png) [@magisu](https://discourse.cmake.org/u/magisu)\
**Post date:** [March 17, 2023, 3:55am UTC](https://discourse.cmake.org/t/fetchcontent-or-externalproject-or-other-choices-for-non-cmake-libraries/7687/5 "2023-03-17T03:55:10Z")

</div>

Thanks for your suggestion! Leaving the external library issue to other people might be a good solution. Yet my problem is that we do have many libraries already configured using `ExternalProject_add` and I will face a lot of complaints if those libraries are not “automatically” downloaded. Do you think in this case it is possible to combine `find_package` with `ExternalProject_add`? If not, may I know what might be the alternative approach?

---

<div class="post-metadata">

**Author:** ![Lecris](https://discourse.cmake.org/user_avatar/discourse.cmake.org/lecris/32/3193_2.png) [@Lecris](https://discourse.cmake.org/u/Lecris)\
**Post date:** [March 17, 2023, 7:58pm UTC](https://discourse.cmake.org/t/fetchcontent-or-externalproject-or-other-choices-for-non-cmake-libraries/7687/6 "2023-03-17T19:58:59Z")

</div>

How about embedding it in a `FindPackage.cmake`?

---

<div class="post-metadata">

**Author:** ![magisu](https://discourse.cmake.org/user_avatar/discourse.cmake.org/magisu/32/3260_2.png) [@magisu](https://discourse.cmake.org/u/magisu)\
**Post date:** [March 17, 2023, 10:06pm UTC](https://discourse.cmake.org/t/fetchcontent-or-externalproject-or-other-choices-for-non-cmake-libraries/7687/7 "2023-03-17T22:06:56Z")

</div>

I did think about this, but the problem lies here:

1. CMake community encourages jemallocConfig.cmake.in and not accepting new Findjemalloc.cmake into its standard modules. I interpret this as “we should avoid Findxxxx” as much as possible.
2. To some extent, I feel the `Find`er should not be a “builder”.

Besides the issues above,

1. To my understanding, `Findxxx` works on the configuration time, implying the external project has to be built during that time. I suppose this might not be favored.

---

<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:** [March 17, 2023, 11:13pm UTC](https://discourse.cmake.org/t/fetchcontent-or-externalproject-or-other-choices-for-non-cmake-libraries/7687/8 "2023-03-17T23:13:26Z")

</div>

The main problem you will have with trying to combine `find_package()` and `ExternalProject` is that `find_package()` provides details at configure time, but `ExternalProject` only provides them at build time. You’ll end up having to manually define all the targets and the underlying files they correspond to, along with all compiler flags, header search paths, etc. Basically all the usual disadvantages of ExternalProject when used in anything other than a pure superbuild arrangement.

---

<div class="post-metadata">

**Author:** ![Lecris](https://discourse.cmake.org/user_avatar/discourse.cmake.org/lecris/32/3193_2.png) [@Lecris](https://discourse.cmake.org/u/Lecris)\
**Post date:** [March 17, 2023, 11:24pm UTC](https://discourse.cmake.org/t/fetchcontent-or-externalproject-or-other-choices-for-non-cmake-libraries/7687/9 "2023-03-17T23:24:05Z")

</div>

Wouldn’t this be on the project level rather than to be built into the standards? For cmake projects we should strive for config ones, but some projects are dead set on not supporting cmake. I don’t see a good way to incorporate with those other than `FindPackage.cmake`. For non-cmake projects I think it makes sense to combine them there.

Also because FindPackage.cmake is generally unregulated, I think it is on equal footing with FetchContent and ExternalProject wince for those you also should define the compilation options.
