diff --git a/cookiecutter.json b/cookiecutter.json index af4620e..fab025e 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -1,4 +1,8 @@ { + "_jinja2_env_vars": { + "trim_blocks": true, + "lstrip_blocks": true + }, "project_name": "My C++ Project", "remote_url": "None", "project_slug": "{%- if cookiecutter.remote_url == 'None' -%}{{ cookiecutter.project_name|replace('+', 'p')|slugify }}{% else %}{{ cookiecutter.remote_url.split('/')[-1]|replace('.git', '')}}{%- endif -%}", @@ -21,6 +25,6 @@ "local_extensions.CurrentDateExtension" ], "__python_module": "{{ cookiecutter|modname }}", - "_catch_version": "3.15.1", - "_cibuildwheel_version": "4.1.0" + "_catch_version": "3.15.3", + "_cibuildwheel_version": "4.2.0" } diff --git a/{{cookiecutter.project_slug}}/.github/workflows/ci.yml b/{{cookiecutter.project_slug}}/.github/workflows/ci.yml index 8488de4..26b2314 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/ci.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/ci.yml @@ -25,29 +25,26 @@ jobs: {% if cookiecutter.use_submodules == "Yes" %} with: submodules: 'recursive' -{%- endif %} +{% endif %} {% if cookiecutter.doxygen == "Yes" %} + - name: Install Doxygen uses: ssciwr/doxygen-install@v2 {% endif %} - - name: Make build directory - run: cmake -E make_directory ${{ "{{ github.workspace }}" }}/build - name: Configure cmake shell: bash - working-directory: ${{ "{{ github.workspace }}" }}/build - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=Debug -D{{ cookiecutter.project_slug }}_BUILD_TESTING=ON -D{{ cookiecutter.project_slug }}_BUILD_DOCS=OFF -D{{ cookiecutter.project_slug }}_BUILD_PYTHON=OFF + run: cmake --preset test - name: Build shell: bash - working-directory: ${{ "{{ github.workspace }}" }}/build - run: cmake --build . + run: cmake --build --preset test - name: Run tests shell: bash - working-directory: ${{ "{{ github.workspace }}" }}/build - run: ctest -{%- if cookiecutter.python_bindings != "None" %} + run: ctest --preset test +{% if cookiecutter.python_bindings != "None" %} + python-testing: name: Python package testing on ${{ "{{matrix.os}}" }} runs-on: ${{ "{{matrix.os}}" }} @@ -60,25 +57,27 @@ jobs: {% if cookiecutter.use_submodules == "Yes" %} with: submodules: 'recursive' -{%- endif %} +{% endif %} - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@v7 with: python-version: "3.14" {% if cookiecutter.doxygen == "Yes" %} + - name: Install Doxygen uses: ssciwr/doxygen-install@v2 {% endif %} + - name: Run Python tests shell: bash run: | python -m pip install . python -m pip install -r requirements-dev.txt pytest -{%- endif %} - +{% endif %} {% if cookiecutter.codecovio == "Yes" %} + coverage-test: name: Coverage Testing runs-on: ubuntu-latest @@ -88,45 +87,44 @@ jobs: {% if cookiecutter.use_submodules == "Yes" %} with: submodules: 'recursive' -{%- endif %} +{% endif %} - name: Install LCov run: | sudo apt-get install -y lcov {% if cookiecutter.doxygen == "Yes" %} + - name: Install Doxygen uses: ssciwr/doxygen-install@v2 {% endif %} {% if cookiecutter.python_bindings != "None" %} + - name: Install Python package editable run: | - python -m pip install scikit_build_core {% if cookiecutter.python_bindings == "pybind11" -%}pybind11[global]{%- elif cookiecutter.python_bindings == "nanobind" %}nanobind[global]{% endif %} + python -m pip install scikit_build_core {{ "pybind11[global]" if cookiecutter.python_bindings == "pybind11" else "nanobind[global]" }} python -m pip install --no-build-isolation --config-settings=build-dir="${{ "{{ github.workspace }}" }}/build" --config-settings=cmake.define.CMAKE_CXX_FLAGS="--coverage" --config-settings=cmake.define.BUILD_TESTING="ON" -v -e . python -m pip install -r requirements-dev.txt - + - name: Run Python tests run: | python -m pytest --cov --cov-report=xml {% else %} - - name: Create cmake build directory - run: cmake -E make_directory ${{ "{{ github.workspace }}" }}/build - name: Configure cmake shell: bash - working-directory: ${{ "{{ github.workspace }}" }}/build run: | - cmake $GITHUB_WORKSPACE -DCMAKE_CXX_FLAGS="--coverage" -D{{ cookiecutter.project_slug }}_BUILD_TESTING=ON -D{{ cookiecutter.project_slug }}_BUILD_DOCS=OFF + cmake --preset test \ + -DCMAKE_CXX_FLAGS="--coverage -fprofile-update=atomic -O0 -g" \ + -DCMAKE_EXE_LINKER_FLAGS="--coverage" - name: Build shell: bash - working-directory: ${{ "{{ github.workspace }}" }}/build - run: cmake --build . + run: cmake --build --preset test {% endif %} - name: Run tests shell: bash - working-directory: ${{ "{{ github.workspace }}" }}/build - run: ctest + run: ctest --preset test - name: Collect coverage report shell: bash @@ -140,3 +138,4 @@ jobs: fail_ci_if_error: true files: ${{ "{{github.workspace}}" }}/coverage.info{% if cookiecutter.python_bindings != "None" %},coverage.xml{% endif %} {% endif %} + diff --git a/{{cookiecutter.project_slug}}/.github/workflows/pypi.yml b/{{cookiecutter.project_slug}}/.github/workflows/pypi.yml index 15b1740..820d153 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/pypi.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/pypi.yml @@ -18,6 +18,7 @@ on: jobs: build-wheels: name: Build wheels on {% raw %}${{ matrix.os }}{% endraw %} + runs-on: {% raw %}${{ matrix.os }}{% endraw %} strategy: @@ -31,12 +32,13 @@ jobs: submodules: 'recursive' - name: Set up Python 3.14 - uses: actions/setup-python@v6 + uses: actions/setup-python@v7 with: python-version: "3.14" - name: Verify release tag matches package version if: {% raw %}${{ github.event_name == 'push' }}{% endraw %} + shell: python run: | import os @@ -62,6 +64,7 @@ jobs: - uses: actions/upload-artifact@v7 with: name: wheels-{% raw %}${{ matrix.os }}{% endraw %} + path: ./wheelhouse/*.whl if-no-files-found: error @@ -86,6 +89,7 @@ jobs: upload-testpypi: name: Publish on TestPyPI if: {% raw %}${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.publish_target == 'testpypi') }}{% endraw %} + needs: [build-wheels, build-sdist] runs-on: ubuntu-latest permissions: @@ -114,6 +118,7 @@ jobs: upload-pypi: name: Publish on PyPI if: {% raw %}${{ github.event_name == 'push' }}{% endraw %} + needs: [build-wheels, build-sdist, upload-testpypi] runs-on: ubuntu-latest permissions: diff --git a/{{cookiecutter.project_slug}}/.gitlab-ci.yml b/{{cookiecutter.project_slug}}/.gitlab-ci.yml index 5b3264e..81b948e 100644 --- a/{{cookiecutter.project_slug}}/.gitlab-ci.yml +++ b/{{cookiecutter.project_slug}}/.gitlab-ci.yml @@ -1,33 +1,37 @@ variables: -{%- if cookiecutter.use_submodules == "Yes" %} +{% if cookiecutter.use_submodules == "Yes" %} GIT_SUBMODULE_STRATEGY: recursive -{%- endif %} +{% endif %} + +.base: + image: ubuntu:24.04 -.template: &template before_script: - - echo "Installing required dependencies..." - - apt update - - apt install -y cmake git - - echo "Installing potential dependencies..." + - apt-get update + - apt-get install -y cmake git $COMPILER_PACKAGES {% if cookiecutter.python_bindings != "None" %} - - apt install -y python3-dev -{%- endif %} + - apt-get install -y python3-dev +{% endif %} {% if cookiecutter.doxygen == "Yes" %} - - apt install -y doxygen + - apt-get install -y doxygen {% endif %} + - cmake --version + - $CXX --version script: - - cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -D{{ cookiecutter.project_slug }}_BUILD_DOCS=OFF -D{{ cookiecutter.project_slug }}_BUILD_PYTHON=OFF - - cmake --build build - - ctest --test-dir build - -# Note: You can use your own Docker images here that e.g. include relevant -# dependencies and development tools. We choose well-maintained images -# providing up-to-date compiler toolchains. + - cmake --preset test + - cmake --build --preset test + - ctest --preset test build-and-test:gcc: - image: gcc:14 - <<: *template + extends: .base + variables: + COMPILER_PACKAGES: "gcc-14 g++-14" + CC: gcc-14 + CXX: g++-14 build-and-test:clang: - image: silkeh/clang:18 - <<: *template + extends: .base + variables: + COMPILER_PACKAGES: "clang-18" + CC: clang-18 + CXX: clang++-18 diff --git a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml index f604b47..ffe1710 100644 --- a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml +++ b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml @@ -1,14 +1,20 @@ repos: {%- if cookiecutter.python_bindings != "None" %} - # Run Black - the uncompromising Python code formatter - - repo: https://github.com/psf/black - rev: 26.5.1 + # Run Ruff - an extremely fast Python linter and code formatter + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.16.3 hooks: - - id: black-jupyter + # Run the linter + - id: ruff-check + types_or: [ python, pyi, jupyter, pyproject ] + args: [ --fix, --show-fixes ] + # Run the formatter + - id: ruff-format {% endif %} + # Format C++ code with Clang-Format - automatically applying the changes - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v22.1.5 + rev: v22.1.8 hooks: - id: clang-format args: @@ -19,24 +25,25 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - # Make sure that contained YAML files are well-formed - - id: check-yaml - # Trim trailing whitespace of all sorts - - id: trailing-whitespace + # Unify file endings + - id: end-of-file-fixer +{% if cookiecutter.python_bindings != "None" %} # Apply a file size limit of 500kB - id: check-added-large-files -{%- if cookiecutter.python_bindings != "None" %} + # Check json files for syntax errors + - id: check-json # Simple parser validation of e.g. pyproject.toml - id: check-toml -{%- endif %} - # Unify file endings - - id: end-of-file-fixer - -{%- if cookiecutter.github_actions_ci == "Yes" %} +{% endif %} + # Make sure that contained YAML files are well-formed + - id: check-yaml + # Trim trailing whitespace of all sorts + - id: trailing-whitespace +{% if cookiecutter.github_actions_ci == "Yes" %} # GitHub Actions Workflow linter - repo: https://github.com/rhysd/actionlint rev: v1.7.12 hooks: - id: actionlint -{%- endif %} +{% endif %} diff --git a/{{cookiecutter.project_slug}}/.readthedocs.yml b/{{cookiecutter.project_slug}}/.readthedocs.yml index 96d219e..bedcfcf 100644 --- a/{{cookiecutter.project_slug}}/.readthedocs.yml +++ b/{{cookiecutter.project_slug}}/.readthedocs.yml @@ -1,19 +1,31 @@ version: 2 -sphinx: - configuration: doc/conf.py - -formats: all - -submodules: - include: all - recursive: true - build: - os: ubuntu-24.04 + os: ubuntu-26.04 tools: - python: "3.12" + python: "3.14" + apt_packages: + - cmake + - doxygen + jobs: + pre_build: + - cmake --preset documentation + - cmake --build --preset documentation + build: + html: + - sphinx-build -T -j auto -b html -d $READTHEDOCS_OUTPUT/doctrees -D language=en doc $READTHEDOCS_OUTPUT/html python: +{% if cookiecutter.python_bindings == "pybind11" or cookiecutter.python_bindings == "nanobind" %} + install: + - method: uv + command: sync + path: python/{{ cookiecutter.__python_module }} + extras: + - docs +{% else %} install: - requirements: doc/requirements-rtd.txt +{% endif %} +sphinx: + configuration: doc/conf.py diff --git a/{{cookiecutter.project_slug}}/CITATION.cff b/{{cookiecutter.project_slug}}/CITATION.cff index 435ed4d..0cec458 100644 --- a/{{cookiecutter.project_slug}}/CITATION.cff +++ b/{{cookiecutter.project_slug}}/CITATION.cff @@ -15,9 +15,9 @@ identifiers: - description: This is a collection of archived snapshots of this project. type: doi value: "10.5281/zenodo.123456" -{%- if cookiecutter.license != "None" %} +{% if cookiecutter.license != "None" %} license: {{cookiecutter.license}} -{%- endif %} -{%- if cookiecutter.remote_url != 'None' %} +{% endif %} +{% if cookiecutter.remote_url != 'None' %} repository-code: {{cookiecutter.remote_url}} -{%- endif %} +{% endif %} diff --git a/{{cookiecutter.project_slug}}/CMakeLists.txt b/{{cookiecutter.project_slug}}/CMakeLists.txt index 7c3ae5a..7f50a01 100644 --- a/{{cookiecutter.project_slug}}/CMakeLists.txt +++ b/{{cookiecutter.project_slug}}/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.23) +cmake_minimum_required(VERSION 3.28) # Set a name and a version number for your project: project({{ cookiecutter.project_slug }} @@ -11,14 +11,14 @@ include(GNUInstallDirs) # Define build options option({{ cookiecutter.project_slug }}_BUILD_TESTING "Enable building of tests" OFF) -{%- if cookiecutter.python_bindings != "None" %} +{% if cookiecutter.python_bindings != "None" %} if(PROJECT_IS_TOP_LEVEL) option({{ cookiecutter.project_slug }}_BUILD_PYTHON "Enable building of Python bindings" ON) else() option({{ cookiecutter.project_slug }}_BUILD_PYTHON "Enable building of Python bindings" OFF) endif() -{%- endif -%} +{% endif %} {% if cookiecutter.doxygen == "Yes" or cookiecutter.readthedocs == "Yes" %} if(PROJECT_IS_TOP_LEVEL) @@ -26,13 +26,13 @@ if(PROJECT_IS_TOP_LEVEL) else() option({{ cookiecutter.project_slug }}_BUILD_DOCS "Enable building of documentation" OFF) endif() -{%- endif %} -{%- if cookiecutter.external_dependency != "None" %} +{% endif %} +{% if cookiecutter.external_dependency != "None" %} # Find external dependencies find_package({{ cookiecutter.external_dependency }}) -{%- endif %} -{%- if cookiecutter.header_only == "No" %} +{% endif %} +{% if cookiecutter.header_only == "No" %} # Compile the library add_subdirectory(src) @@ -55,7 +55,7 @@ target_compile_features({{ cookiecutter.project_slug }} INTERFACE cxx_std_{{ cookiecutter.cxx_minimum_standard }} ) -{%- endif %} +{% endif %} if(PROJECT_IS_TOP_LEVEL) # Compile the application executable @@ -66,19 +66,19 @@ if(PROJECT_IS_TOP_LEVEL) # Compile the tests include(CTest) if({{ cookiecutter.project_slug }}_BUILD_TESTING) - {%- if cookiecutter.use_submodules == "Yes" %} + {% if cookiecutter.use_submodules == "Yes" %} add_subdirectory(ext/Catch2) - {%- endif %} + {% endif %} add_subdirectory(tests) endif() endif() -{%- if cookiecutter.doxygen == "Yes" %} +{% if cookiecutter.doxygen == "Yes" %} # Add the documentation if(PROJECT_IS_TOP_LEVEL AND {{ cookiecutter.project_slug }}_BUILD_DOCS) add_subdirectory(doc) endif() -{%- endif %} +{% endif %} {% if cookiecutter.python_bindings != "None" %} # Add Python bindings if(PROJECT_IS_TOP_LEVEL AND {{ cookiecutter.project_slug }}_BUILD_PYTHON) @@ -87,8 +87,7 @@ if(PROJECT_IS_TOP_LEVEL AND {{ cookiecutter.project_slug }}_BUILD_PYTHON) PROPERTIES POSITION_INDEPENDENT_CODE ON ) - - {% if cookiecutter.python_bindings == "pybind11" -%} + {% if cookiecutter.python_bindings == "pybind11" %} set(PYBIND11_FINDPYTHON ON) find_package(pybind11 REQUIRED) # Compile the Pybind11 module @@ -103,7 +102,7 @@ if(PROJECT_IS_TOP_LEVEL AND {{ cookiecutter.project_slug }}_BUILD_PYTHON) ) find_package(nanobind CONFIG REQUIRED) nanobind_add_module(_{{ cookiecutter|modname }} python/{{ cookiecutter|modname }}/_{{ cookiecutter.project_slug }}.cpp) - {%- endif %} + {% endif %} target_link_libraries(_{{ cookiecutter|modname }} PUBLIC {{ cookiecutter.project_slug }} @@ -112,6 +111,7 @@ if(PROJECT_IS_TOP_LEVEL AND {{ cookiecutter.project_slug }}_BUILD_PYTHON) install(TARGETS _{{ cookiecutter|modname }} DESTINATION .) endif() {% endif %} + # Add an alias target for use if this project is included as a subproject in another project add_library({{ cookiecutter.project_slug }}::{{ cookiecutter.project_slug }} ALIAS {{ cookiecutter.project_slug }}) diff --git a/{{cookiecutter.project_slug}}/CMakePresets.json b/{{cookiecutter.project_slug}}/CMakePresets.json new file mode 100644 index 0000000..dba3963 --- /dev/null +++ b/{{cookiecutter.project_slug}}/CMakePresets.json @@ -0,0 +1,95 @@ +{ + "version": 8, + "cmakeMinimumRequired": { + "major": 3, + "minor": 28, + "patch": 0 + }, + "configurePresets": [ + { + "name": "base", + "hidden": true, + "binaryDir": "${sourceDir}/build/${presetName}", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": true, +{% if cookiecutter.doxygen == "Yes" or cookiecutter.readthedocs == "Yes" %} + "{{ cookiecutter.project_slug }}_BUILD_DOCS": false, +{% endif %} +{% if cookiecutter.python_bindings != "None" %} + "{{ cookiecutter.project_slug }}_BUILD_PYTHON": false, +{% endif %} + "{{ cookiecutter.project_slug }}_BUILD_TESTING": false + } + }, + { + "name": "debug", + "displayName": "Debug", + "description": "Debug build", + "inherits": "base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "release", + "displayName": "Release", + "description": "Release build", + "inherits": "base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, +{% if cookiecutter.doxygen == "Yes" or cookiecutter.readthedocs == "Yes" %} + { + "name": "documentation", + "displayName": "Release build with documentation", + "description": "Release build with Doxygen and Sphinx enabled", + "inherits": "release", + "cacheVariables": { + "{{ cookiecutter.project_slug }}_BUILD_DOCS": true + } + }, +{% endif %} + { + "name": "test", + "displayName": "Debug with tests", + "description": "Debug build with the C++ test suite enabled", + "inherits": "debug", + "cacheVariables": { + "{{ cookiecutter.project_slug }}_BUILD_TESTING": true + } + } + ], + "buildPresets": [ + { + "name": "debug", + "configurePreset": "debug" + }, + { + "name": "release", + "configurePreset": "release" + }, +{% if cookiecutter.doxygen == "Yes" or cookiecutter.readthedocs == "Yes" %} + { + "name": "documentation", + "configurePreset": "documentation", + "targets": [ + "{{ cookiecutter.project_slug }}-sphinx-doc" + ] + }, +{% endif %} + { + "name": "test", + "configurePreset": "test" + } + ], + "testPresets": [ + { + "name": "test", + "configurePreset": "test", + "output": { + "outputOnFailure": true + } + } + ] +} diff --git a/{{cookiecutter.project_slug}}/COPYING.md b/{{cookiecutter.project_slug}}/COPYING.md index 05e14a3..30ffeca 100644 --- a/{{cookiecutter.project_slug}}/COPYING.md +++ b/{{cookiecutter.project_slug}}/COPYING.md @@ -1,6 +1,6 @@ This is the list of copyright holders of {{ cookiecutter.project_name }}. -{%- if cookiecutter.license != "None" %} +{% if cookiecutter.license != "None" %} For information on the license, see LICENSE.md. -{%- endif %} +{% endif %} * {{ cookiecutter.full_name }}, {{ current_year }} diff --git a/{{cookiecutter.project_slug}}/FILESTRUCTURE.md b/{{cookiecutter.project_slug}}/FILESTRUCTURE.md index b0f43b6..5906960 100644 --- a/{{cookiecutter.project_slug}}/FILESTRUCTURE.md +++ b/{{cookiecutter.project_slug}}/FILESTRUCTURE.md @@ -3,20 +3,20 @@ This is an explanation of the repository's file structure: * C++ source files: * `include/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}.hpp` is the main C++ header that declares the interface of your library. -{%- if cookiecutter.header_only == "No" %} +{% if cookiecutter.header_only == "No" %} * `src/{{ cookiecutter.project_slug }}.cpp` is the main file that implements this library. -{%- endif %} +{% endif %} * `app/{{ cookiecutter.project_slug }}_app.cpp` is an executable that uses the library. This can e.g. be used to provide a command line interface for your project. * `tests/{{ cookiecutter.project_slug }}_t.cpp` contains the unit tests for the library. The unit tests are written using Catch2. For further reading on what can be achieved with Catch2, we recommend [their tutorial](https://github.com/catchorg/Catch2/blob/devel/docs/tutorial.md). -{%- if cookiecutter.python_bindings != "None" %} +{% if cookiecutter.python_bindings != "None" %} * The `python/{{ cookiecutter.project_slug.replace("-", "") }}` directory contains a Python package for the project. It contains a compiled Python module `_{{ cookiecutter.project_slug.replace("-", "") }}` - that CMake generates from the {% if cookiecutter.python_bindings == "pybind11" -%}Pybind11{% elif cookiecutter.python_bindings == "nanobind" %}nanobind{% endif %} source file `python/{{ cookiecutter.project_slug.replace("-", "") }}/_{{ cookiecutter.project_slug }}.cpp`. Additionally, it contains pure Python sources (e.g. `__init__.py`) that + that CMake generates from the {% if cookiecutter.python_bindings == "pybind11" %}Pybind11{% elif cookiecutter.python_bindings == "nanobind" %}nanobind{% endif %} source file `python/{{ cookiecutter.project_slug.replace("-", "") }}/_{{ cookiecutter.project_slug }}.cpp`. Additionally, it contains pure Python sources (e.g. `__init__.py`) that allow to wrap Python functionality around the compiled module. -{%- endif %} +{% endif %} * CMake build system files * `CMakeLists.txt` describes the CMake configuration script. You can find such files in many directories. When CMake runs, the `CMakeLists.txt` from the top-level directory @@ -24,24 +24,24 @@ This is an explanation of the repository's file structure: the `CMakeLists.txt` file from the directory `` is immediately executed. A comprehensive reference of CMake's capabilities can be found in the [official CMake docs](https://cmake.org/documentation/). A well-written, opinionated book for beginners and experts is [Modern CMake](https://cliutils.gitlab.io/modern-cmake/). -{%- if cookiecutter.external_dependency != "None" %} +{% if cookiecutter.external_dependency != "None" %} * `{{ cookiecutter.project_slug }}Config.cmake.in` provides a template for the configuration installed alongside your project. This is required to implement the transitivity of your dependency on `{{ cookiecutter.external_dependency }}`: If downstream projects use your library, they should automatically search for `{{ cookiecutter.external_dependency }}`. The config file template implements exactly this logic. -{%- endif %} -{%- if cookiecutter.use_submodules == "Yes" %} +{% endif %} +{% if cookiecutter.use_submodules == "Yes" %} * The `ext` directory contains any submodules that were added by the cookiecutter. -{%- endif %} +{% endif %} * Documentation configuration files -{%- if cookiecutter.doxygen == "Yes" or cookiecutter.readthedocs == "Yes" %} +{% if cookiecutter.doxygen == "Yes" or cookiecutter.readthedocs == "Yes" %} * The Doxygen documentation is configured directly from `doc/CMakeLists.txt`. To further configure the build, you can check the [Doxygen Configuration Manual](https://www.doxygen.nl/manual/config.html) for available options and add them with `set(DOXYGEN_ )` before the call to `doxygen_add_docs`. -{%- endif %} -{%- if cookiecutter.readthedocs == "Yes" %} +{% endif %} +{% if cookiecutter.readthedocs == "Yes" %} * `doc/index.rst` contains the actual text of the Sphinx documentation. It is written in *reStructuredText*, which is described in the [Sphinx documentation](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html). * `doc/conf.py` configures the Sphinx documentation that is build for readthedocs. @@ -52,41 +52,41 @@ This is an explanation of the repository's file structure: the [Breathe documentation](https://breathe.readthedocs.io/en/latest/). * `doc/requirements-rtd.txt` collect a list of dependencies that need to be installed on the Readthedocs build servers. -{%- endif %} +{% endif %} * Configuration for CI/Code analysis/Documentation services -{%- if have_precommit %} +{% if have_precommit %} * `.pre-commit-config.yaml` contains a configuration for the [pre-commit](https://pre-commit.com/) tool. It was added because the `pre-commit` tool was found in your Python environment. -{%- endif %} -{%- if cookiecutter.github_actions_ci == "Yes" %} +{% endif %} +{% if cookiecutter.github_actions_ci == "Yes" %} * `.github/workflows/ci.yml` describes the Github Workflow for Continuous integration. For further reading on workflow files, we recommend the [introduction into Github Actions](https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/introduction-to-github-actions) and [the reference of available options](https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions). -{%- endif %} -{%- if cookiecutter.gitlab_ci == "Yes" %} +{% endif %} +{% if cookiecutter.gitlab_ci == "Yes" %} * `.gitlab-ci.yml` describes the configuration for Gitlab CI. For further reading, we recommend [Gitlabs quick start guide](https://docs.gitlab.com/ee/ci/quick_start/) and the [Gitlab CI configuration reference](https://docs.gitlab.com/ce/ci/yaml/) -{%- endif %} -{%- if cookiecutter.readthedocs == "Yes" %} +{% endif %} +{% if cookiecutter.readthedocs == "Yes" %} * `.readthedocs.yml` configures the documentation build process at [ReadTheDocs](https://readthedocs.org). To customize your build, you can have a look at the [available options](https://docs.readthedocs.io/en/stable/config-file/v2.html). -{%- endif %} -{%- if cookiecutter.codecovio == "Yes" %} +{% endif %} +{% if cookiecutter.codecovio == "Yes" %} * `codecov.yml` configures the coverage checking from [codecov.io](https://codecov.io). The provided file is the default configuration plus suitable exclusions. For more options, check their [configuration reference](https://docs.codecov.io/docs/codecov-yaml). -{%- endif %} +{% endif %} * Markdown files with meta information on the project. [Markdown](https://www.markdownguide.org/basic-syntax/) is a good language for these files, as it is easy to write and rendered into something beautiful by your git repository hosting provider. * `README.md` is the file that users will typically see first when discovering your project. * `COPYING.md` provides a list of copyright holders. * `CITATION.cff` provides citation metadata so others know how to reference your project in publications. -{%- if cookiecutter.license != "None" %} +{% if cookiecutter.license != "None" %} * `LICENSE.md` contains the license you selected. -{%- endif %} +{% endif %} * `TODO.md` contains a list of TODOs for completing the setup of this software project. Following the instructions in that file will give you a fully functional repository with a lot of integration into useful web services activated and running. @@ -94,21 +94,21 @@ This is an explanation of the repository's file structure: repository if you do not need it. * Other files * `.gitignore` contains a default selection of files to omit from version control. -{%- if cookiecutter.use_submodules == "Yes" %} +{% if cookiecutter.use_submodules == "Yes" %} * `.gitmodules` tracks the state of added submodules -{%- endif %} -{%- if cookiecutter.python_bindings == "Yes" %} +{% endif %} +{% if cookiecutter.python_bindings == "Yes" %} * `pyproject.toml` provides information about the Python project and its toolchain. `pip` uses this file to control the entire build process. Additionally, it can be used to configure tools like `pytest`. -{%- if cookiecutter.pypi_release == "Yes" -%} +{% if cookiecutter.pypi_release == "Yes" %} Additionally, this file is needed for the automated release process to PyPI. * `.github/workflows/pypi.yml` defines the workflow that deploys to PyPI. The configuration of this workflow is done in `pyproject.toml`. -{%- endif %} +{% endif %} * `python/tests/test_python_bindings.py` defines a simple unit test suite for the Python bindings that is based on [Pytest](https://docs.pytest.org/en/stable/contents.html). `requirements-dev.txt` collects the required Python packages for running this test suite, they can be installed with `python -m pip install -r requirements-dev.txt`. The `pytest` run is configured in the `tools.pytest` section of `pyproject.toml`. -{%- endif %} +{% endif %} diff --git a/{{cookiecutter.project_slug}}/LICENSE.md b/{{cookiecutter.project_slug}}/LICENSE.md index 7418dc0..ca8aab1 100644 --- a/{{cookiecutter.project_slug}}/LICENSE.md +++ b/{{cookiecutter.project_slug}}/LICENSE.md @@ -1,13 +1,13 @@ Copyright {{ current_year }}, The copyright holders according to COPYING.md -{% if cookiecutter.license == "MIT" -%} +{% if cookiecutter.license == "MIT" %} 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. -{%- endif -%} -{% if cookiecutter.license == "BSD-2" -%} +{% endif %} +{% if cookiecutter.license == "BSD-2" %} Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -15,8 +15,8 @@ Redistribution and use in source and binary forms, with or without modification, 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -{%- endif -%} -{% if cookiecutter.license == "GPL-3.0" -%} +{% endif %} +{% if cookiecutter.license == "GPL-3.0" %} ### GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 @@ -692,8 +692,8 @@ library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . -{%- endif -%} -{% if cookiecutter.license == "LGPL-3.0" -%} +{% endif %} +{% if cookiecutter.license == "LGPL-3.0" %} ### GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 @@ -851,4 +851,4 @@ whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. -{%- endif -%} \ No newline at end of file +{% endif %} \ No newline at end of file diff --git a/{{cookiecutter.project_slug}}/README.md b/{{cookiecutter.project_slug}}/README.md index 5132b30..0a7cf60 100644 --- a/{{cookiecutter.project_slug}}/README.md +++ b/{{cookiecutter.project_slug}}/README.md @@ -1,39 +1,39 @@ # Welcome to {{ cookiecutter.project_name }} {# The white-space control of the below template is quite delicate - if you add one, do it exactly like this (mind the -'s) -#} -{% if cookiecutter.license == "MIT" -%} +{% if cookiecutter.license == "MIT" %} [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -{% endif -%} -{% if cookiecutter.license == "BSD-2" -%} +{% endif %} +{% if cookiecutter.license == "BSD-2" %} [![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause) -{% endif -%} -{% if cookiecutter.license == "GPL-3.0" -%} +{% endif %} +{% if cookiecutter.license == "GPL-3.0" %} [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) -{% endif -%} -{% if cookiecutter.license == "LGPL-3.0" -%} +{% endif %} +{% if cookiecutter.license == "LGPL-3.0" %} [![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0) -{% endif -%} -{% if cookiecutter.remote_url != "None" -%} -{% if cookiecutter.github_actions_ci == "Yes" and cookiecutter|is_github -%} +{% endif %} +{% if cookiecutter.remote_url != "None" %} +{% if cookiecutter.github_actions_ci == "Yes" and cookiecutter|is_github %} [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/{{ cookiecutter|username }}/{{ cookiecutter|remote_slug }}/ci.yml?branch=main)](https://github.com/{{ cookiecutter|username }}/{{ cookiecutter|remote_slug }}/actions/workflows/ci.yml) -{% endif -%} -{% if cookiecutter.gitlab_ci == "Yes" and cookiecutter|is_gitlab -%} +{% endif %} +{% if cookiecutter.gitlab_ci == "Yes" and cookiecutter|is_gitlab %} [![Gitlab pipeline status](https://img.shields.io/gitlab/pipeline/{{ cookiecutter|username }}/{{ cookiecutter|remote_slug }}/main -{%- if "gitlab.com" not in cookiecutter.remote_url -%} +{% if "gitlab.com" not in cookiecutter.remote_url %} ?gitlab_url={{ cookiecutter|gitlab_instance }} -{%- endif -%} +{% endif %} )]({{ cookiecutter|gitlab_instance }}/{{ cookiecutter|username }}/{{ cookiecutter|remote_slug }}/-/pipelines) -{% endif -%} -{% endif -%} -{% if cookiecutter.pypi_release != "No" -%} +{% endif %} +{% endif %} +{% if cookiecutter.pypi_release != "No" %} [![PyPI Release](https://img.shields.io/pypi/v/{{ cookiecutter|modname }}.svg)](https://pypi.org/project/{{ cookiecutter|modname }}) -{% endif -%} -{% if cookiecutter.readthedocs == "Yes" -%} +{% endif %} +{% if cookiecutter.readthedocs == "Yes" %} [![Documentation Status](https://readthedocs.org/projects/{{ cookiecutter|remote_slug }}/badge/)](https://{{ cookiecutter|remote_slug }}.readthedocs.io/) -{% endif -%} -{% if cookiecutter.codecovio == "Yes" -%} +{% endif %} +{% if cookiecutter.codecovio == "Yes" %} [![codecov](https://codecov.io/{{ cookiecutter|provider_acronym }}/{{ cookiecutter|username }}/{{ cookiecutter|remote_slug }}/branch/main/graph/badge.svg)](https://codecov.io/{{ cookiecutter|provider_acronym }}/{{ cookiecutter|username }}/{{ cookiecutter|remote_slug }}) -{%- endif %} +{% endif %} {{ "\n" -}} # Prerequisites @@ -41,18 +41,18 @@ Building {{ cookiecutter.project_name }} requires the following software install * A C++{{ cookiecutter.cxx_minimum_standard }}-compliant compiler * CMake `>= 3.23` -{%- if cookiecutter.external_dependency != "None" %} +{% if cookiecutter.external_dependency != "None" %} * {{ cookiecutter.external_dependency }} -{%- endif %} -{%- if cookiecutter.doxygen == "Yes" or cookiecutter.readthedocs == "Yes" %} +{% endif %} +{% if cookiecutter.doxygen == "Yes" or cookiecutter.readthedocs == "Yes" %} * Doxygen (optional, documentation building is skipped if missing) -{%- endif %} -{%- if cookiecutter.use_submodules == "No" %} +{% endif %} +{% if cookiecutter.use_submodules == "No" %} * The testing framework [Catch2](https://github.com/catchorg/Catch2) for building the test suite -{%- endif %} -{%- if cookiecutter.python_bindings != "None" %} +{% endif %} +{% if cookiecutter.python_bindings != "None" %} * Python `>= 3.10` for building Python bindings -{%- endif %} +{% endif %} # Building {{ cookiecutter.project_name }} @@ -69,12 +69,12 @@ The build process can be customized with the following CMake variables, which can be set by adding `-D={ON, OFF}` to the `cmake` call: * `{{ cookiecutter.project_slug }}_BUILD_TESTING`: Enable building of the test suite (default: `ON`) -{%- if cookiecutter.doxygen == "Yes" or cookiecutter.readthedocs == "Yes" %} +{% if cookiecutter.doxygen == "Yes" or cookiecutter.readthedocs == "Yes" %} * `{{ cookiecutter.project_slug }}_BUILD_DOCS`: Enable building the documentation (default: `ON`) -{%- endif %} -{%- if cookiecutter.python_bindings != "None" %} +{% endif %} +{% if cookiecutter.python_bindings != "None" %} * `{{ cookiecutter.project_slug }}_BUILD_PYTHON`: Enable building the Python bindings (default: `ON`) -{%- endif %} +{% endif %} {% if cookiecutter.python_bindings != "None" %} If you wish to build and install the project as a Python project without @@ -84,7 +84,7 @@ can do so using `pip` from the root directory: ``` python -m pip install . ``` -{%- endif %} +{% endif %} # Testing {{ cookiecutter.project_name }} @@ -104,7 +104,7 @@ and then running `pytest` from the top-level directory: python -m pip install . pytest ``` -{%- endif %} +{% endif %} # Documentation {% if cookiecutter.readthedocs == "Yes" %} @@ -135,7 +135,7 @@ cmake --build . --target doxygen The web documentation can then be browsed by opening `build/doc/html/index.html` in your browser. {% else %} {{ cookiecutter.project_name }} *should* provide a documentation. -{% endif -%} +{% endif %} ## Acknowledgments diff --git a/{{cookiecutter.project_slug}}/app/{{cookiecutter.project_slug}}_app.cpp b/{{cookiecutter.project_slug}}/app/{{cookiecutter.project_slug}}_app.cpp index 94ca074..47f81f2 100644 --- a/{{cookiecutter.project_slug}}/app/{{cookiecutter.project_slug}}_app.cpp +++ b/{{cookiecutter.project_slug}}/app/{{cookiecutter.project_slug}}_app.cpp @@ -1,7 +1,8 @@ #include "{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}.hpp" #include -int main() +int +main() { int result = {{ cookiecutter.project_slug.replace("-", "") }}::add_one(1); std::cout << "1 + 1 = " << result << std::endl; diff --git a/{{cookiecutter.project_slug}}/doc/CMakeLists.txt b/{{cookiecutter.project_slug}}/doc/CMakeLists.txt index b484f8f..33acfbd 100644 --- a/{{cookiecutter.project_slug}}/doc/CMakeLists.txt +++ b/{{cookiecutter.project_slug}}/doc/CMakeLists.txt @@ -1,20 +1,20 @@ -{%- if cookiecutter.doxygen == "Yes" or cookiecutter.readthedocs == "Yes" -%} +{% if cookiecutter.doxygen == "Yes" or cookiecutter.readthedocs == "Yes" %} find_package(Doxygen REQUIRED) set(DOXYGEN_EXCLUDE_PATTERNS "${CMAKE_SOURCE_DIR}/ext/*") set(DOXYGEN_SHORT_NAMES YES) -{% if cookiecutter.readthedocs == "Yes" -%} +{% if cookiecutter.readthedocs == "Yes" %} set(DOXYGEN_GENERATE_XML YES) -{%- endif %} +{% endif %} doxygen_add_docs({{ cookiecutter.project_slug }}-doxygen ${CMAKE_SOURCE_DIR}/include -{%- if cookiecutter.header_only == "No" %} +{% if cookiecutter.header_only == "No" %} ${CMAKE_SOURCE_DIR}/src -{%- endif %} +{% endif %} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT Building doxygen documentation... ) -{%- if cookiecutter.readthedocs == "Yes" %} +{% if cookiecutter.readthedocs == "Yes" %} add_custom_target({{ cookiecutter.project_slug }}-sphinx-doc COMMAND @@ -27,5 +27,5 @@ add_custom_target({{ cookiecutter.project_slug }}-sphinx-doc COMMENT "Generating documentation with Sphinx..." ) add_dependencies({{ cookiecutter.project_slug }}-sphinx-doc {{ cookiecutter.project_slug }}-doxygen) -{%- endif %} -{%- endif -%} +{% endif %} +{% endif %} diff --git a/{{cookiecutter.project_slug}}/doc/conf.py b/{{cookiecutter.project_slug}}/doc/conf.py index f27f02d..e710bda 100644 --- a/{{cookiecutter.project_slug}}/doc/conf.py +++ b/{{cookiecutter.project_slug}}/doc/conf.py @@ -4,24 +4,23 @@ # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html -import os -import subprocess +import sys +from pathlib import Path # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import sys -# sys.path.insert(0, os.path.abspath('.')) +# add these directories to sys.path here. +repo_root = Path(__file__).resolve().parent.parent +python_package_src = repo_root / "python" / "{{ cookiecutter.project_slug }}" / "src" +sys.path.insert(0, str(python_package_src)) # -- Project information ----------------------------------------------------- -project = '{{ cookiecutter.project_slug }}' -copyright = '{{ current_year }}, {{ cookiecutter.full_name }}' -author = '{{ cookiecutter.full_name }}' +project = "{{ cookiecutter.project_slug }}" +copyright = "{{ current_year }}, {{ cookiecutter.full_name }}" +author = "{{ cookiecutter.full_name }}" # -- General configuration --------------------------------------------------- @@ -30,42 +29,18 @@ # ones. extensions = [ "breathe", - "sphinx_rtd_theme", + "sphinx.ext.autodoc", ] -# Add any paths that contain templates here, relative to this directory. -templates_path = [] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [] - - # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = "sphinx_rtd_theme" -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = [] - # Breathe Configuration: Breathe is the bridge between the information extracted # from the C++ sources by Doxygen and Sphinx. -breathe_projects = {} +breathe_projects = { + "{{ cookiecutter.project_slug }}": str(repo_root / "build" / "documentation" / "doc" / "xml"), +} breathe_default_project = "{{ cookiecutter.project_slug }}" - -# Check if we're running on Read the Docs' servers -read_the_docs_build = os.environ.get('READTHEDOCS', None) == "True" - -# Implement build logic on RTD servers -if read_the_docs_build: - cwd = os.getcwd() - os.makedirs("build-cmake", exist_ok=True) - builddir = os.path.join(cwd, "build-cmake") - subprocess.check_call("cmake -D{{ cookiecutter.project_slug }}_BUILD_DOCS=ON -D{{ cookiecutter.project_slug }}_BUILD_TESTING=OFF {% if cookiecutter.python_bindings != 'None' %}-D{{ cookiecutter.project_slug }}_BUILD_PYTHON=OFF{% endif %} ../..".split(), cwd=builddir) - subprocess.check_call("cmake --build . --target {{ cookiecutter.project_slug }}-doxygen".split(), cwd=builddir) - breathe_projects["{{ cookiecutter.project_slug }}"] = os.path.join(builddir, "doc", "xml") diff --git a/{{cookiecutter.project_slug}}/include/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}.hpp b/{{cookiecutter.project_slug}}/include/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}.hpp index 694d442..22f30c7 100644 --- a/{{cookiecutter.project_slug}}/include/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}.hpp +++ b/{{cookiecutter.project_slug}}/include/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}.hpp @@ -12,12 +12,13 @@ namespace {{ cookiecutter.project_slug.replace("-", "") }} { * @param x The number to increase * @returns the successor of x */ -{%- endif %} -{% if cookiecutter.header_only == "Yes" %}inline {% endif %}int -add_one(int x){% if cookiecutter.header_only == "No" %};{%- else %} +{% endif %} +{{ "inline " if cookiecutter.header_only == "Yes" }}int +add_one(int x){{ ";" if cookiecutter.header_only == "No" }} +{% if cookiecutter.header_only == "Yes" %} { return x + 1; } -{%- endif %} +{% endif %} } // namespace {{ cookiecutter.project_slug.replace("-", "") }} diff --git a/{{cookiecutter.project_slug}}/pyproject.toml b/{{cookiecutter.project_slug}}/pyproject.toml index 1a899bc..20b5afd 100644 --- a/{{cookiecutter.project_slug}}/pyproject.toml +++ b/{{cookiecutter.project_slug}}/pyproject.toml @@ -4,11 +4,11 @@ [build-system] requires = [ "scikit-build-core", - {%- if cookiecutter.python_bindings == "pybind11" %} + {% if cookiecutter.python_bindings == "pybind11" %} "pybind11[global]" - {%- elif cookiecutter.python_bindings == "nanobind" %} + {% elif cookiecutter.python_bindings == "nanobind" %} "nanobind[global]" - {%- endif %} + {% endif %} ] build-backend = "scikit_build_core.build" @@ -24,19 +24,18 @@ maintainers = [ { name = "{{ cookiecutter.full_name}}", email = "your@email.com" }, ] requires-python = ">=3.10" -{%- if cookiecutter.license != "None" %} +{% if cookiecutter.license != "None" %} license-files = ["LICEN[CS]E*"] -{%- if cookiecutter.license == "MIT" %} +{% if cookiecutter.license == "MIT" %} license = "MIT" -{%- elif cookiecutter.license == "BSD-2" %} +{% elif cookiecutter.license == "BSD-2" %} license = "BSD-2-Clause" -{%- elif cookiecutter.license == "GPL-3.0" %} +{% elif cookiecutter.license == "GPL-3.0" %} license = "GPL-3.0-only" -{%- elif cookiecutter.license == "LGPL-3.0" %} +{% elif cookiecutter.license == "LGPL-3.0" %} license = "LGPL-3.0-only" -{%- endif %} -{%- endif %} - +{% endif %} +{% endif %} classifiers = [ "Programming Language :: C++", "Programming Language :: Python :: 3", @@ -44,9 +43,16 @@ classifiers = [ ] dependencies = [] +[project.optional-dependencies] +docs = [ + "breathe", + "sphinx", + "sphinx_rtd_theme", +] + # The configuration for the scikit-build-core build process [tool.scikit-build] -cmake.version = ">=3.23" +cmake.version = ">=3.28" build.verbose = true [tool.scikit-build.cmake.define] @@ -57,8 +63,8 @@ build.verbose = true # The following is the configuration for the pytest test suite [tool.pytest.ini_options] testpaths = ["tests/python"] +{% if cookiecutter.pypi_release == "Yes" %} -{% if cookiecutter.pypi_release == "Yes" -%} # The next section configures building wheels in Continuous Integration # The cibuildwheel documentation covers the available options in detail: # https://cibuildwheel.readthedocs.io/en/stable/options/ @@ -76,4 +82,4 @@ skip = "pp* *p27-* cp35-* cp36-* cp37-* cp38-* cp39-* *musllinux*" # Testing commands for our wheels test-command = "pytest {package}/tests/python" test-requires = ["pytest"] -{%- endif %} \ No newline at end of file +{% endif %} \ No newline at end of file diff --git a/{{cookiecutter.project_slug}}/python/{{cookiecutter.__python_module}}/_{{cookiecutter.project_slug}}.cpp b/{{cookiecutter.project_slug}}/python/{{cookiecutter.__python_module}}/_{{cookiecutter.project_slug}}.cpp index ce4f2ff..c655d75 100644 --- a/{{cookiecutter.project_slug}}/python/{{cookiecutter.__python_module}}/_{{cookiecutter.project_slug}}.cpp +++ b/{{cookiecutter.project_slug}}/python/{{cookiecutter.__python_module}}/_{{cookiecutter.project_slug}}.cpp @@ -1,25 +1,21 @@ -{% if cookiecutter.python_bindings == "pybind11" -%} +{% if cookiecutter.python_bindings == "pybind11" %} #include #include -{%- elif cookiecutter.python_bindings == "nanobind" %} +{% elif cookiecutter.python_bindings == "nanobind" %} #include -{%- endif %} +{% endif %} #include "{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}.hpp" -{% if cookiecutter.python_bindings == "pybind11" -%} +{% if cookiecutter.python_bindings == "pybind11" %} namespace py = pybind11; -{%- elif cookiecutter.python_bindings == "nanobind" %} +{% elif cookiecutter.python_bindings == "nanobind" %} namespace nb = nanobind; -{%- endif %} +{% endif %} namespace {{ cookiecutter|modname }} { -{% if cookiecutter.python_bindings == "pybind11" -%} -PYBIND11_MODULE{%- elif cookiecutter.python_bindings == "nanobind" %} -NB_MODULE -{%- endif -%} -(_{{ cookiecutter|modname }}, m) +{{ "PYBIND11_MODULE" if cookiecutter.python_bindings == "pybind11" else "NB_MODULE" }}(_{{ cookiecutter|modname }}, m) { m.doc() = "Python Bindings for {{ cookiecutter.project_name }}"; m.def("add_one", &add_one, "Increments an integer value"); diff --git a/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}.cpp b/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}.cpp index b7c9256..490c0ce 100644 --- a/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}.cpp +++ b/{{cookiecutter.project_slug}}/src/{{cookiecutter.project_slug}}.cpp @@ -2,7 +2,8 @@ namespace {{ cookiecutter.project_slug.replace("-", "") }} { -int add_one(int x) +int +add_one(int x) { return x + 1; } diff --git a/{{cookiecutter.project_slug}}/tests/CMakeLists.txt b/{{cookiecutter.project_slug}}/tests/CMakeLists.txt index 6f02f52..de5b160 100644 --- a/{{cookiecutter.project_slug}}/tests/CMakeLists.txt +++ b/{{cookiecutter.project_slug}}/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -{%- if cookiecutter.use_submodules == "No" -%} +{% if cookiecutter.use_submodules == "No" %} # Enable CMake's FetchContent module, which allows downloading dependencies like Catch2 automatically at configure time. include(FetchContent) @@ -10,11 +10,10 @@ FetchContent_Declare( # Make Catch2 available in this project. This defines the imported targets Catch2::Catch2 and Catch2::Catch2WithMain. FetchContent_MakeAvailable(Catch2) - -{%- else -%} +{% else %} # Find the Catch2 package find_package(Catch2 3 REQUIRED) -{%- endif %} +{% endif %} # Include Catch2's CMake helper functions (e.g., catch_discover_tests). include(Catch) diff --git a/{{cookiecutter.project_slug}}/tests/{{cookiecutter.project_slug}}_t.cpp b/{{cookiecutter.project_slug}}/tests/{{cookiecutter.project_slug}}_t.cpp index 06444c0..6738fc9 100644 --- a/{{cookiecutter.project_slug}}/tests/{{cookiecutter.project_slug}}_t.cpp +++ b/{{cookiecutter.project_slug}}/tests/{{cookiecutter.project_slug}}_t.cpp @@ -3,7 +3,8 @@ using namespace {{ cookiecutter.project_slug.replace("-", "") }}; -TEST_CASE( "add_one", "[adder]" ){ +TEST_CASE("add_one", "[adder]") +{ REQUIRE(add_one(0) == 1); REQUIRE(add_one(123) == 124); REQUIRE(add_one(-1) == 0);