From 1dc64084ebd3200627beec25875ff969de42184d Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Tue, 14 Apr 2020 13:59:38 +0200 Subject: [PATCH] Add optional standalone executable directory (#2) * add standalone executable * update readme * add standalone workflow * fix path --- .github/workflows/standalone.yml | 20 ++++++++++++++ CMakeLists.txt | 1 - README.md | 34 ++++++++++++++++------- standalone/CMakeLists.txt | 31 +++++++++++++++++++++ standalone/source/main.cpp | 46 ++++++++++++++++++++++++++++++++ 5 files changed, 122 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/standalone.yml create mode 100644 standalone/CMakeLists.txt create mode 100644 standalone/source/main.cpp diff --git a/.github/workflows/standalone.yml b/.github/workflows/standalone.yml new file mode 100644 index 0000000..7053659 --- /dev/null +++ b/.github/workflows/standalone.yml @@ -0,0 +1,20 @@ +name: Standalone + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + + - name: configure + run: cmake -Hstandalone -Bbuild + + - name: build + run: cmake --build build + + - name: run + run: ./build/Greeter diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bcbaed..7dacd37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,6 @@ CPMAddPackage( # Note: # for single header libraries use `add_library(Greeter INTERFACE)` instead -# To create an executable use `add_executable(Greeter ${headers} ${sources})` add_library(Greeter ${headers} ${sources}) # Note: for single header libraries use the following instead: diff --git a/README.md b/README.md index 3a58866..09ef3bf 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,8 @@ This template is a collection from learnings of previous projects and should all ## Features - Modern CMake practices -- Suited for single header libraries and larger projects +- Suited for single header libraries and projects of any scale +- Separation into library and executable code - Integrated test suite - Continuous integration via [GitHub Actions](https://help.github.com/en/actions/) - Code coverage via [codecov](https://codecov.io) @@ -27,22 +28,35 @@ This template is a collection from learnings of previous projects and should all ### Adjust the template to your needs -- Use this repo [as a template](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-from-a-template) and replace all occurrences of "Greeter" in [both](test/CMakeLists.txt) [CMakeLists.txt](CMakeLists.txt) with the name of your project +- Use this repo [as a template](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-from-a-template) and replace all occurrences of "Greeter" in the relevant CMakeLists.txt with the name of your project - Replace the source files with your own - For single-header libraries: see the comments in [CMakeLists.txt](CMakeLists.txt) - Add your project's codecov token to your project's github secrets under `CODECOV_TOKEN` - Happy coding! +Remember to eventually remove any unused files, such as the standalone directory or irrelevant tests for your project. + +### Build and run the standalone target + +Use the following command to build and run the executable target. + +```bash +cmake -Hstandalone -Bbuild/standalone +cmake --build build/standalone +./build/standalone/Greeter --help +``` + ### Build and run test suite Use the following commands from the project's root directory to run the test suite. ```bash -cmake -Htest -Bbuild -cmake --build build -CTEST_OUTPUT_ON_FAILURE=1 cmake --build build --target test +cmake -Htest -Bbuild/test +cmake --build build/test +CTEST_OUTPUT_ON_FAILURE=1 cmake --build build/test --target test + # or simply call the executable: -./build/GreeterTests +./build/test/GreeterTests ``` To collect code coverage information, run CMake with the `-DENABLE_TEST_COVERAGE=1` option. @@ -52,11 +66,13 @@ To collect code coverage information, run CMake with the `-DENABLE_TEST_COVERAGE Use the following commands from the project's root directory to run clang-format (must be installed on the host system). ```bash -cmake -Htest -Bbuild +cmake -Htest -Bbuild/test + # view changes -cmake --build build --target format +cmake --build build/test --target format + # apply changes -cmake --build build --target fix-format +cmake --build build/test --target fix-format ``` See [Format.cmake](https://github.com/TheLartians/Format.cmake) for more options. diff --git a/standalone/CMakeLists.txt b/standalone/CMakeLists.txt new file mode 100644 index 0000000..a00e2e9 --- /dev/null +++ b/standalone/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) + +project(GreeterStandalone + LANGUAGES CXX +) + +# ---- Dependencies ---- + +include(../cmake/CPM.cmake) + +CPMAddPackage( + NAME cxxopts + GITHUB_REPOSITORY jarro2783/cxxopts + VERSION 2.2.0 + OPTIONS + "CXXOPTS_BUILD_EXAMPLES Off" + "CXXOPTS_BUILD_TESTS Off" +) + +CPMAddPackage( + NAME Greeter + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/.. +) + +# ---- Create standalone executable ---- + +file(GLOB sources ${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp) +add_executable(GreeterStandalone ${sources}) +set_target_properties(GreeterStandalone PROPERTIES CXX_STANDARD 17 COMPILE_FLAGS "-Wall -pedantic -Wextra") +set_target_properties(GreeterStandalone PROPERTIES OUTPUT_NAME "Greeter") +target_link_libraries(GreeterStandalone Greeter cxxopts) diff --git a/standalone/source/main.cpp b/standalone/source/main.cpp new file mode 100644 index 0000000..70460ef --- /dev/null +++ b/standalone/source/main.cpp @@ -0,0 +1,46 @@ +#include + +#include +#include +#include +#include + +const std::unordered_map languages{ + {"en", greeter::LanguageCode::EN}, + {"de", greeter::LanguageCode::DE}, + {"es", greeter::LanguageCode::ES}, + {"fr", greeter::LanguageCode::FR}, +}; + +int main(int argc, char** argv) { + cxxopts::Options options(argv[0], "A program to welcome the world!"); + + std::string language; + std::string name; + + // clang-format off + options.add_options() + ("h,help", "Show help") + ("n,name", "Name to greet", cxxopts::value(name)->default_value("World")) + ("l,lang", "Language code to use", cxxopts::value(language)->default_value("en")) + ; + // clang-format on + + auto result = options.parse(argc, argv); + + if (result["help"].as()) { + std::cout << options.help() << std::endl; + return 0; + } + + auto langIt = languages.find(language); + if (langIt == languages.end()) { + std::cout << "unknown language code: " << language << std::endl; + return 1; + } + + greeter::Greeter greeter(name); + std::cout << greeter.greet(langIt->second) << std::endl; + + return 0; +}