Skip to content

Commit

Permalink
Add CPM_SOURCE_CACHE environmental variable support and keep existing…
Browse files Browse the repository at this point in the history
… sources (#83)

* read CPM_SOURCE_CACHE from environment

* update readme

* cleanup

* add cache tests
  • Loading branch information
TheLartians authored Oct 10, 2019
1 parent b1855e9 commit 4064a45
Show file tree
Hide file tree
Showing 28 changed files with 300 additions and 58 deletions.
15 changes: 3 additions & 12 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
build
.vscode
.DS_Store
/build*
/.vscode
*.DS_Store
18 changes: 8 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

language: cpp
sudo: require
dist: xenial
Expand All @@ -17,19 +16,19 @@ matrix:
addons: &gcc8
apt:
sources: *all_sources
packages:
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
apt:
sources: *all_sources
packages:
- g++-8
- clang-6.0
env:
- MATRIX_EVAL="export CC=clang-6.0; export CXX=clang++-6.0;"

Expand All @@ -38,7 +37,7 @@ before_install:
- 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
- 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
Expand All @@ -48,5 +47,4 @@ script:
- cmake -Htest -Bbuild/test
- CTEST_OUTPUT_ON_FAILURE=1 cmake --build build/test --target test
# examples
- python3 examples/run_all.py

- python3 examples/build_all.py
38 changes: 19 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,24 +50,22 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(MyProject)
# add executable
add_executable(myProject myProject.cpp)
set_target_properties(myProject PROPERTIES CXX_STANDARD 17)
add_executable(tests tests.cpp)
# add dependencies
include(cmake/CPM.cmake)
CPMAddPackage(
NAME LarsParser
VERSION 1.8
GIT_REPOSITORY https://github.com/TheLartians/Parser.git
OPTIONS
"LARS_PARSER_BUILD_GLUE_EXTENSION ON"
NAME Catch2
GITHUB_REPOSITORY catchorg/Catch2
VERSION 2.5.0
)
target_link_libraries(myProject LarsParser)
# link dependencies
target_link_libraries(tests Catch2)
```

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/TheLartians/CPM/tree/master/examples) for more many examples with source code or the [wiki](https://github.com/TheLartians/CPM/wiki/More-Snippets) for many example snippets.

## Adding CPM

Expand All @@ -78,36 +76,38 @@ mkdir -p cmake
wget -O cmake/CPM.cmake https://raw.githubusercontent.com/TheLartians/CPM/master/cmake/CPM.cmake
```

You can also use CMake to download CPM for you. See the [wiki](https://github.com/TheLartians/CPM/wiki/Adding-CPM) for more details.
You can even use CMake to download CPM for you. See the [wiki](https://github.com/TheLartians/CPM/wiki/Adding-CPM) for more details.

## Updating CPM

To update CPM to the newest version, simply update the script in the project's cmake directory, for example by running the command above. Dependencies using CPM will automatically use the updated script of the outermost project.
To update CPM to the newest version, update the script in the project's root directory, for example by running the command above. Dependencies using CPM will automatically use the updated script of the outermost project.

## Advantages

- **Small and reusable projects** CPM takes care of all project dependencies, allowing developers to focus on creating small, well-tested frameworks.
- **Cross-Platform** CPM adds projects via `add_subdirectory`, which is compatible with all cmake toolchains and generators.
- **Cross-Platform** 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.
- **Plug-and-play** No need to install anything. Just add the script to your project and you're good to go.
- **No packaging 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.
- **Simple source distribution** CPM makes including projects with source files and dependencies easy, reducing the need for monolithic header files or git submodules.

## Limitations

- **No pre-built binaries** For every new project, all dependencies must be downloaded and built from scratch. A possible workaround is to use CPM to fetch a pre-built binary or to enable local packages (see [below](#local-packages)).
- **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 [sccahe](https://github.com/mozilla/sccache) 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 best practices on preparing your projects for CPM, see the [wiki](https://github.com/TheLartians/CPM/wiki/Preparing-projects-for-CPM).
- **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.

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), [vcpkg](https://github.com/microsoft/vcpkg) or [hunter](https://github.com/ruslo/hunter).
Support for package managers is also [planned](https://github.com/TheLartians/CPM/issues/51) for a future version of CPM.
Support for these package managers is also [planned](https://github.com/TheLartians/CPM/issues/51) for a future version of CPM.

## Options

### CPM_SOURCE_ROOT
### CPM_SOURCE_CACHE

To avoid re-downloading dependencies, configure the project with the cmake option `-DCPM_SOURCE_ROOT=<path to an external download directory>`.
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>`.
It can also be defined system-wide as an environmental variable, by adding `export CPM_SOURCE_CACHE=$HOME/.cache/CPM` to your `.bashrc` or `.bash_profile`.
Note that passing the variable as a configure option to CMake will always override the value set by the environmental variable.

### CPM_USE_LOCAL_PACKAGES

Expand Down Expand Up @@ -158,7 +158,7 @@ CPMAddPackage(
CPMAddPackage(
NAME yaml-cpp
GITHUB_REPOSITORY jbeder/yaml-cpp
# 0.6.2 uses depricated CMake syntax
# 0.6.2 uses deprecated CMake syntax
VERSION 0.6.3
# 0.6.3 is not released yet, so use a recent commit
GIT_TAG 012269756149ae99745b6dafefd415843d7420bb
Expand Down Expand Up @@ -247,4 +247,4 @@ For a full example on using CPM to download and configure lua with sol2 see [her

### Full Examples

See the [examples directory](https://github.com/TheLartians/CPM/tree/master/examples) for full examples with source code.
See the [examples directory](https://github.com/TheLartians/CPM/tree/master/examples) for full examples with source code and check out the [wiki](https://github.com/TheLartians/CPM/wiki/More-Snippets) for many more example snippets.
55 changes: 42 additions & 13 deletions cmake/CPM.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

set(CURRENT_CPM_VERSION 0.13)
set(CURRENT_CPM_VERSION 0.14)

if(CPM_DIRECTORY)
if(NOT ${CPM_DIRECTORY} MATCHES ${CMAKE_CURRENT_LIST_DIR})
Expand All @@ -46,7 +46,14 @@ set(CPM_DRY_RUN OFF CACHE INTERNAL "Don't download or configure dependencies (fo

option(CPM_USE_LOCAL_PACKAGES "Use locally installed packages (find_package)" OFF)
option(CPM_LOCAL_PACKAGES_ONLY "Use only locally installed packages" OFF)
set(CPM_SOURCE_ROOT OFF CACHE PATH "Directory to downlaod CPM dependencies")

if(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_SOURCE_CACHE_DEFAULT $ENV{CPM_SOURCE_CACHE})
else()
set(CPM_SOURCE_CACHE_DEFAULT OFF)
endif()

set(CPM_SOURCE_CACHE ${CPM_SOURCE_CACHE_DEFAULT} CACHE PATH "Directory to downlaod CPM dependencies")

include(FetchContent)
include(CMakeParseArguments)
Expand All @@ -67,6 +74,7 @@ function(CPMAddPackage)
GITHUB_REPOSITORY
GITLAB_REPOSITORY
SOURCE_DIR
DOWNLOAD_COMMAND
)

set(multiValueArgs
Expand Down Expand Up @@ -105,14 +113,6 @@ function(CPMAddPackage)
set(CPM_ARGS_GIT_TAG v${CPM_ARGS_VERSION})
endif()

set(FETCH_CONTENT_DECLARE_EXTRA_OPTS "")

if (CPM_SOURCE_ROOT AND NOT DEFINED CPM_ARGS_SOURCE_DIR)
string(TOLOWER ${CPM_ARGS_NAME} lname)
string(REPLACE "-" "_" source_path_name ${lname})
list(APPEND FETCH_CONTENT_DECLARE_EXTRA_OPTS SOURCE_DIR ${CPM_SOURCE_ROOT}/${source_path_name})
endif()

list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_TAG ${CPM_ARGS_GIT_TAG})

if(CPM_ARGS_DOWNLOAD_ONLY)
Expand Down Expand Up @@ -159,16 +159,45 @@ function(CPMAddPackage)
endforeach()
endif()

CPM_DECLARE_PACKAGE(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION} ${CPM_ARGS_GIT_TAG} "${CPM_ARGS_UNPARSED_ARGUMENTS}" ${FETCH_CONTENT_DECLARE_EXTRA_OPTS})
set(FETCH_CONTENT_DECLARE_EXTRA_OPTS "")

if (DEFINED CPM_ARGS_GIT_TAG)
set(PACKAGE_INFO "${CPM_ARGS_GIT_TAG}")
else()
set(PACKAGE_INFO "${CPM_ARGS_VERSION}")
endif()

if (DEFINED CPM_ARGS_DOWNLOAD_COMMAND)
set(FETCH_CONTENT_DECLARE_EXTRA_OPTS DOWNLOAD_COMMAND ${CPM_ARGS_DOWNLOAD_COMMAND})
else()
if (CPM_SOURCE_CACHE AND NOT DEFINED CPM_ARGS_SOURCE_DIR)
string(TOLOWER ${CPM_ARGS_NAME} lower_case_name)
set(origin_parameters ${CPM_ARGS_UNPARSED_ARGUMENTS})
list(SORT origin_parameters)
string(SHA1 origin_hash "${origin_parameters}")
set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash})
list(APPEND FETCH_CONTENT_DECLARE_EXTRA_OPTS SOURCE_DIR ${download_directory})
if (EXISTS ${download_directory})
list(APPEND FETCH_CONTENT_DECLARE_EXTRA_OPTS DOWNLOAD_COMMAND ":")
set(PACKAGE_INFO "${download_directory}")
else()
# remove timestamps so CMake will re-download the dependency
file(REMOVE_RECURSE ${CMAKE_BINARY_DIR}/_deps/${lower_case_name}-subbuild)
set(PACKAGE_INFO "${PACKAGE_INFO} -> ${download_directory}")
endif()
endif()
endif()

CPM_DECLARE_PACKAGE(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION} ${PACKAGE_INFO} "${CPM_ARGS_UNPARSED_ARGUMENTS}" ${FETCH_CONTENT_DECLARE_EXTRA_OPTS})
CPM_FETCH_PACKAGE(${CPM_ARGS_NAME} ${DOWNLOAD_ONLY})
CPMGetProperties(${CPM_ARGS_NAME})
SET(${CPM_ARGS_NAME}_SOURCE_DIR "${${CPM_ARGS_NAME}_SOURCE_DIR}" PARENT_SCOPE)
SET(${CPM_ARGS_NAME}_BINARY_DIR "${${CPM_ARGS_NAME}_BINARY_DIR}" PARENT_SCOPE)
SET(${CPM_ARGS_NAME}_ADDED YES PARENT_SCOPE)
endfunction()

function (CPM_DECLARE_PACKAGE PACKAGE VERSION GIT_TAG)
message(STATUS "${CPM_INDENT} adding package ${PACKAGE}@${VERSION} (${GIT_TAG})")
function (CPM_DECLARE_PACKAGE PACKAGE VERSION INFO)
message(STATUS "${CPM_INDENT} adding package ${PACKAGE}@${VERSION} (${INFO})")

if (${CPM_DRY_RUN})
message(STATUS "${CPM_INDENT} package not declared (dry run)")
Expand Down
14 changes: 13 additions & 1 deletion cmake/testing.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,19 @@ function(ASSERT_EQUAL)
message(FATAL_ERROR "assertion failed: invalid argument count: ${ARGC}")
endif()

if (NOT ${ARGV0} EQUAL ${ARGV1})
if (NOT ${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(ASSERTION_FAILED)
message(FATAL_ERROR "assertion failed: ${ARGN}")
endfunction()
2 changes: 2 additions & 0 deletions examples/benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project(CPMExampleBenchmark)

# ---- Dependencies ----

include(../../cmake/CPM.cmake)
Expand Down
2 changes: 2 additions & 0 deletions examples/boost/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project(CPMExampleBoost)

# ---- Create binary ----

add_executable(CPMExampleBoost main.cpp)
Expand Down
2 changes: 1 addition & 1 deletion examples/run_all.py → examples/build_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def runCommand(command):
print("running example %s" % example.name)
print("================" + ('=' * len(example.name)))
project = Path(".") / 'build' / example.name
configure = runCommand('cmake -H%s -B%s -DCMAKE_BUILD_TYPE=RelWithDebInfo' % (example, project))
configure = runCommand('cmake -H%s -B%s' % (example, project))
print(' ' + '\n '.join([line for line in configure.split('\n') if 'CPM:' in line]))
build = runCommand('cmake --build %s -j4' % (project))
print(' ' + '\n '.join([line for line in build.split('\n') if 'Built target' in line]))
Expand Down
2 changes: 2 additions & 0 deletions examples/catch2/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project(CPMExampleCatch2)

# ---- Options ----

option(ENABLE_TEST_COVERAGE "Enable test coverage" OFF)
Expand Down
2 changes: 2 additions & 0 deletions examples/cxxopts/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project(CPMExampleCXXOpts)

# ---- Options ----

option(ENABLE_TEST_COVERAGE "Enable test coverage" OFF)
Expand Down
2 changes: 2 additions & 0 deletions examples/doctest/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project(CPMExampleDoctest)

# ---- Options ----

option(ENABLE_TEST_COVERAGE "Enable test coverage" OFF)
Expand Down
2 changes: 2 additions & 0 deletions examples/entt/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project(CPMEnTTExample)

# ---- Dependencies ----

include(../../cmake/CPM.cmake)
Expand Down
2 changes: 2 additions & 0 deletions examples/json/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project(CPMJSONExample)

# ---- Dependencies ----

include(../../cmake/CPM.cmake)
Expand Down
2 changes: 2 additions & 0 deletions examples/linenoise/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project(CPMlinenoiseExample)

# ---- Dependencies ----

include(../../cmake/CPM.cmake)
Expand Down
2 changes: 2 additions & 0 deletions examples/parser-lua/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(CPMParserLuaExample)

include(../../cmake/CPM.cmake)

# ---- Dependencies ----
Expand Down
2 changes: 2 additions & 0 deletions examples/parser/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(CPMParserExample)

# add dependencies
include(../../cmake/CPM.cmake)

Expand Down
2 changes: 2 additions & 0 deletions examples/range-v3/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project(CPMRangev3Example)

# ---- Dependencies ----

include(../../cmake/CPM.cmake)
Expand Down
2 changes: 2 additions & 0 deletions examples/simple_match/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project(CPMSimpleMatchExample)

# ---- Dependencies ----

include(../../cmake/CPM.cmake)
Expand Down
2 changes: 2 additions & 0 deletions examples/sol2/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project(CPMSol2Example)

# ---- Dependencies ----

include(../../cmake/CPM.cmake)
Expand Down
Loading

0 comments on commit 4064a45

Please sign in to comment.