mirror of
https://github.com/cpm-cmake/CPM.cmake.git
synced 2025-11-18 15:17:30 -05:00
Compare commits
189 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a575ab57b7 | ||
|
|
ca421f0e0c | ||
|
|
005f202655 | ||
|
|
865648e7bd | ||
|
|
33bdbae902 | ||
|
|
9d3fad01d4 | ||
|
|
11c7ec8afa | ||
|
|
4f7af69925 | ||
|
|
c58e98a0a0 | ||
|
|
a27c66a3ea | ||
|
|
5cb7398a24 | ||
|
|
262f1e0602 | ||
|
|
7cbef3efc8 | ||
|
|
939123d1b4 | ||
|
|
22078d5e0d | ||
|
|
96c268827b | ||
|
|
dad37fbe4e | ||
|
|
fed5f8e8a2 | ||
|
|
d65613e860 | ||
|
|
718ea71759 | ||
|
|
6491382204 | ||
|
|
634800c619 | ||
|
|
f552da96bd | ||
|
|
ea6a8eb895 | ||
|
|
a5c22bf6e8 | ||
|
|
c5cb85b2f1 | ||
|
|
91585e3864 | ||
|
|
9675d46517 | ||
|
|
7078e8286a | ||
|
|
6a0277f16e | ||
|
|
4502bf1e04 | ||
|
|
dd3ba9792c | ||
|
|
de5551e42c | ||
|
|
7644c3a40f | ||
|
|
310efb9b17 | ||
|
|
4fad2eac0a | ||
|
|
ee08119642 | ||
|
|
259f1be8e2 | ||
|
|
32b063eba5 | ||
|
|
d64d816585 | ||
|
|
8e8dcc9a8d | ||
|
|
8afc2af4f9 | ||
|
|
a3d1048ad6 | ||
|
|
492e762591 | ||
|
|
3f6cbe7383 | ||
|
|
4aadac1972 | ||
|
|
4cbf443363 | ||
|
|
2744b87f07 | ||
|
|
fd539b8ff3 | ||
|
|
02d57a1601 | ||
|
|
5f614e5eb6 | ||
|
|
1f5cb903e5 | ||
|
|
7000572bbe | ||
|
|
fe8d15ba82 | ||
|
|
ab6e8d6d8c | ||
|
|
aad0397beb | ||
|
|
1ebbac6332 | ||
|
|
cf3f62b6f2 | ||
|
|
3b404296b5 | ||
|
|
18e09b07ba | ||
|
|
aeef56ea85 | ||
|
|
4271d5981f | ||
|
|
d17500b0be | ||
|
|
5e0c3855c7 | ||
|
|
f96cff720e | ||
|
|
c3c7e2d9a3 | ||
|
|
30b98af416 | ||
|
|
5063c7d992 | ||
|
|
3cfb309f3c | ||
|
|
25603ac4ad | ||
|
|
ac872f6908 | ||
|
|
bd14ccbd5a | ||
|
|
f8afae6eb3 | ||
|
|
9ec279c75f | ||
|
|
392b2a864b | ||
|
|
139d3cacba | ||
|
|
b31063d2ae | ||
|
|
4425bd38cf | ||
|
|
6da5c38dae | ||
|
|
76d7b27459 | ||
|
|
54a2d80d1e | ||
|
|
829262cbd3 | ||
|
|
4aeea1d31d | ||
|
|
58365446f5 | ||
|
|
4937617ef1 | ||
|
|
6f053907f5 | ||
|
|
84b31b560a | ||
|
|
3fff3ca70d | ||
|
|
ca33abc236 | ||
|
|
119eaee84d | ||
|
|
00b5e80f88 | ||
|
|
618cdefa0d | ||
|
|
464ba554c2 | ||
|
|
90558aa9cb | ||
|
|
95c5426d25 | ||
|
|
cea81872cf | ||
|
|
01b69aad82 | ||
|
|
775a235880 | ||
|
|
f8d4e959bb | ||
|
|
4c7aa36dff | ||
|
|
3a4516265c | ||
|
|
47bfb554ab | ||
|
|
0a8a65df32 | ||
|
|
a2800dc96c | ||
|
|
7638be873a | ||
|
|
d1a1b70d4a | ||
|
|
4064a45552 | ||
|
|
b1855e9275 | ||
|
|
5191b4c703 | ||
|
|
8625173d8f | ||
|
|
504761fbf2 | ||
|
|
8b92bb46cd | ||
|
|
88278a4f70 | ||
|
|
72552708e6 | ||
|
|
a6bc65a76c | ||
|
|
64f5fe37cd | ||
|
|
25a9158448 | ||
|
|
1e8d8d43c7 | ||
|
|
160a665973 | ||
|
|
3d75ed06a3 | ||
|
|
1e25367c8c | ||
|
|
9d2b5818c5 | ||
|
|
49e7903e19 | ||
|
|
4d3997d408 | ||
|
|
d74bcebfe8 | ||
|
|
db3111e07e | ||
|
|
840e2e2c40 | ||
|
|
4952fd3d48 | ||
|
|
3659fa581c | ||
|
|
4aeb1215bf | ||
|
|
13559c7137 | ||
|
|
e4f1ade459 | ||
|
|
7723e56dab | ||
|
|
8287799e79 | ||
|
|
cd91713d10 | ||
|
|
4967b841ad | ||
|
|
9c2c34f487 | ||
|
|
bd9143bfa0 | ||
|
|
a4f055c7aa | ||
|
|
002cf6b64c | ||
|
|
f13c343859 | ||
|
|
bf5e9ebafb | ||
|
|
275a12f2d8 | ||
|
|
6878cf622b | ||
|
|
4f57bd4b5b | ||
|
|
bf1996b9f4 | ||
|
|
f72944e897 | ||
|
|
79cbebb4f9 | ||
|
|
d3b23be4e2 | ||
|
|
5352247b4d | ||
|
|
798e4e35bf | ||
|
|
7d6297c5c6 | ||
|
|
e0bfe05874 | ||
|
|
530fc8d42f | ||
|
|
a086f637fb | ||
|
|
5203eb6e30 | ||
|
|
7a8599cf34 | ||
|
|
bd3732706a | ||
|
|
84d6e53c65 | ||
|
|
7bbc667df1 | ||
|
|
f5050169b0 | ||
|
|
a7ab78f3bf | ||
|
|
b1ef60175a | ||
|
|
8253393c75 | ||
|
|
f9ba3f2457 | ||
|
|
77e74910bc | ||
|
|
55caef9286 | ||
|
|
f57476ee43 | ||
|
|
db4f2bf7bb | ||
|
|
8d39e34ff2 | ||
|
|
c2a413300e | ||
|
|
5177860756 | ||
|
|
5dad9d4e9d | ||
|
|
539974785e | ||
|
|
e4a0cb4980 | ||
|
|
a8ccc42f43 | ||
|
|
f92ed18514 | ||
|
|
153c196c18 | ||
|
|
d91befd7ce | ||
|
|
978c101c7e | ||
|
|
8da680df9b | ||
|
|
6943b38afb | ||
|
|
cf042cf1ac | ||
|
|
bebea37c4a | ||
|
|
137bda299d | ||
|
|
4d557d128f | ||
|
|
9021499c52 | ||
|
|
9b97b64da2 | ||
|
|
df752ed5d3 |
16
.clang-format
Normal file
16
.clang-format
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
BasedOnStyle: Google
|
||||
AccessModifierOffset: '-2'
|
||||
AlignTrailingComments: 'true'
|
||||
AllowAllParametersOfDeclarationOnNextLine: 'false'
|
||||
AlwaysBreakTemplateDeclarations: 'No'
|
||||
BreakBeforeBraces: Attach
|
||||
ColumnLimit: '100'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
||||
IncludeBlocks: Regroup
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: '2'
|
||||
NamespaceIndentation: All
|
||||
BreakBeforeBinaryOperators: All
|
||||
BreakBeforeTernaryOperators: 'true'
|
||||
...
|
||||
73
.cmake-format
Normal file
73
.cmake-format
Normal file
@@ -0,0 +1,73 @@
|
||||
format:
|
||||
tab_size: 2
|
||||
line_width: 100
|
||||
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
|
||||
30
.github/workflows/examples.yml
vendored
Normal file
30
.github/workflows/examples.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Examples
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
gcc:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: build all
|
||||
env:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
run: python3 examples/build_all.py
|
||||
|
||||
clang:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: build all
|
||||
env:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
run: python3 examples/build_all.py
|
||||
28
.github/workflows/publish.yaml
vendored
Normal file
28
.github/workflows/publish.yaml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Publish CPM.cmake
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Set CPM version by tag
|
||||
run: |
|
||||
mkdir dist
|
||||
sed "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/get_cpm.cmake > dist/get_cpm.cmake
|
||||
|
||||
- name: Upload CPM.cmake to release
|
||||
uses: svenstaro/upload-release-action@v1-release
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: ${{ github.ref }}
|
||||
file: dist/*.cmake
|
||||
file_glob: true
|
||||
overwrite: true
|
||||
28
.github/workflows/style.yml
vendored
Normal file
28
.github/workflows/style.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: Style
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
style:
|
||||
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Install format dependencies
|
||||
run: |
|
||||
brew install clang-format
|
||||
pip3 install cmake_format==0.6.11 pyyaml
|
||||
|
||||
- name: configure
|
||||
run: cmake -Stest/style -Bbuild/style
|
||||
|
||||
- name: check style
|
||||
run: cmake --build build/style --target check-format
|
||||
33
.github/workflows/test.yml
vendored
Normal file
33
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
# windows-latest is windows-2019 which carries a pretty old version of ruby (2.5)
|
||||
# we need at least ruby 2.7 for the tests
|
||||
# instead of dealing with installing a modern version of ruby on 2019, we'll just use windows-2022 here
|
||||
os: [ubuntu-latest, windows-2022, macos-latest]
|
||||
|
||||
steps:
|
||||
- name: clone
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: unit tests
|
||||
run: |
|
||||
cmake -Stest -Bbuild/test
|
||||
cmake --build build/test --target test-verbose
|
||||
|
||||
- name: integration tests
|
||||
run: ruby test/integration/runner.rb
|
||||
env:
|
||||
CPM_INTEGRATION_TEST_DIR: ./build/integration
|
||||
14
.gitignore
vendored
14
.gitignore
vendored
@@ -1,10 +1,4 @@
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
Testing
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
build
|
||||
build/
|
||||
/build*
|
||||
/.vscode
|
||||
*.DS_Store
|
||||
|
||||
50
.travis.yml
50
.travis.yml
@@ -1,50 +0,0 @@
|
||||
|
||||
language: cpp
|
||||
sudo: require
|
||||
|
||||
common_sources: &all_sources
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty
|
||||
- llvm-toolchain-trusty-6.0
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons: &gcc8
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages:
|
||||
- g++-8
|
||||
env:
|
||||
- MATRIX_EVAL="export CC=gcc-8; export CXX=g++-8;"
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: *all_sources
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-6.0
|
||||
env:
|
||||
- MATRIX_EVAL="export CC=clang-6.0; export CXX=clang++-6.0;"
|
||||
|
||||
before_install:
|
||||
# Update compilers
|
||||
- eval "${MATRIX_EVAL}"
|
||||
- echo "CC=$CC CXX=$CXX"
|
||||
# Install a supported cmake version (>= 3.14)
|
||||
- wget -O cmake.sh https://cmake.org/files/v3.14/cmake-3.14.0-Linux-x86_64.sh
|
||||
- sudo sh cmake.sh --skip-license --exclude-subdir --prefix=/usr/local
|
||||
- export PATH=/usr/local/bin:$PATH
|
||||
- cmake --version
|
||||
|
||||
script:
|
||||
- cmake -Hexamples/simple -Bbuild/simple
|
||||
- cmake --build build/simple
|
||||
- CTEST_OUTPUT_ON_FAILURE=1 cmake --build build/simple --target test
|
||||
- cmake -Hexamples/complex -Bbuild/complex
|
||||
- cmake --build build/complex
|
||||
- CTEST_OUTPUT_ON_FAILURE=1 cmake --build build/complex --target test
|
||||
|
||||
32
CONTRIBUTORS.md
Normal file
32
CONTRIBUTORS.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# CPM.cmake Contributors
|
||||
|
||||
For detailed breakdown of individual contributions see the [Contributors page on GitHub](https://github.com/cpm-cmake/CPM.cmake/graphs/contributors)
|
||||
|
||||
* [Lars Melchior](https://github.com/TheLartians)
|
||||
* [Borislav Stanimirov](https://github.com/iboB)
|
||||
* [Paul T](https://github.com/DeveloperPaul123)
|
||||
* [Leonardo Lima](https://github.com/leozz37)
|
||||
* [pgorgon-hem](https://github.com/pgorgon-hem)
|
||||
* [Xavier Muller](https://github.com/xmuller)
|
||||
* NVIDIA CORPORATION via [Robert Maynard](https://github.com/robertmaynard)
|
||||
* [Kingsley Chen](https://github.com/kingsamchen)
|
||||
* [alexandreSalconiDenis](https://github.com/alexandreSalconiDenis)
|
||||
* [DNKpp](https://github.com/DNKpp)
|
||||
* [Olivier Le Doeuff](https://github.com/OlivierLDff)
|
||||
* [Stuart Dootson](https://github.com/studoot)
|
||||
* [Tobias Hellmann](https://github.com/Tobi823)
|
||||
* [Giuseppe Cesarano](https://github.com/GiuseppeCesarano)
|
||||
* [Pavel Sokolov](https://github.com/hacker-cb)
|
||||
* [Claus Klein](https://github.com/ClausKlein)
|
||||
* [Clare Macrae](https://github.com/claremacrae)
|
||||
* [Kai Germaschewski](https://github.com/germasch)
|
||||
* [Andrea Barbadoro](https://github.com/andijcr)
|
||||
* [MixusMinimax](https://github.com/MixusMinimax)
|
||||
* [Dan Raviv](https://github.com/danra)
|
||||
* [Prabir Shrestha](https://github.com/prabirshrestha)
|
||||
* [Paul Taylor](https://github.com/trxcllnt)
|
||||
* [Ryan Mast](https://github.com/nightlark)
|
||||
* [Vinpasso](https://github.com/Vinpasso)
|
||||
* [Yotam Gingold](https://github.com/yig)
|
||||
* [jecassis](https://github.com/jecassis)
|
||||
* [Johel Ernesto Guerrero Peña](https://github.com/JohelEGP)
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Lars Melchior
|
||||
Copyright (c) 2019-2022 Lars Melchior and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
381
README.md
381
README.md
@@ -1,16 +1,84 @@
|
||||
[](https://travis-ci.com/TheLartians/CPM)
|
||||
|
||||
# CPM
|
||||
<br />
|
||||
<p align="center">
|
||||
<img src="./logo/CPM.png" height="100" />
|
||||
</p>
|
||||
<br />
|
||||
|
||||
CPM is a simple GIT dependency manager written in CMake. The main use-case is abstracting CMake's `FetchContent` and managing dependencies in small to medium sized projects.
|
||||
# Setup-free CMake dependency management
|
||||
|
||||
## Supported projects
|
||||
CPM.cmake is a cross-platform CMake script that adds dependency management capabilities to CMake.
|
||||
It's built as a thin wrapper around CMake's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) module that adds version control, caching, a simple API [and more](#comparison-to-pure-fetchcontent--externalproject).
|
||||
|
||||
Any project that you can add via `add_subdirectory` should already work with CPM.
|
||||
## Manage everything
|
||||
|
||||
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.
|
||||
For everything else, the targets can be created manually after the dependency has been downloaded (see the [snippets](#snippets) below for examples).
|
||||
|
||||
## Further reading
|
||||
|
||||
- [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/)
|
||||
|
||||
## Usage
|
||||
|
||||
To add a new dependency to your project simply add the Projects target name, the git URL and the version. If the git tag for this version does not match the pattern `v$VERSION`, then the exact branch or tag can be specified with the `GIT_TAG` argument. CMake options can also be supplied with the package.
|
||||
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
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
@@ -18,52 +86,291 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
# create project
|
||||
project(MyProject)
|
||||
|
||||
# add dependencies
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME LarsParser
|
||||
VERSION 1.8
|
||||
GIT_REPOSITORY https://github.com/TheLartians/Parser.git
|
||||
GIT_TAG v1.8 # optional here, as indirectly defined by VERSION
|
||||
OPTIONS # optional CMake arguments passed to the dependency
|
||||
"LARS_PARSER_BUILD_GLUE_EXTENSION ON"
|
||||
)
|
||||
|
||||
# add executable
|
||||
add_executable(my-project my-project.cpp)
|
||||
set_target_properties(my-project PROPERTIES CXX_STANDARD 17)
|
||||
target_link_libraries(my-project LarsParser)
|
||||
add_executable(tests tests.cpp)
|
||||
|
||||
# add dependencies
|
||||
include(cmake/CPM.cmake)
|
||||
CPMAddPackage("gh:catchorg/Catch2@2.5.0")
|
||||
|
||||
# link dependencies
|
||||
target_link_libraries(tests Catch2)
|
||||
```
|
||||
|
||||
See the [examples directory](https://github.com/TheLartians/CPM/tree/master/examples) for more examples.
|
||||
See the [examples directory](https://github.com/cpm-cmake/CPM.cmake/tree/master/examples) for complete examples with source code and check [below](#snippets) or in the [wiki](https://github.com/cpm-cmake/CPM.cmake/wiki/More-Snippets) for example snippets.
|
||||
|
||||
## Adding CPM
|
||||
|
||||
To add CPM to your current project, simply add `cmake/CPM.cmake` to your project's `cmake` directory. The command below will perform this automatically.
|
||||
To add CPM to your current project, simply add the [latest release](https://github.com/cpm-cmake/CPM.cmake/releases/latest) of `CPM.cmake` or `get_cpm.cmake` to your project's `cmake` directory.
|
||||
The command below will perform this automatically.
|
||||
|
||||
```bash
|
||||
wget -O cmake/CPM.cmake https://raw.githubusercontent.com/TheLartians/CPM/master/cmake/CPM.cmake
|
||||
mkdir -p cmake
|
||||
wget -O cmake/CPM.cmake https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake
|
||||
```
|
||||
|
||||
You can also download CPM.cmake directly from your project's `CMakeLists.txt`. See the [wiki](https://github.com/cpm-cmake/CPM.cmake/wiki/Downloading-CPM.cmake-in-CMake) for more details.
|
||||
|
||||
## Updating CPM
|
||||
|
||||
To update CPM to the newest version, simply update the script in the project's cmake directory, for example by running the command above. Dependencies using CPM will automatically use the updated script of the outermost project.
|
||||
|
||||
## Options
|
||||
|
||||
Setting the CMake option `CPM_USE_LOCAL_PACKAGES` will activate finding packages via `find_package`. If the option `CPM_LOCAL_PACKAGES_ONLY` is set, CPM will only use local packages.
|
||||
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.
|
||||
|
||||
## Advantages
|
||||
|
||||
- **Small repos** CPM takes care of project dependencies, allowing you to focus on creating small, well-tested frameworks.
|
||||
- **Cross-Plattform** CPM adds projects via `add_subdirectory`, which is compatible with all cmake toolchains and generators.
|
||||
- **Reproducable builds** By using versioning via git tags it is ensured that a project will always be in the same state everywhere.
|
||||
- **No installation required** No need to install anything. Just add the script to your project and you're good to go.
|
||||
- **No Setup required** There is a good chance your existing projects already work as CPM dependencies.
|
||||
- **Small and reusable projects** CPM takes care of all project dependencies, allowing developers to focus on creating small, well-tested libraries.
|
||||
- **Cross-Platform** CPM adds projects directly at the configure stage and is compatible with all CMake toolchains and generators.
|
||||
- **Reproducible builds** By versioning dependencies via git commits or tags it is ensured that a project will always be buildable.
|
||||
- **Recursive dependencies** Ensures that no dependency is added twice and all are added in the minimum required version.
|
||||
- **Plug-and-play** No need to install anything. Just add the script to your project and you're good to go.
|
||||
- **No packaging required** Simply add all external sources as a dependency.
|
||||
- **Simple source distribution** CPM makes including projects with source files and dependencies easy, reducing the need for monolithic header files or git submodules.
|
||||
|
||||
## Limitations
|
||||
|
||||
- **First version used** In diamond-shaped dependency graphs (e.g. `A` depends on `C`(v1.1) and `A` depends on `B` depends on `C`(v1.2)) the first added dependency will be used (in this case `C`@1.1). If the current version is older than the version beeing added, or if provided options are incompatible, a CMake warning will be emitted. To resolve, add the new version of the common dependency to the outer project.
|
||||
- **No auto-update** To update a dependency, version numbers or git tags in the cmake scripts must be adapted manually.
|
||||
- **No pre-built binaries** Unless they are installed or included in the linked repository.
|
||||
- **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).
|
||||
- **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).
|
||||
|
||||
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.
|
||||
Additionally, the option [`CPM_USE_LOCAL_PACKAGES`](#cpmuselocalpackages) will enable `find_package` for all CPM dependencies.
|
||||
|
||||
## Comparison to FindPackage
|
||||
|
||||
The usual way to add libraries in CMake projects is to call `find_package(<PackageName>)` and to link against libraries defined in a `<PackageName>_LIBRARIES` variable.
|
||||
While simple, this may lead to unpredictable builds, as it requires the library to be installed on the system and it is unclear which version of the library has been added.
|
||||
Additionally, it is difficult to cross-compile projects (e.g. for mobile), as the dependencies will need to be rebuilt manually for each targeted architecture.
|
||||
|
||||
CPM.cmake allows dependencies to be unambiguously defined and builds them from source.
|
||||
Note that the behaviour differs from `find_package`, as variables exported to the parent scope (such as `<PackageName>_LIBRARIES`) will not be visible after adding a package using CPM.cmake.
|
||||
The behaviour can be [achieved manually](https://github.com/cpm-cmake/CPM.cmake/issues/132#issuecomment-644955140), if required.
|
||||
|
||||
## Comparison to pure FetchContent / ExternalProject
|
||||
|
||||
CPM.cmake is a wrapper for CMake's FetchContent module and adds a number of features that turn it into a useful dependency manager.
|
||||
The most notable features are:
|
||||
|
||||
- A simpler to use API
|
||||
- Version checking: CPM.cmake will check the version number of any added dependency and emit a warning if another dependency requires a more recent version.
|
||||
- Offline builds: CPM.cmake will override CMake's download and update commands, which allows new builds to be configured while offline if all dependencies [are available locally](#cpm_source_cache).
|
||||
- Automatic shallow clone: if a version tag (e.g. `v2.2.0`) is provided and `CPM_SOURCE_CACHE` is used, CPM.cmake will perform a shallow clone of the dependency, which should be significantly faster while using less storage than a full clone.
|
||||
- Overridable: all `CPMAddPackage` can be configured to use `find_package` by setting a [CMake flag](#cpm_use_local_packages), making it easy to integrate into projects that may require local versioning through the system's package manager.
|
||||
- [Package lock files](#package-lock) for easier transitive dependency management.
|
||||
- Dependencies can be overridden [per-build](#local-package-override) using CMake CLI parameters.
|
||||
|
||||
ExternalProject works similarly as FetchContent, however waits with adding dependencies until build time.
|
||||
This has a quite a few disadvantages, especially as it makes using custom toolchains / cross-compiling very difficult and can lead to problems with nested dependencies.
|
||||
|
||||
## Options
|
||||
|
||||
### CPM_SOURCE_CACHE
|
||||
|
||||
To avoid re-downloading dependencies, CPM has an option `CPM_SOURCE_CACHE` that can be passed to CMake as `-DCPM_SOURCE_CACHE=<path to an external download directory>`.
|
||||
This will also allow projects to be configured offline, as long as the dependencies have been added to the cache before.
|
||||
It may also be defined system-wide as an environmental variable, e.g. by exporting `CPM_SOURCE_CACHE` in your `.bashrc` or `.bash_profile`.
|
||||
|
||||
```bash
|
||||
export CPM_SOURCE_CACHE=$HOME/.cache/CPM
|
||||
```
|
||||
|
||||
Note that passing the variable as a configure option to CMake will always override the value set by the environmental variable.
|
||||
|
||||
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.
|
||||
|
||||
### CPM_DOWNLOAD_ALL
|
||||
|
||||
If set, CPM will forward all calls to `CPMFindPackage` as `CPMAddPackage`.
|
||||
This is useful to create reproducible builds or to determine if the source parameters have all been set correctly.
|
||||
This can also be set as an environmental variable.
|
||||
This can be controlled on a per package basis with the `CPM_DOWNLOAD_<dependency name>` variable.
|
||||
|
||||
### CPM_USE_LOCAL_PACKAGES
|
||||
|
||||
CPM can be configured to use `find_package` to search for locally installed dependencies first by setting the CMake option `CPM_USE_LOCAL_PACKAGES`.
|
||||
If the option `CPM_LOCAL_PACKAGES_ONLY` is set, CPM will emit an error if the dependency is not found locally.
|
||||
These options can also be set as environmental variables.
|
||||
|
||||
In the case that `find_package` requires additional arguments, the parameter `FIND_PACKAGE_ARGUMENTS` may be specified in the `CPMAddPackage` call. The value of this parameter will be forwarded to `find_package`.
|
||||
|
||||
### 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.
|
||||
This can also be set as an environmental variable.
|
||||
|
||||
## Local package override
|
||||
|
||||
Library developers are often in the situation where they work on a locally checked out dependency at the same time as on a consumer project.
|
||||
It is possible to override the consumer's dependency with the version by supplying the CMake option `CPM_<dependency name>_SOURCE` set to the absolute path of the local library.
|
||||
For example, to use the local version of the dependency `Dep` at the path `/path/to/dep`, the consumer can be built with the following command.
|
||||
|
||||
```bash
|
||||
cmake -Bbuild -DCPM_Dep_SOURCE=/path/to/dep
|
||||
```
|
||||
|
||||
## Package lock
|
||||
|
||||
In large projects with many transitive dependencies, it can be useful to introduce a package lock file.
|
||||
This will list all CPM.cmake dependencies and can be used to update dependencies without modifying the original `CMakeLists.txt`.
|
||||
To use a package lock, add the following line directly after including CPM.cmake.
|
||||
|
||||
```cmake
|
||||
CPMUsePackageLock(package-lock.cmake)
|
||||
```
|
||||
|
||||
To create or update the package lock file, build the `cpm-update-package-lock` target.
|
||||
|
||||
```bash
|
||||
cmake -Bbuild
|
||||
cmake --build build --target cpm-update-package-lock
|
||||
```
|
||||
|
||||
See the [wiki](https://github.com/cpm-cmake/CPM.cmake/wiki/Package-lock) for more info.
|
||||
|
||||
## Built with CPM.cmake
|
||||
|
||||
Some amazing projects that are built using the CPM.cmake package manager.
|
||||
If you know others, feel free to add them here through a PR.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://bitfieldaudio.com">
|
||||
<p align="center">
|
||||
<img src="https://avatars2.githubusercontent.com/u/40357059?s=200&v=4" alt="otto-project" height=100pt width=100pt />
|
||||
</p>
|
||||
<p align="center"><b>OTTO - The Open Source GrooveBox</b></p>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://maphi.app">
|
||||
<p align="center">
|
||||
<img src="https://user-images.githubusercontent.com/4437447/89892751-71af8000-dbd7-11ea-9d87-4fe107845069.png" alt="maphi" height=100pt width=100pt />
|
||||
</p>
|
||||
<p align="center"><b>Maphi - the Math App</b></p>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://github.com/TheLartians/ModernCppStarter">
|
||||
<p align="center">
|
||||
<img src="https://repository-images.githubusercontent.com/254842585/4dfa7580-7ffb-11ea-99d0-46b8fe2f4170" alt="modern-cpp-starter" height=100pt width=200pt />
|
||||
</p>
|
||||
<p align="center"><b>ModernCppStarter</b></p>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://git.io/liblava">
|
||||
<p align="center">
|
||||
<img src="https://github.com/liblava.png" alt="liblava" width="100pt" />
|
||||
</p>
|
||||
<p align="center"><b>liblava - Modern Vulkan library</b></p>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Snippets
|
||||
|
||||
These examples demonstrate how to include some well-known projects with CPM.
|
||||
See the [wiki](https://github.com/cpm-cmake/CPM.cmake/wiki/More-Snippets) for more snippets.
|
||||
|
||||
### [Catch2](https://github.com/catchorg/Catch2)
|
||||
|
||||
```cmake
|
||||
CPMAddPackage("gh:catchorg/Catch2@2.5.0")
|
||||
```
|
||||
|
||||
### [Range-v3](https://github.com/ericniebler/range-v3)
|
||||
|
||||
```Cmake
|
||||
CPMAddPackage("gh:ericniebler/range-v3#0.11.0")
|
||||
```
|
||||
|
||||
### [Yaml-cpp](https://github.com/jbeder/yaml-cpp)
|
||||
|
||||
```CMake
|
||||
# as the tag is in an unusual format, we need to explicitly specify the version
|
||||
CPMAddPackage("gh:jbeder/yaml-cpp#yaml-cpp-0.6.3@0.6.3")
|
||||
```
|
||||
|
||||
### [nlohmann/json](https://github.com/nlohmann/json)
|
||||
|
||||
```cmake
|
||||
CPMAddPackage(
|
||||
NAME nlohmann_json
|
||||
VERSION 3.9.1
|
||||
GITHUB_REPOSITORY nlohmann/json
|
||||
OPTIONS
|
||||
"JSON_BuildTests OFF"
|
||||
)
|
||||
```
|
||||
|
||||
### [Boost ](https://github.com/boostorg/boost)
|
||||
|
||||
```CMake
|
||||
# boost is a huge project and will take a while to download
|
||||
# using `CPM_SOURCE_CACHE` is strongly recommended
|
||||
CPMAddPackage(
|
||||
NAME Boost
|
||||
VERSION 1.77.0
|
||||
GITHUB_REPOSITORY "boostorg/boost"
|
||||
GIT_TAG "boost-1.77.0"
|
||||
)
|
||||
```
|
||||
|
||||
### [cxxopts](https://github.com/jarro2783/cxxopts)
|
||||
|
||||
```cmake
|
||||
# the install option has to be explicitly set to allow installation
|
||||
CPMAddPackage(
|
||||
GITHUB_REPOSITORY jarro2783/cxxopts
|
||||
VERSION 2.2.1
|
||||
OPTIONS "CXXOPTS_BUILD_EXAMPLES NO" "CXXOPTS_BUILD_TESTS NO" "CXXOPTS_ENABLE_INSTALL YES"
|
||||
)
|
||||
```
|
||||
|
||||
### [google/benchmark](https://github.com/google/benchmark)
|
||||
|
||||
```cmake
|
||||
CPMAddPackage(
|
||||
NAME benchmark
|
||||
GITHUB_REPOSITORY google/benchmark
|
||||
VERSION 1.5.2
|
||||
OPTIONS "BENCHMARK_ENABLE_TESTING Off"
|
||||
)
|
||||
|
||||
if(benchmark_ADDED)
|
||||
# enable c++11 to avoid compilation errors
|
||||
set_target_properties(benchmark PROPERTIES CXX_STANDARD 11)
|
||||
endif()
|
||||
```
|
||||
|
||||
### [Lua](https://www.lua.org)
|
||||
|
||||
```cmake
|
||||
CPMAddPackage(
|
||||
NAME lua
|
||||
GIT_REPOSITORY https://github.com/lua/lua.git
|
||||
VERSION 5.3.5
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
|
||||
if (lua_ADDED)
|
||||
# lua has no CMake support, so we create our own target
|
||||
|
||||
FILE(GLOB lua_sources ${lua_SOURCE_DIR}/*.c)
|
||||
list(REMOVE_ITEM lua_sources "${lua_SOURCE_DIR}/lua.c" "${lua_SOURCE_DIR}/luac.c")
|
||||
add_library(lua STATIC ${lua_sources})
|
||||
|
||||
target_include_directories(lua
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${lua_SOURCE_DIR}>
|
||||
)
|
||||
endif()
|
||||
```
|
||||
|
||||
For a full example on using CPM to download and configure lua with sol2 see [here](examples/sol2).
|
||||
|
||||
### 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.
|
||||
|
||||
1110
cmake/CPM.cmake
1110
cmake/CPM.cmake
File diff suppressed because it is too large
Load Diff
21
cmake/get_cpm.cmake
Normal file
21
cmake/get_cpm.cmake
Normal file
@@ -0,0 +1,21 @@
|
||||
set(CPM_DOWNLOAD_VERSION 1.0.0-development-version)
|
||||
|
||||
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")
|
||||
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
|
||||
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
|
||||
else()
|
||||
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
|
||||
endif()
|
||||
|
||||
if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
|
||||
message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
|
||||
file(DOWNLOAD
|
||||
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
|
||||
${CPM_DOWNLOAD_LOCATION}
|
||||
)
|
||||
endif()
|
||||
|
||||
include(${CPM_DOWNLOAD_LOCATION})
|
||||
81
cmake/testing.cmake
Normal file
81
cmake/testing.cmake
Normal file
@@ -0,0 +1,81 @@
|
||||
function(ASSERT_EQUAL)
|
||||
if(NOT ARGC EQUAL 2)
|
||||
message(FATAL_ERROR "assertion failed: invalid argument count: ${ARGC}")
|
||||
endif()
|
||||
|
||||
if(NOT "${ARGV0}" STREQUAL "${ARGV1}")
|
||||
message(FATAL_ERROR "assertion failed: '${ARGV0}' != '${ARGV1}'")
|
||||
else()
|
||||
message(STATUS "test passed: '${ARGV0}' == '${ARGV1}'")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(ASSERT_NOT_EQUAL)
|
||||
if(NOT ARGC EQUAL 2)
|
||||
message(FATAL_ERROR "assertion failed: invalid argument count: ${ARGC}")
|
||||
endif()
|
||||
|
||||
if("${ARGV0}" STREQUAL "${ARGV1}")
|
||||
message(FATAL_ERROR "assertion failed: '${ARGV0}' == '${ARGV1}'")
|
||||
else()
|
||||
message(STATUS "test passed: '${ARGV0}' != '${ARGV1}'")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(ASSERT_EMPTY)
|
||||
if(NOT ARGC EQUAL 0)
|
||||
message(FATAL_ERROR "assertion failed: input ${ARGC} not empty: '${ARGV}'")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(ASSERT_DEFINED KEY)
|
||||
if(DEFINED ${KEY})
|
||||
message(STATUS "test passed: '${KEY}' is defined")
|
||||
else()
|
||||
message(FATAL_ERROR "assertion failed: '${KEY}' is not defiend")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(ASSERT_NOT_DEFINED KEY)
|
||||
if(DEFINED ${KEY})
|
||||
message(FATAL_ERROR "assertion failed: '${KEY}' is defiend (${${KEY}})")
|
||||
else()
|
||||
message(STATUS "test passed: '${KEY}' is not defined")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(ASSERT_TRUTHY KEY)
|
||||
if(${${KEY}})
|
||||
message(STATUS "test passed: '${KEY}' is set truthy")
|
||||
else()
|
||||
message(FATAL_ERROR "assertion failed: value of '${KEY}' is not truthy (${${KEY}})")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(ASSERT_FALSY KEY)
|
||||
if(${${KEY}})
|
||||
message(FATAL_ERROR "assertion failed: value of '${KEY}' is not falsy (${${KEY}})")
|
||||
else()
|
||||
message(STATUS "test passed: '${KEY}' is set falsy")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(ASSERTION_FAILED)
|
||||
message(FATAL_ERROR "assertion failed: ${ARGN}")
|
||||
endfunction()
|
||||
|
||||
function(ASSERT_EXISTS file)
|
||||
if(EXISTS ${file})
|
||||
message(STATUS "test passed: '${file}' exists")
|
||||
else()
|
||||
message(FATAL_ERROR "assertion failed: file ${file} does not exist")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(ASSERT_NOT_EXISTS file)
|
||||
if(NOT EXISTS ${file})
|
||||
message(STATUS "test passed: '${file}' does not exist")
|
||||
else()
|
||||
message(FATAL_ERROR "assertion failed: file ${file} exists")
|
||||
endif()
|
||||
endfunction()
|
||||
7
examples/TestingFramework/CMakeLists.txt
Normal file
7
examples/TestingFramework/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMTestingFrameworkExample)
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
CPMAddPackage("bb:HEMRND/TestingFramework@0.4.1")
|
||||
add_test_suites(TESTS SomeTest)
|
||||
19
examples/TestingFramework/SomeTest.cpp
Normal file
19
examples/TestingFramework/SomeTest.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include <HEM/TestingFramework.hpp>
|
||||
|
||||
using namespace fakeit;
|
||||
|
||||
class ITest {
|
||||
public:
|
||||
virtual int getInt() = 0;
|
||||
};
|
||||
|
||||
TEST_CASE("Testing Framework Test") {
|
||||
constexpr int someIntValue = 123456;
|
||||
|
||||
Mock<ITest> testMock;
|
||||
When(Method(testMock, getInt)).Return(someIntValue);
|
||||
|
||||
int readValue = testMock.get().getInt();
|
||||
|
||||
REQUIRE(readValue == someIntValue);
|
||||
}
|
||||
63
examples/asio-standalone/CMakeLists.txt
Normal file
63
examples/asio-standalone/CMakeLists.txt
Normal file
@@ -0,0 +1,63 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMExampleASIOStandalone)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
CPMAddPackage("gh:chriskohlhoff/asio#asio-1-18-1@1.18.1")
|
||||
|
||||
# ASIO doesn't use CMake, we have to configure it manually. Extra notes for using on Windows:
|
||||
#
|
||||
# 1) If _WIN32_WINNT is not set, ASIO assumes _WIN32_WINNT=0x0501, i.e. Windows XP target, which is
|
||||
# definitely not the platform which most users target.
|
||||
#
|
||||
# 2) WIN32_LEAN_AND_MEAN is defined to make Winsock2 work.
|
||||
if(asio_ADDED)
|
||||
add_library(asio INTERFACE)
|
||||
|
||||
target_include_directories(asio SYSTEM INTERFACE ${asio_SOURCE_DIR}/asio/include)
|
||||
|
||||
target_compile_definitions(asio INTERFACE ASIO_STANDALONE ASIO_NO_DEPRECATED)
|
||||
|
||||
target_link_libraries(asio INTERFACE Threads::Threads)
|
||||
|
||||
if(WIN32)
|
||||
# macro see @ https://stackoverflow.com/a/40217291/1746503
|
||||
macro(get_win32_winnt version)
|
||||
if(CMAKE_SYSTEM_VERSION)
|
||||
set(ver ${CMAKE_SYSTEM_VERSION})
|
||||
string(REGEX MATCH "^([0-9]+).([0-9])" ver ${ver})
|
||||
string(REGEX MATCH "^([0-9]+)" verMajor ${ver})
|
||||
# Check for Windows 10, b/c we'll need to convert to hex 'A'.
|
||||
if("${verMajor}" MATCHES "10")
|
||||
set(verMajor "A")
|
||||
string(REGEX REPLACE "^([0-9]+)" ${verMajor} ver ${ver})
|
||||
endif("${verMajor}" MATCHES "10")
|
||||
# Remove all remaining '.' characters.
|
||||
string(REPLACE "." "" ver ${ver})
|
||||
# Prepend each digit with a zero.
|
||||
string(REGEX REPLACE "([0-9A-Z])" "0\\1" ver ${ver})
|
||||
set(${version} "0x${ver}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
if(NOT DEFINED _WIN32_WINNT)
|
||||
get_win32_winnt(ver)
|
||||
set(_WIN32_WINNT ${ver})
|
||||
endif()
|
||||
|
||||
message(STATUS "Set _WIN32_WINNET=${_WIN32_WINNT}")
|
||||
|
||||
target_compile_definitions(asio INTERFACE _WIN32_WINNT=${_WIN32_WINNT} WIN32_LEAN_AND_MEAN)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ---- Executable ----
|
||||
|
||||
add_executable(CPMExampleASIOStandalone main.cpp)
|
||||
target_link_libraries(CPMExampleASIOStandalone asio)
|
||||
target_compile_features(CPMExampleASIOStandalone PRIVATE cxx_std_11)
|
||||
93
examples/asio-standalone/main.cpp
Normal file
93
examples/asio-standalone/main.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// async_tcp_echo_server.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "asio.hpp"
|
||||
|
||||
// An asynchronous tcp echo server.
|
||||
// See https://think-async.com/Asio/asio-1.16.1/src/examples/cpp11/echo/async_tcp_echo_server.cpp
|
||||
|
||||
using asio::ip::tcp;
|
||||
|
||||
class session : public std::enable_shared_from_this<session> {
|
||||
public:
|
||||
session(tcp::socket socket) : socket_(std::move(socket)) {}
|
||||
|
||||
void start() { do_read(); }
|
||||
|
||||
private:
|
||||
void do_read() {
|
||||
auto self(shared_from_this());
|
||||
socket_.async_read_some(asio::buffer(data_, max_length),
|
||||
[this, self](std::error_code ec, std::size_t length) {
|
||||
if (!ec) {
|
||||
do_write(length);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_write(std::size_t length) {
|
||||
auto self(shared_from_this());
|
||||
asio::async_write(socket_, asio::buffer(data_, length),
|
||||
[this, self](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
do_read();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
tcp::socket socket_;
|
||||
enum { max_length = 1024 };
|
||||
char data_[max_length];
|
||||
};
|
||||
|
||||
class server {
|
||||
public:
|
||||
server(asio::io_context& io_context, short port)
|
||||
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) {
|
||||
do_accept();
|
||||
}
|
||||
|
||||
private:
|
||||
void do_accept() {
|
||||
acceptor_.async_accept([this](std::error_code ec, tcp::socket socket) {
|
||||
if (!ec) {
|
||||
std::make_shared<session>(std::move(socket))->start();
|
||||
}
|
||||
|
||||
do_accept();
|
||||
});
|
||||
}
|
||||
|
||||
tcp::acceptor acceptor_;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
try {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: async_tcp_echo_server <port>\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
asio::io_context io_context;
|
||||
|
||||
server s(io_context, std::atoi(argv[1]));
|
||||
|
||||
io_context.run();
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << "Exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
27
examples/benchmark/CMakeLists.txt
Normal file
27
examples/benchmark/CMakeLists.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMExampleBenchmark)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage("gh:cpm-cmake/testpack-fibonacci@2.0")
|
||||
|
||||
CPMAddPackage(
|
||||
NAME benchmark
|
||||
GITHUB_REPOSITORY google/benchmark
|
||||
VERSION 1.5.2
|
||||
OPTIONS "BENCHMARK_ENABLE_TESTING Off"
|
||||
)
|
||||
|
||||
if(benchmark_ADDED)
|
||||
# enable c++11 to avoid compilation errors
|
||||
set_target_properties(benchmark PROPERTIES CXX_STANDARD 11)
|
||||
endif()
|
||||
|
||||
# ---- Executable ----
|
||||
|
||||
add_executable(CPMExampleBenchmark "main.cpp")
|
||||
target_link_libraries(CPMExampleBenchmark fibonacci benchmark)
|
||||
target_compile_features(CPMExampleBenchmark PRIVATE cxx_std_17)
|
||||
35
examples/benchmark/main.cpp
Normal file
35
examples/benchmark/main.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <fibonacci.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
std::vector<unsigned> createTestNumbers() {
|
||||
std::vector<unsigned> v;
|
||||
for (int i = 0; i < 25; ++i) v.emplace_back(i);
|
||||
std::random_device rd;
|
||||
std::mt19937 g(rd());
|
||||
std::shuffle(v.begin(), v.end(), g);
|
||||
return v;
|
||||
}
|
||||
|
||||
void fibonacci(benchmark::State& state) {
|
||||
auto numbers = createTestNumbers();
|
||||
for (auto _ : state) {
|
||||
for (auto v : numbers) benchmark::DoNotOptimize(fibonacci(v));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(fibonacci);
|
||||
|
||||
void fastFibonacci(benchmark::State& state) {
|
||||
auto numbers = createTestNumbers();
|
||||
for (auto _ : state) {
|
||||
for (auto v : numbers) benchmark::DoNotOptimize(fastFibonacci(v));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(fastFibonacci);
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
21
examples/boost/CMakeLists.txt
Normal file
21
examples/boost/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMExampleBoost)
|
||||
|
||||
# ---- Create binary ----
|
||||
|
||||
add_executable(CPMExampleBoost main.cpp)
|
||||
target_compile_features(CPMExampleBoost PRIVATE cxx_std_17)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME Boost
|
||||
VERSION 1.77.0
|
||||
GITHUB_REPOSITORY "boostorg/boost"
|
||||
GIT_TAG "boost-1.77.0"
|
||||
)
|
||||
|
||||
target_link_libraries(CPMExampleBoost PRIVATE Boost::asio)
|
||||
26
examples/boost/main.cpp
Normal file
26
examples/boost/main.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// timer.cpp
|
||||
// ~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <iostream>
|
||||
|
||||
void print(const boost::system::error_code& /*e*/) { std::cout << "Hello, world!" << std::endl; }
|
||||
|
||||
int main() {
|
||||
boost::asio::io_service io;
|
||||
|
||||
boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));
|
||||
t.async_wait(&print);
|
||||
|
||||
io.run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
33
examples/build_all.py
Executable file
33
examples/build_all.py
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
|
||||
from pathlib import Path
|
||||
from subprocess import PIPE, run
|
||||
|
||||
examples = [
|
||||
x for x in Path(__file__).parent.iterdir() if x.is_dir() and (x / 'CMakeLists.txt').exists()
|
||||
]
|
||||
|
||||
assert(len(examples) > 0)
|
||||
|
||||
|
||||
def runCommand(command):
|
||||
print('- %s' % command)
|
||||
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True)
|
||||
if result.returncode != 0:
|
||||
print("error while running '%s':\n" % command, ' ' + str(result.stderr).replace('\n', '\n '))
|
||||
exit(result.returncode)
|
||||
return result.stdout
|
||||
|
||||
|
||||
print('')
|
||||
for example in examples:
|
||||
print("running example %s" % example.name)
|
||||
print("================" + ('=' * len(example.name)))
|
||||
project = Path(".") / 'build' / example.name
|
||||
configure = runCommand('cmake -S%s -B%s' % (example, project))
|
||||
print(' ' + '\n '.join([line for line in configure.split('\n') if 'CPM:' in line]))
|
||||
build = runCommand('cmake --build %s -- -j%i' % (project, os.cpu_count() / 2))
|
||||
print(' ' + '\n '.join([line for line in build.split('\n') if 'Built target' in line]))
|
||||
print('')
|
||||
21
examples/catch2/CMakeLists.txt
Normal file
21
examples/catch2/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMExampleCatch2)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage("gh:cpm-cmake/testpack-fibonacci@2.0")
|
||||
CPMAddPackage("gh:catchorg/Catch2@2.13.4")
|
||||
|
||||
# ---- Create binary ----
|
||||
|
||||
add_executable(CPMExampleCatch2 main.cpp)
|
||||
target_link_libraries(CPMExampleCatch2 fibonacci Catch2)
|
||||
target_compile_features(CPMExampleCatch2 PRIVATE cxx_std_17)
|
||||
|
||||
# ---- Enable testing ----
|
||||
|
||||
enable_testing()
|
||||
add_test(CPMExampleCatch2 CPMExampleCatch2)
|
||||
21
examples/catch2/main.cpp
Normal file
21
examples/catch2/main.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include <fibonacci.h>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
TEST_CASE("fibonacci") {
|
||||
REQUIRE(fibonacci(0) == 0);
|
||||
REQUIRE(fibonacci(1) == 1);
|
||||
REQUIRE(fibonacci(2) == 1);
|
||||
REQUIRE(fibonacci(3) == 2);
|
||||
REQUIRE(fibonacci(4) == 3);
|
||||
REQUIRE(fibonacci(5) == 5);
|
||||
REQUIRE(fibonacci(13) == 233);
|
||||
}
|
||||
|
||||
TEST_CASE("fastFibonacci") {
|
||||
for (unsigned i = 0; i < 25; ++i) {
|
||||
REQUIRE(fibonacci(i) == fastFibonacci(i));
|
||||
}
|
||||
}
|
||||
20
examples/cereal/CMakeLists.txt
Normal file
20
examples/cereal/CMakeLists.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMExampleCereal)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME cereal
|
||||
VERSION 1.3.0
|
||||
GITHUB_REPOSITORY USCiLab/cereal
|
||||
OPTIONS "SKIP_PORTABILITY_TEST ON" "JUST_INSTALL_CEREAL ON"
|
||||
)
|
||||
|
||||
# ---- Create binary ----
|
||||
|
||||
add_executable(CPMExampleCereal main.cpp)
|
||||
target_link_libraries(CPMExampleCereal cereal)
|
||||
target_compile_features(CPMExampleCereal PRIVATE cxx_std_17)
|
||||
26
examples/cereal/main.cpp
Normal file
26
examples/cereal/main.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
struct player_data {
|
||||
int id{-1};
|
||||
std::string name{};
|
||||
};
|
||||
|
||||
template <typename Archive> void serialize(Archive &archive, player_data const &data) {
|
||||
archive(cereal::make_nvp("id", data.id), cereal::make_nvp("name", data.name));
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[]) {
|
||||
player_data player{3, "Gamer One"};
|
||||
std::ostringstream oss;
|
||||
cereal::JSONOutputArchive output(oss);
|
||||
output(cereal::make_nvp("player_data", player));
|
||||
|
||||
std::cout << oss.str() << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
||||
|
||||
project(CPMTest)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/CPM.cmake)
|
||||
|
||||
# ignore locally installed projects for reproducable builds
|
||||
set(CPM_REMOTE_PACKAGES_ONLY ON CACHE INTERNAL "")
|
||||
|
||||
# util library
|
||||
CPMAddPackage(
|
||||
NAME LHC
|
||||
GIT_REPOSITORY https://github.com/TheLartians/LHC.git
|
||||
VERSION 0.7
|
||||
)
|
||||
|
||||
# will be ignored as newer version already added
|
||||
CPMAddPackage(
|
||||
NAME LHC
|
||||
GIT_REPOSITORY https://github.com/TheLartians/LHC.git
|
||||
VERSION 0.2
|
||||
)
|
||||
|
||||
# language bindings
|
||||
# uses git tag instead of version identifier
|
||||
# depends on visitor library that depends on Event library and LHC
|
||||
# CMake configuration arguments passed via OPTIONS
|
||||
CPMAddPackage(
|
||||
NAME Glue
|
||||
GIT_TAG 78af65625751ad15a42ca52b842863e85b5d2adc
|
||||
GIT_REPOSITORY https://github.com/TheLartians/Glue.git
|
||||
VERSION 0.5.1
|
||||
OPTIONS
|
||||
"GLUE_ENABLE_LUA ON"
|
||||
"GLUE_BUILD_LUA ON"
|
||||
)
|
||||
|
||||
# parser library
|
||||
# depends on LHC and Glue
|
||||
CPMAddPackage(
|
||||
NAME LarsParser
|
||||
GIT_REPOSITORY https://github.com/TheLartians/Parser.git
|
||||
VERSION 1.8
|
||||
OPTIONS
|
||||
"LARS_PARSER_BUILD_GLUE_EXTENSION ON"
|
||||
)
|
||||
|
||||
# add executable
|
||||
add_executable(cpm-test-complex main.cpp)
|
||||
set_target_properties(cpm-test-complex PROPERTIES CXX_STANDARD 17)
|
||||
target_link_libraries(cpm-test-complex LHC LarsParser Glue)
|
||||
|
||||
# tests
|
||||
enable_testing()
|
||||
add_test(cpm-test-complex cpm-test-complex)
|
||||
@@ -1,52 +0,0 @@
|
||||
#include <lars/parser/extension.h>
|
||||
#include <lars/lua_glue.h>
|
||||
#include <stdexcept>
|
||||
|
||||
int main() {
|
||||
// create lua state
|
||||
auto lua = lars::LuaState();
|
||||
lua.open_libs();
|
||||
|
||||
// create extensions
|
||||
lars::Extension extensions;
|
||||
|
||||
// add parser library to extension
|
||||
extensions.add_extension("parser", lars::extensions::parser());
|
||||
|
||||
// connect parser extension to lua
|
||||
extensions.connect(lua.get_glue());
|
||||
|
||||
// create a parser
|
||||
lua.run(R"(
|
||||
NumberMap = parser.Program.create()
|
||||
|
||||
NumberMap:setRule("Whitespace", "[ \t]")
|
||||
NumberMap:setSeparatorRule("Whitespace")
|
||||
|
||||
NumberMap:setRuleWithCallback("Object", "'{' KeyValue (',' KeyValue)* '}'",function(e)
|
||||
local N = e:size()-1
|
||||
local res = {}
|
||||
for i=0,N do
|
||||
local a = e:get(i)
|
||||
res[a:get(0):evaluate()] = a:get(1):evaluate()
|
||||
end
|
||||
return res
|
||||
end)
|
||||
|
||||
NumberMap:setRule("KeyValue", "Number ':' Number")
|
||||
|
||||
NumberMap:setRuleWithCallback("Number", "'-'? [0-9]+", function(e) return tonumber(e:string()); end)
|
||||
|
||||
NumberMap:setStartRule("Object")
|
||||
)");
|
||||
|
||||
// parse a string
|
||||
lua.run("m = NumberMap:run('{1:3, 2:-1, 3:42}')");
|
||||
|
||||
// check result
|
||||
if (lua.get_numeric("m[1]") != 3) throw std::runtime_error("unexpected result");
|
||||
if (lua.get_numeric("m[2]") != -1) throw std::runtime_error("unexpected result");
|
||||
if (lua.get_numeric("m[3]") != 42) throw std::runtime_error("unexpected result");
|
||||
|
||||
return 0;
|
||||
}
|
||||
15
examples/cxxopts/CMakeLists.txt
Normal file
15
examples/cxxopts/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMExampleCXXOpts)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage("gh:jarro2783/cxxopts@2.2.0")
|
||||
|
||||
# ---- Create binary ----
|
||||
|
||||
add_executable(CPMExampleCXXOpts main.cpp)
|
||||
target_link_libraries(CPMExampleCXXOpts cxxopts)
|
||||
target_compile_features(CPMExampleCXXOpts PRIVATE cxx_std_17)
|
||||
27
examples/cxxopts/main.cpp
Normal file
27
examples/cxxopts/main.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <cxxopts.hpp>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
cxxopts::Options options("MyProgram", "One line description of MyProgram");
|
||||
|
||||
// clang-format off
|
||||
options.add_options()
|
||||
("h,help", "Show help")
|
||||
("d,debug", "Enable debugging")
|
||||
("f,file", "File name", cxxopts::value<std::string>()
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
auto result = options.parse(argc, argv);
|
||||
|
||||
if (result["help"].as<bool>()) {
|
||||
std::cout << options.help() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (auto arg : result.arguments()) {
|
||||
std::cout << "option: " << arg.key() << ": " << arg.value() << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
21
examples/doctest/CMakeLists.txt
Normal file
21
examples/doctest/CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMExampleDoctest)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage("gh:cpm-cmake/testpack-fibonacci@2.0")
|
||||
CPMAddPackage("gh:onqtam/doctest#2.4.5")
|
||||
|
||||
# ---- Create binary ----
|
||||
|
||||
add_executable(CPMExampleDoctest main.cpp)
|
||||
target_link_libraries(CPMExampleDoctest fibonacci doctest)
|
||||
target_compile_features(CPMExampleDoctest PRIVATE cxx_std_17)
|
||||
|
||||
# ---- Enable testing ----
|
||||
|
||||
enable_testing()
|
||||
add_test(CPMExampleDoctest CPMExampleDoctest)
|
||||
20
examples/doctest/main.cpp
Normal file
20
examples/doctest/main.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
#include <fibonacci.h>
|
||||
|
||||
TEST_CASE("fibonacci") {
|
||||
CHECK(fibonacci(0) == 0);
|
||||
CHECK(fibonacci(1) == 1);
|
||||
CHECK(fibonacci(2) == 1);
|
||||
CHECK(fibonacci(3) == 2);
|
||||
CHECK(fibonacci(4) == 3);
|
||||
CHECK(fibonacci(5) == 5);
|
||||
CHECK(fibonacci(13) == 233);
|
||||
}
|
||||
|
||||
TEST_CASE("fastfibonacci") {
|
||||
for (unsigned i = 0; i < 25; ++i) {
|
||||
CHECK(fibonacci(i) == fastFibonacci(i));
|
||||
}
|
||||
}
|
||||
26
examples/entt/CMakeLists.txt
Normal file
26
examples/entt/CMakeLists.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMEnTTExample)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME EnTT
|
||||
VERSION 3.1.1
|
||||
GITHUB_REPOSITORY skypjack/entt
|
||||
# EnTT's CMakeLists screws with configuration options
|
||||
DOWNLOAD_ONLY True
|
||||
)
|
||||
|
||||
if(EnTT_ADDED)
|
||||
add_library(EnTT INTERFACE)
|
||||
target_include_directories(EnTT SYSTEM INTERFACE ${EnTT_SOURCE_DIR}/src)
|
||||
endif()
|
||||
|
||||
# ---- Executable ----
|
||||
|
||||
add_executable(CPMEnTTExample main.cpp)
|
||||
target_compile_features(CPMEnTTExample PRIVATE cxx_std_17)
|
||||
target_link_libraries(CPMEnTTExample EnTT)
|
||||
56
examples/entt/main.cpp
Normal file
56
examples/entt/main.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#include <cstdint>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
struct position {
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
struct velocity {
|
||||
float dx;
|
||||
float dy;
|
||||
};
|
||||
|
||||
void update(entt::registry ®istry) {
|
||||
auto view = registry.view<position, velocity>();
|
||||
|
||||
for (auto entity : view) {
|
||||
// gets only the components that are going to be used ...
|
||||
|
||||
auto &vel = view.get<velocity>(entity);
|
||||
|
||||
vel.dx = 0.;
|
||||
vel.dy = 0.;
|
||||
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
void update(std::uint64_t dt, entt::registry ®istry) {
|
||||
registry.view<position, velocity>().each([dt](auto &pos, auto &vel) {
|
||||
// gets all the components of the view at once ...
|
||||
|
||||
pos.x += vel.dx * dt;
|
||||
pos.y += vel.dy * dt;
|
||||
|
||||
// ...
|
||||
});
|
||||
}
|
||||
|
||||
int main() {
|
||||
entt::registry registry;
|
||||
std::uint64_t dt = 16;
|
||||
|
||||
for (auto i = 0; i < 10; ++i) {
|
||||
auto entity = registry.create();
|
||||
registry.assign<position>(entity, i * 1.f, i * 1.f);
|
||||
if (i % 2 == 0) {
|
||||
registry.assign<velocity>(entity, i * .1f, i * .1f);
|
||||
}
|
||||
}
|
||||
|
||||
update(dt, registry);
|
||||
update(registry);
|
||||
|
||||
// ...
|
||||
}
|
||||
15
examples/fmt/CMakeLists.txt
Normal file
15
examples/fmt/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMJSONExample)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage("gh:fmtlib/fmt#7.1.3")
|
||||
|
||||
# ---- Executable ----
|
||||
|
||||
add_executable(CPMFmtExample main.cpp)
|
||||
target_compile_features(CPMFmtExample PRIVATE cxx_std_17)
|
||||
target_link_libraries(CPMFmtExample fmt)
|
||||
6
examples/fmt/main.cpp
Normal file
6
examples/fmt/main.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <fmt/format.h>
|
||||
|
||||
int main() {
|
||||
fmt::print("Hello, {}!\n", "world");
|
||||
return 0;
|
||||
}
|
||||
28
examples/gtest/CMakeLists.txt
Normal file
28
examples/gtest/CMakeLists.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMExampleGtest)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage("gh:cpm-cmake/testpack-fibonacci@2.0")
|
||||
|
||||
CPMAddPackage(
|
||||
NAME googletest
|
||||
GITHUB_REPOSITORY google/googletest
|
||||
GIT_TAG release-1.10.0
|
||||
VERSION 1.10.0
|
||||
OPTIONS "INSTALL_GTEST OFF" "gtest_force_shared_crt"
|
||||
)
|
||||
|
||||
# ---- Create binary ----
|
||||
|
||||
add_executable(CPMExampleGtest main.cpp)
|
||||
target_link_libraries(CPMExampleGtest fibonacci gtest gtest_main gmock)
|
||||
target_compile_features(CPMExampleGtest PRIVATE cxx_std_17)
|
||||
|
||||
# ---- Enable testing ----
|
||||
|
||||
enable_testing()
|
||||
add_test(CPMExampleGtest CPMExampleGtest)
|
||||
12
examples/gtest/main.cpp
Normal file
12
examples/gtest/main.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <fibonacci.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(FibonacciTests, BasicChecks) {
|
||||
ASSERT_TRUE(fibonacci(0) == 0);
|
||||
ASSERT_TRUE(fibonacci(1) == 1);
|
||||
ASSERT_TRUE(fibonacci(2) == 1);
|
||||
ASSERT_TRUE(fibonacci(3) == 2);
|
||||
ASSERT_TRUE(fibonacci(4) == 3);
|
||||
ASSERT_TRUE(fibonacci(5) == 5);
|
||||
ASSERT_TRUE(fibonacci(13) == 233);
|
||||
}
|
||||
14
examples/json/CMakeLists.txt
Normal file
14
examples/json/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMJSONExample)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
CPMAddPackage("gh:nlohmann/json@3.10.5")
|
||||
|
||||
# ---- Executable ----
|
||||
|
||||
add_executable(CPMJSONExample main.cpp)
|
||||
target_compile_features(CPMJSONExample PRIVATE cxx_std_17)
|
||||
target_link_libraries(CPMJSONExample nlohmann_json::nlohmann_json)
|
||||
17
examples/json/main.cpp
Normal file
17
examples/json/main.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
int main() {
|
||||
nlohmann::json json = {{"pi", 3.141},
|
||||
{"happy", true},
|
||||
{"name", "Niels"},
|
||||
{"nothing", nullptr},
|
||||
{"answer", {{"everything", 42}}},
|
||||
{"list", {1, 0, 2}},
|
||||
{"object", {{"currency", "USD"}, {"value", 42.99}}}};
|
||||
|
||||
std::cout << "declared JSON object: " << std::setw(2) << json << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
20
examples/linenoise/CMakeLists.txt
Normal file
20
examples/linenoise/CMakeLists.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMlinenoiseExample)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage("gh:antirez/linenoise#1.0")
|
||||
|
||||
if(linenoise_ADDED)
|
||||
add_library(linenoise ${linenoise_SOURCE_DIR}/linenoise.c)
|
||||
target_include_directories(linenoise SYSTEM PUBLIC ${linenoise_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
# ---- Executable ----
|
||||
|
||||
add_executable(CPMlinenoiseExample main.cpp)
|
||||
target_compile_features(CPMlinenoiseExample PRIVATE cxx_std_17)
|
||||
target_link_libraries(CPMlinenoiseExample linenoise)
|
||||
64
examples/linenoise/main.cpp
Normal file
64
examples/linenoise/main.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "linenoise.h"
|
||||
|
||||
void completion(const char *buf, linenoiseCompletions *lc) {
|
||||
if (buf[0] == 'h') {
|
||||
linenoiseAddCompletion(lc, "hello");
|
||||
linenoiseAddCompletion(lc, "hello there");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *line;
|
||||
char *prgname = argv[0];
|
||||
|
||||
/* Parse options, with --multiline we enable multi line editing. */
|
||||
while (argc > 1) {
|
||||
argc--;
|
||||
argv++;
|
||||
if (!strcmp(*argv, "--multiline")) {
|
||||
linenoiseSetMultiLine(1);
|
||||
printf("Multi-line mode enabled.\n");
|
||||
} else if (!strcmp(*argv, "--keycodes")) {
|
||||
linenoisePrintKeyCodes();
|
||||
exit(0);
|
||||
} else {
|
||||
fprintf(stderr, "Usage: %s [--multiline] [--keycodes]\n", prgname);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the completion callback. This will be called every time the
|
||||
* user uses the <tab> key. */
|
||||
linenoiseSetCompletionCallback(completion);
|
||||
|
||||
/* Load history from file. The history file is just a plain text file
|
||||
* where entries are separated by newlines. */
|
||||
linenoiseHistoryLoad("history.txt"); /* Load the history at startup */
|
||||
|
||||
/* Now this is the main loop of the typical linenoise-based application.
|
||||
* The call to linenoise() will block as long as the user types something
|
||||
* and presses enter.
|
||||
*
|
||||
* The typed string is returned as a malloc() allocated string by
|
||||
* linenoise, so the user needs to free() it. */
|
||||
while ((line = linenoise("hello> ")) != NULL) {
|
||||
/* Do something with the string. */
|
||||
if (line[0] != '\0' && line[0] != '/') {
|
||||
printf("echo: '%s'\n", line);
|
||||
linenoiseHistoryAdd(line); /* Add to the history. */
|
||||
linenoiseHistorySave("history.txt"); /* Save the history on disk. */
|
||||
} else if (!strncmp(line, "/historylen", 11)) {
|
||||
/* The "/historylen" command will change the history len. */
|
||||
int len = atoi(line + 11);
|
||||
linenoiseHistorySetMaxLen(len);
|
||||
} else if (line[0] == '/') {
|
||||
printf("Unreconized command: %s\n", line);
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
15
examples/range-v3/CMakeLists.txt
Normal file
15
examples/range-v3/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMRangev3Example)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage("gh:ericniebler/range-v3#0.11.0")
|
||||
|
||||
# ---- Executable ----
|
||||
|
||||
add_executable(CPMRangev3Example main.cpp)
|
||||
target_compile_features(CPMRangev3Example PRIVATE cxx_std_17)
|
||||
target_link_libraries(CPMRangev3Example range-v3)
|
||||
41
examples/range-v3/main.cpp
Normal file
41
examples/range-v3/main.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Range v3 library
|
||||
//
|
||||
// Copyright Jeff Garland 2017
|
||||
//
|
||||
// Use, modification and distribution is subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Project home: https://github.com/ericniebler/range-v3
|
||||
//
|
||||
|
||||
//[any_all_none_of]]
|
||||
// Demonstrates any_of, all_of, none_of
|
||||
// output
|
||||
// vector: [6,2,3,4,5,6]
|
||||
// vector any_of is_six: true
|
||||
// vector all_of is_six: false
|
||||
// vector none_of is_six: false
|
||||
|
||||
#include <iostream>
|
||||
#include <range/v3/algorithm/all_of.hpp>
|
||||
#include <range/v3/algorithm/any_of.hpp>
|
||||
#include <range/v3/algorithm/for_each.hpp>
|
||||
#include <range/v3/algorithm/none_of.hpp>
|
||||
#include <range/v3/view/all.hpp>
|
||||
#include <vector>
|
||||
using std::cout;
|
||||
|
||||
auto is_six = [](int i) { return i == 6; };
|
||||
|
||||
int main() {
|
||||
std::vector<int> v{6, 2, 3, 4, 5, 6};
|
||||
cout << std::boolalpha;
|
||||
cout << "vector: " << ranges::views::all(v) << '\n';
|
||||
|
||||
cout << "vector any_of is_six: " << ranges::any_of(v, is_six) << '\n';
|
||||
cout << "vector all_of is_six: " << ranges::all_of(v, is_six) << '\n';
|
||||
cout << "vector none_of is_six: " << ranges::none_of(v, is_six) << '\n';
|
||||
}
|
||||
//[any_all_none_of]]
|
||||
@@ -1,21 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
||||
|
||||
project(CPMTest)
|
||||
|
||||
# add dependencies
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME LarsParser
|
||||
GIT_REPOSITORY https://github.com/TheLartians/Parser.git
|
||||
VERSION 1.7
|
||||
)
|
||||
|
||||
# add executable
|
||||
add_executable(cpm-test-simple main.cpp)
|
||||
set_target_properties(cpm-test-simple PROPERTIES CXX_STANDARD 17)
|
||||
target_link_libraries(cpm-test-simple LarsParser)
|
||||
|
||||
# tests
|
||||
enable_testing()
|
||||
add_test(cpm-test-simple cpm-test-simple)
|
||||
@@ -1,27 +0,0 @@
|
||||
#include <lars/parser/generator.h>
|
||||
|
||||
int main() {
|
||||
lars::ParserGenerator<float> g;
|
||||
|
||||
// Define grammar and evaluation rules
|
||||
g.setSeparator(g["Whitespace"] << "[\t ]");
|
||||
g["Sum" ] << "Add | Subtract | Product";
|
||||
g["Product" ] << "Multiply | Divide | Atomic";
|
||||
g["Atomic" ] << "Number | '(' Sum ')'";
|
||||
g["Add" ] << "Sum '+' Product" >> [](auto e){ return e[0].evaluate() + e[1].evaluate(); };
|
||||
g["Subtract"] << "Sum '-' Product" >> [](auto e){ return e[0].evaluate() - e[1].evaluate(); };
|
||||
g["Multiply"] << "Product '*' Atomic" >> [](auto e){ return e[0].evaluate() * e[1].evaluate(); };
|
||||
g["Divide" ] << "Product '/' Atomic" >> [](auto e){ return e[0].evaluate() / e[1].evaluate(); };
|
||||
g["Number" ] << "'-'? [0-9]+ ('.' [0-9]+)?" >> [](auto e){ return stof(e.string()); };
|
||||
g.setStart(g["Sum"]);
|
||||
|
||||
// Execute a string
|
||||
float result = g.run("1 + 2 * (3+4)/2 - 3");
|
||||
|
||||
// validate result
|
||||
if (result == 5) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
25
examples/simple_match/CMakeLists.txt
Normal file
25
examples/simple_match/CMakeLists.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMSimpleMatchExample)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME simple_match
|
||||
GIT_REPOSITORY https://github.com/jbandela/simple_match.git
|
||||
GIT_TAG a3ab17f3d98db302de68ad85ed399a42ae41889e
|
||||
DOWNLOAD_ONLY True
|
||||
)
|
||||
|
||||
if(simple_match_ADDED)
|
||||
add_library(simple_match INTERFACE IMPORTED)
|
||||
target_include_directories(simple_match SYSTEM INTERFACE "${simple_match_SOURCE_DIR}/include")
|
||||
endif()
|
||||
|
||||
# ---- Executable ----
|
||||
|
||||
add_executable(CPMSimpleMatchExample main.cpp)
|
||||
target_compile_features(CPMSimpleMatchExample PRIVATE cxx_std_17)
|
||||
target_link_libraries(CPMSimpleMatchExample simple_match)
|
||||
34
examples/simple_match/main.cpp
Normal file
34
examples/simple_match/main.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <iostream>
|
||||
#include <simple_match/simple_match.hpp>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
using namespace simple_match;
|
||||
using namespace simple_match::placeholders;
|
||||
|
||||
std::string input;
|
||||
std::cout << "please enter a number or 'quit' to exit" << std::endl;
|
||||
|
||||
while (true) {
|
||||
std::cout << "> ";
|
||||
std::getline(std::cin, input);
|
||||
if (input == "quit") {
|
||||
break;
|
||||
}
|
||||
int x;
|
||||
try {
|
||||
x = std::stoi(input);
|
||||
} catch (std::invalid_argument&) {
|
||||
std::cout << "invalid input" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
match(
|
||||
x, 1, []() { std::cout << "The answer is one\n"; }, 2,
|
||||
[]() { std::cout << "The answer is two\n"; }, _x < 10,
|
||||
[](auto&& a) { std::cout << "The answer " << a << " is less than 10\n"; }, 10 < _x < 20,
|
||||
[](auto&& a) { std::cout << "The answer " << a << " is between 10 and 20 exclusive\n"; }, _,
|
||||
[]() { std::cout << "Did not match\n"; });
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
43
examples/sol2/CMakeLists.txt
Normal file
43
examples/sol2/CMakeLists.txt
Normal file
@@ -0,0 +1,43 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMSol2Example)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME lua
|
||||
GIT_REPOSITORY https://github.com/lua/lua.git
|
||||
VERSION 5.3.5
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
|
||||
if(lua_ADDED)
|
||||
# lua has no CMakeLists, so we create our own target
|
||||
|
||||
file(GLOB lua_sources ${lua_SOURCE_DIR}/*.c)
|
||||
list(REMOVE_ITEM lua_sources "${lua_SOURCE_DIR}/lua.c" "${lua_SOURCE_DIR}/luac.c")
|
||||
add_library(lua STATIC ${lua_sources})
|
||||
|
||||
target_include_directories(lua SYSTEM PUBLIC $<BUILD_INTERFACE:${lua_SOURCE_DIR}>)
|
||||
endif()
|
||||
|
||||
CPMAddPackage(
|
||||
NAME sol2
|
||||
URL https://github.com/ThePhD/sol2/archive/v3.0.2.zip
|
||||
VERSION 3.0.2
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
|
||||
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 ----
|
||||
|
||||
add_executable(CPMSol2Example main.cpp)
|
||||
target_compile_features(CPMSol2Example PRIVATE cxx_std_17)
|
||||
target_link_libraries(CPMSol2Example sol2)
|
||||
17
examples/sol2/main.cpp
Normal file
17
examples/sol2/main.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <cassert>
|
||||
#include <sol/sol.hpp>
|
||||
|
||||
struct vars {
|
||||
int boop = 0;
|
||||
};
|
||||
|
||||
int main() {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_usertype<vars>("vars", "boop", &vars::boop);
|
||||
lua.script(
|
||||
"beep = vars.new()\n"
|
||||
"beep.boop = 1\n"
|
||||
"print('beep boop')");
|
||||
assert(lua.get<vars>("beep").boop == 1);
|
||||
}
|
||||
15
examples/spdlog/CMakeLists.txt
Normal file
15
examples/spdlog/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMSpdlogExample)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage("gh:gabime/spdlog@1.8.2")
|
||||
|
||||
# ---- Executable ----
|
||||
|
||||
add_executable(CPMSpdlogExample main.cpp)
|
||||
target_compile_features(CPMSpdlogExample PRIVATE cxx_std_17)
|
||||
target_link_libraries(CPMSpdlogExample spdlog)
|
||||
6
examples/spdlog/main.cpp
Normal file
6
examples/spdlog/main.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
int main() {
|
||||
spdlog::info("Hello, world!");
|
||||
return 0;
|
||||
}
|
||||
15
examples/yaml/CMakeLists.txt
Normal file
15
examples/yaml/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMYamlExample)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage("gh:jbeder/yaml-cpp#yaml-cpp-0.6.3@0.6.3")
|
||||
|
||||
# ---- Executable ----
|
||||
|
||||
add_executable(CPMYamlExample main.cpp)
|
||||
target_compile_features(CPMYamlExample PRIVATE cxx_std_17)
|
||||
target_link_libraries(CPMYamlExample yaml-cpp)
|
||||
15
examples/yaml/main.cpp
Normal file
15
examples/yaml/main.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 2) {
|
||||
std::cout << "usage: " << argv[0] << " <path to yaml file>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
YAML::Node config = YAML::LoadFile(argv[1]);
|
||||
std::cout << "Parsed YAML:\n" << config << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
21
examples/yaml/monsters.yaml
Normal file
21
examples/yaml/monsters.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
- name: Ogre
|
||||
position: [0, 5, 0]
|
||||
powers:
|
||||
- name: Club
|
||||
damage: 10
|
||||
- name: Fist
|
||||
damage: 8
|
||||
- name: Dragon
|
||||
position: [1, 0, 10]
|
||||
powers:
|
||||
- name: Fire Breath
|
||||
damage: 25
|
||||
- name: Claws
|
||||
damage: 15
|
||||
- name: Wizard
|
||||
position: [5, -3, 0]
|
||||
powers:
|
||||
- name: Acid Rain
|
||||
damage: 50
|
||||
- name: Staff
|
||||
damage: 3
|
||||
BIN
logo/CPM.afdesign
Normal file
BIN
logo/CPM.afdesign
Normal file
Binary file not shown.
BIN
logo/CPM.png
Normal file
BIN
logo/CPM.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
16
test/CMakeLists.txt
Normal file
16
test/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMTests)
|
||||
|
||||
file(GLOB tests "${CMAKE_CURRENT_SOURCE_DIR}/unit/*.cmake")
|
||||
|
||||
enable_testing()
|
||||
|
||||
foreach(test ${tests})
|
||||
message(STATUS "adding test: ${test}")
|
||||
add_test(NAME ${test} COMMAND ${CMAKE_COMMAND} -DCPM_PATH=${CMAKE_CURRENT_SOURCE_DIR}/../cmake -P
|
||||
"${test}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
add_custom_target(test-verbose COMMAND ${CMAKE_CTEST_COMMAND} -C Debug --verbose)
|
||||
2
test/integration/.gitignore
vendored
Normal file
2
test/integration/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Use this to have a local integration test which is for personal experiments
|
||||
test_local.rb
|
||||
44
test/integration/README.md
Normal file
44
test/integration/README.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# CPM.cmake 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.
|
||||
|
||||
## Running tests
|
||||
|
||||
To run all tests from the repo root execute:
|
||||
|
||||
```
|
||||
$ ruby test/integration/runner.rb
|
||||
```
|
||||
|
||||
The runner will run all tests and generate a report of the exeuction.
|
||||
|
||||
The current working directory doesn't matter. If you are in `<repo-root>/test/integration`, you can run simply `$ ruby runner.rb`.
|
||||
|
||||
You can execute with `--help` (`$ ruby runner.rb --help`) to see various configuration options of the runner like running individual tests or test cases, or ones that match a regex.
|
||||
|
||||
The tests themselves are situated in the Ruby scripts prefixed with `test_`. `<repo-root>/test/integration/test_*`. You can also run an individual test script. For example to only run the **basics** test case, you can execute `$ ruby test_basics.rb`
|
||||
|
||||
The tests generate CMake scripts and execute CMake and build toolchains. By default they do this in a directory they generate in your temp path (`/tmp/cpm-test/` on Linux). You can configure the working directory of the tests with an environment variable `CPM_INTEGRATION_TEST_DIR`. For example `$ CPM_INTEGRATION_TEST_DIR=~/mycpmtest; ruby runner.rb`
|
||||
|
||||
## Writing tests
|
||||
|
||||
Writing tests makes use of the custom integration test framework in `lib.rb`. It is a relatively small extension of Ruby's Test::Unit library.
|
||||
|
||||
### The Gist
|
||||
|
||||
* Tests cases are Ruby scripts in this directory. The file names must be prefixed with `test_`
|
||||
* The script should `require_relative './lib'` to allow for individual execution (or else if will only be executable from the runner)
|
||||
* A test case file should contain a single class which inherits from `IntegrationTest`. It *can* contain multiple classes, but that's bad practice as it makes individual execution harder and implies a dependency between the classes.
|
||||
* 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.
|
||||
* 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 varous points of the test's execution.
|
||||
|
||||
### More
|
||||
|
||||
* [A basic tutorial on writing integration tests.](tutorial.md)
|
||||
* [A brief reference of the integration test framework](reference.md)
|
||||
* Make sure you're familiar with the [idiosyncrasies](idiosyncrasies.md) of writing integration tests
|
||||
* [Some tips and tricks](tips.md)
|
||||
98
test/integration/idiosyncrasies.md
Normal file
98
test/integration/idiosyncrasies.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Notable Idiosyncrasies When Writing Integration Tests
|
||||
|
||||
As an integration test framework based on a unit test framework the one created for CPM.cmake suffers from several idiosyncrasies. Make sure you familiarize yourself with them before writing integration tests.
|
||||
|
||||
## No shared instance variables between methods
|
||||
|
||||
The runner will create an instance of the test class for each test method. This means that instance variables defined in a test method, *will not* be visible in another. For example:
|
||||
|
||||
```ruby
|
||||
class MyTest < IntegrationTest
|
||||
def test_something
|
||||
@x = 123
|
||||
assert_equal 123, @x # Pass. @x is 123
|
||||
end
|
||||
def test_something_else
|
||||
assert_equal 123, @x # Fail! @x would be nil here
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
There are hacks around sharing Ruby state between methods, but we choose not to use them. If you want to initialize something for all test methods, use `setup`.
|
||||
|
||||
```ruby
|
||||
class MyTest < IntegrationTest
|
||||
def setup
|
||||
@x = 123
|
||||
end
|
||||
def test_something
|
||||
assert_equal 123, @x # Pass. @x is 123 thanks to setup
|
||||
end
|
||||
def test_something_else
|
||||
assert_equal 123, @x # Pass. @x is 123 thanks to setup
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## `IntegrationTest` makes use of `Test::Unit::TestCase#cleanup`
|
||||
|
||||
After each test method the `cleanup` method is called thanks to Test::Unit. If you require the use of `cleanup` in your own tests, make sure you call `super` to also run `IntegrationTest#cleanup`.
|
||||
|
||||
```ruby
|
||||
class MyTest < IntegrationTest
|
||||
def cleanup
|
||||
super
|
||||
my_cleanup
|
||||
end
|
||||
# ...
|
||||
end
|
||||
```
|
||||
|
||||
## It's better to have assertions in test methods as opposed to helper methods
|
||||
|
||||
Test::Unit will display a helpful message if an assertion has failed. It will also include the line of code in the test method which caused the failure. However if an assertion is not in the test method, it will display the line which calls the method in which it is. So, please try, to have most assertions in test methods (though we acknowledge that in certain cases this is not practical). For example, if you only require scopes, try using lambdas.
|
||||
|
||||
Instead of this:
|
||||
|
||||
```ruby
|
||||
class MyTest < IntegrationTest
|
||||
def test_something
|
||||
do_a
|
||||
do_b
|
||||
do_c
|
||||
end
|
||||
def do_a
|
||||
# ...
|
||||
end
|
||||
def do_b
|
||||
# ...
|
||||
assert false # will display failed line as "do_b"
|
||||
end
|
||||
def do_c
|
||||
# ...
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
...write this:
|
||||
|
||||
```ruby
|
||||
class MyTest < IntegrationTest
|
||||
def test_something
|
||||
do_a = -> {
|
||||
# ...
|
||||
}
|
||||
do_b = -> {
|
||||
# ...
|
||||
assert false # will display failed line as "assert false"
|
||||
}
|
||||
do_c = -> {
|
||||
# ...
|
||||
}
|
||||
|
||||
do_a.()
|
||||
do_b.()
|
||||
do_c.()
|
||||
end
|
||||
end
|
||||
```
|
||||
200
test/integration/lib.rb
Normal file
200
test/integration/lib.rb
Normal file
@@ -0,0 +1,200 @@
|
||||
require 'fileutils'
|
||||
require 'open3'
|
||||
require 'tmpdir'
|
||||
require 'test/unit'
|
||||
|
||||
module TestLib
|
||||
TMP_DIR = File.expand_path(ENV['CPM_INTEGRATION_TEST_DIR'] || File.join(Dir.tmpdir, 'cpm-test', Time.now.strftime('%Y_%m_%d-%H_%M_%S')))
|
||||
CPM_PATH = File.expand_path('../../cmake/CPM.cmake', __dir__)
|
||||
|
||||
TEMPLATES_DIR = File.expand_path('templates', __dir__)
|
||||
|
||||
# Environment variables which are read by cpm
|
||||
CPM_ENV = %w(
|
||||
CPM_USE_LOCAL_PACKAGES
|
||||
CPM_LOCAL_PACKAGES_ONLY
|
||||
CPM_DOWNLOAD_ALL
|
||||
CPM_DONT_UPDATE_MODULE_PATH
|
||||
CPM_DONT_CREATE_PACKAGE_LOCK
|
||||
CPM_INCLUDE_ALL_IN_PACKAGE_LOCK
|
||||
CPM_USE_NAMED_CACHE_DIRECTORIES
|
||||
CPM_SOURCE_CACHE
|
||||
)
|
||||
def self.clear_env
|
||||
CPM_ENV.each { ENV[_1] = nil }
|
||||
end
|
||||
end
|
||||
|
||||
puts "Warning: test directory '#{TestLib::TMP_DIR}' already exists" if File.exist?(TestLib::TMP_DIR)
|
||||
raise "Cannot find 'CPM.cmake' at '#{TestLib::CPM_PATH}'" if !File.file?(TestLib::CPM_PATH)
|
||||
|
||||
puts "Running CPM.cmake integration tests"
|
||||
puts "Temp directory: '#{TestLib::TMP_DIR}'"
|
||||
|
||||
# Clean all CPM-related env vars
|
||||
TestLib.clear_env
|
||||
|
||||
class Project
|
||||
def initialize(src_dir, bin_dir)
|
||||
@src_dir = src_dir
|
||||
@bin_dir = bin_dir
|
||||
end
|
||||
|
||||
attr :src_dir, :bin_dir
|
||||
|
||||
def create_file(target_path, text, args = {})
|
||||
target_path = File.join(@src_dir, target_path)
|
||||
|
||||
# tweak args
|
||||
args[:cpm_path] = TestLib::CPM_PATH if !args[:cpm_path]
|
||||
args[:packages] = [args[:package]] if args[:package] # if args contain package, create the array
|
||||
args[:packages] = args[:packages].join("\n") if args[:packages] # join all packages if any
|
||||
|
||||
File.write target_path, text % args
|
||||
end
|
||||
|
||||
def create_file_from_template(target_path, source_path, args = {})
|
||||
source_path = File.join(@src_dir, source_path)
|
||||
raise "#{source_path} doesn't exist" if !File.file?(source_path)
|
||||
src_text = File.read source_path
|
||||
create_file target_path, src_text, args
|
||||
end
|
||||
|
||||
# common function to create ./CMakeLists.txt from ./lists.in.cmake
|
||||
def create_lists_from_default_template(args = {})
|
||||
create_file_from_template 'CMakeLists.txt', 'lists.in.cmake', args
|
||||
end
|
||||
|
||||
CommandResult = Struct.new :out, :err, :status
|
||||
def configure(extra_args = '')
|
||||
CommandResult.new *Open3.capture3("cmake -S #{@src_dir} -B #{@bin_dir} #{extra_args}")
|
||||
end
|
||||
def build(extra_args = '')
|
||||
CommandResult.new *Open3.capture3("cmake --build #{@bin_dir} #{extra_args}")
|
||||
end
|
||||
|
||||
class CMakeCache
|
||||
class Entry
|
||||
def initialize(val, type, advanced, desc)
|
||||
@val = val
|
||||
@type = type
|
||||
@advanced = advanced
|
||||
@desc = desc
|
||||
end
|
||||
attr :val, :type, :advanced, :desc
|
||||
alias_method :advanced?, :advanced
|
||||
def inspect
|
||||
"(#{val.inspect} #{type}" + (advanced? ? ' ADVANCED)' : ')')
|
||||
end
|
||||
end
|
||||
|
||||
Package = Struct.new(:ver, :src_dir, :bin_dir)
|
||||
|
||||
def self.from_dir(dir)
|
||||
entries = {}
|
||||
cur_desc = ''
|
||||
file = File.join(dir, 'CMakeCache.txt')
|
||||
return nil if !File.file?(file)
|
||||
File.readlines(file).each { |line|
|
||||
line.strip!
|
||||
next if line.empty?
|
||||
next if line.start_with? '#' # comment
|
||||
if line.start_with? '//'
|
||||
cur_desc += line[2..]
|
||||
else
|
||||
m = /(.+?)(-ADVANCED)?:([A-Z]+)=(.*)/.match(line)
|
||||
raise "Error parsing '#{line}' in #{file}" if !m
|
||||
entries[m[1]] = Entry.new(m[4], m[3], !!m[2], cur_desc)
|
||||
cur_desc = ''
|
||||
end
|
||||
}
|
||||
CMakeCache.new entries
|
||||
end
|
||||
|
||||
def initialize(entries)
|
||||
@entries = entries
|
||||
|
||||
package_list = self['CPM_PACKAGES']
|
||||
@packages = if package_list
|
||||
# collect package data
|
||||
@packages = package_list.split(';').map { |name|
|
||||
[name, Package.new(
|
||||
self["CPM_PACKAGE_#{name}_VERSION"],
|
||||
self["CPM_PACKAGE_#{name}_SOURCE_DIR"],
|
||||
self["CPM_PACKAGE_#{name}_BINARY_DIR"]
|
||||
)]
|
||||
}.to_h
|
||||
else
|
||||
{}
|
||||
end
|
||||
end
|
||||
|
||||
attr :entries, :packages
|
||||
|
||||
def [](key)
|
||||
e = @entries[key]
|
||||
return nil if !e
|
||||
e.val
|
||||
end
|
||||
end
|
||||
def read_cache
|
||||
CMakeCache.from_dir @bin_dir
|
||||
end
|
||||
end
|
||||
|
||||
class IntegrationTest < Test::Unit::TestCase
|
||||
self.test_order = :defined # run tests in order of defintion (as opposed to alphabetical)
|
||||
|
||||
def cleanup
|
||||
# Clear cpm-related env vars which may have been set by the test
|
||||
TestLib.clear_env
|
||||
end
|
||||
|
||||
# extra assertions
|
||||
|
||||
def assert_success(res)
|
||||
msg = build_message(nil, "command status was expected to be a success, but failed with code <?> and STDERR:\n\n#{res.err}", res.status.to_i)
|
||||
assert_block(msg) { res.status.success? }
|
||||
end
|
||||
|
||||
def assert_same_path(a, b)
|
||||
msg = build_message(nil, "<?> expected but was\n<?>", a, b)
|
||||
assert_block(msg) { File.identical? a, b }
|
||||
end
|
||||
|
||||
# utils
|
||||
class << self
|
||||
def startup
|
||||
@@test_dir = File.join(TestLib::TMP_DIR, self.name.
|
||||
# to-underscore conversion from Rails
|
||||
gsub(/::/, '/').
|
||||
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
||||
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
||||
tr("-", "_").
|
||||
downcase
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def cur_test_dir
|
||||
@@test_dir
|
||||
end
|
||||
|
||||
def make_project(template_dir = nil)
|
||||
test_name = local_name
|
||||
test_name = test_name[5..] if test_name.start_with?('test_')
|
||||
|
||||
base = File.join(cur_test_dir, test_name)
|
||||
src_dir = base + '-src'
|
||||
|
||||
FileUtils.mkdir_p src_dir
|
||||
|
||||
if template_dir
|
||||
template_dir = File.join(TestLib::TEMPLATES_DIR, template_dir)
|
||||
raise "#{template_dir} is not a directory" if !File.directory?(template_dir)
|
||||
FileUtils.copy_entry template_dir, src_dir
|
||||
end
|
||||
|
||||
Project.new src_dir, base + '-bin'
|
||||
end
|
||||
end
|
||||
65
test/integration/reference.md
Normal file
65
test/integration/reference.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Integration Test Framework Refernce
|
||||
|
||||
## `TestLib`
|
||||
|
||||
A module for the framework. Provides global data and functionality. For ease of use the utility classes are *not* in this module.
|
||||
|
||||
Provides:
|
||||
|
||||
* `TMP_DIR` - the temporary directory for the current test run
|
||||
* `CPM_PATH` - path to CPM.cmake. The thing that is being tested
|
||||
* `TEMPLATES_DIR` - path to integration test templates
|
||||
* `CPM_ENV` - an array of the names of all environment variables, which CPM.cmake may read
|
||||
* `.clear_env` - a function to clear all aforementioned environment variables
|
||||
|
||||
## `Project`
|
||||
|
||||
A helper class to manage a CMake project.
|
||||
|
||||
Provides:
|
||||
|
||||
* `#initialize(src_dir, bin_dir)` - create a project with a given source and binary directory
|
||||
* `#src_dir`, `#bin_dir` - get project directories
|
||||
* `#create_file(target_path, text, args = {})` - create a file in the project's source directory with a given test. The `args` hash is used to interpolate markup in the text string.
|
||||
* Will set `:cpm_path` in `args` to `TestLib::CPM_PATH` if not already present.
|
||||
* If `:package` is present it will be added to the array `:packages`
|
||||
* Will convert `:packages` form an array to a string
|
||||
* `#create_file_from_template(target_path, source_path, args = {})` - create a file in the project source directory, based on another file in the project source directory. The contents of the file at `source_path` will be read and used in `create_file`
|
||||
* `#create_lists_from_default_template(args = {})` - same as `create_file_from_template('CMakeLists.txt', 'lists.in.cmake', args)`
|
||||
* `::CommandResult` - a struct of:
|
||||
* `out` - the standard output from a command execution
|
||||
* `err` - the standard error output from the execution
|
||||
* `status` - the [`Process::Status`](https://ruby-doc.org/core-2.7.0/Process/Status.html) of the execution
|
||||
* `#configure(extra_args = '') => CommandResult` - configure the project with optional extra args to CMake
|
||||
* `#build(extra_args = '') => CommandResult` - build the project with optional extra args to CMake
|
||||
* `::CMakeCache` - a helper class with the contents of a CMakeCache.txt. Provides:
|
||||
* `::Entry` - a CMake cache entry of:
|
||||
* `val` - the value as string
|
||||
* `type` - the type as string
|
||||
* `advanced?` - whether the entry is an advanced option
|
||||
* `desc` - the description of the entry (can be an empty string)
|
||||
* `::Package` - the CMake cache for a CPM.cmake package. A struct of:
|
||||
* `ver` - the version as string
|
||||
* `src_dir`, `bin_dir` - the source and binary directories of the package
|
||||
* `.from_dir(dir)` - create an instance of `CMakeCache` from `<dir>/CMakeLists.txt`
|
||||
* `#initialize(entries)` - create a cache from a hash of entries by name. Will populate packages.
|
||||
* `#entries => {String => Entry}` - the entries of the cache
|
||||
* `#packages => {String => Package}` - CPM.cmake packages by name found in the cache
|
||||
* `#[](key) => String` - an entry value from an entry name. Created because the value is expected to be needed much more frequently than the entire entry data. To get a full entry use `cache.entries['name']`.
|
||||
* `read_cache => CMakeCache` - reads the CMake cache in the binary directory of the project and returns it as a `CMakeCache` instance
|
||||
|
||||
## `IntegrationTest`
|
||||
|
||||
The class which must be a parent of all integration test case classes. It itself extends `Test::Unit::TestCase` with:
|
||||
|
||||
### Assertions
|
||||
|
||||
* `assert_success(res)` - assert that an instance of `Project::CommandResult` is a success
|
||||
* `assert_same_path(a, b)` - assert that two strings represent the same path. For example on Windows `c:\foo` and `C:\Foo` do.
|
||||
|
||||
### Utils
|
||||
|
||||
* `cur_test_dir` - the directory of the current test case. A subdirectory of `TestLib::TMP_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 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.
|
||||
|
||||
4
test/integration/runner.rb
Normal file
4
test/integration/runner.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
require_relative './lib'
|
||||
|
||||
exit Test::Unit::AutoRunner::run(true, __dir__)
|
||||
|
||||
7
test/integration/templates/no-deps/lists.in.cmake
Normal file
7
test/integration/templates/no-deps/lists.in.cmake
Normal file
@@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(no-deps)
|
||||
|
||||
include("%{cpm_path}")
|
||||
|
||||
add_executable(no-deps main.c)
|
||||
6
test/integration/templates/no-deps/main.c
Normal file
6
test/integration/templates/no-deps/main.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
puts("Hello");
|
||||
return 0;
|
||||
}
|
||||
13
test/integration/templates/using-adder/lists.in.cmake
Normal file
13
test/integration/templates/using-adder/lists.in.cmake
Normal file
@@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(using-adder)
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
include("%{cpm_path}")
|
||||
|
||||
%{packages}
|
||||
|
||||
add_executable(using-adder using-adder.cpp)
|
||||
|
||||
target_link_libraries(using-adder adder)
|
||||
8
test/integration/templates/using-adder/using-adder.cpp
Normal file
8
test/integration/templates/using-adder/using-adder.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <adder/adder.hpp>
|
||||
#include <cstdio>
|
||||
|
||||
int main() {
|
||||
int sum = adder::add(5, 3);
|
||||
std::printf("%d\n", sum);
|
||||
return 0;
|
||||
}
|
||||
13
test/integration/templates/using-fibadder/lists.in.cmake
Normal file
13
test/integration/templates/using-fibadder/lists.in.cmake
Normal file
@@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(using-fibadder)
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
include("%{cpm_path}")
|
||||
|
||||
%{packages}
|
||||
|
||||
add_executable(using-fibadder using-fibadder.cpp)
|
||||
|
||||
target_link_libraries(using-fibadder fibadder)
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <cstdio>
|
||||
#include <fibadder/fibadder.hpp>
|
||||
|
||||
int main() {
|
||||
int sum = fibadder::fibadd(6, 7);
|
||||
std::printf("%d\n", sum);
|
||||
return 0;
|
||||
}
|
||||
56
test/integration/test_basics.rb
Normal file
56
test/integration/test_basics.rb
Normal file
@@ -0,0 +1,56 @@
|
||||
require_relative './lib'
|
||||
|
||||
# Tests of cpm caches and vars when no packages are used
|
||||
|
||||
class Basics < IntegrationTest
|
||||
# Test cpm caches with no cpm-related env vars
|
||||
def test_cpm_default
|
||||
prj = make_project 'no-deps'
|
||||
prj.create_lists_from_default_template
|
||||
assert_success prj.configure
|
||||
|
||||
@cache = prj.read_cache
|
||||
|
||||
assert_empty @cache.packages
|
||||
|
||||
assert_same_path TestLib::CPM_PATH, check_and_get('CPM_FILE')
|
||||
assert_same_path File.dirname(TestLib::CPM_PATH), check_and_get('CPM_DIRECTORY')
|
||||
|
||||
assert_equal 'OFF', check_and_get('CPM_DRY_RUN')
|
||||
assert_equal 'CPM:', check_and_get('CPM_INDENT')
|
||||
assert_equal '1.0.0-development-version', check_and_get('CPM_VERSION')
|
||||
|
||||
assert_equal 'OFF', check_and_get('CPM_SOURCE_CACHE', 'PATH')
|
||||
assert_equal 'OFF', check_and_get('CPM_DOWNLOAD_ALL', 'BOOL')
|
||||
assert_equal 'OFF', check_and_get('CPM_LOCAL_PACKAGES_ONLY', 'BOOL')
|
||||
assert_equal 'OFF', check_and_get('CPM_USE_LOCAL_PACKAGES', 'BOOL')
|
||||
assert_equal 'OFF', check_and_get('CPM_USE_NAMED_CACHE_DIRECTORIES', 'BOOL')
|
||||
|
||||
assert_equal 'OFF', check_and_get('CPM_DONT_CREATE_PACKAGE_LOCK', 'BOOL')
|
||||
assert_equal 'OFF', check_and_get('CPM_INCLUDE_ALL_IN_PACKAGE_LOCK', 'BOOL')
|
||||
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_same_path File.join(prj.bin_dir, 'CPM_modules'), check_and_get('CPM_MODULE_PATH')
|
||||
end
|
||||
|
||||
# Test when env CPM_SOURCE_CACHE is set
|
||||
def test_env_cpm_source_cache
|
||||
ENV['CPM_SOURCE_CACHE'] = cur_test_dir
|
||||
|
||||
prj = make_project 'no-deps'
|
||||
prj.create_lists_from_default_template
|
||||
assert_success prj.configure
|
||||
|
||||
@cache = prj.read_cache
|
||||
|
||||
assert_equal cur_test_dir, check_and_get('CPM_SOURCE_CACHE', 'PATH')
|
||||
end
|
||||
|
||||
def check_and_get(key, type = 'INTERNAL')
|
||||
e = @cache.entries[key]
|
||||
assert_not_nil e, key
|
||||
assert_equal type, e.type, key
|
||||
e.val
|
||||
end
|
||||
end
|
||||
43
test/integration/test_fetchcontent_compatibility.rb
Normal file
43
test/integration/test_fetchcontent_compatibility.rb
Normal file
@@ -0,0 +1,43 @@
|
||||
require_relative './lib'
|
||||
|
||||
# Tests FetchContent overriding with CPM
|
||||
|
||||
class FetchContentCompatibility < IntegrationTest
|
||||
def setup
|
||||
@cache_dir = File.join(cur_test_dir, 'cpmcache')
|
||||
ENV['CPM_SOURCE_CACHE'] = @cache_dir
|
||||
end
|
||||
|
||||
def test_add_dependency_cpm_and_fetchcontent
|
||||
prj = make_project 'using-adder'
|
||||
|
||||
prj.create_lists_from_default_template package: <<~PACK
|
||||
CPMAddPackage(
|
||||
NAME testpack-adder
|
||||
GITHUB_REPOSITORY cpm-cmake/testpack-adder
|
||||
VERSION 1.0.0
|
||||
OPTIONS "ADDER_BUILD_TESTS OFF"
|
||||
)
|
||||
|
||||
# should have no effect, as we added the dependency using CPM
|
||||
FetchContent_Declare(
|
||||
testpack-adder
|
||||
GIT_REPOSITORY https://github.com/cpm-cmake/testpack-adder
|
||||
GIT_TAG v1.0.0
|
||||
)
|
||||
FetchContent_MakeAvailable(testpack-adder)
|
||||
PACK
|
||||
|
||||
# configure with unpopulated cache
|
||||
assert_success prj.configure
|
||||
assert_success prj.build
|
||||
|
||||
# cache is populated
|
||||
assert_true File.exist?(File.join(@cache_dir, "testpack-adder"))
|
||||
|
||||
# configure with populated cache
|
||||
assert_success prj.configure
|
||||
assert_success prj.build
|
||||
end
|
||||
|
||||
end
|
||||
91
test/integration/test_simple.rb
Normal file
91
test/integration/test_simple.rb
Normal file
@@ -0,0 +1,91 @@
|
||||
require_relative './lib'
|
||||
|
||||
class Simple < IntegrationTest
|
||||
ADDER_PACKAGE_NAME = 'testpack-adder'
|
||||
|
||||
def test_update_single_package
|
||||
prj = make_project 'using-adder'
|
||||
adder_cache0 = nil
|
||||
adder_ver_file = nil
|
||||
|
||||
create_with_commit_sha = -> {
|
||||
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
|
||||
|
||||
adder_cache = cache.packages[ADDER_PACKAGE_NAME]
|
||||
assert_not_nil adder_cache
|
||||
assert_equal '0', adder_cache.ver
|
||||
assert File.directory? adder_cache.src_dir
|
||||
assert File.directory? adder_cache.bin_dir
|
||||
|
||||
adder_ver_file = File.join(adder_cache.src_dir, 'version')
|
||||
assert File.file? adder_ver_file
|
||||
assert_equal 'initial', File.read(adder_ver_file).strip
|
||||
|
||||
# calculated adder values
|
||||
assert_equal 'ON', cache['ADDER_BUILD_EXAMPLES']
|
||||
assert_equal 'ON', cache['ADDER_BUILD_TESTS']
|
||||
assert_equal adder_cache.src_dir, cache['adder_SOURCE_DIR']
|
||||
assert_equal adder_cache.bin_dir, cache['adder_BINARY_DIR']
|
||||
|
||||
# store for future comparisons
|
||||
adder_cache0 = adder_cache
|
||||
}
|
||||
update_to_version_1 = -> {
|
||||
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
|
||||
|
||||
adder_cache = cache.packages[ADDER_PACKAGE_NAME]
|
||||
assert_not_nil adder_cache
|
||||
assert_equal '1.0.0', adder_cache.ver
|
||||
|
||||
# dirs shouldn't have changed
|
||||
assert_equal adder_cache0.src_dir, adder_cache.src_dir
|
||||
assert_equal adder_cache0.bin_dir, adder_cache.bin_dir
|
||||
|
||||
assert_equal '1.0.0', File.read(adder_ver_file).strip
|
||||
}
|
||||
update_with_option_off_and_build = -> {
|
||||
prj.create_lists_from_default_template package: <<~PACK
|
||||
CPMAddPackage(
|
||||
NAME testpack-adder
|
||||
GITHUB_REPOSITORY cpm-cmake/testpack-adder
|
||||
VERSION 1.0.0
|
||||
OPTIONS "ADDER_BUILD_TESTS OFF"
|
||||
)
|
||||
PACK
|
||||
assert_success prj.configure
|
||||
assert_success prj.build
|
||||
|
||||
exe_dir = File.join(prj.bin_dir, 'bin')
|
||||
assert File.directory? exe_dir
|
||||
|
||||
exes = Dir[exe_dir + '/**/*'].filter {
|
||||
# on multi-configuration generators (like Visual Studio) the executables will be in bin/<Config>
|
||||
# also filter-out other articacts 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
|
||||
|
||||
# we should end up with two executables
|
||||
# * simple - the simple example from adder
|
||||
# * using-adder - for this project
|
||||
# ...and notably no test for adder, which must be disabled from the option override from above
|
||||
assert_equal ['simple', 'using-adder'], exes
|
||||
}
|
||||
|
||||
create_with_commit_sha.()
|
||||
update_to_version_1.()
|
||||
update_with_option_off_and_build.()
|
||||
end
|
||||
end
|
||||
80
test/integration/test_source_cache.rb
Normal file
80
test/integration/test_source_cache.rb
Normal file
@@ -0,0 +1,80 @@
|
||||
require_relative './lib'
|
||||
|
||||
# Tests with source cache
|
||||
|
||||
class SourceCache < IntegrationTest
|
||||
def setup
|
||||
@cache_dir = File.join(cur_test_dir, 'cpmcache')
|
||||
ENV['CPM_SOURCE_CACHE'] = @cache_dir
|
||||
end
|
||||
|
||||
def test_add_remove_dependency
|
||||
prj = make_project 'using-fibadder'
|
||||
|
||||
###################################
|
||||
# create
|
||||
prj.create_lists_from_default_template package: 'CPMAddPackage("gh:cpm-cmake/testpack-fibadder@1.0.0")'
|
||||
assert_success prj.configure
|
||||
|
||||
@cache = prj.read_cache
|
||||
|
||||
# fibadder - adder
|
||||
# \ fibonacci - Format
|
||||
assert_equal 4, @cache.packages.size
|
||||
|
||||
check_package_cache 'testpack-fibadder', '1.0.0', '6a17d24c95c44a169ff8ba173f52876a2ba3d137'
|
||||
check_package_cache 'testpack-adder', '1.0.0', '1a4c153849d8e0cf9a3a245e5f6ab6e4722d8995'
|
||||
check_package_cache 'testpack-fibonacci', '2.0', '332c789cb09b8c2f92342dfb874c82bec643daf6'
|
||||
check_package_cache 'Format.cmake', '1.0', 'c5897bd28c5032d45f7f669c8fb470790d2ae156'
|
||||
|
||||
###################################
|
||||
# add one package with a newer version
|
||||
prj.create_lists_from_default_template packages: [
|
||||
'CPMAddPackage("gh:cpm-cmake/testpack-adder@1.0.1")',
|
||||
'CPMAddPackage("gh:cpm-cmake/testpack-fibadder@1.0.0")',
|
||||
]
|
||||
assert_success prj.configure
|
||||
|
||||
@cache = prj.read_cache
|
||||
assert_equal 4, @cache.packages.size
|
||||
|
||||
check_package_cache 'testpack-fibadder', '1.0.0', '6a17d24c95c44a169ff8ba173f52876a2ba3d137'
|
||||
check_package_cache 'testpack-adder', '1.0.1', '84eb33c1b8db880083cefc2adf4dc3f04778cd44'
|
||||
check_package_cache 'testpack-fibonacci', '2.0', '332c789cb09b8c2f92342dfb874c82bec643daf6'
|
||||
check_package_cache 'Format.cmake', '1.0', 'c5897bd28c5032d45f7f669c8fb470790d2ae156'
|
||||
end
|
||||
|
||||
def test_second_project
|
||||
prj = make_project 'using-fibadder'
|
||||
prj.create_lists_from_default_template package: 'CPMAddPackage("gh:cpm-cmake/testpack-fibadder@1.1.0")'
|
||||
assert_success prj.configure
|
||||
|
||||
@cache = prj.read_cache
|
||||
|
||||
# fibadder - adder
|
||||
# \ fibonacci - Format
|
||||
assert_equal 4, @cache.packages.size
|
||||
|
||||
check_package_cache 'testpack-fibadder', '1.1.0', '603d79d88d7230cc749460a0f476df862aa70ead'
|
||||
check_package_cache 'testpack-adder', '1.0.1', '84eb33c1b8db880083cefc2adf4dc3f04778cd44'
|
||||
check_package_cache 'testpack-fibonacci', '2.0', '332c789cb09b8c2f92342dfb874c82bec643daf6'
|
||||
check_package_cache 'Format.cmake', '1.0', 'c5897bd28c5032d45f7f669c8fb470790d2ae156'
|
||||
end
|
||||
|
||||
def test_cache_dir_contents
|
||||
num_subdirs = -> (name) { Dir["#{File.join(@cache_dir, name.downcase)}/*/"].size }
|
||||
assert_equal 2, num_subdirs.('testpack-fibadder')
|
||||
assert_equal 2, num_subdirs.('testpack-adder')
|
||||
assert_equal 1, num_subdirs.('testpack-fibonacci')
|
||||
assert_equal 1, num_subdirs.('Format.cmake')
|
||||
end
|
||||
|
||||
def check_package_cache(name, ver, dir_sha1)
|
||||
package = @cache.packages[name]
|
||||
assert_not_nil package, name
|
||||
assert_equal ver, package.ver
|
||||
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_equal dir_sha1, File.basename(package.src_dir)
|
||||
end
|
||||
end
|
||||
35
test/integration/tips.md
Normal file
35
test/integration/tips.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Tips and Tricks
|
||||
|
||||
## Playing and experimenting
|
||||
|
||||
Create a file called `test_local.rb` in this directory to have an integration test which is for your personal experiments and just playing with the integration test framework. `test_local.rb` is gitignored.
|
||||
|
||||
## Speeding-up development
|
||||
|
||||
Running an integration test requires configuring directories with CMake which can be quite slow. To speed-up development of integration tests consider doing the following steps:
|
||||
|
||||
**Work with standalone tests**
|
||||
|
||||
Instead of starting the runner, run just your integration test (`$ ruby test_your_test.rb`). This won't burden the execution with the others.
|
||||
|
||||
**Export the environment variable `CPM_INTEGRATION_TEST_DIR` to some local directory**
|
||||
|
||||
By default the framework generates a new temporary directory for each test run. If you override the temp directory to a specific one, rerunning the tests will work with the binary directories from the previous run and will improve the performance considerably.
|
||||
|
||||
*NOTE HOWEVER* that in certain cases this may not be an option. Some tests might assert that certain artifacts in the temporary directory are missing but upon rerunning in an existing directory they will be there causing the test to fail.
|
||||
|
||||
*ALSO NOTE* that this may silently affect reruns based on CMake caches from previous runs. If your test fails in peculiar ways on reruns, try a clean run. Always do a clean run before declaring a test a success.
|
||||
|
||||
**Set `CPM_SOURCE_CACHE` even if the test doesn't require it**
|
||||
|
||||
This is not a option for tests which explicitly check that there is no source cache. However certain tests may be indiferent to this. For such cases in development, you can add a setup function in the lines of:
|
||||
|
||||
```ruby
|
||||
def setup
|
||||
ENV['CPM_SOURCE_CACHE'] = '/home/myself/.testcpmcache'
|
||||
end
|
||||
```
|
||||
|
||||
Then the packages from your test will be cached and not redownloaded every time which is a dramatic improvement in performance.
|
||||
|
||||
*NOTE HOWEVER* that this may introduce subtle bugs. Always test without this dev-only addition, before declaring a test a success.
|
||||
69
test/integration/tutorial.md
Normal file
69
test/integration/tutorial.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Integration Test Tutorial
|
||||
|
||||
Let's create an integration test which checks that CPM.cmake can make a specific package available.
|
||||
|
||||
First we do some boilerplate.
|
||||
|
||||
```ruby
|
||||
require_relative './lib'
|
||||
|
||||
class MyTest < IntegrationTest
|
||||
# test that CPM.cmake can make https://github.com/cpm-cmake/testpack-adder/ available as a package
|
||||
def test_make_adder_available
|
||||
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 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:
|
||||
|
||||
```ruby
|
||||
prj = make_project
|
||||
```
|
||||
|
||||
`make_project` is method of IntegrationTest which generates a source and a binary directory for it based on the name of our test class and test method. The project doesn't contain anything yet, so let's create some source files:
|
||||
|
||||
```ruby
|
||||
prj.create_file 'main.cpp', <<~SRC
|
||||
#include <iostream>
|
||||
#include <adder/adder.hpp>
|
||||
int main() {
|
||||
std::cout << adder::add(1, 2) << '\\n';
|
||||
return 0;
|
||||
}
|
||||
SRC
|
||||
prj.create_file 'CMakeLists.txt', <<~SRC
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
project(using-adder)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
include("%{cpm_path}")
|
||||
CPMAddPackage("gh:cpm-cmake/testpack-adder@1.0.0")
|
||||
add_executable(using-adder main.cpp)
|
||||
target_link_libraries(using-adder adder)
|
||||
SRC
|
||||
```
|
||||
|
||||
Note the line `include("%{cpm_path}")` when creating `CMakeLists.txt`. It contains a markup `%{cpm_path}`. `Project#create_file` will see such markups and substitute them with the appropriate values (in this case the path to CPM.cmake).
|
||||
|
||||
Now that we have the two files we need it's time we configure our project. We can use the opportunity to assert that the configure is successful as we expect it to be.
|
||||
|
||||
```ruby
|
||||
assert_success prj.configure
|
||||
```
|
||||
|
||||
Now we can read the generated `CMakeCache.txt` and assert that certain values we expect are inside. `Project` provides a method for that: `read_cache`. It will return an instance of `Project::CMakeCache` which contains the data from the cache and provides additional helper functionalities. One of them is `packages`, which is a hash of the CPM.cmake packages in the cache with their versions, binary, source directories. So let's get the cache and assert that there is only one CPM.cmake package inside ant it has the version we expect.
|
||||
|
||||
```ruby
|
||||
cache = prj.read_cache
|
||||
assert_equal 1, cache.packages.size
|
||||
assert_equal '1.0.0', cache.packages['testpack-adder'].ver
|
||||
```
|
||||
|
||||
Finally let's assert that the project can be built. This would mean that CPM.cmake has made the package available to our test project and that it has the appropriate include directories and link libraries to make an executable out of `main.cpp`.
|
||||
|
||||
```ruby
|
||||
assert_success prj.build
|
||||
```
|
||||
|
||||
You can see the entire code for this tutorial in [tutorial.rb](tutorial.rb) in this directory.
|
||||
37
test/integration/tutorial.rb
Normal file
37
test/integration/tutorial.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
# This file is intentionally not prefixed with test_
|
||||
# It is a tutorial for making integration tests and is not to be run from the runner
|
||||
require_relative './lib'
|
||||
|
||||
class Tutorial < IntegrationTest
|
||||
# test that CPM.cmake can make https://github.com/cpm-cmake/testpack-adder/ available as a package
|
||||
def test_make_adder_available
|
||||
prj = make_project
|
||||
|
||||
prj.create_file 'main.cpp', <<~SRC
|
||||
#include <iostream>
|
||||
#include <adder/adder.hpp>
|
||||
int main() {
|
||||
std::cout << adder::add(1, 2) << '\\n';
|
||||
return 0;
|
||||
}
|
||||
SRC
|
||||
|
||||
prj.create_file 'CMakeLists.txt', <<~SRC
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
project(using-adder)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
include("%{cpm_path}")
|
||||
CPMAddPackage("gh:cpm-cmake/testpack-adder@1.0.0")
|
||||
add_executable(using-adder main.cpp)
|
||||
target_link_libraries(using-adder adder)
|
||||
SRC
|
||||
|
||||
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
|
||||
end
|
||||
end
|
||||
14
test/style/CMakeLists.txt
Normal file
14
test/style/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMStyleCheck)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME Format.cmake
|
||||
VERSION 1.7.3
|
||||
GITHUB_REPOSITORY TheLartians/Format.cmake
|
||||
# We exclude cmake files from integration tests as they contain invalid lines of code which are
|
||||
# used by the integration test scripts
|
||||
OPTIONS "CMAKE_FORMAT_EXCLUDE integration/templates"
|
||||
)
|
||||
2
test/unit/broken_dependency/.gitignore
vendored
Normal file
2
test/unit/broken_dependency/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/CMakeLists.txt
|
||||
/package-lock.cmake
|
||||
13
test/unit/broken_dependency/CMakeLists.txt.in
Normal file
13
test/unit/broken_dependency/CMakeLists.txt.in
Normal file
@@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMTest)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(@CPM_PATH@/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME BrokenDependency
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/dependency
|
||||
EXCLUDE_FROM_ALL @EXCLUDE_FROM_ALL@
|
||||
)
|
||||
3
test/unit/broken_dependency/dependency/CMakeLists.txt
Normal file
3
test/unit/broken_dependency/dependency/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
project(BrokenDependency)
|
||||
|
||||
add_custom_target(error ALL ${CMAKE_COMMAND} -E false)
|
||||
137
test/unit/cache.cmake
Normal file
137
test/unit/cache.cmake
Normal file
@@ -0,0 +1,137 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
include(${CPM_PATH}/testing.cmake)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
set(CPM_SOURCE_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/CPM")
|
||||
set(TEST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/remote_dependency)
|
||||
|
||||
function(clear_cache)
|
||||
message(STATUS "clearing CPM cache")
|
||||
file(REMOVE_RECURSE ${CPM_SOURCE_CACHE_DIR})
|
||||
assert_not_exists("${CPM_SOURCE_CACHE_DIR}")
|
||||
endfunction()
|
||||
|
||||
function(update_cmake_lists)
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_LIST_DIR}/remote_dependency/CMakeLists.txt.in"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/remote_dependency/CMakeLists.txt"
|
||||
INSTALL_DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/junk
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(reset_test)
|
||||
clear_cache()
|
||||
file(REMOVE_RECURSE ${TEST_BUILD_DIR})
|
||||
update_cmake_lists()
|
||||
endfunction()
|
||||
|
||||
set(FIBONACCI_VERSION 1.0)
|
||||
|
||||
# Read CPM_SOURCE_CACHE from arguments
|
||||
|
||||
reset_test()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} "-S${CMAKE_CURRENT_LIST_DIR}/remote_dependency" "-B${TEST_BUILD_DIR}"
|
||||
"-DCPM_SOURCE_CACHE=${CPM_SOURCE_CACHE_DIR}" RESULT_VARIABLE ret
|
||||
)
|
||||
|
||||
assert_equal(${ret} "0")
|
||||
assert_exists("${CPM_SOURCE_CACHE_DIR}/fibonacci")
|
||||
|
||||
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
|
||||
|
||||
set(FIBONACCI_VERSION 2.0)
|
||||
update_cmake_lists()
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} ${TEST_BUILD_DIR} RESULT_VARIABLE ret)
|
||||
|
||||
assert_equal(${ret} "0")
|
||||
|
||||
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()
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} ${TEST_BUILD_DIR} RESULT_VARIABLE ret)
|
||||
|
||||
assert_equal(${ret} "0")
|
||||
assert_exists("${CPM_SOURCE_CACHE_DIR}/fibonacci")
|
||||
|
||||
# Read CPM_SOURCE_CACHE from environment
|
||||
|
||||
reset_test()
|
||||
|
||||
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")
|
||||
|
||||
# Reuse cached packages for other build
|
||||
|
||||
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}-2"
|
||||
RESULT_VARIABLE ret
|
||||
)
|
||||
|
||||
assert_equal(${ret} "0")
|
||||
|
||||
# Overwrite CPM_SOURCE_CACHE with argument
|
||||
|
||||
reset_test()
|
||||
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E env "CPM_SOURCE_CACHE=${CMAKE_CURRENT_BINARY_DIR}/junk" ${CMAKE_COMMAND}
|
||||
"-S${CMAKE_CURRENT_LIST_DIR}/remote_dependency" "-B${TEST_BUILD_DIR}"
|
||||
"-DCPM_SOURCE_CACHE=${CPM_SOURCE_CACHE_DIR}"
|
||||
RESULT_VARIABLE ret
|
||||
)
|
||||
|
||||
assert_equal(${ret} "0")
|
||||
assert_exists("${CPM_SOURCE_CACHE_DIR}/fibonacci")
|
||||
|
||||
# Use NO_CACHE option
|
||||
|
||||
set(FIBONACCI_PACKAGE_ARGS "NO_CACHE YES")
|
||||
set(FIBONACCI_VERSION 1.0)
|
||||
update_cmake_lists()
|
||||
reset_test()
|
||||
|
||||
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_not_exists("${CPM_SOURCE_CACHE_DIR}/fibonacci")
|
||||
|
||||
# Use commit hash after version
|
||||
|
||||
set(FIBONACCI_PACKAGE_ARGS "NO_CACHE YES 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_not_exists("${CPM_SOURCE_CACHE_DIR}/fibonacci")
|
||||
29
test/unit/dependency_properties.cmake
Normal file
29
test/unit/dependency_properties.cmake
Normal file
@@ -0,0 +1,29 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
include(${CPM_PATH}/CPM.cmake)
|
||||
include(${CPM_PATH}/testing.cmake)
|
||||
|
||||
set(CPM_DRY_RUN ON)
|
||||
|
||||
CPMAddPackage(NAME A GIT_TAG 1.2.3)
|
||||
|
||||
CPMAddPackage(NAME A VERSION 1.2.3)
|
||||
|
||||
CPMGetPackageVersion(A VERSION)
|
||||
assert_equal(${VERSION} "1.2.3")
|
||||
|
||||
CPMAddPackage(NAME B VERSION 2.4.1)
|
||||
|
||||
CPMAddPackage(NAME B GIT_TAG v2.3.1)
|
||||
|
||||
CPMGetPackageVersion(B VERSION)
|
||||
assert_equal(${VERSION} "2.4.1")
|
||||
|
||||
CPMAddPackage(
|
||||
NAME C
|
||||
GIT_TAG v3.1.2-a
|
||||
VERSION 3.1.2
|
||||
)
|
||||
|
||||
CPMGetPackageVersion(C VERSION)
|
||||
assert_equal(${VERSION} "3.1.2")
|
||||
49
test/unit/dirty-cache-check.cmake
Normal file
49
test/unit/dirty-cache-check.cmake
Normal file
@@ -0,0 +1,49 @@
|
||||
include(${CPM_PATH}/CPM.cmake)
|
||||
include(${CPM_PATH}/testing.cmake)
|
||||
|
||||
set(baseDir "${CMAKE_CURRENT_BINARY_DIR}/test_dirty_cache")
|
||||
|
||||
find_package(Git REQUIRED)
|
||||
|
||||
function(git_do dir)
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} -c user.name='User' -c user.email='user@email.org' ${ARGN}
|
||||
RESULT_VARIABLE result
|
||||
OUTPUT_VARIABLE status
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
WORKING_DIRECTORY "${dir}"
|
||||
)
|
||||
if(result)
|
||||
message(FATAL_ERROR "git ${ARGN} fail: ${result} ${status}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
file(MAKE_DIRECTORY "${baseDir}")
|
||||
|
||||
file(WRITE "${baseDir}/draft.txt" "this is a test")
|
||||
|
||||
git_do("${baseDir}" init -b main)
|
||||
git_do("${baseDir}" commit --allow-empty -m "empty repo")
|
||||
message(STATUS "empty repo with file")
|
||||
cpm_check_git_working_dir_is_clean(${baseDir} HEAD emptygit_test)
|
||||
assert_falsy(emptygit_test)
|
||||
|
||||
git_do("${baseDir}" add draft.txt)
|
||||
git_do("${baseDir}" commit -m "test change")
|
||||
git_do("${baseDir}" tag v0.0.0)
|
||||
message(STATUS "commit a change")
|
||||
cpm_check_git_working_dir_is_clean(${baseDir} v0.0.0 onecommit_test)
|
||||
assert_truthy(onecommit_test)
|
||||
|
||||
file(WRITE "${baseDir}/draft.txt" "a modification")
|
||||
message(STATUS "dirty repo")
|
||||
cpm_check_git_working_dir_is_clean(${baseDir} v0.0.0 nonemptygit_test)
|
||||
assert_falsy(nonemptygit_test)
|
||||
|
||||
git_do("${baseDir}" add draft.txt)
|
||||
git_do("${baseDir}" commit -m "another change")
|
||||
message(STATUS "repo clean")
|
||||
cpm_check_git_working_dir_is_clean(${baseDir} v0.0.0 twocommit_test)
|
||||
assert_falsy(twocommit_test)
|
||||
|
||||
file(REMOVE_RECURSE "${baseDir}")
|
||||
35
test/unit/exclude_from_all.cmake
Normal file
35
test/unit/exclude_from_all.cmake
Normal file
@@ -0,0 +1,35 @@
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(${CPM_PATH}/testing.cmake)
|
||||
|
||||
set(TEST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/exclude_from_all)
|
||||
|
||||
function(init_project EXCLUDE_FROM_ALL)
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_LIST_DIR}/broken_dependency/CMakeLists.txt.in"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/broken_dependency/CMakeLists.txt"
|
||||
INSTALL_DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/junk
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} "-S${CMAKE_CURRENT_LIST_DIR}/broken_dependency" "-B${TEST_BUILD_DIR}"
|
||||
RESULT_VARIABLE ret
|
||||
)
|
||||
|
||||
assert_equal(${ret} "0")
|
||||
endfunction()
|
||||
|
||||
function(build_project expected_success)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} "--build" "${TEST_BUILD_DIR}" RESULT_VARIABLE ret)
|
||||
|
||||
if(expected_success)
|
||||
assert_equal(${ret} 0)
|
||||
else()
|
||||
assert_not_equal(${ret} 0)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
init_project(FALSE)
|
||||
build_project(FALSE)
|
||||
|
||||
init_project(TRUE)
|
||||
build_project(TRUE)
|
||||
38
test/unit/fetchcontent_dependency.cmake
Normal file
38
test/unit/fetchcontent_dependency.cmake
Normal file
@@ -0,0 +1,38 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
include(${CPM_PATH}/testing.cmake)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
set(CPM_SOURCE_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/CPM")
|
||||
set(TEST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/fetchcontent_dependency)
|
||||
|
||||
function(clear_cache)
|
||||
message(STATUS "clearing CPM cache")
|
||||
file(REMOVE_RECURSE ${CPM_SOURCE_CACHE_DIR})
|
||||
assert_not_exists("${CPM_SOURCE_CACHE_DIR}")
|
||||
endfunction()
|
||||
|
||||
function(update_cmake_lists)
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_LIST_DIR}/fetchcontent_dependency/CMakeLists.txt.in"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/fetchcontent_dependency/CMakeLists.txt"
|
||||
INSTALL_DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/junk
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(reset_test)
|
||||
clear_cache()
|
||||
file(REMOVE_RECURSE ${TEST_BUILD_DIR})
|
||||
update_cmake_lists()
|
||||
endfunction()
|
||||
|
||||
# Read CPM_SOURCE_CACHE from arguments
|
||||
|
||||
reset_test()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} "-S${CMAKE_CURRENT_LIST_DIR}/fetchcontent_dependency"
|
||||
"-B${TEST_BUILD_DIR}" "-DCPM_SOURCE_CACHE=${CPM_SOURCE_CACHE_DIR}" RESULT_VARIABLE ret
|
||||
)
|
||||
|
||||
assert_equal(${ret} "0")
|
||||
2
test/unit/fetchcontent_dependency/.gitignore
vendored
Normal file
2
test/unit/fetchcontent_dependency/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/CMakeLists.txt
|
||||
/package-lock.cmake
|
||||
38
test/unit/fetchcontent_dependency/CMakeLists.txt.in
Normal file
38
test/unit/fetchcontent_dependency/CMakeLists.txt.in
Normal file
@@ -0,0 +1,38 @@
|
||||
# ~~~
|
||||
# ┌────────────────────────┐
|
||||
# │ FetchContentDependency │
|
||||
# └─────┬────────────┬─────┘
|
||||
# │1. │3.
|
||||
# │ │
|
||||
# ┌────────▼────┐ ┌───▼─────────┐
|
||||
# │ Dependency ├───► Fibonacci │
|
||||
# └─────────────┘2. └─────────────┘
|
||||
#
|
||||
# 1. Add Project with CPMAddPackage
|
||||
# 2. Dependency will add Fibonacci with FetchContent
|
||||
# 3. Our project add Fibonacci with CPMAddPackage
|
||||
# ~~~
|
||||
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMTest_FetchContentDependency)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(@CPM_PATH@/CPM.cmake)
|
||||
|
||||
# 1 & 2 Dependency will add Fibonacci using FetchContent (1 & 2)
|
||||
CPMAddPackage(NAME Dependency SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/dependency)
|
||||
|
||||
# 3 Add again Fibonacci that have already been populated with FetchContent_MakeAvailable
|
||||
#
|
||||
# * This test should highlight the fact that cpm_add_subdirectory is always called, even when
|
||||
# cpm_fetch_package isn't populating the dependency
|
||||
# * NO_CACHE YES highlight a bug introduced in 32b063eba5c754f833725ed4b9e5f352bc3ca959 where
|
||||
# cpm_fetch_package was checking undefined ${lower_case_name}_POPULATED variable
|
||||
CPMAddPackage(
|
||||
NAME Fibonacci
|
||||
GIT_REPOSITORY https://github.com/cpm-cmake/testpack-fibonacci.git
|
||||
VERSION 2.0
|
||||
NO_CACHE YES
|
||||
)
|
||||
15
test/unit/fetchcontent_dependency/dependency/CMakeLists.txt
Normal file
15
test/unit/fetchcontent_dependency/dependency/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMTest_Dependency)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
Fibonacci
|
||||
GIT_REPOSITORY https://github.com/cpm-cmake/testpack-fibonacci.git
|
||||
GIT_TAG v2.0
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(Fibonacci)
|
||||
22
test/unit/is_git_tag_commit_hash.cmake
Normal file
22
test/unit/is_git_tag_commit_hash.cmake
Normal file
@@ -0,0 +1,22 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
include(${CPM_PATH}/CPM.cmake)
|
||||
include(${CPM_PATH}/testing.cmake)
|
||||
|
||||
cpm_is_git_tag_commit_hash("v1.2.3" RESULT)
|
||||
assert_equal("0" ${RESULT})
|
||||
|
||||
cpm_is_git_tag_commit_hash("asio-1-12-1" RESULT)
|
||||
assert_equal("0" ${RESULT})
|
||||
|
||||
cpm_is_git_tag_commit_hash("513039e3cba83284cec71287fd829865b9f423bc" RESULT)
|
||||
assert_equal("1" ${RESULT})
|
||||
|
||||
cpm_is_git_tag_commit_hash("513039E3CBA83284CEC71287FD829865B9F423BC" RESULT)
|
||||
assert_equal("1" ${RESULT})
|
||||
|
||||
cpm_is_git_tag_commit_hash("513039E" RESULT)
|
||||
assert_equal("1" ${RESULT})
|
||||
|
||||
cpm_is_git_tag_commit_hash("513039E3CBA8" RESULT)
|
||||
assert_equal("1" ${RESULT})
|
||||
2
test/unit/local_dependency/.gitignore
vendored
Normal file
2
test/unit/local_dependency/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/CMakeLists.txt
|
||||
/package-lock.cmake
|
||||
34
test/unit/local_dependency/ModuleCMakeLists.txt.in
Normal file
34
test/unit/local_dependency/ModuleCMakeLists.txt.in
Normal file
@@ -0,0 +1,34 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMTest)
|
||||
|
||||
# ---- Options ----
|
||||
|
||||
option(ENABLE_TEST_COVERAGE "Enable test coverage" OFF)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(@CPM_PATH@/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME @TEST_DEPENDENCY_NAME@
|
||||
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 ----
|
||||
|
||||
dependency_function()
|
||||
|
||||
# ---- 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@_BINARY_DIR)
|
||||
35
test/unit/local_dependency/OptionsCMakeLists.txt.in
Normal file
35
test/unit/local_dependency/OptionsCMakeLists.txt.in
Normal file
@@ -0,0 +1,35 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMTest)
|
||||
|
||||
# ---- Options ----
|
||||
|
||||
option(ENABLE_TEST_COVERAGE "Enable test coverage" OFF)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(@CPM_PATH@/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME Dependency
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/dependency
|
||||
OPTIONS
|
||||
"DEFINE_ALTERNATIVE_FUNCTION YES"
|
||||
"LIST_ARGUMENT a\\\\;b\\\\;c"
|
||||
EXCLUDE_FROM_ALL YES
|
||||
)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
alternative_dependency_function()
|
||||
|
||||
# ---- Check parameters ----
|
||||
|
||||
include(@CPM_PATH@/testing.cmake)
|
||||
|
||||
message("DEFINE_ALTERNATIVE_FUNCTION: ${DEFINE_ALTERNATIVE_FUNCTION}")
|
||||
|
||||
# this option is overridden by CPM.cmake
|
||||
ASSERT_NOT_DEFINED(DEFINE_ALTERNATIVE_FUNCTION)
|
||||
# this option is leaked by the dependency
|
||||
ASSERT_EQUAL(${LEAKED_OPTION} "OFF")
|
||||
27
test/unit/local_dependency/OverrideCMakeLists.txt.in
Normal file
27
test/unit/local_dependency/OverrideCMakeLists.txt.in
Normal file
@@ -0,0 +1,27 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMTest)
|
||||
|
||||
# ---- Options ----
|
||||
|
||||
option(ENABLE_TEST_COVERAGE "Enable test coverage" OFF)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(@CPM_PATH@/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME Dependency
|
||||
)
|
||||
|
||||
# ---- Call dependency method to validate correct addition of directory ----
|
||||
|
||||
dependency_function()
|
||||
|
||||
# ---- Check parameters ----
|
||||
|
||||
include(@CPM_PATH@/testing.cmake)
|
||||
|
||||
ASSERT_TRUTHY(Dependency_ADDED)
|
||||
ASSERT_DEFINED(Dependency_SOURCE_DIR)
|
||||
ASSERT_DEFINED(Dependency_BINARY_DIR)
|
||||
20
test/unit/local_dependency/PackageLockCMakeLists.txt.in
Normal file
20
test/unit/local_dependency/PackageLockCMakeLists.txt.in
Normal file
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMTest)
|
||||
|
||||
# ---- Options ----
|
||||
|
||||
option(ENABLE_TEST_COVERAGE "Enable test coverage" OFF)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(@CPM_PATH@/CPM.cmake)
|
||||
CPMUsePackageLock(package-lock.cmake)
|
||||
|
||||
@PREPARE_CODE@
|
||||
|
||||
CPMGetPackage(Dependency)
|
||||
|
||||
# ---- Call dependency method to validate correct addition of directory ----
|
||||
|
||||
dependency_function()
|
||||
17
test/unit/local_dependency/SubdirCMakeLists.txt.in
Normal file
17
test/unit/local_dependency/SubdirCMakeLists.txt.in
Normal file
@@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
project(CPMTest)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(@CPM_PATH@/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME Dependency
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/dependency
|
||||
SOURCE_SUBDIR inner
|
||||
)
|
||||
|
||||
# ---- Call inner dependency method to validate correct addition of subdirectory ----
|
||||
|
||||
inner_dependency_function()
|
||||
20
test/unit/local_dependency/dependency/CMakeLists.txt
Normal file
20
test/unit/local_dependency/dependency/CMakeLists.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
|
||||
|
||||
option(DEFINE_ALTERNATIVE_FUNCTION "define the alternative function" OFF)
|
||||
option(LEAKED_OPTION "this option will be leaked to the outer scope" OFF)
|
||||
|
||||
if(NOT DEFINE_ALTERNATIVE_FUNCTION)
|
||||
function(dependency_function)
|
||||
message("called external method")
|
||||
endfunction()
|
||||
else()
|
||||
|
||||
# check if list was passed correctly
|
||||
if(NOT "${LIST_ARGUMENT}" STREQUAL "a;b;c")
|
||||
message(FATAL_ERROR "list argument not properly passed to dependency: '${LIST_ARGUMENT}'")
|
||||
endif()
|
||||
|
||||
function(alternative_dependency_function)
|
||||
message("called alternative external method")
|
||||
endfunction()
|
||||
endif()
|
||||
@@ -0,0 +1,3 @@
|
||||
function(inner_dependency_function)
|
||||
message("called inner method")
|
||||
endfunction()
|
||||
28
test/unit/modules.cmake
Normal file
28
test/unit/modules.cmake
Normal file
@@ -0,0 +1,28 @@
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(${CPM_PATH}/testing.cmake)
|
||||
|
||||
set(TEST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/modules)
|
||||
|
||||
function(init_project_with_dependency TEST_DEPENDENCY_NAME)
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_LIST_DIR}/local_dependency/ModuleCMakeLists.txt.in"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/local_dependency/CMakeLists.txt"
|
||||
INSTALL_DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/junk
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} "-S${CMAKE_CURRENT_LIST_DIR}/local_dependency" "-B${TEST_BUILD_DIR}"
|
||||
RESULT_VARIABLE ret
|
||||
)
|
||||
|
||||
assert_equal(${ret} "0")
|
||||
endfunction()
|
||||
|
||||
init_project_with_dependency(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)
|
||||
|
||||
init_project_with_dependency(B)
|
||||
assert_not_exists(${TEST_BUILD_DIR}/CPM_modules/FindA.cmake)
|
||||
assert_exists(${TEST_BUILD_DIR}/CPM_modules/FindB.cmake)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user