Compare commits

..

12 Commits

Author SHA1 Message Date
Lars Melchior
6b5cd6f190 add removed test cases 2023-04-13 17:59:08 +02:00
Lars Melchior
a49358ef34 refactor empty argument passing to not require eval 2023-04-13 17:49:13 +02:00
Craig Hutchinson
f4fd660d09 Maintain key-value CMake formatting 2023-03-23 20:55:19 +00:00
Craig Hutchinson
5c1ce67e3b Fix docs typo 2023-03-23 20:55:19 +00:00
Craig Hutchinson
b847af65c0 Support EVAL CODE on CMake <3.18 2023-03-23 20:55:18 +00:00
Craig Hutchinson
cbe5144f79 Preserving forwarding of empty string arguments
Also:
- Support cmake-format on Windows by using auto lione-ending
2023-03-23 20:55:18 +00:00
Craig Hutchinson
b70460aca4 Test forwarding of arguments to FetchCOntent_Declare 2023-03-23 20:55:18 +00:00
Claus Klein
a02a9601da SOURCE_DIR option disable call to find_package() (#456) 2023-02-28 19:25:01 +01:00
Craig Hutchinson
af3f1ca814 Prevent check variable leaking into caller scope (#457) 2023-02-27 12:48:00 +01:00
Lars Melchior
b9b512a869 Add CMake version as workflow matrix parameter (#451)
* add CMake version as workflow matrix parameter

* change system test behaviour based on specified CMake version

* use explicit version strings

* set CMake version for both test steps

* exclude windows-2022, cmake 3.16 combination
2023-02-22 17:33:50 +01:00
Lars Melchior
e23bd4c0c3 Update Readme to match default SYSTEM behaviour (#452) 2023-02-21 20:00:20 +02:00
Lars Melchior
5f3005ab7c Move section on adding CPM higher in the Readme (#454)
Repositions the "Adding CPM" section higher in the Readme to increase incentive to try it out and make it easier to find for updating CPM in existing projects.
2023-02-21 19:59:57 +02:00
9 changed files with 200 additions and 35 deletions

View File

@@ -1,6 +1,7 @@
format:
tab_size: 2
line_width: 100
line_ending: auto
dangle_parens: true
parse:

View File

@@ -17,6 +17,13 @@ jobs:
# we need at least ruby 2.7 for the tests
# instead of dealing with installing a modern version of ruby on 2019, we'll just use windows-2022 here
os: [ubuntu-latest, windows-2022, macos-latest]
# we want to ensure compatibility with a recent CMake version as well as the lowest officially supported
# legacy version that we define as the default version of the second-latest Ubuntu LTS release currently available
cmake_version: ['3.16.3', '3.25.1']
exclude:
# there seems to be an issue with CMake 3.16 not finding a C++ compiler on windows-2022
- os: windows-2022
cmake_version: '3.16.3'
steps:
- name: clone
@@ -25,14 +32,17 @@ jobs:
- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v1.13
with:
cmake-version: '3.25.x'
cmake-version: ${{ matrix.cmake_version }}
- name: unit tests
run: |
cmake -Stest -Bbuild/test
cmake --build build/test --target test-verbose
env:
CMAKE_VERSION: ${{ matrix.cmake_version }}
- name: integration tests
run: ruby test/integration/runner.rb
env:
CPM_INTEGRATION_TEST_DIR: ./build/integration
CMAKE_VERSION: ${{ matrix.cmake_version }}

View File

@@ -45,6 +45,18 @@ target_link_libraries(main fmt::fmt nlohmann_json::nlohmann_json Catch2::Catch2W
See the [examples directory](https://github.com/cpm-cmake/CPM.cmake/tree/master/examples) for complete examples with source code and check [below](#snippets) or in the [wiki](https://github.com/cpm-cmake/CPM.cmake/wiki/More-Snippets) for example snippets.
## Adding CPM
To add CPM to your current project, simply add the [latest release](https://github.com/cpm-cmake/CPM.cmake/releases/latest) of `CPM.cmake` or `get_cpm.cmake` to your project's `cmake` directory.
The command below will perform this automatically.
```bash
mkdir -p cmake
wget -O cmake/CPM.cmake https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake
```
You can also download CPM.cmake directly from your project's `CMakeLists.txt`. See the [wiki](https://github.com/cpm-cmake/CPM.cmake/wiki/Downloading-CPM.cmake-in-CMake) for more details.
## Usage
After `CPM.cmake` has been [added](#adding-cpm) to your project, the function `CPMAddPackage` can be used to fetch and configure a dependency.
@@ -83,7 +95,7 @@ CPMAddPackage("uri#tag")
CPMAddPackage("uri@version#tag")
```
In the shorthand syntax if the URI is of the form `gh:user/name`, it is interpreted as GitHub URI and converted to `https://github.com/user/name.git`. If the URI is of the form `gl:user/name`, it is interpreted as a [GitLab](https://gitlab.com/explore/) URI and converted to `https://gitlab.com/user/name.git`. If the URI is of the form `bb:user/name`, it is interpreted as a [Bitbucket](https://bitbucket.org/) URI and converted to `https://bitbucket.org/user/name.git`. Otherwise the URI used verbatim as a git URL. All packages added using the shorthand syntax will be added using the [EXCLUDE_FROM_ALL](https://cmake.org/cmake/help/latest/prop_tgt/EXCLUDE_FROM_ALL.html) flag.
In the shorthand syntax if the URI is of the form `gh:user/name`, it is interpreted as GitHub URI and converted to `https://github.com/user/name.git`. If the URI is of the form `gl:user/name`, it is interpreted as a [GitLab](https://gitlab.com/explore/) URI and converted to `https://gitlab.com/user/name.git`. If the URI is of the form `bb:user/name`, it is interpreted as a [Bitbucket](https://bitbucket.org/) URI and converted to `https://bitbucket.org/user/name.git`. Otherwise the URI used verbatim as a git URL. All packages added using the shorthand syntax will be added using the [EXCLUDE_FROM_ALL](https://cmake.org/cmake/help/latest/prop_tgt/EXCLUDE_FROM_ALL.html) and [SYSTEM](https://cmake.org/cmake/help/latest/prop_tgt/SYSTEM.html#prop_tgt:SYSTEM) flag.
The single-argument syntax also works for URLs:
@@ -107,21 +119,9 @@ For using CPM.cmake projects with external package managers, such as conan or vc
In rare cases, this behaviour may be desirable by default. The function `CPMFindPackage` will try to find a local dependency via CMake's `find_package` and fallback to `CPMAddPackage`, if the dependency is not found.
## Adding CPM
To add CPM to your current project, simply add the [latest release](https://github.com/cpm-cmake/CPM.cmake/releases/latest) of `CPM.cmake` or `get_cpm.cmake` to your project's `cmake` directory.
The command below will perform this automatically.
```bash
mkdir -p cmake
wget -O cmake/CPM.cmake https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake
```
You can also download CPM.cmake directly from your project's `CMakeLists.txt`. See the [wiki](https://github.com/cpm-cmake/CPM.cmake/wiki/Downloading-CPM.cmake-in-CMake) for more details.
## Updating CPM
To update CPM to the newest version, update the script in the project's root directory, for example by running the command above.
To update CPM to the newest version, update the script in the project's root directory, for example by running the same command as for [adding CPM](#adding-cpm).
Dependencies using CPM will automatically use the updated script of the outermost project.
## Advantages
@@ -199,11 +199,14 @@ This can be controlled on a per package basis with the `CPM_DOWNLOAD_<dependency
### CPM_USE_LOCAL_PACKAGES
CPM can be configured to use `find_package` to search for locally installed dependencies first by setting the CMake option `CPM_USE_LOCAL_PACKAGES`.
If the option `CPM_LOCAL_PACKAGES_ONLY` is set, CPM will emit an error if the dependency is not found locally.
These options can also be set as environmental variables.
In the case that `find_package` requires additional arguments, the parameter `FIND_PACKAGE_ARGUMENTS` may be specified in the `CPMAddPackage` call. The value of this parameter will be forwarded to `find_package`.
Note that this does not apply to dependencies that have been defined with a truthy `FORCE` parameter. These will be added as defined.
### CPM_USE_NAMED_CACHE_DIRECTORIES
If set, CPM use additional directory level in cache to improve readability of packages names in IDEs like CLion. It changes cache structure, so all dependencies are downloaded again. There is no problem to mix both structures in one cache directory but then there may be 2 copies of some dependencies.

View File

@@ -505,6 +505,60 @@ function(cpm_override_fetchcontent contentName)
set_property(GLOBAL PROPERTY ${propertyName} TRUE)
endfunction()
# replaces empty arguments with a placeholder to compensate CMake issues with handling empty
# arguments
function(cpm_encode_empty_arguments args outVar)
set(out "")
# note: we don't use string replacement for ';;' -> ';__CPM_EMPTY_ARG;' here, as it would
# interfere with nested arguments
foreach(ARG IN LISTS args)
if(NOT out STREQUAL "")
string(APPEND out ";")
endif()
if(ARG STREQUAL "")
string(APPEND out "__CPM_EMPTY_ARG")
else()
# prevent escaped characters from getting resolved early
string(REPLACE "\\" "\\\\\\" ARG "${ARG}")
string(APPEND out "${ARG}")
endif()
endforeach()
set("${outVar}"
"${out}"
PARENT_SCOPE
)
endfunction()
function(cpm_decode_empty_argument arg outVar)
if("${arg}" STREQUAL "__CPM_EMPTY_ARG")
set("${outVar}"
""
PARENT_SCOPE
)
else()
set("${outVar}"
"${arg}"
PARENT_SCOPE
)
endif()
endfunction()
# replaces placeholder arguments from `cpm_encode_empty_arguments` with empty arguments
function(cpm_decode_empty_arguments args outVar)
set(out "")
foreach(ARG IN LISTS args)
if(NOT out STREQUAL "")
string(APPEND out ";")
endif()
cpm_decode_empty_argument("${ARG}" ARG)
string(APPEND out "${ARG}")
endforeach()
set("${outVar}"
"${out}"
PARENT_SCOPE
)
endfunction()
# Download and add a package from source
function(CPMAddPackage)
cpm_set_policies()
@@ -512,7 +566,6 @@ function(CPMAddPackage)
list(LENGTH ARGN argnLength)
if(argnLength EQUAL 1)
cpm_parse_add_package_single_arg("${ARGN}" ARGN)
# The shorthand syntax implies EXCLUDE_FROM_ALL and SYSTEM
set(ARGN "${ARGN};EXCLUDE_FROM_ALL;YES;SYSTEM;YES;")
endif()
@@ -539,10 +592,26 @@ function(CPMAddPackage)
set(multiValueArgs URL OPTIONS)
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")
# Encode arguments for `cmake_parse_arguments`
cpm_encode_empty_arguments("${ARGN}" "PARSE_ARGS")
# Parse arguments
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${PARSE_ARGS}")
# Decode arguments
foreach(ARG IN LISTS oneValueArgs)
if(DEFINED CPM_ARGS_${ARG})
cpm_decode_empty_argument("${CPM_ARGS_${ARG}}" CPM_ARGS_${ARG})
endif()
endforeach()
foreach(ARG IN LISTS multiValueArgs)
if(DEFINED CPM_ARGS_${ARG})
cpm_decode_empty_arguments("${CPM_ARGS_${ARG}}" CPM_ARGS_${ARG})
endif()
endforeach()
cpm_decode_empty_arguments("${CPM_ARGS_UNPARSED_ARGUMENTS}" CPM_ARGS_UNPARSED_ARGUMENTS)
# Set default values for arguments
if(NOT DEFINED CPM_ARGS_VERSION)
if(DEFINED CPM_ARGS_GIT_TAG)
cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION)
@@ -648,6 +717,7 @@ function(CPMAddPackage)
return()
endif()
if(NOT CPM_ARGS_FORCE)
if(CPM_USE_LOCAL_PACKAGES OR CPM_LOCAL_PACKAGES_ONLY)
cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS})
@@ -663,6 +733,7 @@ function(CPMAddPackage)
)
endif()
endif()
endif()
CPMRegisterPackage("${CPM_ARGS_NAME}" "${CPM_ARGS_VERSION}")
@@ -914,8 +985,7 @@ function(cpm_declare_fetch PACKAGE VERSION INFO)
cpm_message(STATUS "${CPM_INDENT} Package not declared (dry run)")
return()
endif()
FetchContent_Declare(${PACKAGE} ${ARGN})
FetchContent_Declare(${PACKAGE} "${ARGN}")
endfunction()
# returns properties for a package previously defined by cpm_declare_fetch
@@ -1103,7 +1173,7 @@ function(cpm_prettify_package_arguments OUT_VAR IS_IN_COMMENT)
GIT_SHALLOW
)
set(multiValueArgs OPTIONS)
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
cmake_parse_arguments(PARSE_ARGV 2 CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}")
foreach(oneArgName ${oneValueArgs})
if(DEFINED CPM_ARGS_${oneArgName})

View File

@@ -27,6 +27,7 @@ else()
if("${check}" STREQUAL "")
download_cpm()
endif()
unset(check)
endif()
include(${CPM_DOWNLOAD_LOCATION})

View File

@@ -12,7 +12,7 @@ To run all tests from the repo root execute:
$ ruby test/integration/runner.rb
```
The runner will run all tests and generate a report of the exeuction.
The runner will run all tests and generate a report of the execution.
The current working directory doesn't matter. If you are in `<repo-root>/test/integration`, you can run simply `$ ruby runner.rb`.

View File

@@ -2,6 +2,11 @@ require_relative './lib'
class SystemWarnings < IntegrationTest
def setup
# system is only supported for CMake >= 3.25
@system_supported = (!ENV['CMAKE_VERSION']) || (Gem::Version.new(ENV['CMAKE_VERSION']) >= Gem::Version.new('3.25'))
end
def test_dependency_added_using_system
for use_system in [true, false] do
prj = make_project name: use_system ? "system" : "no_system", from_template: 'using-adder'
@@ -21,7 +26,7 @@ class SystemWarnings < IntegrationTest
PACK
assert_success prj.configure
if use_system
if use_system and @system_supported
assert_success prj.build
else
assert_failure prj.build
@@ -42,7 +47,11 @@ class SystemWarnings < IntegrationTest
PACK
assert_success prj.configure
if @system_supported
assert_success prj.build
else
assert_failure prj.build
end
end
end

View File

@@ -0,0 +1,69 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
include(${CPM_PATH}/CPM.cmake)
include(${CPM_PATH}/testing.cmake)
set(input "a;;b;c;;;;def;g;;")
cpm_encode_empty_arguments("${input}" encoded)
foreach(arg IN LISTS encoded)
assert_not_equal("${arg}" "")
endforeach()
assert_equal("${contains_empty_arg}" "")
cpm_decode_empty_arguments("${encoded}" decoded)
assert_equal("${decoded}" "${input}")
# ignore source cache if set
set(CPM_SOURCE_CACHE "")
# Intercept underlying `FetchContent_Declare`
function(FetchContent_Declare)
set_property(GLOBAL PROPERTY last_FetchContent_Declare_ARGN "${ARGN}")
endfunction()
cpm_declare_fetch(PACKAGE VERSION INFO EMPTY "" ANOTHER)
# TEST:`cpm_declare_fetch` shall forward empty arguments
get_property(last_FetchContent_Declare_ARGN GLOBAL PROPERTY last_FetchContent_Declare_ARGN)
assert_equal("${last_FetchContent_Declare_ARGN}" "PACKAGE;EMPTY;;ANOTHER")
# TEST:`CPMDeclarePackage` shall store all including empty
CPMDeclarePackage(FOO EMPTY "" ANOTHER)
assert_equal("${CPM_DECLARATION_FOO}" "EMPTY;;ANOTHER")
# Stub the actual fetch
set(fibonacci_POPULATED YES)
set(fibonacci_SOURCE_DIR ".")
set(fibonacci_BINARY_DIR ".")
macro(FetchContent_GetProperties)
endmacro()
# TEST:`CPMAddPackage` shall call `FetchContent_declare` with unmodified arguments including any
# Empty-string arguments
CPMAddPackage(
NAME fibonacci
GIT_REPOSITORY https://github.com/cpm-cmake/testpack-fibonacci.git
VERSION 1.2.3 EMPTY_OPTION "" COMMAND_WITH_EMPTY_ARG foo "" bar
)
get_property(last_FetchContent_Declare_ARGN GLOBAL PROPERTY last_FetchContent_Declare_ARGN)
assert_equal(
"${last_FetchContent_Declare_ARGN}"
"fibonacci;EMPTY_OPTION;;COMMAND_WITH_EMPTY_ARG;foo;;bar;GIT_REPOSITORY;https://github.com/cpm-cmake/testpack-fibonacci.git;GIT_TAG;v1.2.3"
)
# Intercept underlying `cpm_add_package_multi_arg`
function(CPMAddPackage)
set_property(GLOBAL PROPERTY last_cpmaddpackage_argn "${ARGN}")
endfunction()
# TEST: CPM Module file shall store all arguments including empty strings
include(${CPM_MODULE_PATH}/Findfibonacci.cmake)
get_property(last_cpmaddpackage_argn GLOBAL PROPERTY last_cpmaddpackage_argn)
assert_equal(
"${last_cpmaddpackage_argn}"
"NAME;fibonacci;GIT_REPOSITORY;https://github.com/cpm-cmake/testpack-fibonacci.git;VERSION;1.2.3;EMPTY_OPTION;;COMMAND_WITH_EMPTY_ARG;foo;;bar"
)
# remove generated files
file(REMOVE_RECURSE ${CPM_MODULE_PATH})
file(REMOVE ${CPM_PACKAGE_LOCK_FILE})

View File

@@ -2,6 +2,8 @@ include(CMakePackageConfigHelpers)
include(${CPM_PATH}/testing.cmake)
set(TEST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/source_dir)
# clean existing build if it exists
file(REMOVE_RECURSE "${TEST_BUILD_DIR}")
set(TEST_DEPENDENCY_NAME Dependency)