diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index e005487..71eb660 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -27,8 +27,8 @@ jobs: - name: Setup build environment uses: lukka/get-cmake@latest with: - cmakeVersion: "~3.28.0" - ninjaVersion: "^1.11.1" + cmakeVersion: latest + ninjaVersion: latest - name: Setup MSVC if: startsWith(matrix.presets.platform, 'windows') uses: TheMrMilchmann/setup-msvc-dev@v3 @@ -80,8 +80,8 @@ jobs: - name: Install Ninja uses: lukka/get-cmake@latest with: - cmakeVersion: "~4.0.0" - ninjaVersion: "^1.11.1" + cmakeVersion: latest + ninjaVersion: latest - name: Setup MSVC if: startsWith(matrix.platform.os, 'windows') uses: TheMrMilchmann/setup-msvc-dev@v3 @@ -139,8 +139,8 @@ jobs: - name: Setup build environment uses: lukka/get-cmake@latest with: - cmakeVersion: "~3.28.0" - ninjaVersion: "^1.11.1" + cmakeVersion: latest + ninjaVersion: latest - name: Print installed softwares run: | cmake --version @@ -183,8 +183,8 @@ jobs: - name: Setup build environment uses: lukka/get-cmake@latest with: - cmakeVersion: "~4.0.0" - ninjaVersion: "^1.11.1" + cmakeVersion: latest + ninjaVersion: latest - name: Install Compiler id: install-compiler run: | diff --git a/.gitignore b/.gitignore index 6c1ce4b..d92c202 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ # ignore temp build files /compile_commands.json /build +**/_deps/ +**/CMakeFiles/ # ignore emacs temp files *~ @@ -8,3 +10,4 @@ # ignore vscode settings .vscode +.cache diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a26bab0..0cfbde6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -13,14 +13,14 @@ repos: # This brings in a portable version of clang-format. # See also: https://github.com/ssciwr/clang-format-wheel - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v18.1.8 + rev: v21.1.8 hooks: - id: clang-format types_or: [c++, c] # CMake linting and formatting - repo: https://github.com/BlankSpruce/gersemi - rev: 0.15.1 + rev: 0.25.0 hooks: - id: gersemi name: CMake linting @@ -28,6 +28,6 @@ repos: # Markdown linting # Config file: .markdownlint.yaml - repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.42.0 + rev: v0.47.0 hooks: - id: markdownlint diff --git a/CMakeLists.txt b/CMakeLists.txt index afdaf7d..9a7ccdb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,23 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 3.28) +if(CMAKE_CXX_STANDARD GREATER_EQUAL 23) + if(CMAKE_CXX_MODULE_STD) + if(CMAKE_VERSION VERSION_EQUAL 4.0.2) + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD + "a9e1cf81-9932-4810-974b-6eccaf14e457" + ) + else() + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD + "d0edc3af-4c50-42ea-a356-e2862fe7a444" + ) + endif() + set(CMAKE_CXX_SCAN_FOR_MODULES 1) + add_definitions(-DHAS_STDLIB_MODULES) + endif() + set(CMAKE_CXX_STANDARD_REQUIRED OFF) +endif() + +cmake_minimum_required(VERSION 4.0...4.2) project( beman.scope @@ -12,15 +29,45 @@ project( # gersemi: off # Modules opt in only on compilers that support g++-15 and clang-20+ -if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 20) - set(CMAKE_CXX_SCAN_FOR_MODULES 1) -elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15) - set(CMAKE_CXX_SCAN_FOR_MODULES 1) -elseif() +if(CMAKE_CXX_STANDARD GREATER_EQUAL 23) + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 20) + if(APPLE AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 21.1) + execute_process(OUTPUT_VARIABLE LLVM_PREFIX COMMAND brew --prefix llvm@21 COMMAND_ECHO STDOUT) + string(STRIP ${LLVM_PREFIX} LLVM_PREFIX) + file(REAL_PATH ${LLVM_PREFIX} LLVM_ROOT) + set(LLVM_ROOT ${LLVM_ROOT} CACHE PATH "") + message(STATUS "LLVM_ROOT=${LLVM_ROOT}") + + add_compile_options(-fexperimental-library) + add_link_options(-L${LLVM_ROOT}/lib/c++ -lc++experimental) + add_compile_options(-stdlib=libc++) + add_link_options(-stdlib=libc++) + endif() + set(CMAKE_CXX_SCAN_FOR_MODULES 1) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15) + set(CMAKE_CXX_SCAN_FOR_MODULES 1) + endif() +else() set(CMAKE_CXX_SCAN_FOR_MODULES 0) endif() -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +if(CMAKE_CXX_SCAN_FOR_MODULES) + set(CMAKE_CXX_STANDARD_REQUIRED OFF) +endif() + +set(CMAKE_EXPORT_COMPILE_COMMANDS OFF) +if(CMAKE_EXPORT_COMPILE_COMMANDS) + set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) + find_program(CLANG_TIDY_EXE NAMES clang-tidy clang-tidy-20 clang-tidy-21 DOC "Path to clang-tidy executable") +endif() + +include(CMakePrintHelpers) +cmake_print_variables( + CMAKE_CXX_STANDARD + CMAKE_CXX_SCAN_FOR_MODULES + CMAKE_CXX_MODULE_STD + CMAKE_CXX_COMPILER_IMPORT_STD +) # [CMAKE.SKIP_TESTS] option( @@ -42,12 +89,8 @@ option( ${PROJECT_IS_TOP_LEVEL} ) -message( - "Compiler is: ${CMAKE_CXX_COMPILER_ID} version: ${CMAKE_CXX_COMPILER_VERSION}" -) -message( - "cmake is: ${CMAKE_VERSION} modules scan : ${CMAKE_CXX_SCAN_FOR_MODULES}" -) +message(STATUS "Compiler is: ${CMAKE_CXX_COMPILER_ID} version: ${CMAKE_CXX_COMPILER_VERSION}") +message(STATUS "CMake is: ${CMAKE_VERSION} modules scan: ${CMAKE_CXX_SCAN_FOR_MODULES}") if(CMAKE_CXX_SCAN_FOR_MODULES) add_library(beman.scope) @@ -62,6 +105,8 @@ if(CMAKE_CXX_SCAN_FOR_MODULES) BASE_DIRS include FILES include/beman/scope/beman.scope.cppm ) + # prevent "not include "cxx_std_20" (or newer) among its `target_compile_features`; no C++ standard found" + target_compile_features(beman.scope PUBLIC cxx_std_23) else() add_library(beman.scope INTERFACE) target_sources( @@ -71,6 +116,7 @@ else() BASE_DIRS include FILES include/beman/scope/scope.hpp ) + target_compile_features(beman.scope INTERFACE cxx_std_20) endif() add_library(beman::scope ALIAS beman.scope) @@ -90,7 +136,7 @@ install( EXPORT beman.scope-targets FILE_SET CXX_MODULES - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILE_SET HEADERS ) @@ -116,7 +162,8 @@ if(BEMAN_SCOPE_INSTALL_CONFIG_FILE_PACKAGE) EXPORT beman.scope-targets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/beman.scope NAMESPACE beman:: - CXX_MODULES_DIRECTORY cxx-modules + CXX_MODULES_DIRECTORY + cxx-modules COMPONENT beman.scope ) endif() @@ -127,5 +174,11 @@ if(BEMAN_SCOPE_BUILD_TESTS) endif() if(BEMAN_SCOPE_BUILD_EXAMPLES) + if(CLANG_TIDY_EXE) + message(STATUS "clang-tidy found: ${CLANG_TIDY_EXE}") + set(CMAKE_CXX_CLANG_TIDY + "${CLANG_TIDY_EXE};-extra-arg=--Wno-error=unknown-argument" + ) + endif() add_subdirectory(examples) endif() diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..e9b2af6 --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,57 @@ +# 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 hostSystemName=$(shell uname) + +ifeq (${hostSystemName},Darwin) + export LLVM_PREFIX=$(shell brew --prefix llvm) + export LLVM_DIR=$(shell realpath ${LLVM_PREFIX}) + export PATH:=${LLVM_DIR}/bin:${PATH} + + # export CMAKE_CXX_STDLIB_MODULES_JSON=${LLVM_DIR}/lib/c++/libc++.modules.json + # export CXX=clang++ + # export LDFLAGS=-L$(LLVM_DIR)/lib/c++ -lc++abi -lc++ -lc++experimental + # export GCOV="llvm-cov gcov" + + ### TODO: to test g++-15: + export GCC_PREFIX=$(shell brew --prefix gcc) + export GCC_DIR=$(shell realpath ${GCC_PREFIX}) + + export CMAKE_CXX_STDLIB_MODULES_JSON=${GCC_DIR}/lib/gcc/current/libstdc++.modules.json + export CXX:=g++-15 + export CXXFLAGS:=-stdlib=libstdc++ + export GCOV="gcov" +else ifeq (${hostSystemName},Linux) + export LLVM_DIR=/usr/lib/llvm-20 + export PATH:=${LLVM_DIR}/bin:${PATH} + export CXX=clang++-20 +endif + +.PHONY: all install clean distclean + +all: build/compile_commands.json + ln -sf $< . + ninja -C build + +build/compile_commands.json: CMakeLists.txt GNUmakefile + cmake -S . -B build -G Ninja --log-level=DEBUG -D CMAKE_BUILD_TYPE=Release \ + -D CMAKE_EXPERIMENTAL_CXX_IMPORT_STD="d0edc3af-4c50-42ea-a356-e2862fe7a444" \ + -D CMAKE_CXX_STDLIB_MODULES_JSON=${CMAKE_CXX_STDLIB_MODULES_JSON} \ + -D CMAKE_CXX_STANDARD=23 -D CMAKE_CXX_EXTENSIONS=YES -D CMAKE_CXX_STANDARD_REQUIRED=YES \ + -D CMAKE_CXX_MODULE_STD=NO \ + -D CMAKE_INSTALL_MESSAGE=LAZY # XXX -D CMAKE_SKIP_INSTALL_RULES=YES # --fresh + +install: build/cmake_install.cmake + cmake --install build + +distclean: clean + rm -rf build + +# Anything we don't know how to build will use this rule. +% :: + ninja -C build $(@) diff --git a/README.md b/README.md index 55003db..31b0d7d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ SPDX-License-Identifier: CC0-1.0 **Status**: [Under development and not yet ready for production use.](https://github.com/bemanproject/beman/blob/main/docs/BEMAN_LIBRARY_MATURITY_MODEL.md#under-development-and-not-yet-ready-for-production-use) -# Overview +## Overview During the C++20 cycle [P0052 Generic Scope Guard and RAII Wrapper for the Standard Library](https://wg21.link/P0052) added 4 types: `scope_exit`, `scope_fail`, `scope_success` @@ -99,6 +99,7 @@ the `include` directory available add add the following to your source. import beman.scope; ``` + Withmodules import needs to be after any includes to avoid compilation errors. ## Building beman.scope @@ -130,11 +131,13 @@ ninja -j 5 -v; ctest ``` or using cmake presets + ```shell cmake --workflow --preset gcc-release cmake --install build/gcc-release --prefix /opt/beman.scope ``` -# License + +## License Source is licensed with the Apache 2.0 license with LLVM exceptions @@ -150,6 +153,6 @@ The README itself is licensed with CC0 1.0 Universal. Copy the contents and inco // SPDX-License-Identifier: CC0-1.0 -# Contributing +## Contributing Please do! Issues and pull requests are appreciated. diff --git a/cmake/appleclang-toolchain.cmake b/cmake/appleclang-toolchain.cmake index bc12103..e7a6cc4 100644 --- a/cmake/appleclang-toolchain.cmake +++ b/cmake/appleclang-toolchain.cmake @@ -16,8 +16,8 @@ include_guard(GLOBAL) -set(CMAKE_C_COMPILER clang) -set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_C_COMPILER cc) +set(CMAKE_CXX_COMPILER c++) if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan") set(SANITIZER_FLAGS diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1444b00..07889d3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,18 +5,18 @@ include(FetchContent) FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v3.8.0 + GIT_TAG v3.8.1 + SYSTEM + # FIXME: FIND_PACKAGE_ARGS 3.8.1 ) FetchContent_MakeAvailable(Catch2) -# module tests will only compile with gcc15 or clang20 and above +set(ALL_TESTNAMES scope_success scope_exit scope_fail unique_resource) if(CMAKE_CXX_SCAN_FOR_MODULES) - set(ALL_TESTNAMES scope_success scope_exit scope_fail unique_resource module) -else() - set(ALL_TESTNAMES scope_success scope_exit scope_fail unique_resource) + list(APPEND ALL_TESTNAMES module) endif() -message("Tests to be built: ${ALL_TESTNAMES}") +message(DEBUG "Tests to be built: ${ALL_TESTNAMES}") include(Catch) diff --git a/tests/module.test.cpp b/tests/module.test.cpp index a4b22fc..9776b3f 100644 --- a/tests/module.test.cpp +++ b/tests/module.test.cpp @@ -4,6 +4,9 @@ #include // for g++-15 the order is important -- import after includes +#ifdef HAS_STDLIB_MODULES +import std; +#endif import beman.scope; struct DummyResource { @@ -33,5 +36,4 @@ TEST_CASE("module-test", "[scope_module_test]") { REQUIRE(success_ran == true); REQUIRE(fail_ran == false); REQUIRE(cleaned == true); - }