diff --git a/.CMakeUserPresets.json b/.CMakeUserPresets.json new file mode 100644 index 0000000..9552627 --- /dev/null +++ b/.CMakeUserPresets.json @@ -0,0 +1,137 @@ +{ + "version": 6, + "cmakeMinimumRequired": { + "major": 3, + "minor": 28, + "patch": 0 + }, + "configurePresets": [ + { + "name": "dev-common", + "hidden": true, + "inherits": [ + "dev-mode" + ], + "binaryDir": "${sourceDir}/build/${presetName}", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": true, + "BUILD_MCSS_DOCS": false, + "BUILD_SHARED_LIBS": true + }, + "environment": { + "CPM_USE_LOCAL_PACKAGES": "OFF" + } + }, + { + "name": "dev-Linux", + "inherits": [ + "dev-common", + "ci-linux" + ], + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "dev-Darwin", + "inherits": [ + "dev-common", + "ci-darwin" + ], + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "dev-Windows", + "inherits": [ + "dev-common", + "ci-win64" + ], + "environment": { + "UseMultiToolTask": "ON", + "EnforceProcessCountAcrossBuilds": "ON" + } + }, + { + "name": "dev", + "inherits": "dev-" + }, + { + "name": "dev-coverage", + "inherits": [ + "ci-coverage", + "dev-Linux" + ] + }, + { + "name": "dev-sanitize", + "inherits": [ + "ci-sanitize", + "dev-Linux" + ] + } + ], + "buildPresets": [ + { + "name": "dev", + "configurePreset": "dev", + "configuration": "Debug", + "jobs": 12, + "targets": [ + "all", + "all_verify_interface_header_sets", + "install" + ] + } + ], + "testPresets": [ + { + "name": "dev", + "configurePreset": "dev", + "configuration": "Debug", + "output": { + "outputOnFailure": true + }, + "execution": { + "jobs": 12, + "noTestsAction": "error" + } + } + ], + "packagePresets": [ + { + "name": "dev", + "configurePreset": "dev", + "configurations": [ + "Debug" + ], + "generators": [ + "TGZ" + ] + } + ], + "workflowPresets": [ + { + "name": "dev", + "steps": [ + { + "type": "configure", + "name": "dev" + }, + { + "type": "build", + "name": "dev" + }, + { + "type": "test", + "name": "dev" + }, + { + "type": "package", + "name": "dev" + } + ] + } + ] +} diff --git a/.build-errors.txt b/.build-errors.txt new file mode 100644 index 0000000..4716068 --- /dev/null +++ b/.build-errors.txt @@ -0,0 +1,195 @@ +bash-5.2$ ninja -v fmt + +[1/4] cd /Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/build/dev/_deps/fmt-build && +/usr/local/opt/llvm/bin/clang++ -std=c++20 -x c++-module --precompile -c -o fmt.pcm +/Users/clausklein/.cache/CPM/fmt/c3ebf53335b44df838d9982d1a0e35afe190e34f/src/fmt.cc +-I/Users/clausklein/.cache/CPM/fmt/c3ebf53335b44df838d9982d1a0e35afe190e34f/include + +[2/4] cd /Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/build/dev/_deps/fmt-build && +/usr/local/opt/llvm/bin/clang++ +-fmodule-file=/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/build/dev/_deps/fmt-build/fmt.pcm -c -o fmt.o +/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/build/dev/_deps/fmt-build/fmt.pcm + +[3/4] : && /usr/local/opt/llvm/bin/clang++ -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 +-Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough +-Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast -g -arch x86_64 -isysroot +/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.4.sdk -dynamiclib +-Wl,-headerpad_max_install_names -m64 -compatibility_version 10.0.0 -current_version 10.2.1 -o +_deps/fmt-build/libfmtd.10.2.1.dylib -install_name @rpath/libfmtd.10.dylib _deps/fmt-build/fmt.o && : + +[4/4] /usr/local/bin/cmake -E cmake_symlink_library _deps/fmt-build/libfmtd.10.2.1.dylib _deps/fmt-build/libfmtd.10.dylib +_deps/fmt-build/libfmtd.dylib && : + +bash-5.2$ ninja -v Algo + +[1/2] /usr/local/opt/llvm/bin/clang++ -DAlgo_EXPORTS -DFMT_HEADER_ONLY=1 +-I/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/build/dev -isystem +/Users/clausklein/.cache/CPM/fmt/c3ebf53335b44df838d9982d1a0e35afe190e34f/include -Wall -Wextra -Wpedantic -Wconversion +-Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference +-Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast -g +-std=c++20 -arch x86_64 -isysroot +/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.4.sdk -fPIC +-fvisibility=hidden -fvisibility-inlines-hidden -MD -MT CMakeFiles/Algo.dir/algo-impl.cpp.o -MF +CMakeFiles/Algo.dir/algo-impl.cpp.o.d @CMakeFiles/Algo.dir/algo-impl.cpp.o.modmap -o CMakeFiles/Algo.dir/algo-impl.cpp.o -c +/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/algo-impl.cpp + +FAILED: CMakeFiles/Algo.dir/algo-impl.cpp.o +/usr/local/opt/llvm/bin/clang++ -DAlgo_EXPORTS -DFMT_HEADER_ONLY=1 -I/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/build/dev -isystem /Users/clausklein/.cache/CPM/fmt/c3ebf53335b44df838d9982d1a0e35afe190e34f/include -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast -g -std=c++20 -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.4.sdk -fPIC -fvisibility=hidden -fvisibility-inlines-hidden -MD -MT CMakeFiles/Algo.dir/algo-impl.cpp.o -MF CMakeFiles/Algo.dir/algo-impl.cpp.o.d @CMakeFiles/Algo.dir/algo-impl.cpp.o.modmap -o CMakeFiles/Algo.dir/algo-impl.cpp.o -c /Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/algo-impl.cpp +/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/algo-impl.cpp:8:8: fatal error: module 'fmt' not found + 8 | import fmt; + | ~~~~~~~^~~ +1 error generated. +ninja: build stopped: subcommand failed. +bash-5.2$ + +bash-5.2$ tree _deps/ +_deps/ +`-- fmt-build + |-- CMakeFiles + | |-- Export + | | `-- b834597d9b1628ff12ae4314c3a2e4b8 + | | |-- fmt-targets-debug.cmake + | | `-- fmt-targets.cmake + | `-- fmt.dir + |-- cmake_install.cmake + |-- fmt-config-version.cmake + |-- fmt-config.cmake + |-- fmt-targets.cmake + |-- fmt.o + |-- fmt.pc + |-- fmt.pcm + |-- libfmtd.10.2.1.dylib + |-- libfmtd.10.dylib -> libfmtd.10.2.1.dylib + `-- libfmtd.dylib -> libfmtd.10.dylib + +6 directories, 12 files +bash-5.2$ + +bash-5.2$ clang-format -i *.json +bash-5.2$ head -50 *.ddi *.json *.modmap +==> algo-impl.cpp.o.ddi <== +{ + "revision": 0, + "rules": [ + { + "primary-output": "CMakeFiles/Algo.dir/algo-impl.cpp.o", + "requires": [ + { + "logical-name": "fmt" + }, + { + "logical-name": "algo" + } + ] + } + ], + "version": 1 +} + +==> algo-interface.cppm.o.ddi <== +{ + "revision": 0, + "rules": [ + { + "primary-output": "CMakeFiles/Algo.dir/algo-interface.cppm.o", + "provides": [ + { + "is-interface": true, + "logical-name": "algo", + "source-path": "/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/algo-interface.cppm" + } + ] + } + ], + "version": 1 +} + +==> CXXDependInfo.json <== +{ + "bmi-installation": null, + "compiler-frontend-variant": "GNU", + "compiler-id": "Clang", + "compiler-simulate-id": "", + "config": "Debug", + "cxx-modules": + { + "CMakeFiles/Algo.dir/algo-interface.cppm.o": + { + "bmi-only": false, + "destination": "lib/cmake/my_package/src", + "name": "CXX_MODULES", + "relative-directory": "", + "source": "/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/algo-interface.cppm", + "type": "CXX_MODULES", + "visibility": "PUBLIC" + } + }, + "dir-cur-bld": "/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/build/dev", + "dir-cur-src": "/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules", + "dir-top-bld": "/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/build/dev", + "dir-top-src": "/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules", + "exports": + [ + { + "cxx-module-info-dir": ".", + "destination": "lib/cmake/my_package", + "export-name": "Algo", + "export-prefix": "/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/build/dev/CMakeFiles/Export/0814a8a452340fa10b4323026df361bb", + "install": true, + "namespace": "" + } + ], + "forward-modules-from-target-dirs": [], + "include-dirs": + [ + ".", + "/Users/clausklein/.cache/CPM/fmt/c3ebf53335b44df838d9982d1a0e35afe190e34f/include" + ], + "language": "CXX", + "linked-target-dirs": [], + "module-dir": "/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/build/dev/CMakeFiles/Algo.dir" +} +==> CXXModules.json <== +{ + "modules": + { + "algo": + { + "bmi": "/Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/build/dev/CMakeFiles/Algo.dir/algo.pcm", + "is-private": false + } + }, + "references": + { + "algo": + { + "lookup-method": "by-name", + "path": "CMakeFiles/Algo.dir/algo.pcm" + } + }, + "usages": {} +} +==> algo-impl.cpp.o.modmap <== +-fmodule-file=algo=CMakeFiles/Algo.dir/algo.pcm + +==> algo-interface.cppm.o.modmap <== +-x c++-module +-fmodule-output=CMakeFiles/Algo.dir/algo.pcm +bash-5.2$ !tree +tree +. +|-- CXX.dd +|-- CXXDependInfo.json +|-- CXXModules.json +|-- algo-impl.cpp.o.ddi +|-- algo-impl.cpp.o.ddi.d +|-- algo-impl.cpp.o.modmap +|-- algo-interface.cppm.o +|-- algo-interface.cppm.o.ddi +|-- algo-interface.cppm.o.ddi.d +|-- algo-interface.cppm.o.modmap +`-- algo.pcm + +1 directory, 11 files +bash-5.2$ + diff --git a/.clang-format b/.clang-format index 70e07e9..65a4236 100644 --- a/.clang-format +++ b/.clang-format @@ -56,7 +56,7 @@ BreakConstructorInitializersBeforeComma: true BreakConstructorInitializers: BeforeComma BreakAfterJavaFieldAnnotations: true BreakStringLiterals: true -ColumnLimit: 80 +ColumnLimit: 90 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false diff --git a/.clang-tidy b/.clang-tidy index d509f2c..fefd0a9 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -3,16 +3,21 @@ # misc-non-private-member-variables-in-classes: the options don't do anything # modernize-use-nodiscard: too aggressive, attribute is situationally useful Checks: "*,\ - -google-readability-todo,\ + google-readability-todo,\ -altera-*,\ -fuchsia-*,\ fuchsia-multiple-inheritance,\ -llvm-header-guard,\ -llvm-include-order,\ -llvmlibc-*,\ - -modernize-use-nodiscard,\ - -misc-non-private-member-variables-in-classes" -WarningsAsErrors: '' + modernize-use-nodiscard,\ + misc-non-private-member-variables-in-classes,\ + -misc-include-cleaner,\ + -readability-identifier-naming,\ + -readability-redundant-declaration,\ + -readability-avoid-unconditional-preprocessor-if\ +" +WarningsAsErrors: '*' CheckOptions: - key: 'bugprone-argument-comment.StrictMode' value: 'true' diff --git a/.cmake-format b/.cmake-format new file mode 100644 index 0000000..263f534 --- /dev/null +++ b/.cmake-format @@ -0,0 +1,109 @@ +_help_format: Options affecting formatting. +format: + _help_disable: + - Disable formatting entirely, making cmake-format a no-op + disable: false + _help_line_width: + - How wide to allow formatted cmake files + line_width: 100 + _help_tab_size: + - How many spaces to tab for indent + tab_size: 2 + _help_use_tabchars: + - If true, lines are indented using tab characters (utf-8 + - 0x09) instead of space characters (utf-8 0x20). + - In cases where the layout would require a fractional tab + - character, the behavior of the fractional indentation is + - governed by + use_tabchars: false + _help_fractional_tab_policy: + - If is True, then the value of this variable + - indicates how fractional indentions are handled during + - whitespace replacement. If set to 'use-space', fractional + - indentation is left as spaces (utf-8 0x20). If set to + - '`round-up` fractional indentation is replaced with a single' + - tab character (utf-8 0x09) effectively shifting the column + - to the next tabstop + fractional_tab_policy: use-space + _help_max_subgroups_hwrap: + - If an argument group contains more than this many sub-groups + - (parg or kwarg groups) then force it to a vertical layout. + max_subgroups_hwrap: 4 + _help_max_pargs_hwrap: + - If a positional argument group contains more than this many + - arguments, then force it to a vertical layout. + max_pargs_hwrap: 6 + _help_max_rows_cmdline: + - If a cmdline positional group consumes more than this many + - lines without nesting, then invalidate the layout (and nest) + max_rows_cmdline: 2 + _help_separate_ctrl_name_with_space: + - If true, separate flow control names from their parentheses + - with a space + separate_ctrl_name_with_space: false + _help_separate_fn_name_with_space: + - If true, separate function names from parentheses with a + - space + separate_fn_name_with_space: false + _help_dangle_parens: + - If a statement is wrapped to more than one line, than dangle + - the closing parenthesis on its own line. + dangle_parens: true + _help_dangle_align: + - If the trailing parenthesis must be 'dangled' on its on + - 'line, then align it to this reference: `prefix`: the start' + - 'of the statement, `prefix-indent`: the start of the' + - 'statement, plus one indentation level, `child`: align to' + - the column of the arguments + dangle_align: prefix + _help_min_prefix_chars: + - If the statement spelling length (including space and + - parenthesis) is smaller than this amount, then force reject + - nested layouts. + min_prefix_chars: 4 + _help_max_prefix_chars: + - If the statement spelling length (including space and + - parenthesis) is larger than the tab width by more than this + - amount, then force reject un-nested layouts. + max_prefix_chars: 10 + _help_max_lines_hwrap: + - If a candidate layout is wrapped horizontally but it exceeds + - this many lines, then reject the layout. + max_lines_hwrap: 2 + _help_line_ending: + - What style line endings to use in the output. + line_ending: unix + _help_command_case: + - Format command names consistently as 'lower' or 'upper' case + command_case: canonical + _help_keyword_case: + - Format keywords consistently as 'lower' or 'upper' case + keyword_case: unchanged + _help_always_wrap: + - A list of command names which should always be wrapped + always_wrap: [file, install] + _help_enable_sort: + - If true, the argument lists which are known to be sortable + - will be sorted lexicographicall + enable_sort: true + _help_autosort: + - If true, the parsers may infer whether or not an argument + - list is sortable (without annotation). + autosort: false + _help_require_valid_layout: + - By default, if cmake-format cannot successfully fit + - everything into the desired linewidth it will apply the + - last, most aggressive attempt that it made. If this flag is + - True, however, cmake-format will print error, exit with non- + - zero status code, and write-out nothing + require_valid_layout: false + _help_layout_passes: + - A dictionary mapping layout nodes to a list of wrap + - decisions. See the documentation for more information. + layout_passes: {} + +_help_markup: Options affecting comment reflow and formatting. +markup: + _help_enable_markup: + - enable comment markup parsing and reflow + enable_markup: false diff --git a/.cmake-format.json b/.cmake-format.json new file mode 100644 index 0000000..3b58f43 --- /dev/null +++ b/.cmake-format.json @@ -0,0 +1,33 @@ +{ + "format": { + "disable": false, + "line_width": 100, + "tab_size": 2, + "use_tabchars": false, + "fractional_tab_policy": "use-space", + "max_subgroups_hwrap": 4, + "max_pargs_hwrap": 6, + "max_rows_cmdline": 2, + "separate_ctrl_name_with_space": false, + "separate_fn_name_with_space": false, + "dangle_parens": true, + "dangle_align": "prefix", + "min_prefix_chars": 4, + "max_prefix_chars": 10, + "max_lines_hwrap": 2, + "line_ending": "unix", + "command_case": "canonical", + "keyword_case": "unchanged", + "always_wrap": [ + "file", + "install" + ], + "enable_sort": true, + "autosort": false, + "require_valid_layout": false, + "layout_passes": {} + }, + "markup": { + "enable_markup": false + } +} diff --git a/.github/scripts/conan-profile.sh b/.github/scripts/conan-profile.sh index d201862..b30c8f0 100644 --- a/.github/scripts/conan-profile.sh +++ b/.github/scripts/conan-profile.sh @@ -1,12 +1,19 @@ #!/bin/bash set -e +set -u +set -x -conan profile detect -f +pip3 install --upgrade pip || echo ignored +pip3 install conan cmake ninja gcovr || echo ignored -std=20 +which conan +conan --version +conan profile detect --force + +std=23 if [ "$RUNNER_OS" = Windows ]; then - std=20 + std=23 fi profile="$(conan profile path default)" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84b8307..9f7a768 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,27 +4,27 @@ on: push: branches: - master + - develop pull_request: branches: - - master - develop jobs: lint: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 - with: { python-version: "3.10" } + with: { python-version: "3.12" } - name: Install codespell run: pip3 install codespell - name: Lint - run: cmake -D FORMAT_COMMAND=clang-format-14 -P cmake/lint.cmake + run: cmake -D FORMAT_COMMAND=clang-format-18 -P cmake/lint.cmake - name: Spell check if: always() @@ -33,7 +33,9 @@ jobs: coverage: needs: [lint] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 + + env: { CXX: clang++-18 } # To enable coverage, delete the last line from the conditional below and # edit the "" placeholder to your GitHub name. @@ -51,13 +53,27 @@ jobs: - name: Install Python uses: actions/setup-python@v5 - with: { python-version: "3.10" } + with: { python-version: "3.12" } + + - name: Setup Cpp + uses: aminya/setup-cpp@v1 + with: + compiler: llvm-18 + vcvarsall: ${{ contains(matrix.os, 'windows') }} + clangformat: true + clangtidy: true + cmake: true + # NO! conan: true + gcovr: true + ninja: true + # ... - name: Install dependencies + shell: bash run: | - pip3 install conan + # NO! pip3 install conan cmake ninja gcovr bash < .github/scripts/conan-profile.sh - conan install . -b missing + # conan install . -b missing - name: Configure run: cmake --preset=ci-coverage @@ -70,32 +86,47 @@ jobs: run: ctest --output-on-failure --no-tests=error -j 2 - name: Process coverage info - run: cmake --build build/coverage -t coverage + # run: cmake --build build/coverage -t coverage + run: gcovr . - - name: Submit to codecov.io - uses: codecov/codecov-action@v4 - with: - file: build/coverage/coverage.info + # - name: Submit to codecov.io + # uses: codecov/codecov-action@v4 + # with: + # file: build/coverage/coverage.info sanitize: needs: [lint] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 - env: { CXX: clang++-14 } + env: { CXX: clang++-18 } steps: - uses: actions/checkout@v4 - name: Install Python uses: actions/setup-python@v5 - with: { python-version: "3.10" } + with: { python-version: "3.12" } + + - name: Setup Cpp + uses: aminya/setup-cpp@v1 + with: + compiler: llvm-18 + vcvarsall: ${{ contains(matrix.os, 'windows') }} + clangformat: true + clangtidy: true + cmake: true + # NO! conan: true + gcovr: true + ninja: true + # ... - name: Install dependencies + shell: bash run: | - pip3 install conan + # NO! pip3 install conan cmake ninja gcovr bash < .github/scripts/conan-profile.sh - conan install . -b missing + # conan install . -b missing - name: Configure run: cmake --preset=ci-sanitize @@ -121,38 +152,58 @@ jobs: fail-fast: false matrix: - os: [macos-13, ubuntu-22.04, windows-2022] - - type: [shared, static] - + os: [macos-15, ubuntu-24.04, windows-2022] include: - - { type: shared, shared: YES } - - { type: static, shared: NO } + - { os: macos-15, uname: Darwin } + - { os: ubuntu-24.04, uname: Linux } + - { os: windows-2022, uname: Windows } + + # type: [shared, static] + # include: + # - { type: shared, shared: YES } + # - { type: static, shared: NO } runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - - - name: Install static analyzers - if: matrix.os == 'ubuntu-22.04' - run: >- - sudo apt-get install clang-tidy-14 cppcheck -y -q - - sudo update-alternatives --install - /usr/bin/clang-tidy clang-tidy - /usr/bin/clang-tidy-14 140 + with: + submodules: recursive - name: Install Python - uses: actions/setup-python@v4 - with: { python-version: "3.10" } + if: matrix.os != 'macos-15' + uses: actions/setup-python@v5 + with: { python-version: "3.12" } + + - name: Install llvm-18 + if: matrix.os == 'macos-15' + run: | + brew install conan gcovr ninja llvm + echo $(brew --prefix llvm@18)/bin + echo 'export PATH="/usr/local/opt/llvm/bin:$PATH"' >> ~/.profile + export PATH=$(brew --prefix llvm@18)/bin:$PATH && echo "PATH=$PATH" >> $GITHUB_ENV + echo "CXX=clang++" >> $GITHUB_ENV + + - name: Setup Cpp + if: matrix.os == 'ubuntu-24.04' + uses: aminya/setup-cpp@v1 + with: + compiler: llvm-18 + vcvarsall: ${{ contains(matrix.os, 'windows') }} + clangformat: true + clangtidy: true + cmake: true + # NO! conan: true + gcovr: true + ninja: true + # ... - name: Install dependencies shell: bash run: | - pip3 install conan + # pip3 install conan cmake ninja gcovr bash < .github/scripts/conan-profile.sh - conan install . -b missing + # conan install . -b missing - name: Setup MultiToolTask if: matrix.os == 'windows-2022' @@ -160,30 +211,53 @@ jobs: Add-Content "$env:GITHUB_ENV" 'UseMultiToolTask=true' Add-Content "$env:GITHUB_ENV" 'EnforceProcessCountAcrossBuilds=true' - - name: Configure - shell: pwsh - run: cmake "--preset=ci-$("${{ matrix.os }}".split("-")[0])" - -D BUILD_SHARED_LIBS=${{ matrix.shared }} - - name: Setup PATH - if: matrix.os == 'windows-2022' && matrix.type == 'shared' - run: Add-Content "$env:GITHUB_PATH" "$(Get-Location)\build\Release" - - - name: Build - run: cmake --build build --config Release -j 2 - - - name: Install - run: cmake --install build --config Release --prefix prefix + if: matrix.os == 'windows-2022' + run: Add-Content "$env:GITHUB_PATH" "$(Get-Location)\stagedir\bin" - - name: Test - working-directory: build - run: ctest --output-on-failure --no-tests=error -C Release -j 2 + - name: Configure preset + # if: matrix.os != 'windows-2022' + shell: bash + run: | + export hostSystemName=${{ matrix.uname }} + uname || echo ${hostSystemName} + perl -p -e "s//${hostSystemName}/g;" .CMakeUserPresets.json > CMakeUserPresets.json + cmake --workflow --preset=dev # XXX "--preset=ci-$("${{ matrix.os }}".split("-")[0])" + + # - name: Configure on windows + # if: matrix.os == 'windows-2022' + # shell: pwsh + # run: cmake -G "Visual Studio 17 2022" -S . -B build -D CMAKE_BUILD_TYPE=Release + # -D CMAKE_INSTALL_PREFIX=$(Get-Location)/stagedir -D BUILD_SHARED_LIBS=${{ matrix.shared }} + + # - name: Setup PATH + # if: matrix.os == 'windows-2022' && matrix.type == 'shared' + # run: Add-Content "$env:GITHUB_PATH" "$(Get-Location)\build\Release" + + # - name: Build + # run: cmake --build build --config Release -j 2 + + # - name: Install + # run: cmake --install build --config Release --prefix stagedir + + # - name: Test + # working-directory: build + # run: ctest --output-on-failure --no-tests=error -C Release -j 2 + + # - name: TestInstalledVersion + # if: matrix.os != 'windows-2022' + # run: | + # cmake -B example/build -S example -G Ninja -D CMAKE_BUILD_TYPE=Release \ + # -D "CMAKE_PREFIX_PATH=$PWD/stagedir;$PWD/conan" \ + # # --toolchain "$PWD/conan/conan_toolchain.cmake" + # ninja -C example/build + # ninja -C example/build test docs: # Deploy docs only when builds succeed needs: [sanitize, test] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 # To enable, first you have to create an orphaned gh-pages branch: # @@ -204,11 +278,11 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 - with: { python-version: "3.10" } + - uses: actions/setup-python@v5 + with: { python-version: "3.12" } - name: Install m.css dependencies - run: pip3 install jinja2 Pygments + run: pip3 install jinja2 Pygments cmake ninja - name: Install Doxygen run: sudo apt-get update -q diff --git a/.gitignore b/.gitignore index d0d6dae..9bff477 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,11 @@ build/ cmake-build-*/ conan/ prefix/ +stagedir/ .clangd +.init +*.swp CMakeLists.txt.user CMakeUserPresets.json compile_commands.json +tags diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..dcebc89 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cmake/WindowsToolchain"] + path = cmake/WindowsToolchain + url = https://github.com/MarkSchofield/WindowsToolchain.git diff --git a/.notes.txt b/.notes.txt new file mode 100644 index 0000000..e224806 --- /dev/null +++ b/.notes.txt @@ -0,0 +1,26 @@ +bash-5.2$ cmake-init -s -p conan --std 20 --examples cmake-init-modules +Initialized empty Git repository in /Users/clausklein/Workspace/cpp/cxx20/cmake-init-modules/cmake-init-modules/.git/ + +The project is ready to be used with git. If you are using GitHub, you may +push the project with the following commands from the project directory: + + git add . + git commit -m "Initial commit" + git flow init -d + git remote add origin https://github.com//.git + git push -u origin master + +To get started with developing the project, make sure you read the generated +HACKING.md and BUILDING.md files for how to build the project as a developer or +as a user respectively. There are also some details you may want to fill in in +the README.md, CONTRIBUTING.md and .github/workflows/ci.yml files. + +Now make sure you have at least CMake 3.20 installed for local development, to +make use of all the nice Quality-of-Life improvements in newer releases: +https://cmake.org/download/ + +For more tips, like integration with package managers, please see the Wiki: +https://github.com/friendlyanon/cmake-init/wiki + +You are all set. Have fun programming and create something awesome! +bash-5.2$ diff --git a/CMakeLists.txt b/CMakeLists.txt index c24065f..210f3fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,65 +1,203 @@ -cmake_minimum_required(VERSION 3.14) +cmake_minimum_required(VERSION 3.30...3.31) include(cmake/prelude.cmake) -project( - cmake-init-modules - VERSION 0.1.0 - DESCRIPTION "Short description" - HOMEPAGE_URL "https://example.com/" - LANGUAGES CXX +project(cxx_modules_example VERSION 0.1.0 LANGUAGES CXX) + +# This property setting also needs to be consistent between the +# installed shared library and its consumer, otherwise most +# toolchains will once again reject the consumer's generated BMI. + +if(NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 23) + set(CMAKE_CXX_EXTENSIONS FALSE) + set(CMAKE_CXX_STANDARD_REQUIRED TRUE) +endif() + +set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(CMAKE_VISIBILITY_INLINES_HIDDEN TRUE) + +if(PROJECT_IS_TOP_LEVEL) + include(cmake/AddUninstallTarget.cmake) + include(cmake/lint-targets.cmake) + include(cmake/spell-targets.cmake) +endif() + +# Disable clang-tidy for target +macro(target_disable_clang_tidy TARGET) + find_program(CLANGTIDY clang-tidy) + if(CLANGTIDY) + set_target_properties(${TARGET} PROPERTIES C_CLANG_TIDY "") + set_target_properties(${TARGET} PROPERTIES CXX_CLANG_TIDY "") + endif() +endmacro() + +######################################################################### +# cmake-format: off + +# include(cmake/CPM.cmake) +# instead of find_package(fmt REQUIRED) +# cpmaddpackage( +# NAME fmt +# GIT_TAG 10.2.1 +# GITHUB_REPOSITORY fmtlib/fmt +# SYSTEM YES +# # TODO(CK): OPTIONS "FMT_MODULE ON" +# ) +# if(TARGET fmt) +# target_disable_clang_tidy(fmt) +# endif() + +add_library(Algo SHARED) + +target_sources(Algo + PRIVATE + algo-impl.cpp + PUBLIC + FILE_SET CXX_MODULES + FILES + algo-interface.cppm ) -include(cmake/project-is-top-level.cmake) +# CMake requires the language standard to be specified as compile feature +# when a target provides C++23 modules and the target will be installed +target_compile_features(Algo PUBLIC cxx_std_23) + +include(GenerateExportHeader) +generate_export_header(Algo + CUSTOM_CONTENT_FROM_VARIABLE +) +target_sources(Algo + PUBLIC + FILE_SET HEADERS + BASE_DIRS + ${CMAKE_CURRENT_BINARY_DIR} + FILES + ${CMAKE_CURRENT_BINARY_DIR}/algo_export.h +) + +if(NOT CMAKE_SKIP_INSTALL_RULES) + include(CPack) + include(GNUInstallDirs) + include(CMakePackageConfigHelpers) + + write_basic_package_version_file("my_package-config-version.cmake" COMPATIBILITY SameMajorVersion) + + install(TARGETS Algo + EXPORT my_package-targets + # ... a few details omitted, see the "Deep CMake For Library Authors" talk + FILE_SET CXX_MODULES + # There's currently no convention for this location, see discussion below + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/my_package/src + FILE_SET HEADERS + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # Same as default, could be omitted + INCLUDES + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + install(EXPORT my_package-targets + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/my_package + CXX_MODULES_DIRECTORY . + ) + install( + FILES "${PROJECT_BINARY_DIR}/my_package-config-version.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/my_package + ) + # The following file includes the my_package-targets.cmake file + install(FILES cmake/my_package-config.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/my_package + ) +endif() + +# cmake-format: on +######################################################################### + +if(PROJECT_IS_TOP_LEVEL) + enable_testing() + add_subdirectory(example) + + # # cmake-format: off + # add_test(using-std-test + # ${CMAKE_CTEST_COMMAND} + # -C ${CMAKE_BUILD_TYPE} + # --build-and-test + # "${CMAKE_CURRENT_SOURCE_DIR}/std" + # "${CMAKE_CURRENT_BINARY_DIR}/std" + # --build-generator ${CMAKE_GENERATOR} + # --build-makeprogram ${CMAKE_MAKE_PROGRAM} + # --build-options + # "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" + # "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + # "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" + # "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" + # ) + # cmake-format: on +endif() + +################################################## +return() # NOTE: XXX +################################################## + +# project( +# cmake-init-modules +# VERSION 0.1.0 +# DESCRIPTION "Short description" +# HOMEPAGE_URL "https://example.com/" +# LANGUAGES CXX) + include(cmake/variables.cmake) # ---- Declare library ---- -add_library( - cmake-init-modules_cmake-init-modules - source/cmake-init-modules.cpp -) +add_library(cmake-init-modules_cmake-init-modules source/cmake-init-modules.cpp) add_library(cmake-init-modules::cmake-init-modules ALIAS cmake-init-modules_cmake-init-modules) include(GenerateExportHeader) generate_export_header( - cmake-init-modules_cmake-init-modules - BASE_NAME cmake-init-modules - EXPORT_FILE_NAME export/cmake-init-modules/cmake-init-modules_export.hpp - CUSTOM_CONTENT_FROM_VARIABLE pragma_suppress_c4251 + cmake-init-modules_cmake-init-modules + BASE_NAME + cmake-init-modules + EXPORT_FILE_NAME + export/cmake-init-modules/cmake-init-modules_export.hpp + CUSTOM_CONTENT_FROM_VARIABLE + pragma_suppress_c4251 +) + +# cmake-format: off +target_sources( + cmake-init-modules_cmake-init-modules + PUBLIC FILE_SET HEADERS + BASE_DIRS + ${PROJECT_BINARY_DIR}/export + ${PROJECT_SOURCE_DIR}/include + FILES + include/cmake-init-modules/cmake-init-modules.hpp + ${PROJECT_BINARY_DIR}/export/cmake-init-modules/cmake-init-modules_export.hpp ) +# cmake-format: on if(NOT BUILD_SHARED_LIBS) - target_compile_definitions(cmake-init-modules_cmake-init-modules PUBLIC CMAKE_INIT_MODULES_STATIC_DEFINE) + target_compile_definitions( + cmake-init-modules_cmake-init-modules PUBLIC CMAKE_INIT_MODULES_STATIC_DEFINE + ) endif() set_target_properties( - cmake-init-modules_cmake-init-modules PROPERTIES - CXX_VISIBILITY_PRESET hidden - VISIBILITY_INLINES_HIDDEN YES - VERSION "${PROJECT_VERSION}" - SOVERSION "${PROJECT_VERSION_MAJOR}" - EXPORT_NAME cmake-init-modules - OUTPUT_NAME cmake-init-modules + cmake-init-modules_cmake-init-modules + PROPERTIES CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN YES + VERSION "${PROJECT_VERSION}" + SOVERSION "${PROJECT_VERSION_MAJOR}" + EXPORT_NAME cmake-init-modules + OUTPUT_NAME cmake-init-modules ) -target_include_directories( - cmake-init-modules_cmake-init-modules ${warning_guard} - PUBLIC - "$" -) +target_compile_features(cmake-init-modules_cmake-init-modules PUBLIC cxx_std_23) -target_include_directories( - cmake-init-modules_cmake-init-modules SYSTEM - PUBLIC - "$" +#XXX target_link_libraries(cmake-init-modules_cmake-init-modules PRIVATE fmt::fmt) +target_link_libraries( + cmake-init-modules_cmake-init-modules PRIVATE $ ) -target_compile_features(cmake-init-modules_cmake-init-modules PUBLIC cxx_std_20) - -find_package(fmt REQUIRED) -target_link_libraries(cmake-init-modules_cmake-init-modules PRIVATE fmt::fmt) - # ---- Install rules ---- if(NOT CMAKE_SKIP_INSTALL_RULES) @@ -67,6 +205,7 @@ if(NOT CMAKE_SKIP_INSTALL_RULES) endif() # ---- Examples ---- +enable_testing() if(PROJECT_IS_TOP_LEVEL) option(BUILD_EXAMPLES "Build examples tree." "${cmake-init-modules_DEVELOPER_MODE}") @@ -80,10 +219,7 @@ endif() if(NOT cmake-init-modules_DEVELOPER_MODE) return() elseif(NOT PROJECT_IS_TOP_LEVEL) - message( - AUTHOR_WARNING - "Developer mode is intended for developers of cmake-init-modules" - ) + message(AUTHOR_WARNING "Developer mode is intended for developers of cmake-init-modules") endif() include(cmake/dev-mode.cmake) diff --git a/CMakePresets.json b/CMakePresets.json index 133bda3..8e1cf22 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,8 +1,8 @@ { - "version": 6, + "version": 9, "cmakeMinimumRequired": { "major": 3, - "minor": 25, + "minor": 30, "patch": 0 }, "configurePresets": [ @@ -17,24 +17,32 @@ "systemVars": false }, "errors": { - "dev": true, - "deprecated": true + "dev": false, + "deprecated": false } }, { "name": "dev-mode", "hidden": true, "inherits": "cmake-pedantic", + "installDir": "${sourceDir}/stagedir", "cacheVariables": { - "cmake-init-modules_DEVELOPER_MODE": "ON" + "CMAKE_PREFIX_PATH": { + "type": "path", + "value": "${sourceDir}/stagedir" + }, + "CMAKE_EXPORT_COMPILE_COMMANDS": true, + "CMAKE_MESSAGE_LOG_LEVEL": "WARNING", + "CMAKE_VERIFY_INTERFACE_HEADER_SETS": true, + "cmake-init-modules_DEVELOPER_MODE": true } }, { "name": "conan", "hidden": true, "cacheVariables": { - "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/conan/conan_toolchain.cmake", - "CMAKE_POLICY_DEFAULT_CMP0091": "NEW" + "CMAKE_CONFIGURATION_TYPES": "RelWithDebInfo;Release;Debug", + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/conan/conan_toolchain.cmake" } }, { @@ -56,9 +64,9 @@ "description": "This preset makes sure the project actually builds with at least the specified standard", "hidden": true, "cacheVariables": { - "CMAKE_CXX_EXTENSIONS": "OFF", - "CMAKE_CXX_STANDARD": "20", - "CMAKE_CXX_STANDARD_REQUIRED": "ON" + "CMAKE_CXX_EXTENSIONS": false, + "CMAKE_CXX_STANDARD": "23", + "CMAKE_CXX_STANDARD_REQUIRED": true } }, { @@ -68,28 +76,44 @@ "CMAKE_CXX_FLAGS": "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -fstack-protector-strong -fcf-protection=full -fstack-clash-protection -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast", "CMAKE_EXE_LINKER_FLAGS": "-Wl,--allow-shlib-undefined,--as-needed,-z,noexecstack,-z,relro,-z,now", "CMAKE_SHARED_LINKER_FLAGS": "-Wl,--allow-shlib-undefined,--as-needed,-z,noexecstack,-z,relro,-z,now" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" } }, { "name": "flags-darwin", "hidden": true, "cacheVariables": { - "CMAKE_CXX_FLAGS": "-fstack-protector-strong -fcf-protection=full -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast" + "CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Wundef -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" } }, { "name": "flags-windows", - "description": "Note that all the flags after /W4 are required for MSVC to conform to the language standard", + "description": "NOTE: that all the flags after /W4 are required for MSVC to conform to the language standard", "hidden": true, "cacheVariables": { "CMAKE_CXX_FLAGS": "/sdl /guard:cf /utf-8 /diagnostics:caret /w14165 /w44242 /w44254 /w44263 /w34265 /w34287 /w44296 /w44365 /w44388 /w44464 /w14545 /w14546 /w14547 /w14549 /w14555 /w34619 /w34640 /w24826 /w14905 /w14906 /w14928 /w45038 /W4 /permissive- /volatile:iso /Zc:inline /Zc:preprocessor /Zc:enumTypes /Zc:lambda /Zc:__cplusplus /Zc:externConstexpr /Zc:throwingNew /EHsc", "CMAKE_EXE_LINKER_FLAGS": "/machine:x64 /guard:cf", "CMAKE_SHARED_LINKER_FLAGS": "/machine:x64 /guard:cf" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" } }, { "name": "ci-linux", - "generator": "Unix Makefiles", + "generator": "Ninja", + "description": "This build is only available on Linux", "hidden": true, "inherits": [ "flags-linux", @@ -101,7 +125,8 @@ }, { "name": "ci-darwin", - "generator": "Unix Makefiles", + "generator": "Ninja", + "description": "This build is only available on Darwin", "hidden": true, "inherits": [ "flags-darwin", @@ -114,33 +139,61 @@ { "name": "ci-win64", "inherits": [ - "flags-windows", "ci-std" ], - "generator": "Visual Studio 17 2022", - "architecture": "x64", - "hidden": true + "generator": "Ninja Multi-Config", + "description": "This build is only available on Windows", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "CMAKE_C_COMPILER": "cl", + "CMAKE_CXX_COMPILER": "cl", + "CMAKE_SYSTEM_PROCESSOR": "AMD64", + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/cmake/WindowsToolchain/Windows.MSVC.toolchain.cmake" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } }, { "name": "coverage-linux", "binaryDir": "${sourceDir}/build/coverage", "inherits": "ci-linux", + "description": "This build is only available on Linux", "hidden": true, "cacheVariables": { - "ENABLE_COVERAGE": "ON", + "ENABLE_COVERAGE": true, + "CMAKE_SKIP_INSTALL_RULES": true, "CMAKE_BUILD_TYPE": "Coverage", "CMAKE_CXX_FLAGS_COVERAGE": "-Og -g --coverage -fkeep-inline-functions -fkeep-static-functions", "CMAKE_EXE_LINKER_FLAGS_COVERAGE": "--coverage", "CMAKE_SHARED_LINKER_FLAGS_COVERAGE": "--coverage", - "CMAKE_MAP_IMPORTED_CONFIG_COVERAGE": "Coverage;RelWithDebInfo;Release;Debug;" + "CMAKE_MAP_IMPORTED_CONFIG_COVERAGE": "Coverage;RelWithDebInfo;Release;Debug" + } + }, + { + "name": "coverage-darwin", + "binaryDir": "${sourceDir}/build/coverage", + "inherits": "ci-darwin", + "description": "This build is only available on Darwin", + "hidden": true, + "cacheVariables": { + "ENABLE_COVERAGE": true, + "CMAKE_SKIP_INSTALL_RULES": true, + "CMAKE_BUILD_TYPE": "Coverage", + "CMAKE_CXX_FLAGS_COVERAGE": "-Og -g --coverage", + "CMAKE_EXE_LINKER_FLAGS_COVERAGE": "--coverage", + "CMAKE_SHARED_LINKER_FLAGS_COVERAGE": "--coverage", + "CMAKE_MAP_IMPORTED_CONFIG_COVERAGE": "Coverage;RelWithDebInfo;Release;Debug" } }, { "name": "ci-coverage", "inherits": [ "coverage-linux", - "dev-mode", - "conan" + "dev-mode" ], "cacheVariables": { "COVERAGE_HTML_COMMAND": "" @@ -151,13 +204,14 @@ "binaryDir": "${sourceDir}/build/sanitize", "inherits": [ "ci-linux", - "dev-mode", - "conan" + "dev-mode" ], + "description": "This build is only available on Linux", "cacheVariables": { + "CMAKE_SKIP_INSTALL_RULES": true, "CMAKE_BUILD_TYPE": "Sanitize", "CMAKE_CXX_FLAGS_SANITIZE": "-O2 -g -fsanitize=address,undefined -fno-omit-frame-pointer -fno-common", - "CMAKE_MAP_IMPORTED_CONFIG_SANITIZE": "Sanitize;RelWithDebInfo;Release;Debug;" + "CMAKE_MAP_IMPORTED_CONFIG_SANITIZE": "Sanitize;RelWithDebInfo;Release;Debug" } }, { @@ -165,7 +219,7 @@ "binaryDir": "${sourceDir}/build", "hidden": true, "cacheVariables": { - "CMAKE_CONFIGURATION_TYPES": "RelWithDebInfo;Release;Debug;" + "CMAKE_CONFIGURATION_TYPES": "RelWithDebInfo;Release;Debug" } }, { @@ -173,44 +227,36 @@ "inherits": [ "ci-build", "ci-darwin", - "dev-mode", - "conan" - ], - "condition": { - "type": "equals", - "lhs": "${hostSystemName}", - "rhs": "Darwin" - } + "dev-mode" + ] + }, + { + "name": "ci-Darwin", + "inherits": "ci-macos" }, { "name": "ci-ubuntu", "inherits": [ "ci-build", "ci-linux", - "clang-tidy", - "conan", - "cppcheck", "dev-mode" - ], - "condition": { - "type": "equals", - "lhs": "${hostSystemName}", - "rhs": "Linux" - } + ] + }, + { + "name": "ci-Linux", + "inherits": "ci-ubuntu" }, { "name": "ci-windows", "inherits": [ "ci-build", "ci-win64", - "dev-mode", - "conan" - ], - "condition": { - "type": "equals", - "lhs": "${hostSystemName}", - "rhs": "Windows" - } + "dev-mode" + ] + }, + { + "name": "ci-Windows", + "inherits": "ci-windows" } ] } diff --git a/CMakeUserPresets.jsonnet b/CMakeUserPresets.jsonnet new file mode 100644 index 0000000..3643d55 --- /dev/null +++ b/CMakeUserPresets.jsonnet @@ -0,0 +1,184 @@ +# jrsonnet --preserve-order CMakeUserPresets.jsonnet > CMakeUserPresets.json + +local archs = [ + 'Linux', + 'Darwin', + 'win64', +]; + +local types = [ + 'dev', + # 'sanitize', + # 'coverage', +]; + +local link_modes = [ + # 'static', + 'dynamic', +]; + +local configs = [ + 'Debug', + # 'Release', +]; + +local cp_generator(arch, type, link_mode) = + { + name: arch + '-' + type + '-' + link_mode, + inherits: [type, link_mode], + }; + +local bp_generator(arch, type, link_mode, config) = + { + name: arch + '-' + type + '-' + link_mode + '-' + std.asciiLower(config), + # configurePreset: arch + '-' + type + '-' + link_mode, + configurePreset: type + '-' + arch, + configuration: config, + }; + +local tp_generator(arch, type, link_mode, config) = + { + name: arch + '-' + type + '-' + link_mode + '-' + std.asciiLower(config), + # configurePreset: arch + '-' + type + '-' + link_mode, + configurePreset: type + '-' + arch, + output: { outputOnFailure: true }, + execution: { noTestsAction: 'ignore', stopOnFailure: true }, + }; + +local wp_generator(arch, type, link_mode, config) = + { + name: arch + '-' + type + '-' + link_mode + '-' + std.asciiLower(config), + steps: [ + { + type: 'configure', + # name: arch + '-' + type + '-' + link_mode, + name: type + '-' + arch, + }, + { + type: 'build', + name: arch + '-' + type + '-' + link_mode + '-' + std.asciiLower(config), + }, + { + type: 'test', + name: arch + '-' + type + '-' + link_mode + '-' + std.asciiLower(config), + }, + { + type: 'package', + name: arch + '-' + type + '-' + link_mode + '-' + std.asciiLower(config), + }, + ], + }; + +local pp_generator(arch, type, link_mode, config) = + { + name: arch + '-' + type + '-' + link_mode + '-' + std.asciiLower(config), + # configurePreset: arch + '-' + type + '-' + link_mode, + configurePreset: type + '-' + arch, + generators: [ + 'TGZ', + ], + "configurations": [ + config + ], + }; + +{ + version: 9, + cmakeMinimumRequired: { + major: 3, + minor: 30, + patch: 0, + }, + configurePresets: [ + { + name: 'default', + hidden: true, + displayName: 'Default Config', + description: 'Default build using Ninja Multi-Config generator', + generator: 'Ninja Multi-Config', + binaryDir: '${sourceDir}/build/${presetName}', + cacheVariables: { + CMAKE_EXPORT_COMPILE_COMMANDS: true, + CPM_USE_LOCAL_PACKAGES: true, + BUILD_TESTING: true, + }, + }, + { + name: 'asan', + inherits: 'default', + hidden: true, + cacheVariables: { + CMAKE_CXX_FLAGS_SANITIZE: '-U_FORTIFY_SOURCE -O2 -g -fsanitize=address,undefined -fno-omit-frame-pointer -fno-common', + }, + }, + { + name: 'static', + hidden: true, + cacheVariables: { + 'BUILD_SHARED_LIBS': false, + }, + }, + { + name: 'dynamic', + hidden: true, + cacheVariables: { + 'BUILD_SHARED_LIBS': true, + }, + }, + { + "name": "dev-common", + "hidden": true, + "inherits": [ + "dev-mode" + ], + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/${presetName}", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": true, + "BUILD_MCSS_DOCS": false, + "BUILD_SHARED_LIBS": true + }, + "environment": { + "CPM_USE_LOCAL_PACKAGES": "OFF" + } + }, + { + "name": "dev-Linux", + "inherits": [ + "dev-common", + "ci-linux" + ], + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "dev-Darwin", + "inherits": [ + "dev-common", + "ci-darwin" + ], + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "dev-win64", + "inherits": [ + "dev-common", + "cppcheck", + "ci-win64" + ], + "environment": { + "UseMultiToolTask": "ON", + "EnforceProcessCountAcrossBuilds": "ON" + } + }, + ], # TODO: + [cp_generator(arch, type, link_mode) for arch in archs for type in types for link_mode in link_modes], + + buildPresets: [] + [bp_generator(arch, type, link_mode, config) for arch in archs for type in types for link_mode in link_modes for config in configs], + testPresets: [] + [tp_generator(arch, type, link_mode, config) for arch in archs for type in types for link_mode in link_modes for config in configs], + packagePresets: [] + [pp_generator(arch, type, link_mode, config) for arch in archs for type in types for link_mode in link_modes for config in configs], + workflowPresets: [] + [wp_generator(arch, type, link_mode, config) for arch in archs for type in types for link_mode in link_modes for config in configs], +} + diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..6375baf --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,56 @@ +# Standard stuff + +.SUFFIXES: + +MAKEFLAGS+= --no-builtin-rules # Disable the built-in implicit rules. +# MAKEFLAGS+= --warn-undefined-variables # Warn when an undefined variable is referenced. +# MAKEFLAGS+= --include-dir=$(CURDIR)/conan # Search DIRECTORY for included makefiles (*.mk). + +# export CC=gcc-14 +# export CXX=g++-14 +export CC?=clang-19 +export CXX?=$(shell type -f clang++) +export CMAKE_EXPORT_COMPILE_COMMANDS=YES +export CPM_USE_LOCAL_PACKAGES=NO + +export hostSystemName=$(shell uname) + +CONAN_HOME=$(shell conan config home) +# BUILD_TYPE=Release +BUILD_TYPE=Debug + +.PHONY: all clean distclean check format test + +all: .init # conan + cmake --workflow --preset dev # XXX --fresh + # FIXME: gcovr -v + +check: all + -run-clang-tidy -p build/dev + -iwyu_tool -p build/dev/ *.cpp -- -Xiwyu --cxx17ns + +.init: .CMakeUserPresets.json + # TODO: jrsonnet --preserve-order CMakeUserPresets.jsonnet > CMakeUserPresets.json || + perl -p -e 's//${hostSystemName}/g;' .CMakeUserPresets.json > CMakeUserPresets.json + mkdir -p build/coverage/ + touch .init + +conan: conanfile.py GNUmakefile + conan profile detect -f + conan install . -s build_type=$(BUILD_TYPE) -s compiler.cppstd=20 -b missing + +clean: + rm -rf build example/build + +distclean: clean + rm -rf conan stagedir .init CMakeUserPresets.json + # XXX NO! git clean -xdf + +format: distclean + find . -name CMakeLists.txt -o -name '*.cmake' | xargs cmake-format -i + git clang-format master + +# Anything we don't know how to build will use this rule. +# The command is a do-nothing command. +# +% :: ; diff --git a/HACKING.md b/HACKING.md index 2825248..c4b6eb4 100644 --- a/HACKING.md +++ b/HACKING.md @@ -31,16 +31,17 @@ the project: ```json { - "version": 2, + "version": 6, "cmakeMinimumRequired": { "major": 3, - "minor": 14, + "minor": 28, "patch": 0 }, "configurePresets": [ { "name": "dev", "binaryDir": "${sourceDir}/build/dev", + "generator": "Ninja", "inherits": ["dev-mode", "conan", "ci-"], "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" @@ -63,6 +64,25 @@ the project: "outputOnFailure": true } } + ], + "workflowPresets": [ + { + "name": "dev", + "steps": [ + { + "type": "configure", + "name": "dev" + }, + { + "type": "build", + "name": "dev" + }, + { + "type": "test", + "name": "dev" + } + ] + } ] } ``` @@ -72,9 +92,9 @@ the operating system you have, which may be `win64`, `linux` or `darwin`. You can see what these correspond to in the [`CMakePresets.json`](CMakePresets.json) file. -`CMakeUserPresets.json` is also the perfect place in which you can put all -sorts of things that you would otherwise want to pass to the configure command -in the terminal. +[`CMakeUserPresets.json`](.CMakeUserPresets.json) file is also the perfect place +in which you can put all sorts of things that you would otherwise want to pass +to the configure command in the terminal. > **Note** > Some editors are pretty greedy with how they open projects with presets. diff --git a/README.md b/README.md index 7ab2917..e1194ce 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # cmake-init-modules -This is the cmake-init-modules project. +This is the [cmake-init](https://github.com/friendlyanon/cmake-init) generated example project. # Building and installing diff --git a/algo-impl.cpp b/algo-impl.cpp new file mode 100644 index 0000000..1391b6f --- /dev/null +++ b/algo-impl.cpp @@ -0,0 +1,20 @@ +module; + +#include + +#if defined(__cpp_lib_print) +# include +using std::print; +#else +# include +using fmt::print; +#endif + +module algo; + +// FIXME(CK): import fmt; + +void Algo::helloWorld() +{ + print("hello {}\n", m_name); +} diff --git a/algo-interface.cppm b/algo-interface.cppm new file mode 100644 index 0000000..fe277c0 --- /dev/null +++ b/algo-interface.cppm @@ -0,0 +1,21 @@ +module; + +#include // for string +#include // for move + +#include // <-- Generated header added to the global fragment + +export module algo; // <-- Annotation not currently required, but see discussion below + +export class ALGO_EXPORT Algo // <-- ALGO_EXPORT annotation added to the class definition +{ +public: + explicit Algo(std::string name) + : m_name(std::move(name)) + { + } + void helloWorld(); + +private: + std::string m_name; +}; diff --git a/cmake/AddUninstallTarget.cmake b/cmake/AddUninstallTarget.cmake new file mode 100644 index 0000000..efbac59 --- /dev/null +++ b/cmake/AddUninstallTarget.cmake @@ -0,0 +1,102 @@ +# SPDX-FileCopyrightText: 2012-2021 Istituto Italiano di Tecnologia (IIT) +# SPDX-FileCopyrightText: 2008-2013 Kitware Inc. +# SPDX-License-Identifier: BSD-3-Clause + +#[=======================================================================[.rst: +AddUninstallTarget +------------------ + +Add the "uninstall" target for your project:: + + include(AddUninstallTarget) + + +will create a file ``cmake_uninstall.cmake`` in the build directory and add a +custom target ``uninstall`` (or ``UNINSTALL`` on Visual Studio and Xcode) that +will remove the files installed by your package (using +``install_manifest.txt``). +See also +https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake + +The :module:`AddUninstallTarget` module must be included in your main +``CMakeLists.txt``. If included in a subdirectory it does nothing. +This allows you to use it safely in your main ``CMakeLists.txt`` and include +your project using ``add_subdirectory`` (for example when using it with +:cmake:module:`FetchContent`). + +If the ``uninstall`` target already exists, the module does nothing. +#]=======================================================================] + +# AddUninstallTarget works only when included in the main CMakeLists.txt +if(NOT "${CMAKE_CURRENT_BINARY_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") + return() +endif() + +# The name of the target is uppercase in MSVC and Xcode (for coherence with the +# other standard targets) +if("${CMAKE_GENERATOR}" MATCHES "^(Visual Studio|Xcode)") + set(_uninstall "UNINSTALL") +else() + set(_uninstall "uninstall") +endif() + +# If target is already defined don't do anything +if(TARGET ${_uninstall}) + return() +endif() + +set(_filename cmake_uninstall.cmake) + +file( + WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_filename}" + "if(NOT EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\") + message(WARNING \"Cannot find install manifest: \\\"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\\\"\") + return() +endif() + +file(READ \"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\" files) +string(STRIP \"\${files}\" files) +string(REGEX REPLACE \"\\n\" \";\" files \"\${files}\") +list(REVERSE files) +foreach(file \${files}) + if(IS_SYMLINK \"\$ENV{DESTDIR}\${file}\" OR EXISTS \"\$ENV{DESTDIR}\${file}\") + message(STATUS \"Uninstalling: \$ENV{DESTDIR}\${file}\") + execute_process( + COMMAND \${CMAKE_COMMAND} -E remove \"\$ENV{DESTDIR}\${file}\" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval) + if(NOT \"\${rm_retval}\" EQUAL 0) + message(FATAL_ERROR \"Problem when removing \\\"\$ENV{DESTDIR}\${file}\\\"\") + endif() + else() + message(STATUS \"Not-found: \$ENV{DESTDIR}\${file}\") + endif() +endforeach(file) +" +) + +set(_desc "Uninstall the project...") +if(CMAKE_GENERATOR STREQUAL "Unix Makefiles") + set(_comment + COMMAND + \$\(CMAKE_COMMAND\) + -E + cmake_echo_color + --switch=$\(COLOR\) + --cyan + "${_desc}" + ) +else() + set(_comment COMMENT "${_desc}") +endif() +add_custom_target( + ${_uninstall} + ${_comment} + COMMAND ${CMAKE_COMMAND} -P ${_filename} + USES_TERMINAL + BYPRODUCTS uninstall_byproduct + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" +) +set_property(SOURCE uninstall_byproduct PROPERTY SYMBOLIC 1) + +set_property(TARGET ${_uninstall} PROPERTY FOLDER "CMakePredefinedTargets") diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake new file mode 100644 index 0000000..d311a8d --- /dev/null +++ b/cmake/CPM.cmake @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: MIT +# +# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors + +set(CPM_DOWNLOAD_VERSION 0.40.2) +set(CPM_HASH_SUM "c8cdc32c03816538ce22781ed72964dc864b2a34a310d3b7104812a5ca2d835d") + +if(CPM_SOURCE_CACHE) + set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +elseif(DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +else() + set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +endif() + +# Expand relative path. This is important if the provided path contains a tilde (~) +get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) + +file( + DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake + ${CPM_DOWNLOAD_LOCATION} + EXPECTED_HASH SHA256=${CPM_HASH_SUM} +) + +include(${CPM_DOWNLOAD_LOCATION}) diff --git a/cmake/WindowsToolchain b/cmake/WindowsToolchain new file mode 160000 index 0000000..b44662d --- /dev/null +++ b/cmake/WindowsToolchain @@ -0,0 +1 @@ +Subproject commit b44662d3e3fc1a4375e10a856ce098fc1507db1c diff --git a/cmake/coverage.cmake b/cmake/coverage.cmake index c89cc16..f7ead70 100644 --- a/cmake/coverage.cmake +++ b/cmake/coverage.cmake @@ -2,32 +2,22 @@ # We use variables separate from what CTest uses, because those have # customization issues -set( - COVERAGE_TRACE_COMMAND - lcov -c -q - -o "${PROJECT_BINARY_DIR}/coverage.info" - -d "${PROJECT_BINARY_DIR}" - --include "${PROJECT_SOURCE_DIR}/*" - CACHE STRING - "; separated command to generate a trace for the 'coverage' target" +set(COVERAGE_TRACE_COMMAND lcov -c -q -o "${PROJECT_BINARY_DIR}/coverage.info" -d + "${PROJECT_BINARY_DIR}" --include "${PROJECT_SOURCE_DIR}/*" + CACHE STRING "; separated command to generate a trace for the 'coverage' target" ) -set( - COVERAGE_HTML_COMMAND - genhtml --legend -f -q - "${PROJECT_BINARY_DIR}/coverage.info" - -p "${PROJECT_SOURCE_DIR}" - -o "${PROJECT_BINARY_DIR}/coverage_html" - CACHE STRING - "; separated command to generate an HTML report for the 'coverage' target" +set(COVERAGE_HTML_COMMAND genhtml --legend -f -q "${PROJECT_BINARY_DIR}/coverage.info" -p + "${PROJECT_SOURCE_DIR}" -o "${PROJECT_BINARY_DIR}/coverage_html" + CACHE STRING "; separated command to generate an HTML report for the 'coverage' target" ) # ---- Coverage target ---- add_custom_target( - coverage - COMMAND ${COVERAGE_TRACE_COMMAND} - COMMAND ${COVERAGE_HTML_COMMAND} - COMMENT "Generating coverage report" - VERBATIM + coverage + COMMAND ${COVERAGE_TRACE_COMMAND} + COMMAND ${COVERAGE_HTML_COMMAND} + COMMENT "Generating coverage report" + VERBATIM ) diff --git a/cmake/dev-mode.cmake b/cmake/dev-mode.cmake index 0011f5c..1d9f264 100644 --- a/cmake/dev-mode.cmake +++ b/cmake/dev-mode.cmake @@ -1,6 +1,6 @@ include(cmake/folders.cmake) -include(CTest) +option(BUILD_TESTING "" ${PROJECT_IS_TOP_LEVEL}) if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/cmake/docs-ci.cmake b/cmake/docs-ci.cmake index ae7f0c7..b45eabd 100644 --- a/cmake/docs-ci.cmake +++ b/cmake/docs-ci.cmake @@ -13,20 +13,15 @@ set(src "${PROJECT_SOURCE_DIR}") set(mcss_SOURCE_DIR "${bin}/docs/.ci") if(NOT IS_DIRECTORY "${mcss_SOURCE_DIR}") file(MAKE_DIRECTORY "${mcss_SOURCE_DIR}") - file( - DOWNLOAD - https://github.com/friendlyanon/m.css/releases/download/release-1/mcss.zip - "${mcss_SOURCE_DIR}/mcss.zip" - STATUS status - EXPECTED_MD5 00cd2757ebafb9bcba7f5d399b3bec7f + file(DOWNLOAD https://github.com/friendlyanon/m.css/releases/download/release-1/mcss.zip + "${mcss_SOURCE_DIR}/mcss.zip" STATUS status EXPECTED_MD5 00cd2757ebafb9bcba7f5d399b3bec7f ) if(NOT status MATCHES "^0;") message(FATAL_ERROR "Download failed with ${status}") endif() execute_process( - COMMAND "${CMAKE_COMMAND}" -E tar xf mcss.zip - WORKING_DIRECTORY "${mcss_SOURCE_DIR}" - RESULT_VARIABLE result + COMMAND "${CMAKE_COMMAND}" -E tar xf mcss.zip WORKING_DIRECTORY "${mcss_SOURCE_DIR}" + RESULT_VARIABLE result ) if(NOT result EQUAL "0") message(FATAL_ERROR "Extraction failed with ${result}") @@ -41,7 +36,9 @@ endif() # ---- Process project() call in CMakeLists.txt ---- -file(READ "${src}/CMakeLists.txt" content) +file( + READ "${src}/CMakeLists.txt" content +) string(FIND "${content}" "project(" index) if(index EQUAL "-1") @@ -55,7 +52,10 @@ if(index EQUAL "-1") endif() string(SUBSTRING "${content}" 0 "${index}" content) -file(WRITE "${bin}/docs-ci.project.cmake" "docs_${content}\n)\n") +file( + WRITE "${bin}/docs-ci.project.cmake" + "docs_${content}\n)\n" +) macro(list_pop_front list out) list(GET "${list}" 0 "${out}") @@ -100,12 +100,13 @@ endforeach() set(mcss_script "${mcss_SOURCE_DIR}/documentation/doxygen.py") set(config "${bin}/docs/conf.py") -file(REMOVE_RECURSE "${out}/html" "${out}/xml") +file( + REMOVE_RECURSE "${out}/html" "${out}/xml" +) execute_process( - COMMAND "${Python3_EXECUTABLE}" "${mcss_script}" "${config}" - WORKING_DIRECTORY "${bin}/docs" - RESULT_VARIABLE result + COMMAND "${Python3_EXECUTABLE}" "${mcss_script}" "${config}" WORKING_DIRECTORY "${bin}/docs" + RESULT_VARIABLE result ) if(NOT result EQUAL "0") message(FATAL_ERROR "m.css returned with ${result}") diff --git a/cmake/docs.cmake b/cmake/docs.cmake index c6cdda6..ded1e01 100644 --- a/cmake/docs.cmake +++ b/cmake/docs.cmake @@ -7,12 +7,12 @@ endif() include(FetchContent) FetchContent_Declare( - mcss URL - https://github.com/friendlyanon/m.css/releases/download/release-1/mcss.zip - URL_MD5 00cd2757ebafb9bcba7f5d399b3bec7f - SOURCE_DIR "${PROJECT_BINARY_DIR}/mcss" - UPDATE_DISCONNECTED YES - ${extract_timestamps} + mcss + URL https://github.com/friendlyanon/m.css/releases/download/release-1/mcss.zip + URL_MD5 00cd2757ebafb9bcba7f5d399b3bec7f + SOURCE_DIR "${PROJECT_BINARY_DIR}/mcss" + UPDATE_DISCONNECTED YES + ${extract_timestamps} ) FetchContent_MakeAvailable(mcss) @@ -20,8 +20,7 @@ find_package(Python3 3.6 REQUIRED) # ---- Declare documentation target ---- -set( - DOXYGEN_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/docs" +set(DOXYGEN_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/docs" CACHE PATH "Path for the generated Doxygen documentation" ) @@ -35,12 +34,11 @@ set(mcss_script "${mcss_SOURCE_DIR}/documentation/doxygen.py") set(config "${working_dir}/conf.py") add_custom_target( - docs - COMMAND "${CMAKE_COMMAND}" -E remove_directory - "${DOXYGEN_OUTPUT_DIRECTORY}/html" - "${DOXYGEN_OUTPUT_DIRECTORY}/xml" - COMMAND "${Python3_EXECUTABLE}" "${mcss_script}" "${config}" - COMMENT "Building documentation using Doxygen and m.css" - WORKING_DIRECTORY "${working_dir}" - VERBATIM + docs + COMMAND "${CMAKE_COMMAND}" -E remove_directory "${DOXYGEN_OUTPUT_DIRECTORY}/html" + "${DOXYGEN_OUTPUT_DIRECTORY}/xml" + COMMAND "${Python3_EXECUTABLE}" "${mcss_script}" "${config}" + COMMENT "Building documentation using Doxygen and m.css" + WORKING_DIRECTORY "${working_dir}" + VERBATIM ) diff --git a/cmake/install-config.cmake b/cmake/install-config.cmake index dcd03e6..3aa6089 100644 --- a/cmake/install-config.cmake +++ b/cmake/install-config.cmake @@ -1,4 +1,4 @@ -include(CMakeFindDependencyMacro) -find_dependency(fmt) +# include(CMakeFindDependencyMacro) +# find_dependency(fmt) include("${CMAKE_CURRENT_LIST_DIR}/cmake-init-modulesTargets.cmake") diff --git a/cmake/install-rules.cmake b/cmake/install-rules.cmake index 4b349ba..fefd2db 100644 --- a/cmake/install-rules.cmake +++ b/cmake/install-rules.cmake @@ -1,8 +1,5 @@ if(PROJECT_IS_TOP_LEVEL) - set( - CMAKE_INSTALL_INCLUDEDIR "include/cmake-init-modules-${PROJECT_VERSION}" - CACHE PATH "" - ) + set(CMAKE_INSTALL_INCLUDEDIR "include/cmake-init-modules-${PROJECT_VERSION}" CACHE PATH "") endif() include(CMakePackageConfigHelpers) @@ -11,60 +8,46 @@ include(GNUInstallDirs) # find_package() call for consumers to find this project set(package cmake-init-modules) -install( - DIRECTORY - include/ - "${PROJECT_BINARY_DIR}/export/" - DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" - COMPONENT cmake-init-modules_Development +# cmake-format: off +install(TARGETS cmake-init-modules_cmake-init-modules + EXPORT cmake-init-modulesTargets + RUNTIME COMPONENT cmake-init-modules_Runtime + LIBRARY COMPONENT cmake-init-modules_Runtime NAMELINK_COMPONENT cmake-init-modules_Development + ARCHIVE COMPONENT cmake-init-modules_Development + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + FILE_SET HEADERS ) +# cmake-format: on -install( - TARGETS cmake-init-modules_cmake-init-modules - EXPORT cmake-init-modulesTargets - RUNTIME # - COMPONENT cmake-init-modules_Runtime - LIBRARY # - COMPONENT cmake-init-modules_Runtime - NAMELINK_COMPONENT cmake-init-modules_Development - ARCHIVE # - COMPONENT cmake-init-modules_Development - INCLUDES # - DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" -) - -write_basic_package_version_file( - "${package}ConfigVersion.cmake" - COMPATIBILITY SameMajorVersion -) +write_basic_package_version_file("${package}ConfigVersion.cmake" COMPATIBILITY SameMajorVersion) # Allow package maintainers to freely override the path for the configs -set( - cmake-init-modules_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${package}" +set(cmake-init-modules_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${package}" CACHE PATH "CMake package config location relative to the install prefix" ) mark_as_advanced(cmake-init-modules_INSTALL_CMAKEDIR) install( - FILES cmake/install-config.cmake - DESTINATION "${cmake-init-modules_INSTALL_CMAKEDIR}" - RENAME "${package}Config.cmake" - COMPONENT cmake-init-modules_Development + FILES cmake/install-config.cmake + DESTINATION "${cmake-init-modules_INSTALL_CMAKEDIR}" + RENAME "${package}Config.cmake" + COMPONENT cmake-init-modules_Development ) install( - FILES "${PROJECT_BINARY_DIR}/${package}ConfigVersion.cmake" - DESTINATION "${cmake-init-modules_INSTALL_CMAKEDIR}" - COMPONENT cmake-init-modules_Development + FILES "${PROJECT_BINARY_DIR}/${package}ConfigVersion.cmake" + DESTINATION "${cmake-init-modules_INSTALL_CMAKEDIR}" + COMPONENT cmake-init-modules_Development ) install( - EXPORT cmake-init-modulesTargets - NAMESPACE cmake-init-modules:: - DESTINATION "${cmake-init-modules_INSTALL_CMAKEDIR}" - COMPONENT cmake-init-modules_Development + EXPORT cmake-init-modulesTargets + NAMESPACE cmake-init-modules:: + DESTINATION "${cmake-init-modules_INSTALL_CMAKEDIR}" + COMPONENT cmake-init-modules_Development ) if(PROJECT_IS_TOP_LEVEL) + set(CPACK_GENERATOR TGZ) include(CPack) endif() diff --git a/cmake/lint-targets.cmake b/cmake/lint-targets.cmake index 244d521..e73d7b3 100644 --- a/cmake/lint-targets.cmake +++ b/cmake/lint-targets.cmake @@ -1,34 +1,31 @@ -set( - FORMAT_PATTERNS - source/*.cpp source/*.hpp +set(FORMAT_PATTERNS + # CMake*Presets.json + source/*.cpp + source/*.hpp include/*.hpp - test/*.cpp test/*.hpp - example/*.cpp example/*.hpp - CACHE STRING - "; separated patterns relative to the project source dir to format" + test/*.cpp + test/*.hpp + example/*.cpp + example/*.hpp + CACHE STRING "; separated patterns relative to the project source dir to format" ) set(FORMAT_COMMAND clang-format CACHE STRING "Formatter to use") add_custom_target( - format-check - COMMAND "${CMAKE_COMMAND}" - -D "FORMAT_COMMAND=${FORMAT_COMMAND}" - -D "PATTERNS=${FORMAT_PATTERNS}" - -P "${PROJECT_SOURCE_DIR}/cmake/lint.cmake" - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - COMMENT "Linting the code" - VERBATIM + format-check + COMMAND "${CMAKE_COMMAND}" -D "FORMAT_COMMAND=${FORMAT_COMMAND}" -D "PATTERNS=${FORMAT_PATTERNS}" + -P "${PROJECT_SOURCE_DIR}/cmake/lint.cmake" + WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" + COMMENT "Linting the code" + VERBATIM ) add_custom_target( - format-fix - COMMAND "${CMAKE_COMMAND}" - -D "FORMAT_COMMAND=${FORMAT_COMMAND}" - -D "PATTERNS=${FORMAT_PATTERNS}" - -D FIX=YES - -P "${PROJECT_SOURCE_DIR}/cmake/lint.cmake" - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - COMMENT "Fixing the code" - VERBATIM + format-fix + COMMAND "${CMAKE_COMMAND}" -D "FORMAT_COMMAND=${FORMAT_COMMAND}" -D "PATTERNS=${FORMAT_PATTERNS}" + -D FIX=YES -P "${PROJECT_SOURCE_DIR}/cmake/lint.cmake" + WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" + COMMENT "Fixing the code" + VERBATIM ) diff --git a/cmake/lint.cmake b/cmake/lint.cmake index c0d2725..70d5042 100644 --- a/cmake/lint.cmake +++ b/cmake/lint.cmake @@ -8,11 +8,15 @@ endmacro() default(FORMAT_COMMAND clang-format) default( - PATTERNS - source/*.cpp source/*.hpp - include/*.hpp - test/*.cpp test/*.hpp - example/*.cpp example/*.hpp + PATTERNS + # CMake*Presets.json + source/*.cpp + source/*.hpp + include/*.hpp + test/*.cpp + test/*.hpp + example/*.cpp + example/*.hpp ) default(FIX NO) @@ -23,17 +27,17 @@ if(FIX) set(args "") endif() -file(GLOB_RECURSE files ${PATTERNS}) +file( + GLOB_RECURSE files ${PATTERNS} +) set(badly_formatted "") set(output "") string(LENGTH "${CMAKE_SOURCE_DIR}/" path_prefix_length) foreach(file IN LISTS files) execute_process( - COMMAND "${FORMAT_COMMAND}" --style=file "${flag}" "${file}" - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - RESULT_VARIABLE result - ${args} + COMMAND "${FORMAT_COMMAND}" --style=file "${flag}" "${file}" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" RESULT_VARIABLE result ${args} ) if(NOT result EQUAL "0") message(FATAL_ERROR "'${file}': formatter returned with ${result}") diff --git a/cmake/my_package-config.cmake b/cmake/my_package-config.cmake new file mode 100644 index 0000000..eaba36c --- /dev/null +++ b/cmake/my_package-config.cmake @@ -0,0 +1,4 @@ +# include(CMakeFindDependencyMacro) +# TODO(CK): find_dependency(fmt) + +include("${CMAKE_CURRENT_LIST_DIR}/my_package-targets.cmake") diff --git a/cmake/prelude.cmake b/cmake/prelude.cmake index c37d590..f80c416 100644 --- a/cmake/prelude.cmake +++ b/cmake/prelude.cmake @@ -2,7 +2,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) message( - FATAL_ERROR + FATAL_ERROR "In-source builds are not supported. " "Please read the BUILDING document before trying to build this project. " "You may need to delete 'CMakeCache.txt' and 'CMakeFiles/' first." diff --git a/cmake/project-is-top-level.cmake b/cmake/project-is-top-level.cmake deleted file mode 100644 index 3435fc0..0000000 --- a/cmake/project-is-top-level.cmake +++ /dev/null @@ -1,6 +0,0 @@ -# This variable is set by project() in CMake 3.21+ -string( - COMPARE EQUAL - "${CMAKE_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}" - PROJECT_IS_TOP_LEVEL -) diff --git a/cmake/spell-targets.cmake b/cmake/spell-targets.cmake index 0c21cab..16c6111 100644 --- a/cmake/spell-targets.cmake +++ b/cmake/spell-targets.cmake @@ -1,22 +1,19 @@ set(SPELL_COMMAND codespell CACHE STRING "Spell checker to use") add_custom_target( - spell-check - COMMAND "${CMAKE_COMMAND}" - -D "SPELL_COMMAND=${SPELL_COMMAND}" - -P "${PROJECT_SOURCE_DIR}/cmake/spell.cmake" - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - COMMENT "Checking spelling" - VERBATIM + spell-check + COMMAND "${CMAKE_COMMAND}" -D "SPELL_COMMAND=${SPELL_COMMAND}" -P + "${PROJECT_SOURCE_DIR}/cmake/spell.cmake" + WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" + COMMENT "Checking spelling" + VERBATIM ) add_custom_target( - spell-fix - COMMAND "${CMAKE_COMMAND}" - -D "SPELL_COMMAND=${SPELL_COMMAND}" - -D FIX=YES - -P "${PROJECT_SOURCE_DIR}/cmake/spell.cmake" - WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" - COMMENT "Fixing spelling errors" - VERBATIM + spell-fix + COMMAND "${CMAKE_COMMAND}" -D "SPELL_COMMAND=${SPELL_COMMAND}" -D FIX=YES -P + "${PROJECT_SOURCE_DIR}/cmake/spell.cmake" + WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" + COMMENT "Fixing spelling errors" + VERBATIM ) diff --git a/cmake/spell.cmake b/cmake/spell.cmake index e05ecd7..a4f3c36 100644 --- a/cmake/spell.cmake +++ b/cmake/spell.cmake @@ -15,9 +15,7 @@ if(FIX) endif() execute_process( - COMMAND "${SPELL_COMMAND}" ${flag} - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - RESULT_VARIABLE result + COMMAND "${SPELL_COMMAND}" ${flag} WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" RESULT_VARIABLE result ) if(result EQUAL "65") diff --git a/cmake/variables.cmake b/cmake/variables.cmake index c9452ad..d96c946 100644 --- a/cmake/variables.cmake +++ b/cmake/variables.cmake @@ -1,9 +1,9 @@ # ---- Developer mode ---- # Developer mode enables targets and code paths in the CMake scripts that are -# only relevant for the developer(s) of cmake-init-modules -# Targets necessary to build the project must be provided unconditionally, so -# consumers can trivially build and package the project +# only relevant for the developer(s) of cmake-init-modules Targets necessary to +# build the project must be provided unconditionally, so consumers can trivially +# build and package the project if(PROJECT_IS_TOP_LEVEL) option(cmake-init-modules_DEVELOPER_MODE "Enable developer mode" OFF) option(BUILD_SHARED_LIBS "Build shared libs." OFF) @@ -12,27 +12,27 @@ endif() # ---- Suppress C4251 on Windows ---- # Please see include/cmake-init-modules/cmake-init-modules.hpp for more details -set(pragma_suppress_c4251 " +set(pragma_suppress_c4251 + " /* This needs to suppress only for MSVC */ #if defined(_MSC_VER) && !defined(__ICL) # define CMAKE_INIT_MODULES_SUPPRESS_C4251 _Pragma(\"warning(suppress:4251)\") #else # define CMAKE_INIT_MODULES_SUPPRESS_C4251 #endif -") +" +) # ---- Warning guard ---- # target_include_directories with the SYSTEM modifier will request the compiler -# to omit warnings from the provided paths, if the compiler supports that -# This is to provide a user experience similar to find_package when -# add_subdirectory or FetchContent is used to consume this project +# to omit warnings from the provided paths, if the compiler supports that This +# is to provide a user experience similar to find_package when add_subdirectory +# or FetchContent is used to consume this project set(warning_guard "") if(NOT PROJECT_IS_TOP_LEVEL) - option( - cmake-init-modules_INCLUDES_WITH_SYSTEM - "Use SYSTEM modifier for cmake-init-modules's includes, disabling warnings" - ON + option(cmake-init-modules_INCLUDES_WITH_SYSTEM + "Use SYSTEM modifier for cmake-init-modules's includes, disabling warnings" ON ) mark_as_advanced(cmake-init-modules_INCLUDES_WITH_SYSTEM) if(cmake-init-modules_INCLUDES_WITH_SYSTEM) diff --git a/conanfile.py b/conanfile.py index ac1e4bf..07313e9 100644 --- a/conanfile.py +++ b/conanfile.py @@ -9,7 +9,7 @@ def layout(self): self.folders.generators = "conan" def requirements(self): - self.requires("fmt/10.0.0") + self.requires("fmt/10.2.1") def build_requirements(self): - self.test_requires("catch2/3.3.2") + self.test_requires("catch2/3.5.2") diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 36cb59b..446a089 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,12 +1,57 @@ -cmake_minimum_required(VERSION 3.14) +cmake_minimum_required(VERSION 3.28...3.31) project(cmake-init-modulesExamples CXX) -include(../cmake/project-is-top-level.cmake) +if(PROJECT_IS_TOP_LEVEL) + # Neither of these two are technically needed, but they make the expectation clear + set(CMAKE_CXX_STANDARD 23) + set(CMAKE_CXX_EXTENSIONS FALSE) + set(CMAKE_CXX_STANDARD_REQUIRED TRUE) + + find_package(my_package 0.1 QUIET) + if(NOT my_package_FOUND) + message(STATUS "find_package(my_package) was NOT found, use as subproject ...") + # test if the targets are usable if used as subproject + add_subdirectory(.. my_package EXCLUDE_FROM_ALL) + endif() + + enable_testing() +endif() + +add_executable(app main.cpp) +target_link_libraries(app PRIVATE Algo) +add_test(NAME app-tests COMMAND app) + +if(NOT PROJECT_IS_TOP_LEVEL) + # test if the targets are findable from the source or install directory + # cmake-format: off + add_test(NAME find-package-test + COMMAND ${CMAKE_CTEST_COMMAND} + # --verbose + --output-on-failure + -C $ + --build-and-test + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}/find-package-test" + --build-generator ${CMAKE_GENERATOR} + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-options + "-DCMAKE_BUILD_TYPE=$" + "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" + "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" + ) + # cmake-format: on +endif() + +################################################## +return() # NOTE: XXX +################################################## + include(../cmake/folders.cmake) if(PROJECT_IS_TOP_LEVEL) - find_package(cmake-init-modules REQUIRED) + find_package(cmake-init-modules 0.1 REQUIRED) endif() add_custom_target(run-examples) @@ -14,10 +59,11 @@ add_custom_target(run-examples) function(add_example NAME) add_executable("${NAME}" "${NAME}.cpp") target_link_libraries("${NAME}" PRIVATE cmake-init-modules::cmake-init-modules) - target_compile_features("${NAME}" PRIVATE cxx_std_20) + target_compile_features("${NAME}" PRIVATE cxx_std_23) add_custom_target("run_${NAME}" COMMAND "${NAME}" VERBATIM) add_dependencies("run_${NAME}" "${NAME}") add_dependencies(run-examples "run_${NAME}") + add_test(NAME ${NAME} COMMAND ${NAME}) endfunction() add_example(empty_example) diff --git a/example/empty_example.cpp b/example/empty_example.cpp index a736724..aeae052 100644 --- a/example/empty_example.cpp +++ b/example/empty_example.cpp @@ -1,4 +1,9 @@ +#include + +#include + auto main() -> int { + std::cout << exported_class().name() << "\n"; return 0; } diff --git a/example/main.cpp b/example/main.cpp new file mode 100644 index 0000000..272a020 --- /dev/null +++ b/example/main.cpp @@ -0,0 +1,9 @@ +import algo; + +auto main() -> int +{ + Algo sut("cmake professionals"); + sut.helloWorld(); + + return 0; +} diff --git a/gcovr.cfg b/gcovr.cfg new file mode 100644 index 0000000..47164d8 --- /dev/null +++ b/gcovr.cfg @@ -0,0 +1,23 @@ +root = . +search-path = build + +filter = *.cpp +filter = example/* +filter = source/* +filter = include/* + +exclude-directories = stagedir +exclude-directories = example/build +exclude-directories = build/*/*/_deps +exclude-directories = test +exclude-directories = conan + +gcov-ignore-parse-errors = all +print-summary = yes + +html-details = build/coverage/index.html + +cobertura-pretty = yes +cobertura = build/cobertura.xml + +#TBD delete-gcov-files = yes diff --git a/include/cmake-init-modules/cmake-init-modules.hpp b/include/cmake-init-modules/cmake-init-modules.hpp index 4cc561a..5d3b290 100644 --- a/include/cmake-init-modules/cmake-init-modules.hpp +++ b/include/cmake-init-modules/cmake-init-modules.hpp @@ -62,7 +62,7 @@ class CMAKE_INIT_MODULES_EXPORT exported_class /** * @brief Returns a non-owning pointer to the string stored in this class */ - auto name() const -> char const*; + [[nodiscard]] auto name() const -> char const*; private: CMAKE_INIT_MODULES_SUPPRESS_C4251 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1371d57 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,14 @@ +# +# usage: pip install -U -r requirements.txt +# +Pygments>=2.17 +builddriver>=0.9 +cmake-init>=0.40.5 +cmake>=3.28.4 +cmakelint>=1.4.2 +codespell>=2.2.6 +conan>=2.2 +gcovr>=7.2 +jinja2>=3.1.3 +ninja>=1.11.1 +yamllint>=1.35 diff --git a/std/.CMakeLists.txt b/std/.CMakeLists.txt new file mode 100644 index 0000000..71e94ce --- /dev/null +++ b/std/.CMakeLists.txt @@ -0,0 +1,92 @@ +# CMake 3.30 is required for C++23 `import std` support; we use 3.29.20240416 +# here so that in-development versions satisfy it. +cmake_minimum_required(VERSION 3.30 FATAL_ERROR) + +# Set experimental flag to enable `import std` support from CMake. +# This must be enabled before C++ language support. +set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD + # This specific value changes as experimental support evolves. See + # `Help/dev/experimental.rst` in the CMake source corresponding to + # your CMake build for the exact value to use. + "0e5b6991-d74f-4b3d-a41c-cf096e0b2508" +) + +# C++ needs to be enabled. +project(import_std LANGUAGES CXX) + +# Tell CMake that we explicitly want `import std`. This will initialize the +# property on all targets declared after this to 1 +set(CMAKE_CXX_MODULE_STD 1) + +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.1) + # set(USE_MODULES TRUE) # used by fmt + set(CMAKE_CXX_SCAN_FOR_MODULES ON) + # see https://releases.llvm.org/19.1.0/projects/libcxx/docs/index.html + # and https://releases.llvm.org/19.1.0/projects/libcxx/docs/Modules.html + # Currently CMake requires extensions enabled when using import std. + # https://gitlab.kitware.com/cmake/cmake/-/issues/25916 + # https://gitlab.kitware.com/cmake/cmake/-/issues/25539 + set(CMAKE_CXX_EXTENSIONS ON) + add_compile_options(-fexperimental-library) + add_link_options(-lc++experimental) + add_compile_options(-ftime-trace) + add_compile_options(-stdlib=libc++) + add_link_options(-stdlib=libc++) + if(DEFINED ENV{LLVM_ROOT}) + message(STATUS "LLVM_ROOT=$ENV{LLVM_ROOT}") + set(LLVM_LIBC_SOURCE $ENV{LLVM_ROOT}/share/libc++/v1) + set(HAS_STDLIB_MODULES stdlib) + set(CMAKE_CXX_COMPILER_IMPORT_STD 23) + endif() +endif() + +# Build the stdlib module +function(add_stdlib_module NAME) + add_library(${NAME}) + add_library(__CMAKE::CXX23 ALIAS ${NAME}) + # cmake-format: off + target_sources(${NAME} PUBLIC + FILE_SET CXX_MODULES + BASE_DIRS ${LLVM_LIBC_SOURCE} + FILES + ${LLVM_LIBC_SOURCE}/std.cppm + ${LLVM_LIBC_SOURCE}/std.compat.cppm + ) + # cmake-format: on + target_compile_features(${NAME} PUBLIC cxx_std_23) + target_compile_definitions(${NAME} PUBLIC _LIBCPP_HAS_NO_LOCALIZATION) + target_compile_options(${NAME} PRIVATE -Wno-reserved-module-identifier) +endfunction() + +# Build the stdlib module +if(HAS_STDLIB_MODULES) + message(STATUS "HAS_STDLIB_MODULES=${HAS_STDLIB_MODULES}") + # XXX add_stdlib_module(${HAS_STDLIB_MODULES}) +endif() + +# +# Import the modules from libc++ +# + +# include(FetchContent) +# FetchContent_Declare( +# std +# URL "file://${LIBCXX_BUILD}/modules/c++/v1/" +# DOWNLOAD_EXTRACT_TIMESTAMP TRUE +# SYSTEM +# ) +# FetchContent_MakeAvailable(std) + +# Make a library. +add_library(uses_std STATIC) +# Add sources. +target_sources(uses_std PRIVATE uses_std.cxx) +# Tell CMake we're using C++23 but only C++20 is needed to consume it. +target_compile_features(uses_std PRIVATE cxx_std_23 INTERFACE cxx_std_20) + +# Make an executable. +add_executable(main) +# Note that this source is *not* allowed to `import std` as it ends up +# with only C++20 support due to the `uses_std` INTERFACE requirements. +target_sources(main PRIVATE main.cxx) +target_link_libraries(main PRIVATE uses_std) diff --git a/std/CMakeLists.txt b/std/CMakeLists.txt new file mode 100644 index 0000000..88e8533 --- /dev/null +++ b/std/CMakeLists.txt @@ -0,0 +1,54 @@ +cmake_minimum_required(VERSION 3.30...3.31) + +# +# Set language version used +# +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED YES) +# Currently CMake requires extensions enabled when using import std. +# https://gitlab.kitware.com/cmake/cmake/-/issues/25916 +# https://gitlab.kitware.com/cmake/cmake/-/issues/25539 +set(CMAKE_CXX_EXTENSIONS ON) + +# +# see https://gitlab.kitware.com/cmake/cmake/-/issues/25965#note_1523575 +# and https://www.kitware.com/import-std-in-cmake-3-30/ +# +if("${CMAKE_GENERATOR}" STREQUAL "Visual Studio 17 2022") + # This can be done before or after project() on MSVC + # It works regardless of CMAKE_EXPERIMENTAL_CXX_IMPORT_STD + set(CMAKE_CXX_SCAN_FOR_MODULES ON) + + # This does not seem to work on MSVC under any circumstances + # set(CMAKE_CXX_MODULE_STD ON) +else() + # This needs to be done before selecting the languages so the project() command + # The CMAKE_EXPERIMENTAL_CXX_IMPORT_STD is required + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "0e5b6991-d74f-4b3d-a41c-cf096e0b2508") + set(CMAKE_CXX_MODULE_STD ON) + + # Does not work regardless of value of CMAKE_EXPERIMENTAL_CXX_IMPORT_STD + # set(CMAKE_CXX_SCAN_FOR_MODULES ON) +endif() + +project("example" LANGUAGES CXX) + +add_executable(main) +target_sources(main PRIVATE main.cpp) + +# Make a library. +add_library(uses_std STATIC) +# Add sources. +target_sources(uses_std PRIVATE uses_std.cppm) +# Tell CMake we're using C++23 but only C++20 is needed to consume it. +target_compile_features(uses_std PRIVATE cxx_std_23 INTERFACE cxx_std_20) + +# Make an executable. +add_executable(test-module) +# Note that this source is *not* allowed to `import std` as it ends up +# with only C++20 support due to the `uses_std` INTERFACE requirements. +target_sources(test-module PRIVATE main.cxx) +target_link_libraries(test-module PRIVATE uses_std) + +enable_testing() +add_test(NAME test-module COMMAND test-module) diff --git a/std/GNUmakefile b/std/GNUmakefile new file mode 100644 index 0000000..8d75385 --- /dev/null +++ b/std/GNUmakefile @@ -0,0 +1,41 @@ +UNAME:=$(shell uname) +ifeq (${UNAME},Darwin) + export GNU_PREFIX:=$(shell brew --prefix gcc@14) + export GNU_ROOT:=$(shell realpath ${GNU_PREFIX}) + #TODO: export CXX:=g++-14 + + export LLVM_PREFIX:=$(shell brew --prefix llvm@19) + export LLVM_ROOT:=$(shell realpath ${LLVM_PREFIX}) + export LDFLAGS+=-L${LLVM_ROOT}/lib/c++ + export PATH:=${LLVM_ROOT}/bin:${PATH} + export CXX?=clang++ +else ifeq (${UNAME},Linux) + export LLVM_ROOT:=/usr/lib/llvm-18 +endif + +#TODO: export CXXFLAGS:=-std=c++23 +export CMAKE_BUILD_TYPE:=Release + +BUILD_SHARED_LIBS?=YES + +.PHONY: all build install format clean distclean +all: build + ninja -C build + cd build && ctest --verbose + +build: CMakeLists.txt #XXX stagedir + cmake -G Ninja -S . -B build -D BUILD_SHARED_LIBS=$(BUILD_SHARED_LIBS) -D CMAKE_PREFIX_PATH=$(CURDIR)/stagedir --fresh #XXX --debug-find-pkg=Asio + +# stagedir: asio-module/CMakeLists.txt GNUmakefile +# cmake -G Ninja -S asio-module -B build/asio -D CMAKE_INSTALL_PREFIX=$(CURDIR)/stagedir --fresh +# cmake --build build/asio +# cmake --install build/asio # --prefix stagedir + +format: + cmake-format -i CMakeLists.txt asio-module/CMakeLists.txt asio-module/AsioConfig.cmake.in + +clean: + rm -rf build + +distclean: clean + rm -rf stagedir __build diff --git a/std/main.cpp b/std/main.cpp new file mode 100644 index 0000000..134ccb9 --- /dev/null +++ b/std/main.cpp @@ -0,0 +1,7 @@ +import std; // When importing std.compat it's not needed to import std. +import std.compat; + +auto main() -> int { + std::cout << "Hello modular world\n"; + ::printf("Hello compat modular world\n"); +} diff --git a/std/main.cxx b/std/main.cxx new file mode 100644 index 0000000..dd9ff1c --- /dev/null +++ b/std/main.cxx @@ -0,0 +1,9 @@ +#include + +extern void hello_world(std::string const& name); + +auto main(int /*argc*/, char* argv[]) -> int +{ + hello_world((argv[1] != nullptr) ? argv[1] : "Voldemort?"); + return 0; +} diff --git a/std/uses_std.cppm b/std/uses_std.cppm new file mode 100644 index 0000000..241002b --- /dev/null +++ b/std/uses_std.cppm @@ -0,0 +1,6 @@ +import std; + +void hello_world(std::string const& name) +{ + std::print("Hello World! My name is {}\n", name); +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 754f06d..7ea0f3a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,8 +1,7 @@ -cmake_minimum_required(VERSION 3.14) +cmake_minimum_required(VERSION 3.28...3.31) project(cmake-init-modulesTests LANGUAGES CXX) -include(../cmake/project-is-top-level.cmake) include(../cmake/folders.cmake) # ---- Dependencies ---- @@ -19,11 +18,9 @@ include(Catch) add_executable(cmake-init-modules_test source/cmake-init-modules_test.cpp) target_link_libraries( - cmake-init-modules_test PRIVATE - cmake-init-modules::cmake-init-modules - Catch2::Catch2WithMain + cmake-init-modules_test PRIVATE cmake-init-modules::cmake-init-modules Catch2::Catch2WithMain ) -target_compile_features(cmake-init-modules_test PRIVATE cxx_std_20) +target_compile_features(cmake-init-modules_test PRIVATE cxx_std_23) catch_discover_tests(cmake-init-modules_test)