Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetch content #446

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open

Fetch content #446

wants to merge 16 commits into from

Conversation

flagarde
Copy link
Contributor

@flagarde flagarde commented Feb 16, 2023

Base on the conversation on #437. This PR is using the "standard" CMake feature with find_apckage etc.. But the CPM.cmake people need to change the version in command project before releasing.

Should be a better solution than #437

This is an example with the new features provided by this PR in action:

cmake_minimum_required(VERSION 3.14)

project(MyWonderfulProject)

find_package(CPM)
if(NOT CPM_FOUND)
include(FetchContent)

FetchContent_Declare(
  CPM
  GIT_REPOSITORY https://github.com/cpm-cmake/CPM.cmake.git
  GIT_TAG        v0.37.0
)
FetchContent_MakeAvailable(CPM)
else()
message(STATUS "I'm using the installed version")
endif()

## CPM automatically included

# add executable
add_executable(main main.cpp)

CPMAddPackage("gh:fmtlib/fmt#7.1.3")
CPMAddPackage("gh:nlohmann/[email protected]")
CPMAddPackage("gh:catchorg/[email protected]")

# link dependencies
target_link_libraries(main fmt::fmt nlohmann_json::nlohmann_json Catch2::Catch2WithMain)

The other feature is that the PR allow CPM to be installed on user system (for example)

git clone https://github.com/cpm-cmake/CPM.cmake.git
cd CPM.cmake
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=CPMInstallPath ..
make install

then user can use previous cmake code and let CMake find CPM in a la CMake way :

cmake -DCPM_ROOT=CPMInstallPath ..

As you can see this PR makes CPM followinf CMake standards for package

@flagarde
Copy link
Contributor Author

Concerning the Style it seems there is a clash with my Clion and the cmake-format file in the repo. The file gets regenerated with the wrong formatting. Maybe a PR with a pre-commit config files would help

Copy link

@LecrisUT LecrisUT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be a good starting point. We would need to prepare some github actions to test for the 3-4 fetch methods

CMakeLists.txt Outdated
LANGUAGES NONE
)

option(CPM_INSTALL "Install CPM" OFF)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the option necessary? Maybe it is to avoid install on ExternalProject, but if that's the case better use the if(CMAKE_PROJECT_NAME ...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about people using CPM just to compile their project, forcing install would be unnecessary. But for a framework it could be interesting to allow the install of CPM

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is not necessary. Cmake only installs if you pass cmake --install .. The only issue that could occur (I neeed to test this), is that calling cmake --install . on a downstream project would install the upstreams as well. But I haven't tested that, and if it's not the case, then we're all safe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is the case, CMake will install all even upstreams

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you really want to supress this option, maybe we could create a custom target only if we detect CPM is not the main repo and consumer could ask explicitly to install it or make it a dependency to one of the consumer's targets

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed I confirm this is the case (need to fix my packages). Check the review later on about what is a sufficient way to circumvent this option.

CMakeLists.txt Outdated
set(CPM_RELEASE FALSE)
endif()
endif()
find_package(CPM CONFIG REQUIRED NO_POLICY_SCOPE)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work? I've never thought you could find_package() itself especially without the CPMConfig files being generated. Did you test it on a clean machine?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CPMConfig is generated but not installed automatically. I think generally maybe it could not work but in our case we just need to include CPM.cmake so it works. It is working because I have provided CPM_DIR to say where to find the generated Config file

I did some test on my computer. It seems to work

Copy link
Contributor Author

@flagarde flagarde Feb 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems you can use an Configfile generated inside the same project and CMake propose :
New in version 3.1: If the INSTALL_PREFIX argument is passed, this is used as base path to calculate all the relative paths. The <path> argument must be an absolute path. If this argument is not passed, the [CMAKE_INSTALL_PREFIX](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html#variable:CMAKE_INSTALL_PREFIX) variable will be used instead. The default value is good when generating a FooConfig.cmake file to use your package from the install tree. When generating a FooConfig.cmake file to use your package from the build tree this option should be used.
but I don't really catch the meaning and how to use it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I see how that works, but this will mark release tarballs as CPM_RELEASE=FALSE.

A more manageable approach is to set CPM_RELEASE=FALSE on main branch. Then to publish a release:

  • Branch main to X.Y.Z branch
  • Rebase a commit that edits set(CPM_RELEASE OFF) -> set(CPM_RELEASE ON)
  • Tag release to this branch

Copy link
Contributor Author

@flagarde flagarde Feb 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To my understanding release tarballs will not have a .git folder inside so the CPM_RELEASE will be unset in this case. I see you point. What you propose would work but this requires CPM maintainers to agree on this behaviour. I tried to stay conservative on the workflows and CI

I think for now this would work :

if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git" AND IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git")
    find_package(Git REQUIRED QUIET)
    # Generate a git-describe version string from Git repository tags.
    execute_process(
      COMMAND ${GIT_EXECUTABLE} tag --points-at HEAD
      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
      OUTPUT_VARIABLE CPM_TAG
      RESULT_VARIABLE GIT_DESCRIBE_ERROR_CODE
      OUTPUT_STRIP_TRAILING_WHITESPACE
    )
    if(NOT GIT_DESCRIBE_ERROR_CODE AND NOT CPM_TAG STREQUAL "")
      set(CPM_RELEASE TRUE)
    else()
      set(CPM_RELEASE FALSE)
    endif()
else()
 set(CPM_RELEASE TRUE)
endif()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, there is also a possibility of the opposite (downloading a tarball for a specific commit), but let's ignore this for now.

I think we should ping the maintainers about the long-term approach, either here or a separate issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know you could do this :) but it seems very a niche scenario, that it is not possible for now with get_cpm anyway.

@LecrisUT
Copy link

Concerning the Style it seems there is a clash with my Clion and the cmake-format file in the repo. The file gets regenerated with the wrong formatting. Maybe a PR with a pre-commit config files would help

Yeah, I prefer CLion's formatting in some parts as well. I've opened an issue about that on cmake-format. The pre-commit file for that would be straightforward but would need the owner to add pre-commit-ci to automatically cmake-format

@flagarde
Copy link
Contributor Author

Concerning the Style it seems there is a clash with my Clion and the cmake-format file in the repo. The file gets regenerated with the wrong formatting. Maybe a PR with a pre-commit config files would help

Yeah, I prefer CLion's formatting in some parts as well. I've opened an issue about that on cmake-format. The pre-commit file for that would be straightforward but would need the owner to add pre-commit-ci to automatically cmake-format

At least having a pre-commit config could simplify the process for developper. It can be easy to forget to run cmake-format. With pre-commit it would be at least automatic on developper computers. pre-commit.ci for the repo would be the best option of course

CMakeLists.txt Outdated
LANGUAGES NONE
)

option(CPM_INSTALL "Install CPM" OFF)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed I confirm this is the case (need to fix my packages). Check the review later on about what is a sufficient way to circumvent this option.

CMakeLists.txt Outdated Show resolved Hide resolved
cmake/CPM.cmake Outdated Show resolved Hide resolved
@flagarde
Copy link
Contributor Author

@LecrisUT Does everything looks fine now?

Copy link

@LecrisUT LecrisUT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to test if it can enter an infinite loop when FetchContent_Declare(OVERIDE_FIND_PACKAGE)

CMakeLists.txt Show resolved Hide resolved
CMakeLists.txt Outdated Show resolved Hide resolved
@flagarde
Copy link
Contributor Author

I don't know how to test this case

@LecrisUT
Copy link

LecrisUT commented Feb 16, 2023

lgtm

Here's a snippet you can run:

cmake_minimum_required(VERSION 3.24)
project(TestCPMFetchContent)

include(FetchContent)
FetchContent_Declare(CPM
		GIT_REPOSITORY https://github.com/flagarde/CPM.cmake
		GIT_TAG FetchContent
		OVERRIDE_FIND_PACKAGE)
find_package(CPM)

@LecrisUT
Copy link

Hmm my tests on this do not succeed yet. I've added a message(WARNING) inside CPMConfig.cmake.in and it did not print out

CMakeLists.txt Outdated
else()
set(CPM_RELEASE TRUE)
endif()
find_package(CPM CONFIG REQUIRED NO_POLICY_SCOPE)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are over-complicating it here. This works just fine

Suggested change
find_package(CPM CONFIG REQUIRED NO_POLICY_SCOPE)
include(cmake/CPM.cmake)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I found a small bug with how we are looking for the .git I can change this and your changes.

I tested using :

 
cmake_minimum_required(VERSION 3.24)
project(TestCPMFetchContent)

include(FetchContent)
FetchContent_Declare(CPM
		GIT_REPOSITORY https://github.com/flagarde/CPM.cmake
		GIT_TAG FetchContent
		OVERRIDE_FIND_PACKAGE)


FetchContent_MakeAvailable(CPM)
find_package(CPM)
# the install option has to be explicitly set to allow installation
CPMAddPackage(
  GITHUB_REPOSITORY jarro2783/cxxopts
  VERSION 2.2.1
  OPTIONS "CXXOPTS_BUILD_EXAMPLES NO" "CXXOPTS_BUILD_TESTS NO" "CXXOPTS_ENABLE_INSTALL YES"
)

In this case not loop but a crash :

CMake Error at CMakeLists.txt:15 (CPMAddPackage):
  Unknown CMake command "CPMAddPackage".


-- Configuring incomplete, errors occurred!

without OVERRIDE_FIND_PACKAGE :

-- The C compiler identification is GNU 12.2.1
-- The CXX compiler identification is GNU 12.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
fatal : ni ceci ni aucun de ses répertoires parents (jusqu'au point de montage /) n'est un dépôt git
Arrêt à la limite du système de fichiers (GIT_DISCOVERY_ACROSS_FILESYSTEM n'est pas défini).
CMake Warning at CMakeLists.txt:12 (find_package):
  By not providing "FindCPM.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "CPM", but
  CMake did not find one.

  Could not find a package configuration file provided by "CPM" with any of
  the following names:

    CPMConfig.cmake
    cpm-config.cmake

  Add the installation prefix of "CPM" to CMAKE_PREFIX_PATH or set "CPM_DIR"
  to a directory containing one of the above files.  If "CPM" provides a
  separate development package or SDK, be sure it has been installed.


-- CPM: Adding package [email protected] (v2.2.1)
-- cxxopts version 2.2.0
-- Configuring done
-- Generating done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now it seems to work :)

Please have a try too.. just in case

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good now. For an initial integration I'm 👍 on this.

CMakeLists.txt Outdated
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/CPM.cmake" "${CMAKE_CURRENT_BINARY_DIR}/CPM.cmake" COPYONLY
)
set(CPM_DIR "${CMAKE_CURRENT_BINARY_DIR}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really necessary. In my tests, these are not set upstream. I don't understand how but:

  • CPM_DIR (set in this file) and CURRENT_CPM_VERSION (set in the include(cmake/CPM.cmake)) do not propagate upstream
  • But we can still use the macro/functions defined in cmake/CPM.cmake

LecrisUT
LecrisUT previously approved these changes Feb 16, 2023
@flagarde
Copy link
Contributor Author

cmake_minimum_required(VERSION 3.24)
project(TestCPMFetchContent)

include(FetchContent)
FetchContent_Declare(CPM
		GIT_REPOSITORY https://github.com/flagarde/CPM.cmake
		GIT_TAG FetchContent
		)


FetchContent_MakeAvailable(CPM)
find_package(CPM)
# the install option has to be explicitly set to allow installation
CPMAddPackage(
  GITHUB_REPOSITORY jarro2783/cxxopts
  VERSION 2.2.1
  OPTIONS "CXXOPTS_BUILD_EXAMPLES NO" "CXXOPTS_BUILD_TESTS NO" "CXXOPTS_ENABLE_INSTALL YES"
)

this one create a warning but still working

@LecrisUT
Copy link

Of course, but that's the intended behaviour 😄 The warning I get there is:

CMake Warning at cmake-build-debug/_deps/cpm-src/cmake/CPM.cmake:80 (message):
  CPM: Your project is using an unstable development version of CPM.cmake.
  Please update to a recent release if possible.  See
  https://github.com/cpm-cmake/CPM.cmake for details.

Which is ok because it is not a tagged version :)

This one won't show the error even though it is not a release ;)

FetchContent_Declare(CPM
		URL https://github.com/flagarde/CPM.cmake/archive/refs/heads/FetchContent.zip
		OVERRIDE_FIND_PACKAGE)

@flagarde
Copy link
Contributor Author

flagarde commented Feb 16, 2023

Of course, but that's the intended behaviour smile The warning I get there is:

CMake Warning at cmake-build-debug/_deps/cpm-src/cmake/CPM.cmake:80 (message):
  CPM: Your project is using an unstable development version of CPM.cmake.
  Please update to a recent release if possible.  See
  https://github.com/cpm-cmake/CPM.cmake for details.

Which is ok because it is not a tagged version :)

This one won't show the error even though it is not a release ;)

FetchContent_Declare(CPM
		URL https://github.com/flagarde/CPM.cmake/archive/refs/heads/FetchContent.zip
		OVERRIDE_FIND_PACKAGE)

I'm talking about this warning :

CMake Warning at CMakeLists.txt:13 (find_package):
  By not providing "FindCPM.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "CPM", but
  CMake did not find one.

  Could not find a package configuration file provided by "CPM" with any of
  the following names:

    CPMConfig.cmake
    cpm-config.cmake

  Add the installation prefix of "CPM" to CMAKE_PREFIX_PATH or set "CPM_DIR"
  to a directory containing one of the above files.  If "CPM" provides a
  separate development package or SDK, be sure it has been installed.

I tested we need
PARENT_SCOPE for the variable and it works. We can try with PARENT_SCOPE and move to a CACHE variable if necessary

@LecrisUT
Copy link

cmake_minimum_required(VERSION 3.24)
project(TestCPMFetchContent)

include(FetchContent)
FetchContent_Declare(CPM
		GIT_REPOSITORY https://github.com/flagarde/CPM.cmake
		GIT_TAG FetchContent
		)


FetchContent_MakeAvailable(CPM)
find_package(CPM)
# the install option has to be explicitly set to allow installation
CPMAddPackage(
  GITHUB_REPOSITORY jarro2783/cxxopts
  VERSION 2.2.1
  OPTIONS "CXXOPTS_BUILD_EXAMPLES NO" "CXXOPTS_BUILD_TESTS NO" "CXXOPTS_ENABLE_INSTALL YES"
)

this one create a warning but still working

You have an error there. Without OVERRIDE_FIND_PACKAGE you must not use find_package, only FetchContent_MakeAvailable. These two are mutually exclusive!

CPM_VERSION and everything is handled by FetchContent_MakeAvailable

@flagarde
Copy link
Contributor Author

flagarde commented Mar 2, 2023

@LecrisUT @TheLartians @CraigHutchinson
I made some changes based on your comment. The only difficult part that has not been solved is the use of version number in project because this is required to generate the configVersion file.

you can try it with this example :

 
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(MyProject)


find_package(CPM.cmake QUIET)

if(NOT CPM.cmake_FOUND)
message(STATUS "Fetching CPM")
include(FetchContent)
FetchContent_Declare(
        CPM.cmake
        GIT_REPOSITORY https://github.com/flagarde/CPM.cmake.git
        GIT_TAG        FetchContent
)
FetchContent_MakeAvailable(CPM.cmake)
endif()

find_package(CPM.cmake REQUIRED)

CPMAddPackage("gh:fmtlib/fmt#7.1.3")

@LecrisUT
Copy link

LecrisUT commented Mar 2, 2023

Weird, I didn't get any notifications on this the whole week. Thanks for pinning me. Let me catch up to the conversation.

@flagarde
Copy link
Contributor Author

flagarde commented Mar 2, 2023

@LecrisUT It happened to me from time to time, I don't know why.

@TheLartians Concerning your qustion on the possibility to run a project offline when all has been previously loaded. I did a test with the example provided on my last comment. When all has been fetched, you can be offline and all is fine :)

@LecrisUT
Copy link

LecrisUT commented Mar 2, 2023

Additional note - needs discussion: CPM is officially CPM.cmake on GitHub. Therefore I note in private code I have used find_package(CPM.cmake) along with corresponding FindCPM.cmake.cmake. i.e. I'd prefer consistency with the package-name on Github in the end-user-code. Albeit there is something not so nice in just the filename!

My vote is against this, it becomes very confusing for the user, and it is not guaranteed to be supported on cmake side in the long run, e.g. when they implement automatic namespacing. It is perfectly fine for the repo name and project name to have different case sensitivity and so on, since that is only present in FetchContent, not in find_package.

Part of the idea to using cpm.cmake to match the repository is to eventually implement support via the Dependency-Provider mechanism in CMake 3.26 so I am trying to make sure any find_package calls are using the technically correct name.

For this case you have NAMES in find_package, especially since other package managers can use different names (vcpkg, conan, etc.). We should just normalize this standard.

# For consumer using FetchContent
if(NOT ${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME})
# Check if the user download the repo with git and not in an official release
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git" AND IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git")
Copy link

@LecrisUT LecrisUT Mar 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've recently found out about this approach:
.gitattributes and .git_archival.txt (this name is arbitrary).

Basically whenever Github creates the tar ball, it will change the content of .git_archival.txt with appropriate values. E.g.:

Let's go with this approach. We don't need to worry about the versions before this, because you can't use ExternalProject on those versions. Here's a list of the placeholders.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To test locally, use:

$ git archive --format=tar HEAD --output=test.tar.gz

Copy link

@LecrisUT LecrisUT Mar 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TheLartians As an alternative to hard-coded version numbering, would you agree to such approach, i.e.:

  • Read .git_archival.txt before project()
  • Reformat the version to be cmake compliant
  • Use this variable as the version number

I have never tried this in a project, but could be very elegant if it can be implemented. Things to confirm:

  • cmake accepts this format
  • CPM_MAJOR_VERSION and so on are extractable
  • The commit is included in the version and can be retrieved
  • It works on patch version branches, i.e. on v0.38 branch after pushing tag v0.38.1 it continues to be v0.38.1-1-short_hash, while on main it carries on with v0.38.0-1-short_hash and so on
  • Backup method for local development?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relevant PR here. For now this approach works because we don't actually build anything. Basically all of this is now compressed to

# Check if there is anything after the allowed format of `vX.Y.Z`, e.g. `vX.Y.Z-rc1`, `vX.Y.Z-9-gc449f6`, etc.
if (GIT_DESCRIBE MATCH "[v]?[0-9\\.]*.+")
  set(CPM_RELEASE FALSE)
else ()
  set(CPM_RELEASE TRUE)
endif ()

Copy link
Contributor

@CraigHutchinson CraigHutchinson Mar 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may, or may not be useful, i use this for versioning all my builds. Interested to add support for archival as this is new to knowledge to me but I parse the git-describe here. Note the use of EXPR was something I found useful to make it easy to handle all the variants. https://github.com/BareCpper/Version.cmake/blob/38de0dfb1686cfcc0578414587f06e6bcd7415c1/CMake/Version.cmake#L42

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, the regex is wrong because it is not maximally greedy.

That link is overkill though because the major.minor.patch.tweak format is already handled by the project(VERSION) section and the strip from ^([v]?([0-9\\.]+).*) over here, and we only care about if there are additional suffixes like -rc1 of any form. After some thought I think we can simplify it as ^[v]?[0-9\\.]*$ with inverted logic

if(DEFINED CPM_VERSION AND CPM_RELEASE)
set(CURRENT_CPM_VERSION "${CPM_VERSION}${CPM_DEVELOPMENT}")
else()
set(CURRENT_CPM_VERSION 1.0.0-development-version)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the .git_archival.txt we have more details on commit version. Should use that information.

@TheLartians
Copy link
Member

TheLartians commented Mar 5, 2023

@TheLartians Concerning your qustion on the possibility to run a project offline when all has been previously loaded. I did a test with the example provided on my last comment. When all has been fetched, you can be offline and all is fine :)

Sure, it's possible to update an existing configuration, but you won't be able to configure from scratch.

This is possible with get_cpm.cmake or equivalent as long as CPM_SOURCE_CACHE is set:

# initial configure when online
> cmake -S . -B build1 
[successful configure]
# we can now create arbitrary configurations when offline as CPM is cached
> cmake -S . -B build2
[successful configure]

Using the FetchContent approach above, the same attempt results in an error:

# initial configure when online
> cmake -S . -B build1 
[successful configure]
# any attempt to do a new configure when offline will result in an error 
> cmake -S . -B build2

CMake Error at cpm.cmake-subbuild/cpm.cmake-populate-prefix/tmp/cpm.cmake-populate-gitclone.cmake:39 (message):
  Failed to clone repository: 'https://github.com/flagarde/CPM.cmake.git'


make[2]: *** [cpm.cmake-populate-prefix/src/cpm.cmake-populate-stamp/cpm.cmake-populate-download] Error 1
make[1]: *** [CMakeFiles/cpm.cmake-populate.dir/all] Error 2
make: *** [all] Error 2

CMake Error at /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1616 (message):
  Build step for cpm.cmake failed: 2
Call Stack (most recent call first):
  /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1756:EVAL:2 (__FetchContent_directPopulate)
  /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1756 (cmake_language)
  /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1970 (FetchContent_Populate)
  CMakeLists.txt:15 (FetchContent_MakeAvailable)


-- Configuring incomplete, errors occurred!

For me this is actually a pretty common use-case, e.g. for multi platform builds, when debugging CMake scripts or when working in air gapped environments, which is why I prefer to avoid any regression here.

@LecrisUT
Copy link

LecrisUT commented Mar 5, 2023

If you point it to the same download location, i.e. FETCHCONTENT_SOURCE_DIR_CPM, you can do it offline. But this should be up to the downstream to configure to how they want it.

@flagarde
Copy link
Contributor Author

flagarde commented Mar 5, 2023

@TheLartians Concerning your qustion on the possibility to run a project offline when all has been previously loaded. I did a test with the example provided on my last comment. When all has been fetched, you can be offline and all is fine :)

Sure, it's possible to update an existing configuration, but you won't be able to configure from scratch.

This is possible with get_cpm.cmake or equivalent as long as CPM_SOURCE_CACHE is set:

# initial configure when online
> cmake -S . -B build1 
[successful configure]
# we can now create arbitrary configurations when offline as CPM is cached
> cmake -S . -B build2
[successful configure]

Using the FetchContent approach above, the same attempt results in an error:

# initial configure when online
> cmake -S . -B build1 
[successful configure]
# any attempt to do a new configure when offline will result in an error 
> cmake -S . -B build2

CMake Error at cpm.cmake-subbuild/cpm.cmake-populate-prefix/tmp/cpm.cmake-populate-gitclone.cmake:39 (message):
  Failed to clone repository: 'https://github.com/flagarde/CPM.cmake.git'


make[2]: *** [cpm.cmake-populate-prefix/src/cpm.cmake-populate-stamp/cpm.cmake-populate-download] Error 1
make[1]: *** [CMakeFiles/cpm.cmake-populate.dir/all] Error 2
make: *** [all] Error 2

CMake Error at /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1616 (message):
  Build step for cpm.cmake failed: 2
Call Stack (most recent call first):
  /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1756:EVAL:2 (__FetchContent_directPopulate)
  /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1756 (cmake_language)
  /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1970 (FetchContent_Populate)
  CMakeLists.txt:15 (FetchContent_MakeAvailable)


-- Configuring incomplete, errors occurred!

For me this is actually a pretty common use-case, e.g. for multi platform builds, when debugging CMake scripts or when working in air gapped environments, which is why I prefer to avoid any regression here.

You could use CPM.cmake_ROOT to give to the second condiguration the path to the cpm inside the first one. Note that you could install cpm by itself on some folder (it would be an equivalent of CPM_SOURCE_CACHE

@flagarde
Copy link
Contributor Author

flagarde commented Mar 5, 2023

@TheLartians Concerning your qustion on the possibility to run a project offline when all has been previously loaded. I did a test with the example provided on my last comment. When all has been fetched, you can be offline and all is fine :)

Sure, it's possible to update an existing configuration, but you won't be able to configure from scratch.

This is possible with get_cpm.cmake or equivalent as long as CPM_SOURCE_CACHE is set:

# initial configure when online
> cmake -S . -B build1 
[successful configure]
# we can now create arbitrary configurations when offline as CPM is cached
> cmake -S . -B build2
[successful configure]

Using the FetchContent approach above, the same attempt results in an error:

# initial configure when online
> cmake -S . -B build1 
[successful configure]
# any attempt to do a new configure when offline will result in an error 
> cmake -S . -B build2

CMake Error at cpm.cmake-subbuild/cpm.cmake-populate-prefix/tmp/cpm.cmake-populate-gitclone.cmake:39 (message):
  Failed to clone repository: 'https://github.com/flagarde/CPM.cmake.git'


make[2]: *** [cpm.cmake-populate-prefix/src/cpm.cmake-populate-stamp/cpm.cmake-populate-download] Error 1
make[1]: *** [CMakeFiles/cpm.cmake-populate.dir/all] Error 2
make: *** [all] Error 2

CMake Error at /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1616 (message):
  Build step for cpm.cmake failed: 2
Call Stack (most recent call first):
  /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1756:EVAL:2 (__FetchContent_directPopulate)
  /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1756 (cmake_language)
  /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1970 (FetchContent_Populate)
  CMakeLists.txt:15 (FetchContent_MakeAvailable)


-- Configuring incomplete, errors occurred!

For me this is actually a pretty common use-case, e.g. for multi platform builds, when debugging CMake scripts or when working in air gapped environments, which is why I prefer to avoid any regression here.

We could cache the CPM.cmake_DIR to allow find_package to find it

@flagarde
Copy link
Contributor Author

flagarde commented Mar 6, 2023

@TheLartians Concerning your qustion on the possibility to run a project offline when all has been previously loaded. I did a test with the example provided on my last comment. When all has been fetched, you can be offline and all is fine :)

Sure, it's possible to update an existing configuration, but you won't be able to configure from scratch.

This is possible with get_cpm.cmake or equivalent as long as CPM_SOURCE_CACHE is set:

# initial configure when online
> cmake -S . -B build1 
[successful configure]
# we can now create arbitrary configurations when offline as CPM is cached
> cmake -S . -B build2
[successful configure]

Using the FetchContent approach above, the same attempt results in an error:

# initial configure when online
> cmake -S . -B build1 
[successful configure]
# any attempt to do a new configure when offline will result in an error 
> cmake -S . -B build2

CMake Error at cpm.cmake-subbuild/cpm.cmake-populate-prefix/tmp/cpm.cmake-populate-gitclone.cmake:39 (message):
  Failed to clone repository: 'https://github.com/flagarde/CPM.cmake.git'


make[2]: *** [cpm.cmake-populate-prefix/src/cpm.cmake-populate-stamp/cpm.cmake-populate-download] Error 1
make[1]: *** [CMakeFiles/cpm.cmake-populate.dir/all] Error 2
make: *** [all] Error 2

CMake Error at /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1616 (message):
  Build step for cpm.cmake failed: 2
Call Stack (most recent call first):
  /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1756:EVAL:2 (__FetchContent_directPopulate)
  /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1756 (cmake_language)
  /opt/homebrew/Cellar/cmake/3.25.1/share/cmake/Modules/FetchContent.cmake:1970 (FetchContent_Populate)
  CMakeLists.txt:15 (FetchContent_MakeAvailable)


-- Configuring incomplete, errors occurred!

For me this is actually a pretty common use-case, e.g. for multi platform builds, when debugging CMake scripts or when working in air gapped environments, which is why I prefer to avoid any regression here.

I would not say it's a regression as this way to obtain CPM is new, if possible it should be nice to fix this differences but each metthod have pros and cons

@flagarde
Copy link
Contributor Author

flagarde commented Mar 8, 2023

@TheLartians Would it be ok for you if I add the possibility to Fetched CPM to understand CPM_SOURCE_CACHE but I think you should say to user the CMake Alternative mentionned by @LecrisUT is preferred FETCHCONTENT_SOURCE_DIR_CPM,?

@flagarde
Copy link
Contributor Author

flagarde commented Mar 10, 2023

Let me summarize the points we need to fix for this PR :

  • Automatic versionning (@LecrisUT has done 99% of the work)
  • Change package name form CPM to CPM.cmake (need some agreement from CPM developpers)
  • Use CPM_SOURCE_CACHE to store CPM in a specific path, while there is 2 alternative :
    1. Install CPM as a system package and use ROOT_CPM.cmake
    1. Use FETCHCONTENT_SOURCE_DIR_CPM

Do I forget something @LecrisUT @TheLartians @CraigHutchinson

@LecrisUT
Copy link

  • Change package name form CPM to CPM.cmake (need some agreement from CPM developpers)

On my side, I would push against naming the project CPM.cmake. I would not trust that there are no tools out there that have hard-coded assumptions that a cmake project is alpha-numeric only. Maybe for packagers, maybe for passing -DCPM.CMAKE_NEW_OPTION (e.g. scikit-build-core allows for this --config-settings=cmake.define.SOME_OPTION=ON, which in this case will translate to --config-settings=cmake.define.CPM.CMAKE_NEW_OPTION=ON (with an extra .)).

I think this is a risky approach and I would request more thorough discussion on this. @TheLartians @CraigHutchinson, can we discuss the points for and against this approach? The only one that I understood was related to find_package, but there we can specify NAMES for this specific purpose (I remember reading a specific example related to vcpkg and using NAMES for that purpose, but I can't locate it now, sorry).

@flagarde
Copy link
Contributor Author

flagarde commented Mar 10, 2023

  • Change package name form CPM to CPM.cmake (need some agreement from CPM developpers)

On my side, I would push against naming the project CPM.cmake. I would not trust that there are no tools out there that have hard-coded assumptions that a cmake project is alpha-numeric only. Maybe for packagers, maybe for passing -DCPM.CMAKE_NEW_OPTION (e.g. scikit-build-core allows for this --config-settings=cmake.define.SOME_OPTION=ON, which in this case will translate to --config-settings=cmake.define.CPM.CMAKE_NEW_OPTION=ON (with an extra .)).

I think this is a risky approach and I would request more thorough discussion on this. @TheLartians @CraigHutchinson, can we discuss the points for and against this approach? The only one that I understood was related to find_package, but there we can specify NAMES for this specific purpose (I remember reading a specific example related to vcpkg and using NAMES for that purpose, but I can't locate it now, sorry).

I agree with you, but I have not infos on this but I would say it could be very risky too and this is just a convention name for find_package. CPM looks as fine as CPM.cmake to me but CPM are safer concerning the potential problems we can trigger

@vasil-pashov
Copy link

Hello, @flagarde @LecrisUT is there any progress on this? I think it's a great feature but the PR seems stale. Is there any hope?

@LecrisUT
Copy link

Hello, @flagarde @LecrisUT is there any progress on this? I think it's a great feature but the PR seems stale. Is there any hope?

On my side it's only the decision of using . in the project's namespace that I am concerned about, but the other reviewers haven't responded to that.

Other than that, for an initial PR, I think its fine in this state.

@TheLartians
Copy link
Member

For me the hardcoding of the version is still a red flag as it would complicate the release pipeline and at some point I'll likely forget to update the version in the CMakeLists and the version specified in the CMakeLists would be out-of-sync with the project. Is the version specifier really required and no way to automate it on releases?

@flagarde
Copy link
Contributor Author

@TheLartians, @LecrisUT has found a nice way to avoid the hardcoded version. It can be done automatically by git using .git_archival.txt and gitattributes magics. Maybe we coiuld split the PR and try to push this mechanism first ?

@LecrisUT
Copy link

@flagarde Quick comment, remove the ref-names from there. I have later found out it can drastically impact git archive checksum and downstream. I.e. use the .git_archival.txt as:

node: $Format:%H$
node-date: $Format:%cI$
describe-name: $Format:%(describe:tags=true,match=?[0-9.]*)$

@flagarde
Copy link
Contributor Author

@LecrisUT You mean archives would not be reproductible anymore?

@LecrisUT
Copy link

With the file in the comment it will. Some more reading is at: pypa/setuptools-scm#1033

Basically ref-names at release points also to master, but as soon as a new commit is added the git archive no longer points to master so the checksum changes. That's why the recommendation is to delete that line. Everything else would be fine as long as a new tag is not added on the same git commit.

@TheLartians
Copy link
Member

@TheLartians, @LecrisUT has found a nice way to avoid the hardcoded version. It can be done automatically by git using .git_archival.txt and gitattributes magics. Maybe we coiuld split the PR and try to push this mechanism first ?

That's super interesting, I've never heard of this before and even googling hardly shows any information besides the setuptools repo. I do see how it can get the job done, even though it feels a bit dodgy tbh. Is this feature documented somewhere?

@LecrisUT
Copy link

Is this feature documented somewhere?

https://github.com/LecrisUT/CMakeExtraUtils/blob/main/cmake/DynamicVersion.cmake

See also the repo containing it

@flagarde
Copy link
Contributor Author

flagarde commented Apr 22, 2024

@TheLartians I have never seen this before but it seems nice feature

@flagarde flagarde mentioned this pull request Aug 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants