diff --git a/.cmake-format.yaml b/.cmake-format.yaml new file mode 100644 index 0000000..8606e38 --- /dev/null +++ b/.cmake-format.yaml @@ -0,0 +1,7 @@ +format: + line_width: 100 + tab_size: 4 + use_tabchars: false + max_subgroups_hwrap: 3 + max_pargs_hwrap: 3 + dangle_parens: true diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..e656eab --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @Coding-Cuddles/kata-maintainers diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..ca79ca5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..e3e3855 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,29 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v7 + + - name: Check formatting + run: make format-check + + test: + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v7 + + - name: Test + run: make test diff --git a/.gitignore b/.gitignore index 7e24f01..ae1801a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ +build +cmake-build-* +.cache .ccls-cache -compile_commands.json \ No newline at end of file +compile_commands.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 7fcc7d5..4133f06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,26 +1,45 @@ -cmake_minimum_required(VERSION 3.19) +cmake_minimum_required(VERSION 3.24) project(bootstrap-cpp-catch2 CXX) -enable_testing() set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_COLOR_DIAGNOSTICS ON) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) -find_package(Catch2 REQUIRED) +include(FetchCatch2) +fetch_catch2() + +enable_testing() add_executable(main main.cpp) +add_custom_target( + run + COMMAND $ + DEPENDS main + COMMENT "Running main executable" + USES_TERMINAL +) file(GLOB tests test_*.cpp) foreach(test ${tests}) get_filename_component(name ${test} NAME_WE) add_executable(${name} ${test}) - add_test(${name} ${name}) target_link_libraries(${name} PRIVATE Catch2::Catch2) + add_test(NAME ${name} COMMAND ${name}) endforeach() -add_custom_target( - copy-compile-commands ALL - ${CMAKE_COMMAND} -E copy_if_different - ${CMAKE_BINARY_DIR}/compile_commands.json - ${CMAKE_CURRENT_LIST_DIR} -) +if(UNIX) + add_custom_target( + copy-compile-commands ALL + ${CMAKE_COMMAND} + -E + copy_if_different + ${CMAKE_BINARY_DIR}/compile_commands.json + ${CMAKE_CURRENT_LIST_DIR} + COMMENT "Copying compile commands to the source directory" + ) +endif() diff --git a/Makefile b/Makefile index 2e7e90b..41db543 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,50 @@ -all: build +COLOR_CYAN := \033[36m +COLOR_RESET := \033[0m -export CXX := clang++ -BUILDDIR ?= /tmp/build +CLICOLOR ?= 1 +export CLICOLOR + +BUILDDIR ?= build +BUILDCONFIG ?= Debug +SRCS := $(shell git ls-files '*.cpp' '*.h' '*.hpp') + +.DEFAULT_GOAL := help + +.PHONY: all +all: test ## Build and run tests + +.PHONY: help +help: ## Show this help message + @awk 'BEGIN {FS = ":.*##"; printf "Usage: make [options] $(COLOR_CYAN)[target] ...$(COLOR_RESET)\n\n"} \ + /^[a-zA-Z_-]+:.*##/ {printf " $(COLOR_CYAN)%-20s$(COLOR_RESET) %s\n", $$1, $$2}' \ + $(MAKEFILE_LIST) .PHONY: build -build: - cmake -B ${BUILDDIR} -G Ninja . - cmake --build ${BUILDDIR} +build: ## Configure and build + cmake -S . -B ${BUILDDIR} -DCMAKE_BUILD_TYPE=${BUILDCONFIG} + cmake --build ${BUILDDIR} --config ${BUILDCONFIG} .PHONY: run -run: - cd ${BUILDDIR} && ./main +run: build ## Build and run main + cmake --build ${BUILDDIR} --config ${BUILDCONFIG} --target run .PHONY: test -test: - ctest --output-on-failure --test-dir ${BUILDDIR} +test: build ## Build and run tests + ctest --test-dir ${BUILDDIR} --build-config ${BUILDCONFIG} --output-on-failure + +.PHONY: format +format: ## Format C++ sources in place + clang-format -i -style=file $(SRCS) + +.PHONY: format-check +format-check: ## Fail if C++ sources require formatting + clang-format -style=file --dry-run -Werror $(SRCS) \ + || (echo "Some files require formatting. Run 'make format' to fix." && exit 1) .PHONY: clean -clean: - rm -rf ${BUILDDIR} +clean: ## Remove generated build artifacts + rm -rf ${BUILDDIR} compile_commands.json -ifndef VERBOSE +ifneq ($(VERBOSE),1) .SILENT: endif diff --git a/README.md b/README.md index a3f630b..7caae2a 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,85 @@ # Bootstrap for C++ katas -[![Replit](https://img.shields.io/badge/Try%20with%20Replit-black?logo=replit)](https://replit.com/new/github/Coding-Cuddles/bootstrap-cpp-catch2) +[![CI](https://github.com/Coding-Cuddles/bootstrap-cpp-catch2/actions/workflows/main.yml/badge.svg)](https://github.com/Coding-Cuddles/bootstrap-cpp-catch2/actions/workflows/main.yml) +[![C++17](https://img.shields.io/badge/C%2B%2B-17-blue.svg)](https://en.cppreference.com/w/cpp/17) +[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) + +Start a C++17 coding kata with Catch2 v2. Setup is complete when the starter +test passes. ## Overview This is a bootstrap repository for clean code katas in C++17 using Catch2. -## Usage +## Prerequisites + +Required: + +- [Git](https://git-scm.com/downloads) +- A compiler with C++17 support. Choose one: + - [GCC](https://gcc.gnu.org/) 10+ on Linux + - [LLVM Clang](https://llvm.org/) 14+ on Linux + - [Apple Clang](https://developer.apple.com/xcode/) 17+ on macOS + - [MSVC](https://visualstudio.microsoft.com/) 2022 on Windows +- [CMake 3.24 or later](https://cmake.org) + +Optional: + +- [GNU Make](https://www.gnu.org/software/make/), for shorter commands. Every + required task also has direct CMake and CTest commands. Make may be + unavailable on Windows. + +You do not need to install Catch2 separately. CMake finds an installed Catch2 +v2 package or downloads the pinned v2.13.10 release when needed. + +## Set up the kata + +1. Clone the repository: + + ```console + git clone https://github.com/Coding-Cuddles/bootstrap-cpp-catch2.git + ``` + +2. Enter the repository directory: + + ```console + cd bootstrap-cpp-catch2 + ``` + +3. Run the starter test. Use Make when it is installed: -You can import this project into [Replit](https://replit.com), and it will -handle all dependencies automatically. + ```console + make test + ``` -### Prerequisites + Otherwise, use CMake and CTest directly: -* [CMake 3.19+](https://cmake.org) -* [Ninja](https://ninja-build.org) -* [Catch2](https://github.com/catchorg/Catch2) + ```console + cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug + cmake --build build --config Debug + ctest --test-dir build --build-config Debug --output-on-failure + ``` -### Build +The first run may download and build Catch2. CTest should report +`100% tests passed`. -```console -make -``` +If a command reports a missing compiler or CMake, install that prerequisite +and run the setup commands again. -### Run main +Setup is complete when CTest reports `100% tests passed`. -```console -make run -``` +## Make command reference -### Run tests +Make is optional. Run `make` or `make help` to list these commands in the +terminal. -```console -make test -``` +| Command | Result | +| ------------------- | ----------------------------------------- | +| `make all` | Build and run the test suite | +| `make help` | Show the Make command reference | +| `make build` | Configure and build without running tests | +| `make run` | Build and run the main executable | +| `make test` | Build and run the test suite | +| `make format` | Format tracked C++ and header files | +| `make format-check` | Check formatting without changing files | +| `make clean` | Remove generated build artifacts | diff --git a/cmake/FetchCatch2.cmake b/cmake/FetchCatch2.cmake new file mode 100644 index 0000000..0a5d6e9 --- /dev/null +++ b/cmake/FetchCatch2.cmake @@ -0,0 +1,26 @@ +include(FetchContent) + +# Find an installed Catch2 v2 package or fetch and verify the pinned release +function(fetch_catch2) + string( + CONCAT + catch2_url + "https://github.com/catchorg/Catch2/archive/refs/tags/" + "v2.13.10.tar.gz" + ) + set( + catch2_sha256 + d54a712b7b1d7708bc7a819a8e6e47b2fde9536f487b89ccbca295072a7d9943 + ) + + FetchContent_Declare( + Catch2 + URL ${catch2_url} + URL_HASH SHA256=${catch2_sha256} + DOWNLOAD_EXTRACT_TIMESTAMP + FALSE + FIND_PACKAGE_ARGS + 2...<3 + ) + FetchContent_MakeAvailable(Catch2) +endfunction()