diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 68bd07bb..10a9ec2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,12 +12,12 @@ jobs: fail-fast: false matrix: config: - - {name: "Ubuntu Clang 17", os: ubuntu-24.04, toolchain: "clang-17-toolchain.cmake", clang_version: 17, installed_clang_version: 14, cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "} - - {name: "Ubuntu Clang 18", os: ubuntu-24.04, toolchain: "clang-18-toolchain.cmake", clang_version: 18, installed_clang_version: 14, cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "} + - {name: "Ubuntu Clang 17", os: ubuntu-24.04, toolchain: "clang-17", clang_version: 17, installed_clang_version: 17, cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "} + - {name: "Ubuntu Clang 18", os: ubuntu-24.04, toolchain: "clang-18", clang_version: 18, installed_clang_version: 17, cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "} # Note: clang-19 + Asan setup causes errors on some platforms. Temporary skip some checks via .asan_options. - - {name: "Ubuntu Clang 19", os: ubuntu-24.04, toolchain: "clang-19-toolchain.cmake", clang_version: 19, installed_clang_version: 14, cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" ", asan_options: "new_delete_type_mismatch=0"} - - {name: "Ubuntu GCC 13", os: ubuntu-24.04, toolchain: "gcc-13-toolchain.cmake", clang_version: 17, installed_clang_version: 14, cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "} - - {name: "Ubuntu GCC 14", os: ubuntu-24.04, toolchain: "gcc-14-toolchain.cmake", clang_version: 17, installed_clang_version: 14, cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "} + - {name: "Ubuntu Clang 19", os: ubuntu-24.04, toolchain: "clang-19", clang_version: 19, installed_clang_version: 17, cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" ", asan_options: "new_delete_type_mismatch=0"} + - {name: "Ubuntu GCC 13", os: ubuntu-24.04, toolchain: "gcc-13", cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "} + - {name: "Ubuntu GCC 14", os: ubuntu-24.04, toolchain: "gcc-14", cmake_args: "-G \"Ninja Multi-Config\" -DCMAKE_CONFIGURATION_TYPES=\"RelWithDebInfo;Asan\" "} steps: - uses: actions/checkout@v3 with: @@ -26,13 +26,14 @@ jobs: - name: Activate verbose shell run: set -x - name: Install LLVM+Clang - if: startsWith(matrix.config.os, 'ubuntu-') + if: startsWith(matrix.config.name, 'Ubuntu Clang') run: | set -x cat /etc/lsb-release - sudo apt-get remove clang-${{matrix.config.installed_clang_version}} \ - lldb-${{matrix.config.installed_clang_version}} \ - lld-${{matrix.config.installed_clang_version}} \ + # Remove existing Clang installations. + sudo apt-get remove \ + clang-${{matrix.config.installed_clang_version}} \ + clang++-${{matrix.config.installed_clang_version}} \ clangd-${{matrix.config.installed_clang_version}} \ clang-tidy-${{matrix.config.installed_clang_version}} \ clang-format-${{matrix.config.installed_clang_version}} \ @@ -41,39 +42,51 @@ jobs: lld-${{matrix.config.installed_clang_version}} \ lldb-${{matrix.config.installed_clang_version}} \ llvm-${{matrix.config.installed_clang_version}}-tools \ - libomp-${{matrix.config.installed_clang_version}}-dev \ libc++-${{matrix.config.installed_clang_version}}-dev \ libc++abi-${{matrix.config.installed_clang_version}}-dev \ libclang-common-${{matrix.config.installed_clang_version}}-dev \ libclang-${{matrix.config.installed_clang_version}}-dev \ libclang-cpp${{matrix.config.installed_clang_version}}-dev \ - libunwind-${{matrix.config.installed_clang_version}}-dev + libomp-${{matrix.config.installed_clang_version}}-dev \ + libunwind-${{matrix.config.installed_clang_version}}-dev \ + libc++-dev libc++1 libc++abi-dev libc++abi1 + # Install LLVM+Clang. + CLANG_VERSION=$(echo ${{matrix.config.toolchain}} | cut -d '-' -f2) wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh ${{matrix.config.clang_version}} all - sudo apt-get install libc++-dev libc++1 libc++abi-dev libc++abi1 - - name: Install GCC 14 - if: matrix.config.name == 'Ubuntu GCC 14' + sudo ./llvm.sh ${CLANG_VERSION} all + # Link Clang libraries (if not done by llvm.sh - some links are already set). + sudo ln -fs /usr/lib/llvm-${CLANG_VERSION}/lib/lib* /usr/lib/x86_64-linux-gnu/ || true + # If Clang 17, install a newer version of libc++ and libc++abi. + [[ ${CLANG_VERSION} = 17 ]] && sudo apt-get install libc++-dev libc++1 libc++abi-dev libc++abi1 + find /usr/lib/x86_64-linux-gnu/ -name libc++.so* || true + clang++-${CLANG_VERSION} --version + - name: Install GCC + if: startsWith(matrix.config.name, 'Ubuntu GCC') run: | set -x + # Remove existing GCC installations. + sudo apt-get remove gcc-13 g++-13 gcc-14 g++-14 gcc g++ sudo apt update - sudo apt-get install g++-14 - - name: Configure + # Install GCC. + GCC_VERSION=$(echo ${{matrix.config.toolchain}} | cut -d '-' -f2) + echo "GCC_VERSION=$GCC_VERSION" + sudo apt-get install g++-${GCC_VERSION} gcc-${GCC_VERSION} + find /usr/lib/x86_64-linux-gnu/ -name libstdc++.so* + g++-${GCC_VERSION} --version + - name: CMake Configure run: | set -x - rm -rf .build - mkdir -p .build - cd .build echo ${{ matrix.config.cmake_args }} echo ${{ matrix.config.toolchain }} - cmake ${{ matrix.config.cmake_args }} -DCMAKE_TOOLCHAIN_FILE=etc/${{ matrix.config.toolchain }} -B . -S .. - - name: Build + rm -rf .build + cmake ${{ matrix.config.cmake_args }} -DCMAKE_TOOLCHAIN_FILE="etc/${{ matrix.config.toolchain }}-toolchain.cmake" -B .build -S . + - name: CMake Build run: | set -x cmake --build .build --config Asan --target all -- -k 0 - - name: Test + - name: CMake Test run: | set -x - cd .build [[ ! -z "${{ matrix.config.asan_options }}" ]] && export ASAN_OPTIONS="${{ matrix.config.asan_options }}" - ctest --build-config Asan --output-on-failure + ctest --build-config Asan --output-on-failure --test-dir .build diff --git a/.gitmodules b/.gitmodules index 9c4e4556..b44d8c09 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "papers/wg21"] path = papers/P2988/wg21 url = https://github.com/mpark/wg21.git -[submodule "extern/googletest"] - path = extern/googletest - url = https://github.com/google/googletest.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 564e9d76..812a1903 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,19 +3,31 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # cmake-format: on -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.27) project( beman_optional26 VERSION 0.0.0 LANGUAGES CXX) -enable_testing() +# Includes +include(CTest) +include(FetchContent) set(TARGETS_EXPORT_NAME ${CMAKE_PROJECT_NAME}Targets) -add_subdirectory(extern) -add_subdirectory(src) +# Build the tests only if enabled via the CLI flag: BUILD_TESTING. +if(BUILD_TESTING) + # Fetch GoogleTest + FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG f8d7d77c06936315286eb55f8de22cd23c188571 # release-1.14.0 + ) + FetchContent_MakeAvailable(googletest) +endif() + +add_subdirectory(src/Beman/Optional26) add_subdirectory(examples) include(GNUInstallDirs) diff --git a/CMakePresets.json b/CMakePresets.json index 40cb22a2..eb05f0c9 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -68,26 +68,32 @@ }, { "name": "system", + "inherits": "common", "configurePreset": "system" }, { "name": "gcc-14", + "inherits": "common", "configurePreset": "gcc-14" }, { "name": "gcc-13", + "inherits": "common", "configurePreset": "gcc-13" }, { "name": "clang-19", + "inherits": "common", "configurePreset": "clang-19" }, { "name": "clang-18", + "inherits": "common", "configurePreset": "clang-18" }, { "name": "clang-17", + "inherits": "common", "configurePreset": "clang-17" } ], @@ -95,6 +101,7 @@ { "name": "common", "hidden": true, + "configuration": "Asan", "output": { "outputOnFailure": true }, diff --git a/Makefile b/Makefile deleted file mode 100755 index b27aabc4..00000000 --- a/Makefile +++ /dev/null @@ -1,97 +0,0 @@ -#! /usr/bin/make -f -# cmake-format: off -# /Makefile -*-makefile-*- -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# cmake-format: on - -INSTALL_PREFIX?=.install/ -PROJECT?=$(shell basename $(CURDIR)) -BUILD_DIR?=.build -DEST?=$(INSTALL_PREFIX) -CMAKE_FLAGS?= - -TARGETS := test clean all ctest - -export - -.update-submodules: - git submodule update --init --recursive - touch .update-submodules - -.gitmodules: .update-submodules - -CONFIG?=Asan - -export - -ifeq ($(strip $(TOOLCHAIN)),) - _build_name?=build-system/ - _build_dir?=.build/ - _configuration_types?="RelWithDebInfo;Debug;Tsan;Asan" - _cmake_args=-DCMAKE_TOOLCHAIN_FILE=$(CURDIR)/etc/toolchain.cmake -else - _build_name?=build-$(TOOLCHAIN) - _build_dir?=.build/ - _configuration_types?="RelWithDebInfo;Debug;Tsan;Asan" - _cmake_args=-DCMAKE_TOOLCHAIN_FILE=$(CURDIR)/etc/$(TOOLCHAIN)-toolchain.cmake -endif - - -_build_path?=$(_build_dir)/$(_build_name) - -define run_cmake = - cmake \ - -G "Ninja Multi-Config" \ - -DCMAKE_CONFIGURATION_TYPES=$(_configuration_types) \ - -DCMAKE_INSTALL_PREFIX=$(abspath $(INSTALL_PREFIX)) \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=1 \ - $(_cmake_args) \ - $(CURDIR) -endef - -default: test - -$(_build_path): - mkdir -p $(_build_path) - -$(_build_path)/CMakeCache.txt: | $(_build_path) .gitmodules - cd $(_build_path) && $(run_cmake) - -rm compile_commands.json - ln -s $(_build_path)/compile_commands.json - -compile: $(_build_path)/CMakeCache.txt ## Compile the project - cmake --build $(_build_path) --config $(CONFIG) --target all -- -k 0 - -install: $(_build_path)/CMakeCache.txt ## Install the project - DESTDIR=$(abspath $(DEST)) ninja -C $(_build_path) -k 0 install - -ctest: $(_build_path)/CMakeCache.txt ## Run CTest on current build - cd $(_build_path) && ctest --output-on-failure - -ctest_ : compile - cd $(_build_path) && ctest --output-on-failure - -test: ctest_ ## Rebuild and run tests - -cmake: | $(_build_path) - cd $(_build_path) && ${run_cmake} - -clean: $(_build_path)/CMakeCache.txt ## Clean the build artifacts - cmake --build $(_build_path) --config $(CONFIG) --target clean - -realclean: ## Delete the build directory - rm -rf $(_build_path) - -env: - $(foreach v, $(.VARIABLES), $(info $(v) = $($(v)))) - -.PHONY : compile install ctest ctest_ test cmake clean realclean env - -.PHONY: papers -papers: - $(MAKE) -C papers papers - -# Help target -.PHONY: help -help: ## Show this help. - @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) targets.mk | sort diff --git a/README.md b/README.md index bddf6e49..8d3a3722 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,24 @@ This repository implements `std::optional` extensions targeting C++26. The `Bema * [Give *std::optional* Range Support (P3168R2)](https://wg21.link/P3168R2) * [`std::optional` (P2988R5)](https://wg21.link/P2988R5) +## Table of Contents + +* [Beman.Optional26: C++26 Extensions for std::optional](#bemanoptional26-c26-extensions-for-stdoptional) + * [Table of Contents](#table-of-contents) + * [License](#license) + * [Examples](#examples) + * [range\_loop](#range_loop) + * [optional\_ref](#optional_ref) + * [How to Build](#how-to-build) + * [Compiler Support](#compiler-support) + * [Dependencies](#dependencies) + * [Instructions](#instructions) + * [Preset CMake Flows](#preset-cmake-flows) + * [Custom CMake Flows](#custom-cmake-flows) + * [Build and Run Tests](#build-and-run-tests) + * [Build Production, but Skip Tests](#build-production-but-skip-tests) + * [Papers](#papers) + ## License Source is licensed with the Apache 2.0 license with LLVM exceptions @@ -123,7 +141,7 @@ apt-get install \ Full set of supported toolchains can be found in [.github/workflows/ci.yml](.github/workflows/ci.yml). -#### Basic Build +#### Preset CMake Flows This project strives to be as normal and simple a CMake project as possible. This build workflow in particular will work, producing a static `beman_optional26` library, ready to package: @@ -168,15 +186,56 @@ Total Test time (real) = 0.09 sec This should build and run the tests with GCC 14 with the address and undefined behavior sanitizers enabled. -#### More complex cases +#### Custom CMake Flows + +##### Build and Run Tests -The CMake preset system suffers from combinitorial explosion. There is a makefile in the root of the repository to aid in running more configurations. +CI current build and test flows: ```shell -make -k TOOLCHAIN=clang-18 CONFIG=Tsan VERBOSE=1 +# Configure build: default build production code + tests (BUILD_TESTING=ON by default). +$ cmake -G "Ninja Multi-Config" -DCMAKE_CONFIGURATION_TYPES="RelWithDebInfo;Asan" -DCMAKE_TOOLCHAIN_FILE=etc/clang-19-toolchain.cmake -B .build -S . +-- The CXX compiler identification is Clang 19.0.0 +... +-- Build files have been written to: /path/to/Optional26/.build + +# Build. +$ cmake --build .build --config Asan --target all -- -k 0 +... +[30/30] Linking CXX executable ... # Note: 30 targets here (including tests). + +# Run tests. +$ ctest --build-config Asan --output-on-failure --test-dir .build +Internal ctest changing into directory: /path/to/Optional26/.build +Test project /path/to/Optional26/.build +... +100% tests passed, 0 tests failed out of 82 + +Total Test time (real) = 0.67 sec ``` -The makefile will use your system compiler, `c++`, if no toolchain name is provided, otherwise it will use the toolchain in the etc/ directory to perform the build. The Ninja multi config generator is used, with configurations for `RelWithDebugInfo`, `Debug`, `Tsan`, and `Asan` configured by default. +##### Build Production, but Skip Tests + +By default, we build and run tests. You can provide `-DBUILD_TESTING=OFF` and completely disable building tests: + +```shell +# Configure build: build production code, skip tests (BUILD_TESTING=OFF). +$ cmake -G "Ninja Multi-Config" -DCMAKE_CONFIGURATION_TYPES="RelWithDebInfo;Asan" -DCMAKE_TOOLCHAIN_FILE=etc/clang-19-toolchain.cmake -DBUILD_TESTING=OFF -B .build -S . +-- The CXX compiler identification is Clang 19.0.0 +... +-- Build files have been written to: /path/to/Optional26/.build + +# Build. +$ cmake --build .build --config Asan --target all -- -k 0 +... +[15/15] Linking CXX executable ... # Note: 15 targets here (tests were not built). + +# Check that tests are not built/installed. +$ ctest --build-config Asan --output-on-failure --test-dir .build +Internal ctest changing into directory: /path/to/Beman.Optional26/.build +Test project /path/to/Beman.Optional26/.build +No tests were found!!! +``` ## Papers diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt deleted file mode 100644 index 31f2a6fc..00000000 --- a/extern/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# cmake-format: off -# extern/CMakeLists.txt -*-makefile-*- -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# cmake-format: on - -add_subdirectory(googletest EXCLUDE_FROM_ALL) diff --git a/extern/googletest b/extern/googletest deleted file mode 160000 index 305e5a23..00000000 --- a/extern/googletest +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 305e5a238b3c8d11266fbafd85520fb6b3184851 diff --git a/src/Beman/CMakeLists.txt b/src/Beman/CMakeLists.txt deleted file mode 100644 index 45dfa2b8..00000000 --- a/src/Beman/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# cmake-format: off -# src/Beman/CMakeLists.txt -*-makefile-*- -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# cmake-format: on - -add_subdirectory(Optional26) diff --git a/src/Beman/Optional26/CMakeLists.txt b/src/Beman/Optional26/CMakeLists.txt index 9cdd38ac..d19018d8 100644 --- a/src/Beman/Optional26/CMakeLists.txt +++ b/src/Beman/Optional26/CMakeLists.txt @@ -3,25 +3,21 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # cmake-format: on -set(TARGET_LIBRARY "beman_optional26") - -add_library("${TARGET_LIBRARY}" STATIC "") - -target_sources("${TARGET_LIBRARY}" PRIVATE optional.cpp detail/iterator.cpp) +add_library(beman_optional26 STATIC optional.cpp detail/iterator.cpp) include(GNUInstallDirs) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories( - "${TARGET_LIBRARY}" + beman_optional26 PUBLIC $ $ # /include/scratch ) install( - TARGETS "${TARGET_LIBRARY}" - EXPORT ${TARGETS_EXPORT_NAME}1 + TARGETS beman_optional26 + EXPORT ${TARGETS_EXPORT_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) string(TOLOWER ${CMAKE_PROJECT_NAME} CMAKE_LOWER_PROJECT_NAME) @@ -32,24 +28,9 @@ install( FILES_MATCHING PATTERN "*.hpp") -target_link_libraries("${TARGET_LIBRARY}") +target_link_libraries(beman_optional26) # Tests -add_executable(optional_test "") - -target_sources( - optional_test - PRIVATE tests/optional.t.cpp tests/optional_ref.t.cpp - tests/optional_monadic.t.cpp tests/optional_range_support.t.cpp - tests/optional_ref_monadic.t.cpp tests/detail/iterator.t.cpp) - -target_link_libraries(optional_test "${TARGET_LIBRARY}") -target_link_libraries(optional_test gtest) -target_link_libraries(optional_test gtest_main) - -include(GoogleTest) - -# Note: clang-19 + gtest_discover_tests + Asan setup causes errors on some platforms. -# Temporary switch to gtest_add_tests and skip some Asan checks. -enable_testing() -gtest_add_tests(optional_test "" AUTO) +if(BUILD_TESTING) + add_subdirectory(tests) +endif() diff --git a/src/Beman/Optional26/tests/CMakeLists.txt b/src/Beman/Optional26/tests/CMakeLists.txt new file mode 100644 index 00000000..43500207 --- /dev/null +++ b/src/Beman/Optional26/tests/CMakeLists.txt @@ -0,0 +1,22 @@ +# cmake-format: off +# src/Beman/Optional26/tests/CMakeLists.txt -*-makefile-*- +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# cmake-format: on + +include(GoogleTest) + +# Tests +add_executable( + beman_optional26_test + detail/iterator.t.cpp optional_monadic.t.cpp optional_range_support.t.cpp + optional_ref_monadic.t.cpp optional_ref.t.cpp optional.t.cpp) + +target_link_libraries(beman_optional26_test beman_optional26 GTest::gtest + GTest::gtest_main) + +# Issue #32: Re-enable ASAN run CI/clang-19. +# +# Note: clang-19 + gtest_discover_tests + Asan setup causes errors on some +# platforms. Temporary switch to gtest_add_tests and skip some Asan checks. +# Change also applied for CI flows. +gtest_add_tests(TARGET beman_optional26_test "" AUTO) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 5d1346f1..00000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# cmake-format: off -# src/CMakeLists.txt -*-makefile-*- -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# cmake-format: on - -add_subdirectory(Beman)