Compare commits

..

No commits in common. "master" and "v0.35.4" have entirely different histories.

62 changed files with 346 additions and 1670 deletions

View File

@ -1,5 +1,73 @@
include: ["cmake/.cmake-format-additional_commands-cpm"]
format: format:
tab_size: 2 tab_size: 2
line_width: 100 line_width: 100
dangle_parens: true dangle_parens: true
parse:
additional_commands:
cpmaddpackage:
pargs:
nargs: '*'
flags: []
spelling: CPMAddPackage
kwargs: &cpmaddpackagekwargs
NAME: 1
FORCE: 1
VERSION: 1
GIT_TAG: 1
DOWNLOAD_ONLY: 1
GITHUB_REPOSITORY: 1
GITLAB_REPOSITORY: 1
GIT_REPOSITORY: 1
SVN_REPOSITORY: 1
SVN_REVISION: 1
SOURCE_DIR: 1
DOWNLOAD_COMMAND: 1
FIND_PACKAGE_ARGUMENTS: 1
NO_CACHE: 1
GIT_SHALLOW: 1
URL: 1
URL_HASH: 1
URL_MD5: 1
DOWNLOAD_NAME: 1
DOWNLOAD_NO_EXTRACT: 1
HTTP_USERNAME: 1
HTTP_PASSWORD: 1
EXCLUDE_FROM_ALL: 1
SOURCE_SUBDIR: 1
OPTIONS: +
cpmfindpackage:
pargs:
nargs: '*'
flags: []
spelling: CPMFindPackage
kwargs: *cpmaddpackagekwargs
cpmdeclarepackage:
pargs:
nargs: '*'
flags: []
spelling: CPMDeclarePackage
kwargs: *cpmaddpackagekwargs
packageproject:
pargs:
nargs: '*'
flags: []
spelling: packageProject
kwargs:
NAME: 1
VERSION: 1
INCLUDE_DIR: 1
INCLUDE_DESTINATION: 1
BINARY_DIR: 1
COMPATIBILITY: 1
VERSION_HEADER: 1
DEPENDENCIES: +
cpmusepackagelock:
pargs: 1
spelling: CPMUsePackageLock
cpmregisterpackage:
pargs: 1
spelling: CPMRegisterPackage
cpmgetpackageversion:
pargs: 2
spelling: CPMGetPackageVersion

View File

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

1
.gitattributes vendored
View File

@ -1 +0,0 @@
.git_archival.txt export-subst

View File

@ -12,7 +12,7 @@ jobs:
gcc: gcc:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
- name: build all - name: build all
env: env:
CC: gcc CC: gcc
@ -22,7 +22,7 @@ jobs:
clang: clang:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
- name: build all - name: build all
env: env:
CC: clang CC: clang

View File

@ -10,14 +10,13 @@ jobs:
name: Publish CPM.cmake name: Publish CPM.cmake
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v1
- name: Set CPM version by tag - name: Set CPM version by tag
run: | run: |
mkdir dist mkdir dist
sed -e "s/1.0.0-development-version/${GITHUB_REF/refs\/tags\/v}/g" cmake/CPM.cmake > dist/CPM.cmake sed "s/1.0.0-development-version/${GITHUB_REF/refs\/tags\/v}/g" cmake/CPM.cmake > dist/CPM.cmake
sed -e "s/1.0.0-development-version/${GITHUB_REF/refs\/tags\/v}/g" \ sed "s/1.0.0-development-version/${GITHUB_REF/refs\/tags\/v}/g" cmake/get_cpm.cmake > dist/get_cpm.cmake
-e "s/CPM_HASH_SUM_PLACEHOLDER/$(sha256sum dist/CPM.cmake | cut -d' ' -f1)/" cmake/get_cpm.cmake > dist/get_cpm.cmake
- name: Upload CPM.cmake to release - name: Upload CPM.cmake to release
uses: svenstaro/upload-release-action@v1-release uses: svenstaro/upload-release-action@v1-release

View File

@ -11,18 +11,15 @@ on:
jobs: jobs:
style: style:
runs-on: ubuntu-latest runs-on: macos-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v1
- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v1.13
with:
cmake-version: '3.27.x'
- name: Install format dependencies - name: Install format dependencies
run: pip3 install clang-format==14.0.6 cmake_format==0.6.11 pyyaml run: |
brew install clang-format
pip3 install cmake_format==0.6.11 pyyaml
- name: configure - name: configure
run: cmake -Stest/style -Bbuild/style run: cmake -Stest/style -Bbuild/style

View File

@ -17,32 +17,17 @@ jobs:
# we need at least ruby 2.7 for the tests # 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 # 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] 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.27.5', '3.30.0']
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: steps:
- name: clone - name: clone
uses: actions/checkout@v3 uses: actions/checkout@v2
- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v1.13
with:
cmake-version: ${{ matrix.cmake_version }}
- name: unit tests - name: unit tests
run: | run: |
cmake -Stest -Bbuild/test cmake -Stest -Bbuild/test
cmake --build build/test --target test-verbose cmake --build build/test --target test-verbose
env:
CMAKE_VERSION: ${{ matrix.cmake_version }}
- name: integration tests - name: integration tests
run: ruby test/integration/runner.rb run: ruby test/integration/runner.rb
env: env:
CPM_INTEGRATION_TEST_DIR: ./build/integration CPM_INTEGRATION_TEST_DIR: ./build/integration
CMAKE_VERSION: ${{ matrix.cmake_version }}

View File

@ -1,28 +0,0 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git/")
find_package(Git REQUIRED)
execute_process(
COMMAND "${GIT_EXECUTABLE}" describe --tags --match=?[0-9.]*
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT_VARIABLE DESCRIBE_NAME COMMAND_ERROR_IS_FATAL ANY
)
set(CPM_DEVELOPMENT "-development-version")
else()
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/.git_archival.txt" DESCRIBE_NAME
REGEX "^describe-name:.*"
)
endif()
string(REGEX MATCH "([0-9\\.]+)" EXTRACTED_CPM_VERSION "${DESCRIBE_NAME}")
project(
CPM.cmake
VERSION "${EXTRACTED_CPM_VERSION}"
DESCRIPTION
"CMake's missing package manager. A small CMake script for setup-free, cross-platform, reproducible dependency management."
HOMEPAGE_URL "https://github.com/cpm-cmake/CPM.cmake"
LANGUAGES NONE
)
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/CPM.cmake")

View File

@ -1,177 +0,0 @@
<!-- omit in toc -->
# Contributing to CPM.cmake
First off, thanks for taking the time to contribute! ❤️
All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
> - Star the project
> - Tweet about it
> - Refer this project in your project's readme
> - Mention the project at local meetups and tell your friends/colleagues
<!-- omit in toc -->
## Table of Contents
- [I Have a Question](#i-have-a-question)
- [I Want To Contribute](#i-want-to-contribute)
- [Reporting Bugs](#reporting-bugs)
- [Suggesting Enhancements](#suggesting-enhancements)
- [Your First Code Contribution](#your-first-code-contribution)
- [Styleguides](#styleguides)
## I Have a Question
> If you want to ask a question, we assume that you have read the available [Documentation](https://github.com/cpm-cmake/CPM.cmake/blob/master/README.md).
Before you ask a question, it is best to search for existing [Issues](https://github.com/cpm-cmake/CPM.cmake/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
If you then still feel the need to ask a question and need clarification, we recommend the following:
- Open an [Issue](https://github.com/cpm-cmake/CPM.cmake/issues/new).
- Provide as much context as you can about what you're running into.
- Provide project and platform versions (CMake, OS, etc), depending on what seems relevant.
We will then take care of the issue as soon as possible.
## I Want To Contribute
> ### Legal Notice <!-- omit in toc -->
> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.
### Reporting Bugs
<!-- omit in toc -->
#### Before Submitting a Bug Report
A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
- Make sure that you are using the latest version.
- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://github.com/cpm-cmake/CPM.cmake/blob/master/README.md). If you are looking for support, you might want to check [this section](#i-have-a-question)).
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/cpm-cmake/CPM.cmake/issues?q=label%3Abug).
- Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
- Collect information about the bug:
- Stack trace / Full CMake error output
- OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
- Version of CMake, compiler or other tools used, depending on what seems relevant.
- Possibly any relevant environment / command line arguments used
- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
<!-- omit in toc -->
#### How Do I Submit a Good Bug Report?
We use GitHub issues to track bugs and errors. If you run into an issue with the project:
- Open an [Issue](https://github.com/cpm-cmake/CPM.cmake/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
- Explain the behavior you would expect and the actual behavior.
- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
- Provide the information you collected in the previous section.
Once it's filed:
- The project team will label the issue accordingly.
- A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced.
- If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be [implemented by someone](#your-first-code-contribution).
### Suggesting Enhancements
This section guides you through submitting an enhancement suggestion for CPM.cmake, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.
<!-- omit in toc -->
#### Before Submitting an Enhancement
- Make sure that you are using the latest version.
- Read the [documentation](https://github.com/cpm-cmake/CPM.cmake/blob/master/README.md) carefully and find out if the functionality is already covered, maybe by an individual configuration.
- Perform a [search](https://github.com/cpm-cmake/CPM.cmake/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
<!-- omit in toc -->
#### How Do I Submit a Good Enhancement Suggestion?
Enhancement suggestions are tracked as [GitHub issues](https://github.com/cpm-cmake/CPM.cmake/issues).
- Use a **clear and descriptive title** for the issue to identify the suggestion.
- Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you.
- **Explain why this enhancement would be useful** to most CPM.cmake users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
### Your First Code Contribution
Please try to keep your individual changes as minimal and focussed on the issue as possible.
If you discover that the scope of your contribution is growing larger than expected you might want to split the changes into multiple separate contributions to allow a more focussed discussion and review.
It is usually a great idea and often required to add tests for your changes.
This allows us to quickly validate that the changes are working as intended and also guarantees that they won't be broken by other future updates.
For small and targeted functional changes, e.g. supporting a new URL schema, a [unit test](#unit-tests) may be enough.
For contributions that change large-scale behaviour, such as dependency caching features, an [integration test](#integration-tests) is more suited.
Depending on the changes, a combination of both test types may also be appropriate.
#### Unit tests
Unit tests are small CMake scripts that live in the [unit test directory](./test/unit/).
They usually make use of some of the helper assertions defined in the [testing.cmake](./cmake/testing.cmake) file.
An example unit test for checking the `cpm_get_version_from_git_tag` function could look like the following.
```cmake
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
include(${CPM_PATH}/CPM.cmake)
include(${CPM_PATH}/testing.cmake)
cpm_get_version_from_git_tag("v1.2.3-a" VERSION)
assert_equal("1.2.3" ${VERSION})
```
This test can be run directly with CMake by providing the CPM source directory.
```bash
cmake -DCPM_PATH=$(pwd)/cmake -P <path to the test file>
```
We can also the [test directory's](./test/) CMakeLists to detect and run all unit tests using CMake's test runner.
```bash
cmake -Stest -Bbuild/test
cmake --build build/test --target test-verbose # or `test` for less noisy output
```
#### Integration tests
The integration tests of CPM.cmake are written in Ruby. They use a custom integration test framework which extends the [Test::Unit](https://www.rubydoc.info/github/test-unit/test-unit/Test/Unit) library.
They require Ruby 2.7.0 or later.
To run all tests from the repo root execute:
```
ruby test/integration/runner.rb
```
For a detailed guide on integration tests, see the documentation in the [integration test directory](./test/integration/).
## Styleguides
This project uses automatic code styling using [clang-format](https://clang.llvm.org/docs/ClangFormat.html) and [cmake-format](https://github.com/cheshirekow/cmake_format).
The code style is enforced by the tools using the style options defined in the [.clang-format](./.clang-format) and [.cmake-format](./.cmake-format) configuration files.
To install the necessary tools for code styling we recommend using recent version of [Python/pip](https://www.python.org).
```bash
pip3 install clang-format==14.0.6 cmake_format==0.6.11 pyyaml
```
For convenience, we have a CMake project defined in the [test/style](./test/style/) directory that can be called to automatically apply the code styling to all files currently added in git.
```bash
# initialize the project
cmake -Stest/style -Bbuild/style
# apply the code styling to this repository
cmake --build build/style --target fix-format
```
<!-- omit in toc -->
## Attribution
This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)!

View File

@ -30,11 +30,3 @@ For detailed breakdown of individual contributions see the [Contributors page on
* [Yotam Gingold](https://github.com/yig) * [Yotam Gingold](https://github.com/yig)
* [jecassis](https://github.com/jecassis) * [jecassis](https://github.com/jecassis)
* [Johel Ernesto Guerrero Peña](https://github.com/JohelEGP) * [Johel Ernesto Guerrero Peña](https://github.com/JohelEGP)
* [Lars Bilke](https://github.com/bilke)
* [Lava Block](https://github.com/TheLavaBlock)
* [Anton Filimonov](https://github.com/variar)
* [David Fong](https://github.com/david-fong)
* [Thomas Mosegaard Pedersen](https://github.com/thomas-mp)
* [Evgeny Gorodetskiy](https://github.com/egorodet)
* [Kamil Kisiel](https://github.com/kisielk)
* [AlessandroW](https://github.com/AlessandroW)

334
README.md
View File

@ -12,7 +12,7 @@ It's built as a thin wrapper around CMake's [FetchContent](https://cmake.org/cma
## Manage everything ## Manage everything
Any downloadable project or resource can be added as a version-controlled dependency through CPM, it is not necessary to modify or package anything. Any downloadable project or resource can be added as a version-controlled dependency though CPM, it is not necessary to modify or package anything.
Projects using modern CMake are automatically configured and their targets can be used immediately. Projects using modern CMake are automatically configured and their targets can be used immediately.
For everything else, the targets can be created manually after the dependency has been downloaded (see the [snippets](#snippets) below for examples). For everything else, the targets can be created manually after the dependency has been downloaded (see the [snippets](#snippets) below for examples).
@ -21,6 +21,63 @@ For everything else, the targets can be created manually after the dependency ha
- [CPM: An Awesome Dependency Manager for C++ with CMake](https://medium.com/swlh/cpm-an-awesome-dependency-manager-for-c-with-cmake-3c53f4376766) - [CPM: An Awesome Dependency Manager for C++ with CMake](https://medium.com/swlh/cpm-an-awesome-dependency-manager-for-c-with-cmake-3c53f4376766)
- [CMake and the Future of C++ Package Management](https://ibob.github.io/blog/2020/01/13/cmake-package-management/) - [CMake and the Future of C++ Package Management](https://ibob.github.io/blog/2020/01/13/cmake-package-management/)
## Usage
After `CPM.cmake` has been [added](#adding-cpm) to your project, the function `CPMAddPackage` can be used to fetch and configure a dependency.
Afterwards, any targets defined in the dependency can be used directly.
`CPMAddPackage` takes the following named parameters.
```cmake
CPMAddPackage(
NAME # The unique name of the dependency (should be the exported target's name)
VERSION # The minimum version of the dependency (optional, defaults to 0)
OPTIONS # Configuration options passed to the dependency (optional)
DOWNLOAD_ONLY # If set, the project is downloaded, but not configured (optional)
[...] # Origin parameters forwarded to FetchContent_Declare, see below
)
```
The origin may be specified by a `GIT_REPOSITORY`, but other sources, such as direct URLs, are [also supported](https://cmake.org/cmake/help/v3.11/module/ExternalProject.html#external-project-definition).
If `GIT_TAG` hasn't been explicitly specified it defaults to `v(VERSION)`, a common convention for git projects.
On the other hand, if `VERSION` hasn't been explicitly specified, CPM can automatically identify the version from the git tag in some common cases.
`GIT_TAG` can also be set to a specific commit or a branch name such as `master`, however this isn't recommended, as such packages will only be updated when the cache is cleared.
If an additional optional parameter `EXCLUDE_FROM_ALL` is set to a truthy value, then any targets defined inside the dependency won't be built by default. See the [CMake docs](https://cmake.org/cmake/help/latest/prop_tgt/EXCLUDE_FROM_ALL.html) for details.
A single-argument compact syntax is also supported:
```cmake
# A git package from a given uri with a version
CPMAddPackage("uri@version")
# A git package from a given uri with a git tag or commit hash
CPMAddPackage("uri#tag")
# A git package with both version and tag provided
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.
The single-argument syntax also works for URLs:
```cmake
# An archive package from a given url. The version is inferred
CPMAddPackage("https://example.com/my-package-1.2.3.zip")
# An archive package from a given url with an MD5 hash provided
CPMAddPackage("https://example.com/my-package-1.2.3.zip#MD5=68e20f674a48be38d60e129f600faf7d")
# An archive package from a given url. The version is explicitly given
CPMAddPackage("https://example.com/my-package.zip@1.2.3")
```
After calling `CPMAddPackage`, the following variables are defined in the local scope, where `<dependency>` is the name of the dependency.
- `<dependency>_SOURCE_DIR` is the path to the source of the dependency.
- `<dependency>_BINARY_DIR` is the path to the build directory of the dependency.
- `<dependency>_ADDED` is set to `YES` if the dependency has not been added before, otherwise it is set to `NO`.
For using CPM.cmake projects with external package managers, such as conan or vcpkg, setting the variable [`CPM_USE_LOCAL_PACKAGES`](#options) will make CPM.cmake try to add a package through `find_package` first, and add it from source if it doesn't succeed.
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.
## Full CMakeLists Example ## Full CMakeLists Example
```cmake ```cmake
@ -30,17 +87,14 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(MyProject) project(MyProject)
# add executable # add executable
add_executable(main main.cpp) add_executable(tests tests.cpp)
# add dependencies # add dependencies
include(cmake/CPM.cmake) include(cmake/CPM.cmake)
CPMAddPackage("gh:catchorg/Catch2@2.5.0")
CPMAddPackage("gh:fmtlib/fmt#7.1.3")
CPMAddPackage("gh:nlohmann/json@3.10.5")
CPMAddPackage("gh:catchorg/Catch2@3.4.0")
# link dependencies # link dependencies
target_link_libraries(main fmt::fmt nlohmann_json::nlohmann_json Catch2::Catch2WithMain) target_link_libraries(tests Catch2)
``` ```
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. 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.
@ -57,88 +111,9 @@ wget -O cmake/CPM.cmake https://github.com/cpm-cmake/CPM.cmake/releases/latest/d
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. 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.
Afterwards, any targets defined in the dependency can be used directly.
`CPMAddPackage` takes the following named parameters.
```cmake
CPMAddPackage(
NAME # The unique name of the dependency (should be the exported target's name)
VERSION # The minimum version of the dependency (optional, defaults to 0)
PATCHES # Patch files to be applied sequentially using patch and PATCH_OPTIONS (optional)
OPTIONS # Configuration options passed to the dependency (optional)
DOWNLOAD_ONLY # If set, the project is downloaded, but not configured (optional)
[...] # Origin parameters forwarded to FetchContent_Declare, see below
)
```
The origin may be specified by a `GIT_REPOSITORY`, but other sources, such as direct URLs, are [also supported](https://cmake.org/cmake/help/v3.11/module/ExternalProject.html#external-project-definition).
If `GIT_TAG` hasn't been explicitly specified it defaults to `v(VERSION)`, a common convention for git projects.
On the other hand, if `VERSION` hasn't been explicitly specified, CPM can automatically identify the version from the git tag in some common cases.
`GIT_TAG` can also be set to a specific commit or a branch name such as `master`, however this isn't recommended, as such packages will only be updated when the cache is cleared.
`PATCHES` takes a list of patch files to apply sequentially. For a basic example, see [Highway](examples/highway/CMakeLists.txt).
We recommend that if you use `PATCHES`, you also set `CPM_SOURCE_CACHE`. See [issue 577](https://github.com/cpm-cmake/CPM.cmake/issues/577).
If an additional optional parameter `EXCLUDE_FROM_ALL` is set to a truthy value, then any targets defined inside the dependency won't be built by default. See the [CMake docs](https://cmake.org/cmake/help/latest/prop_tgt/EXCLUDE_FROM_ALL.html) for details.
If an additional optional parameter `SYSTEM` is set to a truthy value, the SYSTEM directory property of the subdirectory added will be set to true.
See the [add_subdirectory ](https://cmake.org/cmake/help/latest/command/add_subdirectory.html?highlight=add_subdirectory)
and [SYSTEM](https://cmake.org/cmake/help/latest/prop_tgt/SYSTEM.html#prop_tgt:SYSTEM) target property for details.
A shorthand syntax is also supported:
```cmake
# A git package from a given uri with a version
CPMAddPackage("uri@version")
# A git package from a given uri with a git tag or commit hash
CPMAddPackage("uri#tag")
# A git package with both version and tag provided
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) and [SYSTEM](https://cmake.org/cmake/help/latest/prop_tgt/SYSTEM.html#prop_tgt:SYSTEM) flag.
The single-argument syntax also works for URLs:
```cmake
# An archive package from a given url. The version is inferred
CPMAddPackage("https://example.com/my-package-1.2.3.zip")
# An archive package from a given url with an MD5 hash provided
CPMAddPackage("https://example.com/my-package-1.2.3.zip#MD5=68e20f674a48be38d60e129f600faf7d")
# An archive package from a given url. The version is explicitly given
CPMAddPackage("https://example.com/my-package.zip@1.2.3")
```
Additionally, if needed, extra arguments can be provided while using single argument syntax by using the shorthand syntax with the `URI` specifier.
```cmake
CPMAddPackage(
URI "gh:nlohmann/json@3.9.1"
OPTIONS "JSON_BuildTests OFF"
)
```
The `URI` argument must be the first argument to `CPMAddPackage`.
`URI` automatically sets `EXCLUDE_FROM_ALL YES` and `SYSTEM YES`.
If this is not desired, `EXCLUDE_FROM_ALL NO` and `SYSTEM NO` can be set afterwards.
After calling `CPMAddPackage`, the following variables are defined in the local scope, where `<dependency>` is the name of the dependency.
- `<dependency>_SOURCE_DIR` is the path to the source of the dependency.
- `<dependency>_BINARY_DIR` is the path to the build directory of the dependency.
- `<dependency>_ADDED` is set to `YES` if the dependency has not been added before, otherwise it is set to `NO`.
- `CPM_LAST_PACKAGE_NAME` is set to the determined name of the last added dependency (equivalent to `<dependency>`).
For using CPM.cmake projects with external package managers, such as conan or vcpkg, setting the variable [`CPM_USE_LOCAL_PACKAGES`](#options) will make CPM.cmake try to add a package through `find_package` first, and add it from source if it doesn't succeed.
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.
## Updating CPM ## Updating CPM
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). To update CPM to the newest version, update the script in the project's root directory, for example by running the command above.
Dependencies using CPM will automatically use the updated script of the outermost project. Dependencies using CPM will automatically use the updated script of the outermost project.
## Advantages ## Advantages
@ -156,10 +131,6 @@ Dependencies using CPM will automatically use the updated script of the outermos
- **No pre-built binaries** For every new build directory, all dependencies are initially downloaded and built from scratch. To avoid extra downloads it is recommend to set the [`CPM_SOURCE_CACHE`](#CPM_SOURCE_CACHE) environmental variable. Using a caching compiler such as [ccache](https://github.com/TheLartians/Ccache.cmake) can drastically reduce build time. - **No pre-built binaries** For every new build directory, all dependencies are initially downloaded and built from scratch. To avoid extra downloads it is recommend to set the [`CPM_SOURCE_CACHE`](#CPM_SOURCE_CACHE) environmental variable. Using a caching compiler such as [ccache](https://github.com/TheLartians/Ccache.cmake) can drastically reduce build time.
- **Dependent on good CMakeLists** Many libraries do not have CMakeLists that work well for subprojects. Luckily this is slowly changing, however, until then, some manual configuration may be required (see the snippets [below](#snippets) for examples). For best practices on preparing projects for CPM, see the [wiki](https://github.com/cpm-cmake/CPM.cmake/wiki/Preparing-projects-for-CPM.cmake). - **Dependent on good CMakeLists** Many libraries do not have CMakeLists that work well for subprojects. Luckily this is slowly changing, however, until then, some manual configuration may be required (see the snippets [below](#snippets) for examples). For best practices on preparing projects for CPM, see the [wiki](https://github.com/cpm-cmake/CPM.cmake/wiki/Preparing-projects-for-CPM.cmake).
- **First version used** In diamond-shaped dependency graphs (e.g. `A` depends on `C`@1.1 and `B`, which itself depends on `C`@1.2 the first added dependency will be used (in this case `C`@1.1). In this case, B requires a newer version of `C` than `A`, so CPM will emit a warning. This can be easily resolved by adding a new version of the dependency in the outermost project, or by introducing a [package lock file](#package-lock). - **First version used** In diamond-shaped dependency graphs (e.g. `A` depends on `C`@1.1 and `B`, which itself depends on `C`@1.2 the first added dependency will be used (in this case `C`@1.1). In this case, B requires a newer version of `C` than `A`, so CPM will emit a warning. This can be easily resolved by adding a new version of the dependency in the outermost project, or by introducing a [package lock file](#package-lock).
- **Some CMake policies set to `NEW`** Including CPM.cmake will lead to several CMake policies being set to `NEW`. Users which need the old behavior will need to manually modify their CMake code to ensure they're set to `OLD` at the appropriate places. The policies are:
- [CMP0077](https://cmake.org/cmake/help/latest/policy/CMP0077.html) and [CMP0126](https://cmake.org/cmake/help/latest/policy/CMP0126.html). They make setting package options from `CMPAddPackage` possible.
- [CMP0135](https://cmake.org/cmake/help/latest/policy/CMP0135.html) It allows for proper package rebuilds of packages which are archives, source cache is not used, and the package URL is changed to an older version.
- [CMP0150](https://cmake.org/cmake/help/latest/policy/CMP0150.html) Relative paths provided to `GIT_REPOSITORY` are treated as relative to the parent project's remote.
For projects with more complex needs and where an extra setup step doesn't matter, it may be worth to check out an external C++ package manager such as [vcpkg](https://github.com/microsoft/vcpkg), [conan](https://conan.io) or [hunter](https://github.com/ruslo/hunter). For projects with more complex needs and where an extra setup step doesn't matter, it may be worth to check out an external C++ package manager such as [vcpkg](https://github.com/microsoft/vcpkg), [conan](https://conan.io) or [hunter](https://github.com/ruslo/hunter).
Dependencies added with `CPMFindPackage` should work with external package managers. Dependencies added with `CPMFindPackage` should work with external package managers.
@ -207,9 +178,6 @@ Note that passing the variable as a configure option to CMake will always overri
You can use `CPM_SOURCE_CACHE` on GitHub Actions workflows [cache](https://github.com/actions/cache) and combine it with ccache, to make your CI faster. See the [wiki](https://github.com/cpm-cmake/CPM.cmake/wiki/Caching-with-CPM.cmake-and-ccache-on-GitHub-Actions) for more info. You can use `CPM_SOURCE_CACHE` on GitHub Actions workflows [cache](https://github.com/actions/cache) and combine it with ccache, to make your CI faster. See the [wiki](https://github.com/cpm-cmake/CPM.cmake/wiki/Caching-with-CPM.cmake-and-ccache-on-GitHub-Actions) for more info.
The directory where the version for a project is stored is by default the hash of the arguments to `CPMAddPackage()`.
If for instance the patch command uses external files, the directory name can be set with the argument `CUSTOM_CACHE_KEY`.
### CPM_DOWNLOAD_ALL ### CPM_DOWNLOAD_ALL
If set, CPM will forward all calls to `CPMFindPackage` as `CPMAddPackage`. If set, CPM will forward all calls to `CPMFindPackage` as `CPMAddPackage`.
@ -220,21 +188,11 @@ This can be controlled on a per package basis with the `CPM_DOWNLOAD_<dependency
### CPM_USE_LOCAL_PACKAGES ### 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`. 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. 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. 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`. 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_DONT_UPDATE_MODULE_PATH
By default, CPM will override any `find_package` commands to use the CPM downloaded version.
This is equivalent to the `OVERRIDE_FIND_PACKAGE` FetchContent option, which has no effect in CPM.
To disable this behaviour set the `CPM_DONT_UPDATE_MODULE_PATH` option.
This will not work for `find_package(CONFIG)` in CMake versions before 3.24.
### CPM_USE_NAMED_CACHE_DIRECTORIES ### 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. 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.
@ -343,58 +301,6 @@ If you know others, feel free to add them here through a PR.
</a> </a>
</td> </td>
</tr> </tr>
<tr>
<td>
<a href="https://github.com/jhasse/jngl">
<p align="center">
<img src="https://github.com/jhasse/jngl/raw/master/doc/jngl-logo.svg" alt="JNGL" width="100pt" />
</p>
<p align="center"><b>JNGL - easy to use cross-platform 2D game library</b></p>
</a>
</td>
<td>
<a href="https://github.com/sillydan1/aaltitoad">
<p align="center">
<img src="https://github.com/sillydan1/aaltitoad/raw/v1.1.0/.github/resources/logo/toad_only.svg" alt="aaltitoad" width="100pt" />
</p>
<p align="center"><b>AALTITOAD - verifier and simulator for Tick Tock Automata</b></p>
</a>
</td>
<td>
<a href="https://github.com/ZIMO-Elektronik">
<p align="center">
<img src="https://avatars.githubusercontent.com/u/117935012?s=400&u=9a871a46dd13437f0adcae166e9efbe518ff0b99&v=4" alt="ZIMO-Elektronik" width="100pt" />
</p>
<p align="center"><b>ZIMO-Elektronik</b></p>
</a>
</td>
</tr>
<tr>
<td>
<a href="https://github.com/ada-url/ada">
<p align="center">
<img src="https://avatars.githubusercontent.com/u/120840559?s=200&v=4" alt="ada" width="100pt" />
</p>
<p align="center"><b>ada - WHATWG-compliant and fast URL parser written in modern C++</b></p>
</a>
</td>
<td>
<a href="https://github.com/exaloop/codon">
<p align="center">
<img src="https://github.com/exaloop/codon/blob/develop/docs/img/logo.png?raw=true" alt="codon" width="100pt" />
</p>
<p align="center"><b>codon - A high-performance, zero-overhead, extensible Python compiler using LLVM</b></p>
</a>
</td>
<td>
<a href="https://github.com/RoaringBitmap/CRoaring">
<p align="center">
<img src="https://avatars.githubusercontent.com/u/16548876?s=200&v=4" alt="CRoaring" width="100pt" />
</p>
<p align="center"><b>CRoaring - Roaring bitmaps in C (and C++), with SIMD (AVX2, AVX-512 and NEON) optimizations: used by Apache Doris, ClickHouse, and StarRocks</b></p>
</a>
</td>
</tr>
</table> </table>
## Snippets ## Snippets
@ -425,38 +331,34 @@ CPMAddPackage("gh:jbeder/yaml-cpp#yaml-cpp-0.6.3@0.6.3")
```cmake ```cmake
CPMAddPackage( CPMAddPackage(
URI "gh:nlohmann/json@3.9.1" NAME nlohmann_json
OPTIONS "JSON_BuildTests OFF" VERSION 3.9.1
GITHUB_REPOSITORY nlohmann/json
OPTIONS
"JSON_BuildTests OFF"
) )
``` ```
### [Boost](https://github.com/boostorg/boost) ### [Boost ](https://github.com/boostorg/boost)
Boost is a large project and will take a while to download. Using
`CPM_SOURCE_CACHE` is strongly recommended. Cloning moves much more
data than a source archive, so this sample will use a compressed
source archive (tar.xz) release from Boost's github page.
```CMake ```CMake
# boost is a huge project and directly downloading the 'alternate release' # boost is a huge project and will take a while to download
# from github is much faster than recursively cloning the repo. # using `CPM_SOURCE_CACHE` is strongly recommended
CPMAddPackage( CPMAddPackage(
NAME Boost NAME Boost
VERSION 1.84.0 VERSION 1.77.0
URL https://github.com/boostorg/boost/releases/download/boost-1.84.0/boost-1.84.0.tar.xz GITHUB_REPOSITORY "boostorg/boost"
URL_HASH SHA256=2e64e5d79a738d0fa6fb546c6e5c2bd28f88d268a2a080546f74e5ff98f29d0e GIT_TAG "boost-1.77.0"
OPTIONS "BOOST_ENABLE_CMAKE ON"
) )
``` ```
For a working example of using CPM to download and configure the Boost C++ Libraries see [here](examples/boost).
### [cxxopts](https://github.com/jarro2783/cxxopts) ### [cxxopts](https://github.com/jarro2783/cxxopts)
```cmake ```cmake
# the install option has to be explicitly set to allow installation # the install option has to be explicitly set to allow installation
CPMAddPackage( CPMAddPackage(
URI "gh:jarro2783/cxxopts@2.2.1" GITHUB_REPOSITORY jarro2783/cxxopts
VERSION 2.2.1
OPTIONS "CXXOPTS_BUILD_EXAMPLES NO" "CXXOPTS_BUILD_TESTS NO" "CXXOPTS_ENABLE_INSTALL YES" OPTIONS "CXXOPTS_BUILD_EXAMPLES NO" "CXXOPTS_BUILD_TESTS NO" "CXXOPTS_ENABLE_INSTALL YES"
) )
``` ```
@ -465,7 +367,9 @@ CPMAddPackage(
```cmake ```cmake
CPMAddPackage( CPMAddPackage(
URI "gh:google/benchmark@1.5.2" NAME benchmark
GITHUB_REPOSITORY google/benchmark
VERSION 1.5.2
OPTIONS "BENCHMARK_ENABLE_TESTING Off" OPTIONS "BENCHMARK_ENABLE_TESTING Off"
) )
@ -504,85 +408,3 @@ For a full example on using CPM to download and configure lua with sol2 see [her
### Full Examples ### Full Examples
See the [examples directory](https://github.com/cpm-cmake/CPM.cmake/tree/master/examples) for full examples with source code and check out the [wiki](https://github.com/cpm-cmake/CPM.cmake/wiki/More-Snippets) for many more example snippets. See the [examples directory](https://github.com/cpm-cmake/CPM.cmake/tree/master/examples) for full examples with source code and check out the [wiki](https://github.com/cpm-cmake/CPM.cmake/wiki/More-Snippets) for many more example snippets.
## Source Archives from GitHub
Using a compressed source archive is usually much faster than a shallow
clone. Optionally, you can verify the integrity using
[SHA256](https://en.wikipedia.org/wiki/SHA-2) or similar. Setting the hash is useful to ensure a
specific source is imported, especially since tags, branches, and
archives can change.
Let's look at adding [spdlog](https://github.com/gabime/spdlog) to a project:
```cmake
CPMAddPackage(
NAME spdlog
URL https://github.com/gabime/spdlog/archive/refs/tags/v1.12.0.zip
URL_HASH SHA256=6174bf8885287422a6c6a0312eb8a30e8d22bcfcee7c48a6d02d1835d7769232
)
```
URL_HASH is optional, but it's a good idea for releases.
### Identifying the URL
Information for determining the URL is found
[here](https://docs.github.com/en/repositories/working-with-files/using-files/downloading-source-code-archives#source-code-archive-urls).
#### Release
Not every software package provides releases, but for those that do,
they can be found on the release page of the project. In a browser,
the URL of the specific release is determined in a browser is
determined by right clicking and selecting `Copy link address` (or
similar) for the desired release. This is the value you will use in
the URL section.
This is the URL for spdlog release 1.13.0 in zip format:
`https://github.com/gabime/spdlog/archive/refs/tags/v1.13.0.zip`
#### Branch
The URL for branches is non-obvious from a browser. But it's still fairly easy to figure it out. The format is as follows:
`https://github.com/<user>/<name>/archive/refs/heads/<branch-name>.<archive-type>`
Archive type can be one of `tar.gz` or `zip`.
The URL for branch `v2.x` of spdlog is:
`https://github.com/gabime/spdlog/archive/refs/heads/v2.x.tar.gz`
#### Tag
Tags are similar, but with this format:
`https://github.com/<user>/<name>/archive/refs/tags/<tag-name>.<archive-type>`
Tag `v1.8.5` of spdlog is this:
`https://github.com/gabime/spdlog/archive/refs/tags/v1.8.5.tar.gz`
Exactly like the release.
#### Commit
If a specific commit contains the code you need, it's defined as follows:
`https://github.com/<user>/<name>/archive/<commit-hash>.<archive-type>`
Example:
`https://github.com/gabime/spdlog/archive/c1569a3d293a6b511ecb9c18b2298826c9578d9f.tar.gz`
### Determining the Hash
The following snippet illustrates determining the SHA256 hash on a linux machine using `wget` and `sha256sum`:
```bash
wget https://github.com/gabime/spdlog/archive/refs/tags/v1.13.0.zip -O - | sha256sum
```

View File

@ -1,75 +0,0 @@
parse:
additional_commands:
cpmaddpackage:
pargs:
nargs: '*'
flags: []
spelling: CPMAddPackage
kwargs: &cpmaddpackagekwargs
NAME: 1
FORCE: 1
VERSION: 1
GIT_TAG: 1
DOWNLOAD_ONLY: 1
GITHUB_REPOSITORY: 1
GITLAB_REPOSITORY: 1
GIT_REPOSITORY: 1
SVN_REPOSITORY: 1
SVN_REVISION: 1
SOURCE_DIR: 1
DOWNLOAD_COMMAND: 1
FIND_PACKAGE_ARGUMENTS: 1
NO_CACHE: 1
GIT_SHALLOW: 1
URL: 1
URL_HASH: 1
URL_MD5: 1
DOWNLOAD_NAME: 1
DOWNLOAD_NO_EXTRACT: 1
HTTP_USERNAME: 1
HTTP_PASSWORD: 1
EXCLUDE_FROM_ALL: 1
SYSTEM: 1
SOURCE_SUBDIR: 1
PATCHES: +
OPTIONS: +
cpmfindpackage:
pargs:
nargs: '*'
flags: []
spelling: CPMFindPackage
kwargs: *cpmaddpackagekwargs
cpmdeclarepackage:
pargs:
nargs: '*'
flags: []
spelling: CPMDeclarePackage
kwargs: *cpmaddpackagekwargs
packageproject:
pargs:
nargs: '*'
flags: []
spelling: packageProject
kwargs:
NAME: 1
VERSION: 1
NAMESPACE: 1
INCLUDE_DIR: 1
INCLUDE_DESTINATION: 1
INCLUDE_HEADER_PATTERN: 1
BINARY_DIR: 1
COMPATIBILITY: 1
VERSION_HEADER: 1
EXPORT_HEADER: 1
DISABLE_VERSION_SUFFIX: 1
CPACK: 1
DEPENDENCIES: +
cpmusepackagelock:
pargs: 1
spelling: CPMUsePackageLock
cpmregisterpackage:
pargs: 1
spelling: CPMRegisterPackage
cpmgetpackageversion:
pargs: 2
spelling: CPMGetPackageVersion

View File

@ -5,7 +5,7 @@
# MIT License # MIT License
# ----------- # -----------
#[[ #[[
Copyright (c) 2019-2023 Lars Melchior and contributors Copyright (c) 2019-2022 Lars Melchior and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -28,25 +28,24 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR) cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
# Initialize logging prefix # the policy allows us to change options without caching
if(NOT CPM_INDENT) cmake_policy(SET CMP0077 NEW)
set(CPM_INDENT set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
"CPM:"
CACHE INTERNAL "" # the policy allows us to change set(CACHE) without caching
) if(POLICY CMP0126)
cmake_policy(SET CMP0126 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0126 NEW)
endif() endif()
if(NOT COMMAND cpm_message) # The policy uses the download time for timestamp, instead of the timestamp in the archive. This
function(cpm_message) # allows for proper rebuilds when a projects url changes
message(${ARGV}) if(POLICY CMP0135)
endfunction() cmake_policy(SET CMP0135 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0135 NEW)
endif() endif()
if(DEFINED EXTRACTED_CPM_VERSION) set(CURRENT_CPM_VERSION 1.0.0-development-version)
set(CURRENT_CPM_VERSION "${EXTRACTED_CPM_VERSION}${CPM_DEVELOPMENT}")
else()
set(CURRENT_CPM_VERSION 1.0.0-development-version)
endif()
get_filename_component(CPM_CURRENT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" REALPATH) get_filename_component(CPM_CURRENT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" REALPATH)
if(CPM_DIRECTORY) if(CPM_DIRECTORY)
@ -77,8 +76,7 @@ See https://github.com/cpm-cmake/CPM.cmake for more information."
endif() endif()
if(CURRENT_CPM_VERSION MATCHES "development-version") if(CURRENT_CPM_VERSION MATCHES "development-version")
message( message(WARNING "Your project is using an unstable development version of CPM.cmake. \
WARNING "${CPM_INDENT} Your project is using an unstable development version of CPM.cmake. \
Please update to a recent release if possible. \ Please update to a recent release if possible. \
See https://github.com/cpm-cmake/CPM.cmake for details." See https://github.com/cpm-cmake/CPM.cmake for details."
) )
@ -86,32 +84,6 @@ endif()
set_property(GLOBAL PROPERTY CPM_INITIALIZED true) set_property(GLOBAL PROPERTY CPM_INITIALIZED true)
macro(cpm_set_policies)
# the policy allows us to change options without caching
cmake_policy(SET CMP0077 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
# the policy allows us to change set(CACHE) without caching
if(POLICY CMP0126)
cmake_policy(SET CMP0126 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0126 NEW)
endif()
# The policy uses the download time for timestamp, instead of the timestamp in the archive. This
# allows for proper rebuilds when a projects url changes
if(POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0135 NEW)
endif()
# treat relative git repository paths as being relative to the parent project's remote
if(POLICY CMP0150)
cmake_policy(SET CMP0150 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0150 NEW)
endif()
endmacro()
cpm_set_policies()
option(CPM_USE_LOCAL_PACKAGES "Always try to use `find_package` to get dependencies" option(CPM_USE_LOCAL_PACKAGES "Always try to use `find_package` to get dependencies"
$ENV{CPM_USE_LOCAL_PACKAGES} $ENV{CPM_USE_LOCAL_PACKAGES}
) )
@ -166,7 +138,7 @@ set(CPM_SOURCE_CACHE
CACHE PATH "Directory to download CPM dependencies" CACHE PATH "Directory to download CPM dependencies"
) )
if(NOT CPM_DONT_UPDATE_MODULE_PATH AND NOT DEFINED CMAKE_FIND_PACKAGE_REDIRECTS_DIR) if(NOT CPM_DONT_UPDATE_MODULE_PATH)
set(CPM_MODULE_PATH set(CPM_MODULE_PATH
"${CMAKE_BINARY_DIR}/CPM_modules" "${CMAKE_BINARY_DIR}/CPM_modules"
CACHE INTERNAL "" CACHE INTERNAL ""
@ -202,60 +174,6 @@ function(cpm_package_name_from_git_uri URI RESULT)
endif() endif()
endfunction() endfunction()
# Find the shortest hash that can be used eg, if origin_hash is
# cccb77ae9609d2768ed80dd42cec54f77b1f1455 the following files will be checked, until one is found
# that is either empty (allowing us to assign origin_hash), or whose contents matches ${origin_hash}
#
# * .../cccb.hash
# * .../cccb77ae.hash
# * .../cccb77ae9609.hash
# * .../cccb77ae9609d276.hash
# * etc
#
# We will be able to use a shorter path with very high probability, but in the (rare) event that the
# first couple characters collide, we will check longer and longer substrings.
function(cpm_get_shortest_hash source_cache_dir origin_hash short_hash_output_var)
# for compatibility with caches populated by a previous version of CPM, check if a directory using
# the full hash already exists
if(EXISTS "${source_cache_dir}/${origin_hash}")
set(${short_hash_output_var}
"${origin_hash}"
PARENT_SCOPE
)
return()
endif()
foreach(len RANGE 4 40 4)
string(SUBSTRING "${origin_hash}" 0 ${len} short_hash)
set(hash_lock ${source_cache_dir}/${short_hash}.lock)
set(hash_fp ${source_cache_dir}/${short_hash}.hash)
# Take a lock, so we don't have a race condition with another instance of cmake. We will release
# this lock when we can, however, if there is an error, we want to ensure it gets released on
# it's own on exit from the function.
file(LOCK ${hash_lock} GUARD FUNCTION)
# Load the contents of .../${short_hash}.hash
file(TOUCH ${hash_fp})
file(READ ${hash_fp} hash_fp_contents)
if(hash_fp_contents STREQUAL "")
# Write the origin hash
file(WRITE ${hash_fp} ${origin_hash})
file(LOCK ${hash_lock} RELEASE)
break()
elseif(hash_fp_contents STREQUAL origin_hash)
file(LOCK ${hash_lock} RELEASE)
break()
else()
file(LOCK ${hash_lock} RELEASE)
endif()
endforeach()
set(${short_hash_output_var}
"${short_hash}"
PARENT_SCOPE
)
endfunction()
# Try to infer package name and version from a url # Try to infer package name and version from a url
function(cpm_package_name_and_ver_from_url url outName outVer) function(cpm_package_name_and_ver_from_url url outName outVer)
if(url MATCHES "[/\\?]([a-zA-Z0-9_\\.-]+)\\.(tar|tar\\.gz|tar\\.bz2|zip|ZIP)(\\?|/|$)") if(url MATCHES "[/\\?]([a-zA-Z0-9_\\.-]+)\\.(tar|tar\\.gz|tar\\.bz2|zip|ZIP)(\\?|/|$)")
@ -302,14 +220,19 @@ function(cpm_package_name_and_ver_from_url url outName outVer)
endif() endif()
endfunction() endfunction()
# Initialize logging prefix
if(NOT CPM_INDENT)
set(CPM_INDENT
"CPM:"
CACHE INTERNAL ""
)
endif()
function(cpm_find_package NAME VERSION) function(cpm_find_package NAME VERSION)
string(REPLACE " " ";" EXTRA_ARGS "${ARGN}") string(REPLACE " " ";" EXTRA_ARGS "${ARGN}")
find_package(${NAME} ${VERSION} ${EXTRA_ARGS} QUIET) find_package(${NAME} ${VERSION} ${EXTRA_ARGS} QUIET)
if(${CPM_ARGS_NAME}_FOUND) if(${CPM_ARGS_NAME}_FOUND)
if(DEFINED ${CPM_ARGS_NAME}_VERSION) message(STATUS "${CPM_INDENT} using local package ${CPM_ARGS_NAME}@${VERSION}")
set(VERSION ${${CPM_ARGS_NAME}_VERSION})
endif()
cpm_message(STATUS "${CPM_INDENT} Using local package ${CPM_ARGS_NAME}@${VERSION}")
CPMRegisterPackage(${CPM_ARGS_NAME} "${VERSION}") CPMRegisterPackage(${CPM_ARGS_NAME} "${VERSION}")
set(CPM_PACKAGE_FOUND set(CPM_PACKAGE_FOUND
YES YES
@ -327,25 +250,10 @@ endfunction()
# finding the system library # finding the system library
function(cpm_create_module_file Name) function(cpm_create_module_file Name)
if(NOT CPM_DONT_UPDATE_MODULE_PATH) if(NOT CPM_DONT_UPDATE_MODULE_PATH)
if(DEFINED CMAKE_FIND_PACKAGE_REDIRECTS_DIR) # erase any previous modules
# Redirect find_package calls to the CPM package. This is what FetchContent does when you set file(WRITE ${CPM_MODULE_PATH}/Find${Name}.cmake
# OVERRIDE_FIND_PACKAGE. The CMAKE_FIND_PACKAGE_REDIRECTS_DIR works for find_package in CONFIG "include(\"${CPM_FILE}\")\n${ARGN}\nset(${Name}_FOUND TRUE)"
# mode, unlike the Find${Name}.cmake fallback. CMAKE_FIND_PACKAGE_REDIRECTS_DIR is not defined )
# in script mode, or in CMake < 3.24.
# https://cmake.org/cmake/help/latest/module/FetchContent.html#fetchcontent-find-package-integration-examples
string(TOLOWER ${Name} NameLower)
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/${NameLower}-config.cmake
"include(\"\${CMAKE_CURRENT_LIST_DIR}/${NameLower}-extra.cmake\" OPTIONAL)\n"
"include(\"\${CMAKE_CURRENT_LIST_DIR}/${Name}Extra.cmake\" OPTIONAL)\n"
)
file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/${NameLower}-config-version.cmake
"set(PACKAGE_VERSION_COMPATIBLE TRUE)\n" "set(PACKAGE_VERSION_EXACT TRUE)\n"
)
else()
file(WRITE ${CPM_MODULE_PATH}/Find${Name}.cmake
"include(\"${CPM_FILE}\")\n${ARGN}\nset(${Name}_FOUND TRUE)"
)
endif()
endif() endif()
endfunction() endfunction()
@ -373,6 +281,12 @@ function(CPMFindPackage)
return() return()
endif() endif()
cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}")
if(CPM_PACKAGE_ALREADY_ADDED)
cpm_export_variables(${CPM_ARGS_NAME})
return()
endif()
cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS}) cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS})
if(NOT CPM_PACKAGE_FOUND) if(NOT CPM_PACKAGE_FOUND)
@ -389,7 +303,7 @@ function(cpm_check_if_package_already_added CPM_ARGS_NAME CPM_ARGS_VERSION)
if("${CPM_PACKAGE_VERSION}" VERSION_LESS "${CPM_ARGS_VERSION}") if("${CPM_PACKAGE_VERSION}" VERSION_LESS "${CPM_ARGS_VERSION}")
message( message(
WARNING WARNING
"${CPM_INDENT} Requires a newer version of ${CPM_ARGS_NAME} (${CPM_ARGS_VERSION}) than currently included (${CPM_PACKAGE_VERSION})." "${CPM_INDENT} requires a newer version of ${CPM_ARGS_NAME} (${CPM_ARGS_VERSION}) than currently included (${CPM_PACKAGE_VERSION})."
) )
endif() endif()
cpm_get_fetch_properties(${CPM_ARGS_NAME}) cpm_get_fetch_properties(${CPM_ARGS_NAME})
@ -446,7 +360,7 @@ function(cpm_parse_add_package_single_arg arg outArgs)
set(packageType "git") set(packageType "git")
else() else()
# Give up # Give up
message(FATAL_ERROR "${CPM_INDENT} Can't determine package type of '${arg}'") message(FATAL_ERROR "CPM: Can't determine package type of '${arg}'")
endif() endif()
endif() endif()
@ -464,9 +378,9 @@ function(cpm_parse_add_package_single_arg arg outArgs)
# We don't try to parse the version if it's not provided explicitly. cpm_get_version_from_url # We don't try to parse the version if it's not provided explicitly. cpm_get_version_from_url
# should do this at a later point # should do this at a later point
else() else()
# We should never get here. This is an assertion and hitting it means there's a problem with the # We should never get here. This is an assertion and hitting it means there's a bug in the code
# code above. A packageType was set, but not handled by this if-else. # above. A packageType was set, but not handled by this if-else.
message(FATAL_ERROR "${CPM_INDENT} Unsupported package type '${packageType}' of '${arg}'") message(FATAL_ERROR "CPM: Unsupported package type '${packageType}' of '${arg}'")
endif() endif()
set(${outArgs} set(${outArgs}
@ -499,7 +413,7 @@ function(cpm_check_git_working_dir_is_clean repoPath gitTag isClean)
) )
if(resultGitStatus) if(resultGitStatus)
# not supposed to happen, assume clean anyway # not supposed to happen, assume clean anyway
message(WARNING "${CPM_INDENT} Calling git status on folder ${repoPath} failed") message(WARNING "Calling git status on folder ${repoPath} failed")
set(${isClean} set(${isClean}
TRUE TRUE
PARENT_SCOPE PARENT_SCOPE
@ -537,72 +451,6 @@ function(cpm_check_git_working_dir_is_clean repoPath gitTag isClean)
endfunction() endfunction()
# Add PATCH_COMMAND to CPM_ARGS_UNPARSED_ARGUMENTS. This method consumes a list of files in ARGN
# then generates a `PATCH_COMMAND` appropriate for `ExternalProject_Add()`. This command is appended
# to the parent scope's `CPM_ARGS_UNPARSED_ARGUMENTS`.
function(cpm_add_patches)
# Return if no patch files are supplied.
if(NOT ARGN)
return()
endif()
# Find the patch program.
find_program(PATCH_EXECUTABLE patch)
if(CMAKE_HOST_WIN32 AND NOT PATCH_EXECUTABLE)
# The Windows git executable is distributed with patch.exe. Find the path to the executable, if
# it exists, then search `../usr/bin` and `../../usr/bin` for patch.exe.
find_package(Git QUIET)
if(GIT_EXECUTABLE)
get_filename_component(extra_search_path ${GIT_EXECUTABLE} DIRECTORY)
get_filename_component(extra_search_path_1up ${extra_search_path} DIRECTORY)
get_filename_component(extra_search_path_2up ${extra_search_path_1up} DIRECTORY)
find_program(
PATCH_EXECUTABLE patch HINTS "${extra_search_path_1up}/usr/bin"
"${extra_search_path_2up}/usr/bin"
)
endif()
endif()
if(NOT PATCH_EXECUTABLE)
message(FATAL_ERROR "Couldn't find `patch` executable to use with PATCHES keyword.")
endif()
# Create a temporary
set(temp_list ${CPM_ARGS_UNPARSED_ARGUMENTS})
# Ensure each file exists (or error out) and add it to the list.
set(first_item True)
foreach(PATCH_FILE ${ARGN})
# Make sure the patch file exists, if we can't find it, try again in the current directory.
if(NOT EXISTS "${PATCH_FILE}")
if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/${PATCH_FILE}")
message(FATAL_ERROR "Couldn't find patch file: '${PATCH_FILE}'")
endif()
set(PATCH_FILE "${CMAKE_CURRENT_LIST_DIR}/${PATCH_FILE}")
endif()
# Convert to absolute path for use with patch file command.
get_filename_component(PATCH_FILE "${PATCH_FILE}" ABSOLUTE)
# The first patch entry must be preceded by "PATCH_COMMAND" while the following items are
# preceded by "&&".
if(first_item)
set(first_item False)
list(APPEND temp_list "PATCH_COMMAND")
else()
list(APPEND temp_list "&&")
endif()
# Add the patch command to the list
list(APPEND temp_list "${PATCH_EXECUTABLE}" "-p1" "<" "${PATCH_FILE}")
endforeach()
# Move temp out into parent scope.
set(CPM_ARGS_UNPARSED_ARGUMENTS
${temp_list}
PARENT_SCOPE
)
endfunction()
# method to overwrite internal FetchContent properties, to allow using CPM.cmake to overload # method to overwrite internal FetchContent properties, to allow using CPM.cmake to overload
# FetchContent calls. As these are internal cmake properties, this method should be used carefully # FetchContent calls. As these are internal cmake properties, this method should be used carefully
# and may need modification in future CMake versions. Source: # and may need modification in future CMake versions. Source:
@ -610,7 +458,7 @@ endfunction()
function(cpm_override_fetchcontent contentName) function(cpm_override_fetchcontent contentName)
cmake_parse_arguments(PARSE_ARGV 1 arg "" "SOURCE_DIR;BINARY_DIR" "") cmake_parse_arguments(PARSE_ARGV 1 arg "" "SOURCE_DIR;BINARY_DIR" "")
if(NOT "${arg_UNPARSED_ARGUMENTS}" STREQUAL "") if(NOT "${arg_UNPARSED_ARGUMENTS}" STREQUAL "")
message(FATAL_ERROR "${CPM_INDENT} Unsupported arguments: ${arg_UNPARSED_ARGUMENTS}") message(FATAL_ERROR "Unsupported arguments: ${arg_UNPARSED_ARGUMENTS}")
endif() endif()
string(TOLOWER ${contentName} contentNameLower) string(TOLOWER ${contentName} contentNameLower)
@ -646,7 +494,14 @@ endfunction()
# Download and add a package from source # Download and add a package from source
function(CPMAddPackage) function(CPMAddPackage)
cpm_set_policies()
list(LENGTH ARGN argnLength)
if(argnLength EQUAL 1)
cpm_parse_add_package_single_arg("${ARGN}" ARGN)
# The shorthand syntax implies EXCLUDE_FROM_ALL
set(ARGN "${ARGN};EXCLUDE_FROM_ALL;YES")
endif()
set(oneValueArgs set(oneValueArgs
NAME NAME
@ -659,37 +514,20 @@ function(CPMAddPackage)
BITBUCKET_REPOSITORY BITBUCKET_REPOSITORY
GIT_REPOSITORY GIT_REPOSITORY
SOURCE_DIR SOURCE_DIR
DOWNLOAD_COMMAND
FIND_PACKAGE_ARGUMENTS FIND_PACKAGE_ARGUMENTS
NO_CACHE NO_CACHE
SYSTEM
GIT_SHALLOW GIT_SHALLOW
EXCLUDE_FROM_ALL EXCLUDE_FROM_ALL
SOURCE_SUBDIR SOURCE_SUBDIR
CUSTOM_CACHE_KEY
) )
set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND PATCHES) set(multiValueArgs URL OPTIONS)
list(LENGTH ARGN argnLength)
# Parse single shorthand argument
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;")
# Parse URI shorthand argument
elseif(argnLength GREATER 1 AND "${ARGV0}" STREQUAL "URI")
list(REMOVE_AT ARGN 0 1) # remove "URI gh:<...>@version#tag"
cpm_parse_add_package_single_arg("${ARGV1}" ARGV0)
set(ARGN "${ARGV0};EXCLUDE_FROM_ALL;YES;SYSTEM;YES;${ARGN}")
endif()
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}") cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")
# Set default values for arguments # Set default values for arguments
if(NOT DEFINED CPM_ARGS_VERSION) if(NOT DEFINED CPM_ARGS_VERSION)
if(DEFINED CPM_ARGS_GIT_TAG) if(DEFINED CPM_ARGS_GIT_TAG)
cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION) cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION)
@ -755,7 +593,7 @@ function(CPMAddPackage)
if(NOT DEFINED CPM_ARGS_NAME) if(NOT DEFINED CPM_ARGS_NAME)
message( message(
FATAL_ERROR FATAL_ERROR
"${CPM_INDENT} 'NAME' was not provided and couldn't be automatically inferred for package added with arguments: '${ARGN}'" "CPM: 'NAME' was not provided and couldn't be automatically inferred for package added with arguments: '${ARGN}'"
) )
endif() endif()
@ -774,8 +612,6 @@ function(CPMAddPackage)
NAME "${CPM_ARGS_NAME}" NAME "${CPM_ARGS_NAME}"
SOURCE_DIR "${PACKAGE_SOURCE}" SOURCE_DIR "${PACKAGE_SOURCE}"
EXCLUDE_FROM_ALL "${CPM_ARGS_EXCLUDE_FROM_ALL}" EXCLUDE_FROM_ALL "${CPM_ARGS_EXCLUDE_FROM_ALL}"
SYSTEM "${CPM_ARGS_SYSTEM}"
PATCHES "${CPM_ARGS_PATCHES}"
OPTIONS "${CPM_ARGS_OPTIONS}" OPTIONS "${CPM_ARGS_OPTIONS}"
SOURCE_SUBDIR "${CPM_ARGS_SOURCE_SUBDIR}" SOURCE_SUBDIR "${CPM_ARGS_SOURCE_SUBDIR}"
DOWNLOAD_ONLY "${DOWNLOAD_ONLY}" DOWNLOAD_ONLY "${DOWNLOAD_ONLY}"
@ -796,21 +632,19 @@ function(CPMAddPackage)
return() return()
endif() endif()
if(NOT CPM_ARGS_FORCE) if(CPM_USE_LOCAL_PACKAGES OR CPM_LOCAL_PACKAGES_ONLY)
if(CPM_USE_LOCAL_PACKAGES OR CPM_LOCAL_PACKAGES_ONLY) cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS})
cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS})
if(CPM_PACKAGE_FOUND) if(CPM_PACKAGE_FOUND)
cpm_export_variables(${CPM_ARGS_NAME}) cpm_export_variables(${CPM_ARGS_NAME})
return() return()
endif() endif()
if(CPM_LOCAL_PACKAGES_ONLY) if(CPM_LOCAL_PACKAGES_ONLY)
message( message(
SEND_ERROR SEND_ERROR
"${CPM_INDENT} ${CPM_ARGS_NAME} not found via find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION})" "CPM: ${CPM_ARGS_NAME} not found via find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION})"
) )
endif()
endif() endif()
endif() endif()
@ -831,8 +665,6 @@ function(CPMAddPackage)
set(CPM_FETCHCONTENT_BASE_DIR ${CMAKE_BINARY_DIR}/_deps) set(CPM_FETCHCONTENT_BASE_DIR ${CMAKE_BINARY_DIR}/_deps)
endif() endif()
cpm_add_patches(${CPM_ARGS_PATCHES})
if(DEFINED CPM_ARGS_DOWNLOAD_COMMAND) if(DEFINED CPM_ARGS_DOWNLOAD_COMMAND)
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS DOWNLOAD_COMMAND ${CPM_ARGS_DOWNLOAD_COMMAND}) list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS DOWNLOAD_COMMAND ${CPM_ARGS_DOWNLOAD_COMMAND})
elseif(DEFINED CPM_ARGS_SOURCE_DIR) elseif(DEFINED CPM_ARGS_SOURCE_DIR)
@ -855,64 +687,36 @@ function(CPMAddPackage)
string(TOLOWER ${CPM_ARGS_NAME} lower_case_name) string(TOLOWER ${CPM_ARGS_NAME} lower_case_name)
set(origin_parameters ${CPM_ARGS_UNPARSED_ARGUMENTS}) set(origin_parameters ${CPM_ARGS_UNPARSED_ARGUMENTS})
list(SORT origin_parameters) list(SORT origin_parameters)
if(CPM_ARGS_CUSTOM_CACHE_KEY) if(CPM_USE_NAMED_CACHE_DIRECTORIES)
# Application set a custom unique directory name
set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${CPM_ARGS_CUSTOM_CACHE_KEY})
elseif(CPM_USE_NAMED_CACHE_DIRECTORIES)
string(SHA1 origin_hash "${origin_parameters};NEW_CACHE_STRUCTURE_TAG") string(SHA1 origin_hash "${origin_parameters};NEW_CACHE_STRUCTURE_TAG")
cpm_get_shortest_hash(
"${CPM_SOURCE_CACHE}/${lower_case_name}" # source cache directory
"${origin_hash}" # Input hash
origin_hash # Computed hash
)
set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}/${CPM_ARGS_NAME}) set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}/${CPM_ARGS_NAME})
else() else()
string(SHA1 origin_hash "${origin_parameters}") string(SHA1 origin_hash "${origin_parameters}")
cpm_get_shortest_hash(
"${CPM_SOURCE_CACHE}/${lower_case_name}" # source cache directory
"${origin_hash}" # Input hash
origin_hash # Computed hash
)
set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}) set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash})
endif() endif()
# Expand `download_directory` relative path. This is important because EXISTS doesn't work for # Expand `download_directory` relative path. This is important because EXISTS doesn't work for
# relative paths. # relative paths.
get_filename_component(download_directory ${download_directory} ABSOLUTE) get_filename_component(download_directory ${download_directory} ABSOLUTE)
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${download_directory}) list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${download_directory})
if(CPM_SOURCE_CACHE)
file(LOCK ${download_directory}/../cmake.lock)
endif()
if(EXISTS ${download_directory}) if(EXISTS ${download_directory})
if(CPM_SOURCE_CACHE)
file(LOCK ${download_directory}/../cmake.lock RELEASE)
endif()
cpm_store_fetch_properties( cpm_store_fetch_properties(
${CPM_ARGS_NAME} "${download_directory}" ${CPM_ARGS_NAME} "${download_directory}"
"${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build" "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build"
) )
cpm_get_fetch_properties("${CPM_ARGS_NAME}") cpm_get_fetch_properties("${CPM_ARGS_NAME}")
if(DEFINED CPM_ARGS_GIT_TAG AND NOT (PATCH_COMMAND IN_LIST CPM_ARGS_UNPARSED_ARGUMENTS)) if(DEFINED CPM_ARGS_GIT_TAG)
# warn if cache has been changed since checkout # warn if cache has been changed since checkout
cpm_check_git_working_dir_is_clean(${download_directory} ${CPM_ARGS_GIT_TAG} IS_CLEAN) cpm_check_git_working_dir_is_clean(${download_directory} ${CPM_ARGS_GIT_TAG} IS_CLEAN)
if(NOT ${IS_CLEAN}) if(NOT ${IS_CLEAN})
message( message(WARNING "Cache for ${CPM_ARGS_NAME} (${download_directory}) is dirty")
WARNING "${CPM_INDENT} Cache for ${CPM_ARGS_NAME} (${download_directory}) is dirty"
)
endif() endif()
endif() endif()
cpm_add_subdirectory( cpm_add_subdirectory(
"${CPM_ARGS_NAME}" "${CPM_ARGS_NAME}" "${DOWNLOAD_ONLY}"
"${DOWNLOAD_ONLY}" "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" "${${CPM_ARGS_NAME}_BINARY_DIR}"
"${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" "${CPM_ARGS_EXCLUDE_FROM_ALL}" "${CPM_ARGS_OPTIONS}"
"${${CPM_ARGS_NAME}_BINARY_DIR}"
"${CPM_ARGS_EXCLUDE_FROM_ALL}"
"${CPM_ARGS_SYSTEM}"
"${CPM_ARGS_OPTIONS}"
) )
set(PACKAGE_INFO "${PACKAGE_INFO} at ${download_directory}") set(PACKAGE_INFO "${PACKAGE_INFO} at ${download_directory}")
@ -939,9 +743,7 @@ function(CPMAddPackage)
endif() endif()
endif() endif()
if(NOT "${DOWNLOAD_ONLY}") cpm_create_module_file(${CPM_ARGS_NAME} "CPMAddPackage(\"${ARGN}\")")
cpm_create_module_file(${CPM_ARGS_NAME} "CPMAddPackage(\"${ARGN}\")")
endif()
if(CPM_PACKAGE_LOCK_ENABLED) if(CPM_PACKAGE_LOCK_ENABLED)
if((CPM_ARGS_VERSION AND NOT CPM_ARGS_SOURCE_DIR) OR CPM_INCLUDE_ALL_IN_PACKAGE_LOCK) if((CPM_ARGS_VERSION AND NOT CPM_ARGS_SOURCE_DIR) OR CPM_INCLUDE_ALL_IN_PACKAGE_LOCK)
@ -953,52 +755,20 @@ function(CPMAddPackage)
endif() endif()
endif() endif()
cpm_message( message(
STATUS "${CPM_INDENT} Adding package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION} (${PACKAGE_INFO})" STATUS "${CPM_INDENT} adding package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION} (${PACKAGE_INFO})"
) )
if(NOT CPM_SKIP_FETCH) if(NOT CPM_SKIP_FETCH)
# CMake 3.28 added EXCLUDE, SYSTEM (3.25), and SOURCE_SUBDIR (3.18) to FetchContent_Declare.
# Calling FetchContent_MakeAvailable will then internally forward these options to
# add_subdirectory. Up until these changes, we had to call FetchContent_Populate and
# add_subdirectory separately, which is no longer necessary and has been deprecated as of 3.30.
# A Bug in CMake prevents us to use the non-deprecated functions until 3.30.3.
set(fetchContentDeclareExtraArgs "")
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.30.3")
if(${CPM_ARGS_EXCLUDE_FROM_ALL})
list(APPEND fetchContentDeclareExtraArgs EXCLUDE_FROM_ALL)
endif()
if(${CPM_ARGS_SYSTEM})
list(APPEND fetchContentDeclareExtraArgs SYSTEM)
endif()
if(DEFINED CPM_ARGS_SOURCE_SUBDIR)
list(APPEND fetchContentDeclareExtraArgs SOURCE_SUBDIR ${CPM_ARGS_SOURCE_SUBDIR})
endif()
# For CMake version <3.28 OPTIONS are parsed in cpm_add_subdirectory
if(CPM_ARGS_OPTIONS AND NOT DOWNLOAD_ONLY)
foreach(OPTION ${CPM_ARGS_OPTIONS})
cpm_parse_option("${OPTION}")
set(${OPTION_KEY} "${OPTION_VALUE}")
endforeach()
endif()
endif()
cpm_declare_fetch( cpm_declare_fetch(
"${CPM_ARGS_NAME}" ${fetchContentDeclareExtraArgs} "${CPM_ARGS_UNPARSED_ARGUMENTS}" "${CPM_ARGS_NAME}" "${CPM_ARGS_VERSION}" "${PACKAGE_INFO}" "${CPM_ARGS_UNPARSED_ARGUMENTS}"
) )
cpm_fetch_package("${CPM_ARGS_NAME}" populated)
cpm_fetch_package("${CPM_ARGS_NAME}" ${DOWNLOAD_ONLY} populated ${CPM_ARGS_UNPARSED_ARGUMENTS}) if(${populated})
if(CPM_SOURCE_CACHE AND download_directory)
file(LOCK ${download_directory}/../cmake.lock RELEASE)
endif()
if(${populated} AND ${CMAKE_VERSION} VERSION_LESS "3.30.3")
cpm_add_subdirectory( cpm_add_subdirectory(
"${CPM_ARGS_NAME}" "${CPM_ARGS_NAME}" "${DOWNLOAD_ONLY}"
"${DOWNLOAD_ONLY}" "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" "${${CPM_ARGS_NAME}_BINARY_DIR}"
"${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" "${CPM_ARGS_EXCLUDE_FROM_ALL}" "${CPM_ARGS_OPTIONS}"
"${${CPM_ARGS_NAME}_BINARY_DIR}"
"${CPM_ARGS_EXCLUDE_FROM_ALL}"
"${CPM_ARGS_SYSTEM}"
"${CPM_ARGS_OPTIONS}"
) )
endif() endif()
cpm_get_fetch_properties("${CPM_ARGS_NAME}") cpm_get_fetch_properties("${CPM_ARGS_NAME}")
@ -1013,7 +783,7 @@ macro(CPMGetPackage Name)
if(DEFINED "CPM_DECLARATION_${Name}") if(DEFINED "CPM_DECLARATION_${Name}")
CPMAddPackage(NAME ${Name}) CPMAddPackage(NAME ${Name})
else() else()
message(SEND_ERROR "${CPM_INDENT} Cannot retrieve package ${Name}: no declaration available") message(SEND_ERROR "Cannot retrieve package ${Name}: no declaration available")
endif() endif()
endmacro() endmacro()
@ -1031,10 +801,6 @@ macro(cpm_export_variables name)
"${${name}_ADDED}" "${${name}_ADDED}"
PARENT_SCOPE PARENT_SCOPE
) )
set(CPM_LAST_PACKAGE_NAME
"${name}"
PARENT_SCOPE
)
endmacro() endmacro()
# declares a package, so that any call to CPMAddPackage for the package name will use these # declares a package, so that any call to CPMAddPackage for the package name will use these
@ -1101,9 +867,9 @@ function(CPMGetPackageVersion PACKAGE OUTPUT)
endfunction() endfunction()
# declares a package in FetchContent_Declare # declares a package in FetchContent_Declare
function(cpm_declare_fetch PACKAGE) function(cpm_declare_fetch PACKAGE VERSION INFO)
if(${CPM_DRY_RUN}) if(${CPM_DRY_RUN})
cpm_message(STATUS "${CPM_INDENT} Package not declared (dry run)") message(STATUS "${CPM_INDENT} package not declared (dry run)")
return() return()
endif() endif()
@ -1149,18 +915,13 @@ function(
SOURCE_DIR SOURCE_DIR
BINARY_DIR BINARY_DIR
EXCLUDE EXCLUDE
SYSTEM
OPTIONS OPTIONS
) )
if(NOT DOWNLOAD_ONLY AND EXISTS ${SOURCE_DIR}/CMakeLists.txt) if(NOT DOWNLOAD_ONLY AND EXISTS ${SOURCE_DIR}/CMakeLists.txt)
set(addSubdirectoryExtraArgs "")
if(EXCLUDE) if(EXCLUDE)
list(APPEND addSubdirectoryExtraArgs EXCLUDE_FROM_ALL) set(addSubdirectoryExtraArgs EXCLUDE_FROM_ALL)
endif() else()
if("${SYSTEM}" AND "${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.25") set(addSubdirectoryExtraArgs "")
# https://cmake.org/cmake/help/latest/prop_dir/SYSTEM.html#prop_dir:SYSTEM
list(APPEND addSubdirectoryExtraArgs SYSTEM)
endif() endif()
if(OPTIONS) if(OPTIONS)
foreach(OPTION ${OPTIONS}) foreach(OPTION ${OPTIONS})
@ -1177,13 +938,13 @@ endfunction()
# downloads a previously declared package via FetchContent and exports the variables # downloads a previously declared package via FetchContent and exports the variables
# `${PACKAGE}_SOURCE_DIR` and `${PACKAGE}_BINARY_DIR` to the parent scope # `${PACKAGE}_SOURCE_DIR` and `${PACKAGE}_BINARY_DIR` to the parent scope
function(cpm_fetch_package PACKAGE DOWNLOAD_ONLY populated) function(cpm_fetch_package PACKAGE populated)
set(${populated} set(${populated}
FALSE FALSE
PARENT_SCOPE PARENT_SCOPE
) )
if(${CPM_DRY_RUN}) if(${CPM_DRY_RUN})
cpm_message(STATUS "${CPM_INDENT} Package ${PACKAGE} not fetched (dry run)") message(STATUS "${CPM_INDENT} package ${PACKAGE} not fetched (dry run)")
return() return()
endif() endif()
@ -1192,24 +953,7 @@ function(cpm_fetch_package PACKAGE DOWNLOAD_ONLY populated)
string(TOLOWER "${PACKAGE}" lower_case_name) string(TOLOWER "${PACKAGE}" lower_case_name)
if(NOT ${lower_case_name}_POPULATED) if(NOT ${lower_case_name}_POPULATED)
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.30.3") FetchContent_Populate(${PACKAGE})
if(DOWNLOAD_ONLY)
# MakeAvailable will call add_subdirectory internally which is not what we want when
# DOWNLOAD_ONLY is set. Populate will only download the dependency without adding it to the
# build
FetchContent_Populate(
${PACKAGE}
SOURCE_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-src"
BINARY_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build"
SUBBUILD_DIR "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild"
${ARGN}
)
else()
FetchContent_MakeAvailable(${PACKAGE})
endif()
else()
FetchContent_Populate(${PACKAGE})
endif()
set(${populated} set(${populated}
TRUE TRUE
PARENT_SCOPE PARENT_SCOPE
@ -1303,17 +1047,14 @@ function(cpm_prettify_package_arguments OUT_VAR IS_IN_COMMENT)
DOWNLOAD_ONLY DOWNLOAD_ONLY
GITHUB_REPOSITORY GITHUB_REPOSITORY
GITLAB_REPOSITORY GITLAB_REPOSITORY
BITBUCKET_REPOSITORY
GIT_REPOSITORY GIT_REPOSITORY
SOURCE_DIR SOURCE_DIR
DOWNLOAD_COMMAND
FIND_PACKAGE_ARGUMENTS FIND_PACKAGE_ARGUMENTS
NO_CACHE NO_CACHE
SYSTEM
GIT_SHALLOW GIT_SHALLOW
EXCLUDE_FROM_ALL
SOURCE_SUBDIR
) )
set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND) set(multiValueArgs OPTIONS)
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
foreach(oneArgName ${oneValueArgs}) foreach(oneArgName ${oneValueArgs})

View File

@ -1,11 +1,8 @@
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
set(CPM_DOWNLOAD_VERSION 1.0.0-development-version) set(CPM_DOWNLOAD_VERSION 1.0.0-development-version)
set(CPM_HASH_SUM "CPM_HASH_SUM_PLACEHOLDER")
if(CPM_SOURCE_CACHE) if(CPM_SOURCE_CACHE)
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_SOURCE_CACHE ${CPM_SOURCE_CACHE} ABSOLUTE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE}) elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
@ -13,12 +10,12 @@ else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif() endif()
# Expand relative path. This is important if the provided path contains a tilde (~) if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
file(DOWNLOAD
file(DOWNLOAD https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake ${CPM_DOWNLOAD_LOCATION}
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} )
) endif()
include(${CPM_DOWNLOAD_LOCATION}) include(${CPM_DOWNLOAD_LOCATION})

View File

@ -32,13 +32,13 @@ function(ASSERT_DEFINED KEY)
if(DEFINED ${KEY}) if(DEFINED ${KEY})
message(STATUS "test passed: '${KEY}' is defined") message(STATUS "test passed: '${KEY}' is defined")
else() else()
message(FATAL_ERROR "assertion failed: '${KEY}' is not defined") message(FATAL_ERROR "assertion failed: '${KEY}' is not defiend")
endif() endif()
endfunction() endfunction()
function(ASSERT_NOT_DEFINED KEY) function(ASSERT_NOT_DEFINED KEY)
if(DEFINED ${KEY}) if(DEFINED ${KEY})
message(FATAL_ERROR "assertion failed: '${KEY}' is defined (${${KEY}})") message(FATAL_ERROR "assertion failed: '${KEY}' is defiend (${${KEY}})")
else() else()
message(STATUS "test passed: '${KEY}' is not defined") message(STATUS "test passed: '${KEY}' is not defined")
endif() endif()
@ -79,16 +79,3 @@ function(ASSERT_NOT_EXISTS file)
message(FATAL_ERROR "assertion failed: file ${file} exists") message(FATAL_ERROR "assertion failed: file ${file} exists")
endif() endif()
endfunction() endfunction()
function(ASSERT_CONTENTS_EQUAL file content)
if(EXISTS ${file})
file(READ ${file} file_content)
if(content STREQUAL file_content)
message(STATUS "test passed: '${file}' exists and contains '${content}'")
else()
message(FATAL_ERROR "assertion failed: file '${file}' does not contain expected content.")
endif()
else()
message(FATAL_ERROR "assertion failed: file '${file} does not exist")
endif()
endfunction()

View File

@ -11,7 +11,7 @@ CPMAddPackage("gh:cpm-cmake/testpack-fibonacci@2.0")
CPMAddPackage( CPMAddPackage(
NAME benchmark NAME benchmark
GITHUB_REPOSITORY google/benchmark GITHUB_REPOSITORY google/benchmark
VERSION 1.7.1 VERSION 1.5.2
OPTIONS "BENCHMARK_ENABLE_TESTING Off" OPTIONS "BENCHMARK_ENABLE_TESTING Off"
) )

View File

@ -13,12 +13,9 @@ include(../../cmake/CPM.cmake)
CPMAddPackage( CPMAddPackage(
NAME Boost NAME Boost
VERSION 1.86.0 # Versions less than 1.85.0 may need patches for installation targets. VERSION 1.77.0
URL https://github.com/boostorg/boost/releases/download/boost-1.86.0/boost-1.86.0-cmake.tar.xz GITHUB_REPOSITORY "boostorg/boost"
URL_HASH SHA256=2c5ec5edcdff47ff55e27ed9560b0a0b94b07bd07ed9928b476150e16b0efc57 GIT_TAG "boost-1.77.0"
OPTIONS "BOOST_ENABLE_CMAKE ON" "BOOST_SKIP_INSTALL_RULES ON" # Set `OFF` for installation
"BUILD_SHARED_LIBS OFF" "BOOST_INCLUDE_LIBRARIES container\\\;asio" # Note the escapes!
) )
# `Boost::headers` is also valid target_link_libraries(CPMExampleBoost PRIVATE Boost::asio)
target_link_libraries(CPMExampleBoost PRIVATE Boost::asio Boost::container)

View File

@ -9,22 +9,14 @@
// //
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/container/devector.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream> #include <iostream>
#include <string>
boost::container::devector<std::string> strings; void print(const boost::system::error_code& /*e*/) { std::cout << "Hello, world!" << std::endl; }
void print(const boost::system::error_code& /*e*/) {
for (const auto& a : strings) std::cout << a;
}
int main() { int main() {
boost::asio::io_service io; boost::asio::io_service io;
strings.push_back("Hello, world!\n");
boost::asio::deadline_timer t(io, boost::posix_time::seconds(1)); boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));
t.async_wait(&print); t.async_wait(&print);

View File

@ -7,12 +7,12 @@ project(CPMExampleCatch2)
include(../../cmake/CPM.cmake) include(../../cmake/CPM.cmake)
CPMAddPackage("gh:cpm-cmake/testpack-fibonacci@2.0") CPMAddPackage("gh:cpm-cmake/testpack-fibonacci@2.0")
CPMAddPackage("gh:catchorg/Catch2@3.4.0") CPMAddPackage("gh:catchorg/Catch2@2.13.4")
# ---- Create binary ---- # ---- Create binary ----
add_executable(CPMExampleCatch2 main.cpp) add_executable(CPMExampleCatch2 main.cpp)
target_link_libraries(CPMExampleCatch2 fibonacci Catch2::Catch2WithMain) target_link_libraries(CPMExampleCatch2 fibonacci Catch2)
target_compile_features(CPMExampleCatch2 PRIVATE cxx_std_17) target_compile_features(CPMExampleCatch2 PRIVATE cxx_std_17)
# ---- Enable testing ---- # ---- Enable testing ----

View File

@ -1,6 +1,8 @@
#define CATCH_CONFIG_MAIN
#include <fibonacci.h> #include <fibonacci.h>
#include <catch2/catch_test_macros.hpp> #include <catch2/catch.hpp>
TEST_CASE("fibonacci") { TEST_CASE("fibonacci") {
REQUIRE(fibonacci(0) == 0); REQUIRE(fibonacci(0) == 0);

View File

@ -7,7 +7,7 @@ project(CPMExampleDoctest)
include(../../cmake/CPM.cmake) include(../../cmake/CPM.cmake)
CPMAddPackage("gh:cpm-cmake/testpack-fibonacci@2.0") CPMAddPackage("gh:cpm-cmake/testpack-fibonacci@2.0")
CPMAddPackage("gh:onqtam/doctest@2.4.9") CPMAddPackage("gh:onqtam/doctest#2.4.5")
# ---- Create binary ---- # ---- Create binary ----

View File

@ -9,7 +9,8 @@ include(../../cmake/CPM.cmake)
CPMAddPackage( CPMAddPackage(
NAME EnTT NAME EnTT
VERSION 3.1.1 VERSION 3.1.1
GITHUB_REPOSITORY skypjack/entt # EnTT's CMakeLists screws with configuration options GITHUB_REPOSITORY skypjack/entt
# EnTT's CMakeLists screws with configuration options
DOWNLOAD_ONLY True DOWNLOAD_ONLY True
) )

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR) cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(CPMFmtExample) project(CPMJSONExample)
# ---- Dependencies ---- # ---- Dependencies ----

View File

@ -11,8 +11,8 @@ CPMAddPackage("gh:cpm-cmake/testpack-fibonacci@2.0")
CPMAddPackage( CPMAddPackage(
NAME googletest NAME googletest
GITHUB_REPOSITORY google/googletest GITHUB_REPOSITORY google/googletest
GIT_TAG release-1.12.1 GIT_TAG release-1.10.0
VERSION 1.12.1 VERSION 1.10.0
OPTIONS "INSTALL_GTEST OFF" "gtest_force_shared_crt" OPTIONS "INSTALL_GTEST OFF" "gtest_force_shared_crt"
) )

View File

@ -1,28 +0,0 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(CPMExamplePatchHighway)
# ---- Dependencies ----
include(../../cmake/CPM.cmake)
# Google's highway Includes a SIMD sorting function that is faster than x86-simd-sort for larger
# arrays. See: https://github.com/google/highway/blob/master/g3doc/quick_reference.md
CPMAddPackage(
NAME highway
URL https://github.com/google/highway/archive/refs/tags/1.1.0.tar.gz
URL_HASH SHA256=354a8b4539b588e70b98ec70844273e3f2741302c4c377bcc4e81b3d1866f7c9
PATCHES "highway.patch" # This adds SYSTEM to the includes.
OPTIONS "HWY_ENABLE_EXAMPLES OFF" "HWY_ENABLE_INSTALL OFF" "HWY_ENABLE_TESTS OFF"
)
# ---- Executable ----
if(LINUX)
# This would cause a float compare error inside the highway header code if the patch is NOT
# applied.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wfloat-equal")
endif()
add_executable(CPMExamplePatchHighway "main.cpp")
target_link_libraries(CPMExamplePatchHighway hwy hwy_contrib)

View File

@ -1,28 +0,0 @@
Common subdirectories: a/.bcr and b/.bcr
Common subdirectories: a/.github and b/.github
diff -u a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt 2024-05-21 12:50:37.738318520 -0500
+++ b/CMakeLists.txt 2024-05-21 12:49:59.914226871 -0500
@@ -350,7 +350,7 @@
target_compile_options(hwy PRIVATE ${HWY_FLAGS})
set_property(TARGET hwy PROPERTY POSITION_INDEPENDENT_CODE ON)
set_target_properties(hwy PROPERTIES VERSION ${LIBRARY_VERSION} SOVERSION ${LIBRARY_SOVERSION})
-target_include_directories(hwy PUBLIC
+target_include_directories(hwy SYSTEM PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
target_compile_features(hwy PUBLIC cxx_std_11)
@@ -370,7 +370,7 @@
target_compile_options(hwy_contrib PRIVATE ${HWY_FLAGS})
set_property(TARGET hwy_contrib PROPERTY POSITION_INDEPENDENT_CODE ON)
set_target_properties(hwy_contrib PROPERTIES VERSION ${LIBRARY_VERSION} SOVERSION ${LIBRARY_SOVERSION})
-target_include_directories(hwy_contrib PUBLIC
+target_include_directories(hwy_contrib SYSTEM PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
target_compile_features(hwy_contrib PUBLIC cxx_std_11)
Common subdirectories: a/cmake and b/cmake
Common subdirectories: a/debian and b/debian
Common subdirectories: a/docs and b/docs
Common subdirectories: a/g3doc and b/g3doc
Common subdirectories: a/hwy and b/hwy

View File

@ -1,27 +0,0 @@
#include <hwy/contrib/sort/vqsort.h> // hwy::VQSort() for large data sets
#include <cstdint>
#include <random>
#include <vector>
// Use hwy::VQSort to sort larger vectors
inline void sort_large(std::vector<double>& v) {
hwy::VQSort(v.data(), v.size(), hwy::SortAscending{});
}
int main(int, char**) {
std::random_device random_device;
std::default_random_engine random_engine(random_device());
std::uniform_real_distribution<double> uniform_dist(0.0, 100.0);
const std::size_t sz = 100000;
std::vector<double> v;
v.reserve(sz);
for (std::size_t i = 0; i < sz; ++i) {
v.push_back(uniform_dist(random_engine));
}
sort_large(v);
return 0;
}

View File

@ -56,7 +56,7 @@ int main(int argc, char **argv) {
int len = atoi(line + 11); int len = atoi(line + 11);
linenoiseHistorySetMaxLen(len); linenoiseHistorySetMaxLen(len);
} else if (line[0] == '/') { } else if (line[0] == '/') {
printf("Unrecognized command: %s\n", line); printf("Unreconized command: %s\n", line);
} }
free(line); free(line);
} }

View File

@ -1,14 +0,0 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(CPMSIMDJSONExample)
# ---- Dependencies ----
include(../../cmake/CPM.cmake)
CPMAddPackage("gh:simdjson/simdjson@3.5.0")
# ---- Executable ----
add_executable(CPMSIMDJSONExample main.cpp)
target_compile_features(CPMSIMDJSONExample PRIVATE cxx_std_17)
target_link_libraries(CPMSIMDJSONExample simdjson::simdjson)

View File

@ -1,31 +0,0 @@
#include <iostream>
#include "simdjson.h"
using namespace simdjson;
int main() {
ondemand::parser parser;
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
// Iterating through an array of objects
for (ondemand::object car : parser.iterate(cars_json)) {
// Accessing a field by name
std::cout << "Make/Model: " << std::string_view(car["make"]) << "/"
<< std::string_view(car["model"]) << std::endl;
// Casting a JSON element to an integer
uint64_t year = car["year"];
std::cout << "- This car is " << 2020 - year << " years old." << std::endl;
// Iterating through an array of floats
double total_tire_pressure = 0;
for (double tire_pressure : car["tire_pressure"]) {
total_tire_pressure += tire_pressure;
}
std::cout << "- Average tire pressure: " << (total_tire_pressure / 4) << std::endl;
}
}

View File

@ -8,29 +8,36 @@ include(../../cmake/CPM.cmake)
CPMAddPackage( CPMAddPackage(
NAME lua NAME lua
GITHUB_REPOSITORY lua/lua GIT_REPOSITORY https://github.com/lua/lua.git
VERSION 5.3.5 VERSION 5.3.5
DOWNLOAD_ONLY YES DOWNLOAD_ONLY YES
) )
if(lua_ADDED) if(lua_ADDED)
# lua has no CMakeLists, so we create our own target # lua has no CMakeLists, so we create our own target
file(GLOB lua_sources ${lua_SOURCE_DIR}/*.c) file(GLOB lua_sources ${lua_SOURCE_DIR}/*.c)
list(REMOVE_ITEM lua_sources "${lua_SOURCE_DIR}/lua.c" "${lua_SOURCE_DIR}/luac.c") list(REMOVE_ITEM lua_sources "${lua_SOURCE_DIR}/lua.c" "${lua_SOURCE_DIR}/luac.c")
add_library(lua STATIC ${lua_sources}) add_library(lua STATIC ${lua_sources})
target_include_directories(lua SYSTEM PUBLIC $<BUILD_INTERFACE:${lua_SOURCE_DIR}>) target_include_directories(lua SYSTEM PUBLIC $<BUILD_INTERFACE:${lua_SOURCE_DIR}>)
endif() endif()
CPMAddPackage( CPMAddPackage(
NAME sol2 NAME sol2
GITHUB_REPOSITORY ThePhD/sol2 URL https://github.com/ThePhD/sol2/archive/v3.0.2.zip
VERSION 3.3.0 VERSION 3.0.2
# fix for clang 18.1.0, see https://github.com/ThePhD/sol2/issues/1581#issuecomment-2103463524 DOWNLOAD_ONLY YES
PATCHES fix_for_clang.patch
) )
if(sol2_ADDED)
add_library(sol2 INTERFACE IMPORTED)
target_include_directories(sol2 SYSTEM INTERFACE ${sol2_SOURCE_DIR}/include)
target_link_libraries(sol2 INTERFACE lua)
endif()
# ---- Executable ---- # ---- Executable ----
add_executable(CPMSol2Example main.cpp) add_executable(CPMSol2Example main.cpp)
target_compile_features(CPMSol2Example PRIVATE cxx_std_17) target_compile_features(CPMSol2Example PRIVATE cxx_std_17)
target_link_libraries(CPMSol2Example sol2 lua) target_link_libraries(CPMSol2Example sol2)

View File

@ -1,18 +0,0 @@
diff -u a/include/sol/function_types_stateless.hpp b/include/types/function_types_stateless.hpp
--- a/include/sol/function_types_stateless.hpp
+++ b/include/sol/function_types_stateless.hpp
@@ -322,7 +322,13 @@ namespace sol { namespace function_detail {
}
template <bool is_yielding, bool no_trampoline>
- static int call(lua_State* L) noexcept(std::is_nothrow_copy_assignable_v<T>) {
+ static int call(lua_State* L)
+#if SOL_IS_ON(SOL_COMPILER_CLANG)
+ // apparent regression in clang 18 - llvm/llvm-project#91362
+#else
+ noexcept(std::is_nothrow_copy_assignable_v<T>)
+#endif
+ {
int nr;
if constexpr (no_trampoline) {
nr = real_call(L);

View File

@ -8,20 +8,6 @@ include(../../cmake/CPM.cmake)
CPMAddPackage("gh:gabime/spdlog@1.8.2") CPMAddPackage("gh:gabime/spdlog@1.8.2")
# spdlog uses fmt and bundles that dependency. If you want to use fmt in your project as well, you
# can let spdlog reuse fmt from CPM.cmake like this:
#
# cmake-format: off
#
# CPMAddPackage("gh:fmtlib/fmt#7.1.3")
# CPMAddPackage(
# GITHUB_REPOSITORY gabime/spdlog
# VERSION 1.8.2
# OPTIONS "SPDLOG_FMT_EXTERNAL 1"
# )
#
# cmake-format: on
# ---- Executable ---- # ---- Executable ----
add_executable(CPMSpdlogExample main.cpp) add_executable(CPMSpdlogExample main.cpp)

View File

@ -1,20 +0,0 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(CPMxxHashExample)
# ---- Dependencies ----
include(../../cmake/CPM.cmake)
CPMAddPackage(
GITHUB_REPOSITORY Cyan4973/xxHash
GIT_TAG v0.8.2
OPTIONS "XXHASH_BUILD_ENABLE_INLINE_API OFF" "XXHASH_BUILD_XXHSUM OFF"
SOURCE_SUBDIR cmake_unofficial
)
# ---- Executable ----
add_executable(CPMxxHashExample main.cpp)
target_compile_features(CPMxxHashExample PRIVATE cxx_std_17)
target_link_libraries(CPMxxHashExample xxHash::xxhash)

View File

@ -1,12 +0,0 @@
#include <xxh3.h>
#include <iostream>
int main() {
std::string example = "Hello World!";
XXH64_hash_t hash = XXH3_64bits(example.data(), example.size());
std::cout << "Hash: " << hash << std::endl;
return 0;
}

View File

@ -14,5 +14,3 @@ foreach(test ${tests})
endforeach() endforeach()
add_custom_target(test-verbose COMMAND ${CMAKE_CTEST_COMMAND} -C Debug --verbose) add_custom_target(test-verbose COMMAND ${CMAKE_CTEST_COMMAND} -C Debug --verbose)
add_subdirectory(style)

View File

@ -12,7 +12,7 @@ To run all tests from the repo root execute:
$ ruby test/integration/runner.rb $ ruby test/integration/runner.rb
``` ```
The runner will run all tests and generate a report of the execution. The runner will run all tests and generate a report of the exeuction.
The current working directory doesn't matter. If you are in `<repo-root>/test/integration`, you can run simply `$ ruby runner.rb`. The current working directory doesn't matter. If you are in `<repo-root>/test/integration`, you can run simply `$ ruby runner.rb`.
@ -34,7 +34,7 @@ Writing tests makes use of the custom integration test framework in `lib.rb`. It
* There should be no dependency between the test scripts. Each should be executable individually and the order in which multiple ones are executed mustn't matter. * There should be no dependency between the test scripts. Each should be executable individually and the order in which multiple ones are executed mustn't matter.
* The class should contain methods, also prefixed with `test_` which will be executed by the framework. In most cases there would be a single test method per class. * The class should contain methods, also prefixed with `test_` which will be executed by the framework. In most cases there would be a single test method per class.
* In case there are multiple test methods, they will be executed in the order in which they are defined. * In case there are multiple test methods, they will be executed in the order in which they are defined.
* The test methods should contain assertions which check for the expected state of things at various points of the test's execution. * The test methods should contain assertions which check for the expected state of things at varous points of the test's execution.
### More ### More

View File

@ -143,7 +143,7 @@ class Project
end end
class IntegrationTest < Test::Unit::TestCase class IntegrationTest < Test::Unit::TestCase
self.test_order = :defined # run tests in order of definition (as opposed to alphabetical) self.test_order = :defined # run tests in order of defintion (as opposed to alphabetical)
def cleanup def cleanup
# Clear cpm-related env vars which may have been set by the test # Clear cpm-related env vars which may have been set by the test
@ -157,11 +157,6 @@ class IntegrationTest < Test::Unit::TestCase
assert_block(msg) { res.status.success? } assert_block(msg) { res.status.success? }
end end
def assert_failure(res)
msg = build_message(nil, "command status was expected to be a failure, but succeeded")
assert_block(msg) { !res.status.success? }
end
def assert_same_path(a, b) def assert_same_path(a, b)
msg = build_message(nil, "<?> expected but was\n<?>", a, b) msg = build_message(nil, "<?> expected but was\n<?>", a, b)
assert_block(msg) { File.identical? a, b } assert_block(msg) { File.identical? a, b }
@ -185,20 +180,19 @@ class IntegrationTest < Test::Unit::TestCase
@@test_dir @@test_dir
end end
def make_project(name: nil, from_template: nil) def make_project(template_dir = nil)
test_name = local_name test_name = local_name
test_name = test_name[5..] if test_name.start_with?('test_') test_name = test_name[5..] if test_name.start_with?('test_')
base = File.join(cur_test_dir, test_name) base = File.join(cur_test_dir, test_name)
base += "-#{name}" if name
src_dir = base + '-src' src_dir = base + '-src'
FileUtils.mkdir_p src_dir FileUtils.mkdir_p src_dir
if from_template if template_dir
from_template = File.join(TestLib::TEMPLATES_DIR, from_template) template_dir = File.join(TestLib::TEMPLATES_DIR, template_dir)
raise "#{from_template} is not a directory" if !File.directory?(from_template) raise "#{template_dir} is not a directory" if !File.directory?(template_dir)
FileUtils.copy_entry from_template, src_dir FileUtils.copy_entry template_dir, src_dir
end end
Project.new src_dir, base + '-bin' Project.new src_dir, base + '-bin'

View File

@ -1,4 +1,4 @@
# Integration Test Framework Reference # Integration Test Framework Refernce
## `TestLib` ## `TestLib`
@ -60,7 +60,6 @@ The class which must be a parent of all integration test case classes. It itself
### Utils ### Utils
* `cur_test_dir` - the directory of the current test case. A subdirectory of `TestLib::TMP_DIR` * `cur_test_dir` - the directory of the current test case. A subdirectory of `TestLib::TMP_DIR`
* `make_project(name: nil, from_template: nil)` - create a project from a test method. Will create the project's source and binary directories as subdirectories of `cur_test_dir`. * `make_project(template_dir = nil)` - create a project from a test method. Will create a the project's source and binary directories as subdirectories of `cur_test_dir`.
* Optionally provide a name which will be concatenated to the project directory. This allows creating multiple projects in a test * Optionally work with a template directory, in which case it will copy the contents of the template directory (one from `templates`) in the project's source directory.
* Optionally work with a template, in which case it will copy the contents of the template directory (one from `templates`) in the project's source directory.

View File

@ -1,13 +0,0 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(using-patch-adder)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
include("%{cpm_path}")
%{packages}
add_executable(using-patch-adder using-patch-adder.cpp)
target_link_libraries(using-patch-adder adder)

View File

@ -1,12 +0,0 @@
diff --git a/code/adder/adder.hpp b/code/adder/adder.hpp
index fdb9324..7c2fa00 100644
--- a/code/adder/adder.hpp
+++ b/code/adder/adder.hpp
@@ -1,6 +1,6 @@
#pragma once
-namespace adder
+namespace patched
{
int add(int a, int b);
}

View File

@ -1,12 +0,0 @@
diff --git a/code/adder/adder.cpp b/code/adder/adder.cpp
index fc6e767..44b1197 100644
--- a/code/adder/adder.cpp
+++ b/code/adder/adder.cpp
@@ -1,6 +1,6 @@
#include "adder.hpp"
-namespace adder
+namespace patched
{
int add(int a, int b)
{

View File

@ -1,8 +0,0 @@
#include <adder/adder.hpp>
#include <cstdio>
int main() {
int sum = patched::add(5, 3);
std::printf("%d\n", sum);
return 0;
}

View File

@ -5,7 +5,7 @@ require_relative './lib'
class Basics < IntegrationTest class Basics < IntegrationTest
# Test cpm caches with no cpm-related env vars # Test cpm caches with no cpm-related env vars
def test_cpm_default def test_cpm_default
prj = make_project from_template: 'no-deps' prj = make_project 'no-deps'
prj.create_lists_from_default_template prj.create_lists_from_default_template
assert_success prj.configure assert_success prj.configure
@ -31,16 +31,14 @@ class Basics < IntegrationTest
assert_same_path File.join(prj.bin_dir, 'cpm-package-lock.cmake'), check_and_get('CPM_PACKAGE_LOCK_FILE') assert_same_path File.join(prj.bin_dir, 'cpm-package-lock.cmake'), check_and_get('CPM_PACKAGE_LOCK_FILE')
assert_equal 'OFF', check_and_get('CPM_DONT_UPDATE_MODULE_PATH', 'BOOL') assert_equal 'OFF', check_and_get('CPM_DONT_UPDATE_MODULE_PATH', 'BOOL')
if @cache.entries['CMAKE_FIND_PACKAGE_REDIRECTS_DIR'].nil? assert_same_path File.join(prj.bin_dir, 'CPM_modules'), check_and_get('CPM_MODULE_PATH')
assert_same_path File.join(prj.bin_dir, 'CPM_modules'), check_and_get('CPM_MODULE_PATH')
end
end end
# Test when env CPM_SOURCE_CACHE is set # Test when env CPM_SOURCE_CACHE is set
def test_env_cpm_source_cache def test_env_cpm_source_cache
ENV['CPM_SOURCE_CACHE'] = cur_test_dir ENV['CPM_SOURCE_CACHE'] = cur_test_dir
prj = make_project from_template: 'no-deps' prj = make_project 'no-deps'
prj.create_lists_from_default_template prj.create_lists_from_default_template
assert_success prj.configure assert_success prj.configure

View File

@ -1,25 +0,0 @@
require_relative './lib'
# Tests using a multi-argumenet download command to fetch a dependency
class DownloadCommand < IntegrationTest
def test_fetch_dependency_using_download_command
prj = make_project from_template: 'using-adder'
prj.create_lists_from_default_template package: <<~PACK
set(DOWNLOAD_DIR ${CMAKE_BINARY_DIR}/_deps/testpack-adder-src)
CPMAddPackage(
NAME testpack-adder
SOURCE_DIR ${DOWNLOAD_DIR}
DOWNLOAD_COMMAND git clone --depth 1 --branch v1.0.0 https://github.com/cpm-cmake/testpack-adder.git ${DOWNLOAD_DIR}
OPTIONS "ADDER_BUILD_TESTS OFF"
)
PACK
# configure with unpopulated cache
assert_success prj.configure
assert_success prj.build
end
end

View File

@ -9,7 +9,7 @@ class FetchContentCompatibility < IntegrationTest
end end
def test_add_dependency_cpm_and_fetchcontent def test_add_dependency_cpm_and_fetchcontent
prj = make_project from_template: 'using-adder' prj = make_project 'using-adder'
prj.create_lists_from_default_template package: <<~PACK prj.create_lists_from_default_template package: <<~PACK
CPMAddPackage( CPMAddPackage(

View File

@ -1,21 +0,0 @@
require_relative './lib'
class Parallelism < IntegrationTest
def setup
@cache_dir = File.join(cur_test_dir, 'cpmcache')
ENV['CPM_SOURCE_CACHE'] = @cache_dir
end
def test_populate_cache_in_parallel
4.times.map { |i|
prj = make_project name: i.to_s, from_template: 'using-fibadder'
prj.create_lists_from_default_template package: 'CPMAddPackage("gh:cpm-cmake/testpack-fibadder@1.0.0")'
prj
}.map { |prj|
Thread.new do
assert_success prj.configure
assert_success prj.build
end
}.map(&:join)
end
end

View File

@ -1,27 +0,0 @@
require_relative './lib'
# Tests using a multi-argumenet PATCHES command to fetch and modify a dependency
class DownloadCommand < IntegrationTest
def test_fetch_dependency_using_download_command
prj = make_project from_template: 'using-patch-adder'
prj.create_lists_from_default_template package: <<~PACK
set(DOWNLOAD_DIR ${CMAKE_BINARY_DIR}/_deps/testpack-adder-src)
CPMAddPackage(
NAME testpack-adder
DOWNLOAD_COMMAND git clone --depth 1 --branch v1.0.0 https://github.com/cpm-cmake/testpack-adder.git ${DOWNLOAD_DIR}
OPTIONS "ADDER_BUILD_TESTS OFF" "ADDER_BUILD_EXAMPLES OFF"
PATCHES
patches/001-test_patches_command.patch
patches/002-test_patches_command.patch
)
PACK
# configure with unpopulated cache
assert_success prj.configure
assert_success prj.build
end
end

View File

@ -1,17 +0,0 @@
require_relative './lib'
class RelativeURLs < IntegrationTest
def setup
# relative URLs were introduced in CMake 3.27
@relative_urls_supported = (!ENV['CMAKE_VERSION']) || (Gem::Version.new(ENV['CMAKE_VERSION']) >= Gem::Version.new('3.27'))
end
def test_add_project_with_relative_urls
omit_if !@relative_urls_supported do
prj = make_project from_template: 'using-fibadder'
prj.create_lists_from_default_template package: 'CPMAddPackage("gh:cpm-cmake/testpack-fibadder@1.1.0-relative-urls")'
assert_success prj.configure
assert_success prj.build
end
end
end

View File

@ -2,7 +2,7 @@ require_relative './lib'
class RemoveSourceDir < IntegrationTest class RemoveSourceDir < IntegrationTest
def test_remove_source_dir def test_remove_source_dir
prj = make_project from_template: 'using-adder' prj = make_project 'using-adder'
prj.create_lists_from_default_template package: <<~PACK prj.create_lists_from_default_template package: <<~PACK
CPMAddPackage( CPMAddPackage(

View File

@ -1,86 +0,0 @@
require_relative './lib'
class TestShorthandSyntax < IntegrationTest
def get_project_binaries prj
exe_dir = File.join(prj.bin_dir, 'bin')
assert File.directory? exe_dir
return Dir[exe_dir + '/**/*'].filter {
# on multi-configuration generators (like Visual Studio) the executables will be in bin/<Config>
# also filter-out other artifacts like .pdb or .dsym
!File.directory?(_1) && File.stat(_1).executable?
}.map {
# remove .exe extension if any (there will be one on Windows)
File.basename(_1, '.exe')
}.sort
end
def test_create_with_commit_sha
prj = make_project from_template: 'using-adder'
prj.create_lists_from_default_template package:
'CPMAddPackage("gh:cpm-cmake/testpack-adder#cad1cd4b4cdf957c5b59e30bc9a1dd200dbfc716")'
assert_success prj.configure
cache = prj.read_cache
assert_equal 1, cache.packages.size
assert_equal '0', cache.packages['testpack-adder'].ver
assert_success prj.build
exes = get_project_binaries prj
# No adder projects were built as EXCLUDE_FROM_ALL is implicitly set
assert_equal ['using-adder'], exes
end
def test_create_with_version
prj = make_project from_template: 'using-adder'
prj.create_lists_from_default_template package:
'CPMAddPackage("gh:cpm-cmake/testpack-adder@1.0.0")'
assert_success prj.configure
cache = prj.read_cache
assert_equal 1, cache.packages.size
assert_equal '1.0.0', cache.packages['testpack-adder'].ver
assert_success prj.build
exes = get_project_binaries prj
assert_equal ['using-adder'], exes
end
def test_create_with_all
prj = make_project from_template: 'using-adder'
prj.create_lists_from_default_template package:
'CPMAddPackage(
URI "gh:cpm-cmake/testpack-adder@1.0.0"
EXCLUDE_FROM_ALL false
)'
assert_success prj.configure
cache = prj.read_cache
assert_equal cache.packages.size, 1
assert_equal cache.packages['testpack-adder'].ver, '1.0.0'
assert_success prj.build
exes = get_project_binaries prj
assert_equal exes, ['simple', 'test-adding', 'using-adder']
end
def test_create_with_tests_but_without_examples
prj = make_project from_template: 'using-adder'
prj.create_lists_from_default_template package:
'CPMAddPackage(
URI "gh:cpm-cmake/testpack-adder@1.0.0"
OPTIONS "ADDER_BUILD_EXAMPLES OFF" "ADDER_BUILD_TESTS TRUE"
EXCLUDE_FROM_ALL false
)'
assert_success prj.configure
cache = prj.read_cache
assert_equal cache.packages.size, 1
assert_equal cache.packages['testpack-adder'].ver, '1.0.0'
assert_success prj.build
exes = get_project_binaries prj
assert_equal exes, ['test-adding', 'using-adder']
end
end

View File

@ -4,7 +4,7 @@ class Simple < IntegrationTest
ADDER_PACKAGE_NAME = 'testpack-adder' ADDER_PACKAGE_NAME = 'testpack-adder'
def test_update_single_package def test_update_single_package
prj = make_project from_template: 'using-adder' prj = make_project 'using-adder'
adder_cache0 = nil adder_cache0 = nil
adder_ver_file = nil adder_ver_file = nil
@ -70,7 +70,7 @@ class Simple < IntegrationTest
exes = Dir[exe_dir + '/**/*'].filter { exes = Dir[exe_dir + '/**/*'].filter {
# on multi-configuration generators (like Visual Studio) the executables will be in bin/<Config> # on multi-configuration generators (like Visual Studio) the executables will be in bin/<Config>
# also filter-out other artifacts like .pdb or .dsym # also filter-out other articacts like .pdb or .dsym
!File.directory?(_1) && File.stat(_1).executable? !File.directory?(_1) && File.stat(_1).executable?
}.map { }.map {
# remove .exe extension if any (there will be one on Windows) # remove .exe extension if any (there will be one on Windows)

View File

@ -9,7 +9,7 @@ class SourceCache < IntegrationTest
end end
def test_add_remove_dependency def test_add_remove_dependency
prj = make_project from_template: 'using-fibadder' prj = make_project 'using-fibadder'
################################### ###################################
# create # create
@ -45,7 +45,7 @@ class SourceCache < IntegrationTest
end end
def test_second_project def test_second_project
prj = make_project from_template: 'using-fibadder' prj = make_project 'using-fibadder'
prj.create_lists_from_default_template package: 'CPMAddPackage("gh:cpm-cmake/testpack-fibadder@1.1.0")' prj.create_lists_from_default_template package: 'CPMAddPackage("gh:cpm-cmake/testpack-fibadder@1.1.0")'
assert_success prj.configure assert_success prj.configure
@ -75,17 +75,6 @@ class SourceCache < IntegrationTest
assert_equal ver, package.ver assert_equal ver, package.ver
expected_parent_dir = File.join(@cache_dir, name.downcase) expected_parent_dir = File.join(@cache_dir, name.downcase)
assert package.src_dir.start_with?(expected_parent_dir), "#{package.src_dir} must be in #{expected_parent_dir}" assert package.src_dir.start_with?(expected_parent_dir), "#{package.src_dir} must be in #{expected_parent_dir}"
assert_equal dir_sha1, File.basename(package.src_dir)
# The hash has been shortened by cpm_get_shortest_hash. The following
# should hold:
# - The short hash should be a prefix of the input hash
# - There should be a file ".../${short_hash}.hash" which matches the full hash
short_hash = File.basename(package.src_dir)
assert dir_sha1.start_with?(short_hash), "short_hash should be a prefix of dir_sha1"
# Check that the full hash is stored in the .hash file
hash_file = "#{package.src_dir}.hash"
assert File.exist?(hash_file), "Hash file #{hash_file} should exist"
assert_equal dir_sha1, File.read(hash_file), "Hash file should contain the full original hash"
end end
end end

View File

@ -1,57 +0,0 @@
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'
prj.create_lists_from_default_template package: <<~PACK
# this commit has a warning in a public header
CPMAddPackage(
NAME Adder
GITHUB_REPOSITORY cpm-cmake/testpack-adder
GIT_TAG v1.0.1-warnings
SYSTEM #{use_system ? "YES" : "NO"}
)
# all packages using `adder` will error on warnings
target_compile_options(adder INTERFACE
$<$<CXX_COMPILER_ID:MSVC>:/Wall /WX>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Werror>
)
PACK
assert_success prj.configure
if use_system and @system_supported
assert_success prj.build
else
assert_failure prj.build
end
end
end
def test_dependency_added_implicitly_using_system
prj = make_project from_template: 'using-adder'
prj.create_lists_from_default_template package: <<~PACK
# this commit has a warning in a public header
CPMAddPackage("gh:cpm-cmake/testpack-adder@1.0.1-warnings")
# all packages using `adder` will error on warnings
target_compile_options(adder INTERFACE
$<$<CXX_COMPILER_ID:MSVC>:/Wall /WX>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Werror>
)
PACK
assert_success prj.configure
if @system_supported
assert_success prj.build
else
assert_failure prj.build
end
end
end

View File

@ -14,7 +14,7 @@ class MyTest < IntegrationTest
end end
``` ```
Now we have our test case class, and the single test method that we will require. Let's focus on the method's contents. The integration test framework provides us with a helper class, `Project`, which can be used for this scenario. A project has an associated pair of source and binary directories in the temporary directory and it provides methods to work with them. Now we have our test case class, and the single test method that we will require. Let's focus on the method's contents. The integration test framework provides us with a helper class, `Project`, which can be used for this scenario. A project has an assoiciated pair of source and binary directories in the temporary directory and it provides methods to work with them.
We start by creating the project: We start by creating the project:

View File

@ -26,17 +26,6 @@ function(reset_test)
update_cmake_lists() update_cmake_lists()
endfunction() endfunction()
function(assert_cache_directory_count directory count)
set(version_count 0)
file(GLOB potential_versions ${directory})
foreach(entry ${potential_versions})
if(IS_DIRECTORY ${entry})
math(EXPR version_count "${version_count} + 1")
endif()
endforeach()
assert_equal("${version_count}" "${count}")
endfunction()
set(FIBONACCI_VERSION 1.0) set(FIBONACCI_VERSION 1.0)
# Read CPM_SOURCE_CACHE from arguments # Read CPM_SOURCE_CACHE from arguments
@ -51,7 +40,13 @@ execute_process(
assert_equal(${ret} "0") assert_equal(${ret} "0")
assert_exists("${CPM_SOURCE_CACHE_DIR}/fibonacci") assert_exists("${CPM_SOURCE_CACHE_DIR}/fibonacci")
assert_cache_directory_count("${CPM_SOURCE_CACHE_DIR}/fibonacci/*" 1) file(GLOB FIBONACCI_VERSIONs "${CPM_SOURCE_CACHE_DIR}/fibonacci/*")
list(LENGTH FIBONACCI_VERSIONs FIBONACCI_VERSION_count)
assert_equal(${FIBONACCI_VERSION_count} "1")
file(GLOB fibonacci_versions "${CPM_SOURCE_CACHE_DIR}/fibonacci/*")
list(LENGTH fibonacci_versions fibonacci_version_count)
assert_equal(${fibonacci_version_count} "1")
# Update dependency and keep CPM_SOURCE_CACHE # Update dependency and keep CPM_SOURCE_CACHE
@ -59,9 +54,12 @@ set(FIBONACCI_VERSION 2.0)
update_cmake_lists() update_cmake_lists()
execute_process(COMMAND ${CMAKE_COMMAND} ${TEST_BUILD_DIR} RESULT_VARIABLE ret) execute_process(COMMAND ${CMAKE_COMMAND} ${TEST_BUILD_DIR} RESULT_VARIABLE ret)
assert_equal(${ret} "0") assert_equal(${ret} "0")
assert_cache_directory_count("${CPM_SOURCE_CACHE_DIR}/fibonacci/*" 2) file(GLOB FIBONACCI_VERSIONs "${CPM_SOURCE_CACHE_DIR}/fibonacci/*")
list(LENGTH FIBONACCI_VERSIONs FIBONACCI_VERSION_count)
assert_equal(${FIBONACCI_VERSION_count} "2")
# Clear cache and update # Clear cache and update
@ -137,19 +135,3 @@ execute_process(
assert_equal(${ret} "0") assert_equal(${ret} "0")
assert_not_exists("${CPM_SOURCE_CACHE_DIR}/fibonacci") assert_not_exists("${CPM_SOURCE_CACHE_DIR}/fibonacci")
# Use custom cache directory
set(FIBONACCI_PACKAGE_ARGS
"CUSTOM_CACHE_KEY my_custom_unique_dir GIT_TAG e9ebf168ca0fffaa4ef8c6fefc6346aaa22f6ed5"
)
set(FIBONACCI_VERSION 1.1)
update_cmake_lists()
execute_process(
COMMAND ${CMAKE_COMMAND} -E env "CPM_SOURCE_CACHE=${CPM_SOURCE_CACHE_DIR}" ${CMAKE_COMMAND}
"-S${CMAKE_CURRENT_LIST_DIR}/remote_dependency" "-B${TEST_BUILD_DIR}" RESULT_VARIABLE ret
)
assert_equal(${ret} "0")
assert_exists("${CPM_SOURCE_CACHE_DIR}/fibonacci/my_custom_unique_dir")

View File

@ -6,7 +6,6 @@ include(${CPM_PATH}/testing.cmake)
set(CPM_DRY_RUN ON) set(CPM_DRY_RUN ON)
CPMAddPackage(NAME A GIT_TAG 1.2.3) CPMAddPackage(NAME A GIT_TAG 1.2.3)
assert_equal("${CPM_LAST_PACKAGE_NAME}" "A")
CPMAddPackage(NAME A VERSION 1.2.3) CPMAddPackage(NAME A VERSION 1.2.3)
@ -18,8 +17,6 @@ CPMAddPackage(NAME B VERSION 2.4.1)
CPMAddPackage(NAME B GIT_TAG v2.3.1) CPMAddPackage(NAME B GIT_TAG v2.3.1)
CPMGetPackageVersion(B VERSION) CPMGetPackageVersion(B VERSION)
assert_equal("${CPM_LAST_PACKAGE_NAME}" "B")
assert_equal(${VERSION} "2.4.1") assert_equal(${VERSION} "2.4.1")
CPMAddPackage( CPMAddPackage(
@ -27,10 +24,6 @@ CPMAddPackage(
GIT_TAG v3.1.2-a GIT_TAG v3.1.2-a
VERSION 3.1.2 VERSION 3.1.2
) )
assert_equal("${CPM_LAST_PACKAGE_NAME}" "C")
CPMGetPackageVersion(C VERSION) CPMGetPackageVersion(C VERSION)
assert_equal(${VERSION} "3.1.2") assert_equal(${VERSION} "3.1.2")
CPMAddPackage("gh:dry-run/D")
assert_equal("${CPM_LAST_PACKAGE_NAME}" "D")

View File

@ -1,93 +0,0 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
include(${CPM_PATH}/CPM.cmake)
include(${CPM_PATH}/testing.cmake)
# Random suffix
string(
RANDOM
LENGTH 6
ALPHABET "0123456789abcdef" tmpdir_suffix
)
# Seconds since epoch
string(TIMESTAMP tmpdir_base "%s" UTC)
set(tmp "${CMAKE_CURRENT_BINARY_DIR}/get_shortest_hash-${tmpdir_base}-${tmpdir_suffix}")
if(IS_DIRECTORY ${tmp})
message(FATAL_ERROR "Test directory ${tmp} already exists")
endif()
file(MAKE_DIRECTORY "${tmp}")
# 1. Sanity check: none of these directories should exist yet
assert_not_exists(${tmp}/cccb.hash)
assert_not_exists(${tmp}/cccb77ae.hash)
assert_not_exists(${tmp}/cccb77ae9609.hash)
assert_not_exists(${tmp}/cccb77ae9608.hash)
assert_not_exists(${tmp}/cccb77be.hash)
# 1. The directory is empty, so it should get a 4-character hash
cpm_get_shortest_hash(${tmp} "cccb77ae9609d2768ed80dd42cec54f77b1f1455" hash)
assert_equal(${hash} "cccb")
assert_contents_equal(${tmp}/cccb.hash cccb77ae9609d2768ed80dd42cec54f77b1f1455)
# 1. Calling the function with a new hash that differs subtly should result in more characters being
# used, enough to uniquely identify the hash
cpm_get_shortest_hash(${tmp} "cccb77ae9609d2768ed80dd42cec54f77b1f1456" hash)
assert_equal(${hash} "cccb77ae")
assert_contents_equal(${tmp}/cccb77ae.hash cccb77ae9609d2768ed80dd42cec54f77b1f1456)
cpm_get_shortest_hash(${tmp} "cccb77ae9609d2768ed80dd42cec54f77b1f1457" hash)
assert_equal(${hash} "cccb77ae9609")
assert_contents_equal(${tmp}/cccb77ae9609.hash cccb77ae9609d2768ed80dd42cec54f77b1f1457)
cpm_get_shortest_hash(${tmp} "cccb77ae9608d2768ed80dd42cec54f77b1f1455" hash)
assert_equal(${hash} "cccb77ae9608")
assert_contents_equal(${tmp}/cccb77ae9608.hash cccb77ae9608d2768ed80dd42cec54f77b1f1455)
cpm_get_shortest_hash(${tmp} "cccb77be9609d2768ed80dd42cec54f77b1f1456" hash)
assert_equal(${hash} "cccb77be")
assert_contents_equal(${tmp}/cccb77be.hash cccb77be9609d2768ed80dd42cec54f77b1f1456)
# check that legacy hashs are recognized
file(MAKE_DIRECTORY "${tmp}/cccb77be9609d2768ed80dd42cec54f77b1f1457")
cpm_get_shortest_hash(${tmp} "cccb77be9609d2768ed80dd42cec54f77b1f1457" hash)
assert_equal(${hash} "cccb77be9609d2768ed80dd42cec54f77b1f1457")
# 1. The old file should still exist, and have the same content
assert_contents_equal(${tmp}/cccb.hash cccb77ae9609d2768ed80dd42cec54f77b1f1455)
assert_contents_equal(${tmp}/cccb77ae.hash cccb77ae9609d2768ed80dd42cec54f77b1f1456)
assert_contents_equal(${tmp}/cccb77ae9609.hash cccb77ae9609d2768ed80dd42cec54f77b1f1457)
assert_contents_equal(${tmp}/cccb77ae9608.hash cccb77ae9608d2768ed80dd42cec54f77b1f1455)
assert_contents_equal(${tmp}/cccb77be.hash cccb77be9609d2768ed80dd42cec54f77b1f1456)
# 1. Confirm idempotence: calling any of these function should produce the same hash as before (hash
# lookups work correctly once the .hash files are created)
cpm_get_shortest_hash(${tmp} "cccb77ae9609d2768ed80dd42cec54f77b1f1455" hash)
assert_equal(${hash} "cccb")
assert_contents_equal(${tmp}/cccb.hash cccb77ae9609d2768ed80dd42cec54f77b1f1455)
cpm_get_shortest_hash(${tmp} "cccb77ae9609d2768ed80dd42cec54f77b1f1456" hash)
assert_equal(${hash} "cccb77ae")
assert_contents_equal(${tmp}/cccb77ae.hash cccb77ae9609d2768ed80dd42cec54f77b1f1456)
cpm_get_shortest_hash(${tmp} "cccb77ae9609d2768ed80dd42cec54f77b1f1457" hash)
assert_equal(${hash} "cccb77ae9609")
assert_contents_equal(${tmp}/cccb77ae9609.hash cccb77ae9609d2768ed80dd42cec54f77b1f1457)
cpm_get_shortest_hash(${tmp} "cccb77ae9608d2768ed80dd42cec54f77b1f1455" hash)
assert_equal(${hash} "cccb77ae9608")
assert_contents_equal(${tmp}/cccb77ae9608.hash cccb77ae9608d2768ed80dd42cec54f77b1f1455)
cpm_get_shortest_hash(${tmp} "cccb77be9609d2768ed80dd42cec54f77b1f1456" hash)
assert_equal(${hash} "cccb77be")
assert_contents_equal(${tmp}/cccb77be.hash cccb77be9609d2768ed80dd42cec54f77b1f1456)
# 1. Cleanup - remove the temporary directory that we created
file(REMOVE_RECURSE ${tmp})

View File

@ -8,10 +8,6 @@ option(ENABLE_TEST_COVERAGE "Enable test coverage" OFF)
# ---- Dependencies ---- # ---- Dependencies ----
if (@TEST_FORCE_MODULE_MODE@)
unset(CMAKE_FIND_PACKAGE_REDIRECTS_DIR CACHE)
endif()
include(@CPM_PATH@/CPM.cmake) include(@CPM_PATH@/CPM.cmake)
CPMAddPackage( CPMAddPackage(
@ -19,23 +15,20 @@ CPMAddPackage(
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/dependency SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/dependency
) )
# ---- check if generated modules override find_package ----
if (@test_check_find_package@)
find_package(@TEST_DEPENDENCY_NAME@ REQUIRED)
endif()
# ---- Call dependency method to validate correct addition of directory ---- # ---- Call dependency method to validate correct addition of directory ----
dependency_function() dependency_function()
# ---- Check newly added ----
include(@CPM_PATH@/testing.cmake)
ASSERT_TRUTHY(@TEST_DEPENDENCY_NAME@_ADDED)
# ---- Check if generated modules override find_package ----
if (@TEST_FIND_PACKAGE@)
find_package(@TEST_DEPENDENCY_NAME@ @TEST_FIND_PACKAGE_CONFIG@ REQUIRED)
find_package(@TEST_CANT_FIND_PACKAGE_NAME@ @TEST_FIND_PACKAGE_CONFIG@ QUIET)
ASSERT_FALSY(@TEST_CANT_FIND_PACKAGE_NAME@_FOUND)
endif()
# ---- Check parameters ---- # ---- Check parameters ----
include(@CPM_PATH@/testing.cmake)
ASSERT_TRUTHY(@TEST_DEPENDENCY_NAME@_ADDED)
ASSERT_DEFINED(@TEST_DEPENDENCY_NAME@_SOURCE_DIR) ASSERT_DEFINED(@TEST_DEPENDENCY_NAME@_SOURCE_DIR)
ASSERT_DEFINED(@TEST_DEPENDENCY_NAME@_BINARY_DIR) ASSERT_DEFINED(@TEST_DEPENDENCY_NAME@_BINARY_DIR)
ASSERT_EQUAL("${CPM_LAST_PACKAGE_NAME}" "@TEST_DEPENDENCY_NAME@")

View File

@ -25,5 +25,3 @@ include(@CPM_PATH@/testing.cmake)
ASSERT_TRUTHY(Dependency_ADDED) ASSERT_TRUTHY(Dependency_ADDED)
ASSERT_DEFINED(Dependency_SOURCE_DIR) ASSERT_DEFINED(Dependency_SOURCE_DIR)
ASSERT_DEFINED(Dependency_BINARY_DIR) ASSERT_DEFINED(Dependency_BINARY_DIR)
ASSERT_EQUAL("${CPM_LAST_PACKAGE_NAME}" "Dependency")

View File

@ -3,8 +3,7 @@ include(${CPM_PATH}/testing.cmake)
set(TEST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/modules) set(TEST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/modules)
function(init_project_with_dependency TEST_DEPENDENCY_NAME TEST_CANT_FIND_PACKAGE_NAME) function(init_project_with_dependency TEST_DEPENDENCY_NAME)
set(TEST_FIND_PACKAGE ON)
configure_package_config_file( configure_package_config_file(
"${CMAKE_CURRENT_LIST_DIR}/local_dependency/ModuleCMakeLists.txt.in" "${CMAKE_CURRENT_LIST_DIR}/local_dependency/ModuleCMakeLists.txt.in"
"${CMAKE_CURRENT_LIST_DIR}/local_dependency/CMakeLists.txt" "${CMAKE_CURRENT_LIST_DIR}/local_dependency/CMakeLists.txt"
@ -19,17 +18,11 @@ function(init_project_with_dependency TEST_DEPENDENCY_NAME TEST_CANT_FIND_PACKAG
assert_equal(${ret} "0") assert_equal(${ret} "0")
endfunction() endfunction()
init_project_with_dependency(A B) init_project_with_dependency(A)
init_project_with_dependency(B A) assert_exists(${TEST_BUILD_DIR}/CPM_modules)
assert_exists(${TEST_BUILD_DIR}/CPM_modules/FindA.cmake)
assert_not_exists(${TEST_BUILD_DIR}/CPM_modules/FindB.cmake)
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.24.0") init_project_with_dependency(B)
set(TEST_FIND_PACKAGE_CONFIG CONFIG) assert_not_exists(${TEST_BUILD_DIR}/CPM_modules/FindA.cmake)
init_project_with_dependency(A B) assert_exists(${TEST_BUILD_DIR}/CPM_modules/FindB.cmake)
init_project_with_dependency(B A)
# Test the fallback path for CMake <3.24 works
set(TEST_FIND_PACKAGE_CONFIG)
set(TEST_FORCE_MODULE_MODE ON)
init_project_with_dependency(A B)
init_project_with_dependency(B A)
endif()

View File

@ -30,4 +30,3 @@ include(@CPM_PATH@/testing.cmake)
ASSERT_TRUTHY(fibonacci_ADDED) ASSERT_TRUTHY(fibonacci_ADDED)
ASSERT_DEFINED(fibonacci_SOURCE_DIR) ASSERT_DEFINED(fibonacci_SOURCE_DIR)
ASSERT_DEFINED(fibonacci_BINARY_DIR) ASSERT_DEFINED(fibonacci_BINARY_DIR)
ASSERT_EQUAL("${CPM_LAST_PACKAGE_NAME}" "fibonacci")