diff --git a/.distro/plans/ctest.fmf b/.distro/plans/ctest.fmf index 2ea3895..d7bc2ba 100644 --- a/.distro/plans/ctest.fmf +++ b/.distro/plans/ctest.fmf @@ -1,7 +1,17 @@ -summary: - Test the bundled ctests +summary: Test the bundled ctests + +prepare: + - how: install + package: + - cmake + - gcc-c++ + - git + - cmake(Catch2) + - pkgconf + discover+: how: fmf - path: test + path: . + test: /test/ctest execute: how: tmt diff --git a/.distro/plans/main.fmf b/.distro/plans/main.fmf new file mode 100644 index 0000000..26cc581 --- /dev/null +++ b/.distro/plans/main.fmf @@ -0,0 +1,7 @@ +adjust+: + # Cannot use initiator: fedora-ci reliably yet + when: initiator is not defined or initiator != packit + discover+: + how: fmf + dist-git-source: true + dist-git-extract: json-type-*/ diff --git a/.distro/plans/main.fmf.dist-git b/.distro/plans/main.fmf.dist-git deleted file mode 100644 index 795b207..0000000 --- a/.distro/plans/main.fmf.dist-git +++ /dev/null @@ -1,4 +0,0 @@ -discover: - how: fmf - dist-git-source: true - dist-git-extract: cmake-template-*/ diff --git a/.distro/plans/rpminspect.fmf b/.distro/plans/rpminspect.fmf index 59e9b24..c89abfe 100644 --- a/.distro/plans/rpminspect.fmf +++ b/.distro/plans/rpminspect.fmf @@ -3,3 +3,12 @@ plan: url: https://github.com/packit/tmt-plans ref: main name: /plans/rpminspect +environment: + # upstream is excluded here because it triggers "Unexpected changed source archive content" + # This happens when the released version already contains the package version: + # https://github.com/packit/tmt-plans/issues/13 + RPMINSPECT_EXCLUDE: metadata,upstream +adjust: + when: distro >= fedora-41 + because: Recently rpminspect fails to get the distro-tag + enabled: false diff --git a/.distro/plans/rpmlint.fmf b/.distro/plans/rpmlint.fmf index aac0154..1d28ff9 100644 --- a/.distro/plans/rpmlint.fmf +++ b/.distro/plans/rpmlint.fmf @@ -1,5 +1,10 @@ -plan: - import: - url: https://github.com/packit/tmt-plans - ref: main - name: /plans/rpmlint +prepare: + - how: shell + script: cp ./*.rpmlintrc $TMT_PLAN_DATA/ +discover: + how: fmf + filter: "tag: rpmlint" + url: https://github.com/packit/tmt-plans + ref: main +execute: + how: tmt diff --git a/test/.fmf/version b/.fmf/version similarity index 100% rename from test/.fmf/version rename to .fmf/version diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..5ae283e --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "packageRules": [ + { + "groupName": "CI and devDependencies", + "matchManagers": ["github-actions", "pre-commit", "pep621"] + } + ], + "separateMajorMinor": false, + "extends": [ + "config:recommended", + ":dependencyDashboard", + "schedule:weekly", + ":enablePreCommit", + ":semanticCommitTypeAll(chore)" + ] +} diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7016465..d7c3c62 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -38,13 +38,15 @@ jobs: name: ๐Ÿ‘€ coverage needs: [ tests ] uses: ./.github/workflows/step_coverage.yaml + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} if: github.event_name != 'schedule' static-analysis: needs: [ pre-commit ] uses: ./.github/workflows/step_static-analysis.yaml secrets: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }} if: github.event_name != 'schedule' pass: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 28136fb..c32eaaf 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -18,13 +18,6 @@ jobs: with: mask-experimental: true - # Normally this is unnecessary, but for sonarcloud, this tags the new version - static-analysis: - needs: [ pre-commit ] - uses: ./.github/workflows/step_static-analysis.yaml - secrets: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - docs: name: ๐Ÿ“˜ docs needs: [ pre-commit ] @@ -32,7 +25,7 @@ jobs: tests-pass: name: โœ… Pass - needs: [ pre-commit, tests, static-analysis, docs ] + needs: [ pre-commit, tests, docs ] runs-on: ubuntu-latest steps: - name: Check all CI jobs diff --git a/.github/workflows/step_coverage.yaml b/.github/workflows/step_coverage.yaml index dd3c216..59a4aa1 100644 --- a/.github/workflows/step_coverage.yaml +++ b/.github/workflows/step_coverage.yaml @@ -2,6 +2,10 @@ name: ๐Ÿ‘€ coverage on: workflow_call: + secrets: + CODECOV_TOKEN: + description: Codecov token of the main repository + required: false permissions: contents: read @@ -16,14 +20,14 @@ jobs: steps: - uses: actions/checkout@v4 - uses: lukka/get-cmake@latest - - name: Run CMake configuration for ${{ matrix.toolchain }} toolchain - uses: lukka/run-cmake@v10.3 + - uses: lukka/run-cmake@v10.3 with: workflowPreset: coverage-${{ matrix.coverage }} - - name: Get lcov data - uses: danielealbano/lcov-action@v3 - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + - uses: threeal/gcovr-action@xml-out with: - files: coverage.info + xml-out: coverage.xml + - uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: coverage.xml flags: ${{ matrix.coverage }}-tests diff --git a/.github/workflows/step_static-analysis.yaml b/.github/workflows/step_static-analysis.yaml index 19446c0..f6a3869 100644 --- a/.github/workflows/step_static-analysis.yaml +++ b/.github/workflows/step_static-analysis.yaml @@ -3,35 +3,17 @@ name: static-analysis on: workflow_call: secrets: - SONAR_TOKEN: + QODANA_TOKEN: required: true jobs: - sonar-cloud: - name: SonarCloud + qodana: + name: Qodana runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: WyriHaximus/github-action-get-previous-tag@v1 - id: git-tag - with: - prefix: v - - name: Install sonar-scanner and build-wrapper - uses: SonarSource/sonarcloud-github-c-cpp@v2 - - uses: lukka/get-cmake@latest - - name: Run CMake configuration for ${{ matrix.toolchain }} toolchain - uses: lukka/run-cmake@v10.3 - with: - workflowPreset: coverage-all - - name: Convert output to sonarqube - run: pipx run gcovr --sonarqube > coverage.xml - - name: Run sonar-scanner + - uses: JetBrains/qodana-action@v2024.1 env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: > - sonar-scanner - --define sonar.cfamily.compile-commands=$(echo cmake-build-*)/compile_commands.json - --define sonar.coverageReportPaths=coverage.xml - --define sonar.projectVersion=${{ steps.git-tag.outputs.tag }} + QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }} diff --git a/.github/workflows/step_test.yaml b/.github/workflows/step_test.yaml index 78737dc..82e9ee9 100644 --- a/.github/workflows/step_test.yaml +++ b/.github/workflows/step_test.yaml @@ -12,8 +12,10 @@ permissions: contents: read jobs: - tests: - name: ๐Ÿ› ๏ธ ${{ matrix.toolchain }} + test-toolchains: + name: > + ๐Ÿ› ๏ธ ${{ matrix.toolchain }} + ${{ matrix.experimental && '[๐Ÿงช Experimental]' || '' }} runs-on: ${{ matrix.os || 'ubuntu-latest' }} container: ${{ !matrix.os && 'ghcr.io/lecrisut/dev-env:main' || '' }} continue-on-error: ${{ matrix.experimental || false }} @@ -24,7 +26,6 @@ jobs: include: - os: windows-latest toolchain: windows - experimental: true - os: macos-latest toolchain: macos steps: @@ -44,3 +45,27 @@ jobs: with: workflowPreset: "${{ matrix.toolchain }}-ci" continue-on-error: ${{ matrix.experimental && inputs.mask-experimental}} + + cmake-version: + name: > + ๐Ÿ”จ CMake ${{ matrix.cmake }} + ${{ matrix.experimental && '[๐Ÿงช Experimental]' || '' }} + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental || false }} + strategy: + fail-fast: false + matrix: + cmake: [ "3.25", "latest", "latestrc" ] + include: + - cmake: latestrc + experimental: true + steps: + - uses: actions/checkout@v4 + - uses: lukka/get-cmake@latest + with: + cmakeVersion: ${{ matrix.cmake }} + - name: Run CMake workflow + uses: lukka/run-cmake@v10.3 + with: + workflowPreset: gcc-ci + continue-on-error: ${{ matrix.experimental && inputs.mask-experimental}} diff --git a/.packit.yaml b/.packit.yaml index 85fc1b9..9e078ef 100644 --- a/.packit.yaml +++ b/.packit.yaml @@ -1,83 +1,58 @@ -specfile_path: .distro/cmake-template.spec - -# add or remove files that should be synced files_to_sync: - - src: .distro/cmake-template.spec - dest: cmake-template.spec - - .packit.yaml - - src: .distro/cmake-template.rpmlintrc - dest: cmake-template.rpmlintrc - # tmt setup - - src: .distro/.fmf/ - dest: .fmf/ - - src: .distro/plans/ - dest: plans/ + - src: .distro/ + dest: ./ + delete: true filters: - - "- main.fmf.dist-git" - - "- rpminspect.fmf" - - "- rpmlint.fmf" - - src: .distro/plans/main.fmf.dist-git - dest: plans/main.fmf + - "protect .git*" + - "protect sources" + - "protect changelog" + - "- plans/rpminspect.fmf" + - "- plans/rpmlint.fmf" - .packit.yaml +specfile_path: .distro/cmake-template.spec upstream_package_name: CMake-Template downstream_package_name: cmake-template - -update_release: false upstream_tag_template: v{version} +targets: &targets + - fedora-all-x86_64 + - fedora-all-aarch64 + - epel-10-x86_64 + - epel-10-aarch64 + - epel-9-x86_64 + - epel-9-aarch64 + jobs: - - job: copr_build + - &copr_build + job: copr_build trigger: pull_request - owner: lecris - project: cmake-template - targets: - - fedora-38-x86_64 - - fedora-38-aarch64 - - fedora-development-x86_64 - - fedora-development-aarch64 - - job: tests + - &tests + job: tests trigger: pull_request - targets: - - fedora-38-x86_64 - - fedora-38-aarch64 - - fedora-development-x86_64 - - fedora-development-aarch64 fmf_path: .distro - - job: copr_build + - <<: *copr_build trigger: commit branch: main - owner: lecris project: nightly - targets: - - fedora-38-x86_64 - - fedora-38-aarch64 - - fedora-development-x86_64 - - fedora-development-aarch64 - additional_repos: - - copr://@scikit-build/release - - job: tests + - <<: *tests trigger: commit branch: main - targets: - - fedora-38-x86_64 - - fedora-38-aarch64 - - fedora-development-x86_64 - - fedora-development-aarch64 - fmf_path: .distro - ## Uncomment when released downstream -# - job: propose_downstream -# trigger: release -# dist_git_branches: -# - fedora-rawhide -# - epel-9 -# - job: koji_build -# trigger: commit -# dist_git_branches: -# - fedora-all -# - epel-9 -# - job: bodhi_update -# trigger: commit -# dist_git_branches: -# - fedora-branched -# - epel-9 + - <<: *copr_build + trigger: release + owner: lecris + project: release + - <<: *tests + trigger: release + - job: propose_downstream + trigger: release + dist_git_branches: + - fedora-rawhide + - job: koji_build + trigger: commit + dist_git_branches: + - fedora-all + - job: bodhi_update + trigger: commit + dist_git_branches: + - fedora-branched diff --git a/CMakeLists.txt b/CMakeLists.txt index b2fcdf7..419994e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,5 @@ # Minimum version follows the current Ubuntu LTS and RHEL version -cmake_minimum_required(VERSION 3.20) -# CMake version compatibility. This allows to future-proof implementations and easily update -# when bumping cmake_minimum_required -# Enable using return(PROPAGATE) -# TODO: Remove when cmake 3.25 is commonly distributed -if (POLICY CMP0140) - cmake_policy(SET CMP0140 NEW) -endif () +cmake_minimum_required(VERSION 3.25...3.29) #[=============================================================================[ # Basic project definition # @@ -20,17 +13,6 @@ project(Template LANGUAGES CXX ) -# Back-porting to PROJECT_IS_TOP_LEVEL to older cmake -# TODO: Remove when requiring cmake >= 3.21 -if (NOT DEFINED Template_IS_TOP_LEVEL) - if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) - set(PROJECT_IS_TOP_LEVEL ON) - else () - set(PROJECT_IS_TOP_LEVEL OFF) - endif () - set(Template_IS_TOP_LEVEL ${PROJECT_IS_TOP_LEVEL}) -endif () - # Specify C++ standard used in the project. set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -56,23 +38,20 @@ list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) # Include basic tools include(FetchContent) -if (TEMPLATE_INSTALL) - include(CMakePackageConfigHelpers) - if (UNIX) - include(GNUInstallDirs) - endif () -endif () - -# Define basic parameters -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) -endif () -set(BUILD_SHARED_LIBS ${TEMPLATE_SHARED_LIBS}) +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) #[=============================================================================[ # External packages # ]=============================================================================] +# Make sure dependencies are built statically if taken from FetchContent +if (TEMPLATE_SHARED_LIBS) + set(FMT_INSTALL OFF) + set(BUILD_SHARED_LIBS OFF) +else () + set(FMT_INSTALL OFF) +endif () FetchContent_Declare(fmt GIT_REPOSITORY https://github.com/fmtlib/fmt GIT_TAG master @@ -80,6 +59,7 @@ FetchContent_Declare(fmt ) FetchContent_MakeAvailable(fmt) +set(BUILD_SHARED_LIBS ${TEMPLATE_SHARED_LIBS}) feature_summary( FILENAME ${CMAKE_CURRENT_BINARY_DIR}/Template.info @@ -166,20 +146,11 @@ endif () # Make project available for FetchContent if(NOT PROJECT_IS_TOP_LEVEL) # Propagate variables - if (CMAKE_VERSION VERSION_LESS 3.25) - # TODO: Remove when cmake 3.25 is commonly distributed - set(Template_VERSION ${Template_VERSION} PARENT_SCOPE) - set(Template_VERSION_MAJOR ${Template_VERSION_MAJOR} PARENT_SCOPE) - set(Template_VERSION_MINOR ${Template_VERSION_MINOR} PARENT_SCOPE) - set(Template_VERSION_PATCH ${Template_VERSION_PATCH} PARENT_SCOPE) - set(Template_VERSION_TWEAK ${Template_VERSION_TWEAK} PARENT_SCOPE) - else () - return(PROPAGATE - Template_VERSION - Template_VERSION_MAJOR - Template_VERSION_MINOR - Template_VERSION_PATCH - Template_VERSION_TWEAK - ) - endif () + return(PROPAGATE + Template_VERSION + Template_VERSION_MAJOR + Template_VERSION_MINOR + Template_VERSION_PATCH + Template_VERSION_TWEAK + ) endif () diff --git a/README.md b/README.md index a616de3..aa84287 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ [rtd-badge]: https://readthedocs.org/projects/lecrisut-cmake-template/badge/?version=latest [codecov-badge]: https://codecov.io/gh/LecrisUT/CMake-Template/graph/badge.svg?token=YAEN2SWB10 [sonarcloud-badge]: https://sonarcloud.io/api/project_badges/measure?project=LecrisUT_CMake-Template&metric=alert_status -[cmake-badge]: https://img.shields.io/badge/CMake-3.20-blue?logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMiIgdmlld0JveD0iMCAwIDU0NS41IDU0NS45Ij48cGF0aCBkPSJNNTQ2IDUzNCAyODIgOWwzOSA0MzQgMjI1IDkxeiIgZGF0YS1uYW1lPSJyZWQgcmlnaHQiIHN0eWxlPSJmaWxsOiNmMzI3MzU7c3Ryb2tlLXdpZHRoOjAiLz48cGF0aCBkPSJNNTI1IDU0NiAxNzAgNDAzIDEgNTQ2aDUyNHoiIGRhdGEtbmFtZT0iZ3JlZW4gYm90dG9tIiBzdHlsZT0ic3Ryb2tlLXdpZHRoOjA7ZmlsbDojM2VhZTJiIi8+PHBhdGggZD0iTTI2MyAwIDAgNTIybDI4OC0yNDRMMjYzIDB6IiBkYXRhLW5hbWU9ImJsdWUgbGVmdCIgc3R5bGU9ImZpbGw6IzAwNjhjNztzdHJva2Utd2lkdGg6MCIvPjxwYXRoIGQ9Im0yOTEgMjk5LTEwNSA4OSAxMTcgNDgtMTItMTM3eiIgZGF0YS1uYW1lPSJncmF5IGNlbnRlciIgc3R5bGU9ImZpbGw6I2RjZTNlYztzdHJva2Utd2lkdGg6MCIvPjwvc3ZnPg== +[cmake-badge]: https://img.shields.io/badge/CMake-3.25-blue?logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMiIgdmlld0JveD0iMCAwIDU0NS41IDU0NS45Ij48cGF0aCBkPSJNNTQ2IDUzNCAyODIgOWwzOSA0MzQgMjI1IDkxeiIgZGF0YS1uYW1lPSJyZWQgcmlnaHQiIHN0eWxlPSJmaWxsOiNmMzI3MzU7c3Ryb2tlLXdpZHRoOjAiLz48cGF0aCBkPSJNNTI1IDU0NiAxNzAgNDAzIDEgNTQ2aDUyNHoiIGRhdGEtbmFtZT0iZ3JlZW4gYm90dG9tIiBzdHlsZT0ic3Ryb2tlLXdpZHRoOjA7ZmlsbDojM2VhZTJiIi8+PHBhdGggZD0iTTI2MyAwIDAgNTIybDI4OC0yNDRMMjYzIDB6IiBkYXRhLW5hbWU9ImJsdWUgbGVmdCIgc3R5bGU9ImZpbGw6IzAwNjhjNztzdHJva2Utd2lkdGg6MCIvPjxwYXRoIGQ9Im0yOTEgMjk5LTEwNSA4OSAxMTcgNDgtMTItMTM3eiIgZGF0YS1uYW1lPSJncmF5IGNlbnRlciIgc3R5bGU9ImZpbGw6I2RjZTNlYztzdHJva2Utd2lkdGg6MCIvPjwvc3ZnPg== [ci-link]: https://github.com/LecrisUT/CMake-Template/actions?query=branch%3Amain+event%3Apush [rtd-link]: https://lecrisut-cmake-template.readthedocs.io/en/latest/?badge=latest diff --git a/cmake/CMakePresets-defaults.json b/cmake/CMakePresets-defaults.json index 0b46ba7..0295cf9 100644 --- a/cmake/CMakePresets-defaults.json +++ b/cmake/CMakePresets-defaults.json @@ -9,6 +9,10 @@ "CMAKE_BUILD_TYPE": { "type": "STRING", "value": "Release" + }, + "CMAKE_MESSAGE_CONTEXT_SHOW": { + "type": "BOOL", + "value": true } } } diff --git a/cmake/Template_Helpers.cmake b/cmake/Template_Helpers.cmake index e0c0737..5127320 100644 --- a/cmake/Template_Helpers.cmake +++ b/cmake/Template_Helpers.cmake @@ -1,7 +1,7 @@ include_guard(GLOBAL) include(FindPackageHandleStandardArgs) -find_package(PkgConfig REQUIRED) +find_package(PkgConfig) macro(Template_FindPackage name) #[===[.md @@ -87,7 +87,7 @@ macro(Template_FindPackage name) find_package_handle_standard_args(${name} CONFIG_MODE HANDLE_COMPONENTS ) - else () + elseif (PkgConfig_FOUND) # Try pkg-config next # Construct the moduleSpec to search for if (NOT DEFINED ARGS_PKG_MODULE_SPECS) diff --git a/cmake/Template_test.cmake b/cmake/Template_test.cmake new file mode 100644 index 0000000..be1b176 --- /dev/null +++ b/cmake/Template_test.cmake @@ -0,0 +1,69 @@ +include_guard() + +function(Template_add_test test) + #[===[.md + # Template_add_test + + Internal helper for adding functional tests specific for the current template project + + ## Synopsis + ```cmake + Template_add_test( + [TEST_NAME ] + [TARGET ] + [LABELS ]) + ``` + + ## Options + + `` + Path to the CMake project to be executed relative to `${CMAKE_CURRENT_SOURCE_DIR}` + + `TEST_NAME` [Default: ``] + Name for the test to be used as the ctest name + + `LABELS` + Additional labels to be added + + ]===] + + list(APPEND CMAKE_MESSAGE_CONTEXT "Template_add_test") + + set(ARGS_Options) + set(ARGS_OneValue + TEST_NAME + ) + set(ARGS_MultiValue + LABELS + ) + cmake_parse_arguments(PARSE_ARGV 1 ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}") + # Check required/optional arguments + if (ARGC LESS 1) + message(FATAL_ERROR "Missing test name") + endif () + if (NOT DEFINED ARGS_TEST_NAME) + set(ARGS_TEST_NAME ${test}) + endif () + set(extra_args) + if (Template_IS_TOP_LEVEL) + list(APPEND extra_args + -DFETCHCONTENT_TRY_FIND_PACKAGE_MODE=ALWAYS + # Generated Config file point to binary targets until it is installed + -DTemplate_ROOT=${Template_BINARY_DIR} + -DFETCHCONTENT_SOURCE_DIR_TEMPLATE=${Template_SOURCE_DIR} + ) + endif () + + add_test(NAME ${ARGS_TEST_NAME} + COMMAND ${CMAKE_CTEST_COMMAND} --build-and-test ${CMAKE_CURRENT_SOURCE_DIR}/${test} + ${CMAKE_CURRENT_BINARY_DIR}/${test} + # Use the same build environment as the current runner + --build-generator "${CMAKE_GENERATOR}" + --build-options -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + ${extra_args} + --test-command ${CMAKE_CTEST_COMMAND} --test-dir ${CMAKE_CURRENT_BINARY_DIR}/${test} --output-on-failure + ) + set_tests_properties(${ARGS_TEST_NAME} PROPERTIES + LABELS "${ARGS_LABELS}" + ) +endfunction() diff --git a/docs/guides/developer/index.md b/docs/guides/developer/index.md index 145fc90..0a20633 100644 --- a/docs/guides/developer/index.md +++ b/docs/guides/developer/index.md @@ -1,10 +1,10 @@ # Developer guide ```{toctree} -: maxdepth: 2 -: titlesonly: true -: hidden: true -: glob: true +:maxdepth: 2 +:titlesonly: true +:hidden: true +:glob: true who-is-the-developer paradigms/index diff --git a/docs/guides/developer/paradigms/export.md b/docs/guides/developer/paradigms/export.md index 0707469..88fca30 100644 --- a/docs/guides/developer/paradigms/export.md +++ b/docs/guides/developer/paradigms/export.md @@ -28,8 +28,8 @@ Disregarding the most of the paradigms for the sake of brevity, the project files would look like this: ```{code-block} cmake -: caption: CMakeLists.txt -: emphasize-lines: 9-17,25-33 +:caption: CMakeLists.txt +:emphasize-lines: 9-17,25-33 option(EXAMPLE_EXECUTABLE "Build the say-hello executable" OFF) @@ -75,8 +75,8 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ExampleConfig.cmake ) ``` ```{code-block} -: caption: ExampleConfig.cmake.in -: emphasize-lines: 3-6 +:caption: ExampleConfig.cmake.in +:emphasize-lines: 3-6 @PACKAGE_INIT@ @@ -109,8 +109,8 @@ exported appropriately. ```{code-block} cmake -: caption: CMakeLists.txt -: emphasize-lines: 2,6-10 +:caption: CMakeLists.txt +:emphasize-lines: 2,6-10 add_library(hello) add_library(Example::hello ALIAS hello) @@ -141,6 +141,6 @@ Make sure that [`_VERSION`] and its equivalents are exported [`find_package`]: inv:cmake:cmake:command#command:find_package [`install(TARGETS)`]: inv:cmake:cmake:command#command:install(targets) [`install(EXPORT)`]: inv:cmake:cmake:command#command:install(export) -[`export(EXPORT)`]: inv:cmake:std:label#export(export) +[`export(EXPORT)`]: inv:cmake:cmake:command#command:export [`Config.cmake`]: [`_VERSION`]: inv:cmake:cmake:variable#variable:_VERSION diff --git a/docs/guides/developer/paradigms/import.md b/docs/guides/developer/paradigms/import.md index 6db50ea..45b49fe 100644 --- a/docs/guides/developer/paradigms/import.md +++ b/docs/guides/developer/paradigms/import.md @@ -56,7 +56,7 @@ order to avoid conflicts with other similarly defined modules. If you still need such a module, an example module can look as follows: ```{code-block} cmake -: caption: FindExample.cmake +:caption: FindExample.cmake set(CMAKE_REQUIRE_FIND_PACKAGE_Example FALSE) find_package(Example CONFIG QUIET) diff --git a/docs/guides/developer/paradigms/index.md b/docs/guides/developer/paradigms/index.md index a8a18f6..d3013f0 100644 --- a/docs/guides/developer/paradigms/index.md +++ b/docs/guides/developer/paradigms/index.md @@ -1,8 +1,8 @@ # Design paradigms ```{toctree} -: maxdepth: 1 -: titlesonly: true +:maxdepth: 1 +:titlesonly: true top-level-cmake namespace diff --git a/docs/guides/developer/paradigms/top-level-cmake.md b/docs/guides/developer/paradigms/top-level-cmake.md index e2a47af..ec2f97d 100644 --- a/docs/guides/developer/paradigms/top-level-cmake.md +++ b/docs/guides/developer/paradigms/top-level-cmake.md @@ -148,7 +148,7 @@ More details can be found in the [export] section [`configure_file`]: inv:cmake:cmake:command#command:configure_file [`write_basic_package_version_file`]: inv:cmake:cmake:command#command:write_basic_package_version_file [`configure_package_config_file`]: inv:cmake:cmake:command#command:configure_package_config_file -[`export(EXPORT)`]: inv:cmake:std:label#export(export) +[`export(EXPORT)`]: inv:cmake:cmake:command#command:export [`Config.cmake`]: [`return(PROPAGATE)`]: inv:cmake:cmake:command#command:return [`set(PARENT_SCOPE)`]: inv:cmake:cmake:command#command:set(normal) diff --git a/docs/guides/developer/tools/github-workflows.md b/docs/guides/developer/tools/github-workflows.md index c001559..6e31b1c 100644 --- a/docs/guides/developer/tools/github-workflows.md +++ b/docs/guides/developer/tools/github-workflows.md @@ -50,13 +50,13 @@ A typical project's workflow should contain: - pre-commit checks: calls [pre-commit] - main tests: runs the main ctest - doc tests: runs other sphinx builders, e.g. `linkcheck`, `html -W` -- static-analysis: in this template it is [sonarcloud] +- static-analysis: in this template it is [Qodana] - code coverage: re-runs each subset of tests with coverage - release workflow: re-runs the CI tests, and publishes the release to GitHub and to other downstream packaging [pre-commit]: pre-commit.md -[sonarcloud]: sonarcloud.md +[Qodana]: qodana.md [`alls-green`]: https://github.com/re-actors/alls-green [`steps.[*].continue-on-error`]: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepscontinue-on-error diff --git a/docs/guides/developer/tools/index.md b/docs/guides/developer/tools/index.md index fa09bd3..75f32d8 100644 --- a/docs/guides/developer/tools/index.md +++ b/docs/guides/developer/tools/index.md @@ -1,14 +1,14 @@ # CI Tools ```{toctree} -: maxdepth: 1 -: titlesonly: true +:maxdepth: 1 +:titlesonly: true pre-commit github-workflows rtd packit codecov -sonarcloud +qodana tmt ``` diff --git a/docs/guides/developer/tools/qodana.md b/docs/guides/developer/tools/qodana.md new file mode 100644 index 0000000..0d10532 --- /dev/null +++ b/docs/guides/developer/tools/qodana.md @@ -0,0 +1,13 @@ +# Qodana + +Project link: [Qodana] + +## Purpose + +Perform static analysis. + +## Configuration + +See the `qodana.yaml` file. + +[Qodana]: https://www.jetbrains.com/qodana/ diff --git a/docs/guides/developer/tools/sonarcloud.md b/docs/guides/developer/tools/sonarcloud.md deleted file mode 100644 index 8acbc99..0000000 --- a/docs/guides/developer/tools/sonarcloud.md +++ /dev/null @@ -1,26 +0,0 @@ -# SonarCloud - -Project link: [SonarCloud] - -## Purpose - -Perform static analysis and track code coverage. - -:::{note} -Code coverage is not as customizable as with [codecov], however, it calculates -code coverage including the if-statement branching, while the latter only -calculates line coverage. -::: - -## Configuration - -See the `sonar-project.properties` file. - -## Recommendation - -Reuse the artifacts of the test/coverage, but currently it is unclear how to -design that. - -[SonarCloud]: https://www.sonarsource.com/products/sonarcloud/ - -[codecov]: codecov.md diff --git a/docs/guides/index.md b/docs/guides/index.md index b98a853..45ee653 100644 --- a/docs/guides/index.md +++ b/docs/guides/index.md @@ -1,8 +1,8 @@ # Guides ```{toctree} -: maxdepth: 2 -: titlesonly: true +:maxdepth: 2 +:titlesonly: true user/index developer/index @@ -31,8 +31,8 @@ to it using [inter-sphinx]. For example, include the following configurations to your `docs/conf.py` file: ```{code-block} python -: caption: docs/conf.py -: emphasize-lines: 5 +:caption: docs/conf.py +:emphasize-lines: 5 extensions = [ "sphinx.ext.intersphinx", @@ -53,8 +53,8 @@ Then, you can use it in your documentation files as follows: ::::{tab-set} :::{tab-item} Markdown ```{code-block} markdown -: caption: docs/example.md -: emphasize-lines: 4 +:caption: docs/example.md +:emphasize-lines: 4 Refer to the [following guide][template-user-guide] for a basic how-to interact with a CMake project... @@ -64,8 +64,8 @@ with a CMake project... ::: :::{tab-item} reStructuredText ```{code-block} rst -: caption: docs/example.rst -: emphasize-lines: 1 +:caption: docs/example.rst +:emphasize-lines: 1 Refer to the :external+template-user-guide:std:doc:`following guide` for a basic how-to interact with a CMake project... diff --git a/docs/guides/user/configure/import.md b/docs/guides/user/configure/import.md index 8482426..5d9cb8e 100644 --- a/docs/guides/user/configure/import.md +++ b/docs/guides/user/configure/import.md @@ -69,7 +69,7 @@ dependency, or simply disable the feature if it is an [optional dependency]. ### Controlling how dependencies are imported :::{table} -: name: dependency-import-options +:name: dependency-import-options | Option | Effect | Notes | |:--------------------------------------------:|:-------------------------------------------------------|:-------------------------------------------------------------------------------------------| diff --git a/docs/guides/user/configure/index.md b/docs/guides/user/configure/index.md index 8ccff7f..dcc338f 100644 --- a/docs/guides/user/configure/index.md +++ b/docs/guides/user/configure/index.md @@ -1,9 +1,9 @@ # Configuring the project ```{toctree} -: maxdepth: 1 -: titlesonly: true -: hidden: true +:maxdepth: 1 +:titlesonly: true +:hidden: true options import @@ -98,8 +98,8 @@ at compile/build time. :::{admonition} Tl;dr ```{code-block} json -: emphasize-lines: 9-11 -: caption: CMakeUserPresets.json +:emphasize-lines: 9-11 +:caption: CMakeUserPresets.json { "version": 6, diff --git a/docs/guides/user/index.md b/docs/guides/user/index.md index 630f3d4..d748e24 100644 --- a/docs/guides/user/index.md +++ b/docs/guides/user/index.md @@ -1,9 +1,9 @@ # User guide ```{toctree} -: maxdepth: 2 -: titlesonly: true -: hidden: true +:maxdepth: 2 +:titlesonly: true +:hidden: true who-is-the-user download diff --git a/docs/index.md b/docs/index.md index cdec9d4..dd92a7a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,19 +1,19 @@ # CMake Template ```{toctree} -: maxdepth: 2 -: titlesonly: true -: caption: Contents -: hidden: true -: glob: true +:maxdepth: 2 +:titlesonly: true +:caption: Contents +:hidden: true +:glob: true self guides/index.md ``` ```{include} ../README.md -: start-after: -: end-before: +:start-after: +:end-before: ``` [cmake-presets]: inv:cmake:std:doc#manual/cmake-presets.7 diff --git a/qodana.yaml b/qodana.yaml new file mode 100644 index 0000000..e43f82c --- /dev/null +++ b/qodana.yaml @@ -0,0 +1,10 @@ +version: "1.0" +profile: + name: qodana.recommended +exclude: + - name: All + paths: + - build/_deps +linter: jetbrains/qodana-clang:latest +bootstrap: | + cmake --preset default -B ./build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON diff --git a/sonar-project.properties b/sonar-project.properties deleted file mode 100644 index 986888a..0000000 --- a/sonar-project.properties +++ /dev/null @@ -1,6 +0,0 @@ -sonar.projectKey=LecrisUT_CMake-Template -sonar.organization=lecris - -sonar.projectName=CMake Template -sonar.sources=src -sonar.tests=test diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fbafe73..e58b58f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,27 +4,30 @@ target_sources(Template_Hello PRIVATE target_sources(Template_Template PRIVATE template.cpp ) +# Headers to be installed or used locally by the IDE +target_sources(Template_Template PUBLIC + FILE_SET template_header TYPE HEADERS FILES + template.h +) target_link_libraries(Template_Template PRIVATE fmt::fmt) target_link_libraries(Template_Hello PRIVATE Template_Template) -set_target_properties(Template_Template PROPERTIES - PUBLIC_HEADER template.h -) target_include_directories(Template_Template PUBLIC "$" "$" ) +if (TARGET fmt) + set_target_properties(fmt PROPERTIES + POSITION_INDEPENDENT_CODE True + ) +endif () if (TEMPLATE_INSTALL) - install(TARGETS Template_Hello - EXPORT TemplateTargets - RUNTIME DESTINATION ${CMAKE_INSTALL_RUNTIMEDIR} COMPONENT Template_Runtime - ) - install(TARGETS Template_Template + install(TARGETS Template_Template Template_Hello EXPORT TemplateTargets - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Template_Runtime NAMELINK_COMPONENT Template_Development - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Template_Development - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT Template_Development - RUNTIME DESTINATION ${CMAKE_INSTALL_RUNTIMEDIR} COMPONENT Template_Runtime + LIBRARY COMPONENT Template_Runtime NAMELINK_COMPONENT Template_Development + ARCHIVE COMPONENT Template_Development + FILE_SET template_header COMPONENT Template_Development + RUNTIME COMPONENT Template_Runtime ) endif () diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8af344c..299abfa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.25...3.29) #[=============================================================================[ # Basic project definition # @@ -18,7 +18,7 @@ set(CMAKE_CXX_EXTENSIONS ON) include(CMakeDependentOption) include(FeatureSummary) -cmake_dependent_option(TEMPLATE_TEST_COVERAGE "Template: Test with coverage" OFF "TEMPLATE_TESTS;Template_IS_TOP_LEVEL" OFF) +cmake_dependent_option(TEMPLATE_TEST_COVERAGE "Template: Test with coverage" OFF "Template_IS_TOP_LEVEL" OFF) add_feature_info(Coverage TEMPLATE_TEST_COVERAGE "Compile with test coverage") mark_as_advanced(TEMPLATE_TEST_COVERAGE) @@ -26,7 +26,10 @@ mark_as_advanced(TEMPLATE_TEST_COVERAGE) # Project configuration # ]==============================================================================================] +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake) + include(FetchContent) +include(Template_test) if (TEMPLATE_TEST_COVERAGE) target_compile_options(Template_Template PRIVATE --coverage) @@ -38,23 +41,16 @@ endif () # External packages # ]=============================================================================] -set(external_libs) -if (NOT Template_IS_TOP_LEVEL) - FetchContent_Declare(Template - GIT_REPOSITORY https://github.com/LecrisUT/CMake-Template - GIT_TAG main - FIND_PACKAGE_ARGS CONFIG - ) - list(APPEND external_libs Template) +if (NOT TARGET Template::Template) + find_package(Template REQUIRED CONFIG) endif () FetchContent_Declare(Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2 - GIT_TAG v3.4.0 + GIT_TAG v3.7.0 FIND_PACKAGE_ARGS CONFIG ) -list(APPEND external_libs Catch2) -FetchContent_MakeAvailable(${external_libs}) +FetchContent_MakeAvailable(Catch2) #[=============================================================================[ # Main definition # @@ -63,77 +59,13 @@ FetchContent_MakeAvailable(${external_libs}) enable_testing() include(Catch) +if (WIN32 AND CMAKE_VERSION VERSION_LESS 3.27) + message(FATAL_ERROR "Cannot reliably test for windows with CMake < 3.27") +endif () + add_executable(test-suite) target_link_libraries(test-suite PRIVATE Catch2::Catch2WithMain Template::Template) -function(Template_add_test test) - #[===[.md - # Template_add_test - - Internal helper for adding functional tests specific for the current template project - - ## Synopsis - ```cmake - Template_add_test( - [TEST_NAME ] - [TARGET ] - [LABELS ]) - ``` - - ## Options - - `` - Path to the CMake project to be executed relative to `${CMAKE_CURRENT_SOURCE_DIR}` - - `TEST_NAME` [Default: ``] - Name for the test to be used as the ctest name - - `LABELS` - Additional labels to be added - - ]===] - - list(APPEND CMAKE_MESSAGE_CONTEXT "Template_add_test") - - set(ARGS_Options) - set(ARGS_OneValue - TEST_NAME - ) - set(ARGS_MultiValue - LABELS - ) - cmake_parse_arguments(PARSE_ARGV 1 ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}") - # Check required/optional arguments - if (ARGC LESS 1) - message(FATAL_ERROR "Missing test name") - endif () - if (NOT DEFINED ARGS_TEST_NAME) - set(ARGS_TEST_NAME ${test}) - endif () - set(extra_args) - if (Template_IS_TOP_LEVEL) - list(APPEND extra_args - -DFETCHCONTENT_TRY_FIND_PACKAGE_MODE=ALWAYS - # Generated Config file point to binary targets until it is installed - -DTemplate_ROOT=${Template_BINARY_DIR} - -DFETCHCONTENT_SOURCE_DIR_TEMPLATE=${Template_SOURCE_DIR} - ) - endif () - - add_test(NAME ${ARGS_TEST_NAME} - COMMAND ${CMAKE_CTEST_COMMAND} --build-and-test ${CMAKE_CURRENT_SOURCE_DIR}/${test} - ${CMAKE_CURRENT_BINARY_DIR}/${test} - # Use the same build environment as the current runner - --build-generator "${CMAKE_GENERATOR}" - --build-options -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - ${extra_args} - --test-command ${CMAKE_CTEST_COMMAND} --test-dir ${CMAKE_CURRENT_BINARY_DIR}/${test} --output-on-failure - ) - set_tests_properties(${ARGS_TEST_NAME} PROPERTIES - LABELS "${ARGS_LABELS}" - ) -endfunction() - foreach (test_type IN ITEMS unit functional @@ -142,8 +74,23 @@ foreach (test_type IN ITEMS add_subdirectory(${test_type}) endforeach () -catch_discover_tests(test-suite +set(extra_args) +set(test_properties # Manually hard-coding labels until upstream support is included # https://github.com/catchorg/Catch2/pull/2690 - PROPERTIES LABELS "unit" + LABELS "unit" +) +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.27) + # Patch DLL path for windows + # https://stackoverflow.com/a/77990416 + list(APPEND test_properties + ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$,\;>" + ) + list(APPEND extra_args + DL_PATHS "$" + ) +endif () +catch_discover_tests(test-suite + PROPERTIES ${test_properties} + ${extra_args} ) diff --git a/test/ctest.fmf b/test/ctest.fmf index e17c0a8..f3b5ff2 100644 --- a/test/ctest.fmf +++ b/test/ctest.fmf @@ -1,11 +1,3 @@ tag: [ cmake ] -require: - - cmake - - rsync - - tree - - gcc-c++ - - pkgconf - - git framework: beakerlib -path: / test: ./test.sh diff --git a/test/package/FetchContent/CMakeLists.txt b/test/package/FetchContent/CMakeLists.txt index 8d78f01..af8f720 100644 --- a/test/package/FetchContent/CMakeLists.txt +++ b/test/package/FetchContent/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.25...3.29) project(example_spglib LANGUAGES CXX) include(FetchContent) @@ -32,3 +32,9 @@ add_test(NAME smoke_test set_tests_properties(smoke_test PROPERTIES PASS_REGULAR_EXPRESSION "^Hello, World!" ) +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.27) + # https://stackoverflow.com/a/77990416 + set_property(TEST smoke_test APPEND PROPERTY + ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$,\;>" + ) +endif () diff --git a/test/package/find_package/CMakeLists.txt b/test/package/find_package/CMakeLists.txt index 49192dd..c643f72 100644 --- a/test/package/find_package/CMakeLists.txt +++ b/test/package/find_package/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.25...3.29) project(example_spglib LANGUAGES CXX) find_package(Template REQUIRED CONFIG) @@ -13,3 +13,9 @@ add_test(NAME smoke_test set_tests_properties(smoke_test PROPERTIES PASS_REGULAR_EXPRESSION "^Hello, World!" ) +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.27) + # https://stackoverflow.com/a/77990416 + set_property(TEST smoke_test APPEND PROPERTY + ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$,\;>" + ) +endif () diff --git a/test/package/pkg-config/CMakeLists.txt b/test/package/pkg-config/CMakeLists.txt index 9449a1a..41b3f7c 100644 --- a/test/package/pkg-config/CMakeLists.txt +++ b/test/package/pkg-config/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.25...3.29) project(example_spglib LANGUAGES CXX) find_package(PkgConfig REQUIRED) @@ -14,3 +14,9 @@ add_test(NAME smoke_test set_tests_properties(smoke_test PROPERTIES PASS_REGULAR_EXPRESSION "^Hello, World!" ) +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.27) + # https://stackoverflow.com/a/77990416 + set_property(TEST smoke_test APPEND PROPERTY + ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$,\;>" + ) +endif () diff --git a/test/test.sh b/test/test.sh index 244948f..e7ee259 100755 --- a/test/test.sh +++ b/test/test.sh @@ -6,20 +6,16 @@ source /usr/share/beakerlib/beakerlib.sh || exit 1 rlJournalStart rlPhaseStartSetup rlRun "tmp=\$(mktemp -d)" 0 "Create tmp directory" - rlRun "rsync -rL ./ $tmp" 0 "Copy example project" - rlRun "pushd $tmp" - rlRun "tree" 0 "Show directory tree" rlRun "set -o pipefail" rlPhaseEnd rlPhaseStartTest - rlRun "cmake -B ./build" - rlRun "cmake --build ./build" - rlRun "ctest --test-dir ./build --output-on-failure" + rlRun "cmake -B $tmp/build --log-context -Wdev" + rlRun "cmake --build $tmp/build" + rlRun "ctest --test-dir $tmp/build --output-on-failure" rlPhaseEnd rlPhaseStartCleanup - rlRun "popd" rlRun "rm -r $tmp" 0 "Remove tmp directory" rlPhaseEnd rlJournalEnd