diff --git a/.clang-format b/.clang-format
index 2d264bf..74f95dc 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,85 +1,102 @@
---
-Language: Cpp
-BasedOnStyle: LLVM
+Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
+AlignConsecutiveAssignments:
+ Enabled: true
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ PadOperators: true
AlignConsecutiveBitFields:
- Enabled: true
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ PadOperators: false
+AlignConsecutiveDeclarations:
+ Enabled: true
AcrossEmptyLines: false
- AcrossComments: true
- AlignCompound: true
- PadOperators: true
+ AcrossComments: false
+ AlignCompound: false
+ PadOperators: true
AlignConsecutiveMacros:
- Enabled: true
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ PadOperators: false
+AlignConsecutiveShortCaseStatements:
+ Enabled: false
AcrossEmptyLines: false
- AcrossComments: false
- AlignCompound: true
- PadOperators: true
+ AcrossComments: false
+ AlignCaseColons: false
AlignEscapedNewlines: Left
-AlignOperands: AlignAfterOperator
-AlignTrailingComments: true
-AllowAllArgumentsOnNextLine: false
-AllowAllParametersOfDeclarationOnNextLine: false
-AllowShortEnumsOnASingleLine: false
-AllowShortBlocksOnASingleLine: Empty
-AllowShortCaseLabelsOnASingleLine: true
-AllowShortFunctionsOnASingleLine: Inline
+AlignOperands: Align
+AlignTrailingComments:
+ Kind: Always
+ OverEmptyLines: 0
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortEnumsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
-AllowShortIfStatementsOnASingleLine: WithoutElse
-AllowShortLoopsOnASingleLine: true
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
-AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: false
BinPackParameters: false
+BitFieldColonSpacing: Both
BraceWrapping:
- AfterCaseLabel: false
- AfterClass: false
+ AfterCaseLabel: false
+ AfterClass: false
AfterControlStatement: Never
- AfterEnum: false
- AfterFunction: false
- AfterNamespace: false
- AfterObjCDeclaration: false
- AfterStruct: false
- AfterUnion: false
+ AfterEnum: false
AfterExternBlock: false
- BeforeCatch: false
- BeforeElse: false
+ AfterFunction: false
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ BeforeCatch: false
+ BeforeElse: false
BeforeLambdaBody: false
- BeforeWhile: false
- IndentBraces: false
+ BeforeWhile: false
+ IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
+BreakAfterAttributes: Never
+BreakAfterJavaFieldAnnotations: false
+BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
-BreakBeforeBraces: Attach
-BreakBeforeInheritanceComma: false
-BreakInheritanceList: AfterColon
+BreakBeforeBraces: Custom
+BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
-BreakConstructorInitializersBeforeComma: false
-BreakConstructorInitializers: AfterColon
-BreakAfterJavaFieldAnnotations: false
+BreakConstructorInitializers: BeforeColon
+BreakInheritanceList: BeforeColon
BreakStringLiterals: true
-ColumnLimit: 119
-CommentPragmas: "^ IWYU pragma:"
-QualifierAlignment: Leave
+# Please update .markdownlint.yaml if this line is to be updated
+ColumnLimit: 119
+CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
-DeriveLineEnding: true
DerivePointerAlignment: false
-DisableFormat: false
+DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
-PackConstructorInitializers: BinPack
-ConstructorInitializerAllOnOneLineOrOnePerLine: false
-AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true
ForEachMacros:
- foreach
@@ -87,46 +104,57 @@ ForEachMacros:
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
-IncludeBlocks: Preserve
+IncludeBlocks: Preserve
IncludeCategories:
- - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
- Priority: 2
- SortPriority: 0
- CaseSensitive: false
- - Regex: '^(<|"(gtest|gmock|isl|json)/)'
- Priority: 3
- SortPriority: 0
- CaseSensitive: false
- - Regex: ".*"
- Priority: 1
- SortPriority: 0
- CaseSensitive: false
-IncludeIsMainRegex: "(Test)?$"
-IncludeIsMainSourceRegex: ""
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '^(<|"(gtest|isl|json)/)'
+ Priority: 3
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '.*'
+ Priority: 1
+ SortPriority: 0
+ CaseSensitive: false
+IncludeIsMainRegex: '$'
+IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
-IndentCaseLabels: false
IndentCaseBlocks: false
-IndentGotoLabels: true
-IndentPPDirectives: None
+IndentCaseLabels: false
IndentExternBlock: AfterExternBlock
+IndentGotoLabels: true
+IndentPPDirectives: BeforeHash
IndentRequiresClause: true
-IndentWidth: 2
+IndentWidth: 4
IndentWrappedFunctionNames: false
-InsertBraces: false
+InsertBraces: false
+InsertNewlineAtEOF: false
InsertTrailingCommas: None
+IntegerLiteralSeparator:
+ Binary: 0
+ BinaryMinDigits: 0
+ Decimal: 0
+ DecimalMinDigits: 0
+ Hex: 0
+ HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
+KeepEmptyLinesAtEOF: false
LambdaBodyIndentation: Signature
-MacroBlockBegin: ""
-MacroBlockEnd: ""
+LineEnding: DeriveLF
+MacroBlockBegin: ''
+MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
-ObjCBlockIndentWidth: 2
+ObjCBlockIndentWidth: 4
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
+PackConstructorInitializers: NextLine
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
@@ -135,66 +163,80 @@ PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
-PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
+PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
-PPIndentWidth: -1
-ReferenceAlignment: Left
-ReflowComments: true
+PPIndentWidth: -1
+QualifierAlignment: Custom
+QualifierOrder:
+ - inline
+ - static
+ - constexpr
+ - const
+ - volatile
+ - type
+ReferenceAlignment: Pointer
+ReflowComments: true
RemoveBracesLLVM: false
+RemoveParentheses: Leave
+RemoveSemicolon: false
RequiresClausePosition: OwnLine
+RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
-SortIncludes: CaseSensitive
+SortIncludes: Never
SortJavaStaticImport: Before
-SortUsingDeclarations: true
+SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
+SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
+SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
- AfterIfMacros: true
+ AfterIfMacros: true
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
-SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
-SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
-SpacesInAngles: Never
-SpacesInConditionalStatement: false
+SpacesInAngles: Never
SpacesInContainerLiterals: true
-SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
- Minimum: 1
- Maximum: -1
-SpacesInParentheses: false
+ Minimum: 1
+ Maximum: -1
+SpacesInParens: Never
+SpacesInParensOptions:
+ InCStyleCasts: false
+ InConditionalStatements: false
+ InEmptyParentheses: false
+ Other: false
SpacesInSquareBrackets: false
-SpaceBeforeSquareBrackets: false
-BitFieldColonSpacing: Both
-Standard: Latest
+Standard: Auto
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
-TabWidth: 8
-UseCRLF: false
-UseTab: Never
+TabWidth: 8
+UseTab: Never
+VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
+...
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..85f7dd3
--- /dev/null
+++ b/.exemplar_version
@@ -0,0 +1 @@
+9883c77ef9f6fddbee09565347ab611c4dde63d0
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..793dce7
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +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 30973e7..04e7635 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,4 +1,3 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-# Codeowners for reviews on PRs
-* @rishyak @nickelpro
+* @nickelpro
diff --git a/.github/actions/cmake-build-test/action.yml b/.github/actions/cmake-build-test/action.yml
deleted file mode 100644
index 60c4a0a..0000000
--- a/.github/actions/cmake-build-test/action.yml
+++ /dev/null
@@ -1,78 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-name: "CMake Build Test"
-description: ""
-inputs:
- cpp_version:
- description: "cpp version"
- required: true
- toolchain_file:
- description: "toolchain file"
- required: true
- cmake_extra_args:
- description: "extra cmake arguments"
- default: ""
- disable_test:
- description: "disable test"
- default: "false"
-runs:
- using: "composite"
- steps:
- - name: Print installed software
- shell: bash
- run: |
- echo "Build system:"
- cmake --version
- ninja --version
- - name: Get pkg-config
- shell: bash
- if: ${{ !contains(runner.os, 'Windows') }}
- run: |
- sudo apt-get install -y pkg-config zip
- - name: Restore vcpkg cache
- id: vcpkg-cache
- uses: TAServers/vcpkg-cache@v3
- with:
- token: ${{ github.token }}
- - name: Configure CMake
- shell: bash
- env:
- CMAKE_GENERATOR: "Ninja Multi-Config"
- VCPKG_BINARY_SOURCES: "clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite"
- run: |
- cmake \
- -B build \
- -S . \
- -DCMAKE_CXX_STANDARD=${{ inputs.cpp_version }} \
- -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE="$(pwd)/${{ inputs.toolchain_file }}" \
- -DBEMAN_BOUNDS_TEST_BOOTSTRAP_VCPKG=ON \
- ${{ matrix.cmake_args.args }}
- - name: Build Release
- shell: bash
- run: |
- cmake --build build --config Release --parallel --verbose
- cmake --build build --config Release --target all_verify_interface_header_sets
- - name: Prepare Install Directory
- if: ${{ !startsWith(matrix.platform.os, 'windows') }}
- shell: bash
- run: sudo chmod -R 777 /opt/
- - name: Build Install
- shell: bash
- run: |
- 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/actions/setup-environment/action.yml b/.github/actions/setup-environment/action.yml
deleted file mode 100644
index ed3484a..0000000
--- a/.github/actions/setup-environment/action.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-name: "Setup Environment"
-description: "Setup environment on windows/ macos"
-runs:
- using: "composite"
- steps:
- - name: Setup CMake
- uses: lukka/get-cmake@latest
- with:
- cmakeVersion: latest
- ninjaVersion: latest
- - name: Setup MSVC
- if: runner.os == 'windows'
- uses: TheMrMilchmann/setup-msvc-dev@v3
- with:
- arch: x64
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 6d5d89a..194ab3c 100644
--- a/.github/workflows/ci_tests.yml
+++ b/.github/workflows/ci_tests.yml
@@ -4,212 +4,136 @@ name: Continuous Integration Tests
on:
push:
+ branches:
+ - main
pull_request:
workflow_dispatch:
schedule:
- - cron: "30 15 * * *"
+ - cron: '30 15 * * *'
jobs:
- preset-test:
- permissions:
- actions: read
- strategy:
- fail-fast: false
- matrix:
- presets:
- - preset: "gcc-debug"
- compiler: "gcc:14"
- - preset: "gcc-release"
- compiler: "gcc:14"
- - preset: "llvm-debug"
- compiler: "clang:19"
- - preset: "llvm-release"
- compiler: "clang:19"
- # - 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 || matrix.presets.compiler }}"
- runs-on: ${{ matrix.presets.platform || 'ubuntu-latest' }}
- container:
- image: ${{ matrix.presets.compiler && 'ghcr.io/bemanproject/testingcontainers-' }}${{ matrix.presets.compiler }}
- steps:
- - uses: actions/checkout@v4
- - name: Setup Environment
- if: ${{ !matrix.presets.compiler }}
- uses: ./.github/actions/setup-environment
- - name: Get vcpkg deps
- shell: bash
- if: ${{ !contains(runner.os, 'Windows') }}
- run: |
- sudo apt-get install -y pkg-config zip
- - name: Restore vcpkg cache
- id: vcpkg-cache
- uses: TAServers/vcpkg-cache@v3
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- - name: Run preset
- env:
- VCPKG_BINARY_SOURCES: "clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite"
- run: cmake --workflow --preset ${{ matrix.presets.preset }}
-
- catch-test:
- permissions:
- actions: read
- strategy:
- fail-fast: false
- matrix:
- platform:
- - description: "GNU 14"
- compiler: "gcc:14"
- toolchain: "cmake/gnu-toolchain.cmake"
- - description: "LLVM 19"
- compiler: "clang:19"
- toolchain: "cmake/llvm-toolchain.cmake"
- - description: "Windows MSVC"
- os: windows-latest
- toolchain: "cmake/msvc-toolchain.cmake"
- #- description: "Macos Appleclang"
- # os: macos-latest
- # toolchain: "cmake/appleclang-toolchain.cmake"
- cpp_version: [20, 23, 26]
- cmake_args:
- - description: "Default"
- - description: "TSan"
- args: "-DBEMAN_BUILDSYS_SANITIZER=TSan"
- - description: "MaxSan"
- args: "-DBEMAN_BUILDSYS_SANITIZER=MaxSan"
- include:
- - platform:
- description: "GCC 14"
- compiler: "gcc:14"
- toolchain: "cmake/gnu-toolchain.cmake"
- cpp_version: 20
- cmake_args:
- description: "Werror"
- args: "-DCMAKE_CXX_FLAGS='-Werror=all -Werror=extra'"
- - platform:
- description: "GCC 14"
- compiler: "gcc:14"
- toolchain: "cmake/gnu-toolchain.cmake"
- cpp_version: 20
- cmake_args:
- description: "Dynamic"
- args: "-DBUILD_SHARED_LIBS=on"
- exclude:
- # MSVC does not support thread sanitizer
- - platform:
- description: "Windows MSVC"
- cmake_args:
- description: "TSan"
+ beman-submodule-check:
+ uses: bemanproject/infra-workflows/.github/workflows/reusable-beman-submodule-check.yml@1.5.3
- name: "Unit:
- ${{ matrix.platform.description }}
- ${{ matrix.cpp_version }}
- ${{ matrix.cmake_args.description }}"
- runs-on: ${{ matrix.platform.os || 'ubuntu-latest' }}
- container:
- image: ${{ matrix.platform.compiler && 'ghcr.io/bemanproject/testingcontainers-' }}${{ matrix.platform.compiler }}
- steps:
- - uses: actions/checkout@v4
- - name: Setup Environment
- if: ${{ !matrix.platform.compiler }}
- uses: ./.github/actions/setup-environment
- - 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:
- permissions:
- actions: read
- runs-on: ubuntu-latest
- container:
- image: ghcr.io/bemanproject/testingcontainers-gcc:14
- strategy:
- fail-fast: false
- matrix:
- args:
- - name: "Disable build testing"
- arg: "-DBEMAN_BOUNDS_TEST_BUILD_TESTS=OFF"
- - name: "Disable example building"
- arg: "-DBEMAN_BOUNDS_TEST_BUILD_EXAMPLES=OFF"
- - name: "Disable config-file package creation"
- arg: "-DBEMAN_BOUNDS_TEST_INSTALL_CONFIG_FILE_PACKAGE=OFF"
- name: "CMake: ${{ matrix.args.name }}"
- steps:
- - uses: actions/checkout@v4
- - name: Build and Test
- uses: ./.github/actions/cmake-build-test
- with:
- cpp_version: 20
- toolchain_file: "cmake/gnu-toolchain.cmake"
- cmake_extra_args: ${{ matrix.args.arg }}
- disable_test: true
+ preset-test:
+ 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": "msvc-debug", "runner": "windows-latest"},
+ {"preset": "msvc-release", "runner": "windows-latest"}
+ ]
- compiler-test:
- permissions:
- actions: read
- strategy:
- fail-fast: false
- matrix:
- compilers:
- - class: gcc
- version: 14
- toolchain: "cmake/gnu-toolchain.cmake"
- - class: clang
- version: 20
- toolchain: "cmake/llvm-toolchain.cmake"
- - class: clang
- version: 19
- toolchain: "cmake/llvm-toolchain.cmake"
- - class: clang
- version: 18
- toolchain: "cmake/llvm-toolchain.cmake"
- - class: clang
- version: 17
- toolchain: "cmake/llvm-toolchain.cmake"
- name: "Compiler: ${{ matrix.compilers.class }} ${{ matrix.compilers.version }}"
- runs-on: ubuntu-24.04
- container:
- image: ghcr.io/bemanproject/testingcontainers-${{ matrix.compilers.class }}:${{ matrix.compilers.version }}
- steps:
- - uses: actions/checkout@v4
- - name: Build and Test
- uses: ./.github/actions/cmake-build-test
- with:
- cpp_version: 20
- toolchain_file: ${{ matrix.compilers.toolchain }}
+ 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", "Debug.Dynamic"
+ ]
+ }
+ ]
+ },
+ { "cxxversions": ["c++23", "c++20"],
+ "tests": [{ "stdlibs": ["libstdc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ },
+ { "versions": ["14", "13"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23", "c++20"],
+ "tests": [{ "stdlibs": ["libstdc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ },
+ {
+ "versions": ["12", "11"],
+ "tests": [
+ { "cxxversions": ["c++23", "c++20"],
+ "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", "c++20"],
+ "tests": [
+ {"stdlibs": ["libstdc++", "libc++"], "tests": ["Release.Default"]}
+ ]
+ }
+ ]
+ },
+ { "versions": ["21", "20", "19"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23", "c++20"],
+ "tests": [
+ {"stdlibs": ["libstdc++", "libc++"], "tests": ["Release.Default"]}
+ ]
+ }
+ ]
+ },
+ { "versions": ["18"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23", "c++20"],
+ "tests": [{"stdlibs": ["libc++"], "tests": ["Release.Default"]}]
+ },
+ { "cxxversions": ["c++23", "c++20"],
+ "tests": [{"stdlibs": ["libstdc++"], "tests": ["Release.Default"]}]
+ }
+ ]
+ },
+ { "versions": ["17"],
+ "tests": [
+ { "cxxversions": ["c++26", "c++23", "c++20"],
+ "tests": [{"stdlibs": ["libc++"], "tests": ["Release.Default"]}]
+ },
+ { "cxxversions": ["c++20"],
+ "tests": [{"stdlibs": ["libstdc++"], "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, catch-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..9257379
--- /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: "38 15 * * 4"
+
+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 4957963..d293e3b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,12 @@
-# IDE and development folders
-.vscode/
-.idea/
-.settings/
-.cache/
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+/.cache
+/compile_commands.json
+/build
# ignore emacs temp files
*~
\#*\#
-# Miscellaneous build and testing folders
-build/
-
-# Loose files
-.DS_Store
+# 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 d19c5e6..eb01186 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -2,35 +2,47 @@
# 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
- - id: check-yaml
- - id: check-added-large-files
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-yaml
+ - id: check-added-large-files
# Clang-format for C++
# 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]
+ - id: clang-format
+ types_or: [c++, c]
+
+ # 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
# Markdown linting
# Config file: .markdownlint.yaml
- - repo: https://github.com/igorshubovych/markdownlint-cli
- rev: v0.42.0
- hooks:
- - id: markdownlint
+ # Commented out to disable this by default. Uncomment to enable markdown linting.
+ # - repo: https://github.com/igorshubovych/markdownlint-cli
+ # rev: v0.42.0
+ # hooks:
+ # - id: markdownlint
- repo: https://github.com/codespell-project/codespell
- rev: v2.3.0
+ rev: v2.4.2
hooks:
- id: codespell
+ # Beman Standard checking via beman-tidy
- repo: https://github.com/bemanproject/beman-tidy
rev: v0.3.1
hooks:
- - id: beman-tidy
+ - id: beman-tidy
+
+exclude: 'cookiecutter/|infra/'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5d0e4e8..7bd5d17 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,13 +1,12 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-cmake_minimum_required(VERSION 3.28)
-include(cmake/bootstrap_vcpkg.cmake)
+cmake_minimum_required(VERSION 3.30...4.3)
project(
beman.bounds_test
DESCRIPTION "A library for checking integer operation boundary conditions"
LANGUAGES CXX
- VERSION 0.0.1
+ VERSION 0.1.0
)
# [CMAKE.SKIP_TESTS]
@@ -24,83 +23,55 @@ option(
${PROJECT_IS_TOP_LEVEL}
)
-option(
- BEMAN_BOUNDS_TEST_INSTALL_CONFIG_FILE_PACKAGE
- "Enable creating and installing a CMake config-file package. Default: ${PROJECT_IS_TOP_LEVEL}. Values: { ON, OFF }."
- ${PROJECT_IS_TOP_LEVEL}
-)
+# for find of beman_install_library and configure_build_telemetry
+include(infra/cmake/beman-install-library.cmake)
+include(infra/cmake/BuildTelemetryConfig.cmake)
add_library(beman.bounds_test)
add_library(beman::bounds_test ALIAS beman.bounds_test)
-set_target_properties(
- beman.bounds_test
- PROPERTIES
- VERIFY_INTERFACE_HEADER_SETS ON
- EXPORT_NAME bounds_test
-)
-
target_sources(
beman.bounds_test
-
PUBLIC
FILE_SET HEADERS
- BASE_DIRS include
- FILES
- include/beman/bounds_test/bounds_test.hpp
- include/beman/bounds_test/plat/common.hpp
-
+ BASE_DIRS include
+ FILES
+ include/beman/bounds_test/bounds_test.hpp
+ include/beman/bounds_test/plat/common.hpp
PUBLIC
FILE_SET CXX_MODULES
- BASE_DIRS include
- FILES
- include/beman/bounds_test/beman.bounds_test.cppm
+ BASE_DIRS include
+ FILES include/beman/bounds_test/beman.bounds_test.cppm
+)
+
+set_target_properties(
+ beman.bounds_test
+ PROPERTIES VERIFY_INTERFACE_HEADER_SETS ${PROJECT_IS_TOP_LEVEL}
)
-include(GNUInstallDirs)
include(cmake/check_plat.cmake)
add_subdirectory(include/beman/bounds_test/plat)
-install(
- TARGETS beman.bounds_test
- EXPORT beman.bounds_test-targets
- COMPONENT beman.bounds_test
+beman_install_library(beman.bounds_test TARGETS beman.bounds_test)
+configure_build_telemetry()
- FILE_SET CXX_MODULES
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+include(GNUInstallDirs)
- FILE_SET HEADERS
+install(
+ FILES cmake/check_plat.cmake cmake/beman.bounds_test-config.cmake
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/beman.bounds_test
)
-if(BEMAN_BOUNDS_TEST_INSTALL_CONFIG_FILE_PACKAGE)
- include(CMakePackageConfigHelpers)
-
- write_basic_package_version_file(
- ${CMAKE_CURRENT_BINARY_DIR}/beman.bounds_test-config-version.cmake
- COMPATIBILITY ExactVersion
- )
-
- install(
- FILES
- cmake/beman.bounds_test-config.cmake
- cmake/check_plat.cmake
- ${CMAKE_CURRENT_BINARY_DIR}/beman.bounds_test-config-version.cmake
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/beman.bounds_test
- COMPONENT beman.bounds_test
- )
-
- install(
- EXPORT beman.bounds_test-targets
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/beman.bounds_test
- NAMESPACE beman::
- CXX_MODULES_DIRECTORY cxx-modules
- COMPONENT beman.bounds_test
- )
-endif()
+install(
+ DIRECTORY
+ include/beman/bounds_test/plat/generic
+ include/beman/bounds_test/plat/gnu
+ include/beman/bounds_test/plat/msvc
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/beman/bounds_test/plat
+)
if(BEMAN_BOUNDS_TEST_BUILD_TESTS)
- include(CTestUseLaunchers)
enable_testing()
add_subdirectory(tests/beman/bounds_test)
endif()
diff --git a/CMakePresets.json b/CMakePresets.json
index c8d62c1..483e1a3 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -9,7 +9,7 @@
"cacheVariables": {
"CMAKE_CXX_STANDARD": "20",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
- "BEMAN_BOUNDS_TEST_BOOTSTRAP_VCPKG": "ON"
+ "CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "./infra/cmake/use-fetch-content.cmake"
}
},
{
@@ -35,7 +35,7 @@
"_debug-base"
],
"cacheVariables": {
- "VCPKG_CHAINLOAD_TOOLCHAIN_FILE": "${sourceDir}/cmake/gnu-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/gnu-toolchain.cmake"
}
},
{
@@ -46,7 +46,7 @@
"_release-base"
],
"cacheVariables": {
- "VCPKG_CHAINLOAD_TOOLCHAIN_FILE": "${sourceDir}/cmake/gnu-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/gnu-toolchain.cmake"
}
},
{
@@ -57,7 +57,7 @@
"_debug-base"
],
"cacheVariables": {
- "VCPKG_CHAINLOAD_TOOLCHAIN_FILE": "${sourceDir}/cmake/llvm-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/llvm-toolchain.cmake"
}
},
{
@@ -68,7 +68,7 @@
"_release-base"
],
"cacheVariables": {
- "VCPKG_CHAINLOAD_TOOLCHAIN_FILE": "${sourceDir}/cmake/llvm-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/llvm-toolchain.cmake"
}
},
{
@@ -79,7 +79,7 @@
"_debug-base"
],
"cacheVariables": {
- "VCPKG_CHAINLOAD_TOOLCHAIN_FILE": "${sourceDir}/cmake/appleclang-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/appleclang-toolchain.cmake"
}
},
{
@@ -90,7 +90,7 @@
"_release-base"
],
"cacheVariables": {
- "VCPKG_CHAINLOAD_TOOLCHAIN_FILE": "${sourceDir}/cmake/appleclang-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/appleclang-toolchain.cmake"
}
},
{
@@ -101,7 +101,7 @@
"_debug-base"
],
"cacheVariables": {
- "VCPKG_CHAINLOAD_TOOLCHAIN_FILE": "${sourceDir}/cmake/msvc-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/msvc-toolchain.cmake"
}
},
{
@@ -112,7 +112,7 @@
"_release-base"
],
"cacheVariables": {
- "VCPKG_CHAINLOAD_TOOLCHAIN_FILE": "${sourceDir}/cmake/msvc-toolchain.cmake"
+ "CMAKE_TOOLCHAIN_FILE": "infra/cmake/msvc-toolchain.cmake"
}
}
],
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..8272dce
--- /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=20 \
+ # 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.bounds_test 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=20 \
+ -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_BOUNDS_TEST`.
+You can see the list of available options with:
+
+```bash
+cmake -LH -S . -B build | grep "BEMAN_BOUNDS_TEST" -C 2
+```
+
+
+
+Some project-specific configure arguments
+
+### `BEMAN_BOUNDS_TEST_BUILD_TESTS`
+
+Enable building tests and test infrastructure. Default: `ON`.
+Values: `{ ON, OFF }`.
+
+### `BEMAN_BOUNDS_TEST_BUILD_EXAMPLES`
+
+Enable building examples. Default: `ON`. Values: `{ ON, OFF }`.
+
+### `BEMAN_BOUNDS_TEST_INSTALL_CONFIG_FILE_PACKAGE`
+
+Enable installing the CMake config file package. Default: `ON`.
+Values: `{ ON, OFF }`.
+
+This is required so that users of `beman.bounds_test` can use
+`find_package(beman.bounds_test)` to locate the library.
+
+
diff --git a/README.md b/README.md
index 0aefc35..fe57e2a 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-->
-   
+   [](https://coveralls.io/github/bemanproject/bounds_test?branch=main) 
`beman.bounds_test` is a C++ library providing overflow and undefined behavior
checking for integer operations. The library conforms to [The Beman Standard](https://github.com/bemanproject/beman/blob/main/docs/beman_standard.md).
@@ -15,6 +15,10 @@ targeted at C++29.
**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.bounds_test` is licensed under the Apache License v2.0 with LLVM Exceptions.
+
## Overview
The integer operations in C++ have boundary conditions that may readily be
@@ -45,6 +49,53 @@ static_assert(beman::bounds_test::can_negate(small));
static_assert(beman::bounds_test::can_negate(big));
```
+Full runnable examples can be found in [`examples/`](examples/).
+
+## Implementation Details
+
+All provided checks are fully `constexpr`, and so have zero runtime cost where
+they can be evaluated at compile-time. For the runtime case, wherever possible
+`beman.bounds_test` delegates to compiler builtins for bounds checking.
+
+This has trivial cost on most platforms, for example `can_add()` typically
+resolves to a single [`setno`](https://www.felixcloutier.com/x86/setcc)
+instruction on x86, or is optimized out entirely in favor of a conditional jump.
+However, where compiler builtins are not available generic range-checking is
+used instead. This optimizes less well than the builtins.
+
+The builtin checks used by `beman.bounds_test` can be found in
+`cmake/check_plat.cmake`.
+
+## Dependencies
+
+### Build Environment
+
+This project requires at least the following to build:
+
+* A C++ compiler that conforms to the C++20 standard or greater
+* CMake 3.30 or later
+* (Test Only) Catch2
+
+You can disable building tests by setting CMake option `BEMAN_BOUNDS_TEST_BUILD_TESTS` to
+`OFF` when configuring the project.
+
+### Supported Platforms
+
+| Compiler | Version | C++ Standards | Standard Library |
+|----------|---------|---------------|-------------------|
+| GCC | 15-13 | C++26-C++20 | libstdc++ |
+| GCC | 12-11 | C++23, C++20 | libstdc++ |
+| Clang | 22-19 | C++26-C++20 | libstdc++, libc++ |
+| Clang | 18 | C++26-C++20 | libc++ |
+| Clang | 18 | C++23, C++20 | libstdc++ |
+| Clang | 17 | C++26-C++20 | libc++ |
+| Clang | 17 | C++20 | libstdc++ |
+| MSVC | latest | C++23 | MSVC STL |
+
+## Development
+
+See the [Contributing Guidelines](CONTRIBUTING.md).
+
## Integrate beman.bounds_test into your project
`beman.bounds_test` is available as both a header and a module. It requires
@@ -67,62 +118,90 @@ find_package(beman.bounds_test)
target_link_libraries( PRIVATE beman::bounds_test)
```
-## Building beman.bounds_test
+### Build
+
+You can build bounds_test using a CMake workflow preset:
-`beman.bounds_test` has no dependencies when being built without tests, so is
-easily built via typical CMake workflows. The CMakePresets provide some
-examples, but a trivial build might be performed as follows:
+```bash
+cmake --workflow --preset gcc-release
+```
-```plaintext
-cmake -B build -G Ninja \
- -DCMAKE_CXX_STANDARD=20 \
- -DBEMAN_BOUNDS_TEST_BUILD_TESTS=OFF \
- -DBEMAN_BOUNDS_TEST_BUILD_EXAMPLES=OFF
+To list available workflow presets, you can invoke:
-cmake --build build
-cmake --install build --prefix
+```bash
+cmake --list-presets=workflow
```
-When building tests `beman.bounds_test` relies on [Catch2](https://github.com/catchorg/Catch2)
-to provide testing infrastructure. This can be provided as part of the build
-environment, or can be provided by vcpkg as part of the build. In order to
-bootstrap vcpkg, use the `-DBEMAN_BOUNDS_TEST_BOOTSTRAP_VCPKG=ON` option.
+For details on building beman.bounds_test without using a CMake preset, refer to the
+[Contributing Guidelines](CONTRIBUTING.md).
-## Implementation Details
+### Installation
-All provided checks are fully `constexpr`, and so have zero runtime cost where
-they can be evaluated at compile-time. For the runtime case, wherever possible
-`beman.bounds_test` delegates to compiler builtins for bounds checking.
+To install beman.bounds_test globally after building with the `gcc-release` preset, you can
+run:
-This has trivial cost on most platforms, for example `can_add()` typically
-resolves to a single [`setno`](https://www.felixcloutier.com/x86/setcc)
-instruction on x86, or is optimized out entirely in favor of a conditional jump.
-However, where compiler builtins are not available generic range-checking is
-used instead. This optimizes less well than the builtins.
+```bash
+sudo cmake --install build/gcc-release
+```
-The builtin checks used by `beman.bounds_test` can be found in
-`cmake/check_plat.cmake`.
+Alternatively, to install to a prefix, for example `/opt/beman`, you can run:
-## License
+```bash
+sudo cmake --install build/gcc-release --prefix /opt/beman
+```
-beman.bounds_test is licensed under the Apache License v2.0 with LLVM
+This will generate the following directory structure:
+
+```txt
+/opt/beman
+├── include
+│ └── beman
+│ └── bounds_test
+│ ├── bounds_test.hpp
+│ └── ...
+└── lib
+ ├── cmake
+ │ └── beman.bounds_test
+ │ ├── beman.bounds_test-config-version.cmake
+ │ ├── beman.bounds_test-config.cmake
+ │ ├── beman.bounds_test-targets-debug.cmake
+ │ └── beman.bounds_test-targets.cmake
+ └── libbeman.bounds_test.a
+```
-Source is licensed with the Apache 2.0 license with LLVM exceptions
+### CMake Configuration
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+If you installed beman.bounds_test to a prefix, you can specify that prefix to your CMake
+project using `CMAKE_PREFIX_PATH`; for example, `-DCMAKE_PREFIX_PATH=/opt/beman`.
-Documentation and associated papers are licensed with the Creative Commons
-Attribution 4.0 International license.
+You need to bring in the `beman.bounds_test` package to define the `beman::bounds_test` CMake
+target:
-// SPDX-License-Identifier: CC-BY-4.0
+```cmake
+find_package(beman.bounds_test REQUIRED)
+```
-The intent is that the source and documentation are available for use by people
-how they wish.
+You will then need to add `beman::bounds_test` to the link libraries of any libraries or
+executables that include `beman.bounds_test` headers.
-The README itself is licensed with CC0 1.0 Universal. Copy the contents and
-incorporate in your own work as you see fit.
+```cmake
+target_link_libraries(yourlib PUBLIC beman::bounds_test)
+```
+
+### Using beman.bounds_test
+
+To use `beman.bounds_test` in your C++ project,
+include an appropriate `beman.bounds_test` header from your source code.
+
+```c++
+#include
+```
-// SPDX-License-Identifier: CC0-1.0
+> [!NOTE]
+>
+> `beman.bounds_test` headers are to be included with the `beman/bounds_test/` prefix.
+> Altering include search paths to spell the include target another way (e.g.
+> `#include `) is unsupported.
## Contributing
diff --git a/cmake/bootstrap_vcpkg.cmake b/cmake/bootstrap_vcpkg.cmake
deleted file mode 100644
index fd61f30..0000000
--- a/cmake/bootstrap_vcpkg.cmake
+++ /dev/null
@@ -1,47 +0,0 @@
-option(BEMAN_BOUNDS_TEST_BOOTSTRAP_VCPKG "Bootstrap vcpkg if no other toolchain exists" OFF)
-
-if(BEMAN_BOUNDS_TEST_BOOTSTRAP_VCPKG AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
- include(FetchContent)
-
- if(WIN32)
- set(VCPKG vcpkg.exe)
- elseif(LINUX)
- if(EXISTS "/etc/alpine-release")
- set(VCPKG vcpkg-musl)
- else()
- set(VCPKG vcpkg-glibc)
- endif()
- elseif(APPLE)
- set(VCPKG vcpkg-macos)
- else()
- message(FATAL_ERROR "Cannot bootstrap vcpkg: Unsupported platform")
- endif()
-
- FetchContent_Declare(vcpkg
- URL https://github.com/microsoft/vcpkg-tool/releases/latest/download/${VCPKG}
- DOWNLOAD_NO_EXTRACT TRUE
- )
-
- FetchContent_MakeAvailable(vcpkg)
- set(VCPKG ${vcpkg_SOURCE_DIR}/${VCPKG})
-
- file(CHMOD ${VCPKG} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
- set(ENV{VCPKG_ROOT} ${vcpkg_SOURCE_DIR})
- execute_process(COMMAND ${VCPKG} bootstrap-standalone)
-
- if(NOT WIN32)
- file(RENAME ${VCPKG} ${vcpkg_SOURCE_DIR}/vcpkg)
- endif()
-
- set(CMAKE_TOOLCHAIN_FILE
- ${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake
- CACHE FILEPATH "Vcpkg toolchain file"
- )
- set(VCPKG_ROOT_DIR ${vcpkg_SOURCE_DIR} CACHE PATH "Vcpkg Root Directory")
-endif()
-
-if(DEFINED VCPKG_ROOT_DIR)
- add_custom_target(UpdateVcpkgBaseline
- ${VCPKG_ROOT_DIR}/vcpkg x-update-baseline
- )
-endif()
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index cbb01c5..99d8ba6 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,16 +1,13 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-function(add_bounds_test_example NAME)
- add_executable(beman.bounds_test.examples.${NAME})
- target_sources(beman.bounds_test.examples.${NAME} PRIVATE ${NAME}.cpp)
- target_compile_features(beman.bounds_test.examples.${NAME}
- PRIVATE cxx_std_20
- )
+set(ALL_EXAMPLES placeholder cartesian_plane)
+message("Examples to be built: ${ALL_EXAMPLES}")
+
+foreach(example ${ALL_EXAMPLES})
+ add_executable(beman.bounds_test.examples.${example})
+ target_sources(beman.bounds_test.examples.${example} PRIVATE ${example}.cpp)
target_link_libraries(
- beman.bounds_test.examples.${NAME}
+ beman.bounds_test.examples.${example}
PRIVATE beman::bounds_test
)
-endfunction()
-
-add_bounds_test_example(placeholder)
-add_bounds_test_example(cartesian_plane)
+endforeach()
diff --git a/include/beman/bounds_test/CMakeLists.txt b/include/beman/bounds_test/CMakeLists.txt
new file mode 100644
index 0000000..9e26200
--- /dev/null
+++ b/include/beman/bounds_test/CMakeLists.txt
@@ -0,0 +1 @@
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
diff --git a/include/beman/bounds_test/bounds_test.hpp b/include/beman/bounds_test/bounds_test.hpp
index ca99421..af48c51 100644
--- a/include/beman/bounds_test/bounds_test.hpp
+++ b/include/beman/bounds_test/bounds_test.hpp
@@ -8,9 +8,9 @@
#include
#ifdef __INTELLISENSE__
-#include "plat/generic/beman/bounds_test/plat/plat.hpp"
+ #include "plat/generic/beman/bounds_test/plat/plat.hpp"
#else
-#include
+ #include
#endif
namespace beman::bounds_test {
@@ -33,91 +33,93 @@ constexpr bool can_subtract_in_place_modular(A a, B b) noexcept;
template
constexpr bool can_convert(A a) noexcept {
- return std::in_range(a);
+ return std::in_range(a);
}
template
constexpr bool can_convert_modular(A /* a */) noexcept {
- return true;
+ return true;
}
template
constexpr bool can_increment(A a) noexcept {
- return can_add_in_place(a, 1);
+ return can_add_in_place(a, 1);
}
template
constexpr bool can_decrement(A a) noexcept {
- return can_subtract_in_place(a, 1);
+ return can_subtract_in_place(a, 1);
}
template
constexpr bool can_promote(A /* a */) noexcept {
- return true;
+ return true;
}
template
constexpr bool can_negate(A a) noexcept {
- using result_t = decltype(-a);
- if constexpr (std::unsigned_integral) return !a;
- return a != std::numeric_limits::min();
+ using result_t = decltype(-a);
+ if constexpr (std::unsigned_integral)
+ return !a;
+ return a != std::numeric_limits::min();
}
template
constexpr bool can_bitwise_not(A /* a */) noexcept {
- return true;
+ return true;
}
template
constexpr bool can_increment_modular(A a) noexcept {
- return can_add_in_place_modular(a, 1);
+ return can_add_in_place_modular(a, 1);
}
template
constexpr bool can_decrement_modular(A a) noexcept {
- return can_subtract_in_place_modular(a, 1);
+ return can_subtract_in_place_modular(a, 1);
}
template
constexpr bool can_promote_modular(A /* a */) noexcept {
- return true;
+ return true;
}
template
constexpr bool can_negate_modular(A a) noexcept {
- using result_t = decltype(-a);
- if constexpr (std::unsigned_integral) return true;
- return a != std::numeric_limits::min();
+ using result_t = decltype(-a);
+ if constexpr (std::unsigned_integral)
+ return true;
+ return a != std::numeric_limits::min();
}
template
constexpr bool can_bitwise_not_modular(A /* a */) noexcept {
- return true;
+ return true;
}
template
constexpr bool can_add(A a, B b) noexcept {
- return ::beman::bounds_test::detail::can_add(a, b, decltype(a + b){});
+ return ::beman::bounds_test::detail::can_add(a, b, decltype(a + b){});
}
template
constexpr bool can_subtract(A a, B b) noexcept {
- return ::beman::bounds_test::detail::can_sub(a, b, decltype(a - b){});
+ return ::beman::bounds_test::detail::can_sub(a, b, decltype(a - b){});
}
template
constexpr bool can_multiply(A a, B b) noexcept {
- return ::beman::bounds_test::detail::can_mul(a, b, decltype(a * b){});
+ return ::beman::bounds_test::detail::can_mul(a, b, decltype(a * b){});
}
template
constexpr bool can_divide(A a, B b) noexcept {
- return ::beman::bounds_test::detail::can_div(a, b, decltype(a / b){});
+ return ::beman::bounds_test::detail::can_div(a, b, decltype(a / b){});
}
template
constexpr bool can_take_remainder(A a, B b) noexcept {
- return can_divide(a, b);
+ return can_divide(a, b);
}
template
@@ -128,17 +130,17 @@ constexpr bool can_shift_right(A a, B b) noexcept;
template
constexpr bool can_bitwise_and(A /* a */, B /* b */) noexcept {
- return true;
+ return true;
}
template
constexpr bool can_bitwise_xor(A /* a */, B /* b */) noexcept {
- return true;
+ return true;
}
template
constexpr bool can_bitwise_or(A /* a */, B /* b */) noexcept {
- return true;
+ return true;
}
template
@@ -146,14 +148,16 @@ constexpr bool can_compare(A a, B b) noexcept;
template
constexpr bool can_add_modular(A a, B b) noexcept {
- if constexpr (std::unsigned_integral) return true;
- return can_add(a, b);
+ if constexpr (std::unsigned_integral)
+ return true;
+ return can_add(a, b);
}
template
constexpr bool can_subtract_modular(A a, B b) noexcept {
- if constexpr (std::unsigned_integral) return true;
- return can_subtract(a, b);
+ if constexpr (std::unsigned_integral)
+ return true;
+ return can_subtract(a, b);
}
template
@@ -167,42 +171,42 @@ constexpr bool can_shift_right_modular(A, B) noexcept;
template
constexpr bool can_bitwise_and_modular(A /* a */, B /* b */) noexcept {
- return true;
+ return true;
}
template
constexpr bool can_bitwise_xor_modular(A /* a */, B /* b */) noexcept {
- return true;
+ return true;
}
template
constexpr bool can_bitwise_or_modular(A /* a */, B /* b */) noexcept {
- return true;
+ return true;
}
template
constexpr bool can_add_in_place(A a, B b) noexcept {
- return ::beman::bounds_test::detail::can_add(a, b, a);
+ return ::beman::bounds_test::detail::can_add(a, b, a);
}
template
constexpr bool can_subtract_in_place(A a, B b) noexcept {
- return ::beman::bounds_test::detail::can_sub(a, b, a);
+ return ::beman::bounds_test::detail::can_sub(a, b, a);
}
template
constexpr bool can_multiply_in_place(A a, B b) noexcept {
- return ::beman::bounds_test::detail::can_mul(a, b, a);
+ return ::beman::bounds_test::detail::can_mul(a, b, a);
}
template
constexpr bool can_divide_in_place(A a, B b) noexcept {
- return ::beman::bounds_test::detail::can_div(a, b, a);
+ return ::beman::bounds_test::detail::can_div(a, b, a);
}
template
constexpr bool can_take_remainder_in_place(A a, B b) noexcept {
- return can_divide_in_place(a, b);
+ return can_divide_in_place(a, b);
}
template
@@ -213,29 +217,31 @@ constexpr bool can_shift_right_in_place(A a, B b) noexcept;
template
constexpr bool can_bitwise_and_in_place(A a, B b) noexcept {
- return std::in_range(a & b);
+ return std::in_range(a & b);
}
template
constexpr bool can_bitwise_xor_in_place(A a, B b) noexcept {
- return std::in_range(a ^ b);
+ return std::in_range(a ^ b);
}
template
constexpr bool can_bitwise_or_in_place(A a, B b) noexcept {
- return std::in_range(a | b);
+ return std::in_range(a | b);
}
template
constexpr bool can_add_in_place_modular(A a, B b) noexcept {
- if constexpr (std::unsigned_integral) return true;
- return can_add_in_place(a, b);
+ if constexpr (std::unsigned_integral)
+ return true;
+ return can_add_in_place(a, b);
}
template
constexpr bool can_subtract_in_place_modular(A a, B b) noexcept {
- if constexpr (std::unsigned_integral) return true;
- return can_subtract_in_place(a, b);
+ if constexpr (std::unsigned_integral)
+ return true;
+ return can_subtract_in_place(a, b);
}
template
@@ -243,27 +249,27 @@ constexpr bool can_multiply_in_place_modular(A a, B b) noexcept;
template
constexpr bool can_shift_left_in_place_modular(A a, B b) noexcept {
- return ::beman::bounds_test::detail::can_shift(a, b, a);
+ return ::beman::bounds_test::detail::can_shift(a, b, a);
};
template
constexpr bool can_shift_right_in_place_modular(A a, B b) noexcept {
- return ::beman::bounds_test::detail::can_shift(a, b, a);
+ return ::beman::bounds_test::detail::can_shift(a, b, a);
};
template
constexpr bool can_bitwise_and_in_place_modular(A /* a */, B /* b */) noexcept {
- return true;
+ return true;
}
template
constexpr bool can_bitwise_xor_in_place_modular(A /* a */, B /* b */) noexcept {
- return true;
+ return true;
}
template
constexpr bool can_bitwise_or_in_place_modular(A /* a */, B /* b */) noexcept {
- return true;
+ return true;
}
} // namespace beman::bounds_test
diff --git a/infra/.beman_submodule b/infra/.beman_submodule
new file mode 100644
index 0000000..8463363
--- /dev/null
+++ b/infra/.beman_submodule
@@ -0,0 +1,3 @@
+[beman_submodule]
+remote=https://github.com/bemanproject/infra.git
+commit_hash=dfdb103b5fc9cccd3424c377130e318466f1dd89
diff --git a/infra/.github/CODEOWNERS b/infra/.github/CODEOWNERS
new file mode 100644
index 0000000..4ff90a4
--- /dev/null
+++ b/infra/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @ednolan @neatudarius @rishyak @wusatosi @JeffGarland
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
new file mode 100644
index 0000000..b7cdbb5
--- /dev/null
+++ b/infra/.gitignore
@@ -0,0 +1,59 @@
+# Prerequisites
+*.d
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+*.smod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.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/.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/LICENSE b/infra/LICENSE
new file mode 100644
index 0000000..f6db814
--- /dev/null
+++ b/infra/LICENSE
@@ -0,0 +1,219 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+---- LLVM Exceptions to the Apache 2.0 License ----
+
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into an Object form of such source code, you
+may redistribute such embedded portions in such Object form without complying
+with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
+
+In addition, if you combine or link compiled forms of this Software with
+software that is licensed under the GPLv2 ("Combined Software") and if a
+court of competent jurisdiction determines that the patent provision (Section
+3), the indemnity provision (Section 9) or other Section of the License
+conflicts with the conditions of the GPLv2, you may retroactively and
+prospectively choose to deem waived or otherwise exclude such Section(s) of
+the License, but only in their entirety and only with respect to the Combined
+Software.
diff --git a/infra/README.md b/infra/README.md
new file mode 100644
index 0000000..bf9bbb0
--- /dev/null
+++ b/infra/README.md
@@ -0,0 +1,88 @@
+# Beman Project Infrastructure Repository
+
+
+
+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.
+
+## 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/cmake/appleclang-toolchain.cmake b/infra/cmake/appleclang-toolchain.cmake
similarity index 85%
rename from cmake/appleclang-toolchain.cmake
rename to infra/cmake/appleclang-toolchain.cmake
index e7a6cc4..70ef548 100644
--- a/cmake/appleclang-toolchain.cmake
+++ b/infra/cmake/appleclang-toolchain.cmake
@@ -16,6 +16,8 @@
include_guard(GLOBAL)
+# Prevent PATH collision with an LLVM clang installation by using the system
+# compiler shims
set(CMAKE_C_COMPILER cc)
set(CMAKE_CXX_COMPILER c++)
@@ -37,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/cmake/gnu-toolchain.cmake b/infra/cmake/gnu-toolchain.cmake
similarity index 90%
rename from cmake/gnu-toolchain.cmake
rename to infra/cmake/gnu-toolchain.cmake
index b6dddf6..d3b9f92 100644
--- a/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/cmake/llvm-toolchain.cmake b/infra/cmake/llvm-toolchain.cmake
similarity index 90%
rename from cmake/llvm-toolchain.cmake
rename to infra/cmake/llvm-toolchain.cmake
index 5f5ee4b..f1623b7 100644
--- a/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/cmake/msvc-toolchain.cmake b/infra/cmake/msvc-toolchain.cmake
similarity index 87%
rename from cmake/msvc-toolchain.cmake
rename to infra/cmake/msvc-toolchain.cmake
index 2802982..bdc24de 100644
--- a/cmake/msvc-toolchain.cmake
+++ b/infra/cmake/msvc-toolchain.cmake
@@ -20,10 +20,7 @@ include_guard(GLOBAL)
set(CMAKE_C_COMPILER cl)
set(CMAKE_CXX_COMPILER cl)
-# Off until I figure out how I want to handle vcpkg (dependencies also need to
-# be built with address sanitizer)
-# if(BEMAN_BUILDSYS_SANITIZER STREQUAL "MaxSan")
-if(OFF)
+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")
@@ -39,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
new file mode 100644
index 0000000..f2428b5
--- /dev/null
+++ b/infra/cmake/use-fetch-content.cmake
@@ -0,0 +1,188 @@
+cmake_minimum_required(VERSION 3.24)
+
+include(FetchContent)
+
+if(NOT BEMAN_EXEMPLAR_LOCKFILE)
+ set(BEMAN_EXEMPLAR_LOCKFILE
+ "lockfile.json"
+ CACHE FILEPATH
+ "Path to the dependency lockfile for the Beman Exemplar."
+ )
+endif()
+
+set(BemanExemplar_projectDir "${CMAKE_CURRENT_LIST_DIR}/../..")
+message(TRACE "BemanExemplar_projectDir=\"${BemanExemplar_projectDir}\"")
+
+message(TRACE "BEMAN_EXEMPLAR_LOCKFILE=\"${BEMAN_EXEMPLAR_LOCKFILE}\"")
+file(
+ REAL_PATH "${BEMAN_EXEMPLAR_LOCKFILE}"
+ BemanExemplar_lockfile
+ BASE_DIRECTORY "${BemanExemplar_projectDir}"
+ EXPAND_TILDE
+)
+message(DEBUG "Using lockfile: \"${BemanExemplar_lockfile}\"")
+
+# Force CMake to reconfigure the project if the lockfile changes
+set_property(
+ DIRECTORY "${BemanExemplar_projectDir}"
+ APPEND
+ PROPERTY CMAKE_CONFIGURE_DEPENDS "${BemanExemplar_lockfile}"
+)
+
+# For more on the protocol for this function, see:
+# https://cmake.org/cmake/help/latest/command/cmake_language.html#provider-commands
+function(BemanExemplar_provideDependency method package_name)
+ # Read the lockfile
+ file(READ "${BemanExemplar_lockfile}" BemanExemplar_rootObj)
+
+ # Get the "dependencies" field and store it in BemanExemplar_dependenciesObj
+ string(
+ JSON BemanExemplar_dependenciesObj
+ ERROR_VARIABLE BemanExemplar_error
+ GET "${BemanExemplar_rootObj}"
+ "dependencies"
+ )
+ if(BemanExemplar_error)
+ message(FATAL_ERROR "${BemanExemplar_lockfile}: ${BemanExemplar_error}")
+ endif()
+
+ # Get the length of the libraries array and store it in BemanExemplar_dependenciesObj
+ string(
+ JSON BemanExemplar_numDependencies
+ ERROR_VARIABLE BemanExemplar_error
+ LENGTH "${BemanExemplar_dependenciesObj}"
+ )
+ if(BemanExemplar_error)
+ 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}")
+ set(BemanExemplar_errorPrefix
+ "${BemanExemplar_lockfile}, dependency ${BemanExemplar_index}"
+ )
+
+ # Get the dependency object at BemanExemplar_index
+ # and store it in BemanExemplar_depObj
+ string(
+ JSON BemanExemplar_depObj
+ ERROR_VARIABLE BemanExemplar_error
+ GET "${BemanExemplar_dependenciesObj}"
+ "${BemanExemplar_index}"
+ )
+ if(BemanExemplar_error)
+ message(
+ FATAL_ERROR
+ "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}"
+ )
+ endif()
+
+ # Get the "name" field and store it in BemanExemplar_name
+ string(
+ JSON BemanExemplar_name
+ ERROR_VARIABLE BemanExemplar_error
+ GET "${BemanExemplar_depObj}"
+ "name"
+ )
+ if(BemanExemplar_error)
+ message(
+ FATAL_ERROR
+ "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}"
+ )
+ endif()
+
+ # Get the "package_name" field and store it in BemanExemplar_pkgName
+ string(
+ JSON BemanExemplar_pkgName
+ ERROR_VARIABLE BemanExemplar_error
+ GET "${BemanExemplar_depObj}"
+ "package_name"
+ )
+ if(BemanExemplar_error)
+ message(
+ FATAL_ERROR
+ "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}"
+ )
+ endif()
+
+ # Get the "git_repository" field and store it in BemanExemplar_repo
+ string(
+ JSON BemanExemplar_repo
+ ERROR_VARIABLE BemanExemplar_error
+ GET "${BemanExemplar_depObj}"
+ "git_repository"
+ )
+ if(BemanExemplar_error)
+ message(
+ FATAL_ERROR
+ "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}"
+ )
+ endif()
+
+ # Get the "git_tag" field and store it in BemanExemplar_tag
+ string(
+ JSON BemanExemplar_tag
+ ERROR_VARIABLE BemanExemplar_error
+ GET "${BemanExemplar_depObj}"
+ "git_tag"
+ )
+ if(BemanExemplar_error)
+ message(
+ FATAL_ERROR
+ "${BemanExemplar_errorPrefix}: ${BemanExemplar_error}"
+ )
+ endif()
+
+ if(method STREQUAL "FIND_PACKAGE")
+ if(package_name STREQUAL BemanExemplar_pkgName)
+ string(
+ APPEND BemanExemplar_debug
+ "Redirecting find_package calls for ${BemanExemplar_pkgName} "
+ "to FetchContent logic.\n"
+ )
+ string(
+ APPEND BemanExemplar_debug
+ "Fetching ${BemanExemplar_repo} at "
+ "${BemanExemplar_tag} according to ${BemanExemplar_lockfile}."
+ )
+ message(DEBUG "${BemanExemplar_debug}")
+ FetchContent_Declare(
+ "${BemanExemplar_name}"
+ GIT_REPOSITORY "${BemanExemplar_repo}"
+ GIT_TAG "${BemanExemplar_tag}"
+ EXCLUDE_FROM_ALL
+ )
+ set(INSTALL_GTEST OFF) # Disable GoogleTest installation
+ 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)
+ endif()
+ endif()
+ endforeach()
+endfunction()
+
+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/lockfile.json b/lockfile.json
new file mode 100644
index 0000000..a1f3d8f
--- /dev/null
+++ b/lockfile.json
@@ -0,0 +1,10 @@
+{
+ "dependencies": [
+ {
+ "name": "Catch2",
+ "package_name": "Catch2",
+ "git_repository": "https://github.com/catchorg/Catch2.git",
+ "git_tag": "25319fd3047c6bdcf3c0170e76fa526c77f99ca9"
+ }
+ ]
+}
diff --git a/tests/beman/bounds_test/CMakeLists.txt b/tests/beman/bounds_test/CMakeLists.txt
index 677f22b..1ea5f00 100644
--- a/tests/beman/bounds_test/CMakeLists.txt
+++ b/tests/beman/bounds_test/CMakeLists.txt
@@ -1,14 +1,13 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-find_package(Catch2 3 REQUIRED CONFIG)
+find_package(Catch2 3 REQUIRED)
-add_executable(beman.bounds_test.tests)
-target_sources(beman.bounds_test.tests PRIVATE bounds_test.tests.cpp)
-target_compile_features(beman.bounds_test.tests PRIVATE cxx_std_20)
+add_executable(beman.bounds_test.tests.bounds_test)
+target_sources(beman.bounds_test.tests.bounds_test PRIVATE bounds_test.test.cpp)
target_link_libraries(
- beman.bounds_test.tests
+ beman.bounds_test.tests.bounds_test
PRIVATE beman::bounds_test Catch2::Catch2WithMain
)
include(Catch)
-catch_discover_tests(beman.bounds_test.tests)
+catch_discover_tests(beman.bounds_test.tests.bounds_test)
diff --git a/vcpkg.json b/vcpkg.json
deleted file mode 100644
index 78394b8..0000000
--- a/vcpkg.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "name": "beman-bounds-test",
- "version": "0.0.1",
- "description": "A library for checking integer operation boundary conditions",
- "maintainers": [
- "Rishyak Panchal ",
- "Vito Gamberini "
- ],
- "license": "Apache-2.0 WITH LLVM-exception",
- "dependencies": [
- "catch2"
- ],
- "vcpkg-configuration": {
- "default-registry": {
- "kind": "git",
- "baseline": "7e21420f775f72ae938bdeb5e6068f722088f06a",
- "repository": "https://github.com/microsoft/vcpkg.git"
- }
- }
-}