Skip to content

Commit 033d393

Browse files
authored
Merge pull request #113 from steve-downey/find_package
Find package
2 parents eec9177 + 8b18f32 commit 033d393

File tree

9 files changed

+244
-60
lines changed

9 files changed

+244
-60
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,12 @@ jobs:
9393
echo ${{ matrix.config.cmake_args }}
9494
echo ${{ matrix.config.toolchain }}
9595
rm -rf .build
96-
cmake ${{ matrix.config.cmake_args }} -DCMAKE_INSTALL_PREFIX=.install -DCMAKE_TOOLCHAIN_FILE="etc/${{ matrix.config.toolchain }}-toolchain.cmake" -B .build -S .
96+
cmake ${{ matrix.config.cmake_args }} \
97+
-DCMAKE_INSTALL_PREFIX=.install \
98+
-DCMAKE_TOOLCHAIN_FILE="etc/${{ matrix.config.toolchain }}-toolchain.cmake" \
99+
-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES="./cmake/use-fetch-content.cmake" \
100+
-B .build \
101+
-S .
97102
- name: CMake ASAN Build
98103
run: |
99104
set -x

.markdownlint.yaml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@
22
# Disable inline html linter is needed for <details> <summary>
33
MD033: false
44

5-
# MD013/line-length : Line length : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md013.md
6-
# Conforms to .clang-format ColumnLimit
7-
# Update the comment in .clang-format if we no-longer tie these two column limits.
8-
MD013:
9-
line_length: 119
10-
115
# MD024/no-duplicate-heading : https://github.com/DavidAnson/markdownlint/blob/main/doc/md024.md
126
# Supress warning about the same heading twice unless they are in the same block
137
MD024:

.pre-commit-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ repos:
3131
rev: v0.43.0
3232
hooks:
3333
- id: markdownlint
34+
args: ['--disable', 'MD013', ' --']
3435
exclude: ^papers/
3536

3637
# Config file: .codespell_ignore

CMakeLists.txt

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,6 @@ option(
1818
${PROJECT_IS_TOP_LEVEL}
1919
)
2020

21-
# Build the tests if enabled via the option OPTIONAL_ENABLE_TESTING
22-
if(OPTIONAL_ENABLE_TESTING)
23-
# Fetch GoogleTest
24-
FetchContent_Declare(
25-
googletest
26-
EXCLUDE_FROM_ALL
27-
GIT_REPOSITORY https://github.com/google/googletest.git
28-
GIT_TAG
29-
e39786088138f2749d64e9e90e0f9902daa77c40 # release-1.15.0
30-
)
31-
FetchContent_MakeAvailable(googletest)
32-
endif()
33-
3421
set(CMAKE_VERIFY_INTERFACE_HEADER_SETS ON)
3522

3623
# Create the library target and named header set for beman_optional
@@ -41,18 +28,29 @@ target_sources(
4128
)
4229

4330
if(OPTIONAL_ENABLE_TESTING)
44-
# Create the library target and named header set for testing beman_optional
45-
# and mark the set private
46-
add_executable(beman_optional_test)
47-
target_sources(
48-
beman_optional_test
49-
PRIVATE
50-
FILE_SET beman_optional_test_headers
51-
TYPE HEADERS
52-
BASE_DIRS tests
53-
)
54-
55-
add_subdirectory(tests/beman/optional)
31+
find_package(GTest QUIET)
32+
if(GTest_FOUND)
33+
# Create the library target and named header set for testing beman_optional
34+
# and mark the set private
35+
add_executable(beman_optional_test)
36+
target_sources(
37+
beman_optional_test
38+
PRIVATE
39+
FILE_SET beman_optional_test_headers
40+
TYPE HEADERS
41+
BASE_DIRS tests
42+
)
43+
# Tests
44+
add_subdirectory(tests/beman/optional)
45+
else()
46+
message(
47+
WARNING
48+
"
49+
No provider for GTest. Unable to build tests.
50+
Consider using CMAKE_PROJECT_TOP_LEVEL_INCLUDES=./cmake/use-fetch-content.cmake as documented in the README.md
51+
"
52+
)
53+
endif()
5654
endif()
5755

5856
add_subdirectory(include/beman/optional)

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ define run_cmake =
4545
-DCMAKE_CONFIGURATION_TYPES=$(_configuration_types) \
4646
-DCMAKE_INSTALL_PREFIX=$(abspath $(INSTALL_PREFIX)) \
4747
-DCMAKE_EXPORT_COMPILE_COMMANDS=1 \
48+
-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES="./cmake/use-fetch-content.cmake" \
4849
$(_cmake_args) \
4950
$(CURDIR)
5051
endef

README.md

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@ SPDX-License-Identifier: 2.0 license with LLVM exceptions
88
<img src="https://github.com/bemanproject/beman/blob/main/images/logos/beman_logo-beman_library_production_ready_api_may_undergo_changes.png" style="width:5%; height:auto;"> ![CI Tests](https://github.com/bemanproject/optional/actions/workflows/ci.yml/badge.svg) [![Coverage](https://coveralls.io/repos/github/bemanproject/optional/badge.svg?branch=main)](https://coveralls.io/github/bemanproject/optional?branch=main)
99
<!-- markdownlint-enable -->
1010

11-
This repository implements `std::optional` extensions targeting C++26. The `beman.optional` library aims to evaluate
12-
the stability, the usability, and the performance of these proposed changes before they are officially adopted by WG21
13-
into the C++ Working Draft. Additionally, it allows developers to use these new features before they are implemented in
14-
major standard library compilers.
11+
This repository implements `std::optional` extensions targeting C++26. The `beman.optional` library aims to evaluate the stability, the usability, and the performance of these proposed changes before they are officially adopted by WG21 into the C++ Working Draft. Additionally, it allows developers to use these new features before they are implemented in major standard library compilers.
1512

1613
**Implements**: [Give *std::optional* Range Support (P3168R2)](https://wg21.link/P3168R2) and [`std::optional<T&>` (P2988R5)](https://wg21.link/P2988R5)
1714

@@ -27,11 +24,9 @@ Documentation and associated papers are licensed with the Creative Commons Attri
2724

2825
// SPDX-License-Identifier: CC-BY-4.0
2926

30-
The intent is that the source and documentation are available for use by people implementing their own optional types
31-
as well as people using the optional presented here as-is.
27+
The intent is that the source and documentation are available for use by people implementing their own optional types as well as people using the optional presented here as-is.
3228

33-
The README itself is licensed with CC0 1.0 Universal. Copy the contents and incorporate in your own work as you see
34-
fit.
29+
The README itself is licensed with CC0 1.0 Universal. Copy the contents and incorporate in your own work as you see fit.
3530

3631
// SPDX-License-Identifier: CC0-1.0
3732

@@ -68,7 +63,7 @@ Full code can be found in [./examples/range_loop.cpp](./examples/range_loop.cpp)
6863
### optional_ref
6964

7065
The next code snippet shows optional reference support added in [`std::optional<T&>`
71-
(P2988R5)](https://wg21.link/P2988R5):
66+
(P2988)](https://wg21.link/P2988):
7267

7368
```cpp
7469
#include <beman/optional/optional.hpp>
@@ -107,8 +102,7 @@ Default build: `C++23`. Please check `etc/${compiler}-flags.cmake`.
107102

108103
### Dependencies
109104

110-
This project is mainly tested on `Ubuntu 22.04` and `Ubuntu 24.04`, but it should be as portable as CMake is. This
111-
project has no C or C++ dependencies.
105+
This project is mainly tested on `Ubuntu 22.04` and `Ubuntu 24.04`, but it should be as portable as CMake is. This project has no C or C++ dependencies.
112106

113107
Build-time dependencies:
114108

@@ -128,14 +122,29 @@ apt-get install \
128122
clang-18 clang++-18 clang-17 clang++-17
129123
```
130124

125+
<details>
126+
<summary> Build GoogleTest dependency from github.com </summary>
127+
128+
If you do not have GoogleTest installed on your development system, you may
129+
optionally configure this project to download a known-compatible release of
130+
GoogleTest from source and build it as well.
131+
132+
```shell
133+
cmake -B build -S . -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./cmake/use-fetch-content.cmake
134+
```
135+
136+
The precise version of GoogleTest that will be used is maintained in
137+
`./lockfile.json`.
138+
139+
</details>
140+
131141
### Instructions
132142

133143
Full set of supported toolchains can be found in [.github/workflows/ci.yml](.github/workflows/ci.yml).
134144

135145
#### Preset CMake Flows
136146

137-
This project strives to be as normal and simple a CMake project as possible. This build workflow in particular will
138-
work, producing a static `beman_optional` library, ready to package:
147+
This project strives to be as normal and simple a CMake project as possible. This build workflow in particular will work, producing a static `beman_optional` library, ready to package:
139148

140149
```shell
141150
# List available preset configurations:
@@ -238,14 +247,9 @@ No tests were found!!!
238247

239248
#### Pre-Commit for Linting
240249

241-
Various linting tools are configured and installed via the [pre-commit](https://pre-commit.com/) framework. This
242-
requires a working python environment, but also allows the tools, such as clang-format and cmake-lint, to be versioned
243-
on a per project basis rather than being installed globally. Version changes in lint checks often means differences in
244-
success or failure between the versions in CI and the versions used by a developer. By using the same configurations,
245-
this problem is avoided.
250+
Various linting tools are configured and installed via the [pre-commit](https://pre-commit.com/) framework. This requires a working python environment, but also allows the tools, such as clang-format and cmake-lint, to be versioned on a per project basis rather than being installed globally. Version changes in lint checks often means differences in success or failure between the versions in CI and the versions used by a developer. By using the same configurations, this problem is avoided.
246251

247-
In order to set up a python environment, using a python virtual environment can simplify maintaining different
248-
configurations between projects. There is no particular dependency on a particular python3 version.
252+
In order to set up a python environment, using a python virtual environment can simplify maintaining different configurations between projects. There is no particular dependency on a particular python3 version.
249253

250254
##### Creating and configuring a venv
251255

@@ -258,8 +262,7 @@ python3 -m venv .venv
258262
. .venv/bin/activate && exec bash
259263
```
260264

261-
This will create the venv, install the python and python development tools, and run bash with the PATH and other
262-
environment variables set to use the venv preferentially.
265+
This will create the venv, install the python and python development tools, and run bash with the PATH and other environment variables set to use the venv preferentially.
263266

264267
##### Running the linting tools
265268

@@ -291,3 +294,4 @@ Latest revision(s) of the papers can be built / found at:
291294
* issue: [#1661](https://github.com/cplusplus/papers/issues/1661)
292295
* LEWG:
293296
* Reviewed in Tokyo 2024.
297+
* Forwarded by LEWG in 2025 in Hagenberg.

cmake/use-fetch-content.cmake

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
cmake_minimum_required(VERSION 3.24)
2+
3+
if(NOT BEMAN_OPTIONAL_LOCKFILE)
4+
set(BEMAN_OPTIONAL_LOCKFILE
5+
"lockfile.json"
6+
CACHE FILEPATH
7+
"Path to the dependency lockfile for the Beman Optional."
8+
)
9+
endif()
10+
11+
set(BemanOptional_projectDir "${CMAKE_CURRENT_LIST_DIR}/..")
12+
message(TRACE "BemanOptional_projectDir=\"${BemanOptional_projectDir}\"")
13+
14+
message(TRACE "BEMAN_OPTIONAL_LOCKFILE=\"${BEMAN_OPTIONAL_LOCKFILE}\"")
15+
file(
16+
REAL_PATH
17+
"${BEMAN_OPTIONAL_LOCKFILE}"
18+
BemanOptional_lockfile
19+
BASE_DIRECTORY "${BemanOptional_projectDir}"
20+
EXPAND_TILDE
21+
)
22+
message(DEBUG "Using lockfile: \"${BemanOptional_lockfile}\"")
23+
24+
# Force CMake to reconfigure the project if the lockfile changes
25+
set_property(
26+
DIRECTORY "${BemanOptional_projectDir}"
27+
APPEND
28+
PROPERTY CMAKE_CONFIGURE_DEPENDS "${BemanOptional_lockfile}"
29+
)
30+
31+
# For more on the protocol for this function, see:
32+
# https://cmake.org/cmake/help/latest/command/cmake_language.html#provider-commands
33+
function(BemanOptional_provideDependency method package_name)
34+
# Read the lockfile
35+
file(READ "${BemanOptional_lockfile}" BemanOptional_rootObj)
36+
37+
# Get the "dependencies" field and store it in BemanOptional_dependenciesObj
38+
string(
39+
JSON
40+
BemanOptional_dependenciesObj
41+
ERROR_VARIABLE BemanOptional_error
42+
GET "${BemanOptional_rootObj}"
43+
"dependencies"
44+
)
45+
if(BemanOptional_error)
46+
message(FATAL_ERROR "${BemanOptional_lockfile}: ${BemanOptional_error}")
47+
endif()
48+
49+
# Get the length of the libraries array and store it in BemanOptional_dependenciesObj
50+
string(
51+
JSON
52+
BemanOptional_numDependencies
53+
ERROR_VARIABLE BemanOptional_error
54+
LENGTH "${BemanOptional_dependenciesObj}"
55+
)
56+
if(BemanOptional_error)
57+
message(FATAL_ERROR "${BemanOptional_lockfile}: ${BemanOptional_error}")
58+
endif()
59+
60+
# Loop over each dependency object
61+
math(EXPR BemanOptional_maxIndex "${BemanOptional_numDependencies} - 1")
62+
foreach(BemanOptional_index RANGE "${BemanOptional_maxIndex}")
63+
set(BemanOptional_errorPrefix
64+
"${BemanOptional_lockfile}, dependency ${BemanOptional_index}"
65+
)
66+
67+
# Get the dependency object at BemanOptional_index
68+
# and store it in BemanOptional_depObj
69+
string(
70+
JSON
71+
BemanOptional_depObj
72+
ERROR_VARIABLE BemanOptional_error
73+
GET "${BemanOptional_dependenciesObj}"
74+
"${BemanOptional_index}"
75+
)
76+
if(BemanOptional_error)
77+
message(
78+
FATAL_ERROR
79+
"${BemanOptional_errorPrefix}: ${BemanOptional_error}"
80+
)
81+
endif()
82+
83+
# Get the "name" field and store it in BemanOptional_name
84+
string(
85+
JSON
86+
BemanOptional_name
87+
ERROR_VARIABLE BemanOptional_error
88+
GET "${BemanOptional_depObj}"
89+
"name"
90+
)
91+
if(BemanOptional_error)
92+
message(
93+
FATAL_ERROR
94+
"${BemanOptional_errorPrefix}: ${BemanOptional_error}"
95+
)
96+
endif()
97+
98+
# Get the "package_name" field and store it in BemanOptional_pkgName
99+
string(
100+
JSON
101+
BemanOptional_pkgName
102+
ERROR_VARIABLE BemanOptional_error
103+
GET "${BemanOptional_depObj}"
104+
"package_name"
105+
)
106+
if(BemanOptional_error)
107+
message(
108+
FATAL_ERROR
109+
"${BemanOptional_errorPrefix}: ${BemanOptional_error}"
110+
)
111+
endif()
112+
113+
# Get the "git_repository" field and store it in BemanOptional_repo
114+
string(
115+
JSON
116+
BemanOptional_repo
117+
ERROR_VARIABLE BemanOptional_error
118+
GET "${BemanOptional_depObj}"
119+
"git_repository"
120+
)
121+
if(BemanOptional_error)
122+
message(
123+
FATAL_ERROR
124+
"${BemanOptional_errorPrefix}: ${BemanOptional_error}"
125+
)
126+
endif()
127+
128+
# Get the "git_tag" field and store it in BemanOptional_tag
129+
string(
130+
JSON
131+
BemanOptional_tag
132+
ERROR_VARIABLE BemanOptional_error
133+
GET "${BemanOptional_depObj}"
134+
"git_tag"
135+
)
136+
if(BemanOptional_error)
137+
message(
138+
FATAL_ERROR
139+
"${BemanOptional_errorPrefix}: ${BemanOptional_error}"
140+
)
141+
endif()
142+
143+
if(method STREQUAL "FIND_PACKAGE")
144+
if(package_name STREQUAL BemanOptional_pkgName)
145+
string(
146+
APPEND
147+
BemanOptional_debug
148+
"Redirecting find_package calls for ${BemanOptional_pkgName} "
149+
"to FetchContent logic fetching ${BemanOptional_repo} at "
150+
"${BemanOptional_tag} according to ${BemanOptional_lockfile}."
151+
)
152+
message(STATUS "${BemanOptional_debug}")
153+
FetchContent_Declare(
154+
"${BemanOptional_name}"
155+
GIT_REPOSITORY "${BemanOptional_repo}"
156+
GIT_TAG "${BemanOptional_tag}"
157+
EXCLUDE_FROM_ALL
158+
)
159+
set(INSTALL_GTEST OFF) # Disable GoogleTest installation
160+
FetchContent_MakeAvailable("${BemanOptional_name}")
161+
162+
# Important! <PackageName>_FOUND tells CMake that `find_package` is
163+
# not needed for this package anymore
164+
message(STATUS "setting ${BemanOptional_pkgName}_FOUND to true")
165+
set("${BemanOptional_pkgName}_FOUND" TRUE PARENT_SCOPE)
166+
endif()
167+
endif()
168+
endforeach()
169+
170+
# set(GTest_FOUND TRUE PARENT_SCOPE)
171+
endfunction()
172+
173+
cmake_language(
174+
SET_DEPENDENCY_PROVIDER BemanOptional_provideDependency
175+
SUPPORTED_METHODS FIND_PACKAGE
176+
)

0 commit comments

Comments
 (0)