mirror of
https://github.com/cpm-cmake/CPM.cmake.git
synced 2025-11-23 04:37:43 -05:00
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f57476ee43 | ||
|
|
db4f2bf7bb | ||
|
|
8d39e34ff2 | ||
|
|
c2a413300e | ||
|
|
5177860756 | ||
|
|
5dad9d4e9d | ||
|
|
539974785e | ||
|
|
e4a0cb4980 | ||
|
|
a8ccc42f43 | ||
|
|
f92ed18514 | ||
|
|
153c196c18 | ||
|
|
d91befd7ce | ||
|
|
978c101c7e | ||
|
|
8da680df9b | ||
|
|
6943b38afb | ||
|
|
cf042cf1ac | ||
|
|
bebea37c4a | ||
|
|
137bda299d | ||
|
|
4d557d128f | ||
|
|
9021499c52 | ||
|
|
9b97b64da2 | ||
|
|
df752ed5d3 | ||
|
|
f00f5517a6 | ||
|
|
a97b32824e | ||
|
|
e558d795f9 | ||
|
|
76748fe542 | ||
|
|
e453671327 | ||
|
|
5192f713d2 | ||
|
|
282b98423a | ||
|
|
2ff0f5f58f | ||
|
|
9343f7c69a | ||
|
|
044edb1fd2 | ||
|
|
07a4d626a1 | ||
|
|
0d529f73cd | ||
|
|
96dba3b03c | ||
|
|
ba256b71c1 | ||
|
|
b3a875e2dd | ||
|
|
a582911527 | ||
|
|
0a07f53d6d | ||
|
|
b81a29b598 | ||
|
|
0adcd87add | ||
|
|
95634c30fd | ||
|
|
bf205f77b4 | ||
|
|
610448d275 | ||
|
|
dd63d9fcdb | ||
|
|
f8899a5912 | ||
|
|
48b84b8cdf | ||
|
|
d3d8a6ab4f | ||
|
|
923265e7ae | ||
|
|
f2ad294ef3 | ||
|
|
3e65078ce7 | ||
|
|
946019a336 | ||
|
|
2d95c66fa4 | ||
|
|
77a118d3ce | ||
|
|
4dee712eef | ||
|
|
3c0d201c76 | ||
|
|
4c22b73ebd | ||
|
|
50aa889be8 | ||
|
|
e4bbd6e215 | ||
|
|
e368fce6c3 | ||
|
|
f8e571e416 | ||
|
|
e565e35397 | ||
|
|
702f413801 | ||
|
|
03b2dd0cb9 | ||
|
|
4badcddc5d | ||
|
|
72371bcc8b | ||
|
|
0798050d6d | ||
|
|
ffa310199a | ||
|
|
cd3cdfd197 |
17
.travis.yml
17
.travis.yml
@@ -1,11 +1,14 @@
|
||||
|
||||
language: cpp
|
||||
sudo: require
|
||||
dist: xenial
|
||||
|
||||
common_sources: &all_sources
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty
|
||||
- llvm-toolchain-trusty-6.0
|
||||
|
||||
python:
|
||||
- 3.7
|
||||
|
||||
matrix:
|
||||
include:
|
||||
@@ -34,12 +37,12 @@ before_install:
|
||||
# Update compilers
|
||||
- eval "${MATRIX_EVAL}"
|
||||
- echo "CC=$CC CXX=$CXX"
|
||||
# Install a supported cmake version (>= 3.14)
|
||||
- wget -O cmake.sh https://cmake.org/files/v3.14/cmake-3.14.0-Linux-x86_64.sh
|
||||
- sudo sh cmake.sh --skip-license --exclude-subdir --prefix=/usr/local
|
||||
- export PATH=/usr/local/bin:$PATH
|
||||
- cmake --version
|
||||
|
||||
script:
|
||||
- cmake -Htests/simple -Bbuild/simple
|
||||
- cmake --build build/simple
|
||||
- CTEST_OUTPUT_ON_FAILURE=1 cmake --build build/simple --target test
|
||||
- cmake -Htests/complex -Bbuild/complex
|
||||
- cmake --build build/complex
|
||||
- CTEST_OUTPUT_ON_FAILURE=1 cmake --build build/complex --target test
|
||||
- python3 examples/run_all.py
|
||||
|
||||
139
README.md
139
README.md
@@ -2,34 +2,145 @@
|
||||
|
||||
# CPM
|
||||
|
||||
CPM is a very simple package manager written in Cmake based on the amazing [DownloadProject](https://github.com/Crascit/DownloadProject) script. It is extremely easy to use and drastically simplifies the inclusion of other Cmake-based projects from github.
|
||||
CPM is a simple dependency manager written in CMake built on top of CMake's built-in [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) module.
|
||||
|
||||
# Usage
|
||||
## Supported projects
|
||||
|
||||
To add a new dependency to your project simply add the Projects target name, the git URL and the version. If the git tag for this version does not match the pattern `v$VERSION`, then the exact branch or tag can be specified with the `GIT_TAG` argument.
|
||||
Any project that you can add via `add_subdirectory` should already work with CPM.
|
||||
|
||||
## Usage
|
||||
|
||||
After `CPM.cmake` has been added to your project, you can call `CPMAddPackage` for every dependency of the project with the following named parameters.
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
||||
CPMAddPackage(
|
||||
NAME # The dependency name (usually chosen to match the target 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)
|
||||
[...] # Source options, see below
|
||||
)
|
||||
```
|
||||
|
||||
project(MyParser)
|
||||
The command downloads the project defined by the source options if a newer version hasn't been included before.
|
||||
The source is usually a git repository, but svn and direct urls are als supported.
|
||||
See the [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) documentation for all available options.
|
||||
If a `GIT_TAG` hasn't been explicitly specified it defaults to `v$VERSION` which is a common convention for github projects.
|
||||
|
||||
After calling `CPMAddPackage`, the variables `(DEPENDENCY)_SOURCE_DIR` and `(DEPENDENCY)_BINARY_DIR` are set, where `(DEPENDENCY)` is the name of the dependency.
|
||||
|
||||
## Full Example
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
# create project
|
||||
project(MyProject)
|
||||
|
||||
# add dependencies
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/CPM.cmake)
|
||||
include(cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME LarsParser
|
||||
VERSION 1.2
|
||||
VERSION 1.8
|
||||
GIT_REPOSITORY https://github.com/TheLartians/Parser.git
|
||||
GIT_TAG master # optional
|
||||
OPTIONS
|
||||
"LARS_PARSER_BUILD_GLUE_EXTENSION ON"
|
||||
)
|
||||
|
||||
# add executable
|
||||
set (CMAKE_CXX_STANDARD 17)
|
||||
add_executable(my-parser my-parser.cpp)
|
||||
target_link_libraries(cpm-test LarsParser)
|
||||
add_executable(myProject myProject.cpp)
|
||||
set_target_properties(myProject PROPERTIES CXX_STANDARD 17)
|
||||
target_link_libraries(myProject LarsParser)
|
||||
```
|
||||
|
||||
# Limitations
|
||||
See the [examples directory](https://github.com/TheLartians/CPM/tree/master/examples) for more examples with source code.
|
||||
|
||||
- First version used: in diamond dependency graphs (e.g. `A` depends on `C`(v1.1) and `A` depends on `B` depends on `C`(v1.2)) the first added dependency will be used (in this case `C`@1.1).
|
||||
- No possibility not automatically update dependencies. To update a dependency, version numbers or git tags in the cmake scripts must be adapted manually.
|
||||
## 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.
|
||||
|
||||
```bash
|
||||
wget -O cmake/CPM.cmake https://raw.githubusercontent.com/TheLartians/CPM/master/cmake/CPM.cmake
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
## Snipplets
|
||||
|
||||
These are some small snipplets demonstrating how to include some projects used with CPM.
|
||||
|
||||
### Catch2
|
||||
|
||||
Has a CMakeLists.txt that supports `add_subdirectory`.
|
||||
|
||||
```cmake
|
||||
CPMAddPackage(
|
||||
NAME Catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
VERSION 2.5.0
|
||||
)
|
||||
```
|
||||
|
||||
### google/benchmark
|
||||
|
||||
Has a CMakeLists.txt that supports `add_subdirectory`, but needs some configuring to work without external dependencies.
|
||||
|
||||
```cmake
|
||||
CPMAddPackage(
|
||||
NAME benchmark
|
||||
GIT_REPOSITORY https://github.com/google/benchmark.git
|
||||
VERSION 1.4.1
|
||||
OPTIONS
|
||||
"BENCHMARK_ENABLE_TESTING Off"
|
||||
)
|
||||
|
||||
# needed to compile with C++17
|
||||
set_target_properties(benchmark PROPERTIES CXX_STANDARD 17)
|
||||
```
|
||||
|
||||
### Lua
|
||||
|
||||
Has no CMakeLists.txt, so a target must be created manually.
|
||||
|
||||
```cmake
|
||||
CPMAddPackage(
|
||||
NAME lua
|
||||
GIT_REPOSITORY https://github.com/lua/lua.git
|
||||
VERSION 5-3-4
|
||||
GIT_SHALLOW YES
|
||||
DOWNLOAD_ONLY YES
|
||||
)
|
||||
|
||||
FILE(GLOB lua_sources ${lua_SOURCE_DIR}/*.c)
|
||||
add_library(lua STATIC ${lua_sources})
|
||||
|
||||
target_include_directories(lua
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${lua_SOURCE_DIR}>
|
||||
)
|
||||
```
|
||||
|
||||
## Local packages
|
||||
|
||||
CPM can be configured to use `find_package` to search for locally installed dependencies first.
|
||||
If `CPM_LOCAL_PACKAGES_ONLY` is set, CPM will error when dependency is not found locally.
|
||||
|
||||
## Advantages
|
||||
|
||||
- **Small repos** CPM takes care of project dependencies, allowing you to focus on creating small, well-tested frameworks.
|
||||
- **Cross-Plattform** CPM adds projects via `add_subdirectory`, which is compatible with all cmake toolchains and generators.
|
||||
- **Reproducable builds** By using versioning via git tags it is ensured that a project will always be in the same state everywhere.
|
||||
- **No installation required** No need to install anything. Just add the script to your project and you're good to go.
|
||||
- **No Setup required** There is a good chance your existing projects already work as CPM dependencies.
|
||||
- **Simple source distribution** CPM makes including projects with source files easy, reducing the need for monolithic header files.
|
||||
|
||||
## Limitations
|
||||
|
||||
- **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.
|
||||
- **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 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) instead.
|
||||
|
||||
196
cmake/CPM.cmake
196
cmake/CPM.cmake
@@ -1,65 +1,189 @@
|
||||
set(_CPM_Dir "${CMAKE_CURRENT_LIST_DIR}")
|
||||
# TheLartians/CPM - A simple Git dependency manager
|
||||
# =================================================
|
||||
# See https://github.com/TheLartians/CPM for usage and update instructions.
|
||||
#
|
||||
# MIT License
|
||||
# -----------
|
||||
#[[
|
||||
Copyright (c) 2019 Lars Melchior
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
set(CURRENT_CPM_VERSION 0.9)
|
||||
|
||||
if(CPM_DIRECTORY)
|
||||
if(NOT ${CPM_DIRECTORY} MATCHES ${CMAKE_CURRENT_LIST_DIR})
|
||||
if (${CPM_VERSION} VERSION_LESS ${CURRENT_CPM_VERSION})
|
||||
message(AUTHOR_WARNING "${CPM_INDENT} \
|
||||
A dependency is using a more recent CPM (${CURRENT_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()
|
||||
|
||||
set(CPM_VERSION ${CURRENT_CPM_VERSION} CACHE INTERNAL "")
|
||||
|
||||
set(CPM_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} CACHE INTERNAL "")
|
||||
set(CPM_PACKAGES "" CACHE INTERNAL "")
|
||||
|
||||
option(CPM_USE_LOCAL_PACKAGES "Use locally installed packages (find_package)" OFF)
|
||||
option(CPM_LOCAL_PACKAGES_ONLY "Use only locally installed packages" OFF)
|
||||
|
||||
include(FetchContent)
|
||||
include(CMakeParseArguments)
|
||||
include(${_CPM_Dir}/DownloadProject.cmake)
|
||||
|
||||
function(CPMHasPackage)
|
||||
|
||||
if(NOT CPM_INDENT)
|
||||
set(CPM_INDENT "CPM:")
|
||||
endif()
|
||||
|
||||
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)
|
||||
set(CPM_PACKAGE_VERSION "${CPM_PACKAGE_${PACKAGE}_VERSION}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
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")
|
||||
string(SUBSTRING ${OPTION} "${OPTION_KEY_LENGTH}" "-1" OPTION_VALUE)
|
||||
set(OPTION_KEY "${OPTION_KEY}" PARENT_SCOPE)
|
||||
set(OPTION_VALUE "${OPTION_VALUE}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(CPMAddPackage)
|
||||
set(options QUIET)
|
||||
|
||||
set(oneValueArgs
|
||||
NAME
|
||||
GIT_REPOSITORY
|
||||
VERSION
|
||||
GIT_TAG
|
||||
BINARY_DIR
|
||||
DOWNLOAD_ONLY
|
||||
)
|
||||
|
||||
set(multiValueArgs "")
|
||||
set(multiValueArgs
|
||||
OPTIONS
|
||||
)
|
||||
|
||||
cmake_parse_arguments(CPM_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if (NOT CPM_PACKAGES)
|
||||
set(CPM_PACKAGES "")
|
||||
if(${CPM_USE_LOCAL_PACKAGES} OR ${CPM_LOCAL_PACKAGES_ONLY})
|
||||
find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION} QUIET)
|
||||
|
||||
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
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
|
||||
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 CPM_ARGS_BINARY_DIR)
|
||||
set(CPM_ARGS_BINARY_DIR ${CMAKE_BINARY_DIR}/CPM-projects/${CPM_ARGS_NAME})
|
||||
endif()
|
||||
|
||||
message("test: ${CPM_ARGS_BINARY_DIR}")
|
||||
|
||||
if (NOT CPM_PROJECT_DIR)
|
||||
set(CPM_PROJECT_DIR "${CPM_ARGS_BINARY_DIR}")
|
||||
if (NOT CPM_ARGS_VERSION)
|
||||
set(CPM_ARGS_VERSION 0)
|
||||
endif()
|
||||
|
||||
if (NOT CPM_ARGS_GIT_TAG)
|
||||
set(CPM_ARGS_GIT_TAG v${CPM_ARGS_VERSION})
|
||||
endif()
|
||||
|
||||
SET(CPM_TARGET_CMAKE_FILE "${CPM_PROJECT_DIR}")
|
||||
if(CPM_ARGS_DOWNLOAD_ONLY)
|
||||
set(DOWNLOAD_ONLY ${CPM_ARGS_DOWNLOAD_ONLY})
|
||||
else()
|
||||
set(DOWNLOAD_ONLY NO)
|
||||
endif()
|
||||
|
||||
if (${CPM_ARGS_NAME} IN_LIST CPM_PACKAGES)
|
||||
message(STATUS "CPM: package ${CPM_ARGS_NAME} already added")
|
||||
else()
|
||||
message(STATUS "CPM: adding package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION}")
|
||||
# update package data
|
||||
LIST(APPEND CPM_PACKAGES ${CPM_ARGS_NAME})
|
||||
# save package data
|
||||
set(CPM_PACKAGES "${CPM_PACKAGES}" CACHE INTERNAL "CPM Packages")
|
||||
|
||||
configure_file(
|
||||
"${_CPM_Dir}/CPMProject.CMakeLists.cmake.in"
|
||||
"${CPM_TARGET_CMAKE_FILE}/CMakeLists.txt"
|
||||
@ONLY
|
||||
)
|
||||
CPM_GET_PACKAGE_VERSION(${CPM_ARGS_NAME})
|
||||
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})
|
||||
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)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (NOT TARGET ${CPM_ARGS_NAME})
|
||||
add_subdirectory(${CPM_TARGET_CMAKE_FILE} ${CPM_ARGS_BINARY_DIR})
|
||||
CPMRegisterPackage(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION})
|
||||
|
||||
if (CPM_ARGS_OPTIONS)
|
||||
foreach(OPTION ${CPM_ARGS_OPTIONS})
|
||||
CPM_PARSE_OPTION(${OPTION})
|
||||
set(${OPTION_KEY} ${OPTION_VALUE} CACHE INTERNAL "")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
CPM_DECLARE_PACKAGE(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION} ${CPM_ARGS_GIT_TAG} "${CPM_ARGS_UNPARSED_ARGUMENTS}")
|
||||
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)
|
||||
endfunction()
|
||||
|
||||
function (CPM_DECLARE_PACKAGE PACKAGE VERSION GIT_TAG)
|
||||
message(STATUS "${CPM_INDENT} adding package ${PACKAGE}@${VERSION} (${GIT_TAG})")
|
||||
|
||||
FetchContent_Declare(
|
||||
${PACKAGE}
|
||||
GIT_TAG ${GIT_TAG}
|
||||
${ARGN}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function (CPM_FETCH_PACKAGE PACKAGE DOWNLOAD_ONLY)
|
||||
set(CPM_OLD_INDENT "${CPM_INDENT}")
|
||||
set(CPM_INDENT "${CPM_INDENT} ${PACKAGE}:")
|
||||
if(${DOWNLOAD_ONLY})
|
||||
if(NOT "${PACKAGE}_POPULATED")
|
||||
FetchContent_Populate(${PACKAGE})
|
||||
endif()
|
||||
else()
|
||||
FetchContent_MakeAvailable(${PACKAGE})
|
||||
endif()
|
||||
set(CPM_INDENT "${CPM_OLD_INDENT}")
|
||||
endfunction()
|
||||
|
||||
function (CPMGetProperties PACKAGE)
|
||||
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()
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
||||
|
||||
if(TARGET @CPM_ARGS_NAME@)
|
||||
return()
|
||||
endif()
|
||||
|
||||
find_package(@CPM_ARGS_NAME@ @CPM_ARGS_VERSION@ QUIET)
|
||||
|
||||
if(${PACKAGE_FOUND})
|
||||
set_target_properties(@CPM_ARGS_NAME@
|
||||
PROPERTIES
|
||||
IMPORTED_GLOBAL True
|
||||
)
|
||||
else()
|
||||
|
||||
download_project(
|
||||
PROJ @CPM_ARGS_NAME@
|
||||
GIT_REPOSITORY @CPM_ARGS_GIT_REPOSITORY@
|
||||
GIT_TAG @CPM_ARGS_GIT_TAG@
|
||||
UPDATE_DISCONNECTED 1
|
||||
GIT_SHALLOW 1
|
||||
PREFIX @CPM_ARGS_BINARY_DIR@/dl
|
||||
QUIET
|
||||
)
|
||||
|
||||
add_subdirectory(${@CPM_ARGS_NAME@_SOURCE_DIR} ${@CPM_ARGS_NAME@_BINARY_DIR})
|
||||
endif()
|
||||
@@ -1,17 +0,0 @@
|
||||
# Distributed under the OSI-approved MIT License. See accompanying
|
||||
# file LICENSE or https://github.com/Crascit/DownloadProject for details.
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.2)
|
||||
|
||||
project(${DL_ARGS_PROJ}-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(${DL_ARGS_PROJ}-download
|
||||
${DL_ARGS_UNPARSED_ARGUMENTS}
|
||||
SOURCE_DIR "${DL_ARGS_SOURCE_DIR}"
|
||||
BINARY_DIR "${DL_ARGS_BINARY_DIR}"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
@@ -1,182 +0,0 @@
|
||||
# Distributed under the OSI-approved MIT License. See accompanying
|
||||
# file LICENSE or https://github.com/Crascit/DownloadProject for details.
|
||||
#
|
||||
# MODULE: DownloadProject
|
||||
#
|
||||
# PROVIDES:
|
||||
# download_project( PROJ projectName
|
||||
# [PREFIX prefixDir]
|
||||
# [DOWNLOAD_DIR downloadDir]
|
||||
# [SOURCE_DIR srcDir]
|
||||
# [BINARY_DIR binDir]
|
||||
# [QUIET]
|
||||
# ...
|
||||
# )
|
||||
#
|
||||
# Provides the ability to download and unpack a tarball, zip file, git repository,
|
||||
# etc. at configure time (i.e. when the cmake command is run). How the downloaded
|
||||
# and unpacked contents are used is up to the caller, but the motivating case is
|
||||
# to download source code which can then be included directly in the build with
|
||||
# add_subdirectory() after the call to download_project(). Source and build
|
||||
# directories are set up with this in mind.
|
||||
#
|
||||
# The PROJ argument is required. The projectName value will be used to construct
|
||||
# the following variables upon exit (obviously replace projectName with its actual
|
||||
# value):
|
||||
#
|
||||
# projectName_SOURCE_DIR
|
||||
# projectName_BINARY_DIR
|
||||
#
|
||||
# The SOURCE_DIR and BINARY_DIR arguments are optional and would not typically
|
||||
# need to be provided. They can be specified if you want the downloaded source
|
||||
# and build directories to be located in a specific place. The contents of
|
||||
# projectName_SOURCE_DIR and projectName_BINARY_DIR will be populated with the
|
||||
# locations used whether you provide SOURCE_DIR/BINARY_DIR or not.
|
||||
#
|
||||
# The DOWNLOAD_DIR argument does not normally need to be set. It controls the
|
||||
# location of the temporary CMake build used to perform the download.
|
||||
#
|
||||
# The PREFIX argument can be provided to change the base location of the default
|
||||
# values of DOWNLOAD_DIR, SOURCE_DIR and BINARY_DIR. If all of those three arguments
|
||||
# are provided, then PREFIX will have no effect. The default value for PREFIX is
|
||||
# CMAKE_BINARY_DIR.
|
||||
#
|
||||
# The QUIET option can be given if you do not want to show the output associated
|
||||
# with downloading the specified project.
|
||||
#
|
||||
# In addition to the above, any other options are passed through unmodified to
|
||||
# ExternalProject_Add() to perform the actual download, patch and update steps.
|
||||
# The following ExternalProject_Add() options are explicitly prohibited (they
|
||||
# are reserved for use by the download_project() command):
|
||||
#
|
||||
# CONFIGURE_COMMAND
|
||||
# BUILD_COMMAND
|
||||
# INSTALL_COMMAND
|
||||
# TEST_COMMAND
|
||||
#
|
||||
# Only those ExternalProject_Add() arguments which relate to downloading, patching
|
||||
# and updating of the project sources are intended to be used. Also note that at
|
||||
# least one set of download-related arguments are required.
|
||||
#
|
||||
# If using CMake 3.2 or later, the UPDATE_DISCONNECTED option can be used to
|
||||
# prevent a check at the remote end for changes every time CMake is run
|
||||
# after the first successful download. See the documentation of the ExternalProject
|
||||
# module for more information. It is likely you will want to use this option if it
|
||||
# is available to you. Note, however, that the ExternalProject implementation contains
|
||||
# bugs which result in incorrect handling of the UPDATE_DISCONNECTED option when
|
||||
# using the URL download method or when specifying a SOURCE_DIR with no download
|
||||
# method. Fixes for these have been created, the last of which is scheduled for
|
||||
# inclusion in CMake 3.8.0. Details can be found here:
|
||||
#
|
||||
# https://gitlab.kitware.com/cmake/cmake/commit/bdca68388bd57f8302d3c1d83d691034b7ffa70c
|
||||
# https://gitlab.kitware.com/cmake/cmake/issues/16428
|
||||
#
|
||||
# If you experience build errors related to the update step, consider avoiding
|
||||
# the use of UPDATE_DISCONNECTED.
|
||||
#
|
||||
# EXAMPLE USAGE:
|
||||
#
|
||||
# include(DownloadProject)
|
||||
# download_project(PROJ googletest
|
||||
# GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
# GIT_TAG master
|
||||
# UPDATE_DISCONNECTED 1
|
||||
# QUIET
|
||||
# )
|
||||
#
|
||||
# add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
|
||||
#
|
||||
#========================================================================================
|
||||
|
||||
|
||||
set(_DownloadProjectDir "${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
function(download_project)
|
||||
|
||||
set(options QUIET)
|
||||
set(oneValueArgs
|
||||
PROJ
|
||||
PREFIX
|
||||
DOWNLOAD_DIR
|
||||
SOURCE_DIR
|
||||
BINARY_DIR
|
||||
# Prevent the following from being passed through
|
||||
CONFIGURE_COMMAND
|
||||
BUILD_COMMAND
|
||||
INSTALL_COMMAND
|
||||
TEST_COMMAND
|
||||
)
|
||||
set(multiValueArgs "")
|
||||
|
||||
cmake_parse_arguments(DL_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
# Hide output if requested
|
||||
if (DL_ARGS_QUIET)
|
||||
set(OUTPUT_QUIET "OUTPUT_QUIET")
|
||||
else()
|
||||
unset(OUTPUT_QUIET)
|
||||
message(STATUS "Downloading/updating ${DL_ARGS_PROJ}")
|
||||
endif()
|
||||
|
||||
# Set up where we will put our temporary CMakeLists.txt file and also
|
||||
# the base point below which the default source and binary dirs will be.
|
||||
# The prefix must always be an absolute path.
|
||||
if (NOT DL_ARGS_PREFIX)
|
||||
set(DL_ARGS_PREFIX "${CMAKE_BINARY_DIR}")
|
||||
else()
|
||||
get_filename_component(DL_ARGS_PREFIX "${DL_ARGS_PREFIX}" ABSOLUTE
|
||||
BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
if (NOT DL_ARGS_DOWNLOAD_DIR)
|
||||
set(DL_ARGS_DOWNLOAD_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-download")
|
||||
endif()
|
||||
|
||||
# Ensure the caller can know where to find the source and build directories
|
||||
if (NOT DL_ARGS_SOURCE_DIR)
|
||||
set(DL_ARGS_SOURCE_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-src")
|
||||
endif()
|
||||
if (NOT DL_ARGS_BINARY_DIR)
|
||||
set(DL_ARGS_BINARY_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-build")
|
||||
endif()
|
||||
set(${DL_ARGS_PROJ}_SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" PARENT_SCOPE)
|
||||
set(${DL_ARGS_PROJ}_BINARY_DIR "${DL_ARGS_BINARY_DIR}" PARENT_SCOPE)
|
||||
|
||||
# The way that CLion manages multiple configurations, it causes a copy of
|
||||
# the CMakeCache.txt to be copied across due to it not expecting there to
|
||||
# be a project within a project. This causes the hard-coded paths in the
|
||||
# cache to be copied and builds to fail. To mitigate this, we simply
|
||||
# remove the cache if it exists before we configure the new project. It
|
||||
# is safe to do so because it will be re-generated. Since this is only
|
||||
# executed at the configure step, it should not cause additional builds or
|
||||
# downloads.
|
||||
file(REMOVE "${DL_ARGS_DOWNLOAD_DIR}/CMakeCache.txt")
|
||||
|
||||
# Create and build a separate CMake project to carry out the download.
|
||||
# If we've already previously done these steps, they will not cause
|
||||
# anything to be updated, so extra rebuilds of the project won't occur.
|
||||
# Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project
|
||||
# has this set to something not findable on the PATH.
|
||||
configure_file("${_DownloadProjectDir}/DownloadProject.CMakeLists.cmake.in"
|
||||
"${DL_ARGS_DOWNLOAD_DIR}/CMakeLists.txt")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}"
|
||||
-D "CMAKE_MAKE_PROGRAM:FILE=${CMAKE_MAKE_PROGRAM}"
|
||||
.
|
||||
RESULT_VARIABLE result
|
||||
${OUTPUT_QUIET}
|
||||
WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}"
|
||||
)
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for ${DL_ARGS_PROJ} failed: ${result}")
|
||||
endif()
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} --build .
|
||||
RESULT_VARIABLE result
|
||||
${OUTPUT_QUIET}
|
||||
WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}"
|
||||
)
|
||||
if(result)
|
||||
message(FATAL_ERROR "Build step for ${DL_ARGS_PROJ} failed: ${result}")
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
28
examples/benchmark/CMakeLists.txt
Normal file
28
examples/benchmark/CMakeLists.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME fibonacci
|
||||
GIT_REPOSITORY https://github.com/TheLartians/Fibonacci.git
|
||||
VERSION 1.0
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME benchmark
|
||||
GIT_REPOSITORY https://github.com/google/benchmark.git
|
||||
VERSION 1.4.1
|
||||
OPTIONS
|
||||
"BENCHMARK_ENABLE_TESTING Off"
|
||||
)
|
||||
|
||||
# patch google benchmark target
|
||||
set_target_properties(benchmark PROPERTIES CXX_STANDARD 17)
|
||||
|
||||
# ---- Executable ----
|
||||
|
||||
add_executable(CPMExampleBenchmark "main.cpp")
|
||||
set_target_properties(CPMExampleBenchmark PROPERTIES CXX_STANDARD 17)
|
||||
target_link_libraries(CPMExampleBenchmark fibonacci benchmark)
|
||||
36
examples/benchmark/main.cpp
Normal file
36
examples/benchmark/main.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
||||
#include <fibonacci.h>
|
||||
|
||||
|
||||
std::vector<unsigned> createTestNumbers(){
|
||||
std::vector<unsigned> v;
|
||||
for (int i=0;i<25;++i) v.emplace_back(i);
|
||||
std::random_device rd;
|
||||
std::mt19937 g(rd());
|
||||
std::shuffle(v.begin(), v.end(), g);
|
||||
return v;
|
||||
}
|
||||
|
||||
void fibonnacci(benchmark::State& state) {
|
||||
auto numbers = createTestNumbers();
|
||||
for (auto _ : state) {
|
||||
for (auto v: numbers) benchmark::DoNotOptimize(fibonnacci(v));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(fibonnacci);
|
||||
|
||||
void fastFibonacci(benchmark::State& state) {
|
||||
auto numbers = createTestNumbers();
|
||||
for (auto _ : state) {
|
||||
for (auto v: numbers) benchmark::DoNotOptimize(fastFibonacci(v));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(fastFibonacci);
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
39
examples/catch2/CMakeLists.txt
Normal file
39
examples/catch2/CMakeLists.txt
Normal file
@@ -0,0 +1,39 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
# ---- Options ----
|
||||
|
||||
option(ENABLE_TEST_COVERAGE "Enable test coverage" OFF)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME fibonacci
|
||||
GIT_REPOSITORY https://github.com/TheLartians/Fibonacci.git
|
||||
VERSION 1.0
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME Catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
VERSION 2.5.0
|
||||
)
|
||||
|
||||
# ---- Create binary ----
|
||||
|
||||
add_executable(CPMExampleCatch2 main.cpp)
|
||||
target_link_libraries(CPMExampleCatch2 fibonacci Catch2)
|
||||
set_target_properties(CPMExampleCatch2 PROPERTIES CXX_STANDARD 17 COMPILE_FLAGS "-Wall -pedantic -Wextra -Werror")
|
||||
|
||||
# ---- Enable testing ----
|
||||
|
||||
ENABLE_TESTING()
|
||||
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()
|
||||
20
examples/catch2/main.cpp
Normal file
20
examples/catch2/main.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#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("fastFibonnacci"){
|
||||
for (unsigned i=0; i<25; ++i){
|
||||
REQUIRE(fibonnacci(i) == fastFibonacci(i));
|
||||
}
|
||||
}
|
||||
41
examples/doctest/CMakeLists.txt
Normal file
41
examples/doctest/CMakeLists.txt
Normal file
@@ -0,0 +1,41 @@
|
||||
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||
|
||||
# ---- Options ----
|
||||
|
||||
option(ENABLE_TEST_COVERAGE "Enable test coverage" OFF)
|
||||
|
||||
# ---- Dependencies ----
|
||||
|
||||
include(../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME fibonacci
|
||||
GIT_REPOSITORY https://github.com/TheLartians/Fibonacci.git
|
||||
VERSION 1.0
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME doctest
|
||||
GIT_REPOSITORY https://github.com/onqtam/doctest.git
|
||||
VERSION 2.3.2
|
||||
GIT_TAG 2.3.2
|
||||
GIT_SHALLOW True
|
||||
)
|
||||
|
||||
# ---- Create binary ----
|
||||
|
||||
add_executable(CPMExampleDoctest main.cpp)
|
||||
target_link_libraries(CPMExampleDoctest fibonacci doctest)
|
||||
set_target_properties(CPMExampleDoctest PROPERTIES CXX_STANDARD 17 COMPILE_FLAGS "-Wall -pedantic -Wextra -Werror")
|
||||
|
||||
# ---- Enable testing ----
|
||||
|
||||
ENABLE_TESTING()
|
||||
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()
|
||||
20
examples/doctest/main.cpp
Normal file
20
examples/doctest/main.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
#include <fibonacci.h>
|
||||
|
||||
TEST_CASE("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("fastFibonnacci"){
|
||||
for (unsigned i=0; i<25; ++i){
|
||||
CHECK(fibonnacci(i) == fastFibonacci(i));
|
||||
}
|
||||
}
|
||||
28
examples/parser-lua/CMakeLists.txt
Normal file
28
examples/parser-lua/CMakeLists.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
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)
|
||||
46
examples/parser-lua/main.cpp
Normal file
46
examples/parser-lua/main.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#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;
|
||||
}
|
||||
15
examples/parser/CMakeLists.txt
Normal file
15
examples/parser/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
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)
|
||||
57
examples/parser/main.cpp
Normal file
57
examples/parser/main.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#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;
|
||||
}
|
||||
29
examples/run_all.py
Normal file
29
examples/run_all.py
Normal file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from pathlib import Path
|
||||
from subprocess import PIPE, run
|
||||
|
||||
examples = [
|
||||
x for x in Path(__file__).parent.iterdir() if x.is_dir() and (x / 'CMakeLists.txt').exists()
|
||||
]
|
||||
|
||||
assert(len(examples) > 0)
|
||||
|
||||
def runCommand(command):
|
||||
print('- %s' % command)
|
||||
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True)
|
||||
if result.returncode != 0:
|
||||
print("error while running '%s':\n" % command, ' ' + str(result.stderr).replace('\n','\n '))
|
||||
exit(result.returncode)
|
||||
return result.stdout
|
||||
|
||||
print('')
|
||||
for example in examples:
|
||||
print("running example %s" % example.name)
|
||||
print("================" + ('=' * len(example.name)))
|
||||
project = Path(".") / 'build' / example.name
|
||||
configure = runCommand('cmake -H%s -B%s -DCMAKE_BUILD_TYPE=RelWithDebInfo' % (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]))
|
||||
print('')
|
||||
@@ -1,41 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
||||
|
||||
project(CPMTest)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME LHC
|
||||
GIT_REPOSITORY https://github.com/TheLartians/LHC.git
|
||||
VERSION 0.3
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME LarsEvent
|
||||
GIT_REPOSITORY https://github.com/TheLartians/Event.git
|
||||
VERSION 1.0
|
||||
GIT_TAG master
|
||||
)
|
||||
|
||||
# Add project that depends on previous project
|
||||
CPMAddPackage(
|
||||
NAME LarsParser
|
||||
GIT_REPOSITORY https://github.com/TheLartians/Parser.git
|
||||
VERSION 1.3
|
||||
)
|
||||
|
||||
# add project twice
|
||||
CPMAddPackage(
|
||||
NAME LHC
|
||||
GIT_REPOSITORY https://github.com/TheLartians/LHC.git
|
||||
VERSION 0.3
|
||||
)
|
||||
|
||||
# add executable
|
||||
set (CMAKE_CXX_STANDARD 17)
|
||||
add_executable(cpm-test test.cpp)
|
||||
target_link_libraries(cpm-test LHC LarsEvent LarsParser)
|
||||
|
||||
# tests
|
||||
enable_testing()
|
||||
add_test(cpm-test cpm-test)
|
||||
@@ -1,32 +0,0 @@
|
||||
#include <lars/parser_generator.h>
|
||||
#include <lars/event.h>
|
||||
|
||||
int main() {
|
||||
// Define the return value
|
||||
int result = 1;
|
||||
|
||||
// Define grammar and evaluation rules
|
||||
lars::ParserGenerator<float> g;
|
||||
g.setSeparator(g["Whitespace"] << "[\t ]");
|
||||
g["Sum" ] << "Add | Subtract | Product";
|
||||
g["Product" ] << "Multiply | Divide | Atomic";
|
||||
g["Atomic" ] << "Number | '(' Sum ')'";
|
||||
g["Add" ] << "Sum '+' Product" >> [](auto e){ return e[0].evaluate() + e[1].evaluate(); };
|
||||
g["Subtract"] << "Sum '-' Product" >> [](auto e){ return e[0].evaluate() - e[1].evaluate(); };
|
||||
g["Multiply"] << "Product '*' Atomic" >> [](auto e){ return e[0].evaluate() * e[1].evaluate(); };
|
||||
g["Divide" ] << "Product '/' Atomic" >> [](auto e){ return e[0].evaluate() / e[1].evaluate(); };
|
||||
g["Number" ] << "'-'? [0-9]+ ('.' [0-9]+)?" >> [](auto e){ return stof(e.string()); };
|
||||
g.setStart(g["Sum"]);
|
||||
|
||||
// Execute a string
|
||||
|
||||
// create an event
|
||||
lars::Event<float> onResult;
|
||||
onResult.connect([&](float v){ result = !(int(v) == 5); });
|
||||
|
||||
// emit the result of a parsed string
|
||||
onResult.notify(g.run("1 + 2 * (3+4)/2 - 3"));
|
||||
|
||||
// return the result
|
||||
return result;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
||||
|
||||
project(CPMTest)
|
||||
|
||||
# add dependencies
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME LarsParser
|
||||
GIT_REPOSITORY https://github.com/TheLartians/Parser.git
|
||||
VERSION 1.3
|
||||
)
|
||||
|
||||
# add executable
|
||||
set (CMAKE_CXX_STANDARD 17)
|
||||
add_executable(cpm-test test.cpp)
|
||||
target_link_libraries(cpm-test LarsParser)
|
||||
|
||||
# tests
|
||||
enable_testing()
|
||||
add_test(cpm-test cpm-test)
|
||||
@@ -1,27 +0,0 @@
|
||||
#include <lars/parser_generator.h>
|
||||
|
||||
int main() {
|
||||
lars::ParserGenerator<float> g;
|
||||
|
||||
// Define grammar and evaluation rules
|
||||
g.setSeparator(g["Whitespace"] << "[\t ]");
|
||||
g["Sum" ] << "Add | Subtract | Product";
|
||||
g["Product" ] << "Multiply | Divide | Atomic";
|
||||
g["Atomic" ] << "Number | '(' Sum ')'";
|
||||
g["Add" ] << "Sum '+' Product" >> [](auto e){ return e[0].evaluate() + e[1].evaluate(); };
|
||||
g["Subtract"] << "Sum '-' Product" >> [](auto e){ return e[0].evaluate() - e[1].evaluate(); };
|
||||
g["Multiply"] << "Product '*' Atomic" >> [](auto e){ return e[0].evaluate() * e[1].evaluate(); };
|
||||
g["Divide" ] << "Product '/' Atomic" >> [](auto e){ return e[0].evaluate() / e[1].evaluate(); };
|
||||
g["Number" ] << "'-'? [0-9]+ ('.' [0-9]+)?" >> [](auto e){ return stof(e.string()); };
|
||||
g.setStart(g["Sum"]);
|
||||
|
||||
// Execute a string
|
||||
float result = g.run("1 + 2 * (3+4)/2 - 3");
|
||||
|
||||
// validate result
|
||||
if (result == 5) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user