Compare commits

..

208 Commits

Author SHA1 Message Date
Alecto Irene Perez
d9364ce284
Implement #624: Use shorter hashes with CPM_SOURCE_CACHE (#631)
* Add ASSERT_CONTENTS_EQUAL test macro in testing.cmake

Checks if the contents of a file matches the given input

* Use shorter hashes with CPM_SOURCE_CACHE (#624)

Uses shorter hashes with CPM_SOURCE_CACHE. Falls back to a longer hash
if necessary (ie, if there's a collision with an existing hash).

See: https://github.com/cpm-cmake/CPM.cmake/issues/624

* Update integration tests to support shorter hashes

* trigger ci

* run cmake-format

* if already available, use the legacy cache hash

* create temporary file in current binary dir

* add test case for legacy hash

---------

Co-authored-by: Lars Melchior <lars.melchior@gmail.com>
Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2025-05-18 19:02:47 +02:00
Simon Gene Gottlieb
d7614381ab
feature: allow URI to use shorthand syntax with additional options (#617)
* feature: add URI to use shorthand syntax with additional options

This allows to combine the shorthand syntax with URI and additional arguments:
```
CPMAddPackage(URI "gh:nlohmann/json@3.9.1" OPTIONS "JSON_BUildTests OFF")
```

This is much shorter than the longer syntax way of writing:
```
CPMAddPackage(
  NAME nlohmann_json
  VERSION 3.9.1
  GITHUB_REPOSITORY nlohmann/json
  OPTIONS
    "JSON_BuildTests OFF"
)
```

* fix: use shorthand syntax in examples

* test: add test for shorthand syntax with options

* doc: extend README mentioning shorthand syntax with options

* feat: URI keyword also sets EXCLUDE_FROM AND SYSTEM

* doc: more explicit about the behavior of URI

* doc: adjust README accordingly to PR-Review

* test: fix inline documentation of test_simple

* move URI comment

* added new test for shorthand syntax

* reset simple test

* add that URI must be the first argument

---------

Co-authored-by: Lars Melchior <lars.melchior@gmail.com>
2025-05-03 19:12:08 +02:00
Avus-c
97023e8b97
fix: do not generate module files with DOWNLOAD_ONLY (#654)
Co-authored-by: Avus <48911667+Avus@users.noreply.github.com>
2025-03-12 19:10:52 +01:00
flagarde
0f231080d9
Fetch content (#593)
* Add git_archival mechanism

* fetch_content

* Delete .pre-commit-config.yaml

* Update CPM.cmake

* cmake-format
2025-03-04 17:06:21 +01:00
Patrick Stewart
33efd5f5d2
Fix version filename for find_package redirects (#630)
Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2025-03-02 22:08:20 +01:00
Lars Melchior
4b3a60fb32
Investigate sol2 CI build issue (#648)
* trigger CI to see if sol2 example is reliably failing

* attempt patch from github comment

* fix patch

* add info to comment on patch

* run fix-format

* simplify patchfile
2025-03-02 21:59:58 +01:00
Rokas Kupstys
cd28d445ae
Fix finding patch executable when cross-compiling on windows. (#627)
`WIN32` checks whether current build context is windows. This is not correct in case of cross-compiling, because we are interested in finding host's tools, not SDK's tools.
2024-12-29 18:15:04 +01:00
Daniel Lemire
2a9e203320
doc: warn users that PATCHES may not work properly when CPM_SOURCE_CACHE is unset. (#580) 2024-12-22 23:25:51 +01:00
Scott B
22381df399
Update boost to 1.86 (#592)
* Update to v1.85.0

* Boost example to 1.86
2024-12-22 22:39:17 +01:00
Avus-c
c3807eb774
circumvent bug in cmake <3.30.3 (#605)
Co-authored-by: Avus <48911667+Avus@users.noreply.github.com>
2024-12-22 13:08:38 +01:00
Patrick Stewart
9ddfe1b6a8
Add find_package overrides that also work in CONFIG mode (#498) (#604) 2024-12-20 16:38:22 +01:00
Scott B
0bc73f41ce
Additional search path for patch.exe (#581)
* Additional search path for patch.exe

* Style
2024-08-02 15:44:55 +02:00
Avus-c
8b67fe2344
replace deprecated calls to FetchContent_Populate (#570)
* replace deprecated calls to FetchContent_Populate

The single argument signature for FetchContent_Populate is deprecated with CMake 3.30.
It was used, in order to call add_subdirectory manually with the EXCLUDE_FROM_ALL and SYSTEM flags.
These have been added to FetchContent_Declare with 3.25 and 3.28.
Calling FetchContent_MakeAvailable will internally call add_subdirectory with EXCLUDE_FROM_ALL and SYSTEM.
There is therefore no need to call this manually.

* fix: OPTIONS passed to CPMAddPackage not set

where previously parsed in cpm_add_subdirectory which is not called
on the new code path.

* refactor: remove an unnecessary else branch

* ci: include cmake 3.30 in test matrix

* fix: forward SOURCE_SUBDIR to FetchContent_Declare

For CMake version <3.28 this is done by calling add_subdirectory manually.
For newer version FetchContent_Declare/MakeAvailable handles this for us.

* fix: only set options if download_only is false

this replicates the old behaviour

* fix: DOWNLOAD_ONLY test

* refactor: always use *_Populate to reduce code paths

* Revert "refactor: always use *_Populate to reduce code paths"

This reverts commit 0e8ca2a0e92d1c2035a64d3d1e365325b1279ef9.

---------

Co-authored-by: Avus <48911667+Avus@users.noreply.github.com>
2024-07-29 11:19:31 +02:00
Scott B
d416d9b22c
Adding PATCHES keyword. (#558)
* Adding PATCHES keyword.

* Formatting fix.

* Move cpm_add_patches() outside if/else scopes.

* cmake-format: add PATCHES to CPMAddPackage.

* Integration tests for PATCHES command.

* Use get_filename_component() in place of cmake_path() for use with all cmake versions 3.14 and above.

* Added an example and improved comment for cpm_add_patches.
2024-06-12 15:43:27 +02:00
PercentBoat4164
76ca48690b
Remove 'bug' from comment (#555)
* Remove 'bug' from comment

* Fix the styling

Oh gosh, I messed up the style...

* Line endings
2024-04-21 21:12:30 +02:00
Gerhard Olsson
0370507fed
Custom cache directory name (#543)
* Custom cache directory name

Enable setting a custom directory name for cached packages.
Required if e.g. patch_command uses external variables or
just to set a human readable name.

* fixup! review comment CUSTOM_CACHE_DIR -> CUSTOM_CACHE_KEY

* run cmake-format

---------

Co-authored-by: Olsson Gerhard <gerhard.olsson@volvo.com>
Co-authored-by: Lars Melchior <lars.melchior@gmail.com>
2024-04-08 18:24:10 +02:00
Project D.D
c0855c9543
Add xxHash example (#549)
* Add xxHash example

* Fix link error

* run code formatters

---------

Co-authored-by: Lars Melchior <lars.melchior@gmail.com>
2024-04-08 16:14:14 +00:00
black-desk
7e81149c1e
Use cpm_find_package to check if a package added (#552)
If I have a project, which has:

1. /CMakeLists.txt:

   ```cmake
   cmake_minimum_required(VERSION 3.29)
   project(test)
   include(./cmake/CPM.cmake)
   add_subdirectory(subdir)
   cpmfindpackage(
     NAME
     nlohmann_json
     VERSION
     3.11.2
     URL
     "https://github.com/nlohmann/json/releases/download/v3.11.2/json.tar.xz"
     EXCLUDE_FROM_ALL
     ON)

   if(NOT TARGET nlohmann_json::nlohmann_json)
     message(FATAL_ERROR "BUG")
   endif()
   ```
2. /subdir/CMakeLists.txt

   ```cmake
   cpmfindpackage(
     NAME
     nlohmann_json
     VERSION
     3.11.2
     URL
     "https://github.com/nlohmann/json/releases/download/v3.11.2/json.tar.xz"
     EXCLUDE_FROM_ALL
     ON)
   ```

When nlohmann_json is first founded by find_package,
CPM.cmake register this package and later call to CPMFindPackage will
not actually perform a find_package again, which leads to this buggy
behavior.

As CPM write a FindXXX.cmake file for packages added by CPM to pervert
find_package to get local package, I think directly use cpm_find_package
to check if a package is already added is good enough.
2024-04-07 23:40:46 +02:00
Simon Gene Gottlieb
0e450ef450
fix,doc: spelling errors (#551) 2024-04-07 21:36:07 +00:00
Scott B
a8144f511d
Update Boost example (#531)
* Update CMake and main to add another library and download FASTER.

* Apply style formatters

* Update README.md's boost example and add information on determining source archive location at GitHub.

* Update README.md

---------

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2024-02-02 18:25:34 +00:00
Claus Klein
3c25130ffa
Feature/add missing packageproject options (#524)
* Add missing packageproject options

* Fix typos with codespell

* Update test/style/CMakeLists.txt

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

* fix-cmake-format

---------

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2024-01-17 09:06:16 +01:00
Chris Wright
369f1316f6
Treat relative paths as relative to parent project's remote (#522)
* Treat relative paths as relative to parent project's remote

* replace unit test case with integration test

* run relative URL test only on supported CMake versions (3.27)

* omit cmake 2.25.x test runner as replaced by 2.27.x

---------

Co-authored-by: Chris Wright <chris.wright@mqa.co.uk>
Co-authored-by: Lars Melchior <lars.melchior@gmail.com>
2023-11-30 20:01:03 +01:00
Daniel Lemire
a9c8c6fe1b
Adding simdjson example (#516)
* Adding simdjson example

* Update README.md

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

* cmake format

---------

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2023-11-06 17:19:06 +00:00
Daniel Lemire
2fa48378e2
new users (#515) 2023-11-06 17:13:56 +00:00
Lars Melchior
4276c79d28
update catch2 to 3.4.0 (#517) 2023-11-06 18:04:37 +01:00
Alfi Maulana
ee6d879a50
Includes missing arguments in the cpm_prettify_package_arguments function (#511) 2023-10-08 17:48:42 +00:00
Lars Melchior
d6d5d0d5ab
Remove logs in get_cpm.cmake script (#508)
* remove all logs from get_cpm.cmake

* simplify get_cpm.cmake script
2023-09-18 16:11:03 +02:00
Lars Melchior
16c6a3b0af
Fix download_command by declaring it a multi-value option (#473) 2023-09-18 15:37:35 +02:00
Lars Melchior
52ee7c9d53
Fix new release script to use correct version and hash sum (#507)
* fix new release script to use correct version and hash sum

* update logging behaviour
2023-09-18 15:01:57 +02:00
Tobias Schmidl
699c7a0038
Added download status, added comparison by hash sum (#474) 2023-09-18 14:01:34 +02:00
Vincent Hamp
daf9d766c6
Add ZIMO-Elektronik to "Built with CPM.cmake" (#490) 2023-09-18 11:45:33 +02:00
Carlo Corradini
439bfcf134
chore(license): update license year (#504) 2023-09-17 19:35:11 +00:00
Alois Klink
02ecc4608a
Add SPDX tags to get_cpm.cmake to comply with MIT (#496)
Add [SPDX][1] licensing/copyright tags to the `get_cpm.cmake` script,
so that anybody that copies the `get_cpm.cmake` script into their repo
(following the instructions in the README.md)
will automatically comply with CPM's MIT license.

[1]: https://spdx.dev/
2023-08-19 12:53:28 +00:00
Johel Ernesto Guerrero Peña
4608688d85
docs: fix spelling of "through" (#489) 2023-08-19 13:29:57 +02:00
Johel Ernesto Guerrero Peña
cda03b434e
ci(cmake): split additional_commands to its own file (#486) 2023-08-19 12:57:47 +02:00
Andreas K
ee556fc555
fix(lock): fix typo: CPM_CACHE_SOURCE -> CPM_SOURCE_CACHE (#485) 2023-07-12 15:43:48 +02:00
Asger Gitz-Johansen
1b59cb6b16
Add AALTITOAD to "Built with CPM.cmake" (#463) 2023-04-13 09:58:49 +00:00
Claus Klein
a02a9601da
SOURCE_DIR option disable call to find_package() (#456) 2023-02-28 19:25:01 +01:00
Craig Hutchinson
af3f1ca814
Prevent check variable leaking into caller scope (#457) 2023-02-27 12:48:00 +01:00
Lars Melchior
b9b512a869
Add CMake version as workflow matrix parameter (#451)
* add CMake version as workflow matrix parameter

* change system test behaviour based on specified CMake version

* use explicit version strings

* set CMake version for both test steps

* exclude windows-2022, cmake 3.16 combination
2023-02-22 17:33:50 +01:00
Lars Melchior
e23bd4c0c3
Update Readme to match default SYSTEM behaviour (#452) 2023-02-21 20:00:20 +02:00
Lars Melchior
5f3005ab7c
Move section on adding CPM higher in the Readme (#454)
Repositions the "Adding CPM" section higher in the Readme to increase incentive to try it out and make it easier to find for updating CPM in existing projects.
2023-02-21 19:59:57 +02:00
Lars Melchior
12daf366c7
Add SYSTEM option (#449)
* add system property for cpm_add_subdirectory

* add test case for system property

* lock CMake version in test workflow

* refactor to make SYSTEM an extra config option and update tests

* remove old comment change

* use consistent CMake version and extension for all workflows

* make warning more specific and try to trigger on windows

* another attempt to trigger warning on MSVC

* update readme

* simplify test case and use git tag

* add SYSTEM option to .cmake-format

* forward system arg for source overrides

* enable system implicitly for the single argument syntax

* Use SYSTEM option for FetchContent and add_subdirectory (#441)

* Use SYSTEM option for FetchContent and add_subdirectory

* Add SYSTEM option to syntax and doku

* Update CPM.cmake

* Update .cmake-format

---------

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

---------

Co-authored-by: Claus Klein <claus.klein@arcormail.de>
2023-02-21 15:51:33 +01:00
PercentBoat4164
0938e8fde7
Improve Multi-threaded Performance. (#450)
* Optimized multi-threading.

* Remove old multi-threading implementation.

* Release files instead of removing.

* Lock before choosing to check cache or download.

* Unlock directly after verifying directory exists.
2023-02-21 15:47:15 +01:00
PercentBoat4164
09b056ae20
Add file locking to support parallel runs. (#427)
* Add file locking to support parallel runs.

* Fixed formatting.

* Prevent double locking file.

* Fix SegFault from test 2.

* Remove unnecessary debugging messages.

* Lock the package directory rather than the cache directory.
Only synchronize if CPM_SOURCE_CACHE is defined.

* Lock the version specific cache entry rather than the package specific entry.

* Remove unnecessary arguments in conditional statements.

* Change back to locking entire cache directory.

* Only check CPM_HAS_CACHE_LOCK.

* Lock on a per-package basis rather than the entire cache.

* Clean up the locked file.

* Unlock then remove to fix Windows.

* Specify use of cmake.lock as the lock file.

* - Changed CPM_HAS_CACHE_LOCK to ${CPM_ARGS_NAME}_CPM_HAS_CACHE_LOCK.
- Removed redundant variable initialization.

* Add unit test.

* Actually test if resulting git cache is clean in unit test.

* - Added comments
- Fixed formatting
- Removed unnecessary imports

* convert parallelism test to integration test

* remove comment

* - Removed now unnecessary variable.
 - Only delete file instead of unlocking it then deleting it.

* Forgot to change variable name.

* Add similar changes to the missed section.

* Fixed formatting.

* Unlock the file, but do not delete it.

* Only unlock the file if it exists.

* Changed cache.cmake test to ignore non-directory entries.

* Integration test lib make_project:
* keyword args
* 'name' arg to allow multiple projects from the same test

* - Moved checks to function.
- Fixed small grammatical errors.

* - Fix formatting

* Switch to snake case.

---------

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
Co-authored-by: Lars Melchior <lars.melchior@gmail.com>
Co-authored-by: Borislav Stanimirov <b.stanimirov@abv.bg>
2023-01-28 14:36:44 +01:00
Jan Niklas Hasse
d34d2a8730
Add JNGL to "Built with CPM.cmake" (#434)
Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2023-01-10 15:48:29 +00:00
Lars Melchior
6fc2170d5d
Update example dependency versions (#430)
* update example versions

* update doctest

* update lua

* update google benchmark

* update catch2

* update readme to match updated dependencies

Co-authored-by: Lars Melchior <lars@Larss-Laptop.local>
2023-01-10 15:31:57 +01:00
haenkel
1184a6e6e7
get_cpm: Recover from failed download (#426)
* get_cpm: Recover from failed download

If the download fails during the cmake config step
an empty `CPM_<version>.cmake` file is created.
So far the script only checks the files existence,
so there is no second try until the empty file is deleted manually.

This adds a check if the file is empty
and resumes the download on next config if it is.

* More descriptive function name
2022-11-29 17:30:22 +00:00
flagarde
c53417bd65
Small helper function for logging : (#422)
* Small helper function for logging :

This PR add an helper function only when `message(STATUS ...)` as the other are `backtracing` and adding the helper function add on stack.

It should fix #328 #342 with a few line of code.

* Formatting
2022-11-29 17:50:19 +01:00
Jan Niklas Hasse
50e9b9edb8
Instead of spdlog's bundled fmt re-use it from CPM.cmake (#364)
* Instead of spdlog's bundled fmt re-use it from CPM.cmake

* Add comment about re-using fmt for spdlog

* Update examples/spdlog/CMakeLists.txt

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

* run cmake-format

* disable cmake-format around code block

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2022-11-09 11:23:09 +00:00
Craig Hutchinson
03705fcce1
Added export of CPM_LAST_PACKAGE_NAME (#403) 2022-09-28 21:39:31 +02:00
Lars Melchior
f00ccd89c4
Update example in readme (#413)
* update readme example

* Update README.md
2022-09-28 22:31:15 +03:00
Lars Melchior
1f4909ca44
add CONTRIBUTING.md (#412) 2022-09-28 05:55:09 +03:00
Borislav Stanimirov
4d33686a50
Updated contributor list (#411) 2022-09-27 21:09:28 +02:00
AlessandroW
984251f46c
Fix copy/paste bug in fmt example CMakeLists.txt
#410
2022-09-27 21:01:21 +03:00
Robert Maynard
63d0de7114
Don't warn about dirty source trees when a PATCH_COMMAND is provided (#401)
The patch command will always cause a dirty source tree, which
is expected and not a cause for concern.
2022-09-13 23:21:12 +02:00
Kamil Kisiel
65c760a840
Expand absolute path later in get_cpm.cmake (#397)
* Expand absolute path later in get_cpm.cmake

Supports expanding tildes in the environment.

* Apply cmake-format to get_cpm.cmake

* Use .cmake-format file
2022-09-13 20:54:57 +00:00
Robert Maynard
b5e60e72e8
cpm_find_package Use found package version when possible (#396) 2022-09-13 22:44:24 +02:00
Robert Maynard
10bf25a811
Restore policy changes in CPMAddPackage (#388)
* Restore policy changes in CPMAddPackage

Fixes #387

* Correct style issues found by CI
2022-08-11 19:12:21 +00:00
Lars Melchior
18b6cbf233
perform policy changes only in top-level CPM.cmake script (#386) 2022-08-09 12:56:46 +02:00
Olivier Le Doeuff
698741ff7c
Fix a very confusing typo (#384) 2022-08-04 10:34:33 +03:00
Borislav Stanimirov
1f09de0d9b
Document policies being set to NEW when including CPM.cmake (#383) 2022-08-04 08:32:05 +02:00
Robert Maynard
b224ce280d
Timestamps for URL downloads match the download time (#372)
* Timestamps for URL downloads match the download time

By enabling CMake policy 135 we ensure that extracted files
timestamp match that of the download time, instead of when the
archive is created. This makes sure that if the URL changes to
an older version we still rebuild everything as the timestamp
stays newer.

* Introduce CPM_SET_RECOMMENDED_CMAKE_POLICIES

Enabling CPM_SET_RECOMMENDED_CMAKE_POLICIES will establish defaults
for all CMake policies so that both CPM and added projects
operate inline with CPM recommended best practices.

* Fix style issues found by ci

* Update README.md

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

* Update cmake/CPM.cmake

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

* Set policies when CPM.cmake is included

* CPM_SET_RECOMMENDED_CMAKE_POLICIES default is ON

* Correct failing CI tests

* CPM.cmake always sets policies to on

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2022-08-04 00:22:50 +02:00
Lars Melchior
49af958fb4
Use 3 column layout in showcase (#381) 2022-08-03 10:55:32 +03:00
Evgeny Gorodetskiy
90c763532a
Add Methane Kit project to showcase table in ReadMe (#380)
* Add MethaneKit project to the showcase table

* Shorten description, wrap to new line in table
2022-08-01 20:55:03 +02:00
Robert Maynard
4605d32f0e
CPM_DIRECTORY always stores absolute non symlink paths (#379)
* CPM_DIRECTORY always stores absolute non symlink paths

When CPM is brought into a project via downloading it will be placed
in the build directory. When the build directory is a symlink the
CPM_DIRECTORY value will hold the symlink value. This means that
trying to run CMake via the real build directory will cause CPM
to fail since it considers the current CMAKE_CURRENT_LIST_DIR
to be different and will early exit.

This resolves the issue be always getting CMake to resolve symlinks
before comparing paths for CPM_DIRECTORY.

* Refactor logic based on PR review
2022-07-31 21:51:27 +02:00
Thomas Mosegaard Pedersen
ede60451a9
CPMAddPackage fails if the SOURCE_DIR directory is deleted. (#370)
* Fixed: Deleted SOURCE_DIR directory would abort just after git stash save --quiet;--include-untracked

* Fixed: Review comments

* Added: Integration test for deleted SOURCE_DIR with FetchContent

* Fixed: Review comments

* Fixed: Review comments
2022-07-26 07:15:11 +00:00
David Fong
5961f9f9fb
bump example range-v3 to 0.12.0 (#366)
* bump range-v3 to 0.12.0

* bump range-v3 to 0.12.0
2022-07-02 12:56:11 +00:00
Anton Filimonov
69e9ff3766
Klogg switched to CPM for dependency management (#363)
Klogg used to vendor all external dependencies, and now we switched to CPM, and this makes using local dependencies and packaging much easier. Thanks for all you effort!
2022-06-27 23:39:13 +02:00
Olivier Le Doeuff
3fee69c894
Add readme "Customize repository URL" with git-config (#353) 2022-05-17 08:17:14 +02:00
Lars Melchior
a575ab57b7
Allow overriding FetchContent using CPM (#352)
* Override FetchContent paramers, fixes #281

* add check to verify that dependency is cached

* update test comment

* rename test file and class

* update test indentation
2022-05-16 21:28:44 +02:00
Lava Block
ca421f0e0c
Add liblava to "Built with CPM.cmake" (#346) 2022-04-10 18:59:05 +00:00
Robert Maynard
005f202655
Add per package CPM_DOWNLOAD controls (#336)
* Add per project CPM_DOWNLOAD controls

Introduces support for `CPM_<PACKAGE>_DOWNLOAD` variable ( and env )
which allows finer grained control.

* Address PR feedback on API names
2022-02-11 19:37:32 +01:00
Lars Bilke
865648e7bd
Fixed typos in comments 2022-02-09 11:25:26 +00:00
Borislav Stanimirov
33bdbae902
List of contributors (#340)
* Updated copyright years. Same copyright holders in code and LICENSE

* Contributor list. Order is from contributors gh page
2022-02-07 20:21:43 +01:00
Tobias Hellmann
9d3fad01d4
Fix broken example for nlohmann/json (#338) 2022-01-27 22:59:28 +00:00
Robert Maynard
11c7ec8afa
Use CMake 3.14+ documented way to pass the source dir -S. (#337)
The `-H<src_dir>` was never officially documented by CMake
2022-01-27 23:45:35 +01:00
Robert Maynard
4f7af69925
CMake 3.22 allows set/set(CACHE) to behave the same as set(X)/option(x) (#335)
By enabling CMP0126 we tell CMake that when constructing a CACHE variable
with the same name as a local variable to not unset the local variable.

By enabling CMPO126 it makes sure that CPM behavior around `OPTION` is
consistent if the option is created with `set(CACHE)` or with `option`.
2022-01-27 23:36:12 +01:00
Borislav Stanimirov
c58e98a0a0
Initial version of integration tests (#330)
* Initial commit for integration tests. Experimental. Playing with potential syntax

* Some experimental code to setup tests

* Piecewise building of CMakeLists

* First check

* Alternative approach. Using ruby's test/unit

* Parse CMakeCache. Separate lib

* First integration test

* Latest Format.cmake. Passing style

* Allow user-provided integration test dir. Allow reuse

* Separate class with utils for cache (no longer pure Hash)

* Allow running of tests from any dir

* Add integration tests to CI

* Use an in-source integration test directory

* Allow relative integration test dir from env

* Custom assertion for a success of CommandResult

* Windows-latest-latest

* Enrich CMakeCache class with more CPM data

* Added test for CPM-specific CMakeCache values

* Style

* Style

* test_update_single_package

* WiP for source cache test

* Small source_cache test

* Style

* Moved env clean to cleanup to make setup methods simpler (not require super)

* WiP for integration test documentation

* WiP for integration test documentation

* Project file creation tweaks

* Split docs into multiple files. Complete tutorial. Reference.

* Tips

* Typo

* Setup Ruby inistead of requiring windows-2022

* Revert "Setup Ruby inistead of requiring windows-2022"

This reverts commit 8aa2732145445099e64b5b13490867886bbfc910.
2022-01-19 00:18:41 +01:00
Lars Melchior
a27c66a3ea
Remove badges (#327)
As we now use the unified CI workflow (#326), it seems we unfortunately [can't have separate badges for each OS](https://github.community/t/separate-workflow-badges-when-using-matrix-testing-possible/16708). As the display of the badges was to reference the cross-platform nature of the project, imo it can be replaced by adding a reference in the introduction instead.
2022-01-13 03:44:07 +02:00
Vinpasso
5cb7398a24
[Example] Disable JSON tests being included in ctest (#329)
* Disable JSON tests being included in ctest

If `CPMAddPackage` includes json without setting JSON_BuildTests off first then the target's ctest will include lots of json's tests.

* Bump example JSON version to avoid JSON tests
2022-01-12 20:29:59 +01:00
Borislav Stanimirov
262f1e0602
Unified GitHub workflow for tests on major operating systems (#326) 2022-01-11 21:16:04 +01:00
Dan Raviv
7cbef3efc8
Fix comment out-of-sync with modified code (#321) 2022-01-06 08:46:54 +02:00
DNKpp
939123d1b4
Fix <package>_SOURCE_DIR and _BINARY_DIR handling when caching is active (#314)
* fix: use CACHE variables instead relying on FetchContents mechanism

* apply cmake-format

Signed-off-by: DNKpp <DNKpp2011@gmail.com>
2021-12-30 16:20:37 +01:00
Lars Melchior
22078d5e0d
add quotes around module arguments (#313) 2021-12-30 15:20:16 +02:00
Pavel Sokolov
96c268827b
Pass DOWNLOAD_ONLY flag when CPM_pkg_SOURCE is set. (#308)
https://github.com/cpm-cmake/CPM.cmake/issues/307
2021-12-15 21:23:18 +01:00
Lars Melchior
dad37fbe4e
Change example ordering and add note on boost (#305)
Reorders examples from simple to more complex. Also adds note on using `CPM_SOURCE_CACHE` for boost.
2021-12-12 15:09:50 +01:00
Lars Melchior
fed5f8e8a2
use official boost release (#304) 2021-12-05 16:08:47 +01:00
Lars Melchior
d65613e860
add warning when not using release version of CPM.cmake (#303) 2021-12-05 16:08:02 +01:00
Lars Melchior
718ea71759
Allow passing lists in the options (#302)
* allow list options by passing option parameter as string, not value

* add test

* remove debug message

* run formatter
2021-12-05 16:07:20 +01:00
Lars Melchior
6491382204
Remove travis badge from readme (#289)
Follow up on #283 to remove the now obsolete travis badge.
2021-09-29 13:48:40 +03:00
pgorgon-hem
634800c619
Added directory inside cache to make it shown more friendly in CLion (#268)
* Added directory inside cache to make it shown more friendly in CLion

* Changed hash generation to omit collision with old cache scheme. Removed moving old directory for compatibility reason.

* Added CPM_USE_NAMED_CACHE_DIRECTORIES option

* Fixed formatting

* Added description of CPM_USE_NAMED_CACHE_DIRECTORIES into README.md

Co-authored-by: Paweł Gorgoń <pgorgon@hem-e.com>
2021-09-15 21:39:31 +02:00
Andrea Barbadoro
f552da96bd
Detecting when the cache is dirty (#284)
* Check that the cache working directory is clean

* cpm_check_working_dir_is_clean for non git repo will not terminate cmake

* sileneced check for git repo, in case of error

* style(CPM.cmake): fixed indentation for ERROR_QUIET

* refactor(CPM.cmake): added logic to handle a cache folder inside a (not correlated) git repo

this is accomplished by checking if we are in the directory where .git lives

* style(CPM.cmake): stray tab to spaces

* test(dirty-cache-check): added unit test to check cpm_check_working_dir_is_clean

the test creates a file in a folder and then uses git to create a repo in that folder, to check various conditions

* Update test/unit/dirty-cache-check.cmake

added user.name and user.email to comply with test machine where git is not completely configured

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

* feat(cpm_check_working_dir_is_clean): now it takes a git tag (works with hashes too) to check for uncommitted and commited changes

* refactor(cpm_check_working_dir_is_clean): early return for the most common case of uncommited changes in a repo

* refactor(cpm_check_git_working_dir_is_clean): removed edgecase detection (a non-git folder in an unrelated git repo)

now the contract is that com_check_git_working_dir_is_clean is given the base folder of a git repo

Co-authored-by: Andrew Gribble <ag131012@renishaw.com>
Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2021-09-15 11:38:49 +02:00
Olivier Le Doeuff
ea6a8eb895
Fix CPMAddPackage when FetchContent_MakeAvailable already added package (#288)
Add fetchcontent_dependency unit test:
* 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

https://github.com/cpm-cmake/CPM.cmake/issues/287
2021-08-29 22:02:18 +02:00
MixusMinimax
a5c22bf6e8
use quotes for CPM_FILE when creating FIND.cmake (#286) 2021-08-29 22:01:50 +02:00
Lars Melchior
c5cb85b2f1
Build examples in CI using GitHub (#283)
* build examples in CI using github

* update cxxopts style
2021-08-29 20:27:10 +02:00
pgorgon-hem
91585e3864
Added support for bitbucket repositories (#256)
* Added support for bitbucket repositories:
* added variable BITBUCKET_REPOSITORY
* added short syntax in form "bb:user/repo"
* added description of that to readme.md

* Added test for bitbucket short syntax

* Used elseif syntax in handling of git services (github, gitlab, bitbucket).

* Added HEMRND/TestingFramework example located on bitbucket.org

* Reformatted CMakeLists.txt in TestingFramework example

* Bumped version of TestingFramework. It supports older version of c++ standard.

Co-authored-by: Paweł Gorgoń <pgorgon@hem-e.com>
2021-06-08 19:15:40 +02:00
Stuart Dootson
9675d46517
Expand relative download directory to prevent unnecessary download (#267)
* Expand relative download directory to prevent unnecessary download

If `CMAKE_SOURCE_CACHE` (and thus `download_directory`) is set to a relative path, the condition `if(EXISTS ${download_directory})` will fail even if the required directory exists. Expanding the variable `download_directory` to an absolute path before the test will rectify this, preventing unnecessary downloads of the sources.

* iFixed up formatting

Co-authored-by: Stuart Dootson <stuart.dootson@rolls-royce.com>
2021-06-08 19:12:20 +02:00
Lars Melchior
7078e8286a
Remove branch name references from README (#265)
As noted in #263, setting `GIT_TAG` to a branch name results in unexpected and unreproducible build behaviour, as it does not automatically update when the `HEAD` changes.
2021-06-08 15:55:03 +03:00
Lars Melchior
6a0277f16e
Update CMake to 3.20 for integration tests (#264)
This allows us to use more recent projects in the examples
2021-06-08 15:27:31 +03:00
Lars Melchior
4502bf1e04
Forward exclude and subdir options when using local package override (#261)
* forward exclude and subdir options when using local package override.
fixes #260.

* run cmake format

* add SOURCE_SUBDIR parameter to cmake-format
2021-06-08 15:26:39 +03:00
Clare Macrae
dd3ba9792c
Fix typo in README - omit -> emit (#258) 2021-06-02 09:36:29 +03:00
Lars Melchior
de5551e42c
Update boost-cmake (#252)
* update boost-cmake

* run cmake-format
2021-05-18 16:29:52 +03:00
Paul Taylor
7644c3a40f
Respect FETCHCONTENT_BASE_DIR if set by a user (#244)
* Respect `FETCHCONTENT_BASE_DIR` if set by a user

* Use a single `CPM_FETCHCONTENT_BASE_DIR` var
2021-04-16 17:27:51 +02:00
Lars Melchior
310efb9b17
Update more examples from the readme (#241)
* update examples from the readme

* add explainations to the examples
2021-03-26 18:31:35 +02:00
Lars Melchior
4fad2eac0a
remove option consistency check (#240) 2021-03-25 19:24:44 +02:00
flagarde
ee08119642
Scope package options to avoid changing the local scope (#235)
* Fix #222

* Fix #222

* move policy change and local options to cpm_add_subdirectory

* change default policy as well

see https://gitlab.kitware.com/cmake/cmake/-/issues/20312

* add test

* update check to not use the NOT operator

(interestingly it works as expected locally)

* simplify test by not using options

* check options in tests

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2021-03-25 15:59:34 +01:00
Lars Melchior
259f1be8e2
update cxxopts and add reasonable options (#239) 2021-03-25 14:20:06 +02:00
Lars Melchior
32b063eba5
Fix support for source subdirectories (#238)
* add support for source subdirectories

* style fixes

* remove debug log

* grammar fix in comment
2021-03-25 10:42:51 +01:00
Lars Melchior
d64d816585
Make CPMFindPackage less prominent in the Readme (#236)
Giving `CPMFindPackage` a less prominent position, as in almost all cases, `CPMAddPackage` should be preferred.

Following a related discussion in #222.
2021-03-22 12:37:11 +01:00
Lars Melchior
8e8dcc9a8d
moved test repostitory to CPM.cmake namespace (#228) 2021-03-04 11:01:01 +02:00
Lars Melchior
8afc2af4f9
update more examples to use shorthand syntax (#223)
* update more examples to use shorthand syntax

* revert google-benchmark as tests require googletest to be installed

* update comments

* always quote single-arguments

* undo accidental deletion
2021-02-25 09:53:28 +02:00
Borislav Stanimirov
a3d1048ad6
Infer package name and version from URL (#220)
* Function to extract name and version from url. Some tests

* Rewrite. Previous version was not safe enough. More tests

* Allow underscore as a name-version separator (<name>_<ver>)

* CPMAddPackage can infer name and version from url

* Allow URL parse from single arg and uncomment tests

* Info about shorthand syntax in README

* Fix style

* Fixed typo

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

* Explicit hash algorithm in shorthand URL example.
Also added tests which include a hash algorithm provided
We can't document a default until it's confirmed here: https://gitlab.kitware.com/cmake/cmake/-/issues/21859

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2021-02-23 20:15:45 +01:00
Lars Melchior
492e762591
update examples to use new syntax where possible (#218) 2021-02-23 08:14:32 +02:00
Borislav Stanimirov
3f6cbe7383
Single-argument shorthand syntax for CPMAddPackage (#207)
* Added quotes in equality checks so lists can be compared

* Function to parse argument of CPMAddPackage in case a single one was provided

* Error on URL type in CPMAddPackage single-arg

* Fixed format

* Support single argument syntax of CPMAddPackage

* Documenting and showcasing the new shorthand syntax of CPMAddPackage

* Auto EXCLUDE_FROM_ALL for the shorthand syntax

* Fixed accidental paste of TOLOWER

* Document why some test cases are commented out

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

* Update README.md

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

* Removed GitHub as the default package shorthand provider

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2021-02-22 21:12:06 +01:00
Borislav Stanimirov
4aadac1972
Improved regex match in cpm_package_name_from_git_uri (#206) 2021-02-19 09:45:04 +01:00
Borislav Stanimirov
4cbf443363
If a name isn't provided, try to infer it from the git repo (#202)
* Added assert_not_defined check

* Function to get package name form git uri and tests

* Autofix format

* If name is not provided, try to infer it from the git repo

* Unset result of cpm_package_name_from_git_uri if there is no match
- Also reordered tests to ensure that the result is actually unset when needed

* Removed trailing spaces in README

* Updated the main example with the new minimal syntax

* Well... autofix format again

* Update error message for missing name to reflect the possible auto-infer step

* Autofix format... yet again :)
2021-02-17 12:41:25 +01:00
Borislav Stanimirov
2744b87f07
FATAL_ERROR if no NAME is provided (#201)
* FATAL_ERROR if no NAME is provided

* Fixed format
2021-02-16 14:54:31 +00:00
Lars Melchior
fd539b8ff3
Add dependencies using EXCLUDE_FROM_ALL flag (#198)
* add dependencies using EXCLUDE_FROM_ALL flag

* respect DOWNLOAD_ONLY flag

* set EXCLUDE_FROM_ALL as an optional flag

* use one value arg for consistency

* fix argument passing

* add unit test

* update cmake-format
2021-02-16 10:26:16 +00:00
Lars Melchior
02d57a1601
Update URLs for new CPM.cmake organisation (#194)
* update URLs for new CPM.cmake organisation

* trigger travis
2021-02-08 21:31:06 +01:00
Claus Klein
5f614e5eb6
update most package versions (#190)
* update most package versions

extent build_all.py to inject cmake modules
and use Ninja generator

* fix build problems while build on debian

use SYSTEM include paths (for clang++)
we should not use local installed header!

* fix banchmark example

finalize cmake project code injection as an option

* fix build problems on travis CI

gtest needs c++17

* Update examples/build_all.py

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

* reindent py script requested by review

indent with only 2 spaces again

* changes according the review

the gtest build error seems to be a make -j cpucount problem

* revert filter too

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2021-02-07 17:08:04 +01:00
Xavier Muller
1f5cb903e5
fix superbuild cmake < 3.17 (#193)
* CPM_INDENT in the global scope as suggest

* Fix FetchContent failure with cmake < 3.17

* format
2021-02-07 17:07:47 +01:00
alexandreSalconiDenis
7000572bbe
Feature/prettify package lock (#162)
* add prettify macro

* apply the prettier and change the name of the output arg

* add parameter inside macro

* resolve path if its cmake_sourc_dir

* add missing uparsed argument

* add early unit test for prettifier

* retab prettify_cpm_add_package

* rename prettify_cpm_add_package  cpm_prettyfy_package_arguments

* convert macro to function and fix unit test

* fix typo in the name of the parse argument in prettyfy function

* change the unit test to test only the function

* add test for the commented part

* remove dead code

* fix typo

* run cmake-format on CPM.cmake

* reformated unit test prettify

* flip the logic to add space on new argument unparsed to avoir space at the end

* remove debug message

* apply most suggestion from pr 162, disable formating only for small part in unit test

* add unit test to cover defauld source dir added inside lock

* run format tool on unit test

* remove dead code

* change the prettifier from 4 space to 2

* run format on unit test
2021-01-27 13:29:15 +01:00
Borislav Stanimirov
fe8d15ba82
Expand CPM_SOURCE_CACHE path provided as a configure argument (#186)
Otherwise if one configures with -DCPM_SOURCE_CACHE=~/something (tilde to be expanded to $HOME), https://gitlab.kitware.com/cmake/cmake/-/issues/21729 hits, EXISTS always fails, and file(DOWNLOAD) fails
2021-01-21 16:31:55 +01:00
Lars Melchior
ab6e8d6d8c
Performance improvement: bypass FetchContent for cached dependencies (#182)
* skip FetchContent for cached dependencies

* set default value for CPM_SKIP_FETCH to avoid conflicts

* add tests to check exported values
2021-01-20 13:15:18 +01:00
Lars Melchior
aad0397beb
add further reading section (#177) 2021-01-14 12:28:11 +00:00
Lars Melchior
1ebbac6332
Apply clang-format and cmake-format and add style check workflow (#171)
* apply clang-format and cmake-format and add style check workflow

* add declare package definition

* add additional public methods and rename internals

* change development verison tag to 1.0.0

* rename internal method

* rename public method

* rename test var

* update copyright and fix comment

* typo

* run fix-format

* fix test function names
2021-01-06 14:40:33 +01:00
Yotam Gingold
cf3f62b6f2
Fixed typo in help message (#165) 2020-11-26 17:52:34 +01:00
Xavier Muller
3b404296b5
fix: GIT_TAG not parsed inside CPMFindPackage (#159)
When using CPMFindPackage, if no VERSION is given then GIT_TAG is used as fallback if defined, which is a good idea.
The issue is that GIT_TAG is missing inside the oneValueArgs variable therefore GIT_TAG is not parsed. This is resolved by this little change.
2020-10-19 09:34:42 +02:00
Leonardo Lima
18e09b07ba
Implemented GitHub Actions cache example (#156)
* Implemented GitHub Actions cache example

* Updated GitHub Actions example

* Update README.md

* Fixed consistency

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2020-10-06 13:07:00 +02:00
Kai Germaschewski
aeef56ea85
fix passing options when using CPM_<pkg>_SOURCE (#155)
When I used CPM_<pkg>_SOURCE to point to a locally modified copy,
the options ended up not being passed on. I think they should be, so
this patch does so.
2020-09-27 22:56:32 +02:00
The Gitter Badger
4271d5981f
Add Gitter badge (#154) 2020-09-25 17:42:02 +02:00
Prabir Shrestha
d17500b0be
ignore lua.c and luac.c from lua (#149)
* ignore lua.c and luac.c from lua

* Update README.md

* update CMakeLists.txt for sol2
2020-09-13 12:00:19 +02:00
Leonardo
5e0c3855c7
Implemented spdlog library example (#150) 2020-09-08 14:08:35 +02:00
Lars Melchior
f96cff720e
switch to on-demand download script as the recommended way to get CPM.cmake (#147) 2020-08-20 10:31:08 +02:00
Lars Melchior
c3c7e2d9a3
add on-demand download script to release (#146) 2020-08-20 09:32:03 +02:00
Lars Melchior
30b98af416
Add link to tutorial (#143) 2020-08-12 13:41:40 +02:00
Lars Melchior
5063c7d992
Add built with CPM.cmake section (#142)
* add built with cpm.cmake section

* update text

* explicitly set width
2020-08-11 14:49:21 +02:00
Lars Melchior
3cfb309f3c
add comparisons to other approaches (#141) 2020-08-11 12:49:37 +02:00
Lars Melchior
25603ac4ad
Update publish script to set CPM.cmake version automatically (#139)
* update publish script to set CPM.cmake version automatically

* set a minimum development version to avoid deprecated error handler call
2020-08-04 13:12:35 +02:00
Lars Melchior
ac872f6908
Bump version and add gitlab source to examples (#138)
* use gitlab as source for example library

* bump CPM.cmake version
2020-08-04 12:24:06 +02:00
jecassis
bd14ccbd5a
Fix indeterminate command for GitLab argument (#137) 2020-08-04 11:40:58 +02:00
Kingsley Chen
f8afae6eb3
Add asio standalone example (#133)
* Add asio standalone example

* Mark VERSION explicitly

Without this version information, CPM's versioning mechanism may break
in some cases.

Also add comments for compile definition on Windows.

* Use aync-tcp-echo-server as the example

* Add boost software license to the demo source

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
2020-06-24 12:40:12 +02:00
Lars Melchior
9ec279c75f
bump version and update tests (#131) 2020-06-15 10:16:30 +02:00
Kingsley Chen
392b2a864b
Use shallow clone for git repositories by default (#129) (#130)
* Use shallow clone for git repositories by default (#129)

* use shallow clone for git repositories by default

* remove trailing spaces

* Enable shallow clone for actual tags

* Support short commit hash

* Enable shallow only when downloading dependencies into cache

* Always honor user specified GIT_SHALLOW opiton
2020-06-15 09:27:26 +02:00
Lars Melchior
139d3cacba
Add NO_CACHE option (#128)
* add NO_CACHE option

* add unit test
2020-06-04 14:22:57 +02:00
Lars Melchior
b31063d2ae
prevent overriding declarations (#127) 2020-05-29 16:08:41 +02:00
Lars Melchior
4425bd38cf
Add FORCE parameter (#126)
* add scope protection

* rename to cpm_clean_argument_scope and update patch version

* undo unnecessary scope cleaning

* undo some changes

* consistent define checks
2020-05-29 15:37:49 +02:00
Lars Melchior
6da5c38dae
Add package lock section to the readme (#125)
* add package lock section to the readme

* clarify position of package lock
2020-05-29 12:24:55 +02:00
Lars Melchior
76d7b27459
Fix typo and wording (#124)
* Fix typo

* Update README.md
2020-05-29 10:15:09 +02:00
Lars Melchior
54a2d80d1e
Add option for local package override (#123)
* add option for local package override

* print info on the source directory
2020-05-29 09:58:39 +02:00
Lars Melchior
829262cbd3
omit unversioned and local dependencies in package lock (#122)
* omit unversioned and local dependencies in package lock

* update package lock for active project only
2020-05-28 13:29:25 +02:00
Lars Melchior
4aeea1d31d
Add package lock (#121)
* add package lock creation

* change target name

* fix cpm_export_variables

* add test

* fix git repo detection addition

* remove test package lock from git

* add link to package lock wiki

* add CPMGetPackage
2020-05-27 19:07:06 +02:00
Lars Melchior
58365446f5
fix DOWNLOAD_ONLY option when used with CPMFindPackage (#120) 2020-05-19 20:47:12 +02:00
Johel Ernesto Guerrero Peña
4937617ef1
Use STREQUAL rather than MATCHES <regex> (#116) 2020-05-10 11:21:07 +02:00
Lars Melchior
6f053907f5
check if package added before find_package (#115) 2020-05-07 23:54:10 +02:00
Ryan Mast
84b31b560a
Fix wiki link to preparing projects for CPM.cmake (#114) 2020-04-30 09:45:12 +02:00
Lars Melchior
3fff3ca70d
Call FetchContent_GetProperties before DOWNLOAD_ONLY population (#113)
* call FetchContent_GetProperties before checking populated

* fix old CPM.cmake links

* update description

* bump version
2020-04-29 12:40:12 +02:00
Lars Melchior
ca33abc236
create FindXXX.cmake modules for added CPM packages (#112)
* create FindXXX.cmake modules for added CPM packages

* don't use list(PREPEND) as it unsupported on older CMake versions

* use CMAKE_BINARY_DIR

* ensure CPM.cmake is initialized only once

* import CPM.cmake in modules
2020-04-29 09:18:54 +02:00
Giuseppe Cesarano
119eaee84d
Fixed link in README.md (#111)
The section `Adding CPM` was poiting to non exinsting wiki page
2020-04-26 16:44:16 +02:00
Lars Melchior
00b5e80f88
Fix offline cache support (#110)
* use cmake -E true as empty command

* use cmake without arguments as valid empty command
2020-04-25 01:27:27 +02:00
Lars Melchior
618cdefa0d
Support CPM_SOURCE_CACHE on windows (#109)
* use semicolon as empty command and add test

* remove platform specific test coverage

* only run actions for pushes and prs into master (avoid duplication)

* remove cache test as it's already part of the test suite

* update version

* test cache reuse
2020-04-25 00:51:18 +02:00
Lars Melchior
464ba554c2
suppress package not found warning in CPMFindPackage (#103) 2020-04-14 09:35:31 +02:00
Lars Melchior
90558aa9cb
Add GitHub action to publish CPM on release (#102)
* add github action to publish cpm on release

* add checkout step

* update readme
2020-03-16 20:37:30 +01:00
Lars Melchior
95c5426d25
remove code artifact from previous PR (#101) 2020-03-16 20:09:15 +01:00
Lars Melchior
cea81872cf
Add fmt example and document version from git tag (#100)
* add VERSION_PREFIX argument

* add fmt example

* add VERSION_PREFIX note to readme

* rollback, add info about determining version from git tag

* rollback version
2020-03-16 20:00:30 +01:00
Lars Melchior
01b69aad82
add support for SOURCE_DIR argument (#97)
* add support for SOURCE_DIR argument

* simplify code

* add test

* update comment
2020-02-25 13:29:21 +01:00
Lars Melchior
775a235880
default to "ON" for options without explicit value definition (#96)
* default to "ON" for options without explicit value definition

* increment CPM version

* compare the correct lengths
2020-02-06 11:50:55 +01:00
Lars Melchior
f8d4e959bb
abort when nested (bugfix) (#94)
* abort when nested (bugfix)

* update error message

* update error message
2019-10-25 20:52:22 +02:00
Lars Melchior
4c7aa36dff
Update README.md 2019-10-25 16:01:47 +02:00
Lars Melchior
3a4516265c
Add GitHub workflows (#93)
* add mac workflow

* rename and add windows and ubuntu workflows

* update tests

* update tests

* update travis
2019-10-24 18:14:58 +02:00
Lars Melchior
47bfb554ab
reorganise source and add CPMFindPackage (#92)
* reorganise source and add CPMFindPackage

* add consistent find_package behaviour

* document CPMFindPackage

* reset examples to CPMAddPackage unless tested

* update version

* update README.md

* Update README.md
2019-10-24 15:42:25 +02:00
Lars Melchior
0a8a65df32
Update README.md (#90) 2019-10-19 15:45:19 +02:00
Lars Melchior
a2800dc96c
Update for new repo name (old URLs are still valid) (#89)
* Update for new repo name (old URL is still valid)

* Update README.md
2019-10-18 11:53:36 +02:00
Lars Melchior
7638be873a
Add Ccache.cmake link (#88) 2019-10-14 17:12:33 +02:00
Lars Melchior
d1a1b70d4a
update readme (#87) 2019-10-14 12:55:47 +02:00
Lars Melchior
4064a45552
Add CPM_SOURCE_CACHE environmental variable support and keep existing sources (#83)
* read CPM_SOURCE_CACHE from environment

* update readme

* cleanup

* add cache tests
2019-10-10 20:13:10 +02:00
Paul T
b1855e9275 Feature/cereal example (#85)
* Added GTest (googletest) Example

The examples tests the Fibonacci library similar to the doctest example.

* Add Example for the cereal library.

* Update examples/cereal/CMakeLists.txt

Co-Authored-By: Lars Melchior <TheLartians@users.noreply.github.com>

* Remove Test Coverage Code

* Remove Test Coverage Option
2019-10-09 15:30:59 +02:00
Paul T
5191b4c703 Added GTest (googletest) Example (#84)
* Added GTest (googletest) Example

The examples tests the Fibonacci library similar to the doctest example.

* Update examples/gtest/CMakeLists.txt

Co-Authored-By: Lars Melchior <TheLartians@users.noreply.github.com>
2019-10-09 14:50:27 +02:00
Lars Melchior
8625173d8f
add CPM_SOURCE_ROOT option (#81)
* add CPM_SOURCE_ROOT option

* update version and readme
2019-10-07 16:34:07 +02:00
Lars Melchior
504761fbf2
add EnTT example (#78) 2019-09-06 11:52:18 +02:00
Lars Melchior
8b92bb46cd
Add more readme links to the wiki (#77)
* Add readme link to snippets

* Update README.md
2019-08-16 11:12:11 +02:00
Paul T
88278a4f70 Add Blurb on Including CPM (#76)
* Add Blurb on Including CPM

Added demo cmake code to auto download CPM from github.

* Remove Section in favor of including a link to a wiki page.
2019-08-15 19:34:21 +02:00
Lars Melchior
72552708e6
add linenoise (#74) 2019-07-31 13:25:58 +02:00
Lars Melchior
a6bc65a76c
add cxxopts example and update lua (#73)
* add cxxopts example

* use new tags for lua

* update readme

* update readme

* update lua

* typo
2019-07-24 11:48:50 +02:00
Lars Melchior
64f5fe37cd
Update README.md (#71) 2019-07-01 20:44:51 +02:00
Lars Melchior
25a9158448
Add boost example (#70)
* add unit tests

* added boost

* cleanup

* add pthread

* Update README.md
2019-07-01 20:30:21 +02:00
Lars Melchior
1e8d8d43c7
typos (#68) 2019-06-29 19:23:38 +02:00
Lars Melchior
160a665973
remove unused argument (#67) 2019-06-27 13:06:52 +02:00
Lars Melchior
3d75ed06a3
add unit tests and determine version from GIT_TAG (#66)
* add unit tests

* determine package version from git tag. closes #54.

* update readme

* bugfix

* update example

* update gitignore
2019-06-22 13:31:32 +02:00
Lars Melchior
1e25367c8c
add sol2 example (#65)
* add sol2 example

* Update README.md

* Update README.md
2019-05-25 14:14:31 +02:00
Lars Melchior
9d2b5818c5
Update README.md (#64)
* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md
2019-05-24 16:34:05 +02:00
Lars Melchior
49e7903e19
Update README.md (#62) 2019-05-23 14:35:45 +02:00
Lars Melchior
4d3997d408
update logo (#61)
* update logo

* update

* update

* update

* update

* update
2019-05-23 14:17:41 +02:00
Lars Melchior
d74bcebfe8
Update README.md (#60) 2019-05-23 13:26:53 +02:00
Lars Melchior
db3111e07e
update logo (#59)
* update logo

* convert to png
2019-05-23 12:47:55 +02:00
Lars Melchior
840e2e2c40
Update README.md (#58) 2019-05-23 12:25:10 +02:00
Lars Melchior
4952fd3d48
Update range v3 (#56)
* update range-v3 example as the projects CMakeLists messes up the configuration

* add comment

* add range-v3 snipplet back
2019-05-23 12:25:00 +02:00
Lars Melchior
3659fa581c
Add logo (#57)
* add logo

* Update README.md

* Update README.md
2019-05-23 12:08:46 +02:00
Lars Melchior
4aeb1215bf
Update README.md 2019-05-22 18:33:41 +02:00
Lars Melchior
13559c7137
Add range-v3 example (#55)
* add range-v3 example

* update Readme

* Update README.md

* Update README.md

* Update README.md
2019-05-22 14:21:54 +02:00
Lars Melchior
e4f1ade459
Update README.md 2019-05-22 10:46:48 +02:00
Lars Melchior
7723e56dab
Update README.md 2019-05-22 01:32:41 +02:00
Lars Melchior
8287799e79
Update README.md 2019-05-22 01:18:07 +02:00
Lars Melchior
cd91713d10
Update README.md 2019-05-22 00:16:11 +02:00
Lars Melchior
4967b841ad
Update CPM.cmake 2019-05-20 17:54:08 +02:00
Lars Melchior
9c2c34f487
Update CPM.cmake 2019-05-20 17:53:37 +02:00
Lars Melchior
bd9143bfa0
Update README.md 2019-05-20 14:52:46 +02:00
137 changed files with 5711 additions and 598 deletions

16
.clang-format Normal file
View 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'
...

5
.cmake-format Normal file
View File

@ -0,0 +1,5 @@
include: ["cmake/.cmake-format-additional_commands-cpm"]
format:
tab_size: 2
line_width: 100
dangle_parens: true

3
.git_archival.txt Normal file
View File

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

1
.gitattributes vendored Normal file
View File

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

30
.github/workflows/examples.yaml vendored Normal file
View 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@v3
- name: build all
env:
CC: gcc
CXX: g++
run: python3 examples/build_all.py
clang:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: build all
env:
CC: clang
CXX: clang++
run: python3 examples/build_all.py

29
.github/workflows/publish.yaml vendored Normal file
View File

@ -0,0 +1,29 @@
name: Publish
on:
push:
tags:
- '*'
jobs:
build:
name: Publish CPM.cmake
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set CPM version by tag
run: |
mkdir dist
sed -e "s/1.0.0-development-version/${GITHUB_REF/refs\/tags\/v}/g" cmake/CPM.cmake > dist/CPM.cmake
sed -e "s/1.0.0-development-version/${GITHUB_REF/refs\/tags\/v}/g" \
-e "s/CPM_HASH_SUM_PLACEHOLDER/$(sha256sum dist/CPM.cmake | cut -d' ' -f1)/" cmake/get_cpm.cmake > dist/get_cpm.cmake
- name: Upload CPM.cmake to release
uses: svenstaro/upload-release-action@v1-release
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
file: dist/*.cmake
file_glob: true
overwrite: true

31
.github/workflows/style.yaml vendored Normal file
View File

@ -0,0 +1,31 @@
name: Style
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
style:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v1.13
with:
cmake-version: '3.27.x'
- name: Install format dependencies
run: pip3 install clang-format==14.0.6 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

48
.github/workflows/test.yaml vendored Normal file
View File

@ -0,0 +1,48 @@
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]
# we want to ensure compatibility with a recent CMake version as well as the lowest officially supported
# legacy version that we define as the default version of the second-latest Ubuntu LTS release currently available
cmake_version: ['3.16.3', '3.27.5', '3.30.0']
exclude:
# there seems to be an issue with CMake 3.16 not finding a C++ compiler on windows-2022
- os: windows-2022
cmake_version: '3.16.3'
steps:
- name: clone
uses: actions/checkout@v3
- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v1.13
with:
cmake-version: ${{ matrix.cmake_version }}
- name: unit tests
run: |
cmake -Stest -Bbuild/test
cmake --build build/test --target test-verbose
env:
CMAKE_VERSION: ${{ matrix.cmake_version }}
- name: integration tests
run: ruby test/integration/runner.rb
env:
CPM_INTEGRATION_TEST_DIR: ./build/integration
CMAKE_VERSION: ${{ matrix.cmake_version }}

14
.gitignore vendored
View File

@ -1,10 +1,4 @@
CMakeCache.txt build/
CMakeFiles /build*
CMakeScripts /.vscode
Testing *.DS_Store
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
build

View File

@ -1,48 +0,0 @@
language: cpp
sudo: require
dist: xenial
common_sources: &all_sources
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty
python:
- 3.7
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:
- python3 examples/run_all.py

28
CMakeLists.txt Normal file
View File

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

177
CONTRIBUTING.md Normal file
View File

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

40
CONTRIBUTORS.md Normal file
View File

@ -0,0 +1,40 @@
# 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)
* [Lars Bilke](https://github.com/bilke)
* [Lava Block](https://github.com/TheLavaBlock)
* [Anton Filimonov](https://github.com/variar)
* [David Fong](https://github.com/david-fong)
* [Thomas Mosegaard Pedersen](https://github.com/thomas-mp)
* [Evgeny Gorodetskiy](https://github.com/egorodet)
* [Kamil Kisiel](https://github.com/kisielk)
* [AlessandroW](https://github.com/AlessandroW)

View File

@ -1,6 +1,6 @@
MIT License 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 Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

606
README.md
View File

@ -1,41 +1,27 @@
[![Build Status](https://travis-ci.com/TheLartians/CPM.svg?branch=master)](https://travis-ci.com/TheLartians/CPM)
# CPM <br />
<p align="center">
<img src="./logo/CPM.png" height="100" />
</p>
<br />
CPM is a CMake script that adds dependency management capabilities to CMake. # Setup-free CMake dependency management
It's built as an extension of CMake's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) module that adds version control and simpler usage.
## 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
## Usage Any downloadable project or resource can be added as a version-controlled dependency through 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).
After `CPM.cmake` has been added to your project, the function `CPMAddPackage` can be used to fetch and configure all dependencies. ## Further reading
Afterwards all targets defined in the dependencies can be used.
`CPMAddPackage` takes the following named arguments.
```cmake - [CPM: An Awesome Dependency Manager for C++ with CMake](https://medium.com/swlh/cpm-an-awesome-dependency-manager-for-c-with-cmake-3c53f4376766)
CPMAddPackage( - [CMake and the Future of C++ Package Management](https://ibob.github.io/blog/2020/01/13/cmake-package-management/)
NAME # The name of the dependency (should be chosen to match the main 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 paramters forwarded to FetchContent_Declare, see below
)
```
The origin is usually specified by a `GIT_REPOSITORY`, but [svn revisions and direct URLs are also supported](https://cmake.org/cmake/help/latest/module/FetchContent.html#declaring-content-details). ## Full CMakeLists Example
If `GIT_TAG` hasn't been explicitly specified it defaults to `v(VERSION)`, a common convention for github projects.
`GIT_TAG` can also be set to a branch name such as `master` to download the most recent version.
Besides downloading and to configuring the dependency, 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`.
## Full Example
```cmake ```cmake
cmake_minimum_required(VERSION 3.14 FATAL_ERROR) cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
@ -43,108 +29,467 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
# create project # create project
project(MyProject) project(MyProject)
# add executable
add_executable(main main.cpp)
# add dependencies # add dependencies
include(cmake/CPM.cmake) include(cmake/CPM.cmake)
CPMAddPackage( CPMAddPackage("gh:fmtlib/fmt#7.1.3")
NAME LarsParser CPMAddPackage("gh:nlohmann/json@3.10.5")
VERSION 1.8 CPMAddPackage("gh:catchorg/Catch2@3.4.0")
GIT_REPOSITORY https://github.com/TheLartians/Parser.git
OPTIONS
"LARS_PARSER_BUILD_GLUE_EXTENSION ON"
)
# add executable # link dependencies
add_executable(myProject myProject.cpp) target_link_libraries(main fmt::fmt nlohmann_json::nlohmann_json Catch2::Catch2WithMain)
set_target_properties(myProject PROPERTIES CXX_STANDARD 17)
target_link_libraries(myProject LarsParser)
``` ```
See the [examples directory](https://github.com/TheLartians/CPM/tree/master/examples) for more examples with source code. 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 ## 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 ```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.
## Usage
After `CPM.cmake` has been [added](#adding-cpm) to your project, the function `CPMAddPackage` can be used to fetch and configure a dependency.
Afterwards, any targets defined in the dependency can be used directly.
`CPMAddPackage` takes the following named parameters.
```cmake
CPMAddPackage(
NAME # The unique name of the dependency (should be the exported target's name)
VERSION # The minimum version of the dependency (optional, defaults to 0)
PATCHES # Patch files to be applied sequentially using patch and PATCH_OPTIONS (optional)
OPTIONS # Configuration options passed to the dependency (optional)
DOWNLOAD_ONLY # If set, the project is downloaded, but not configured (optional)
[...] # Origin parameters forwarded to FetchContent_Declare, see below
)
```
The origin may be specified by a `GIT_REPOSITORY`, but other sources, such as direct URLs, are [also supported](https://cmake.org/cmake/help/v3.11/module/ExternalProject.html#external-project-definition).
If `GIT_TAG` hasn't been explicitly specified it defaults to `v(VERSION)`, a common convention for git projects.
On the other hand, if `VERSION` hasn't been explicitly specified, CPM can automatically identify the version from the git tag in some common cases.
`GIT_TAG` can also be set to a specific commit or a branch name such as `master`, however this isn't recommended, as such packages will only be updated when the cache is cleared.
`PATCHES` takes a list of patch files to apply sequentially. For a basic example, see [Highway](examples/highway/CMakeLists.txt).
We recommend that if you use `PATCHES`, you also set `CPM_SOURCE_CACHE`. See [issue 577](https://github.com/cpm-cmake/CPM.cmake/issues/577).
If an additional optional parameter `EXCLUDE_FROM_ALL` is set to a truthy value, then any targets defined inside the dependency won't be built by default. See the [CMake docs](https://cmake.org/cmake/help/latest/prop_tgt/EXCLUDE_FROM_ALL.html) for details.
If an additional optional parameter `SYSTEM` is set to a truthy value, the SYSTEM directory property of the subdirectory added will be set to true.
See the [add_subdirectory ](https://cmake.org/cmake/help/latest/command/add_subdirectory.html?highlight=add_subdirectory)
and [SYSTEM](https://cmake.org/cmake/help/latest/prop_tgt/SYSTEM.html#prop_tgt:SYSTEM) target property for details.
A shorthand syntax is also supported:
```cmake
# A git package from a given uri with a version
CPMAddPackage("uri@version")
# A git package from a given uri with a git tag or commit hash
CPMAddPackage("uri#tag")
# A git package with both version and tag provided
CPMAddPackage("uri@version#tag")
```
In the shorthand syntax if the URI is of the form `gh:user/name`, it is interpreted as GitHub URI and converted to `https://github.com/user/name.git`. If the URI is of the form `gl:user/name`, it is interpreted as a [GitLab](https://gitlab.com/explore/) URI and converted to `https://gitlab.com/user/name.git`. If the URI is of the form `bb:user/name`, it is interpreted as a [Bitbucket](https://bitbucket.org/) URI and converted to `https://bitbucket.org/user/name.git`. Otherwise the URI used verbatim as a git URL. All packages added using the shorthand syntax will be added using the [EXCLUDE_FROM_ALL](https://cmake.org/cmake/help/latest/prop_tgt/EXCLUDE_FROM_ALL.html) and [SYSTEM](https://cmake.org/cmake/help/latest/prop_tgt/SYSTEM.html#prop_tgt:SYSTEM) flag.
The single-argument syntax also works for URLs:
```cmake
# An archive package from a given url. The version is inferred
CPMAddPackage("https://example.com/my-package-1.2.3.zip")
# An archive package from a given url with an MD5 hash provided
CPMAddPackage("https://example.com/my-package-1.2.3.zip#MD5=68e20f674a48be38d60e129f600faf7d")
# An archive package from a given url. The version is explicitly given
CPMAddPackage("https://example.com/my-package.zip@1.2.3")
```
Additionally, if needed, extra arguments can be provided while using single argument syntax by using the shorthand syntax with the `URI` specifier.
```cmake
CPMAddPackage(
URI "gh:nlohmann/json@3.9.1"
OPTIONS "JSON_BuildTests OFF"
)
```
The `URI` argument must be the first argument to `CPMAddPackage`.
`URI` automatically sets `EXCLUDE_FROM_ALL YES` and `SYSTEM YES`.
If this is not desired, `EXCLUDE_FROM_ALL NO` and `SYSTEM NO` can be set afterwards.
After calling `CPMAddPackage`, the following variables are defined in the local scope, where `<dependency>` is the name of the dependency.
- `<dependency>_SOURCE_DIR` is the path to the source of the dependency.
- `<dependency>_BINARY_DIR` is the path to the build directory of the dependency.
- `<dependency>_ADDED` is set to `YES` if the dependency has not been added before, otherwise it is set to `NO`.
- `CPM_LAST_PACKAGE_NAME` is set to the determined name of the last added dependency (equivalent to `<dependency>`).
For using CPM.cmake projects with external package managers, such as conan or vcpkg, setting the variable [`CPM_USE_LOCAL_PACKAGES`](#options) will make CPM.cmake try to add a package through `find_package` first, and add it from source if it doesn't succeed.
In rare cases, this behaviour may be desirable by default. The function `CPMFindPackage` will try to find a local dependency via CMake's `find_package` and fallback to `CPMAddPackage`, if the dependency is not found.
## Updating CPM ## Updating CPM
To update CPM to the newest version, 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. To update CPM to the newest version, update the script in the project's root directory, for example by running the same command as for [adding CPM](#adding-cpm).
Dependencies using CPM will automatically use the updated script of the outermost project.
## Snipplets ## Advantages
These examples demonstrate how to include some well-known projects with CPM. - **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.
### [Catch2](https://github.com/catchorg/Catch2.git) ## Limitations
Has a CMakeLists.txt that supports `add_subdirectory`. - **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).
- **Some CMake policies set to `NEW`** Including CPM.cmake will lead to several CMake policies being set to `NEW`. Users which need the old behavior will need to manually modify their CMake code to ensure they're set to `OLD` at the appropriate places. The policies are:
- [CMP0077](https://cmake.org/cmake/help/latest/policy/CMP0077.html) and [CMP0126](https://cmake.org/cmake/help/latest/policy/CMP0126.html). They make setting package options from `CMPAddPackage` possible.
- [CMP0135](https://cmake.org/cmake/help/latest/policy/CMP0135.html) It allows for proper package rebuilds of packages which are archives, source cache is not used, and the package URL is changed to an older version.
- [CMP0150](https://cmake.org/cmake/help/latest/policy/CMP0150.html) Relative paths provided to `GIT_REPOSITORY` are treated as relative to the parent project's remote.
```cmake 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).
CPMAddPackage( Dependencies added with `CPMFindPackage` should work with external package managers.
NAME Catch2 Additionally, the option [`CPM_USE_LOCAL_PACKAGES`](#cpmuselocalpackages) will enable `find_package` for all CPM dependencies.
GITHUB_REPOSITORY catchorg/Catch2
VERSION 2.5.0 ## 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
``` ```
See [here](https://github.com/TheLartians/CPM/blob/master/examples/doctest/CMakeLists.txt) for doctest example. Note that passing the variable as a configure option to CMake will always override the value set by the environmental variable.
Note that we can shorten Github and Gitlab URLs by using `GITHUB_REPOSITORY` or `GITLAB_REPOSITORY`, respectively.
### [google/benchmark](https://github.com/google/benchmark.git) 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.
Has a CMakeLists.txt that supports `add_subdirectory`, but needs some configuring to work without external dependencies. The directory where the version for a project is stored is by default the hash of the arguments to `CPMAddPackage()`.
If for instance the patch command uses external files, the directory name can be set with the argument `CUSTOM_CACHE_KEY`.
### CPM_DOWNLOAD_ALL
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`.
Note that this does not apply to dependencies that have been defined with a truthy `FORCE` parameter. These will be added as defined.
### CPM_DONT_UPDATE_MODULE_PATH
By default, CPM will override any `find_package` commands to use the CPM downloaded version.
This is equivalent to the `OVERRIDE_FIND_PACKAGE` FetchContent option, which has no effect in CPM.
To disable this behaviour set the `CPM_DONT_UPDATE_MODULE_PATH` option.
This will not work for `find_package(CONFIG)` in CMake versions before 3.24.
### CPM_USE_NAMED_CACHE_DIRECTORIES
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 ```cmake
CPMAddPackage( CPMUsePackageLock(package-lock.cmake)
NAME benchmark ```
GITHUB_REPOSITORY google/benchmark
VERSION 1.4.1
OPTIONS
"BENCHMARK_ENABLE_TESTING Off"
)
# needed to compile with C++17 To create or update the package lock file, build the `cpm-update-package-lock` target.
set_target_properties(benchmark PROPERTIES CXX_STANDARD 17)
```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.
## Private repositories and CI
When using CPM.cmake with private repositories, there may be a need to provide an [access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) to be able to clone other projects. Instead of providing the token in CMake, we recommend to provide the regular URL and use [git-config](https://git-scm.com/docs/git-config) to rewrite the URLs to include the token.
As an example, you could include one of the following in your CI script.
```bash
# Github
git config --global url."https://${USERNAME}:${TOKEN}@github.com".insteadOf "https://github.com"
```
```bash
# GitLab
git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com".insteadOf "https://gitlab.com"
```
## 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>
</tr>
<tr>
<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>
<td>
<a href="https://github.com/variar/klogg">
<p align="center">
<img src="https://github.com/variar/klogg/blob/master/src/app/images/hicolor/scalable/klogg.svg" alt="klogg" width="100pt" />
</p>
<p align="center"><b>klogg - fast advanced log explorer</b></p>
</a>
</td>
<td>
<a href="https://github.com/MethanePowered/MethaneKit">
<p align="center">
<img src="https://github.com/MethanePowered/MethaneKit/raw/master/Docs/Images/Logo/MethaneLogoSmall.png" alt="MethaneKit" width="100pt" />
</p>
<p align="center"><b>Methane Kit - modern 3D graphics rendering framework</b></p>
</a>
</td>
</tr>
<tr>
<td>
<a href="https://github.com/jhasse/jngl">
<p align="center">
<img src="https://github.com/jhasse/jngl/raw/master/doc/jngl-logo.svg" alt="JNGL" width="100pt" />
</p>
<p align="center"><b>JNGL - easy to use cross-platform 2D game library</b></p>
</a>
</td>
<td>
<a href="https://github.com/sillydan1/aaltitoad">
<p align="center">
<img src="https://github.com/sillydan1/aaltitoad/raw/v1.1.0/.github/resources/logo/toad_only.svg" alt="aaltitoad" width="100pt" />
</p>
<p align="center"><b>AALTITOAD - verifier and simulator for Tick Tock Automata</b></p>
</a>
</td>
<td>
<a href="https://github.com/ZIMO-Elektronik">
<p align="center">
<img src="https://avatars.githubusercontent.com/u/117935012?s=400&u=9a871a46dd13437f0adcae166e9efbe518ff0b99&v=4" alt="ZIMO-Elektronik" width="100pt" />
</p>
<p align="center"><b>ZIMO-Elektronik</b></p>
</a>
</td>
</tr>
<tr>
<td>
<a href="https://github.com/ada-url/ada">
<p align="center">
<img src="https://avatars.githubusercontent.com/u/120840559?s=200&v=4" alt="ada" width="100pt" />
</p>
<p align="center"><b>ada - WHATWG-compliant and fast URL parser written in modern C++</b></p>
</a>
</td>
<td>
<a href="https://github.com/exaloop/codon">
<p align="center">
<img src="https://github.com/exaloop/codon/blob/develop/docs/img/logo.png?raw=true" alt="codon" width="100pt" />
</p>
<p align="center"><b>codon - A high-performance, zero-overhead, extensible Python compiler using LLVM</b></p>
</a>
</td>
<td>
<a href="https://github.com/RoaringBitmap/CRoaring">
<p align="center">
<img src="https://avatars.githubusercontent.com/u/16548876?s=200&v=4" alt="CRoaring" width="100pt" />
</p>
<p align="center"><b>CRoaring - Roaring bitmaps in C (and C++), with SIMD (AVX2, AVX-512 and NEON) optimizations: used by Apache Doris, ClickHouse, and StarRocks</b></p>
</a>
</td>
</tr>
</table>
## 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.12.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) ### [nlohmann/json](https://github.com/nlohmann/json)
Header-only library with a huge git repositoy. ```cmake
Instead of downloading the whole repositoy, we fetch the zip included with the release and create our own target. CPMAddPackage(
URI "gh:nlohmann/json@3.9.1"
OPTIONS "JSON_BuildTests OFF"
)
```
### [Boost](https://github.com/boostorg/boost)
Boost is a large project and will take a while to download. Using
`CPM_SOURCE_CACHE` is strongly recommended. Cloning moves much more
data than a source archive, so this sample will use a compressed
source archive (tar.xz) release from Boost's github page.
```CMake
# boost is a huge project and directly downloading the 'alternate release'
# from github is much faster than recursively cloning the repo.
CPMAddPackage(
NAME Boost
VERSION 1.84.0
URL https://github.com/boostorg/boost/releases/download/boost-1.84.0/boost-1.84.0.tar.xz
URL_HASH SHA256=2e64e5d79a738d0fa6fb546c6e5c2bd28f88d268a2a080546f74e5ff98f29d0e
OPTIONS "BOOST_ENABLE_CMAKE ON"
)
```
For a working example of using CPM to download and configure the Boost C++ Libraries see [here](examples/boost).
### [cxxopts](https://github.com/jarro2783/cxxopts)
```cmake
# the install option has to be explicitly set to allow installation
CPMAddPackage(
URI "gh:jarro2783/cxxopts@2.2.1"
OPTIONS "CXXOPTS_BUILD_EXAMPLES NO" "CXXOPTS_BUILD_TESTS NO" "CXXOPTS_ENABLE_INSTALL YES"
)
```
### [google/benchmark](https://github.com/google/benchmark)
```cmake ```cmake
CPMAddPackage( CPMAddPackage(
NAME nlohmann_json URI "gh:google/benchmark@1.5.2"
VERSION 3.6.1 OPTIONS "BENCHMARK_ENABLE_TESTING Off"
URL https://github.com/nlohmann/json/releases/download/v3.6.1/include.zip
URL_HASH SHA256=69cc88207ce91347ea530b227ff0776db82dcb8de6704e1a3d74f4841bc651cf
) )
if (nlohmann_json_ADDED) if(benchmark_ADDED)
add_library(nlohmann_json INTERFACE) # enable c++11 to avoid compilation errors
target_include_directories(nlohmann_json INTERFACE ${nlohmann_json_SOURCE_DIR}) set_target_properties(benchmark PROPERTIES CXX_STANDARD 11)
endif() endif()
``` ```
Adding large repos works as well, but takes a while for the initial clone.
### [Lua](https://www.lua.org) ### [Lua](https://www.lua.org)
Lua does not oficially support CMake, so we query the sources and create our own target.
```cmake ```cmake
CPMAddPackage( CPMAddPackage(
NAME lua NAME lua
GIT_REPOSITORY https://github.com/lua/lua.git GIT_REPOSITORY https://github.com/lua/lua.git
VERSION 5-3-4 VERSION 5.3.5
DOWNLOAD_ONLY YES DOWNLOAD_ONLY YES
) )
if (lua_ADDED) if (lua_ADDED)
# lua has no CMake support, so we create our own target
FILE(GLOB lua_sources ${lua_SOURCE_DIR}/*.c) FILE(GLOB lua_sources ${lua_SOURCE_DIR}/*.c)
list(REMOVE_ITEM lua_sources "${lua_SOURCE_DIR}/lua.c" "${lua_SOURCE_DIR}/luac.c")
add_library(lua STATIC ${lua_sources}) add_library(lua STATIC ${lua_sources})
target_include_directories(lua target_include_directories(lua
@ -154,25 +499,90 @@ if (lua_ADDED)
endif() endif()
``` ```
## Local packages For a full example on using CPM to download and configure lua with sol2 see [here](examples/sol2).
CPM can be configured to use `find_package` to search for locally installed dependencies first. ### Full Examples
If `CPM_LOCAL_PACKAGES_ONLY` is set, CPM will error when dependency is not found locally.
## Advantages 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.
- **Small and reusable projects** CPM takes care of project dependencies, allowing developers to focus on creating small, well-tested frameworks. ## Source Archives from GitHub
- **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.
- **Recursive dependencies** Ensures that no dependency is added twice and is added in the minimum required version.
- **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.
- **Simple source distribution** CPM makes including projects with source files and dependencies easy, reducing the need for monolithic header files.
## Limitations Using a compressed source archive is usually much faster than a shallow
clone. Optionally, you can verify the integrity using
[SHA256](https://en.wikipedia.org/wiki/SHA-2) or similar. Setting the hash is useful to ensure a
specific source is imported, especially since tags, branches, and
archives can change.
- **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 an error. This can be resolved by updating the outermost dependency version. Let's look at adding [spdlog](https://github.com/gabime/spdlog) to a project:
- **No auto-update** To update a dependency, version must be adapted manually and there is no way for CPM to figure out the most recent version.
- **No pre-built binaries** Unless they are installed or included in the linked repository.
For projects with more complex needs and where an extra setup step doesn't matter, it is worth to check out fully featured C++ package managers such as [conan](https://conan.io) or [hunter](https://github.com/ruslo/hunter). ```cmake
CPMAddPackage(
NAME spdlog
URL https://github.com/gabime/spdlog/archive/refs/tags/v1.12.0.zip
URL_HASH SHA256=6174bf8885287422a6c6a0312eb8a30e8d22bcfcee7c48a6d02d1835d7769232
)
```
URL_HASH is optional, but it's a good idea for releases.
### Identifying the URL
Information for determining the URL is found
[here](https://docs.github.com/en/repositories/working-with-files/using-files/downloading-source-code-archives#source-code-archive-urls).
#### Release
Not every software package provides releases, but for those that do,
they can be found on the release page of the project. In a browser,
the URL of the specific release is determined in a browser is
determined by right clicking and selecting `Copy link address` (or
similar) for the desired release. This is the value you will use in
the URL section.
This is the URL for spdlog release 1.13.0 in zip format:
`https://github.com/gabime/spdlog/archive/refs/tags/v1.13.0.zip`
#### Branch
The URL for branches is non-obvious from a browser. But it's still fairly easy to figure it out. The format is as follows:
`https://github.com/<user>/<name>/archive/refs/heads/<branch-name>.<archive-type>`
Archive type can be one of `tar.gz` or `zip`.
The URL for branch `v2.x` of spdlog is:
`https://github.com/gabime/spdlog/archive/refs/heads/v2.x.tar.gz`
#### Tag
Tags are similar, but with this format:
`https://github.com/<user>/<name>/archive/refs/tags/<tag-name>.<archive-type>`
Tag `v1.8.5` of spdlog is this:
`https://github.com/gabime/spdlog/archive/refs/tags/v1.8.5.tar.gz`
Exactly like the release.
#### Commit
If a specific commit contains the code you need, it's defined as follows:
`https://github.com/<user>/<name>/archive/<commit-hash>.<archive-type>`
Example:
`https://github.com/gabime/spdlog/archive/c1569a3d293a6b511ecb9c18b2298826c9578d9f.tar.gz`
### Determining the Hash
The following snippet illustrates determining the SHA256 hash on a linux machine using `wget` and `sha256sum`:
```bash
wget https://github.com/gabime/spdlog/archive/refs/tags/v1.13.0.zip -O - | sha256sum
```

View File

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

File diff suppressed because it is too large Load Diff

24
cmake/get_cpm.cmake Normal file
View File

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

94
cmake/testing.cmake Normal file
View File

@ -0,0 +1,94 @@
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 defined")
endif()
endfunction()
function(ASSERT_NOT_DEFINED KEY)
if(DEFINED ${KEY})
message(FATAL_ERROR "assertion failed: '${KEY}' is defined (${${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()
function(ASSERT_CONTENTS_EQUAL file content)
if(EXISTS ${file})
file(READ ${file} file_content)
if(content STREQUAL file_content)
message(STATUS "test passed: '${file}' exists and contains '${content}'")
else()
message(FATAL_ERROR "assertion failed: file '${file}' does not contain expected content.")
endif()
else()
message(FATAL_ERROR "assertion failed: file '${file} does not exist")
endif()
endfunction()

View File

@ -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)

View 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);
}

View 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)

View 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;
}

View File

@ -1,30 +1,27 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR) cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(CPMExampleBenchmark)
# ---- Dependencies ---- # ---- Dependencies ----
include(../../cmake/CPM.cmake) include(../../cmake/CPM.cmake)
CPMAddPackage( CPMAddPackage("gh:cpm-cmake/testpack-fibonacci@2.0")
NAME fibonacci
GIT_REPOSITORY https://github.com/TheLartians/Fibonacci.git
VERSION 1.0
)
CPMAddPackage( CPMAddPackage(
NAME benchmark NAME benchmark
GITHUB_REPOSITORY google/benchmark GITHUB_REPOSITORY google/benchmark
VERSION 1.4.1 VERSION 1.7.1
OPTIONS OPTIONS "BENCHMARK_ENABLE_TESTING Off"
"BENCHMARK_ENABLE_TESTING Off"
) )
if(benchmark_ADDED) if(benchmark_ADDED)
# patch google benchmark target # enable c++11 to avoid compilation errors
set_target_properties(benchmark PROPERTIES CXX_STANDARD 17) set_target_properties(benchmark PROPERTIES CXX_STANDARD 11)
endif() endif()
# ---- Executable ---- # ---- Executable ----
add_executable(CPMExampleBenchmark "main.cpp") add_executable(CPMExampleBenchmark "main.cpp")
set_target_properties(CPMExampleBenchmark PROPERTIES CXX_STANDARD 17)
target_link_libraries(CPMExampleBenchmark fibonacci benchmark) target_link_libraries(CPMExampleBenchmark fibonacci benchmark)
target_compile_features(CPMExampleBenchmark PRIVATE cxx_std_17)

View File

@ -1,10 +1,9 @@
#include <benchmark/benchmark.h> #include <benchmark/benchmark.h>
#include <vector>
#include <algorithm>
#include <random>
#include <fibonacci.h> #include <fibonacci.h>
#include <algorithm>
#include <random>
#include <vector>
std::vector<unsigned> createTestNumbers() { std::vector<unsigned> createTestNumbers() {
std::vector<unsigned> v; std::vector<unsigned> v;
@ -15,14 +14,14 @@ std::vector<unsigned> createTestNumbers(){
return v; return v;
} }
void fibonnacci(benchmark::State& state) { void fibonacci(benchmark::State& state) {
auto numbers = createTestNumbers(); auto numbers = createTestNumbers();
for (auto _ : state) { for (auto _ : state) {
for (auto v: numbers) benchmark::DoNotOptimize(fibonnacci(v)); for (auto v : numbers) benchmark::DoNotOptimize(fibonacci(v));
} }
} }
BENCHMARK(fibonnacci); BENCHMARK(fibonacci);
void fastFibonacci(benchmark::State& state) { void fastFibonacci(benchmark::State& state) {
auto numbers = createTestNumbers(); auto numbers = createTestNumbers();

View File

@ -0,0 +1,24 @@
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.86.0 # Versions less than 1.85.0 may need patches for installation targets.
URL https://github.com/boostorg/boost/releases/download/boost-1.86.0/boost-1.86.0-cmake.tar.xz
URL_HASH SHA256=2c5ec5edcdff47ff55e27ed9560b0a0b94b07bd07ed9928b476150e16b0efc57
OPTIONS "BOOST_ENABLE_CMAKE ON" "BOOST_SKIP_INSTALL_RULES ON" # Set `OFF` for installation
"BUILD_SHARED_LIBS OFF" "BOOST_INCLUDE_LIBRARIES container\\\;asio" # Note the escapes!
)
# `Boost::headers` is also valid
target_link_libraries(CPMExampleBoost PRIVATE Boost::asio Boost::container)

34
examples/boost/main.cpp Normal file
View File

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

8
examples/run_all.py → examples/build_all.py Normal file → Executable file
View File

@ -1,5 +1,7 @@
#!/usr/bin/python3 #!/usr/bin/python3
import os
from pathlib import Path from pathlib import Path
from subprocess import PIPE, run from subprocess import PIPE, run
@ -9,6 +11,7 @@ examples = [
assert(len(examples) > 0) assert(len(examples) > 0)
def runCommand(command): def runCommand(command):
print('- %s' % command) print('- %s' % command)
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True) result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True)
@ -17,13 +20,14 @@ def runCommand(command):
exit(result.returncode) exit(result.returncode)
return result.stdout return result.stdout
print('') print('')
for example in examples: for example in examples:
print("running example %s" % example.name) print("running example %s" % example.name)
print("================" + ('=' * len(example.name))) print("================" + ('=' * len(example.name)))
project = Path(".") / 'build' / example.name project = Path(".") / 'build' / example.name
configure = runCommand('cmake -H%s -B%s -DCMAKE_BUILD_TYPE=RelWithDebInfo' % (example, project)) configure = runCommand('cmake -S%s -B%s' % (example, project))
print(' ' + '\n '.join([line for line in configure.split('\n') if 'CPM:' in line])) print(' ' + '\n '.join([line for line in configure.split('\n') if 'CPM:' in line]))
build = runCommand('cmake --build %s -j4' % (project)) 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(' ' + '\n '.join([line for line in build.split('\n') if 'Built target' in line]))
print('') print('')

View File

@ -1,39 +1,21 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR) cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
# ---- Options ---- project(CPMExampleCatch2)
option(ENABLE_TEST_COVERAGE "Enable test coverage" OFF)
# ---- Dependencies ---- # ---- Dependencies ----
include(../../cmake/CPM.cmake) include(../../cmake/CPM.cmake)
CPMAddPackage( CPMAddPackage("gh:cpm-cmake/testpack-fibonacci@2.0")
NAME fibonacci CPMAddPackage("gh:catchorg/Catch2@3.4.0")
GIT_REPOSITORY https://github.com/TheLartians/Fibonacci.git
VERSION 1.0
)
CPMAddPackage(
NAME Catch2
GITHUB_REPOSITORY catchorg/Catch2
VERSION 2.5.0
)
# ---- Create binary ---- # ---- Create binary ----
add_executable(CPMExampleCatch2 main.cpp) add_executable(CPMExampleCatch2 main.cpp)
target_link_libraries(CPMExampleCatch2 fibonacci Catch2) target_link_libraries(CPMExampleCatch2 fibonacci Catch2::Catch2WithMain)
set_target_properties(CPMExampleCatch2 PROPERTIES CXX_STANDARD 17 COMPILE_FLAGS "-Wall -pedantic -Wextra -Werror") target_compile_features(CPMExampleCatch2 PRIVATE cxx_std_17)
# ---- Enable testing ---- # ---- Enable testing ----
ENABLE_TESTING() enable_testing()
ADD_TEST(CPMExampleCatch2 CPMExampleCatch2) add_test(CPMExampleCatch2 CPMExampleCatch2)
# ---- Add code coverage ----
if (${ENABLE_TEST_COVERAGE})
set_target_properties(CPMExampleCatch2 PROPERTIES CXX_STANDARD 17 COMPILE_FLAGS "-O0 -g -fprofile-arcs -ftest-coverage --coverage")
target_link_options(CPMExampleCatch2 PUBLIC "--coverage")
endif()

View File

@ -1,20 +1,19 @@
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
#include <fibonacci.h> #include <fibonacci.h>
TEST_CASE("fibonnacci"){ #include <catch2/catch_test_macros.hpp>
REQUIRE(fibonnacci(0) == 0);
REQUIRE(fibonnacci(1) == 1); TEST_CASE("fibonacci") {
REQUIRE(fibonnacci(2) == 1); REQUIRE(fibonacci(0) == 0);
REQUIRE(fibonnacci(3) == 2); REQUIRE(fibonacci(1) == 1);
REQUIRE(fibonnacci(4) == 3); REQUIRE(fibonacci(2) == 1);
REQUIRE(fibonnacci(5) == 5); REQUIRE(fibonacci(3) == 2);
REQUIRE(fibonnacci(13) == 233); REQUIRE(fibonacci(4) == 3);
REQUIRE(fibonacci(5) == 5);
REQUIRE(fibonacci(13) == 233);
} }
TEST_CASE("fastFibonnacci"){ TEST_CASE("fastFibonacci") {
for (unsigned i = 0; i < 25; ++i) { for (unsigned i = 0; i < 25; ++i) {
REQUIRE(fibonnacci(i) == fastFibonacci(i)); REQUIRE(fibonacci(i) == fastFibonacci(i));
} }
} }

View 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
View 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;
}

View 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
View 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;
}

View File

@ -1,40 +1,21 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR) cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
# ---- Options ---- project(CPMExampleDoctest)
option(ENABLE_TEST_COVERAGE "Enable test coverage" OFF)
# ---- Dependencies ---- # ---- Dependencies ----
include(../../cmake/CPM.cmake) include(../../cmake/CPM.cmake)
CPMAddPackage( CPMAddPackage("gh:cpm-cmake/testpack-fibonacci@2.0")
NAME fibonacci CPMAddPackage("gh:onqtam/doctest@2.4.9")
GIT_REPOSITORY https://github.com/TheLartians/Fibonacci.git
VERSION 1.0
)
CPMAddPackage(
NAME doctest
GITHUB_REPOSITORY onqtam/doctest
VERSION 2.3.2
GIT_TAG 2.3.2
)
# ---- Create binary ---- # ---- Create binary ----
add_executable(CPMExampleDoctest main.cpp) add_executable(CPMExampleDoctest main.cpp)
target_link_libraries(CPMExampleDoctest fibonacci doctest) target_link_libraries(CPMExampleDoctest fibonacci doctest)
set_target_properties(CPMExampleDoctest PROPERTIES CXX_STANDARD 17 COMPILE_FLAGS "-Wall -pedantic -Wextra -Werror") target_compile_features(CPMExampleDoctest PRIVATE cxx_std_17)
# ---- Enable testing ---- # ---- Enable testing ----
ENABLE_TESTING() enable_testing()
ADD_TEST(CPMExampleDoctest CPMExampleDoctest) add_test(CPMExampleDoctest CPMExampleDoctest)
# ---- Add code coverage ----
if (${ENABLE_TEST_COVERAGE})
set_target_properties(CPMExampleDoctest PROPERTIES CXX_STANDARD 17 COMPILE_FLAGS "-O0 -g -fprofile-arcs -ftest-coverage --coverage")
target_link_options(CPMExampleDoctest PUBLIC "--coverage")
endif()

View File

@ -3,18 +3,18 @@
#include <doctest/doctest.h> #include <doctest/doctest.h>
#include <fibonacci.h> #include <fibonacci.h>
TEST_CASE("fibonnacci"){ TEST_CASE("fibonacci") {
CHECK(fibonnacci(0) == 0); CHECK(fibonacci(0) == 0);
CHECK(fibonnacci(1) == 1); CHECK(fibonacci(1) == 1);
CHECK(fibonnacci(2) == 1); CHECK(fibonacci(2) == 1);
CHECK(fibonnacci(3) == 2); CHECK(fibonacci(3) == 2);
CHECK(fibonnacci(4) == 3); CHECK(fibonacci(4) == 3);
CHECK(fibonnacci(5) == 5); CHECK(fibonacci(5) == 5);
CHECK(fibonnacci(13) == 233); CHECK(fibonacci(13) == 233);
} }
TEST_CASE("fastFibonnacci"){ TEST_CASE("fastfibonacci") {
for (unsigned i = 0; i < 25; ++i) { for (unsigned i = 0; i < 25; ++i) {
CHECK(fibonnacci(i) == fastFibonacci(i)); CHECK(fibonacci(i) == fastFibonacci(i));
} }
} }

View File

@ -0,0 +1,25 @@
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
View 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 &registry) {
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 &registry) {
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);
// ...
}

View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(CPMFmtExample)
# ---- 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
View File

@ -0,0 +1,6 @@
#include <fmt/format.h>
int main() {
fmt::print("Hello, {}!\n", "world");
return 0;
}

View 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.12.1
VERSION 1.12.1
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
View 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);
}

View File

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

View File

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

27
examples/highway/main.cpp Normal file
View File

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

View File

@ -1,24 +1,14 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR) cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(CPMJSONExample)
# ---- Dependencies ---- # ---- Dependencies ----
include(../../cmake/CPM.cmake) include(../../cmake/CPM.cmake)
CPMAddPackage("gh:nlohmann/json@3.10.5")
CPMAddPackage(
NAME nlohmann_json
VERSION 3.6.1
# not using the repo as it takes forever to clone
URL https://github.com/nlohmann/json/releases/download/v3.6.1/include.zip
URL_HASH SHA256=69cc88207ce91347ea530b227ff0776db82dcb8de6704e1a3d74f4841bc651cf
)
if(nlohmann_json_ADDED)
add_library(nlohmann_json INTERFACE)
target_include_directories(nlohmann_json INTERFACE ${nlohmann_json_SOURCE_DIR})
endif()
# ---- Executable ---- # ---- Executable ----
add_executable(CPMJSONExample "main.cpp") add_executable(CPMJSONExample main.cpp)
set_target_properties(CPMJSONExample PROPERTIES CXX_STANDARD 17) target_compile_features(CPMJSONExample PRIVATE cxx_std_17)
target_link_libraries(CPMJSONExample nlohmann_json) target_link_libraries(CPMJSONExample nlohmann_json::nlohmann_json)

View File

@ -1,23 +1,15 @@
#include <nlohmann/json.hpp>
#include <iostream>
#include <iomanip> #include <iomanip>
#include <iostream>
#include <nlohmann/json.hpp>
int main() { int main() {
nlohmann::json json = {{"pi", 3.141},
nlohmann::json json = {
{"pi", 3.141},
{"happy", true}, {"happy", true},
{"name", "Niels"}, {"name", "Niels"},
{"nothing", nullptr}, {"nothing", nullptr},
{"answer", { {"answer", {{"everything", 42}}},
{"everything", 42}
}},
{"list", {1, 0, 2}}, {"list", {1, 0, 2}},
{"object", { {"object", {{"currency", "USD"}, {"value", 42.99}}}};
{"currency", "USD"},
{"value", 42.99}
}}
};
std::cout << "declared JSON object: " << std::setw(2) << json << std::endl; std::cout << "declared JSON object: " << std::setw(2) << json << std::endl;

View 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)

View 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("Unrecognized command: %s\n", line);
}
free(line);
}
return 0;
}

View File

@ -1,28 +0,0 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
include(../../cmake/CPM.cmake)
# ---- Dependencies ----
CPMAddPackage(
NAME Glue
GIT_REPOSITORY https://github.com/TheLartians/Glue.git
VERSION 0.8.1
OPTIONS
"GLUE_ENABLE_LUA ON"
"GLUE_BUILD_LUA ON"
)
CPMAddPackage(
NAME LarsParser
GIT_REPOSITORY https://github.com/TheLartians/Parser.git
VERSION 1.9
OPTIONS
"LARS_PARSER_BUILD_GLUE_EXTENSION ON"
)
# ---- Create binary ----
add_executable(parser-lua main.cpp)
set_target_properties(parser-lua PROPERTIES CXX_STANDARD 17)
target_link_libraries(parser-lua LHC LarsParser Glue)

View File

@ -1,46 +0,0 @@
#include <lars/parser/extension.h>
#include <glue/lua.h>
#include <stdexcept>
#include <iostream>
int main() {
auto lua = glue::LuaState();
lua.openStandardLibs();
lua["parser"] = lars::glue::parser();
lua.run(R"(
wordParser = parser.Program.create()
wordParser:setRule("Whitespace", "[ \t]")
wordParser:setSeparatorRule("Whitespace")
wordParser:setRule("Word", "[a-zA-Z]+")
wordParser:setRuleWithCallback("Words", "Word*", function(e)
local N = e:size()
local res = {}
for i=0,N-1 do res[#res+1] = e:get(i):string() end
return res
end)
wordParser:setStartRule("Words")
)");
lua.run(R"(
while true do
print("please enter some words or 'quit' to exit");
local input = io.read();
if input == "quit" then os.exit() end
local result
ok, err = pcall(function() result = wordParser:run(input) end)
if ok then
print("you entered " .. #result .. " words!")
else
print("error: " .. tostring(err))
end
end
)");
return 0;
}

View File

@ -1,15 +0,0 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
# add dependencies
include(../../cmake/CPM.cmake)
CPMAddPackage(
NAME LarsParser
GIT_REPOSITORY https://github.com/TheLartians/Parser.git
VERSION 1.7
)
# add executable
add_executable(calculator main.cpp)
set_target_properties(calculator PROPERTIES CXX_STANDARD 17)
target_link_libraries(calculator LarsParser)

View File

@ -1,57 +0,0 @@
#include <iostream>
#include <unordered_map>
#include <cmath>
#include <lars/parser/generator.h>
int main() {
using namespace std;
using VariableMap = unordered_map<string, float>;
lars::ParserGenerator<float, VariableMap &> calculator;
auto &g = calculator;
g.setSeparator(g["Whitespace"] << "[\t ]");
g["Expression"] << "Set | Sum";
g["Set" ] << "Name '=' Sum" >> [](auto e, auto &v){ return v[e[0].string()] = e[1].evaluate(v); };
g["Sum" ] << "Add | Subtract | Product";
g["Product" ] << "Multiply | Divide | Exponent";
g["Exponent" ] << "Power | Atomic";
g["Atomic" ] << "Number | Brackets | Variable";
g["Brackets" ] << "'(' Sum ')'";
g["Add" ] << "Sum '+' Product" >> [](auto e, auto &v){ return e[0].evaluate(v) + e[1].evaluate(v); };
g["Subtract" ] << "Sum '-' Product" >> [](auto e, auto &v){ return e[0].evaluate(v) - e[1].evaluate(v); };
g["Multiply" ] << "Product '*' Exponent" >> [](auto e, auto &v){ return e[0].evaluate(v) * e[1].evaluate(v); };
g["Divide" ] << "Product '/' Exponent" >> [](auto e, auto &v){ return e[0].evaluate(v) / e[1].evaluate(v); };
g["Power" ] << "Atomic ('^' Exponent)" >> [](auto e, auto &v){ return pow(e[0].evaluate(v), e[1].evaluate(v)); };
g["Variable" ] << "Name" >> [](auto e, auto &v){ return v[e[0].string()]; };
g["Name" ] << "[a-zA-Z] [a-zA-Z0-9]*";
g["Number" ] << "'-'? [0-9]+ ('.' [0-9]+)?" >> [](auto e, auto &){ return stod(e.string()); };
g.setStart(g["Expression"]);
cout << "Enter an expression to be evaluated or 'quit' to exit.\n";
VariableMap variables;
while (true) {
string str;
cout << "> ";
getline(cin,str);
if(str == "q" || str == "quit"){ break; }
try {
auto result = calculator.run(str, variables);
cout << str << " = " << result << endl;
} catch (lars::SyntaxError &error) {
auto syntax = error.syntax;
cout << " ";
cout << string(syntax->begin, ' ');
cout << string(syntax->length(), '~');
cout << "^\n";
cout << " " << "Syntax error while parsing " << syntax->rule->name << endl;
}
}
return 0;
}

View 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.12.0")
# ---- Executable ----
add_executable(CPMRangev3Example main.cpp)
target_compile_features(CPMRangev3Example PRIVATE cxx_std_17)
target_link_libraries(CPMRangev3Example range-v3)

View 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]]

View File

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

View File

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

View File

@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR) cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(CPMSimpleMatchExample)
# ---- Dependencies ---- # ---- Dependencies ----
include(../../cmake/CPM.cmake) include(../../cmake/CPM.cmake)
@ -13,12 +15,11 @@ CPMAddPackage(
if(simple_match_ADDED) if(simple_match_ADDED)
add_library(simple_match INTERFACE IMPORTED) add_library(simple_match INTERFACE IMPORTED)
target_include_directories(simple_match INTERFACE "${simple_match_SOURCE_DIR}/include") target_include_directories(simple_match SYSTEM INTERFACE "${simple_match_SOURCE_DIR}/include")
endif() endif()
# ---- Executable ---- # ---- Executable ----
add_executable(CPMSimpleMatchExample "main.cpp") add_executable(CPMSimpleMatchExample main.cpp)
set_target_properties(CPMSimpleMatchExample PROPERTIES CXX_STANDARD 17) target_compile_features(CPMSimpleMatchExample PRIVATE cxx_std_17)
target_link_libraries(CPMSimpleMatchExample simple_match) target_link_libraries(CPMSimpleMatchExample simple_match)

View File

@ -1,6 +1,5 @@
#include <simple_match/simple_match.hpp>
#include <iostream> #include <iostream>
#include <simple_match/simple_match.hpp>
int main(int argc, char** argv) { int main(int argc, char** argv) {
using namespace simple_match; using namespace simple_match;
@ -12,7 +11,9 @@ int main(int argc, char ** argv){
while (true) { while (true) {
std::cout << "> "; std::cout << "> ";
std::getline(std::cin, input); std::getline(std::cin, input);
if (input == "quit") { break; } if (input == "quit") {
break;
}
int x; int x;
try { try {
x = std::stoi(input); x = std::stoi(input);
@ -21,13 +22,12 @@ int main(int argc, char ** argv){
continue; continue;
} }
match(x, match(
1, []() {std::cout << "The answer is one\n"; }, x, 1, []() { std::cout << "The answer is one\n"; }, 2,
2, []() {std::cout << "The answer is two\n"; }, []() { std::cout << "The answer is two\n"; }, _x < 10,
_x < 10, [](auto&& a) {std::cout << "The answer " << a << " is less than 10\n"; }, [](auto&& a) { std::cout << "The answer " << a << " is less than 10\n"; }, 10 < _x < 20,
10 < _x < 20, [](auto&& a) {std::cout << "The answer " << a << " is between 10 and 20 exclusive\n"; }, [](auto&& a) { std::cout << "The answer " << a << " is between 10 and 20 exclusive\n"; }, _,
_, []() {std::cout << "Did not match\n"; } []() { std::cout << "Did not match\n"; });
);
} }
return 0; return 0;

View File

@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(CPMSol2Example)
# ---- Dependencies ----
include(../../cmake/CPM.cmake)
CPMAddPackage(
NAME lua
GITHUB_REPOSITORY lua/lua
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
GITHUB_REPOSITORY ThePhD/sol2
VERSION 3.3.0
# fix for clang 18.1.0, see https://github.com/ThePhD/sol2/issues/1581#issuecomment-2103463524
PATCHES fix_for_clang.patch
)
# ---- Executable ----
add_executable(CPMSol2Example main.cpp)
target_compile_features(CPMSol2Example PRIVATE cxx_std_17)
target_link_libraries(CPMSol2Example sol2 lua)

View File

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

17
examples/sol2/main.cpp Normal file
View 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);
}

View File

@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(CPMSpdlogExample)
# ---- Dependencies ----
include(../../cmake/CPM.cmake)
CPMAddPackage("gh:gabime/spdlog@1.8.2")
# spdlog uses fmt and bundles that dependency. If you want to use fmt in your project as well, you
# can let spdlog reuse fmt from CPM.cmake like this:
#
# cmake-format: off
#
# CPMAddPackage("gh:fmtlib/fmt#7.1.3")
# CPMAddPackage(
# GITHUB_REPOSITORY gabime/spdlog
# VERSION 1.8.2
# OPTIONS "SPDLOG_FMT_EXTERNAL 1"
# )
#
# cmake-format: on
# ---- Executable ----
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
View File

@ -0,0 +1,6 @@
#include <spdlog/spdlog.h>
int main() {
spdlog::info("Hello, world!");
return 0;
}

View File

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

12
examples/xxHash/main.cpp Normal file
View File

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

View File

@ -1,25 +1,15 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR) cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(CPMYamlExample)
# ---- Dependencies ---- # ---- Dependencies ----
include(../../cmake/CPM.cmake) include(../../cmake/CPM.cmake)
CPMAddPackage( CPMAddPackage("gh:jbeder/yaml-cpp#yaml-cpp-0.6.3@0.6.3")
NAME yaml-cpp
GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
# 0.6.2 uses depricated CMake syntax
VERSION 0.6.3
# 0.6.3 is not released yet, so use the most recent commit
GIT_TAG 012269756149ae99745b6dafefd415843d7420bb
OPTIONS
"YAML_CPP_BUILD_TESTS Off"
"YAML_CPP_BUILD_CONTRIB Off"
"YAML_CPP_BUILD_TOOLS Off"
)
# ---- Executable ---- # ---- Executable ----
add_executable(CPMYamlExample "main.cpp") add_executable(CPMYamlExample main.cpp)
set_target_properties(CPMYamlExample PROPERTIES CXX_STANDARD 17) target_compile_features(CPMYamlExample PRIVATE cxx_std_17)
target_link_libraries(CPMYamlExample yaml-cpp) target_link_libraries(CPMYamlExample yaml-cpp)

View File

@ -1,4 +1,5 @@
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
#include <iostream> #include <iostream>
int main(int argc, char** argv) { int main(int argc, char** argv) {

BIN
logo/CPM.afdesign Normal file

Binary file not shown.

BIN
logo/CPM.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

18
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,18 @@
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)
add_subdirectory(style)

2
test/integration/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Use this to have a local integration test which is for personal experiments
test_local.rb

View 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 execution.
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 various 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)

View 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
```

206
test/integration/lib.rb Normal file
View File

@ -0,0 +1,206 @@
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 definition (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_failure(res)
msg = build_message(nil, "command status was expected to be a failure, but succeeded")
assert_block(msg) { !res.status.success? }
end
def assert_same_path(a, b)
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(name: nil, from_template: nil)
test_name = local_name
test_name = test_name[5..] if test_name.start_with?('test_')
base = File.join(cur_test_dir, test_name)
base += "-#{name}" if name
src_dir = base + '-src'
FileUtils.mkdir_p src_dir
if from_template
from_template = File.join(TestLib::TEMPLATES_DIR, from_template)
raise "#{from_template} is not a directory" if !File.directory?(from_template)
FileUtils.copy_entry from_template, src_dir
end
Project.new src_dir, base + '-bin'
end
end

View File

@ -0,0 +1,66 @@
# Integration Test Framework Reference
## `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(name: nil, from_template: nil)` - create a project from a test method. Will create the project's source and binary directories as subdirectories of `cur_test_dir`.
* Optionally provide a name which will be concatenated to the project directory. This allows creating multiple projects in a test
* Optionally work with a template, in which case it will copy the contents of the template directory (one from `templates`) in the project's source directory.

View File

@ -0,0 +1,4 @@
require_relative './lib'
exit Test::Unit::AutoRunner::run(true, __dir__)

View 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)

View File

@ -0,0 +1,6 @@
#include <stdio.h>
int main() {
puts("Hello");
return 0;
}

View 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)

View 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;
}

View 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)

View File

@ -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;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,58 @@
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 from_template: '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')
if @cache.entries['CMAKE_FIND_PACKAGE_REDIRECTS_DIR'].nil?
assert_same_path File.join(prj.bin_dir, 'CPM_modules'), check_and_get('CPM_MODULE_PATH')
end
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 from_template: '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

View File

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

View File

@ -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 from_template: '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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,36 @@
require_relative './lib'
class RemoveSourceDir < IntegrationTest
def test_remove_source_dir
prj = make_project from_template: '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"
SOURCE_DIR testpack-adder
)
PACK
# configure and build
assert_success prj.configure
assert_success prj.build
# source_dir is populated
assert_true File.exist?(File.join(prj.bin_dir, 'testpack-adder'))
# source_dir is deleted by user
FileUtils.remove_dir(File.join(prj.bin_dir, 'testpack-adder'), true)
assert_false File.exist?(File.join(prj.bin_dir, 'testpack-adder'))
# configure and build with missing source_dir to fetch new content
assert_success prj.configure
assert_success prj.build
# source_dir is populated
assert_true File.exist?(File.join(prj.bin_dir, 'testpack-adder'))
end
end

View File

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

View File

@ -0,0 +1,91 @@
require_relative './lib'
class Simple < IntegrationTest
ADDER_PACKAGE_NAME = 'testpack-adder'
def test_update_single_package
prj = make_project from_template: '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 artifacts like .pdb or .dsym
!File.directory?(_1) && File.stat(_1).executable?
}.map {
# remove .exe extension if any (there will be one on Windows)
File.basename(_1, '.exe')
}.sort
# 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

View File

@ -0,0 +1,91 @@
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 from_template: '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 from_template: '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}"
# The hash has been shortened by cpm_get_shortest_hash. The following
# should hold:
# - The short hash should be a prefix of the input hash
# - There should be a file ".../${short_hash}.hash" which matches the full hash
short_hash = File.basename(package.src_dir)
assert dir_sha1.start_with?(short_hash), "short_hash should be a prefix of dir_sha1"
# Check that the full hash is stored in the .hash file
hash_file = "#{package.src_dir}.hash"
assert File.exist?(hash_file), "Hash file #{hash_file} should exist"
assert_equal dir_sha1, File.read(hash_file), "Hash file should contain the full original hash"
end
end

View File

@ -0,0 +1,57 @@
require_relative './lib'
class SystemWarnings < IntegrationTest
def setup
# system is only supported for CMake >= 3.25
@system_supported = (!ENV['CMAKE_VERSION']) || (Gem::Version.new(ENV['CMAKE_VERSION']) >= Gem::Version.new('3.25'))
end
def test_dependency_added_using_system
for use_system in [true, false] do
prj = make_project name: use_system ? "system" : "no_system", from_template: 'using-adder'
prj.create_lists_from_default_template package: <<~PACK
# this commit has a warning in a public header
CPMAddPackage(
NAME Adder
GITHUB_REPOSITORY cpm-cmake/testpack-adder
GIT_TAG v1.0.1-warnings
SYSTEM #{use_system ? "YES" : "NO"}
)
# all packages using `adder` will error on warnings
target_compile_options(adder INTERFACE
$<$<CXX_COMPILER_ID:MSVC>:/Wall /WX>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Werror>
)
PACK
assert_success prj.configure
if use_system and @system_supported
assert_success prj.build
else
assert_failure prj.build
end
end
end
def test_dependency_added_implicitly_using_system
prj = make_project from_template: 'using-adder'
prj.create_lists_from_default_template package: <<~PACK
# this commit has a warning in a public header
CPMAddPackage("gh:cpm-cmake/testpack-adder@1.0.1-warnings")
# all packages using `adder` will error on warnings
target_compile_options(adder INTERFACE
$<$<CXX_COMPILER_ID:MSVC>:/Wall /WX>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Werror>
)
PACK
assert_success prj.configure
if @system_supported
assert_success prj.build
else
assert_failure prj.build
end
end
end

35
test/integration/tips.md Normal file
View 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.

View 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 associated 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.

Some files were not shown because too many files have changed in this diff Show More