Skip to content

Commit b716587

Browse files
authored
Merge pull request #34 from bemanproject/33-module-for-beman-scope
add module file for scope and modular example
2 parents 0b4314c + 0f4fd2e commit b716587

File tree

8 files changed

+180
-25
lines changed

8 files changed

+180
-25
lines changed

.github/workflows/ci_tests.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
- name: Setup build environment
2828
uses: lukka/get-cmake@latest
2929
with:
30-
cmakeVersion: "~3.25.0"
30+
cmakeVersion: "~3.28.0"
3131
ninjaVersion: "^1.11.1"
3232
- name: Setup MSVC
3333
if: startsWith(matrix.presets.platform, 'windows')
@@ -80,7 +80,7 @@ jobs:
8080
- name: Install Ninja
8181
uses: lukka/get-cmake@latest
8282
with:
83-
cmakeVersion: "~3.25.0"
83+
cmakeVersion: "~4.0.0"
8484
ninjaVersion: "^1.11.1"
8585
- name: Setup MSVC
8686
if: startsWith(matrix.platform.os, 'windows')
@@ -139,7 +139,7 @@ jobs:
139139
- name: Setup build environment
140140
uses: lukka/get-cmake@latest
141141
with:
142-
cmakeVersion: "~3.25.0"
142+
cmakeVersion: "~3.28.0"
143143
ninjaVersion: "^1.11.1"
144144
- name: Print installed softwares
145145
run: |
@@ -183,7 +183,7 @@ jobs:
183183
- name: Setup build environment
184184
uses: lukka/get-cmake@latest
185185
with:
186-
cmakeVersion: "~3.25.0"
186+
cmakeVersion: "~4.0.0"
187187
ninjaVersion: "^1.11.1"
188188
- name: Install Compiler
189189
id: install-compiler

.github/workflows/pre-commit.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,4 @@ jobs:
7373
with:
7474
tool_name: pre-commit
7575
level: warning
76-
reviewdog_flags: "-fail-level=none"
76+
reviewdog_flags: "-fail-level=error"

CMakeLists.txt

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
22

3-
cmake_minimum_required(VERSION 3.25)
3+
cmake_minimum_required(VERSION 3.28)
44

55
project(
66
beman.scope
@@ -9,6 +9,19 @@ project(
99
VERSION 0.0.1
1010
)
1111

12+
# gersemi: off
13+
14+
# Modules opt in only on compilers that support g++-15 and clang-20+
15+
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 20)
16+
set(CMAKE_CXX_SCAN_FOR_MODULES 1)
17+
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15)
18+
set(CMAKE_CXX_SCAN_FOR_MODULES 1)
19+
elseif()
20+
set(CMAKE_CXX_SCAN_FOR_MODULES 0)
21+
endif()
22+
23+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
24+
1225
# [CMAKE.SKIP_TESTS]
1326
option(
1427
BEMAN_SCOPE_BUILD_TESTS
@@ -29,35 +42,61 @@ option(
2942
${PROJECT_IS_TOP_LEVEL}
3043
)
3144

32-
add_library(beman.scope INTERFACE)
45+
message(
46+
"Compiler is: ${CMAKE_CXX_COMPILER_ID} version: ${CMAKE_CXX_COMPILER_VERSION}"
47+
)
48+
message(
49+
"cmake is: ${CMAKE_VERSION} modules scan : ${CMAKE_CXX_SCAN_FOR_MODULES}"
50+
)
51+
52+
if(CMAKE_CXX_SCAN_FOR_MODULES)
53+
add_library(beman.scope)
54+
target_sources(
55+
beman.scope
56+
PUBLIC
57+
FILE_SET HEADERS
58+
BASE_DIRS include
59+
FILES include/beman/scope/scope.hpp
60+
PUBLIC
61+
FILE_SET CXX_MODULES
62+
BASE_DIRS include
63+
FILES include/beman/scope/beman.scope.cppm
64+
)
65+
else()
66+
add_library(beman.scope INTERFACE)
67+
target_sources(
68+
beman.scope
69+
INTERFACE
70+
FILE_SET HEADERS
71+
BASE_DIRS include
72+
FILES include/beman/scope/scope.hpp
73+
)
74+
endif()
75+
3376
add_library(beman::scope ALIAS beman.scope)
3477

35-
# gersemi: off
3678
set_target_properties(
3779
beman.scope
3880
PROPERTIES
3981
VERIFY_INTERFACE_HEADER_SETS ON
4082
EXPORT_NAME scope
4183
)
4284

43-
target_sources(
44-
beman.scope
45-
INTERFACE
46-
FILE_SET HEADERS
47-
BASE_DIRS include
48-
FILES include/beman/scope/scope.hpp
49-
)
85+
include(GNUInstallDirs)
5086

5187
install(
5288
TARGETS beman.scope
53-
EXPORT beman.scope-targets
5489
COMPONENT beman.scope
90+
EXPORT beman.scope-targets
91+
92+
FILE_SET CXX_MODULES
93+
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
5594
FILE_SET HEADERS
5695
)
96+
5797
# gersemi: on
5898

5999
if(BEMAN_SCOPE_INSTALL_CONFIG_FILE_PACKAGE)
60-
include(GNUInstallDirs)
61100
include(CMakePackageConfigHelpers)
62101

63102
write_basic_package_version_file(
@@ -77,6 +116,7 @@ if(BEMAN_SCOPE_INSTALL_CONFIG_FILE_PACKAGE)
77116
EXPORT beman.scope-targets
78117
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/beman.scope
79118
NAMESPACE beman::
119+
CXX_MODULES_DIRECTORY cxx-modules
80120
COMPONENT beman.scope
81121
)
82122
endif()

README.md

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,23 +85,32 @@ Full runnable examples can be found in `examples/`.
8585
## Integrate beman.scope into your project
8686

8787
Beman.scope is a header-only library that currently relies on TS implementations
88-
and is thus currently available only on GCC13 and up, or Clang 19 and up -- in C++20 mode.
88+
and is thus currently available only on g++-13 and up, or clang 19 and up -- in C++20 mode.
89+
90+
Note that modules support is currently tested only on clang++-19 and above and g++-15.
8991

9092
As a header only library no building is required to use in a project -- simply make
9193
the `include` directory available add add the following to your source.
9294

9395
```cpp
9496
#include <beman/scope/scope.hpp>
97+
98+
//modular version
99+
100+
import beman.scope;
95101
```
102+
Withmodules import needs to be after any includes to avoid compilation errors.
96103

97104
## Building beman.scope
98105

99-
Building is only required to run tests and examples.
106+
Building is only required to run tests and examples. All compilers build and
107+
run `include` based tests. Compilers known to support modules are automatically
108+
detected added to tests.
100109

101110
### Build Dependencies
102111

103-
The library itself has no build dependencies other than Catch2 for testing
104-
and cmake.
112+
The library itself has no build dependencies other than Catch2 for testing.
113+
And for building cmake and ninja. Makefiles are supported in non-modular builds.
105114

106115
Build-time dependencies:
107116

@@ -110,14 +119,21 @@ Build-time dependencies:
110119
- CMake defaults to "Unix Makefiles" on POSIX systems
111120
- `catch2` for building tests
112121

113-
### How to build beman.scope
122+
### How to build beman.scope tests and examples
123+
124+
from root of repo:
114125

115126
```shell
116-
cmake --workflow --preset gcc-debug
127+
mkdir build; cd build;
128+
cmake .. -DCMAKE_CXX_COMPILER=g++-15 -DCMAKE_CXX_STANDARD=26 -G=Ninja
129+
ninja -j 5 -v; ctest
130+
```
131+
132+
or using cmake presets
133+
```shell
117134
cmake --workflow --preset gcc-release
118135
cmake --install build/gcc-release --prefix /opt/beman.scope
119136
```
120-
121137
# License
122138

123139
Source is licensed with the Apache 2.0 license with LLVM exceptions

examples/scope-module.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2+
3+
// This example uses c++20 modules with beman.scope
4+
//
5+
// The following are by hand instructions for compiling with g++-15
6+
// first line generates gcm.cache file for standard headers - one time only
7+
// g++-15 -std=c++26 -O2 -fmodules -fsearch-include-path -fmodule-only -c bits/std.cc
8+
// g++-15 -std=c++26 -O2 -fmodules -fmodule-only -c ${scope_top}/include/beman/scope/beman.scope.cppm
9+
// g++-15 -std=c++26 -fmodules scope-module.cpp
10+
//
11+
// prints:
12+
// --> scope start
13+
// construct noisy
14+
// --> scope end
15+
// destroy noisy
16+
// scope exit: true success: true fail: false
17+
18+
import std;
19+
import beman.scope;
20+
21+
// clang-format off
22+
struct noisy_resource {
23+
noisy_resource() { std::print( "construct noisy\n" ); }
24+
~noisy_resource() { std::print( "destroy noisy\n" ); }
25+
};
26+
27+
int main() {
28+
29+
bool exit_ran, success_ran, fail_ran = false;
30+
{
31+
std::print("--> scope start\n");
32+
beman::scope::scope_exit _([&exit_ran] { exit_ran = true; });
33+
beman::scope::scope_success _([&success_ran] { success_ran = true; });
34+
beman::scope::scope_fail _([&fail_ran] { fail_ran = true; });
35+
auto resource_ptr = beman::scope::unique_resource(new noisy_resource(),
36+
// Cleanup function
37+
[](noisy_resource* ptr) { delete ptr; });
38+
std::print("--> scope end\n");
39+
} // Normal scope exit
40+
41+
std::print("scope exit: {} success: {} fail: {} \n", exit_ran, success_ran, fail_ran);
42+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2+
// create the beman.scope.gcm in gcm.cache directory
3+
// g++-15 -std=c++26 -O2 -fmodules -fmodule-only -c ${scopetop}/include/beman/scope/beman.scope.cppm
4+
module;
5+
6+
#include "scope.hpp"
7+
8+
export module beman.scope;
9+
10+
export namespace beman::scope {
11+
using ::beman::scope::scope_exit;
12+
using ::beman::scope::scope_fail;
13+
using ::beman::scope::scope_success;
14+
using ::beman::scope::unique_resource;
15+
} // namespace beman::scope

tests/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ FetchContent_Declare(
99
)
1010
FetchContent_MakeAvailable(Catch2)
1111

12-
set(ALL_TESTNAMES scope_success scope_exit scope_fail unique_resource)
12+
# module tests will only compile with gcc15 or clang20 and above
13+
if(CMAKE_CXX_SCAN_FOR_MODULES)
14+
set(ALL_TESTNAMES scope_success scope_exit scope_fail unique_resource module)
15+
else()
16+
set(ALL_TESTNAMES scope_success scope_exit scope_fail unique_resource)
17+
endif()
1318

1419
message("Tests to be built: ${ALL_TESTNAMES}")
1520

tests/module.test.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2+
3+
#define CATCH_CONFIG_MAIN
4+
#include <catch2/catch_all.hpp>
5+
6+
// for g++-15 the order is important -- import after includes
7+
import beman.scope;
8+
9+
struct DummyResource {
10+
bool& cleaned;
11+
12+
DummyResource(bool& flag) : cleaned(flag) { cleaned = false; }
13+
14+
bool is_clean() const { return cleaned; }
15+
};
16+
17+
TEST_CASE("module-test", "[scope_module_test]") {
18+
bool exit_ran, success_ran, fail_ran = false;
19+
bool cleaned = true;
20+
{
21+
// clang-format off
22+
beman::scope::scope_exit _se([&exit_ran] { exit_ran = true; });
23+
beman::scope::scope_success _ss([&success_ran] { success_ran = true; });
24+
beman::scope::scope_fail _sf([&fail_ran] { fail_ran = true; });
25+
auto resource_ptr = beman::scope::unique_resource(new DummyResource(cleaned),
26+
[](DummyResource* ptr) { ptr->cleaned =true; delete ptr; });
27+
REQUIRE(cleaned == false);
28+
REQUIRE(resource_ptr->is_clean() == false);
29+
// clang-format on
30+
} // Normal scope exit
31+
32+
REQUIRE(exit_ran == true);
33+
REQUIRE(success_ran == true);
34+
REQUIRE(fail_ran == false);
35+
REQUIRE(cleaned == true);
36+
37+
}

0 commit comments

Comments
 (0)