diff --git a/.clang-format b/.clang-format
index 05baf03..74f95dc 100644
--- a/.clang-format
+++ b/.clang-format
@@ -125,7 +125,7 @@ IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
-IndentPPDirectives: None
+IndentPPDirectives: BeforeHash
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
deleted file mode 100644
index e1662e7..0000000
--- a/.devcontainer/devcontainer.json
+++ /dev/null
@@ -1,16 +0,0 @@
-// For format details, see https://aka.ms/devcontainer.json. For config options, see the
-// README at: https://github.com/devcontainers/templates/tree/main/src/cpp
-
-{
- "name": "Beman Project Generic Devcontainer",
- "image": "ghcr.io/bemanproject/devcontainers-gcc:14",
- "postCreateCommand": "pre-commit",
- "customizations": {
- "vscode": {
- "extensions": [
- "ms-vscode.cpptools",
- "ms-vscode.cmake-tools"
- ]
- }
- }
-}
diff --git a/.exemplar_version b/.exemplar_version
new file mode 100644
index 0000000..447909a
--- /dev/null
+++ b/.exemplar_version
@@ -0,0 +1 @@
+ab5c7c0cbf1f67eb43b7be9c2d18acd4d6de1ea4
diff --git a/.gitattributes b/.gitattributes
index 2c34f89..793dce7 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,5 @@
infra/** linguist-vendored
+cookiecutter/** linguist-vendored
+*.bib -linguist-detectable
+*.tex -linguist-detectable
+papers/* linguist-documentation
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index c4e66dc..34d0cfe 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,23 +1,3 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-# Codeowners for reviews on PRs
-# Note(river):
-# **Please understand how codeowner file work before uncommenting anything in this section:**
-# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
-#
-# For projects using exemplar as a template and intend to reuse its infrastructure,
-# River (@wusatosi) helped create most of the original infrastructure under the scope described below,
-# they are more than happy to help out with any PRs downstream,
-# as well as to sync any useful change upstream to exemplar.
-#
-# Github Actions:
-# .github/workflows/ @wusatosi # Add other project owners here
-#
-# Devcontainer:
-# .devcontainer/ @wusatosi # Add other project owners here
-#
-# Pre-commit:
-# .pre-commit-config.yaml @wusatosi # Add other project owners here
-# .markdownlint.yaml @wusatosi # Add other project owners here
-
-* @bretbrownjr @changkhothuychung @dietmarkuehl @steve-downey @wusatosi
+* @Dragosh-C
diff --git a/.github/actions/cmake-build-test/action.yml b/.github/actions/cmake-build-test/action.yml
deleted file mode 100644
index 421b8c9..0000000
--- a/.github/actions/cmake-build-test/action.yml
+++ /dev/null
@@ -1,61 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-name: 'CMake Build Test'
-description: ''
-inputs:
- cpp_version:
- required: true
- toolchain_file:
- required: true
- cmake_extra_args:
- description: 'extra cmake arguments'
- Default: ''
- disable_test:
- Default: false
-runs:
- using: 'composite'
- steps:
- - name: Setup Macos
- if: startsWith(matrix.platform.os, 'macos')
- shell: bash
- run: sudo chmod -R 777 /opt/
- - name: Print installed software
- shell: bash
- run: |
- echo "Build system:"
- cmake --version
- ninja --version
- - name: Configure CMake
- shell: bash
- run: |
- cmake \
- -B build \
- -S . \
- -DCMAKE_CXX_STANDARD=${{ inputs.cpp_version }} \
- -DCMAKE_TOOLCHAIN_FILE="${{ inputs.toolchain_file }}" \
- -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES="./infra/cmake/use-fetch-content.cmake" \
- ${{ matrix.cmake_args.args }}
- env:
- CMAKE_GENERATOR: "Ninja Multi-Config"
- - name: Build Release
- shell: bash
- run: |
- cmake --build build --config Release --parallel --verbose
- cmake --build build --config Release --target all_verify_interface_header_sets
- cmake --install build --config Release --prefix /opt/beman.package
- ls -R /opt/beman.package
- - name: Test Release
- if: ${{ !inputs.disable_test }}
- shell: bash
- run: ctest --test-dir build --build-config Release
- - name: Build Debug
- shell: bash
- run: |
- cmake --build build --config Debug --parallel --verbose
- cmake --build build --config Debug --target all_verify_interface_header_sets
- cmake --install build --config Debug --prefix /opt/beman.package
- ls -R /opt/beman.package
- - name: Test Debug
- if: ${{ !inputs.disable_test }}
- shell: bash
- run: ctest --test-dir build --build-config Debug
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 6085d62..071cb28 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,71 +1,5 @@
-
-
-
-
-## Description
-
-Please describe your contribution in a single sentence.
-
-## Related Issues
-
-
-
-## Motivation and Context
-
-Explain why this change is needed.
-
-## Testing
-
-Explain how is this tested.
-
-## Meta
-
-
-
-- [ ] If all approvals are obtained and the PR is green, any Beman member can merge the PR.
-
-
diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml
index 8ea6411..162b165 100644
--- a/.github/workflows/ci_tests.yml
+++ b/.github/workflows/ci_tests.yml
@@ -4,253 +4,144 @@ name: Continuous Integration Tests
on:
push:
+ branches:
+ - main
pull_request:
workflow_dispatch:
schedule:
- - cron: '30 15 * * *'
+ - cron: '1 17 * * 6'
jobs:
- beman-submodule-test:
- runs-on: ubuntu-latest
- name: "Check beman submodules for consistency"
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: beman submodule consistency check
- run: |
- (set -o pipefail; ./infra/tools/beman-submodule/beman-submodule status | grep -qvF '+')
+ beman-submodule-check:
+ uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-submodule-check.yml@1.5.3
preset-test:
- strategy:
- fail-fast: false
- matrix:
- presets:
- - preset: "gcc-debug"
- platform: "ubuntu-latest"
- - preset: "gcc-release"
- platform: "ubuntu-latest"
- - preset: "llvm-debug"
- platform: "ubuntu-latest"
- - preset: "llvm-release"
- platform: "ubuntu-latest"
- - preset: "appleclang-debug"
- platform: "macos-latest"
- - preset: "appleclang-release"
- platform: "macos-latest"
- - preset: "msvc-debug"
- platform: "windows-latest"
- - preset: "msvc-release"
- platform: "windows-latest"
- name: "Preset: ${{ matrix.presets.preset }} on ${{ matrix.presets.platform }}"
- runs-on: ${{ matrix.presets.platform }}
- steps:
- - uses: actions/checkout@v4
- - name: Setup build environment
- uses: lukka/get-cmake@latest
- with:
- cmakeVersion: "~3.25.0"
- ninjaVersion: "^1.11.1"
- - name: Setup MSVC
- if: startsWith(matrix.presets.platform, 'windows')
- uses: TheMrMilchmann/setup-msvc-dev@v3
- with:
- arch: x64
- - name: Run preset
- run: cmake --workflow --preset ${{ matrix.presets.preset }}
-
- gtest-test:
- strategy:
- fail-fast: false
- matrix:
- platform:
- - description: "Ubuntu GNU"
- os: ubuntu-latest
- toolchain: "infra/cmake/gnu-toolchain.cmake"
- - description: "Ubuntu LLVM"
- os: ubuntu-latest
- toolchain: "infra/cmake/llvm-toolchain.cmake"
- - description: "Windows MSVC"
- os: windows-latest
- toolchain: "infra/cmake/msvc-toolchain.cmake"
- - description: "Macos Appleclang"
- os: macos-latest
- toolchain: "infra/cmake/appleclang-toolchain.cmake"
- cpp_version: [17, 20, 23, 26]
- cmake_args:
- - description: "Default"
- - description: "TSan"
- args: "-DBEMAN_BUILDSYS_SANITIZER=TSan"
- - description: "MaxSan"
- args: "-DBEMAN_BUILDSYS_SANITIZER=MaxSan"
- include:
- - platform:
- description: "Ubuntu GCC"
- os: ubuntu-latest
- toolchain: "infra/cmake/gnu-toolchain.cmake"
- cpp_version: 17
- cmake_args:
- description: "Werror"
- args: "-DCMAKE_CXX_FLAGS='-Werror=all -Werror=extra'"
- - platform:
- description: "Ubuntu GCC"
- os: ubuntu-latest
- toolchain: "infra/cmake/gnu-toolchain.cmake"
- cpp_version: 17
- cmake_args:
- description: "Dynamic"
- args: "-DBUILD_SHARED_LIBS=on"
- exclude:
- # MSVC does not support thread sanitizer
- - platform:
- description: "Windows MSVC"
- cmake_args:
- description: "TSan"
-
- name: "Unit:
- ${{ matrix.platform.description }}
- ${{ matrix.cpp_version }}
- ${{ matrix.cmake_args.description }}"
- runs-on: ${{ matrix.platform.os }}
- steps:
- - uses: actions/checkout@v4
- - name: Install Ninja
- uses: lukka/get-cmake@latest
- with:
- cmakeVersion: "~3.25.0"
- ninjaVersion: "^1.11.1"
- - name: Setup MSVC
- if: startsWith(matrix.platform.os, 'windows')
- uses: TheMrMilchmann/setup-msvc-dev@v3
- with:
- arch: x64
- - name: Build and Test
- uses: ./.github/actions/cmake-build-test
- with:
- cpp_version: ${{ matrix.cpp_version }}
- toolchain_file: ${{ matrix.platform.toolchain }}
- cmake_extra_args: ${{ matrix.cmake_args.args }}
-
- configuration-test:
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- matrix:
- args:
- - name: "Disable build testing"
- arg: "-DBEMAN_EXEMPLAR_BUILD_TESTS=OFF"
- - name: "Disable example building"
- arg: "-DBEMAN_EXEMPLAR_BUILD_EXAMPLES=OFF"
- - name: "Disable config-file package creation"
- arg: "-DBEMAN_EXEMPLAR_INSTALL_CONFIG_FILE_PACKAGE=OFF"
- name: "CMake: ${{ matrix.args.name }}"
- steps:
- - uses: actions/checkout@v4
- - name: Setup build environment
- uses: lukka/get-cmake@latest
- with:
- cmakeVersion: "~3.25.0"
- ninjaVersion: "^1.11.1"
- - name: Build and Test
- uses: ./.github/actions/cmake-build-test
- with:
- cpp_version: 17
- toolchain_file: "infra/cmake/gnu-toolchain.cmake"
- cmake_extra_args: ${{ matrix.args.arg }}
- disable_test: true
-
- compiler-test:
- runs-on: ubuntu-24.04
- strategy:
- fail-fast: false
- matrix:
- compilers:
- - class: GNU
- version: 14
- toolchain: "infra/cmake/gnu-toolchain.cmake"
- - class: GNU
- version: 13
- toolchain: "infra/cmake/gnu-toolchain.cmake"
- - class: GNU
- version: 12
- toolchain: "infra/cmake/gnu-toolchain.cmake"
- - class: LLVM
- version: 20
- toolchain: "infra/cmake/llvm-toolchain.cmake"
- - class: LLVM
- version: 19
- toolchain: "infra/cmake/llvm-toolchain.cmake"
- - class: LLVM
- version: 18
- toolchain: "infra/cmake/llvm-toolchain.cmake"
- - class: LLVM
- version: 17
- toolchain: "infra/cmake/llvm-toolchain.cmake"
- name: "Compiler: ${{ matrix.compilers.class }} ${{ matrix.compilers.version }}"
- steps:
- - uses: actions/checkout@v4
- - name: Setup build environment
- uses: lukka/get-cmake@latest
- with:
- cmakeVersion: "~3.25.0"
- ninjaVersion: "^1.11.1"
- - name: Install Compiler
- id: install-compiler
- run: |
- sudo add-apt-repository universe
- sudo apt-get update
-
- if [ "${{ matrix.compilers.class }}" = "GNU" ]; then
- CC=gcc-${{ matrix.compilers.version }}
- CXX=g++-${{ matrix.compilers.version }}
-
- sudo apt-get install -y $CC
- sudo apt-get install -y $CXX
-
- $CC --version
- $CXX --version
- else
- wget https://apt.llvm.org/llvm.sh
- chmod +x llvm.sh
- sudo bash llvm.sh ${{ matrix.compilers.version }}
-
- CC=clang-${{ matrix.compilers.version }}
- CXX=clang++-${{ matrix.compilers.version }}
-
- $CC --version
- $CXX --version
- fi
-
- echo "CC=$CC" >> "$GITHUB_OUTPUT"
- echo "CXX=$CXX" >> "$GITHUB_OUTPUT"
- - name: Build and Test
- uses: ./.github/actions/cmake-build-test
- with:
- cpp_version: 20
- toolchain_file: ${{ matrix.compilers.toolchain }}
+ uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-preset-test.yml@1.5.3
+ with:
+ matrix_config: >
+ [
+ {"preset": "gcc-debug", "image": "ghcr.io/bemanproject/infra-containers-gcc:latest"},
+ {"preset": "gcc-release", "image": "ghcr.io/bemanproject/infra-containers-gcc:latest"},
+ {"preset": "llvm-debug", "image": "ghcr.io/bemanproject/infra-containers-clang:latest"},
+ {"preset": "llvm-release", "image": "ghcr.io/bemanproject/infra-containers-clang:latest"},
+ {"preset": "appleclang-debug", "runner": "macos-latest"},
+ {"preset": "appleclang-release", "runner": "macos-latest"},
+ {"preset": "msvc-debug", "runner": "windows-latest"},
+ {"preset": "msvc-release", "runner": "windows-latest"}
+ ]
+
+ build-and-test:
+ uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-build-and-test.yml@1.5.3
+ with:
+ matrix_config: >
+ {
+ "gcc": [
+ { "versions": ["15"],
+ "tests": [
+ { "cxxversions": ["c++26"],
+ "tests": [
+ { "stdlibs": ["libstdc++"],
+ "tests": [
+ "Debug.Default", "Release.Default", "Release.TSan",
+ "Release.MaxSan", "Debug.Werror",
+ "Debug.Coverage"
+ ]
+ }
+ ]
+ },
+ { "cxxversions": ["c++23"],
+ "tests": [{ "stdlibs": ["libstdc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ },
+ { "versions": ["14", "13"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23"],
+ "tests": [{ "stdlibs": ["libstdc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ },
+ {
+ "versions": ["12"],
+ "tests": [
+ { "cxxversions": ["c++23"],
+ "tests": [{ "stdlibs": ["libstdc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ }
+ ],
+ "clang": [
+ { "versions": ["22"],
+ "tests": [
+ {"cxxversions": ["c++26"],
+ "tests": [
+ { "stdlibs": ["libstdc++", "libc++"],
+ "tests": [
+ "Debug.Default", "Release.Default", "Release.TSan",
+ "Release.MaxSan", "Debug.Werror"
+ ]
+ }
+ ]
+ },
+ { "cxxversions": ["c++23"],
+ "tests": [
+ {"stdlibs": ["libstdc++", "libc++"], "tests": ["Release.Default"]}
+ ]
+ }
+ ]
+ },
+ { "versions": ["21", "20", "19"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23"],
+ "tests": [
+ {"stdlibs": ["libstdc++", "libc++"], "tests": ["Release.Default"]}
+ ]
+ }
+ ]
+ },
+ { "versions": ["18"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23"],
+ "tests": [{"stdlibs": ["libc++"], "tests": ["Release.Default"]}]
+ },
+ { "cxxversions": ["c++23"],
+ "tests": [{"stdlibs": ["libstdc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ },
+ { "versions": ["17"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23"],
+ "tests": [{"stdlibs": ["libc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ }
+ ],
+ "appleclang": [
+ { "versions": ["latest"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23"],
+ "tests": [{ "stdlibs": ["libc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ }
+ ],
+ "msvc": [
+ { "versions": ["latest"],
+ "tests": [
+ { "cxxversions": ["c++23"],
+ "tests": [
+ { "stdlibs": ["stl"],
+ "tests": ["Debug.Default", "Release.Default", "Release.MaxSan"]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
create-issue-when-fault:
- runs-on: ubuntu-latest
- needs: [preset-test, gtest-test, configuration-test, compiler-test]
+ needs: [preset-test, build-and-test]
if: failure() && github.event_name == 'schedule'
- steps:
- # See https://github.com/cli/cli/issues/5075
- - uses: actions/checkout@v4
- - name: Create issue
- run: |
- issue_num=$(gh issue list -s open -S "[SCHEDULED-BUILD] Build & Test failure" -L 1 --json number | jq 'if length == 0 then -1 else .[0].number end')
-
- body="**Build-and-Test Failure Report**
- - **Time of Failure**: $(date -u '+%B %d, %Y, %H:%M %Z')
- - **Commit**: [${{ github.sha }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }})
- - **Action Run**: [View logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
-
- The scheduled build-and-test triggered by cron has failed.
- Please investigate the logs and recent changes associated with this commit or rerun the workflow if you believe this is an error."
-
- if [[ $issue_num -eq -1 ]]; then
- gh issue create --repo ${{ github.repository }} --title "[SCHEDULED-BUILD] Build & Test failure" --body "$body"
- else
- gh issue comment --repo ${{ github.repository }} $issue_num --body "$body"
- fi
- env:
- GH_TOKEN: ${{ github.token }}
+ uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-create-issue-when-fault.yml@1.5.3
diff --git a/.github/workflows/pre-commit-check.yml b/.github/workflows/pre-commit-check.yml
new file mode 100644
index 0000000..980f6c5
--- /dev/null
+++ b/.github/workflows/pre-commit-check.yml
@@ -0,0 +1,19 @@
+name: Lint Check (pre-commit)
+
+on:
+ # We have to use pull_request_target here as pull_request does not grant
+ # enough permission for reviewdog
+ pull_request_target:
+ push:
+ branches:
+ - main
+
+permissions:
+ contents: read
+ checks: write
+ issues: write
+ pull-requests: write
+
+jobs:
+ pre-commit:
+ uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-pre-commit.yml@1.5.3
diff --git a/.github/workflows/pre-commit-update.yml b/.github/workflows/pre-commit-update.yml
new file mode 100644
index 0000000..7142aef
--- /dev/null
+++ b/.github/workflows/pre-commit-update.yml
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+name: Weekly pre-commit autoupdate
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: "56 16 * * 0"
+
+jobs:
+ auto-update-pre-commit:
+ uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-update-pre-commit.yml@1.5.3
+ secrets:
+ APP_ID: ${{ secrets.AUTO_PR_BOT_APP_ID }}
+ PRIVATE_KEY: ${{ secrets.AUTO_PR_BOT_PRIVATE_KEY }}
diff --git a/.gitignore b/.gitignore
index 286a38e..d293e3b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,12 @@
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+/.cache
/compile_commands.json
/build
+
+# ignore emacs temp files
+*~
+\#*\#
+
+# ignore vscode settings
+.vscode
diff --git a/.markdownlint.yaml b/.markdownlint.yaml
index 81f5fcd..21c2849 100644
--- a/.markdownlint.yaml
+++ b/.markdownlint.yaml
@@ -7,3 +7,4 @@ MD033: false
# Update the comment in .clang-format if we no-longer tie these two column limits.
MD013:
line_length: 119
+ code_blocks: false
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 25c2ab7..eb01186 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,19 +13,21 @@ 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: v22.1.4
hooks:
- id: clang-format
types_or: [c++, c]
# CMake linting and formatting
- - repo: https://github.com/BlankSpruce/gersemi
- rev: 0.15.1
+ - repo: https://github.com/BlankSpruce/gersemi-pre-commit
+ rev: 0.27.2
hooks:
- id: gersemi
name: CMake linting
+ exclude: ^.*/tests/.*/data/ # Exclude test data directories
# Markdown linting
+ # Config file: .markdownlint.yaml
# Commented out to disable this by default. Uncomment to enable markdown linting.
# - repo: https://github.com/igorshubovych/markdownlint-cli
# rev: v0.42.0
@@ -33,7 +35,7 @@ repos:
# - id: markdownlint
- repo: https://github.com/codespell-project/codespell
- rev: v2.3.0
+ rev: v2.4.2
hooks:
- id: codespell
@@ -42,3 +44,5 @@ repos:
rev: v0.3.1
hooks:
- id: beman-tidy
+
+exclude: 'cookiecutter/|infra/'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dd9f81f..3f3eb98 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,53 +1,56 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-cmake_minimum_required(VERSION 3.25)
+cmake_minimum_required(VERSION 3.30...4.3)
project(
beman.copyable_function # CMake Project Name, which is also the name of the top-level
# targets (e.g., library, executable, etc.).
DESCRIPTION "A Beman library copyable_function"
LANGUAGES CXX
- VERSION 1.0.0
+ VERSION 0.1.0
)
-set(CMAKE_CXX_STANDARD 26)
-
-enable_testing()
# [CMAKE.SKIP_TESTS]
option(
BEMAN_COPYABLE_FUNCTION_BUILD_TESTS
- "Enable building tests and test infrastructure. Default: ON. Values: { ON, OFF }."
+ "Enable building tests and test infrastructure. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }."
${PROJECT_IS_TOP_LEVEL}
)
+# [CMAKE.SKIP_EXAMPLES]
option(
- BEMAN_COPYABLE_FUNCTION_INSTALL_CONFIG_FILE_PACKAGE
- "Enable creating and installing a CMake config-file package. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }."
+ BEMAN_COPYABLE_FUNCTION_BUILD_EXAMPLES
+ "Enable building examples. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }."
${PROJECT_IS_TOP_LEVEL}
)
-include(FetchContent)
-include(GNUInstallDirs)
+# for find of beman_install_library and configure_build_telemetry
+include(infra/cmake/beman-install-library.cmake)
+include(infra/cmake/BuildTelemetryConfig.cmake)
-if(BEMAN_COPYABLE_FUNCTION_BUILD_TESTS)
- # Fetch GoogleTest
- FetchContent_Declare(
- GTest
- GIT_REPOSITORY https://github.com/google/googletest.git
- GIT_TAG
- 6910c9d9165801d8827d628cb72eb7ea9dd538c5 # release-1.16.0
- EXCLUDE_FROM_ALL
- )
- set(INSTALL_GTEST OFF) # Disable GoogleTest installation
- FetchContent_MakeAvailable(GTest)
-endif()
+add_library(beman.copyable_function INTERFACE)
+add_library(beman::copyable_function ALIAS beman.copyable_function)
-add_subdirectory(src/beman/copyable_function)
+target_sources(
+ beman.copyable_function
+ PUBLIC FILE_SET HEADERS BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include"
+)
+
+set_target_properties(
+ beman.copyable_function
+ PROPERTIES VERIFY_INTERFACE_HEADER_SETS ${PROJECT_IS_TOP_LEVEL}
+)
+
+add_subdirectory(include/beman/copyable_function)
+
+beman_install_library(beman.copyable_function TARGETS beman.copyable_function)
+configure_build_telemetry()
if(BEMAN_COPYABLE_FUNCTION_BUILD_TESTS)
+ enable_testing()
add_subdirectory(tests/beman/copyable_function)
endif()
-if(BEMAN_COPYABLE_FUNCTION_BUILD_TESTS)
+if(BEMAN_COPYABLE_FUNCTION_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
diff --git a/CMakePresets.json b/CMakePresets.json
index 4fe1b5b..bd35911 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -7,7 +7,7 @@
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
- "CMAKE_CXX_STANDARD": "26",
+ "CMAKE_CXX_STANDARD": "23",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "./infra/cmake/use-fetch-content.cmake"
}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..ad1e153
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,111 @@
+# Development
+
+## Configure and Build the Project Using CMake Presets
+
+The simplest way of configuring and building the project is to use [CMake
+Presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html). Appropriate
+presets for major compilers have been included by default. You can use `cmake
+--list-presets=workflow` to see all available presets.
+
+Here is an example of invoking the `gcc-debug` preset:
+
+```shell
+cmake --workflow --preset gcc-debug
+```
+
+Generally, there are two kinds of presets, `debug` and `release`.
+
+The `debug` presets are designed to aid development, so they have debuginfo and sanitizers
+enabled.
+
+> [!NOTE]
+>
+> The sanitizers that are enabled vary from compiler to compiler. See the toolchain files
+> under ([`infra/cmake`](infra/cmake/)) to determine the exact configuration used for each
+> preset.
+
+The `release` presets are designed for production use, and
+consequently have the highest optimization turned on (e.g. `O3`).
+
+## Configure and Build Manually
+
+If the presets are not suitable for your use case, a traditional CMake invocation will
+provide more configurability.
+
+To configure, build and test the project manually, you can run this set of commands. Note
+that this requires GoogleTest to be installed.
+
+```bash
+cmake \
+ -B build \
+ -S . \
+ -DCMAKE_CXX_STANDARD=17 \
+ # Your extra arguments here.
+cmake --build build
+ctest --test-dir build
+```
+
+> [!IMPORTANT]
+>
+> Beman projects are [passive projects](
+> https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#cmakepassive_projects),
+> so you need to specify the C++ version via `CMAKE_CXX_STANDARD` when manually
+> configuring the project.
+
+## Dependency Management
+
+### FetchContent
+
+Instead of installing the project's dependencies via a package manager, you can optionally
+configure beman.copyable_function to fetch them automatically via CMake FetchContent.
+
+To do so, specify
+`-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./infra/cmake/use-fetch-content.cmake`. This will
+bring in GoogleTest automatically along with any other dependency the project may require.
+
+Example commands:
+
+```shell
+cmake \
+ -B build \
+ -S . \
+ -DCMAKE_CXX_STANDARD=17 \
+ -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./infra/cmake/use-fetch-content.cmake
+cmake --build build
+ctest --test-dir build
+```
+
+The file `./lockfile.json` configures the list of dependencies and versions that will be
+acquired by FetchContent.
+
+## Project-specific configure arguments
+
+Project-specific options are prefixed with `BEMAN_COPYABLE_FUNCTION`.
+You can see the list of available options with:
+
+```bash
+cmake -LH -S . -B build | grep "BEMAN_COPYABLE_FUNCTION" -C 2
+```
+
+
+
+Some project-specific configure arguments
+
+### `BEMAN_COPYABLE_FUNCTION_BUILD_TESTS`
+
+Enable building tests and test infrastructure. Default: `ON`.
+Values: `{ ON, OFF }`.
+
+### `BEMAN_COPYABLE_FUNCTION_BUILD_EXAMPLES`
+
+Enable building examples. Default: `ON`. Values: `{ ON, OFF }`.
+
+### `BEMAN_COPYABLE_FUNCTION_INSTALL_CONFIG_FILE_PACKAGE`
+
+Enable installing the CMake config file package. Default: `ON`.
+Values: `{ ON, OFF }`.
+
+This is required so that users of `beman.copyable_function` can use
+`find_package(beman.copyable_function)` to locate the library.
+
+
diff --git a/README.md b/README.md
index 25c9b5b..291c481 100644
--- a/README.md
+++ b/README.md
@@ -4,20 +4,19 @@
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-->
-
-
- 
-
-
+
+   [](https://coveralls.io/github/bemanproject/copyable_function?branch=main) 
`beman.copyable_function` is a type-erased function wrapper that can represent any copyable callable matching
the function signature R(Args...). The library conforms to the [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md).
+**Implements**: `std::copyable_function` proposed in [P2548R6](https://wg21.link/P2548R6).
+
**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)
## License
-beman.copyable\_function is licensed under the Apache License v2.0 with LLVM Exceptions.
+`beman.copyable_function` is licensed under the Apache License v2.0 with LLVM Exceptions.
## Usage
@@ -41,247 +40,122 @@ int main()
```
+Full runnable examples can be found in [`examples/`](examples/).
+
## Dependencies
### Build Environment
This project requires at least the following to build:
-* C++17
-* CMake 3.25
+* A C++ compiler that conforms to the C++17 standard or greater
+* CMake 3.30 or later
+* (Test Only) GoogleTest
-This project pulls [Google Test](https://github.com/google/googletest)
-from GitHub as a development dependency for its testing framework,
-thus requiring an active internet connection to configure.
-You can disable this behavior by setting cmake option
-[`BEMAN_EXEMPLAR_BUILD_TESTS`](#beman_exemplar_build_tests) to `OFF`
-when configuring the project.
+You can disable building tests by setting CMake option `BEMAN_COPYABLE_FUNCTION_BUILD_TESTS` to
+`OFF` when configuring the project.
### Supported Platforms
-This project officially supports:
-
-* GNU GCC Compiler \[version 12-14\]
-* LLVM Clang++ Compiler \[version 17-20\]
-* AppleClang compiler on Mac OS
-* MSVC compiler on Windows
-
-> [!NOTE]
->
-> Versions outside of this range would likely work as well,
-> especially if you're using a version above the given range
-> (e.g. HEAD/ nightly).
-> These development environments are verified using our CI configuration.
+| Compiler | Version | C++ Standards | Standard Library |
+|------------|---------|---------------|-------------------|
+| GCC | 15-13 | C++26, C++23 | libstdc++ |
+| GCC | 12 | C++23 | libstdc++ |
+| Clang | 22-19 | C++26, C++23 | libstdc++, libc++ |
+| Clang | 18 | C++26, C++23 | libc++ |
+| Clang | 18 | C++23 | libstdc++ |
+| Clang | 17 | C++26, C++23 | libc++ |
+| AppleClang | latest | C++26, C++23 | libc++ |
+| MSVC | latest | C++23 | MSVC STL |
## Development
-### Develop using GitHub Codespace
-
-This project supports [GitHub Codespace](https://github.com/features/codespaces)
-via [Development Containers](https://containers.dev/),
-which allows rapid development and instant hacking in your browser.
-We recommend you using GitHub codespace to explore this project as this
-requires minimal setup.
-
-You can create a codespace for this project by clicking this badge:
-
-[](https://codespaces.new/bemanproject/exemplar)
-
-For more detailed documentation regarding creating and developing inside of
-GitHub codespaces, please reference [this doc](https://docs.github.com/en/codespaces/).
-
-> [!NOTE]
->
-> The codespace container may take up to 5 minutes to build and spin-up,
-> this is normal as we need to build a custom docker container to setup
-> an environment appropriate for beman projects.
-
-### Develop locally on your machines
-
-
- For Linux based systems
-
-Beman libraries requires [recent versions of CMake](#build-environment),
-we advice you download CMake directly from [CMake's website](https://cmake.org/download/)
-or install via the [Kitware apt library](https://apt.kitware.com/).
-
-A [supported compiler](#supported-platforms) should be available from your package manager.
-Alternatively you could use an install script from official compiler vendors.
-
-Here is an example of how to install the latest stable version of clang
-as per [the official LLVM install guide](https://apt.llvm.org/).
-
-```bash
-bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"
-```
+See the [Contributing Guidelines](CONTRIBUTING.md).
-
+## Integrate beman.copyable_function into your project
-
- For MacOS based systems
+### Build
-Beman libraries require [recent versions of CMake](#build-environment).
-You can use [`Homebrew`](https://brew.sh/) to install the latest major version of CMake.
+You can build copyable_function using a CMake workflow preset:
```bash
-brew install cmake
+cmake --workflow --preset gcc-release
```
-A [supported compiler](#supported-platforms) is also available from brew.
-
-For example, you can install latest major release of Clang++ compiler as:
+To list available workflow presets, you can invoke:
```bash
-brew install llvm
-```
-
-
-
-### Configure and Build the Project Using CMake Presets
-
-This project recommends using [CMake Presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html)
-to configure, build and test the project.
-Appropriate presets for major compilers have been included by default.
-You can use `cmake --list-presets` to see all available presets.
-
-Here is an example to invoke the `gcc-debug` preset.
-
-```shell
-cmake --workflow --preset gcc-debug
+cmake --list-presets=workflow
```
-Generally, there's two kinds of presets, `debug` and `release`.
-
-The `debug` presets are designed to aid development, so it has debugging
-instrumentation enabled and as many sanitizers turned on as possible.
+For details on building beman.copyable_function without using a CMake preset, refer to the
+[Contributing Guidelines](CONTRIBUTING.md).
-> [!NOTE]
->
-> The set of sanitizer supports are different across compilers.
-> You can checkout the exact set compiler arguments by looking at the toolchain
-> files under the [`cmake`](cmake/) directory.
-
-The `release` presets are designed for use in production environments,
-thus it has the highest optimization turned on (e.g. `O3`).
-
-### Configure and Build Manually
-
-While [CMake Presets](#configure-and-build-the-project-using-cmake-presets) are
-convenient, you might want to set different configuration or compiler arguments
-than any provided preset supports.
+### Installation
-To configure, build and test the project with extra arguments,
-you can run this sets of command.
+To install beman.copyable_function globally after building with the `gcc-release` preset, you can
+run:
```bash
-cmake -B build -S . -DCMAKE_CXX_STANDARD=20 # Your extra arguments here.
-cmake --build build
-ctest --test-dir build
+sudo cmake --install build/gcc-release
```
-> [!IMPORTANT]
->
-> Beman projects are
-> [passive projects](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md#cmake),
-> therefore,
-> you will need to specify C++ version via `CMAKE_CXX_STANDARD`
-> when manually configuring the project.
-
-### Project specific configure arguments
-
-When configuring the project manually,
-you can pass an array of project specific CMake configs to customize your build.
-
-Project specific options are prefixed with `BEMAN_EXEMPLAR`.
-You can see the list of available options with:
+Alternatively, to install to a prefix, for example `/opt/beman`, you can run:
```bash
-cmake -LH | grep "BEMAN_EXEMPLAR" -C 2
+sudo cmake --install build/gcc-release --prefix /opt/beman
```
-
-
- Details of CMake arguments.
+This will generate the following directory structure:
-#### `BEMAN_EXEMPLAR_BUILD_TESTS`
-
-Enable building tests and test infrastructure. Default: ON.
-Values: { ON, OFF }.
-
-You can configure the project to have this option turned off via:
-
-```bash
-cmake -B build -S . -DCMAKE_CXX_STANDARD=20 -DBEMAN_EXEMPLAR_BUILD_TESTS=OFF
-```
-
-> [!TIP]
-> Because this project requires Google Tests as part of its development
-> dependency,
-> disable building tests avoids the project from pulling Google Tests from
-> GitHub.
-
-#### `BEMAN_EXEMPLAR_BUILD_EXAMPLES`
-
-Enable building examples. Default: ON. Values: { ON, OFF }.
-
-
-
-## Integrate beman.copyable_function into your project
-
-To use `beman.copyable_function` in your C++ project,
-include an appropriate `beman.copyable_function` header from your source code.
-
-```c++
-#include
+```txt
+/opt/beman
+├── include
+│ └── beman
+│ └── copyable_function
+│ ├── copyable_function.hpp
+│ └── ...
+└── lib
+ └── cmake
+ └── beman.copyable_function
+ ├── beman.copyable_function-config-version.cmake
+ ├── beman.copyable_function-config.cmake
+ └── beman.copyable_function-targets.cmake
```
-> [!NOTE]
->
-> `beman.copyable_function` headers are to be included with the `beman/copyable_function/` directories prefixed.
-> It is not supported to alter include search paths to spell the include target another way. For instance,
-> `#include ` is not a supported interface.
-
-How you will link your project against `beman.copyable_function` will depend on your build system.
-CMake instructions are provided in following sections.
+### CMake Configuration
-### Linking your project to beman.exemplar with CMake
+If you installed beman.copyable_function to a prefix, you can specify that prefix to your CMake
+project using `CMAKE_PREFIX_PATH`; for example, `-DCMAKE_PREFIX_PATH=/opt/beman`.
-For CMake based projects,
-you will need to use the `beman.copyable_function` CMake module
-to define the `beman::copyable_function` CMake target:
+You need to bring in the `beman.copyable_function` package to define the `beman::copyable_function` CMake
+target:
```cmake
find_package(beman.copyable_function REQUIRED)
```
-You will also need to add `beman::copyable_function` to the link libraries of
-any libraries or executables that include beman.copyable_function's header file.
+You will then need to add `beman::copyable_function` to the link libraries of any libraries or
+executables that include `beman.copyable_function` headers.
```cmake
target_link_libraries(yourlib PUBLIC beman::copyable_function)
```
-### Produce beman.copyable_function static library locally
+### Using beman.copyable_function
-You can include copyable_function's headers locally
-by producing a static `libbeman.copyable_function.a` library.
+To use `beman.copyable_function` in your C++ project,
+include an appropriate `beman.copyable_function` header from your source code.
-```bash
-cmake --workflow --preset gcc-release
-cmake --install build/gcc-release --prefix /opt/beman.copyable_function
+```c++
+#include
```
-This will generate such directory structure at `/opt/beman.copyable_function`.
-
-```txt
-/opt/beman.copyable_function
-├── include
-│ └── beman
-│ └── copyable_function
-│ └── copyable_function.hpp
-└── lib
- └── libbeman.copyable_function.a
-```
+> [!NOTE]
+>
+> `beman.copyable_function` headers are to be included with the `beman/copyable_function/` prefix.
+> Altering include search paths to spell the include target another way (e.g.
+> `#include `) is unsupported.
## Contributing
diff --git a/cmake/appleclang-toolchain.cmake b/cmake/appleclang-toolchain.cmake
deleted file mode 100644
index bc12103..0000000
--- a/cmake/appleclang-toolchain.cmake
+++ /dev/null
@@ -1,39 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-# This toolchain file is not meant to be used directly,
-# but to be invoked by CMake preset and GitHub CI.
-#
-# This toolchain file configures for apple clang family of compiler.
-# Note this is different from LLVM toolchain.
-#
-# BEMAN_BUILDSYS_SANITIZER:
-# This optional CMake parameter is not meant for public use and is subject to
-# change.
-# Possible values:
-# - MaxSan: configures clang and clang++ to use all available non-conflicting
-# sanitizers. Note that apple clang does not support leak sanitizer.
-# - TSan: configures clang and clang++ to enable the use of thread sanitizer.
-
-include_guard(GLOBAL)
-
-set(CMAKE_C_COMPILER clang)
-set(CMAKE_CXX_COMPILER clang++)
-
-if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan")
- set(SANITIZER_FLAGS
- "-fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined"
- )
-elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan")
- set(SANITIZER_FLAGS "-fsanitize=thread")
-endif()
-
-set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}")
-set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}")
-
-set(RELEASE_FLAGS "-O3 ${SANITIZER_FLAGS}")
-
-set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
-set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
-
-set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
-set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
diff --git a/cmake/beman.copyable_function-config.cmake.in b/cmake/beman.copyable_function-config.cmake.in
deleted file mode 100644
index 3910054..0000000
--- a/cmake/beman.copyable_function-config.cmake.in
+++ /dev/null
@@ -1,7 +0,0 @@
-set(BEMAN_COPYABLE_FUNCTION_VERSION @PROJECT_VERSION@)
-
-@PACKAGE_INIT@
-
-include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake)
-
-check_required_components(@PROJECT_NAME@)
diff --git a/cmake/gnu-toolchain.cmake b/cmake/gnu-toolchain.cmake
deleted file mode 100644
index 2e2a2ad..0000000
--- a/cmake/gnu-toolchain.cmake
+++ /dev/null
@@ -1,38 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-# This toolchain file is not meant to be used directly,
-# but to be invoked by CMake preset and GitHub CI.
-#
-# This toolchain file configures for GNU family of compiler.
-#
-# BEMAN_BUILDSYS_SANITIZER:
-# This optional CMake parameter is not meant for public use and is subject to
-# change.
-# Possible values:
-# - MaxSan: configures gcc and g++ to use all available non-conflicting
-# sanitizers.
-# - TSan: configures gcc and g++ to enable the use of thread sanitizer
-
-include_guard(GLOBAL)
-
-set(CMAKE_C_COMPILER gcc)
-set(CMAKE_CXX_COMPILER g++)
-
-if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan")
- set(SANITIZER_FLAGS
- "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined"
- )
-elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan")
- set(SANITIZER_FLAGS "-fsanitize=thread")
-endif()
-
-set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}")
-set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}")
-
-set(RELEASE_FLAGS "-O3 ${SANITIZER_FLAGS}")
-
-set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
-set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
-
-set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
-set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
diff --git a/cmake/llvm-toolchain.cmake b/cmake/llvm-toolchain.cmake
deleted file mode 100644
index d783803..0000000
--- a/cmake/llvm-toolchain.cmake
+++ /dev/null
@@ -1,38 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-# This toolchain file is not meant to be used directly,
-# but to be invoked by CMake preset and GitHub CI.
-#
-# This toolchain file configures for LLVM family of compiler.
-#
-# BEMAN_BUILDSYS_SANITIZER:
-# This optional CMake parameter is not meant for public use and is subject to
-# change.
-# Possible values:
-# - MaxSan: configures clang and clang++ to use all available non-conflicting
-# sanitizers.
-# - TSan: configures clang and clang++ to enable the use of thread sanitizer.
-
-include_guard(GLOBAL)
-
-set(CMAKE_C_COMPILER clang)
-set(CMAKE_CXX_COMPILER clang++)
-
-if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan")
- set(SANITIZER_FLAGS
- "-fsanitize=address -fsanitize=leak -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined"
- )
-elseif(BEMAN_BUILDSYS_SANITIZER STREQUAL "TSan")
- set(SANITIZER_FLAGS "-fsanitize=thread")
-endif()
-
-set(CMAKE_C_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}")
-set(CMAKE_CXX_FLAGS_DEBUG_INIT "${SANITIZER_FLAGS}")
-
-set(RELEASE_FLAGS "-O3 ${SANITIZER_FLAGS}")
-
-set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
-set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
-
-set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
-set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
diff --git a/cmake/msvc-toolchain.cmake b/cmake/msvc-toolchain.cmake
deleted file mode 100644
index c2fffa7..0000000
--- a/cmake/msvc-toolchain.cmake
+++ /dev/null
@@ -1,38 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-# This toolchain file is not meant to be used directly,
-# but to be invoked by CMake preset and GitHub CI.
-#
-# This toolchain file configures for MSVC family of compiler.
-#
-# BEMAN_BUILDSYS_SANITIZER:
-# This optional CMake parameter is not meant for public use and is subject to
-# change.
-# Possible values:
-# - MaxSan: configures cl to use all available non-conflicting sanitizers.
-#
-# Note that in other toolchain files, TSan is also a possible value for
-# BEMAN_BUILDSYS_SANITIZER, however, MSVC does not support thread sanitizer,
-# thus this value is omitted.
-
-include_guard(GLOBAL)
-
-set(CMAKE_C_COMPILER cl)
-set(CMAKE_CXX_COMPILER cl)
-
-if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan")
- # /Zi flag (add debug symbol) is needed when using address sanitizer
- # See C5072: https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-c5072
- set(SANITIZER_FLAGS "/fsanitize=address /Zi")
-endif()
-
-set(CMAKE_CXX_FLAGS_DEBUG_INIT "/EHsc /permissive- ${SANITIZER_FLAGS}")
-set(CMAKE_C_FLAGS_DEBUG_INIT "/EHsc /permissive- ${SANITIZER_FLAGS}")
-
-set(RELEASE_FLAGS "/EHsc /permissive- /O2 ${SANITIZER_FLAGS}")
-
-set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
-set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
-
-set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
-set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 7efcfad..89230e6 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,5 +1,16 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-add_executable(sample_usage sample_usage.cpp)
+set(ALL_EXAMPLES sample_usage)
+message("Examples to be built: ${ALL_EXAMPLES}")
-target_link_libraries(sample_usage PRIVATE beman::copyable_function)
+foreach(example ${ALL_EXAMPLES})
+ add_executable(beman.copyable_function.examples.${example})
+ target_sources(
+ beman.copyable_function.examples.${example}
+ PRIVATE ${example}.cpp
+ )
+ target_link_libraries(
+ beman.copyable_function.examples.${example}
+ PRIVATE beman::copyable_function
+ )
+endforeach()
diff --git a/include/beman/copyable_function/CMakeLists.txt b/include/beman/copyable_function/CMakeLists.txt
new file mode 100644
index 0000000..a49b39a
--- /dev/null
+++ b/include/beman/copyable_function/CMakeLists.txt
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+target_sources(
+ beman.copyable_function
+ PUBLIC
+ FILE_SET HEADERS
+ FILES
+ copyable_function.hpp
+ copyable_function_helper.h
+ copyable_function_impl.hpp
+)
diff --git a/include/beman/copyable_function/copyable_function_helper.h b/include/beman/copyable_function/copyable_function_helper.h
index 02c2d81..ecd4a77 100644
--- a/include/beman/copyable_function/copyable_function_helper.h
+++ b/include/beman/copyable_function/copyable_function_helper.h
@@ -1,7 +1,11 @@
#ifndef BEMAN_COPYABLE_FUNCTION_HELPER
#define BEMAN_COPYABLE_FUNCTION_HELPER
+#include
+#include
#include
+#include
+#include
namespace beman {
template
struct _is_in_place_type : std::false_type {};
diff --git a/infra/.beman_submodule b/infra/.beman_submodule
index 7d06f0a..56dbbcc 100644
--- a/infra/.beman_submodule
+++ b/infra/.beman_submodule
@@ -1,3 +1,3 @@
[beman_submodule]
remote=https://github.com/bemanproject/infra.git
-commit_hash=3dc3acd501eccaf3c9bd8d93edb1ebf1fa58d8c6
+commit_hash=ea3ef79f77fdcc378149ebc7406e81e9ceb04146
diff --git a/infra/.devcontainer/docker_dev_container/devcontainer.json b/infra/.devcontainer/docker_dev_container/devcontainer.json
deleted file mode 100644
index 6707a25..0000000
--- a/infra/.devcontainer/docker_dev_container/devcontainer.json
+++ /dev/null
@@ -1,13 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-{
- "name": "beman.infra Docker Devcontainer",
- "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
- "features": {
- "ghcr.io/devcontainers/features/docker-in-docker:2": {
- "version": "latest",
- "enableNonRootDocker": true,
- "moby": false
- },
- "ghcr.io/devcontainers-extra/features/pre-commit:2": {}
- }
-}
diff --git a/infra/.github/CODEOWNERS b/infra/.github/CODEOWNERS
index d3be6f1..4ff90a4 100644
--- a/infra/.github/CODEOWNERS
+++ b/infra/.github/CODEOWNERS
@@ -1 +1 @@
-* @bemanproject/core-reviewers
+* @ednolan @neatudarius @rishyak @wusatosi @JeffGarland
diff --git a/infra/.github/workflows/beman-submodule.yml b/infra/.github/workflows/beman-submodule.yml
deleted file mode 100644
index d18dd7f..0000000
--- a/infra/.github/workflows/beman-submodule.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-name: beman-submodule tests
-
-on:
- push:
- pull_request:
- workflow_dispatch:
-
-jobs:
- beman-submodule-script-ci:
- name: beman_module.py ci
- runs-on: ubuntu-latest
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
-
- - name: Set up Python
- uses: actions/setup-python@v5
- with:
- python-version: 3.13
-
- - name: Install pytest
- run: |
- python3 -m pip install pytest
-
- - name: Run pytest
- run: |
- cd tools/beman-submodule/
- pytest
diff --git a/infra/.github/workflows/build_devcontainer.yml b/infra/.github/workflows/build_devcontainer.yml
deleted file mode 100644
index 1f26fc7..0000000
--- a/infra/.github/workflows/build_devcontainer.yml
+++ /dev/null
@@ -1,97 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-name: Publish Beman Containers
-
-on:
- push:
- paths:
- - ".github/workflows/build_devcontainer.yml"
- - "containers/**"
- workflow_dispatch:
-
-env:
- REGISTRY: ghcr.io
- DEBUG_NAME: ${{ github.repository }}
- DEPLOY_DEV_NAME_PREFIX: bemanproject/devcontainers
- DEPLOY_TESTING_NAME_PREFIX: bemanproject/testingcontainers
- BASE_IMAGE_DEV: mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04
- BASE_IMAGE_TEST: ubuntu:24.04
-
-permissions:
- packages: write
-
-jobs:
- containers:
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- matrix:
- compilers:
- - kind: gcc
- version: 14
- - kind: gcc
- version: 13
- - kind: gcc
- version: 12
- - kind: gcc
- version: 11
- - kind: clang
- version: 21
- - kind: clang
- version: 20
- - kind: clang
- version: 19
- - kind: clang
- version: 18
- - kind: clang
- version: 17
- usage: [dev, test]
- name: "${{ matrix.usage }}: ${{ matrix.compilers.kind }}-${{ matrix.compilers.version }}"
- steps:
- - name: Compute Image Name
- id: image_name
- run: |
- if [ "${{ github.repository }}/${{ github.ref }}" != "bemanproject/infra/refs/heads/main" ]; then
- image_name="${{ env.DEBUG_NAME }}"
- tag="${{ matrix.usage }}-${{ matrix.compilers.kind }}-${{ matrix.compilers.version }}"
- else
- if [ "${{ matrix.usage }}" = "dev" ]; then
- image_name="${{ env.DEPLOY_DEV_NAME_PREFIX }}-${{ matrix.compilers.kind }}"
- else
- image_name="${{ env.DEPLOY_TESTING_NAME_PREFIX }}-${{ matrix.compilers.kind }}"
- fi
- tag="${{ matrix.compilers.version }}"
- fi
-
- echo "Image Name: $image_name, Tag: $tag"
-
- echo "image_name=$image_name" >> "$GITHUB_OUTPUT"
- echo "tag=$tag" >> "$GITHUB_OUTPUT"
- - name: Compute Image base
- id: image_base
- run: |
- if [ "${{ matrix.usage }}" == "dev" ]; then
- echo "image=${{ env.BASE_IMAGE_DEV }}" >> "$GITHUB_OUTPUT"
- else
- echo "image=${{ env.BASE_IMAGE_TEST }}" >> "$GITHUB_OUTPUT"
- fi
- - name: Checkout repository
- uses: actions/checkout@v4
- - name: Log in to the Container registry
- uses: docker/login-action@v3
- with:
- registry: ${{ env.REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
- - name: Build and push Docker image
- uses: docker/build-push-action@v6
- with:
- context: containers
- build-args: |
- base_image=${{ steps.image_base.outputs.image }}
- compiler_kind=${{ matrix.compilers.kind }}
- compiler_version=${{ matrix.compilers.version }}
- push: true
- tags: ${{ env.REGISTRY }}/${{ steps.image_name.outputs.image_name }}:${{ steps.image_name.outputs.tag }}
- # https://github.com/docker/build-push-action/issues/894
- provenance: false
diff --git a/.github/workflows/pre-commit.yml b/infra/.github/workflows/pre-commit.yml
similarity index 98%
rename from .github/workflows/pre-commit.yml
rename to infra/.github/workflows/pre-commit.yml
index f3c4332..9646831 100644
--- a/.github/workflows/pre-commit.yml
+++ b/infra/.github/workflows/pre-commit.yml
@@ -5,6 +5,8 @@ on:
# enough permission for reviewdog
pull_request_target:
push:
+ branches:
+ - main
jobs:
pre-commit-push:
diff --git a/infra/.github/workflows/reusable-beman-create-issue-when-fault.yml b/infra/.github/workflows/reusable-beman-create-issue-when-fault.yml
new file mode 100644
index 0000000..024a51f
--- /dev/null
+++ b/infra/.github/workflows/reusable-beman-create-issue-when-fault.yml
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+name: 'Beman issue creation workflow'
+on:
+ workflow_call:
+ workflow_dispatch:
+jobs:
+ create-issue:
+ runs-on: ubuntu-latest
+ steps:
+ # See https://github.com/cli/cli/issues/5075
+ - uses: actions/checkout@v4
+ - name: Create issue
+ run: |
+ issue_num=$(gh issue list -s open -S "[SCHEDULED-BUILD] infra repo CI job failure" -L 1 --json number | jq 'if length == 0 then -1 else .[0].number end')
+ body="**CI job failure Report**
+ - **Time of Failure**: $(date -u '+%B %d, %Y, %H:%M %Z')
+ - **Commit**: [${{ github.sha }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }})
+ - **Action Run**: [View logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
+ The scheduled job triggered by cron has failed.
+ Please investigate the logs and recent changes associated with this commit or rerun the workflow if you believe this is an error."
+ if [[ $issue_num -eq -1 ]]; then
+ gh issue create --repo ${{ github.repository }} --title "[SCHEDULED-BUILD] infra repo CI job failure" --body "$body" --assignee ${{ github.actor }}
+ else
+ gh issue comment --repo ${{ github.repository }} $issue_num --body "$body"
+ fi
+ env:
+ GH_TOKEN: ${{ github.token }}
diff --git a/infra/.gitignore b/infra/.gitignore
index 259148f..b7cdbb5 100644
--- a/infra/.gitignore
+++ b/infra/.gitignore
@@ -30,3 +30,30 @@
*.exe
*.out
*.app
+
+# Python
+__pycache__/
+.pytest_cache/
+*.pyc
+*.pyo
+*.pyd
+*.pyw
+*.pyz
+*.pywz
+*.pyzw
+*.pyzwz
+*.delete_me
+
+# MAC OS
+*.DS_Store
+
+# Editor files
+.vscode/
+.idea/
+
+# Build directories
+infra.egg-info/
+beman_tidy.egg-info/
+*.egg-info/
+build/
+dist/
diff --git a/infra/.markdownlint.yaml b/infra/.markdownlint.yaml
deleted file mode 100644
index 81f5fcd..0000000
--- a/infra/.markdownlint.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-# MD033/no-inline-html : Inline HTML : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md033.md
-# Disable inline html linter is needed for
-MD033: false
-
-# MD013/line-length : Line length : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md013.md
-# Conforms to .clang-format ColumnLimit
-# Update the comment in .clang-format if we no-longer tie these two column limits.
-MD013:
- line_length: 119
diff --git a/infra/.pre-commit-config.yaml b/infra/.pre-commit-config.yaml
new file mode 100644
index 0000000..8052e18
--- /dev/null
+++ b/infra/.pre-commit-config.yaml
@@ -0,0 +1,21 @@
+repos:
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v6.0.0
+ hooks:
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-yaml
+ - id: check-added-large-files
+
+ - repo: https://github.com/codespell-project/codespell
+ rev: v2.4.2
+ hooks:
+ - id: codespell
+
+ # CMake linting and formatting
+ - repo: https://github.com/BlankSpruce/gersemi-pre-commit
+ rev: 0.27.2
+ hooks:
+ - id: gersemi
+ name: CMake linting
+ exclude: ^.*/tests/.*/data/ # Exclude test data directories
diff --git a/infra/README.md b/infra/README.md
index 4d31a49..bf9bbb0 100644
--- a/infra/README.md
+++ b/infra/README.md
@@ -2,10 +2,87 @@
-This repository contains the infrastructure for The Beman Project. This is NOT a library repository, so it does not
-respect the usual structure of a Beman library repository nor The Beman Standard.
+This repository contains the infrastructure for The Beman Project. This is NOT a library repository,
+so it does not respect the usual structure of a Beman library repository nor The Beman Standard!
## Description
+* `cmake/`: CMake modules and toolchain files used by Beman libraries.
* `containers/`: Containers used for CI builds and tests in the Beman org.
-* `tools/`: Tools used to manage the infrastructure and the codebase (e.g., linting, formatting, etc.).
+
+## Usage
+
+This repository is intended to be used as a beman-submodule in other Beman repositories. See
+[the beman-submodule documentation](https://github.com/bemanproject/beman-submodule) for details.
+
+
+### CMake Modules
+
+
+#### `beman_install_library`
+
+The CMake modules in this repository are intended to be used by Beman libraries. Use the
+`beman_add_install_library_config()` function to install your library, along with header
+files, any metadata files, and a CMake config file for `find_package()` support.
+
+```cmake
+add_library(beman.something)
+add_library(beman::something ALIAS beman.something)
+
+# ... configure your target as needed ...
+
+find_package(beman-install-library REQUIRED)
+beman_install_library(beman.something)
+```
+
+Note that the target must be created before calling `beman_install_library()`. The module
+also assumes that the target is named using the `beman.something` convention, and it
+uses that assumption to derive the names to match other Beman standards and conventions.
+If your target does not follow that convention, raise an issue or pull request to add
+more configurability to the module.
+
+The module will configure the target to install:
+
+* The library target itself
+* Any public headers associated with the target
+* CMake files for `find_package(beman.something)` support
+
+Some options for the project and target will also be supported:
+
+* `BEMAN_INSTALL_CONFIG_FILE_PACKAGES` - a list of package names (e.g., `beman.something`) for which to install the config file
+ (default: all packages)
+* `_INSTALL_CONFIG_FILE_PACKAGE` - a per-project option to enable/disable config file installation (default: `ON` if the project is top-level, `OFF` otherwise). For instance for `beman.something`, the option would be `BEMAN_SOMETHING_INSTALL_CONFIG_FILE_PACKAGE`.
+
+# BuildTelemetry
+
+The cmake modules in this library provide access to CMake instrumentation data in Google Trace format which is visualizable with chrome://tracing and https://ui.perfetto.dev.
+
+Telemetry may be enabled in several ways:
+
+## `include`
+
+```cmake
+include (infra/cmake/BuildTelemetry.cmake)
+configure_build_telemetry()
+```
+
+## `find_package`
+
+```cmake
+find_package(BuildTelemetry)
+configure_build_telemetry()
+```
+
+as long as [BuildTelemetryConfig.cmake](./cmake/BuildTelemetryConfig.cmake) is in your module path.
+
+## `CMAKE_PROJECT_TOP_LEVEL_INCLUDES`
+A non-invasive way to inject this telemetry into a CMake build you do not want to modify.
+Add:
+```sh
+-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=infra/cmake/BuildTelemetry.cmake
+```
+To the cmake invocation.
+
+In any form, CMake will call `telemetry.sh` which will copy the trace data in json format into a `.trace` subdirectory within the build directory.
+
+Multiple calls to `configure_build_telemetry` will only configure the callback hooks once, so it is safe to enable multiple times, including by TOP_LEVEL_INCLUDE.
diff --git a/infra/cmake/BuildTelemetry.cmake b/infra/cmake/BuildTelemetry.cmake
new file mode 100755
index 0000000..c2ff343
--- /dev/null
+++ b/infra/cmake/BuildTelemetry.cmake
@@ -0,0 +1,4 @@
+include_guard(GLOBAL)
+
+include(${CMAKE_CURRENT_LIST_DIR}/BuildTelemetryConfig.cmake)
+configure_build_telemetry()
diff --git a/infra/cmake/BuildTelemetryConfig.cmake b/infra/cmake/BuildTelemetryConfig.cmake
new file mode 100755
index 0000000..15aae48
--- /dev/null
+++ b/infra/cmake/BuildTelemetryConfig.cmake
@@ -0,0 +1,58 @@
+include_guard(GLOBAL)
+
+set(BUILD_TELEMETRY_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+function(configure_build_telemetry)
+ if(NOT BUILD_TELEMETRY_CONFIGURATION)
+ # Check if the CMake version is at least 4.3
+ if(CMAKE_VERSION VERSION_LESS "4.3")
+ message(
+ STATUS
+ "CMake version is less than 4.3, configuring cmake_instrumentation is unavailable."
+ )
+ return()
+ else()
+ message(STATUS "Configuring Build Telemetry")
+ endif()
+
+ # Find bash and jq for the telemetry callback script.
+ # On Windows, Git for Windows provides bash if available.
+ find_program(BEMAN_BASH bash)
+ find_program(BEMAN_JQ jq)
+ if(NOT BEMAN_BASH OR NOT BEMAN_JQ)
+ message(
+ STATUS
+ "bash or jq not found, build telemetry disabled on this platform."
+ )
+ return()
+ endif()
+
+ # Telemetry query
+ cmake_instrumentation(
+ API_VERSION 1
+ DATA_VERSION 1
+ OPTIONS staticSystemInformation dynamicSystemInformation trace
+ HOOKS
+ postGenerate
+ preBuild
+ postBuild
+ preCMakeBuild
+ postCMakeBuild
+ postCMakeInstall
+ postCTest
+ CALLBACK ${BEMAN_BASH}
+ ${BUILD_TELEMETRY_DIR}/telemetry.sh
+ )
+ message(
+ DEBUG
+ "using callback script ${BUILD_TELEMETRY_DIR}/telemetry.sh via ${BEMAN_BASH}"
+ )
+
+ # Mark configuration as done in cache
+ set(BUILD_TELEMETRY_CONFIGURATION
+ TRUE
+ CACHE INTERNAL
+ "Flag to ensure Build Telemetry configured only once"
+ )
+ endif()
+endfunction(configure_build_telemetry)
diff --git a/infra/cmake/Config.cmake.in b/infra/cmake/Config.cmake.in
new file mode 100644
index 0000000..3f1341c
--- /dev/null
+++ b/infra/cmake/Config.cmake.in
@@ -0,0 +1,12 @@
+# cmake/Config.cmake.in -*-makefile-*-
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+include(CMakeFindDependencyMacro)
+
+@BEMAN_INSTALL_FIND_DEPENDENCIES@
+
+@PACKAGE_INIT@
+
+include(${CMAKE_CURRENT_LIST_DIR}/@BEMAN_INSTALL_BASE_PKG_NAME@-targets.cmake)
+
+check_required_components(@BEMAN_INSTALL_BASE_PKG_NAME@)
diff --git a/infra/cmake/appleclang-toolchain.cmake b/infra/cmake/appleclang-toolchain.cmake
index 5f44e80..70ef548 100644
--- a/infra/cmake/appleclang-toolchain.cmake
+++ b/infra/cmake/appleclang-toolchain.cmake
@@ -39,3 +39,6 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
+
+# Add this dir to the module path so that `find_package(beman-install-library)` works
+list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}")
diff --git a/infra/cmake/beman-install-library.cmake b/infra/cmake/beman-install-library.cmake
new file mode 100644
index 0000000..dc5a4d1
--- /dev/null
+++ b/infra/cmake/beman-install-library.cmake
@@ -0,0 +1,323 @@
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+include_guard(GLOBAL)
+
+include(CMakePackageConfigHelpers)
+include(GNUInstallDirs)
+
+# beman_install_library
+# =====================
+#
+# Installs a library (or set of targets) along with headers, C++ modules,
+# and optional CMake package configuration files.
+#
+# Usage:
+# ------
+# beman_install_library(
+# TARGETS [ ...]
+# [DEPENDENCIES [ ...]]
+# [NAMESPACE ]
+# [EXPORT_NAME ]
+# [DESTINATION ]
+# )
+#
+# Arguments:
+# ----------
+#
+# name
+# Logical package name (e.g. "beman.utility").
+# Used to derive config file names and cache variable prefixes.
+#
+# TARGETS (required)
+# List of CMake targets to install.
+#
+# DEPENDENCIES (optional)
+# Semicolon-separated list, one dependency per entry.
+# Each entry is a valid find_dependency() argument list.
+# Note: you must use the bracket form for quoting if not only a package name is used!
+# "[===[beman.inplace_vector 1.0.0]===] [===[beman.scope 0.0.1 EXACT]===] fmt"
+#
+# NAMESPACE (optional)
+# Namespace for exported targets.
+# Defaults to "beman::".
+#
+# EXPORT_NAME (optional)
+# Name of the CMake export set.
+# Defaults to "-targets".
+#
+# DESTINATION (optional)
+# The install destination for CXX_MODULES.
+# Defaults to ${CMAKE_INSTALL_LIBDIR}/cmake/${name}/modules.
+#
+# Brief
+# -----
+#
+# This function installs the specified project TARGETS and its FILE_SET
+# HEADERS to the default CMAKE install destination.
+#
+# It also handles the installation of the CMake config package files if
+# needed. If the given targets has a PUBLIC FILE_SET CXX_MODULE, it will also
+# installed to the given DESTINATION
+#
+# Cache variables:
+# ----------------
+#
+# BEMAN_INSTALL_CONFIG_FILE_PACKAGES
+# List of package names for which config files should be installed.
+#
+# _INSTALL_CONFIG_FILE_PACKAGE
+# Per-package override to enable/disable config file installation.
+# is the uppercased package name with dots replaced by underscores.
+#
+# Caveats
+# -------
+#
+# **Only one `PUBLIC FILE_SET CXX_MODULES` is yet supported to install with this
+# function!**
+#
+# **Only header files contained in a `PUBLIC FILE_SET TYPE HEADERS` will be
+# install with this function!**
+
+function(beman_install_library name)
+ # ----------------------------
+ # Argument parsing
+ # ----------------------------
+ set(oneValueArgs NAMESPACE EXPORT_NAME DESTINATION)
+ set(multiValueArgs TARGETS DEPENDENCIES)
+
+ cmake_parse_arguments(
+ BEMAN_INSTALL
+ "${options}"
+ "${oneValueArgs}"
+ "${multiValueArgs}"
+ ${ARGN}
+ )
+
+ if(NOT BEMAN_INSTALL_TARGETS)
+ message(
+ FATAL_ERROR
+ "beman_install_library(${name}): TARGETS must be specified"
+ )
+ endif()
+
+ if(CMAKE_SKIP_INSTALL_RULES)
+ message(
+ WARNING
+ "beman_install_library(${name}): not installing targets '${BEMAN_INSTALL_TARGETS}' due to CMAKE_SKIP_INSTALL_RULES"
+ )
+ return()
+ endif()
+
+ set(_config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${name}")
+
+ # ----------------------------
+ # Defaults
+ # ----------------------------
+ if(NOT BEMAN_INSTALL_NAMESPACE)
+ set(BEMAN_INSTALL_NAMESPACE "beman::")
+ endif()
+
+ if(NOT BEMAN_INSTALL_EXPORT_NAME)
+ set(BEMAN_INSTALL_EXPORT_NAME "${name}-targets")
+ endif()
+
+ if(NOT BEMAN_INSTALL_DESTINATION)
+ set(BEMAN_INSTALL_DESTINATION "${_config_install_dir}/modules")
+ endif()
+
+ string(REPLACE "beman." "" install_component_name "${name}")
+ message(
+ VERBOSE
+ "beman-install-library(${name}): COMPONENT '${install_component_name}'"
+ )
+
+ # --------------------------------------------------
+ # Install each target with all of its file sets
+ # --------------------------------------------------
+ foreach(_tgt IN LISTS BEMAN_INSTALL_TARGETS)
+ if(NOT TARGET "${_tgt}")
+ message(
+ WARNING
+ "beman_install_library(${name}): '${_tgt}' is not a target"
+ )
+ continue()
+ endif()
+
+ # Given foo.bar, the component name is bar
+ string(REPLACE "." ";" name_parts "${_tgt}")
+ # fail if the name doesn't look like foo.bar
+ list(LENGTH name_parts name_parts_length)
+ if(NOT name_parts_length EQUAL 2)
+ message(
+ FATAL_ERROR
+ "beman_install_library(${name}): expects a name of the form 'beman.', got '${_tgt}'"
+ )
+ endif()
+ list(GET name_parts -1 component_name)
+ set_target_properties(
+ "${_tgt}"
+ PROPERTIES EXPORT_NAME "${component_name}"
+ )
+ message(
+ VERBOSE
+ "beman_install_library(${name}): EXPORT_NAME ${component_name} for TARGET '${_tgt}'"
+ )
+
+ # Get the list of interface header sets, exact one expected!
+ set(_install_header_set_args)
+ get_target_property(
+ _available_header_sets
+ ${_tgt}
+ INTERFACE_HEADER_SETS
+ )
+ if(_available_header_sets)
+ message(
+ VERBOSE
+ "beman-install-library(${name}): '${_tgt}' has INTERFACE_HEADER_SETS=${_available_header_sets}"
+ )
+ foreach(_install_header_set IN LISTS _available_header_sets)
+ list(
+ APPEND _install_header_set_args
+ FILE_SET
+ "${_install_header_set}"
+ COMPONENT
+ "${install_component_name}_Development"
+ )
+ endforeach()
+ else()
+ set(_install_header_set_args FILE_SET HEADERS) # Note: empty FILE_SET in this case! CK
+ endif()
+
+ # Detect presence of PUBLIC C++ module file sets. Note: exact one is expected!
+ get_target_property(_module_sets "${_tgt}" INTERFACE_CXX_MODULE_SETS)
+ if(_module_sets)
+ message(
+ VERBOSE
+ "beman-install-library(${name}): '${_tgt}' has INTERFACE_CXX_MODULE_SETS=${_module_sets}"
+ )
+ install(
+ TARGETS "${_tgt}"
+ EXPORT ${BEMAN_INSTALL_EXPORT_NAME}
+ ARCHIVE COMPONENT "${install_component_name}_Development"
+ LIBRARY
+ COMPONENT "${install_component_name}_Runtime"
+ NAMELINK_COMPONENT "${install_component_name}_Development"
+ RUNTIME COMPONENT "${install_component_name}_Runtime"
+ ${_install_header_set_args}
+ FILE_SET ${_module_sets}
+ DESTINATION "${BEMAN_INSTALL_DESTINATION}"
+ COMPONENT "${install_component_name}_Development"
+ # NOTE: There's currently no convention for this location! CK
+ CXX_MODULES_BMI
+ DESTINATION
+ ${_config_install_dir}/bmi-${CMAKE_CXX_COMPILER_ID}_$
+ COMPONENT "${install_component_name}_Development"
+ )
+ else()
+ install(
+ TARGETS "${_tgt}"
+ EXPORT ${BEMAN_INSTALL_EXPORT_NAME}
+ ARCHIVE COMPONENT "${install_component_name}_Development"
+ LIBRARY
+ COMPONENT "${install_component_name}_Runtime"
+ NAMELINK_COMPONENT "${install_component_name}_Development"
+ RUNTIME COMPONENT "${install_component_name}_Runtime"
+ ${_install_header_set_args}
+ )
+ endif()
+ endforeach()
+
+ # --------------------------------------------------
+ # Export targets
+ # --------------------------------------------------
+ # gersemi: off
+ install(
+ EXPORT ${BEMAN_INSTALL_EXPORT_NAME}
+ NAMESPACE ${BEMAN_INSTALL_NAMESPACE}
+ CXX_MODULES_DIRECTORY cxx-modules
+ DESTINATION ${_config_install_dir}
+ COMPONENT "${install_component_name}_Development"
+ )
+ # gersemi: on
+
+ # ----------------------------------------
+ # Config file installation logic
+ #
+ # Precedence (highest to lowest):
+ # 1. Per-package variable _INSTALL_CONFIG_FILE_PACKAGE
+ # 2. Allow-list BEMAN_INSTALL_CONFIG_FILE_PACKAGES (if defined)
+ # 3. Default: ON
+ # ----------------------------------------
+ string(TOUPPER "${name}" _pkg_upper)
+ string(REPLACE "." "_" _pkg_prefix "${_pkg_upper}")
+
+ option(
+ ${_pkg_prefix}_INSTALL_CONFIG_FILE_PACKAGE
+ "Enable creating and installing a CMake config-file package. Default: ON. Values: { ON, OFF }."
+ ON
+ )
+
+ set(_pkg_var "${_pkg_prefix}_INSTALL_CONFIG_FILE_PACKAGE")
+
+ # Default: install config files
+ set(_install_config ON)
+
+ # If the allow-list is defined, only install for packages in the list
+ if(DEFINED BEMAN_INSTALL_CONFIG_FILE_PACKAGES)
+ if(NOT "${name}" IN_LIST BEMAN_INSTALL_CONFIG_FILE_PACKAGES)
+ set(_install_config OFF)
+ endif()
+ endif()
+
+ # Per-package override takes highest precedence
+ if(DEFINED ${_pkg_var})
+ set(_install_config ${${_pkg_var}})
+ endif()
+
+ # ----------------------------------------
+ # expand dependencies
+ # ----------------------------------------
+ set(_beman_find_deps "")
+ foreach(dep IN LISTS BEMAN_INSTALL_DEPENDENCIES)
+ message(
+ VERBOSE
+ "beman-install-library(${name}): Add find_dependency(${dep})"
+ )
+ string(APPEND _beman_find_deps "find_dependency(${dep})\n")
+ endforeach()
+ set(BEMAN_INSTALL_FIND_DEPENDENCIES "${_beman_find_deps}")
+
+ # ----------------------------------------
+ # Generate + install config files
+ # ----------------------------------------
+ if(_install_config)
+ set(BEMAN_INSTALL_BASE_PKG_NAME ${name})
+ configure_package_config_file(
+ "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Config.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/${name}-config.cmake"
+ INSTALL_DESTINATION ${_config_install_dir}
+ )
+
+ write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/${name}-config-version.cmake"
+ VERSION ${PROJECT_VERSION}
+ COMPATIBILITY SameMajorVersion
+ )
+
+ install(
+ FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/${name}-config.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/${name}-config-version.cmake"
+ DESTINATION ${_config_install_dir}
+ COMPONENT "${install_component_name}_Development"
+ )
+ else()
+ message(
+ WARNING
+ "beman-install-library(${name}): Not installing a config package for '${name}'"
+ )
+ endif()
+endfunction()
+
+set(CPACK_GENERATOR TGZ)
+include(CPack)
diff --git a/infra/cmake/gnu-toolchain.cmake b/infra/cmake/gnu-toolchain.cmake
index b6dddf6..d3b9f92 100644
--- a/infra/cmake/gnu-toolchain.cmake
+++ b/infra/cmake/gnu-toolchain.cmake
@@ -36,3 +36,6 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
+
+# Add this dir to the module path so that `find_package(beman-install-library)` works
+list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}")
diff --git a/infra/cmake/llvm-libc++-toolchain.cmake b/infra/cmake/llvm-libc++-toolchain.cmake
new file mode 100644
index 0000000..76264c6
--- /dev/null
+++ b/infra/cmake/llvm-libc++-toolchain.cmake
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: BSL-1.0
+
+# This toolchain file is not meant to be used directly,
+# but to be invoked by CMake preset and GitHub CI.
+#
+# This toolchain file configures for LLVM family of compiler.
+#
+# BEMAN_BUILDSYS_SANITIZER:
+# This optional CMake parameter is not meant for public use and is subject to
+# change.
+# Possible values:
+# - MaxSan: configures clang and clang++ to use all available non-conflicting
+# sanitizers.
+# - TSan: configures clang and clang++ to enable the use of thread sanitizer.
+
+include(${CMAKE_CURRENT_LIST_DIR}/llvm-toolchain.cmake)
+
+if(NOT CMAKE_CXX_FLAGS MATCHES "-stdlib=libc\\+\\+")
+ string(APPEND CMAKE_CXX_FLAGS " -stdlib=libc++")
+endif()
diff --git a/infra/cmake/llvm-toolchain.cmake b/infra/cmake/llvm-toolchain.cmake
index 5f5ee4b..f1623b7 100644
--- a/infra/cmake/llvm-toolchain.cmake
+++ b/infra/cmake/llvm-toolchain.cmake
@@ -36,3 +36,6 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
+
+# Add this dir to the module path so that `find_package(beman-install-library)` works
+list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}")
diff --git a/infra/cmake/msvc-toolchain.cmake b/infra/cmake/msvc-toolchain.cmake
index c2fffa7..bdc24de 100644
--- a/infra/cmake/msvc-toolchain.cmake
+++ b/infra/cmake/msvc-toolchain.cmake
@@ -36,3 +36,6 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${RELEASE_FLAGS}")
set(CMAKE_C_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "${RELEASE_FLAGS}")
+
+# Add this dir to the module path so that `find_package(beman-install-library)` works
+list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}")
diff --git a/infra/cmake/telemetry.sh b/infra/cmake/telemetry.sh
new file mode 100755
index 0000000..307cc94
--- /dev/null
+++ b/infra/cmake/telemetry.sh
@@ -0,0 +1,118 @@
+#!/usr/bin/env bash
+
+set -o nounset
+set -o errexit
+trap 'echo "Aborting due to errexit on line $LINENO. Exit code: $?" >&2' ERR
+set -o errtrace
+set -o pipefail
+IFS=$'\n\t'
+
+###############################################################################
+# Environment
+###############################################################################
+
+# $_ME
+#
+# This program's basename.
+_ME="$(basename "${0}")"
+
+###############################################################################
+# Help
+###############################################################################
+
+# _print_help()
+#
+# Usage:
+# _print_help
+#
+# Print the program help information.
+_print_help() {
+ cat <]
+ ${_ME} -h | --help
+
+Options:
+ -h --help Show this screen.
+
+Environment:
+ Setting DEBUG_TELEMETRY in the environment will enable DEBUG logging
+HEREDOC
+}
+
+###############################################################################
+# Program Functions
+###############################################################################
+_debug_print() {
+ if [[ -n "${DEBUG_TELEMETRY:-}" ]]; then
+ printf "[DEBUG] $(date +'%H:%M:%S'): %s \n" "$1" >&2
+ fi
+}
+
+_check_file_exists() {
+ local file="$1"
+ if [[ ! -f "${file}" ]]; then
+ echo "Error: File not found: ${file}" >&2
+ exit 1 # Exit the entire script with a non-zero status
+ fi
+}
+
+_process_index() {
+ indexFile=${1:-}
+ _check_file_exists "${indexFile}"
+ _debug_print "$(cat "${indexFile}")"
+
+ local buildDir
+ buildDir=$(jq -r '.buildDir' "${1:-}")
+ _debug_print "$(printf "buildDir is |%q|" "${buildDir}")"
+
+ local dataDir
+ dataDir=$(jq -r '.dataDir' "${1:-}")
+ _debug_print "$(printf "dataDir is |%q|" "${dataDir}")"
+
+ local hook
+ hook=$(jq -r '.hook' "${1:-}")
+ _debug_print "$(printf "hook is |%q|" "${hook}")"
+
+ local trace
+ trace=$(jq -r '.trace' "${1:-}")
+ _debug_print "$(printf "trace is |%q|" "${trace}")"
+
+ local outputDir
+ outputDir="${buildDir}/.trace"
+ _debug_print "$(printf "Copy trace to |%q|" "${outputDir}")"
+ mkdir -p "${outputDir}"
+
+ local traceDestFile
+ traceDestFile="${outputDir}/${hook}-$(basename "${trace}")"
+ _debug_print "$(printf "traceDestFile: |%q|" "${traceDestFile}")"
+ cp "${dataDir}/${trace}" "${outputDir}/${hook}-$(basename "${trace}")"
+}
+
+###############################################################################
+# Main
+###############################################################################
+
+# _main()
+#
+# Usage:
+# _main [] []
+#
+# Description:
+# Entry point for the program, handling basic option parsing and dispatching.
+_main() {
+ # Avoid complex option parsing when only one program option is expected.
+ if [[ "${1:-}" =~ ^-h|--help$ ]]
+ then
+ _print_help
+ else
+ _process_index "$@"
+ fi
+}
+
+# Call `_main` after everything has been defined.
+_main "$@"
diff --git a/infra/cmake/use-fetch-content.cmake b/infra/cmake/use-fetch-content.cmake
index 82c5db2..0564513 100644
--- a/infra/cmake/use-fetch-content.cmake
+++ b/infra/cmake/use-fetch-content.cmake
@@ -15,8 +15,7 @@ message(TRACE "BemanExemplar_projectDir=\"${BemanExemplar_projectDir}\"")
message(TRACE "BEMAN_EXEMPLAR_LOCKFILE=\"${BEMAN_EXEMPLAR_LOCKFILE}\"")
file(
- REAL_PATH
- "${BEMAN_EXEMPLAR_LOCKFILE}"
+ REAL_PATH "${BEMAN_EXEMPLAR_LOCKFILE}"
BemanExemplar_lockfile
BASE_DIRECTORY "${BemanExemplar_projectDir}"
EXPAND_TILDE
@@ -38,8 +37,7 @@ function(BemanExemplar_provideDependency method package_name)
# Get the "dependencies" field and store it in BemanExemplar_dependenciesObj
string(
- JSON
- BemanExemplar_dependenciesObj
+ JSON BemanExemplar_dependenciesObj
ERROR_VARIABLE BemanExemplar_error
GET "${BemanExemplar_rootObj}"
"dependencies"
@@ -50,8 +48,7 @@ function(BemanExemplar_provideDependency method package_name)
# Get the length of the libraries array and store it in BemanExemplar_dependenciesObj
string(
- JSON
- BemanExemplar_numDependencies
+ JSON BemanExemplar_numDependencies
ERROR_VARIABLE BemanExemplar_error
LENGTH "${BemanExemplar_dependenciesObj}"
)
@@ -59,6 +56,10 @@ function(BemanExemplar_provideDependency method package_name)
message(FATAL_ERROR "${BemanExemplar_lockfile}: ${BemanExemplar_error}")
endif()
+ if(BemanExemplar_numDependencies EQUAL 0)
+ return()
+ endif()
+
# Loop over each dependency object
math(EXPR BemanExemplar_maxIndex "${BemanExemplar_numDependencies} - 1")
foreach(BemanExemplar_index RANGE "${BemanExemplar_maxIndex}")
@@ -69,8 +70,7 @@ function(BemanExemplar_provideDependency method package_name)
# Get the dependency object at BemanExemplar_index
# and store it in BemanExemplar_depObj
string(
- JSON
- BemanExemplar_depObj
+ JSON BemanExemplar_depObj
ERROR_VARIABLE BemanExemplar_error
GET "${BemanExemplar_dependenciesObj}"
"${BemanExemplar_index}"
@@ -84,8 +84,7 @@ function(BemanExemplar_provideDependency method package_name)
# Get the "name" field and store it in BemanExemplar_name
string(
- JSON
- BemanExemplar_name
+ JSON BemanExemplar_name
ERROR_VARIABLE BemanExemplar_error
GET "${BemanExemplar_depObj}"
"name"
@@ -99,8 +98,7 @@ function(BemanExemplar_provideDependency method package_name)
# Get the "package_name" field and store it in BemanExemplar_pkgName
string(
- JSON
- BemanExemplar_pkgName
+ JSON BemanExemplar_pkgName
ERROR_VARIABLE BemanExemplar_error
GET "${BemanExemplar_depObj}"
"package_name"
@@ -114,8 +112,7 @@ function(BemanExemplar_provideDependency method package_name)
# Get the "git_repository" field and store it in BemanExemplar_repo
string(
- JSON
- BemanExemplar_repo
+ JSON BemanExemplar_repo
ERROR_VARIABLE BemanExemplar_error
GET "${BemanExemplar_depObj}"
"git_repository"
@@ -129,8 +126,7 @@ function(BemanExemplar_provideDependency method package_name)
# Get the "git_tag" field and store it in BemanExemplar_tag
string(
- JSON
- BemanExemplar_tag
+ JSON BemanExemplar_tag
ERROR_VARIABLE BemanExemplar_error
GET "${BemanExemplar_depObj}"
"git_tag"
@@ -145,10 +141,13 @@ function(BemanExemplar_provideDependency method package_name)
if(method STREQUAL "FIND_PACKAGE")
if(package_name STREQUAL BemanExemplar_pkgName)
string(
- APPEND
- BemanExemplar_debug
+ APPEND BemanExemplar_debug
"Redirecting find_package calls for ${BemanExemplar_pkgName} "
- "to FetchContent logic fetching ${BemanExemplar_repo} at "
+ "to FetchContent logic.\n"
+ )
+ string(
+ APPEND BemanExemplar_debug
+ "Fetching ${BemanExemplar_repo} at "
"${BemanExemplar_tag} according to ${BemanExemplar_lockfile}."
)
message(DEBUG "${BemanExemplar_debug}")
@@ -158,9 +157,63 @@ function(BemanExemplar_provideDependency method package_name)
GIT_TAG "${BemanExemplar_tag}"
EXCLUDE_FROM_ALL
)
- set(INSTALL_GTEST OFF) # Disable GoogleTest installation
+
+ # Apply per-dependency cmake_args from the lockfile
+ string(
+ JSON BemanExemplar_cmakeArgs
+ ERROR_VARIABLE BemanExemplar_cmakeArgsError
+ GET "${BemanExemplar_depObj}"
+ "cmake_args"
+ )
+ if(NOT BemanExemplar_cmakeArgsError)
+ string(
+ JSON BemanExemplar_numCmakeArgs
+ LENGTH "${BemanExemplar_cmakeArgs}"
+ )
+ if(BemanExemplar_numCmakeArgs GREATER 0)
+ math(
+ EXPR
+ BemanExemplar_maxArgIndex
+ "${BemanExemplar_numCmakeArgs} - 1"
+ )
+ foreach(
+ BemanExemplar_argIndex
+ RANGE "${BemanExemplar_maxArgIndex}"
+ )
+ string(
+ JSON BemanExemplar_argKey
+ MEMBER "${BemanExemplar_cmakeArgs}"
+ "${BemanExemplar_argIndex}"
+ )
+ string(
+ JSON BemanExemplar_argValue
+ GET "${BemanExemplar_cmakeArgs}"
+ "${BemanExemplar_argKey}"
+ )
+ message(
+ DEBUG
+ "Setting ${BemanExemplar_argKey}=${BemanExemplar_argValue} for ${BemanExemplar_name}"
+ )
+ set("${BemanExemplar_argKey}"
+ "${BemanExemplar_argValue}"
+ )
+ endforeach()
+ endif()
+ endif()
+
FetchContent_MakeAvailable("${BemanExemplar_name}")
+ # Catch2's CTest integration module isn't on CMAKE_MODULE_PATH
+ # when brought in via FetchContent. Add it so that
+ # `include(Catch)` works.
+ if(BemanExemplar_pkgName STREQUAL "Catch2")
+ list(
+ APPEND CMAKE_MODULE_PATH
+ "${${BemanExemplar_name}_SOURCE_DIR}/extras"
+ )
+ set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" PARENT_SCOPE)
+ endif()
+
# Important! _FOUND tells CMake that `find_package` is
# not needed for this package anymore
set("${BemanExemplar_pkgName}_FOUND" TRUE PARENT_SCOPE)
@@ -173,3 +226,6 @@ cmake_language(
SET_DEPENDENCY_PROVIDER BemanExemplar_provideDependency
SUPPORTED_METHODS FIND_PACKAGE
)
+
+# Add this dir to the module path so that `find_package(beman-install-library)` works
+list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}")
diff --git a/infra/containers/Dockerfile b/infra/containers/Dockerfile
deleted file mode 100644
index f5f5f9d..0000000
--- a/infra/containers/Dockerfile
+++ /dev/null
@@ -1,37 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-ARG base_image=mcr.microsoft.com/devcontainers/cpp:1-ubuntu-24.04
-FROM ${base_image}
-
-# Create the vscode user
-RUN bash </dev/null; then
- apt-get update && apt-get install -y sudo adduser
- useradd -ms /bin/bash -p "" vscode && usermod -aG sudo vscode
- fi
-EOF
-
-USER vscode
-WORKDIR /tmp
-
-COPY install_sys.sh .
-RUN bash install_sys.sh
-
-# Newer gcc/ clang is needed to avoid ASAN Stalling, which is turned on by default across beman projects.
-# See: https://github.com/google/sanitizers/issues/1614
-# Minimal version: clang-18.1.3, gcc-13.2
-ARG compiler_kind=gcc
-ARG compiler_version=14
-
-COPY install_compiler.sh .
-RUN bash install_compiler.sh ${compiler_kind} ${compiler_version}
-
-# Common dependency: google-test
-RUN sudo apt-get install -y libgtest-dev
-
-# Pre-commit is beman library's standard linting tool
-RUN sudo apt-get install -y pipx
-RUN pipx install pre-commit
-ENV PATH="/home/vscode/.local/bin:${PATH}"
-
-ENTRYPOINT ["/usr/bin/bash"]
diff --git a/infra/containers/README.md b/infra/containers/README.md
deleted file mode 100644
index 83b357d..0000000
--- a/infra/containers/README.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Containers
-
-
-
-This folder contains the infrastructure for Beman project's
-generic container images. You can checkout available images in beman's
-[GitHub Packages page](https://github.com/orgs/bemanproject/packages).
-
-These images includes:
-
-- The latest CMake from kitware's apt repository
-- Latest compiler based on build args (gcc or clang) installed from the universe repository
-- [pre-commit](https://pre-commit.com/), the standard linter manager across Beman
-
-## Devcontainer
-
-The image is build on top of GitHub's
-[C++ devcontainer image](https://github.com/devcontainers/images/tree/main/src/cpp)
-for Ubuntu 24.04.
-
-### Example devcontainer setup
-
-```json
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-{
- "name": "Beman Generic Devcontainer",
- "image": "ghcr.io/bemanproject/devcontainers-gcc:14",
- "postCreateCommand": "pre-commit",
- "customizations": {
- "vscode": {
- "extensions": [
- "ms-vscode.cpptools",
- "ms-vscode.cmake-tools"
- ]
- }
- }
-}
-```
-
-### Building your own image
-
-You can build your own Beman devcontainer image with:
-
-```bash
-docker build devcontainer/
-```
diff --git a/infra/containers/install_compiler.sh b/infra/containers/install_compiler.sh
deleted file mode 100644
index bef0e1c..0000000
--- a/infra/containers/install_compiler.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/bash
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-set -e
-set +x
-TOOL=$1
-VERSION=$2
-
-echo "Install ${TOOL} at: ${VERSION}"
-
-shopt -s nocasematch
-if [ "$TOOL" = "gcc" ]; then
- sudo apt-get remove -y gcc-"$VERSION" g++-"$VERSION" gcc g++
- sudo apt-get install -y gcc-"$VERSION" g++-"$VERSION" lcov
-
- sudo rm -f /usr/bin/gcc
- sudo rm -f /usr/bin/g++
- sudo rm -f /usr/bin/gcov
-
- sudo ln -s "$(which gcc-"$VERSION")" /usr/bin/gcc
- sudo ln -s "$(which g++-"$VERSION")" /usr/bin/g++
- sudo ln -s "$(which gcov-"$VERSION")" /usr/bin/gcov
-
- gcc --version
-else
- sudo apt-get install -y lsb-release wget software-properties-common gnupg
- wget https://apt.llvm.org/llvm.sh
-
- sudo bash llvm.sh "${VERSION}"
- sudo apt-get install -y libc++-"$VERSION"-dev clang-tools-"$VERSION" lcov
-
- sudo rm -f /usr/bin/clang
- sudo rm -f /usr/bin/clang++
-
- sudo ln -s "$(which clang-"$VERSION")" /usr/bin/clang
- sudo ln -s "$(which clang++-"$VERSION")" /usr/bin/clang++
-
- clang --version
-fi
diff --git a/infra/containers/install_sys.sh b/infra/containers/install_sys.sh
deleted file mode 100644
index 0e31aca..0000000
--- a/infra/containers/install_sys.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-# Install Basic utilities
-sudo apt-get install -y ca-certificates gpg wget git curl
-
-# Install Latest CMake
-wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
-echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ noble main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null
-sudo apt-get update && sudo apt-get install -y cmake
-
-# Install Ninja
-sudo apt-get install -y ninja-build
diff --git a/infra/tools/beman-submodule/README.md b/infra/tools/beman-submodule/README.md
deleted file mode 100644
index 36883ad..0000000
--- a/infra/tools/beman-submodule/README.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# beman-submodule
-
-
-
-## What is this script?
-
-`beman-submodule` provides some of the features of `git submodule`, adding child git
-repositories to a parent git repository, but unlike with `git submodule`, the entire child
-repo is directly checked in, so only maintainers, not users, need to run this script. The
-command line interface mimics `git submodule`'s.
-
-## How do I add a beman submodule to my repository?
-
-The first beman submodule you should add is this repository, `infra/`, which you can
-bootstrap by running:
-
-
-```sh
-curl -s https://raw.githubusercontent.com/bemanproject/infra/refs/heads/main/tools/beman-submodule/beman-submodule | python3 - add https://github.com/bemanproject/infra.git
-```
-
-Once that's added, you can run the script from `infra/tools/beman-submodule/beman-submodule`.
-
-## How do I update a beman submodule to the latest trunk?
-
-You can run `beman-submodule update --remote` to update all beman submodule to latest
-trunk, or e.g. `beman-submodule update --remote infra` to update only a specific one.
-
-## How does it work under the hood?
-
-Along with the files from the child repository, it creates a dotfile called
-`.beman_submodule`, which looks like this:
-
-```ini
-[beman_submodule]
-remote=https://github.com/bemanproject/infra.git
-commit_hash=9b88395a86c4290794e503e94d8213b6c442ae77
-```
-
-## How do I update a beman submodule to a specific commit or change the remote URL?
-
-You can edit the corresponding lines in the `.beman_submodule` file and run
-`beman-submodule update` to update the state of the beman submodule to the new
-`.beman_submodule` settings.
-
-## How can I make CI ensure that my beman submodules are in a valid state?
-
-Add this job to your CI workflow:
-
-```yaml
- beman-submodule-test:
- runs-on: ubuntu-latest
- name: "Check beman submodules for consistency"
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- - name: beman submodule consistency check
- run: |
- (set -o pipefail; ./infra/tools/beman-submodule/beman-submodule status | grep -qvF '+')
-```
-
-This will fail if the contents of any beman submodule don't match what's specified in the
-`.beman_submodule` file.
diff --git a/infra/tools/beman-submodule/beman-submodule b/infra/tools/beman-submodule/beman-submodule
deleted file mode 100755
index 2007fc4..0000000
--- a/infra/tools/beman-submodule/beman-submodule
+++ /dev/null
@@ -1,212 +0,0 @@
-#!/usr/bin/env python3
-
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-import argparse
-import configparser
-import filecmp
-import os
-import pathlib
-import shutil
-import subprocess
-import sys
-import tempfile
-
-def directory_compare(dir1, dir2, ignore):
- compared = filecmp.dircmp(dir1, dir2, ignore=ignore)
- if compared.left_only or compared.right_only or compared.diff_files:
- return False
- for common_dir in compared.common_dirs:
- path1 = os.path.join(dir1, common_dir)
- path2 = os.path.join(dir2, common_dir)
- if not directory_compare(path1, path2, ignore):
- return False
- return True
-
-class BemanSubmodule:
- def __init__(self, dirpath, remote, commit_hash):
- self.dirpath = dirpath
- self.remote = remote
- self.commit_hash = commit_hash
-
-def parse_beman_submodule_file(path):
- config = configparser.ConfigParser()
- read_result = config.read(path)
- def fail():
- raise Exception(f'Failed to parse {path} as a .beman_submodule file')
- if not read_result:
- fail()
- if not 'beman_submodule' in config:
- fail()
- if not 'remote' in config['beman_submodule']:
- fail()
- if not 'commit_hash' in config['beman_submodule']:
- fail()
- return BemanSubmodule(
- str(pathlib.Path(path).resolve().parent),
- config['beman_submodule']['remote'], config['beman_submodule']['commit_hash'])
-
-def get_beman_submodule(dir):
- beman_submodule_filepath = os.path.join(dir, '.beman_submodule')
- if os.path.isfile(beman_submodule_filepath):
- return parse_beman_submodule_file(beman_submodule_filepath)
- else:
- return None
-
-def find_beman_submodules_in(dir):
- assert os.path.isdir(dir)
- result = []
- for dirpath, _, filenames in os.walk(dir):
- if '.beman_submodule' in filenames:
- result.append(parse_beman_submodule_file(os.path.join(dirpath, '.beman_submodule')))
- return sorted(result, key=lambda module: module.dirpath)
-
-def cwd_git_repository_path():
- process = subprocess.run(
- ['git', 'rev-parse', '--show-toplevel'], capture_output=True, text=True,
- check=False)
- if process.returncode == 0:
- return process.stdout.strip()
- elif "fatal: not a git repository" in process.stderr:
- return None
- else:
- raise Exception("git rev-parse --show-toplevel failed")
-
-def clone_beman_submodule_into_tmpdir(beman_submodule, remote):
- tmpdir = tempfile.TemporaryDirectory()
- subprocess.run(
- ['git', 'clone', beman_submodule.remote, tmpdir.name], capture_output=True,
- check=True)
- if not remote:
- subprocess.run(
- ['git', '-C', tmpdir.name, 'reset', '--hard', beman_submodule.commit_hash],
- capture_output=True, check=True)
- return tmpdir
-
-def beman_submodule_status(beman_submodule):
- tmpdir = clone_beman_submodule_into_tmpdir(beman_submodule, False)
- if directory_compare(tmpdir.name, beman_submodule.dirpath, ['.beman_submodule', '.git']):
- status_character=' '
- else:
- status_character='+'
- parent_repo_path = cwd_git_repository_path()
- if not parent_repo_path:
- raise Exception('this is not a git repository')
- relpath = pathlib.Path(
- beman_submodule.dirpath).relative_to(pathlib.Path(parent_repo_path))
- return status_character + ' ' + beman_submodule.commit_hash + ' ' + str(relpath)
-
-def beman_submodule_update(beman_submodule, remote):
- tmpdir = clone_beman_submodule_into_tmpdir(beman_submodule, remote)
- shutil.rmtree(beman_submodule.dirpath)
- with open(os.path.join(tmpdir.name, '.beman_submodule'), 'w') as f:
- f.write('[beman_submodule]\n')
- f.write(f'remote={beman_submodule.remote}\n')
- f.write(f'commit_hash={beman_submodule.commit_hash}\n')
- shutil.rmtree(os.path.join(tmpdir.name, '.git'))
- shutil.copytree(tmpdir.name, beman_submodule.dirpath)
-
-def update_command(remote, path):
- if not path:
- parent_repo_path = cwd_git_repository_path()
- if not parent_repo_path:
- raise Exception('this is not a git repository')
- beman_submodules = find_beman_submodules_in(parent_repo_path)
- else:
- beman_submodule = get_beman_submodule(path)
- if not beman_submodule:
- raise Exception(f'{path} is not a beman_submodule')
- beman_submodules = [beman_submodule]
- for beman_submodule in beman_submodules:
- beman_submodule_update(beman_submodule, remote)
-
-def add_command(repository, path):
- tmpdir = tempfile.TemporaryDirectory()
- subprocess.run(
- ['git', 'clone', repository], capture_output=True, check=True, cwd=tmpdir.name)
- repository_name = os.listdir(tmpdir.name)[0]
- if not path:
- path = repository_name
- if os.path.exists(path):
- raise Exception(f'{path} exists')
- os.makedirs(path)
- tmpdir_repo = os.path.join(tmpdir.name, repository_name)
- sha_process = subprocess.run(
- ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True,
- cwd=tmpdir_repo)
- with open(os.path.join(tmpdir_repo, '.beman_submodule'), 'w') as f:
- f.write('[beman_submodule]\n')
- f.write(f'remote={repository}\n')
- f.write(f'commit_hash={sha_process.stdout.strip()}\n')
- shutil.rmtree(os.path.join(tmpdir_repo, '.git'))
- shutil.copytree(tmpdir_repo, path, dirs_exist_ok=True)
-
-def status_command(paths):
- if not paths:
- parent_repo_path = cwd_git_repository_path()
- if not parent_repo_path:
- raise Exception('this is not a git repository')
- beman_submodules = find_beman_submodules_in(parent_repo_path)
- else:
- beman_submodules = []
- for path in paths:
- beman_submodule = get_beman_submodule(path)
- if not beman_submodule:
- raise Exception(f'{path} is not a beman_submodule')
- beman_submodules.append(beman_submodule)
- for beman_submodule in beman_submodules:
- print(beman_submodule_status(beman_submodule))
-
-def get_parser():
- parser = argparse.ArgumentParser(description='Beman pseudo-submodule tool')
- subparsers = parser.add_subparsers(dest='command', help='available commands')
- parser_update = subparsers.add_parser('update', help='update beman_submodules')
- parser_update.add_argument(
- '--remote', action='store_true',
- help='update a beman_submodule to its latest from upstream')
- parser_update.add_argument(
- 'beman_submodule_path', nargs='?',
- help='relative path to the beman_submodule to update')
- parser_add = subparsers.add_parser('add', help='add a new beman_submodule')
- parser_add.add_argument('repository', help='git repository to add')
- parser_add.add_argument(
- 'path', nargs='?', help='path where the repository will be added')
- parser_status = subparsers.add_parser(
- 'status', help='show the status of beman_submodules')
- parser_status.add_argument('paths', nargs='*')
- return parser
-
-def parse_args(args):
- return get_parser().parse_args(args);
-
-def usage():
- return get_parser().format_help()
-
-def run_command(args):
- if args.command == 'update':
- update_command(args.remote, args.beman_submodule_path)
- elif args.command == 'add':
- add_command(args.repository, args.path)
- elif args.command == 'status':
- status_command(args.paths)
- else:
- raise Exception(usage())
-
-def check_for_git(path):
- env = os.environ.copy()
- if path is not None:
- env["PATH"] = path
- return shutil.which("git", path=env.get("PATH")) is not None
-
-def main():
- try:
- if not check_for_git(None):
- raise Exception('git not found in PATH')
- args = parse_args(sys.argv[1:])
- run_command(args)
- except Exception as e:
- print("Error:", e, file=sys.stderr)
- sys.exit(1)
-
-if __name__ == '__main__':
- main()
diff --git a/infra/tools/beman-submodule/test/test_beman_submodule.py b/infra/tools/beman-submodule/test/test_beman_submodule.py
deleted file mode 100644
index 47e2303..0000000
--- a/infra/tools/beman-submodule/test/test_beman_submodule.py
+++ /dev/null
@@ -1,359 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-import os
-import pathlib
-import pytest
-import shutil
-import stat
-import subprocess
-import tempfile
-
-# https://stackoverflow.com/a/19011259
-import types
-import importlib.machinery
-loader = importlib.machinery.SourceFileLoader(
- 'beman_submodule',
- os.path.join(os.path.dirname(os.path.realpath(__file__)), '../beman-submodule'))
-beman_submodule = types.ModuleType(loader.name)
-loader.exec_module(beman_submodule)
-
-def create_test_git_repository():
- tmpdir = tempfile.TemporaryDirectory()
- subprocess.run(['git', 'init'], check=True, cwd=tmpdir.name, capture_output=True)
- def make_commit(a_txt_contents):
- with open(os.path.join(tmpdir.name, 'a.txt'), 'w') as f:
- f.write(a_txt_contents)
- subprocess.run(
- ['git', 'add', 'a.txt'], check=True, cwd=tmpdir.name, capture_output=True)
- subprocess.run(
- ['git', '-c', 'user.name=test', '-c', 'user.email=test@example.com', 'commit',
- '--author="test "', '-m', 'test'],
- check=True, cwd=tmpdir.name, capture_output=True)
- make_commit('A')
- make_commit('a')
- return tmpdir
-
-def test_directory_compare():
- def create_dir_structure(dir_path):
- bar_path = os.path.join(dir_path, 'bar')
- os.makedirs(bar_path)
-
- with open(os.path.join(dir_path, 'foo.txt'), 'w') as f:
- f.write('foo')
- with open(os.path.join(bar_path, 'baz.txt'), 'w') as f:
- f.write('baz')
-
- with tempfile.TemporaryDirectory() as dir_a, \
- tempfile.TemporaryDirectory() as dir_b:
-
- create_dir_structure(dir_a)
- create_dir_structure(dir_b)
-
- assert beman_submodule.directory_compare(dir_a, dir_b, [])
-
- with open(os.path.join(os.path.join(dir_a, 'bar'), 'quux.txt'), 'w') as f:
- f.write('quux')
-
- assert not beman_submodule.directory_compare(dir_a, dir_b, [])
- assert beman_submodule.directory_compare(dir_a, dir_b, ['quux.txt'])
-
-def test_parse_beman_submodule_file():
- def valid_file():
- tmpfile = tempfile.NamedTemporaryFile()
- tmpfile.write('[beman_submodule]\n'.encode('utf-8'))
- tmpfile.write(
- 'remote=git@github.com:bemanproject/infra.git\n'.encode('utf-8'))
- tmpfile.write(
- 'commit_hash=9b88395a86c4290794e503e94d8213b6c442ae77\n'.encode('utf-8'))
- tmpfile.flush()
- module = beman_submodule.parse_beman_submodule_file(tmpfile.name)
- assert module.dirpath == str(pathlib.Path(tmpfile.name).resolve().parent)
- assert module.remote == 'git@github.com:bemanproject/infra.git'
- assert module.commit_hash == '9b88395a86c4290794e503e94d8213b6c442ae77'
- valid_file()
- def invalid_file_missing_remote():
- threw = False
- try:
- tmpfile = tempfile.NamedTemporaryFile()
- tmpfile.write('[beman_submodule]\n'.encode('utf-8'))
- tmpfile.write(
- 'commit_hash=9b88395a86c4290794e503e94d8213b6c442ae77\n'.encode('utf-8'))
- tmpfile.flush()
- beman_submodule.parse_beman_submodule_file(tmpfile.name)
- except:
- threw = True
- assert threw
- invalid_file_missing_remote()
- def invalid_file_missing_commit_hash():
- threw = False
- try:
- tmpfile = tempfile.NamedTemporaryFile()
- tmpfile.write('[beman_submodule]\n'.encode('utf-8'))
- tmpfile.write(
- 'remote=git@github.com:bemanproject/infra.git\n'.encode('utf-8'))
- tmpfile.flush()
- beman_submodule.parse_beman_submodule_file(tmpfile.name)
- except:
- threw = True
- assert threw
- invalid_file_missing_commit_hash()
- def invalid_file_wrong_section():
- threw = False
- try:
- tmpfile = tempfile.NamedTemporaryFile()
- tmpfile.write('[invalid]\n'.encode('utf-8'))
- tmpfile.write(
- 'remote=git@github.com:bemanproject/infra.git\n'.encode('utf-8'))
- tmpfile.write(
- 'commit_hash=9b88395a86c4290794e503e94d8213b6c442ae77\n'.encode('utf-8'))
- tmpfile.flush()
- beman_submodule.parse_beman_submodule_file(tmpfile.name)
- except:
- threw = True
- assert threw
- invalid_file_wrong_section()
-
-def test_get_beman_submodule():
- tmpdir = create_test_git_repository()
- tmpdir2 = create_test_git_repository()
- original_cwd = os.getcwd()
- os.chdir(tmpdir2.name)
- beman_submodule.add_command(tmpdir.name, 'foo')
- assert beman_submodule.get_beman_submodule('foo')
- os.remove('foo/.beman_submodule')
- assert not beman_submodule.get_beman_submodule('foo')
- os.chdir(original_cwd)
-
-def test_find_beman_submodules_in():
- tmpdir = create_test_git_repository()
- tmpdir2 = create_test_git_repository()
- original_cwd = os.getcwd()
- os.chdir(tmpdir2.name)
- beman_submodule.add_command(tmpdir.name, 'foo')
- beman_submodule.add_command(tmpdir.name, 'bar')
- beman_submodules = beman_submodule.find_beman_submodules_in(tmpdir2.name)
- sha_process = subprocess.run(
- ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True,
- cwd=tmpdir.name)
- sha = sha_process.stdout.strip()
- assert beman_submodules[0].dirpath == os.path.join(tmpdir2.name, 'bar')
- assert beman_submodules[0].remote == tmpdir.name
- assert beman_submodules[0].commit_hash == sha
- assert beman_submodules[1].dirpath == os.path.join(tmpdir2.name, 'foo')
- assert beman_submodules[1].remote == tmpdir.name
- assert beman_submodules[1].commit_hash == sha
- os.chdir(original_cwd)
-
-def test_cwd_git_repository_path():
- original_cwd = os.getcwd()
- tmpdir = tempfile.TemporaryDirectory()
- os.chdir(tmpdir.name)
- assert not beman_submodule.cwd_git_repository_path()
- subprocess.run(['git', 'init'])
- assert beman_submodule.cwd_git_repository_path() == tmpdir.name
- os.chdir(original_cwd)
-
-def test_clone_beman_submodule_into_tmpdir():
- tmpdir = create_test_git_repository()
- tmpdir2 = create_test_git_repository()
- original_cwd = os.getcwd()
- os.chdir(tmpdir2.name)
- sha_process = subprocess.run(
- ['git', 'rev-parse', 'HEAD^'], capture_output=True, check=True, text=True,
- cwd=tmpdir.name)
- sha = sha_process.stdout.strip()
- beman_submodule.add_command(tmpdir.name, 'foo')
- module = beman_submodule.get_beman_submodule(os.path.join(tmpdir2.name, 'foo'))
- module.commit_hash = sha
- tmpdir3 = beman_submodule.clone_beman_submodule_into_tmpdir(module, False)
- assert not beman_submodule.directory_compare(tmpdir.name, tmpdir3.name, ['.git'])
- tmpdir4 = beman_submodule.clone_beman_submodule_into_tmpdir(module, True)
- assert beman_submodule.directory_compare(tmpdir.name, tmpdir4.name, ['.git'])
- subprocess.run(
- ['git', 'reset', '--hard', sha], capture_output=True, check=True,
- cwd=tmpdir.name)
- assert beman_submodule.directory_compare(tmpdir.name, tmpdir3.name, ['.git'])
- os.chdir(original_cwd)
-
-def test_beman_submodule_status():
- tmpdir = create_test_git_repository()
- tmpdir2 = create_test_git_repository()
- original_cwd = os.getcwd()
- os.chdir(tmpdir2.name)
- beman_submodule.add_command(tmpdir.name, 'foo')
- sha_process = subprocess.run(
- ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True,
- cwd=tmpdir.name)
- sha = sha_process.stdout.strip()
- assert ' ' + sha + ' foo' == beman_submodule.beman_submodule_status(
- beman_submodule.get_beman_submodule(os.path.join(tmpdir2.name, 'foo')))
- with open(os.path.join(os.path.join(tmpdir2.name, 'foo'), 'a.txt'), 'w') as f:
- f.write('b')
- assert '+ ' + sha + ' foo' == beman_submodule.beman_submodule_status(
- beman_submodule.get_beman_submodule(os.path.join(tmpdir2.name, 'foo')))
- os.chdir(original_cwd)
-
-def test_update_command_no_paths():
- tmpdir = create_test_git_repository()
- tmpdir2 = create_test_git_repository()
- original_cwd = os.getcwd()
- os.chdir(tmpdir2.name)
- beman_submodule.add_command(tmpdir.name, 'foo')
- beman_submodule.add_command(tmpdir.name, 'bar')
- sha_process = subprocess.run(
- ['git', 'rev-parse', 'HEAD^'], capture_output=True, check=True, text=True,
- cwd=tmpdir.name)
- sha = sha_process.stdout.strip()
- subprocess.run(
- ['git', 'reset', '--hard', sha], capture_output=True, check=True,
- cwd=tmpdir.name)
- with open(os.path.join(os.path.join(tmpdir2.name, 'foo'), '.beman_submodule'), 'w') as f:
- f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n')
- with open(os.path.join(os.path.join(tmpdir2.name, 'bar'), '.beman_submodule'), 'w') as f:
- f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n')
- beman_submodule.update_command(tmpdir.name, None)
- assert beman_submodule.directory_compare(
- tmpdir.name, os.path.join(tmpdir2.name, 'foo'), ['.git', '.beman_submodule'])
- assert beman_submodule.directory_compare(
- tmpdir.name, os.path.join(tmpdir2.name, 'bar'), ['.git', '.beman_submodule'])
- os.chdir(original_cwd)
-
-def test_update_command_with_path():
- tmpdir = create_test_git_repository()
- tmpdir2 = create_test_git_repository()
- tmpdir_copy1 = tempfile.TemporaryDirectory()
- shutil.copytree(tmpdir.name, tmpdir_copy1.name, dirs_exist_ok=True)
- original_cwd = os.getcwd()
- os.chdir(tmpdir2.name)
- beman_submodule.add_command(tmpdir.name, 'foo')
- beman_submodule.add_command(tmpdir.name, 'bar')
- sha_process = subprocess.run(
- ['git', 'rev-parse', 'HEAD^'], capture_output=True, check=True, text=True,
- cwd=tmpdir.name)
- sha = sha_process.stdout.strip()
- subprocess.run(
- ['git', 'reset', '--hard', sha], capture_output=True, check=True,
- cwd=tmpdir.name)
- with open(os.path.join(os.path.join(tmpdir2.name, 'foo'), '.beman_submodule'), 'w') as f:
- f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n')
- with open(os.path.join(os.path.join(tmpdir2.name, 'bar'), '.beman_submodule'), 'w') as f:
- f.write(f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n')
- beman_submodule.update_command(tmpdir.name, 'foo')
- assert beman_submodule.directory_compare(
- tmpdir.name, os.path.join(tmpdir2.name, 'foo'), ['.git', '.beman_submodule'])
- assert beman_submodule.directory_compare(
- tmpdir_copy1.name, os.path.join(tmpdir2.name, 'bar'), ['.git', '.beman_submodule'])
- os.chdir(original_cwd)
-
-def test_add_command():
- tmpdir = create_test_git_repository()
- tmpdir2 = create_test_git_repository()
- original_cwd = os.getcwd()
- os.chdir(tmpdir2.name)
- beman_submodule.add_command(tmpdir.name, 'foo')
- sha_process = subprocess.run(
- ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True,
- cwd=tmpdir.name)
- sha = sha_process.stdout.strip()
- assert beman_submodule.directory_compare(
- tmpdir.name, os.path.join(tmpdir2.name, 'foo'), ['.git', '.beman_submodule'])
- with open(os.path.join(os.path.join(tmpdir2.name, 'foo'), '.beman_submodule'), 'r') as f:
- assert f.read() == f'[beman_submodule]\nremote={tmpdir.name}\ncommit_hash={sha}\n'
- os.chdir(original_cwd)
-
-def test_status_command_no_paths(capsys):
- tmpdir = create_test_git_repository()
- tmpdir2 = create_test_git_repository()
- original_cwd = os.getcwd()
- os.chdir(tmpdir2.name)
- beman_submodule.add_command(tmpdir.name, 'foo')
- beman_submodule.add_command(tmpdir.name, 'bar')
- sha_process = subprocess.run(
- ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True,
- cwd=tmpdir.name)
- with open(os.path.join(os.path.join(tmpdir2.name, 'bar'), 'a.txt'), 'w') as f:
- f.write('b')
- beman_submodule.status_command([])
- sha = sha_process.stdout.strip()
- assert capsys.readouterr().out == '+ ' + sha + ' bar\n' + ' ' + sha + ' foo\n'
- os.chdir(original_cwd)
-
-def test_status_command_with_path(capsys):
- tmpdir = create_test_git_repository()
- tmpdir2 = create_test_git_repository()
- original_cwd = os.getcwd()
- os.chdir(tmpdir2.name)
- beman_submodule.add_command(tmpdir.name, 'foo')
- beman_submodule.add_command(tmpdir.name, 'bar')
- sha_process = subprocess.run(
- ['git', 'rev-parse', 'HEAD'], capture_output=True, check=True, text=True,
- cwd=tmpdir.name)
- with open(os.path.join(os.path.join(tmpdir2.name, 'bar'), 'a.txt'), 'w') as f:
- f.write('b')
- beman_submodule.status_command(['bar'])
- sha = sha_process.stdout.strip()
- assert capsys.readouterr().out == '+ ' + sha + ' bar\n'
- os.chdir(original_cwd)
-
-def test_check_for_git():
- tmpdir = tempfile.TemporaryDirectory()
- assert not beman_submodule.check_for_git(tmpdir.name)
- fake_git_path = os.path.join(tmpdir.name, 'git')
- with open(fake_git_path, 'w'):
- pass
- os.chmod(fake_git_path, stat.S_IRWXU)
- assert beman_submodule.check_for_git(tmpdir.name)
-
-def test_parse_args():
- def plain_update():
- args = beman_submodule.parse_args(['update'])
- assert args.command == 'update'
- assert not args.remote
- assert not args.beman_submodule_path
- plain_update()
- def update_remote():
- args = beman_submodule.parse_args(['update', '--remote'])
- assert args.command == 'update'
- assert args.remote
- assert not args.beman_submodule_path
- update_remote()
- def update_path():
- args = beman_submodule.parse_args(['update', 'infra/'])
- assert args.command == 'update'
- assert not args.remote
- assert args.beman_submodule_path == 'infra/'
- update_path()
- def update_path_remote():
- args = beman_submodule.parse_args(['update', '--remote', 'infra/'])
- assert args.command == 'update'
- assert args.remote
- assert args.beman_submodule_path == 'infra/'
- update_path_remote()
- def plain_add():
- args = beman_submodule.parse_args(['add', 'git@github.com:bemanproject/infra.git'])
- assert args.command == 'add'
- assert args.repository == 'git@github.com:bemanproject/infra.git'
- assert not args.path
- plain_add()
- def add_path():
- args = beman_submodule.parse_args(
- ['add', 'git@github.com:bemanproject/infra.git', 'infra/'])
- assert args.command == 'add'
- assert args.repository == 'git@github.com:bemanproject/infra.git'
- assert args.path == 'infra/'
- add_path()
- def plain_status():
- args = beman_submodule.parse_args(['status'])
- assert args.command == 'status'
- assert args.paths == []
- plain_status()
- def status_one_module():
- args = beman_submodule.parse_args(['status', 'infra/'])
- assert args.command == 'status'
- assert args.paths == ['infra/']
- status_one_module()
- def status_multiple_modules():
- args = beman_submodule.parse_args(['status', 'infra/', 'foobar/'])
- assert args.command == 'status'
- assert args.paths == ['infra/', 'foobar/']
- status_multiple_modules()
diff --git a/lockfile.json b/lockfile.json
index 3a69ab1..787b905 100644
--- a/lockfile.json
+++ b/lockfile.json
@@ -4,7 +4,10 @@
"name": "googletest",
"package_name": "GTest",
"git_repository": "https://github.com/google/googletest.git",
- "git_tag": "6910c9d9165801d8827d628cb72eb7ea9dd538c5"
+ "git_tag": "6910c9d9165801d8827d628cb72eb7ea9dd538c5",
+ "cmake_args": {
+ "INSTALL_GTEST": "OFF"
+ }
}
]
}
diff --git a/src/beman/copyable_function/CMakeLists.txt b/src/beman/copyable_function/CMakeLists.txt
deleted file mode 100644
index aa5dd2a..0000000
--- a/src/beman/copyable_function/CMakeLists.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-add_library(beman.copyable_function)
-add_library(beman::copyable_function ALIAS beman.copyable_function)
-
-target_sources(beman.copyable_function PRIVATE copyable_function.cpp)
-
-target_sources(
- beman.copyable_function
- PUBLIC
- FILE_SET HEADERS
- BASE_DIRS ${PROJECT_SOURCE_DIR}/include
- FILES
- ${PROJECT_SOURCE_DIR}/include/beman/copyable_function/copyable_function.hpp
-)
-
-set_target_properties(
- beman.copyable_function
- PROPERTIES VERIFY_INTERFACE_HEADER_SETS ON EXPORT_NAME copyable_function
-)
-
-install(
- TARGETS beman.copyable_function
- EXPORT beman.copyable_function
- DESTINATION
- ${CMAKE_INSTALL_LIBDIR}$<$:/debug>
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}$<$:/debug>
- FILE_SET HEADERS DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
-)
-
-if(BEMAN_COPYABLE_FUNCTION_INSTALL_CONFIG_FILE_PACKAGE)
- include(CMakePackageConfigHelpers)
-
- configure_package_config_file(
- "${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake.in"
- "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-config.cmake"
- INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
- PATH_VARS PROJECT_NAME PROJECT_VERSION
- )
-
- write_basic_package_version_file(
- "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-version.cmake"
- VERSION ${PROJECT_VERSION}
- COMPATIBILITY SameMajorVersion
- )
-
- install(
- FILES
- "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-config.cmake"
- "${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}/${PROJECT_NAME}-version.cmake"
- DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
- COMPONENT development
- )
-
- install(
- EXPORT beman.copyable_function
- DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
- NAMESPACE beman::
- FILE ${PROJECT_NAME}-targets.cmake
- COMPONENT development
- )
-endif()
diff --git a/src/beman/copyable_function/copyable_function.cpp b/src/beman/copyable_function/copyable_function.cpp
deleted file mode 100644
index 8d1f5c5..0000000
--- a/src/beman/copyable_function/copyable_function.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#include
diff --git a/tests/beman/copyable_function/CMakeLists.txt b/tests/beman/copyable_function/CMakeLists.txt
index 1ba5e1d..35966d2 100644
--- a/tests/beman/copyable_function/CMakeLists.txt
+++ b/tests/beman/copyable_function/CMakeLists.txt
@@ -1,16 +1,16 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-include(GoogleTest)
+find_package(GTest REQUIRED)
add_executable(beman.copyable_function.tests.copyable_function)
target_sources(
beman.copyable_function.tests.copyable_function
- PRIVATE assignment.test.cpp ctor.test.cpp call.test.cpp swap.test.cpp
+ PRIVATE assignment.test.cpp call.test.cpp ctor.test.cpp swap.test.cpp
)
-
target_link_libraries(
beman.copyable_function.tests.copyable_function
PRIVATE beman::copyable_function GTest::gtest GTest::gtest_main
)
-gtest_add_tests(beman.copyable_function.tests.copyable_function "" AUTO)
+include(GoogleTest)
+gtest_discover_tests(beman.copyable_function.tests.copyable_function)