diff --git a/.github/workflows/cpp.yml b/.github/workflows/cpp.yml index 90b6c90..2385f20 100644 --- a/.github/workflows/cpp.yml +++ b/.github/workflows/cpp.yml @@ -24,14 +24,14 @@ jobs: test: needs: formatting-check - name: "Test (${{ matrix.toolchain.os }}/${{ matrix.toolchain.compiler }}, ${{ matrix.build-type }})" + name: "Test (${{ matrix.toolchain.os }}/${{ matrix.toolchain.compiler-id }}, ${{ matrix.build-type }})" strategy: fail-fast: false matrix: toolchain: - - { os: Linux, compiler: GCC, runner-label: gcc-14 } - - { os: Linux, compiler: Clang, runner-label: clang-19 } + - { os: Linux, compiler-id: GCC, runner-label: gcc-14 } + - { os: Linux, compiler-id: Clang, runner-label: clang-19 } build-type: - Release - Debug @@ -42,7 +42,7 @@ jobs: runs-on: [self-hosted, ubuntu, base, "${{ matrix.toolchain.runner-label }}"] env: - CT_CMAKE_PRESET: "CI-${{ matrix.toolchain.compiler }}-${{ matrix.build-type }}" + CT_CMAKE_PRESET: "Default-${{ matrix.build-type }}" defaults: run: diff --git a/CMakeLists.txt b/CMakeLists.txt index 8131fc3..4aff57b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,7 @@ -cmake_minimum_required(VERSION 3.21...3.31) +cmake_minimum_required(VERSION 3.24...3.31) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -include(SetupToolchain) -include(ConfigureTarget) +include(ConfigureCompiler) include(CompilerWarnings) project(template LANGUAGES CXX) @@ -12,27 +11,26 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +ct_configure_compiler() +include(Dependencies) + # Setup a 'solution' target file(GLOB SOLUTION_SRC CONFIGURE_DEPENDS src/*.cpp src/*.h) add_library(solution ${SOLUTION_SRC}) target_include_directories(solution PUBLIC src) set_target_properties(solution PROPERTIES LINKER_LANGUAGE CXX) -ct_configure_target(solution) +ct_set_compiler_warnings(solution) # Setup a 'tests' target file(GLOB TESTS_SRC CONFIGURE_DEPENDS test/*.cpp test/*.h) add_executable(tests ${TESTS_SRC}) target_include_directories(tests PRIVATE test) -ct_configure_target(tests) +ct_set_compiler_warnings(tests) # Link tests with solution target_link_libraries(tests PRIVATE solution) # Link tests with dependencies -find_package(Catch2 REQUIRED) +find_package(Catch2 CONFIG REQUIRED) target_link_libraries(tests PRIVATE Catch2::Catch2WithMain) -# Enable warnings -option(CT_TREAT_WARNINGS_AS_ERRORS "Treat warnings as errors" OFF) -ct_set_compiler_warnings(solution ${CT_TREAT_WARNINGS_AS_ERRORS}) -ct_set_compiler_warnings(tests ${CT_TREAT_WARNINGS_AS_ERRORS}) diff --git a/CMakePresets.json b/CMakePresets.json index b2eefd4..ca6cb0b 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -52,78 +52,6 @@ "cacheVariables": { "CT_SANITIZED": "ON" } - }, - { - "name": "CI-Linux", - "description": "Base preset for CI builds on Linux", - "hidden": true, - "inherits": "Base", - "cacheVariables": { - "CT_TRIPLET_TEMPLATE": "${sourceDir}/cmake/vcpkg-triplet-templates/ct-x64-linux.cmake.in", - "CT_TOOLCHAIN_TEMPLATE": "${sourceDir}/cmake/toolchain-templates/ci.cmake.in" - } - }, - { - "name": "CI-GCC", - "description": "Base preset for Linux/GCC CI builds", - "hidden": true, - "inherits": "CI-Linux", - "cacheVariables": { - "CT_C_EXE": "gcc-14", - "CT_CXX_EXE": "gcc-14", - "CT_COMPILER_ID": "GNU" - } - }, - { - "name": "CI-Clang", - "description": "Base preset for Linux/Clang CI builds", - "hidden": true, - "inherits": "CI-Linux", - "cacheVariables": { - "CT_C_EXE": "clang-19", - "CT_CXX_EXE": "clang++-19", - "CT_COMPILER_ID": "Clang" - } - }, - { - "name": "CI-GCC-Release", - "inherits": ["CI-GCC", "Default-Release"] - }, - { - "name": "CI-GCC-Debug", - "inherits": ["CI-GCC", "Default-Debug"] - }, - { - "name": "CI-GCC-RelWithDebInfo", - "inherits": ["CI-GCC", "Default-RelWithDebInfo"] - }, - { - "name": "CI-GCC-Sanitized", - "inherits": ["CI-GCC", "Default-Sanitized"] - }, - { - "name": "CI-GCC-SanitizedDebug", - "inherits": ["CI-GCC", "Default-SanitizedDebug"] - }, - { - "name": "CI-Clang-Release", - "inherits": ["CI-Clang", "Default-Release"] - }, - { - "name": "CI-Clang-Debug", - "inherits": ["CI-Clang", "Default-Debug"] - }, - { - "name": "CI-Clang-RelWithDebInfo", - "inherits": ["CI-Clang", "Default-RelWithDebInfo"] - }, - { - "name": "CI-Clang-Sanitized", - "inherits": ["CI-Clang", "Default-Sanitized"] - }, - { - "name": "CI-Clang-SanitizedDebug", - "inherits": ["CI-Clang", "Default-SanitizedDebug"] } ] } diff --git a/cmake/CompilerWarnings.cmake b/cmake/CompilerWarnings.cmake index 52d90f9..126d693 100644 --- a/cmake/CompilerWarnings.cmake +++ b/cmake/CompilerWarnings.cmake @@ -1,4 +1,6 @@ -function(ct_set_compiler_warnings TARGET TREAT_WARNINGS_AS_ERRORS) +option(CT_TREAT_WARNINGS_AS_ERRORS "Treat warnings as errors" OFF) + +function(ct_set_compiler_warnings TARGET) set(GCC_CLANG_COMMON_WARNINGS -Wall -Wextra # baseline reasonable and standard warnings @@ -30,7 +32,7 @@ function(ct_set_compiler_warnings TARGET TREAT_WARNINGS_AS_ERRORS) set(MSVC_WARNINGS /W4 /permissive-) - if(TREAT_WARNINGS_AS_ERRORS) + if(CT_TREAT_WARNINGS_AS_ERRORS) message(STATUS "Warnings are treated as errors") list(APPEND GCC_WARNINGS -Werror -pedantic-errors) list(APPEND CLANG_WARNINGS -Werror -pedantic-errors) diff --git a/cmake/ConfigureCompiler.cmake b/cmake/ConfigureCompiler.cmake index 84723c0..8a22055 100644 --- a/cmake/ConfigureCompiler.cmake +++ b/cmake/ConfigureCompiler.cmake @@ -1,65 +1,67 @@ -function(ct_set_compiler C_EXE CXX_EXE) - find_program(C_EXE_PATH "${C_EXE}") - find_program(CXX_EXE_PATH "${CXX_EXE}") +option(CT_HARDENED "Should the standard library be hardened" OFF) +option(CT_SANITIZED "Should the build be sanitized" OFF) - if(NOT C_EXE_PATH OR NOT CXX_EXE_PATH) - message(FATAL_ERROR "Could not find a requested compiler (C_EXE=${C_EXE}, CXX_EXE=${CXX_EXE})") - endif() - - set(CMAKE_C_COMPILER "${C_EXE_PATH}") - set(CMAKE_CXX_COMPILER "${CXX_EXE_PATH}") -endfunction() +function(ct_configure_compiler) -function(ct_configure_compiler COMPILER_ID HARDENED SANITIZED STABLE_ABI) - set(IS_GCC OFF) - set(IS_CLANG OFF) + set(isGCC OFF) + set(isClang OFF) + set(isMSVC OFF) - if(COMPILER_ID STREQUAL "GNU") - set(IS_GCC ON) - elseif(COMPILER_ID MATCHES "Clang") - set(IS_CLANG ON) + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(isGCC ON) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(isClang ON) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(isMSVC ON) endif() - set(CT_COMPILER_FLAGS "") - set(CT_LINKER_FLAGS "") + set(compilerOptions "") + set(compilerDefinitions "") + set(linkerOptions "") - if(IS_CLANG AND NOT STABLE_ABI) - set(CT_COMPILER_FLAGS "${CT_COMPILER_FLAGS} -stdlib=libc++") - set(CT_LINKER_FLAGS "${CT_LINKER_FLAGS} -stdlib=libc++") + if(isClang) + list(APPEND compilerOptions -stdlib=libc++) + list(APPEND linkerOptions -stdlib=libc++) message(STATUS "Using libc++ as a standard library") endif() - if(HARDENED AND NOT STABLE_ABI) - if(IS_GCC) - set(CT_COMPILER_FLAGS "${CT_COMPILER_FLAGS} -D_GLIBCXX_DEBUG") + if(CT_HARDENED) + if(isGCC) + list(APPEND compilerDefinitions _GLIBCXX_DEBUG) message(STATUS "Enabled debug mode for libstdc++") - elseif(IS_CLANG) - set(CT_COMPILER_FLAGS "${CT_COMPILER_FLAGS} -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG") + elseif(isClang) + list(APPEND compilerDefinitions _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG) message(STATUS "Enabled hardening mode for libc++") else() - message(WARNING "Hardening is not supported for CXX compiler: '${COMPILER_ID}'") + # TODO: https://github.com/microsoft/STL/wiki/STL-Hardening + message(STATUS "Hardening is not supported for CXX compiler: '${COMPILER_ID}'") endif() endif() - if(SANITIZED) - if(IS_GCC OR IS_CLANG) - set(CT_COMPILER_FLAGS "${CT_COMPILER_FLAGS} -fsanitize=undefined,address") - set(CT_LINKER_FLAGS "${CT_LINKER_FLAGS} -fsanitize=undefined,address") - string(JOIN " " CT_COMPILER_FLAGS - "${CT_COMPILER_FLAGS}" - "-fno-sanitize-recover=all" - "-fno-optimize-sibling-calls" - "-fno-omit-frame-pointer" + if(CT_SANITIZED) + if(isGCC OR isClang) + list(APPEND compilerOptions -fsanitize=undefined,address) + list(APPEND linkerOptions -fsanitize=undefined,address) + list(APPEND compilerOptions + -fno-sanitize-recover=all + -fno-optimize-sibling-calls + -fno-omit-frame-pointer ) message(STATUS "Enabled UBSan and ASan") + elseif(isMSVC) + list(APPEND compilerOptions /fsanitize=address) + message(STATUS "Enabled ASan") else() message(WARNING "Sanitized builds are not supported for CXX compiler: '${COMPILER_ID}'") endif() endif() - message(STATUS "New compiler flags: ${CT_COMPILER_FLAGS}") - message(STATUS "New linker flags: ${CT_LINKER_FLAGS}") + message(STATUS "Setting global compiler options: ${compilerOptions}") + message(STATUS "Setting global compiler definitions: ${compilerDefinitions}") + message(STATUS "Setting global linker options: ${linkerOptions}") + + add_compile_options(${compilerOptions}) + add_compile_definitions(${compilerDefinitions}) + add_link_options(${linkerOptions}) - set(CT_COMPILER_FLAGS ${CT_COMPILER_FLAGS} PARENT_SCOPE) - set(CT_LINKER_FLAGS ${CT_LINKER_FLAGS} PARENT_SCOPE) endfunction() diff --git a/cmake/ConfigureTarget.cmake b/cmake/ConfigureTarget.cmake deleted file mode 100644 index 874b1af..0000000 --- a/cmake/ConfigureTarget.cmake +++ /dev/null @@ -1,15 +0,0 @@ -function(ct_configure_target TARGET) - if(CT_COMPILER_FLAGS OR CT_LINKER_FLAGS) - message(STATUS "No need to configure '${TARGET}': Using global toolchain options") - return() - endif() - - include(ConfigureCompiler) - ct_configure_compiler("${CMAKE_CXX_COMPILER_ID}" "${CT_HARDENED}" "${CT_SANITIZED}" ON) - - separate_arguments(CT_COMPILER_FLAGS) - separate_arguments(CT_LINKER_FLAGS) - - target_compile_options("${TARGET}" PRIVATE ${CT_COMPILER_FLAGS}) - target_link_options("${TARGET}" PRIVATE ${CT_LINKER_FLAGS}) -endfunction() diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake new file mode 100644 index 0000000..fc94917 --- /dev/null +++ b/cmake/Dependencies.cmake @@ -0,0 +1,9 @@ +include(FetchContent) + +message(STATUS "Fetching Catch2...") +FetchContent_Declare( + Catch2 + URL https://github.com/catchorg/Catch2/archive/refs/tags/v3.8.0.tar.gz + FIND_PACKAGE_ARGS +) +FetchContent_MakeAvailable(Catch2) diff --git a/cmake/FetchVcpkg.cmake b/cmake/FetchVcpkg.cmake deleted file mode 100644 index d523eaa..0000000 --- a/cmake/FetchVcpkg.cmake +++ /dev/null @@ -1,48 +0,0 @@ -include(FetchContent) - -option(CT_FETCH_VCPKG "Should the vcpkg be fetched via FetchContent" ON) - -function(ct_fetch_vcpkg) - if(PROJECT_NAME) - message(FATAL_ERROR "ct_fetch_vcpkg must be run before the first project directive") - endif() - - if(NOT CT_FETCH_VCPKG) - message(STATUS "Skipped fetching vcpkg because CT_FETCH_VCPKG=OFF") - return() - endif() - - if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg.cmake$") - message(STATUS "Skipped fetching vcpkg because CMAKE_TOOLCHAIN_FILE is already set to vcpkg.cmake") - return() - endif() - - message(STATUS "Fetching vcpkg...") - FetchContent_Declare( - vcpkg - URL https://github.com/microsoft/vcpkg/archive/refs/tags/2025.02.14.tar.gz - ) - FetchContent_MakeAvailable(vcpkg) - - set(VCPKG_BOOTSTRAP_OPTIONS "-disableMetrics" CACHE STRING "") - - if(CMAKE_TOOLCHAIN_FILE) - set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" CACHE FILEPATH "") - endif() - set(CMAKE_TOOLCHAIN_FILE "${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake" - CACHE FILEPATH "Vcpkg toolchain file" FORCE) - - if(CT_TRIPLET_TEMPLATE) - cmake_path(GET CT_TRIPLET_TEMPLATE STEM CT_TRIPLET_NAME) - - configure_file( - "${CT_TRIPLET_TEMPLATE}" - "${CMAKE_BINARY_DIR}/vcpkg-triplets/${CT_TRIPLET_NAME}.cmake" - @ONLY - ) - message(STATUS "Generated a vcpkg triplet '${CT_TRIPLET_NAME}' from template") - - set(VCPKG_TARGET_TRIPLET "${CT_TRIPLET_NAME}" CACHE FILEPATH "") - set(VCPKG_OVERLAY_TRIPLETS "${CMAKE_BINARY_DIR}/vcpkg-triplets" CACHE FILEPATH "") - endif() -endfunction() diff --git a/cmake/GenerateToolchain.cmake b/cmake/GenerateToolchain.cmake deleted file mode 100644 index 67c52a5..0000000 --- a/cmake/GenerateToolchain.cmake +++ /dev/null @@ -1,25 +0,0 @@ -option(CT_HARDENED "Should the standard library be hardened" OFF) -option(CT_SANITIZED "Should the build be sanitized" OFF) - -function(ct_gen_toolchain) - if(PROJECT_NAME) - message(FATAL_ERROR "ct_gen_toolchain must be run before the first project directive") - endif() - - if(NOT CT_TOOLCHAIN_TEMPLATE) - return() - endif() - - if(CMAKE_TOOLCHAIN_FILE) - message(STATUS "Skipped generating toolchain file because CMAKE_TOOLCHAIN_FILE is already set") - return() - endif() - - cmake_path(GET CT_TOOLCHAIN_TEMPLATE STEM CT_TOOLCHAIN_NAME) - set(CT_GENERATED_TOOLCHAIN "${CMAKE_BINARY_DIR}/toolchains/${CT_TOOLCHAIN_NAME}.cmake") - - configure_file("${CT_TOOLCHAIN_TEMPLATE}" "${CT_GENERATED_TOOLCHAIN}" @ONLY) - message(STATUS "Generated a toolchain '${CT_TOOLCHAIN_NAME}' from template") - - set(CMAKE_TOOLCHAIN_FILE "${CT_GENERATED_TOOLCHAIN}" CACHE FILEPATH "") -endfunction() diff --git a/cmake/SetupToolchain.cmake b/cmake/SetupToolchain.cmake deleted file mode 100644 index e668b23..0000000 --- a/cmake/SetupToolchain.cmake +++ /dev/null @@ -1,5 +0,0 @@ -include(GenerateToolchain) -include(FetchVcpkg) - -ct_gen_toolchain() -ct_fetch_vcpkg() diff --git a/cmake/toolchain-templates/ci.cmake.in b/cmake/toolchain-templates/ci.cmake.in deleted file mode 100644 index b82ee19..0000000 --- a/cmake/toolchain-templates/ci.cmake.in +++ /dev/null @@ -1,12 +0,0 @@ -include("@CMAKE_SOURCE_DIR@/cmake/ConfigureCompiler.cmake") - -ct_set_compiler("@CT_C_EXE@" "@CT_CXX_EXE@") -ct_configure_compiler("@CT_COMPILER_ID@" "@CT_HARDENED" "@CT_SANITIZED@" OFF) - -set(CMAKE_C_FLAGS "${CT_COMPILER_FLAGS}" CACHE STRING "") -set(CMAKE_CXX_FLAGS "${CT_COMPILER_FLAGS}" CACHE STRING "") - -foreach(linker IN ITEMS "SHARED" "MODULE" "EXE") - set(CMAKE_${linker}_LINKER_FLAGS_INIT "${CT_LINKER_FLAGS}" CACHE STRING "") - set(CMAKE_${linker}_LINKER_FLAGS "${CT_LINKER_FLAGS}" CACHE STRING "") -endforeach() diff --git a/cmake/vcpkg-triplet-templates/ct-x64-linux.cmake.in b/cmake/vcpkg-triplet-templates/ct-x64-linux.cmake.in deleted file mode 100644 index 764062d..0000000 --- a/cmake/vcpkg-triplet-templates/ct-x64-linux.cmake.in +++ /dev/null @@ -1,7 +0,0 @@ -set(VCPKG_TARGET_ARCHITECTURE x64) -set(VCPKG_CRT_LINKAGE dynamic) -set(VCPKG_LIBRARY_LINKAGE static) - -set(VCPKG_CMAKE_SYSTEM_NAME Linux) - -set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "@VCPKG_CHAINLOAD_TOOLCHAIN_FILE@") diff --git a/vcpkg.json b/vcpkg.json deleted file mode 100644 index 4a35f54..0000000 --- a/vcpkg.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "example", - "version-string": "0.0.1", - "dependencies": [ - "catch2" - ] -}