GithubHelp home page GithubHelp logo

CPM.cmake vs. FetchContent about cpm.cmake HOT 6 CLOSED

cpm-cmake avatar cpm-cmake commented on July 19, 2024 1
CPM.cmake vs. FetchContent

from cpm.cmake.

Comments (6)

TheLartians avatar TheLartians commented on July 19, 2024 5

Hey thanks for asking! This library actually adds a bit of functionality over using "pure" FetchContent.

  • Versioning: if provided explicitly or implicitly, CPM.cmake will compare the version number of all added dependencies and will warn the user if a dependency itself requires a more recent version.
  • Options: any Options passed to a dependency are stored and compared on later use, so if another dependency tries to add an existing dependency with incompatible options a warning will be emitted to the user. The options are set directly before adding a package, so settings from previous packages will be overridden.
  • FETCHCONTENT_BASE_DIR is a completely different option than CPM_SOURCE_CACHE, as it determines the current project's download and build directory for dependencies (also CPM.cmake dependencies). If you use pure FetchContent and set the same FETCHCONTENT_BASE_DIR in multiple projects that have the same dependencies, this may lead to unexpected results or failed builds as the dependencies will share the same source and build directories, regardless of the version or configuration options. Using CPM_SOURCE_CACHE, CPM.cmake will download each version of each dependency into a separate directory, but building them with local configuration and options inside the current build directory.
  • Offline builds: CPM.cmake will override CMake's download and update commands, which allows new builds to be configured while offline if all dependencies are available locally.
  • Shallow clone: If a version tag (e.g. v2.2.0) is provided and CPM_SOURCE_CACHE is used, CPM.cmake will perform a shallow clone of the dependency, which should be significantly faster while using less storage than a full clone.
  • Overridable: all CPMAddPackage can be automatically turned into find_package by setting a CMake flag, making it easy to integrate into projects that may require local versioning through the system pm.
  • Other features include an (opinionated) simpler to use API and the possibility of creating version lock files for easier transitive dependency management.
  • The option to override packages on a per-build basis using CMake CLI parameters.

I hope this answers the questions you had, otherwise feel free to ask more.

from cpm.cmake.

dominiklohmann avatar dominiklohmann commented on July 19, 2024 5

From someone who's been silently watching this repo for a while now (and using it): I think that information should go into the README.

from cpm.cmake.

sacceus avatar sacceus commented on July 19, 2024 1

[...] simpler to use API and the possibility of creating version lock files

Overridable: all CPMAddPackage can be automatically turned into find_package

Very true about simpler API. I have not used version lock yet, but will try it. Overridable CPMAddPackage to turn it into find_package for local files sounds cool.

CPM.cmake will compare the version number of all added dependencies and will warn the user if a dependency itself requires a more recent version.

I am not completely sure what you mean by that wording, but FetchContent does compare the same packages added by multiple different projects. It doesn't warn about the different versions, at least to my knowledge, because it's designed so that the top-most project can or must decide and possibly override the version of package defined at lower level sub-project.

Options: any Options passed to a dependency are stored and compared on later use, so if another dependency tries to add an existing dependency with incompatible options a warning will be emitted to the user.

This indeed sounds very useful. However as talked in previous question, FetchContent will define the package and it's options just once, so I wonder if this is really a feature? At least in some cases, like header libraries, we cannot use same header library with two different versions in the same project.

FETCHCONTENT_BASE_DIR is a completely different option than CPM_SOURCE_CACHE

Not completely different at least on my use case, because I wanted to put all external dependencies to ${CMAKE_PROJECT_DIR}/external as I want to be able to delete same-level build folder completely, and then configure project without need to download and setup the dependencies again. This seems to work for both methods.

This may lead to unexpected results or failed builds as the dependencies will share the same source and build directories, regardless of the version or configuration options.

Having two different projects, whether same level or not, in the same super-build, we can have two different external folders one on each project. However if other project had declared the package earlier, I guess the following project would not re-download and configure the dependency in it's own external folder again. Is this something we want or not, I'm not sure. Interface libraries, like header-only, if declared as INTERFACE library would be passed up to top-most project where conflict would happen in-case two projects would define it. Naming the package dependency differently could solve the problem, ${PROJECT_NAME}${PACKAGE_NAME}.

Using CPM_SOURCE_CACHE, CPM.cmake will download each version of each dependency into a separate directory, but building them with local configuration and options inside the current build directory.

Perhaps not same thing, but variables FETCHCONTENT_SOURCE_DIR_<package> and FETCHCONTENT_BINARY_DIR_<package> can be used to guide where FetchContent (downloads,) looks for and builds dependencies, when set before the calls.

Offline builds: CPM.cmake will override CMake's download and update commands, which allows new builds to be configured while offline if all dependencies are available locally.

Variables FETCHCONTENT_FULLY_DISCONNECTED and FETCHCONTENT_UPDATES_DISCONNECTED(_<PACKAGE>) can be used for... "new builds to be configured while offline if all dependencies are available locally.".

Shallow clone: If a version tag (e.g. v2.2.0) is provided and CPM_SOURCE_CACHE is used, CPM.cmake will perform a shallow clone of the dependency, [...]

As FetchContent accepts same parameters as ExternalProject for GIT, we can use GIT_SHALLOW TRUE to have the same feature. In documentation it says:
https://cmake.org/cmake/help/latest/module/FetchContent.html#id4
"The <contentOptions> can be any of the download or update/patch options that the ExternalProject_Add() command understands. "
https://cmake.org/cmake/help/latest/module/ExternalProject.html
Download Step Options: GIT_SHALLOW <bool>

from cpm.cmake.

sacceus avatar sacceus commented on July 19, 2024 1

Just for an interested reader, I will add a note I found from a earlier mentioned book. The dependency hierarchies are handled with FetchContent on basis of "first setter wins", which means the first project/dependency/external to set requirement for package, will decide the features for it overriding anything that comes after it.

In this example TopProj (current CMakeLists.txt) set dependency Jerry first, before foo and bar, even they also Fetch it internally.

image

from cpm.cmake.

TheLartians avatar TheLartians commented on July 19, 2024

That's a good point! I'll keep this issue up until we've updated the README.

from cpm.cmake.

TheLartians avatar TheLartians commented on July 19, 2024

I am not completely sure what you mean by that wording, but FetchContent does compare the same packages added by multiple different projects. It doesn't warn about the different versions, at least to my knowledge, because it's designed so that the top-most project can or must decide and possibly override the version of package defined at lower level sub-project.

Yeah CPM.cmake functions the same way (it is a wrapper for FetchContent after all). The warning is useful though, as using a dependency in a less recent version can lead to unexpected problems. Note that this can also happen implicitly, as the outdated dependency could have been added by any other dependency in the top-level project.

This indeed sounds very useful. However as talked in previous question, FetchContent will define the package and it's options just once, so I wonder if this is really a feature? At least in some cases, like header libraries, we cannot use same header library with two different versions in the same project.

I'm not sure I understand the question. Ofc the ODR only allows adding a project once, so only one version will be added at any point. If a package has already been added before, CPM.cmake will at least verify that there is no clash in the requested configuration options.

Not completely different at least on my use case, because I wanted to put all external dependencies to ${CMAKE_PROJECT_DIR}/external as I want to be able to delete same-level build folder completely, and then configure project without need to download and setup the dependencies again. This seems to work for both methods.

That does work as long as you always configure and build one project at a time and all dependencies use the same configuration options and dependency versions. Otherwise the shared build and source directories can lead to unexpected issues.

Naming the package dependency differently could solve the problem, ${PROJECT_NAME}${PACKAGE_NAME}.

I still wouldn't recommend it, as you can still have different projects with the same name. Or even different versions of the same project that you might want to build in parallel.

Perhaps not same thing, but variables FETCHCONTENT_SOURCE_DIR_ and FETCHCONTENT_BINARY_DIR_ can be used to guide where FetchContent (downloads,) looks for and builds dependencies, when set before the calls.
Variables FETCHCONTENT_FULLY_DISCONNECTED and FETCHCONTENT_UPDATES_DISCONNECTED(_) can be used for... "new builds to be configured while offline if all dependencies are available locally."
As FetchContent accepts same parameters as ExternalProject for GIT, we can use GIT_SHALLOW TRUE to have the same feature. In documentation it says:

Absolutely, you can get the same behaviour by setting all the configuration options by hand. But at that point you could simply let CPM.cmake do the work for you. That is actually the exact purpose of this project. 😉

from cpm.cmake.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.