cpm-cmake / CPM.cmake

📦 CMake's missing package manager. A small CMake script for setup-free, cross-platform, reproducible dependency management.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Bug: GIT_SUBMODULES_RECURSE and GIT_SUBMODULES are ignored

ethindp opened this issue · comments

I have a CMake project that has private submodules. The project's CMake configuration process will acquire the public submodules that I need. Therefore, I've used the following git-related options:

    GIT_SUBMODULES ""
    GIT_SUBMODULES_RECURSE FALSE

According to the CMake documentation, with this set, FetchContent_Declare (and, by extension, ExternalProject_Add) will not clone submodules, as long as CMP0096 is set to NEW. So I did that at the top of my project:

cmake_policy(VERSION 3.25)
cmake_policy(SET CMP0096 NEW)

However, the arguments I set in CPMAddPackage (GIT_SUBMODULES and GIT_SUBMODULES_RECURSE) are ignored, and all submodules are cloned anyway. Is this a bug in CPM? Logically this should work perfectly fine, but it isn't for some reason.

Okay, so it looks like CPMAddPackage doesn't actually take all possible content options. CPM should probably be updated to take into account all options that ExternalProject/FetchContent accepts.

CPM should already forward all additional arguments to FetchContent_Declare, so hard to say what's not working here. Can you confirm that CMake behaves as intended using the same arguments passed directly to FetchContent?

@TheLartians Yes, can confirm. When I replace the CPMAddPackage line with FetchContent_Declare, it works fine. I do have to set CMP0096 to NEW, but other than that I get the expected behavior.

The reason, as I discovered, is that CPMAddPackage does not in fact forward all arguments to FetchContent_Declare. It only extracts the NAME, FORCE, VERSION, GIT_TAG, DOWNLOAD_ONLY, GITHUB_REPOSITORY, GITLAB_REPOSITORY, BITBUCKET_REPOSITORY, GIT_REPOSITORY, SOURCE_DIR, DOWNLOAD_COMMAND, FIND_PACKAGE_ARGUMENTS, NO_CACHE, SYSTEM, GIT_SHALLOW, EXCLUDE_FROM_ALL, SOURCE_SUBDIR, URL, and OPTIONS arguments, but FetchContent_Declare(and by extension,ExternalProject_Add) supports many more arguments than these. At least, that's my understanding of the code. I'm not positive how cmake_parse_arguments works, so for all I know I could be wrong.

In fact from my understanding it should capture all arguments. From the CMake docs:

All remaining arguments are collected in a variable _UNPARSED_ARGUMENTS that will be undefined if all arguments were recognized.

Which we should later forward to FetchContent. So I'm unsure why it isn't working in this case. Can you share a minimal example to reproduce?

@TheLartians Sure thing. I'm trying to use a project that has some (private) submodules. So I can't just recursively fetch everything; I don't have rights to all of the submodules. The CMake project, therefore, fetches the modules that I actually need, and excludes those that are private, unless I explicitly opt into it doing so. So, I tried this using CPM:

CPMAddPackage(
    NAME nabla
    VERSION 0.4-beta
    GIT_REPOSITORY https://github.com/devsh-graphics-programming/nabla
    GIT_TAG v0.4-beta
    GIT_SUBMODULES ""
    GIT_SUBMODULES_RECURSE FALSE
    GIT_PROGRESS TRUE
    OPTIONS
    "NBL_COMPILE_WITH_CUDA ON"
    "NBL_BUILD_DPL ON"
    "NBL_PCH ON"
    "NBL_FAST_MATH ON"
    "NBL_BUILD_EXAMPLES OFF"
    "NBL_BUILD_TOOLS OFF"
    "NBL_BUILD_MITSUBA_LOADER ON"
    "NBL_BUILD_OPTIX ON"
    "NBL_EMBED_BUILTIN_RESOURCES ON"
)

Doing that still caused Git to fetch all submodules, even those that were private. Which is not my desired behavior. A minimal example for a project might be something like:

cmake_minimum_required(VERSION 3.25)
cmake_policy(VERSION 3.25)
cmake_policy(SET CMP0096 NEW)
cmake_policy(SET CMP0077 NEW)
project(game VERSION 0.0.1 LANGUAGES CXX)
include(CheckPIESupported)
check_pie_supported()
if(NOT CMAKE_MAXIMUM_RECURSION_DEPTH)
  set(CMAKE_MAXIMUM_RECURSION_DEPTH 2000)
endif()
add_executable(game
    main.cpp
)
# Fetch external targets
set(CPM_DOWNLOAD_VERSION 0.38.1)

if(CPM_SOURCE_CACHE)
    set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
    set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
    set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()

if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
    message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
    file(DOWNLOAD
        https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
        ${CPM_DOWNLOAD_LOCATION}
    )
endif()

include(${CPM_DOWNLOAD_LOCATION})

CPMAddPackage(
    NAME nabla
    VERSION 0.4-beta
    GIT_REPOSITORY https://github.com/devsh-graphics-programming/nabla
    GIT_TAG v0.4-beta
    GIT_SUBMODULES ""
    GIT_SUBMODULES_RECURSE FALSE
    GIT_PROGRESS TRUE
    OPTIONS
    "NBL_COMPILE_WITH_CUDA ON"
    "NBL_BUILD_DPL ON"
    "NBL_PCH ON"
    "NBL_FAST_MATH ON"
    "NBL_BUILD_EXAMPLES OFF"
    "NBL_BUILD_TOOLS OFF"
    "NBL_BUILD_MITSUBA_LOADER ON"
    "NBL_BUILD_OPTIX ON"
    "NBL_EMBED_BUILTIN_RESOURCES ON"
)
include(${CMAKE_CURRENT_BINARY_DIR}/_deps/nabla-src/cmake/build/AddNablaModule.cmake)
addNablaModule(game "${CMAKE_CURRENT_BINARY_DIR}/_deps/nabla-build/install")
target_compile_features(game PUBLIC cxx_std_20)
set_target_properties(game PROPERTIES
    CXX_EXTENSIONS OFF
    POSITION_INDEPENDENT_CODE TRUE
    C_STANDARD 18
    C_STANDARD_REQUIRED 18
    CXX_SCAN_FOR_MODULES ON
    CXX_STANDARD 20
    CXX_STANDARD_REQUIRED 20
    INTERPROCEDURAL_OPTIMIZATION ON
   PCH_INSTANTIATE_TEMPLATES ON
    PCH_WARN_INVALID ON
    UNITY_BUILD ON
    UNITY_BUILD_UNIQUE_ID "GAME"
)

(I might've made some errors, I hope not.) The source code in main.cpp can be anything, since CMake fails the configure stage.

@TheLartians I should also note that you'll need the Cuda toolkit and NVIDIA OptiX for this to work. You can turn that off if you don't have them or you don't want to go get them just for this. The configure stage will take quite a while anyway, though.

Super, thanks for the reproducer!
Now that I see it I believe this is related an issue currently being worked on where empty string parameters (eg the "" in GIT_SUBMODULES "") get lost in the CMake parsing toolchain.

Hopefully the fix will be released soon, but in the meanwhile could you try replacing the contents of CPM.cmake with this development version and see if that solves your issue?

@ethindp I feel this bug was prematurely closed, the Fix PR hasn't made progress so this bug should be open so its visible to others.