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
This commit is contained in:
Lars Melchior
2019-10-24 15:42:25 +02:00
committed by GitHub
parent 0a8a65df32
commit 47bfb554ab
20 changed files with 199 additions and 303 deletions

View File

@@ -46,5 +46,5 @@ script:
# unit tests
- cmake -Htest -Bbuild/test
- CTEST_OUTPUT_ON_FAILURE=1 cmake --build build/test --target test
# examples
# build examples
- python3 examples/build_all.py

View File

@@ -7,7 +7,7 @@
# Setup-free CMake dependency management
CPM.cmake is a CMake script that adds dependency management capabilities to CMake.
It's built as a wrapper around CMake's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) module that adds version control, caching and a simple API.
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 and a simple API.
## Manage everything
@@ -17,30 +17,34 @@ For everything else, the targets can be created manually after the dependency ha
## Usage
After `CPM.cmake` has been [added](#adding-cpm) to your project, the function `CPMAddPackage` can be used to fetch and configure a dependency.
After `CPM.cmake` has been [added](#adding-cpm) to your project, the function `CPMAddPackage` or `CPMFindPackage` 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.
`CPMFindPackage` and `CPMAddPackage` take the following named parameters.
```cmake
CPMAddPackage(
NAME # The unique name of the dependency (should be the main target's name)
NAME # The unique name of the dependency (should be the exported target's name)
VERSION # The minimum version of the dependency (optional, defaults to 0)
OPTIONS # Configuration options passed to the dependency (optional)
DOWNLOAD_ONLY # If set, the project is downloaded, but not configured (optional)
[...] # Origin paramters forwarded to FetchContent_Declare, see below
[...] # 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.
`GIT_TAG` can also be set to a specific commit or a branch name such as `master` to always download the most recent version.
The optional argument `FIND_PACKAGE_ARGUMENTS` can be specified to a string of parameters that will be passed to `find_package` if enabled (see below).
After calling `CPMAddPackage`, the following variables are defined in the local scope, where `<dependency>` is the name of the dependency.
After calling `CPMAddPackage` or `CPMFindPackage`, 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`.
The difference between `CPMFindPackage` and `CPMAddPackage` is that `CPMFindPackage` will try to find a local dependency via CMake's `find_package` and fallback to `CPMAddPackage` if the dependency is not found.
This behaviour can be also modified globally via [CPM options](#options).
## Full CMakeLists Example
```cmake
@@ -99,8 +103,9 @@ Dependencies using CPM will automatically use the updated script of the outermos
- **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/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 a warning. This can be resolved by adding a new version of the dependency in the outermost project.
For projects with more complex needs and where an extra setup step doesn't matter, it may be worth to check out a fully featured C++ package manager such as [conan](https://conan.io), [vcpkg](https://github.com/microsoft/vcpkg) or [hunter](https://github.com/ruslo/hunter).
Support for these package managers is also [planned](https://github.com/TheLartians/CPM/issues/51) for a future version of CPM.
For projects with more complex needs and where an extra setup step doesn't matter, it may be worth to check out an external C++ package manager such as [vcpkg](https://github.com/microsoft/vcpkg), [conan](https://conan.io) or [hunter](https://github.com/ruslo/hunter).
Dependencies added with `CPMFindPackages` should work with external package managers.
This can also be enabled for all CPM dependencies by enabling [`CPM_USE_LOCAL_PACKAGES`](#cpmuselocalpackages).
## Options
@@ -116,10 +121,17 @@ export CPM_SOURCE_CACHE=$HOME/.cache/CPM
Note that passing the variable as a configure option to CMake will always override the value set by the environmental variable.
### 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.
### 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.
## Snippets

View File

@@ -28,25 +28,29 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
set(CURRENT_CPM_VERSION 0.14)
set(CURRENT_CPM_VERSION 0.15)
if(CPM_DIRECTORY)
if(NOT ${CPM_DIRECTORY} MATCHES ${CMAKE_CURRENT_LIST_DIR})
if (${CPM_VERSION} VERSION_LESS ${CURRENT_CPM_VERSION})
CPM_HANDLE_OLD_VERSION(${CURRENT_CPM_VERSION})
message(AUTHOR_WARNING "${CPM_INDENT} \
A dependency is using a more recent CPM (${NEW_CPM_VERSION}) than the current project (${CPM_VERSION}). \
It is recommended to upgrade CPM to the most recent version. \
See https://github.com/TheLartians/CPM for more information."
)
endif()
return()
endif()
endif()
option(CPM_USE_LOCAL_PACKAGES "Always try to use `find_package` to get dependencies" $ENV{CPM_USE_LOCAL_PACKAGES})
option(CPM_LOCAL_PACKAGES_ONLY "Only use `find_package` to get dependencies" $ENV{CPM_LOCAL_PACKAGES_ONLY})
option(CPM_DOWNLOAD_ALL "Always download dependencies from source" $ENV{CPM_DOWNLOAD_ALL})
set(CPM_VERSION ${CURRENT_CPM_VERSION} CACHE INTERNAL "")
set(CPM_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} CACHE INTERNAL "")
set(CPM_PACKAGES "" CACHE INTERNAL "")
set(CPM_DRY_RUN OFF CACHE INTERNAL "Don't download or configure dependencies (for testing)")
option(CPM_USE_LOCAL_PACKAGES "Use locally installed packages (find_package)" OFF)
option(CPM_LOCAL_PACKAGES_ONLY "Use only locally installed packages" OFF)
if(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_SOURCE_CACHE_DEFAULT $ENV{CPM_SOURCE_CACHE})
else()
@@ -63,7 +67,44 @@ if(NOT CPM_INDENT)
set(CPM_INDENT "CPM:")
endif()
# The main workhorse of CPM
function(cpm_find_package NAME VERSION)
string(REPLACE " " ";" EXTRA_ARGS "${ARGN}")
find_package(${NAME} ${VERSION} ${EXTRA_ARGS})
if(${CPM_ARGS_NAME}_FOUND)
message(STATUS "${CPM_INDENT} using local package ${CPM_ARGS_NAME}@${${CPM_ARGS_NAME}_VERSION}")
CPMRegisterPackage(${CPM_ARGS_NAME} "${${CPM_ARGS_NAME}_VERSION}")
set(CPM_PACKAGE_FOUND YES PARENT_SCOPE)
else()
set(CPM_PACKAGE_FOUND NO PARENT_SCOPE)
endif()
endfunction()
# Find a package locally or fallback to CPMAddPackage
function(CPMFindPackage)
set(oneValueArgs
NAME
VERSION
FIND_PACKAGE_ARGUMENTS
)
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "" ${ARGN})
if (CPM_DOWNLOAD_ALL)
CPMAddPackage(${ARGN})
cpm_export_variables()
return()
endif()
cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS})
if(NOT CPM_PACKAGE_FOUND)
CPMAddPackage(${ARGN})
cpm_export_variables()
endif()
endfunction()
# Download and add a package from source
function(CPMAddPackage)
set(oneValueArgs
@@ -75,6 +116,7 @@ function(CPMAddPackage)
GITLAB_REPOSITORY
SOURCE_DIR
DOWNLOAD_COMMAND
FIND_PACKAGE_ARGUMENTS
)
set(multiValueArgs
@@ -83,26 +125,21 @@ function(CPMAddPackage)
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(${CPM_USE_LOCAL_PACKAGES} OR ${CPM_LOCAL_PACKAGES_ONLY})
find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION} QUIET)
if(CPM_USE_LOCAL_PACKAGES OR CPM_LOCAL_PACKAGES_ONLY)
cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS})
if(${CPM_PACKAGE_FOUND})
message(STATUS "CPM: adding local package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION}")
set_target_properties(${CPM_ARGS_NAME}
PROPERTIES
IMPORTED_GLOBAL True
)
if(CPM_PACKAGE_FOUND)
return()
endif()
if(${CPM_LOCAL_PACKAGES_ONLY})
if(CPM_LOCAL_PACKAGES_ONLY)
message(SEND_ERROR "CPM: ${CPM_ARGS_NAME} not found via find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION})")
endif()
endif()
if (NOT DEFINED CPM_ARGS_VERSION)
if (DEFINED CPM_ARGS_GIT_TAG)
CPM_GET_VERSION_FROM_GIT_TAG("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION)
cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION)
endif()
if (NOT DEFINED CPM_ARGS_VERSION)
set(CPM_ARGS_VERSION 0)
@@ -130,23 +167,24 @@ function(CPMAddPackage)
endif()
if (${CPM_ARGS_NAME} IN_LIST CPM_PACKAGES)
CPM_GET_PACKAGE_VERSION(${CPM_ARGS_NAME} CPM_PACKAGE_VERSION)
CPMGetPackageVersion(${CPM_ARGS_NAME} CPM_PACKAGE_VERSION)
if(${CPM_PACKAGE_VERSION} VERSION_LESS ${CPM_ARGS_VERSION})
message(WARNING "${CPM_INDENT} requires a newer version of ${CPM_ARGS_NAME} (${CPM_ARGS_VERSION}) than currently included (${CPM_PACKAGE_VERSION}).")
endif()
if (CPM_ARGS_OPTIONS)
foreach(OPTION ${CPM_ARGS_OPTIONS})
CPM_PARSE_OPTION(${OPTION})
cpm_parse_option(${OPTION})
if(NOT "${${OPTION_KEY}}" STREQUAL ${OPTION_VALUE})
message(WARNING "${CPM_INDENT} ignoring package option for ${CPM_ARGS_NAME}: ${OPTION_KEY} = ${OPTION_VALUE} (${${OPTION_KEY}})")
endif()
endforeach()
endif()
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 NO PARENT_SCOPE)
cpm_fetch_package(${CPM_ARGS_NAME} ${DOWNLOAD_ONLY})
cpm_get_fetch_properties(${CPM_ARGS_NAME})
SET(${CPM_ARGS_NAME}_SOURCE_DIR "${${CPM_ARGS_NAME}_SOURCE_DIR}")
SET(${CPM_ARGS_NAME}_BINARY_DIR "${${CPM_ARGS_NAME}_BINARY_DIR}")
SET(${CPM_ARGS_NAME}_ADDED NO)
cpm_export_variables()
return()
endif()
@@ -154,7 +192,7 @@ function(CPMAddPackage)
if (CPM_ARGS_OPTIONS)
foreach(OPTION ${CPM_ARGS_OPTIONS})
CPM_PARSE_OPTION(${OPTION})
cpm_parse_option(${OPTION})
set(${OPTION_KEY} ${OPTION_VALUE} CACHE INTERNAL "")
endforeach()
endif()
@@ -188,15 +226,35 @@ function(CPMAddPackage)
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)
cpm_declare_fetch(${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})
cpm_get_fetch_properties(${CPM_ARGS_NAME})
SET(${CPM_ARGS_NAME}_ADDED YES)
cpm_export_variables()
endfunction()
function (CPM_DECLARE_PACKAGE PACKAGE VERSION INFO)
# export variables available to the caller to the parent scope
# expects ${CPM_ARGS_NAME} to be set
macro(cpm_export_variables)
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 "${${CPM_ARGS_NAME}_ADDED}" PARENT_SCOPE)
endmacro()
# declares that a package has been added to CPM
function(CPMRegisterPackage PACKAGE VERSION)
list(APPEND CPM_PACKAGES ${PACKAGE})
set(CPM_PACKAGES ${CPM_PACKAGES} CACHE INTERNAL "")
set("CPM_PACKAGE_${PACKAGE}_VERSION" ${VERSION} CACHE INTERNAL "")
endfunction()
# retrieve the current version of the package to ${OUTPUT}
function(CPMGetPackageVersion PACKAGE OUTPUT)
set(${OUTPUT} "${CPM_PACKAGE_${PACKAGE}_VERSION}" PARENT_SCOPE)
endfunction()
# declares a package in FetchContent_Declare
function (cpm_declare_fetch PACKAGE VERSION INFO)
message(STATUS "${CPM_INDENT} adding package ${PACKAGE}@${VERSION} (${INFO})")
if (${CPM_DRY_RUN})
@@ -210,7 +268,19 @@ function (CPM_DECLARE_PACKAGE PACKAGE VERSION INFO)
)
endfunction()
function (CPM_FETCH_PACKAGE PACKAGE DOWNLOAD_ONLY)
# returns properties for a package previously defined by cpm_declare_fetch
function (cpm_get_fetch_properties PACKAGE)
if (${CPM_DRY_RUN})
return()
endif()
FetchContent_GetProperties(${PACKAGE})
string(TOLOWER ${PACKAGE} lpackage)
SET(${PACKAGE}_SOURCE_DIR "${${lpackage}_SOURCE_DIR}" PARENT_SCOPE)
SET(${PACKAGE}_BINARY_DIR "${${lpackage}_BINARY_DIR}" PARENT_SCOPE)
endfunction()
# downloads a previously declared package via FetchContent
function (cpm_fetch_package PACKAGE DOWNLOAD_ONLY)
if (${CPM_DRY_RUN})
message(STATUS "${CPM_INDENT} package ${PACKAGE} not fetched (dry run)")
@@ -229,27 +299,8 @@ function (CPM_FETCH_PACKAGE PACKAGE DOWNLOAD_ONLY)
set(CPM_INDENT "${CPM_OLD_INDENT}")
endfunction()
function (CPMGetProperties PACKAGE)
if (${CPM_DRY_RUN})
return()
endif()
FetchContent_GetProperties(${PACKAGE})
string(TOLOWER ${PACKAGE} lpackage)
SET(${PACKAGE}_SOURCE_DIR "${${lpackage}_SOURCE_DIR}" PARENT_SCOPE)
SET(${PACKAGE}_BINARY_DIR "${${lpackage}_BINARY_DIR}" PARENT_SCOPE)
endfunction()
function(CPMRegisterPackage PACKAGE VERSION)
list(APPEND CPM_PACKAGES ${PACKAGE})
set(CPM_PACKAGES ${CPM_PACKAGES} CACHE INTERNAL "")
set("CPM_PACKAGE_${PACKAGE}_VERSION" ${VERSION} CACHE INTERNAL "")
endfunction()
function(CPM_GET_PACKAGE_VERSION PACKAGE OUTPUT)
set(${OUTPUT} "${CPM_PACKAGE_${PACKAGE}_VERSION}" PARENT_SCOPE)
endfunction()
function(CPM_PARSE_OPTION OPTION)
# splits a package option
function(cpm_parse_option OPTION)
string(REGEX MATCH "^[^ ]+" OPTION_KEY ${OPTION})
string(LENGTH ${OPTION_KEY} OPTION_KEY_LENGTH)
math(EXPR OPTION_KEY_LENGTH "${OPTION_KEY_LENGTH}+1")
@@ -258,17 +309,14 @@ function(CPM_PARSE_OPTION OPTION)
set(OPTION_VALUE "${OPTION_VALUE}" PARENT_SCOPE)
endfunction()
function(CPM_GET_VERSION_FROM_GIT_TAG GIT_TAG RESULT)
string(REGEX MATCH "v?([0123456789.]*).*" _ ${GIT_TAG})
SET(${RESULT} ${CMAKE_MATCH_1} PARENT_SCOPE)
endfunction()
function (CPM_HANDLE_OLD_VERSION NEW_CPM_VERSION)
message(AUTHOR_WARNING "${CPM_INDENT} \
A dependency is using a more recent CPM (${NEW_CPM_VERSION}) than the current project (${CPM_VERSION}). \
It is recommended to upgrade CPM to the most recent version. \
See https://github.com/TheLartians/CPM for more information."
)
# guesses the package version from a git tag
function(cpm_get_version_from_git_tag GIT_TAG RESULT)
string(LENGTH ${GIT_TAG} length)
if (length EQUAL 40)
# GIT_TAG is probably a git hash
SET(${RESULT} 0 PARENT_SCOPE)
else()
string(REGEX MATCH "v?([0123456789.]*).*" _ ${GIT_TAG})
SET(${RESULT} ${CMAKE_MATCH_1} PARENT_SCOPE)
endif()
endfunction()

View File

@@ -9,13 +9,13 @@ include(../../cmake/CPM.cmake)
CPMAddPackage(
NAME fibonacci
GIT_REPOSITORY https://github.com/TheLartians/Fibonacci.git
VERSION 1.0
VERSION 2.0
)
CPMAddPackage(
NAME benchmark
GITHUB_REPOSITORY google/benchmark
VERSION 1.4.1
VERSION 1.5.0
OPTIONS
"BENCHMARK_ENABLE_TESTING Off"
)

View File

@@ -15,14 +15,14 @@ std::vector<unsigned> createTestNumbers(){
return v;
}
void fibonnacci(benchmark::State& state) {
void fibonacci(benchmark::State& state) {
auto numbers = createTestNumbers();
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) {
auto numbers = createTestNumbers();

View File

@@ -11,10 +11,11 @@ set_target_properties(CPMExampleBoost PROPERTIES CXX_STANDARD 17)
include(../../cmake/CPM.cmake)
CPMAddPackage(
NAME boost
CPMFindPackage(
NAME Boost
GITHUB_REPOSITORY Orphis/boost-cmake
VERSION 1.67.0
FIND_PACKAGE_ARGUMENTS "COMPONENTS system"
)
target_link_libraries(CPMExampleBoost PRIVATE Boost::system pthread)

View File

@@ -13,7 +13,7 @@ include(../../cmake/CPM.cmake)
CPMAddPackage(
NAME fibonacci
GIT_REPOSITORY https://github.com/TheLartians/Fibonacci.git
VERSION 1.0
VERSION 2.0
)
CPMAddPackage(

View File

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

View File

@@ -13,7 +13,7 @@ include(../../cmake/CPM.cmake)
CPMAddPackage(
NAME fibonacci
GIT_REPOSITORY https://github.com/TheLartians/Fibonacci.git
VERSION 1.0
VERSION 2.0
)
CPMAddPackage(

View File

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

View File

@@ -13,7 +13,7 @@ include(../../cmake/CPM.cmake)
CPMAddPackage(
NAME fibonacci
GIT_REPOSITORY https://github.com/TheLartians/Fibonacci.git
VERSION 1.0
VERSION 2.0
)
CPMAddPackage(

View File

@@ -3,11 +3,11 @@
TEST(FibonacciTests, BasicChecks)
{
ASSERT_TRUE(fibonnacci(0) == 0);
ASSERT_TRUE(fibonnacci(1) == 1);
ASSERT_TRUE(fibonnacci(2) == 1);
ASSERT_TRUE(fibonnacci(3) == 2);
ASSERT_TRUE(fibonnacci(4) == 3);
ASSERT_TRUE(fibonnacci(5) == 5);
ASSERT_TRUE(fibonnacci(13) == 233);
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

@@ -1,30 +0,0 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(CPMParserLuaExample)
include(../../cmake/CPM.cmake)
# ---- Dependencies ----
CPMAddPackage(
NAME Glue
GIT_REPOSITORY https://github.com/TheLartians/Glue.git
VERSION 0.8.2
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,17 +0,0 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(CPMParserExample)
# 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

@@ -29,7 +29,7 @@ function(reset_test)
update_cmake_lists()
endfunction()
set(CATCH2_VERSION 2.8.0)
set(FIBONACCI_VERSION 1.0)
## Read CPM_SOURCE_CACHE from arguments
@@ -43,13 +43,13 @@ execute_process(
ASSERT_EQUAL(${ret} "0")
if (NOT EXISTS "${CPM_SOURCE_CACHE_DIR}/catch2")
ASSERTION_FAILED("catch2 not in cache")
if (NOT EXISTS "${CPM_SOURCE_CACHE_DIR}/fibonacci")
ASSERTION_FAILED("fibonacci not in cache")
endif()
FILE(GLOB catch2_versions "${CPM_SOURCE_CACHE_DIR}/catch2/*")
list(LENGTH catch2_versions catch2_version_count)
ASSERT_EQUAL(${catch2_version_count} "1")
FILE(GLOB FIBONACCI_VERSIONs "${CPM_SOURCE_CACHE_DIR}/fibonacci/*")
list(LENGTH FIBONACCI_VERSIONs FIBONACCI_VERSION_count)
ASSERT_EQUAL(${FIBONACCI_VERSION_count} "1")
FILE(GLOB fibonacci_versions "${CPM_SOURCE_CACHE_DIR}/fibonacci/*")
list(LENGTH fibonacci_versions fibonacci_version_count)
@@ -57,7 +57,7 @@ ASSERT_EQUAL(${fibonacci_version_count} "1")
## Update dependency and keep CPM_SOURCE_CACHE
set(CATCH2_VERSION 2.9.0)
set(FIBONACCI_VERSION 2.0)
update_cmake_lists()
execute_process(
@@ -68,13 +68,9 @@ execute_process(
ASSERT_EQUAL(${ret} "0")
FILE(GLOB catch2_versions "${CPM_SOURCE_CACHE_DIR}/catch2/*")
list(LENGTH catch2_versions catch2_version_count)
ASSERT_EQUAL(${catch2_version_count} "2")
FILE(GLOB fibonacci_versions "${CPM_SOURCE_CACHE_DIR}/fibonacci/*")
list(LENGTH fibonacci_versions fibonacci_version_count)
ASSERT_EQUAL(${fibonacci_version_count} "1")
FILE(GLOB FIBONACCI_VERSIONs "${CPM_SOURCE_CACHE_DIR}/fibonacci/*")
list(LENGTH FIBONACCI_VERSIONs FIBONACCI_VERSION_count)
ASSERT_EQUAL(${FIBONACCI_VERSION_count} "2")
## Clear cache and update
@@ -88,8 +84,8 @@ execute_process(
ASSERT_EQUAL(${ret} "0")
if (NOT EXISTS "${CPM_SOURCE_CACHE_DIR}/catch2")
ASSERTION_FAILED("catch2 not in cache")
if (NOT EXISTS "${CPM_SOURCE_CACHE_DIR}/fibonacci")
ASSERTION_FAILED("fibonacci not in cache")
endif()
## Read CPM_SOURCE_CACHE from environment
@@ -104,8 +100,8 @@ execute_process(
ASSERT_EQUAL(${ret} "0")
if (NOT EXISTS "${CPM_SOURCE_CACHE_DIR}/catch2")
ASSERTION_FAILED("catch2 not in cache")
if (NOT EXISTS "${CPM_SOURCE_CACHE_DIR}/fibonacci")
ASSERTION_FAILED("fibonacci not in cache")
endif()
## Overwrite CPM_SOURCE_CACHE with argument
@@ -120,6 +116,6 @@ execute_process(
ASSERT_EQUAL(${ret} "0")
if (NOT EXISTS "${CPM_SOURCE_CACHE_DIR}/catch2")
ASSERTION_FAILED("catch2 not in cache")
if (NOT EXISTS "${CPM_SOURCE_CACHE_DIR}/fibonacci")
ASSERTION_FAILED("fibonacci not in cache")
endif()

View File

@@ -13,18 +13,11 @@ include(@CPM_PATH@/CPM.cmake)
CPMAddPackage(
NAME fibonacci
GIT_REPOSITORY https://github.com/TheLartians/Fibonacci.git
VERSION 1.0
)
CPMAddPackage(
NAME Catch2
GITHUB_REPOSITORY catchorg/Catch2
VERSION @CATCH2_VERSION@
GIT_SHALLOW YES
VERSION @FIBONACCI_VERSION@
)
# ---- Create binary ----
add_executable(CPMExampleCatch2 main.cpp)
target_link_libraries(CPMExampleCatch2 fibonacci Catch2)
target_link_libraries(CPMExampleCatch2 fibonacci)
set_target_properties(CPMExampleCatch2 PROPERTIES CXX_STANDARD 17 COMPILE_FLAGS "-Wall -pedantic -Wextra -Werror")

View File

@@ -1,13 +1,9 @@
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
#include <fibonacci.h>
#include <iostream>
TEST_CASE("fibonnacci"){
REQUIRE(fibonnacci(0) == 0);
REQUIRE(fibonnacci(1) == 1);
REQUIRE(fibonnacci(2) == 1);
REQUIRE(fibonnacci(3) == 2);
REQUIRE(fibonnacci(4) == 3);
REQUIRE(fibonnacci(5) == 5);
int main(){
std::cout << "fib(10) = " << fastFibonacci(10) << std::endl;
return 0;
}

View File

@@ -15,7 +15,7 @@ CPMAddPackage(
VERSION 1.2.3
)
CPM_GET_PACKAGE_VERSION(A VERSION)
CPMGetPackageVersion(A VERSION)
ASSERT_EQUAL(${VERSION} "1.2.3")
CPMAddPackage(
@@ -28,7 +28,7 @@ CPMAddPackage(
GIT_TAG v2.3.1
)
CPM_GET_PACKAGE_VERSION(B VERSION)
CPMGetPackageVersion(B VERSION)
ASSERT_EQUAL(${VERSION} "2.4.1")
CPMAddPackage(
@@ -37,5 +37,5 @@ CPMAddPackage(
VERSION 3.1.2
)
CPM_GET_PACKAGE_VERSION(C VERSION)
CPMGetPackageVersion(C VERSION)
ASSERT_EQUAL(${VERSION} "3.1.2")