Skip to content

Commit 2b6cf03

Browse files
cjdbjeremy-rifkin
andauthored
adds experimental support for C++20 modules (#248)
Programmers can now use `import cpptrace;` instead of needing to include headers. Support is currently experimental. Since macros aren't exported by modules, users need to include either `<cpptrace/exceptions_macros.hpp>` or `<from_current_macros.hpp>`, depending on their needs. --------- Co-authored-by: Jeremy Rifkin <51220084+jeremy-rifkin@users.noreply.github.com>
1 parent cd73a25 commit 2b6cf03

25 files changed

+399
-127
lines changed

CMakeLists.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required(VERSION 3.14)
1+
cmake_minimum_required(VERSION 3.15...4.0)
22

33
include(cmake/PreventInSourceBuilds.cmake)
44

@@ -156,6 +156,15 @@ target_sources(
156156
src/platform/dbghelp_utils.cpp
157157
)
158158

159+
if(HAS_CXX20_MODULES)
160+
target_sources(
161+
${target_name} PUBLIC
162+
FILE_SET CXX_MODULES
163+
FILES "src/cpptrace.cppm"
164+
BASE_DIRS "src"
165+
)
166+
endif()
167+
159168
target_include_directories(
160169
${target_name}
161170
PUBLIC

ci/test-all-configs.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def build(runner: MatrixRunner):
119119
args = [
120120
"cmake",
121121
"..",
122+
"-GNinja",
122123
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
123124
f"-DCMAKE_CXX_COMPILER={matrix['compiler']}",
124125
f"-DCMAKE_C_COMPILER={get_c_compiler_counterpart(matrix['compiler'])}",
@@ -138,7 +139,7 @@ def build(runner: MatrixRunner):
138139
args.append("-DCPPTRACE_BUILD_TEST_RDYNAMIC=On")
139140
succeeded = runner.run_command(*args)
140141
if succeeded:
141-
return runner.run_command("make", "-j")
142+
return runner.run_command("ninja")
142143
else:
143144
args = [
144145
"cmake",
@@ -158,11 +159,11 @@ def build(runner: MatrixRunner):
158159
f"-DBUILD_SHARED_LIBS={matrix['shared']}"
159160
]
160161
if matrix["compiler"] == "g++":
161-
args.append("-GUnix Makefiles")
162+
args.append("-GNinja")
162163
succeeded = runner.run_command(*args)
163164
if succeeded:
164165
if matrix["compiler"] == "g++":
165-
return runner.run_command("make", "-j")
166+
return runner.run_command("ninja")
166167
else:
167168
return runner.run_command("msbuild", "cpptrace.sln")
168169
return False
@@ -173,6 +174,7 @@ def build_full_or_auto(runner: MatrixRunner):
173174
args = [
174175
"cmake",
175176
"..",
177+
"-GNinja",
176178
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
177179
f"-DCMAKE_CXX_COMPILER={matrix['compiler']}",
178180
f"-DCMAKE_C_COMPILER={get_c_compiler_counterpart(matrix['compiler'])}",
@@ -189,7 +191,7 @@ def build_full_or_auto(runner: MatrixRunner):
189191
args.append(f"{matrix['config']}")
190192
succeeded = runner.run_command(*args)
191193
if succeeded:
192-
return runner.run_command("make", "-j")
194+
return runner.run_command("ninja")
193195
else:
194196
args = [
195197
"cmake",
@@ -208,11 +210,11 @@ def build_full_or_auto(runner: MatrixRunner):
208210
if matrix["config"] != "":
209211
args.append(f"{matrix['config']}")
210212
if matrix["compiler"] == "g++":
211-
args.append("-GUnix Makefiles")
213+
args.append("-GNinja")
212214
succeeded = runner.run_command(*args)
213215
if succeeded:
214216
if matrix["compiler"] == "g++":
215-
return runner.run_command("make", "-j")
217+
return runner.run_command("ninja")
216218
else:
217219
return runner.run_command("msbuild", "cpptrace.sln")
218220
return False

cmake/Autoconfig.cmake

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,27 @@ else()
2626
check_support(HAS_STACKWALK has_stackwalk.cpp "" "dbghelp" "")
2727
endif()
2828

29+
set(HAS_CXX20_MODULES FALSE)
30+
if(CMAKE_CXX_STANDARD GREATER_EQUAL 20)
31+
# https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html#compiler-support
32+
# msvc 14.34+/19.34+
33+
# clang 16+
34+
# gcc 15 and newer
35+
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
36+
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.34)
37+
set(HAS_CXX20_MODULES TRUE)
38+
endif()
39+
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
40+
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)
41+
set(HAS_CXX20_MODULES TRUE)
42+
endif()
43+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
44+
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15.0)
45+
set(HAS_CXX20_MODULES TRUE)
46+
endif()
47+
endif()
48+
endif()
49+
2950
if(NOT WIN32 OR MINGW)
3051
check_support(HAS_BACKTRACE has_backtrace.cpp "" "backtrace" "${CPPTRACE_BACKTRACE_PATH_DEFINITION}")
3152
set(STACKTRACE_LINK_LIB "stdc++_libbacktrace")

cmake/InstallRules.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ install(
2626
COMPONENT ${package_name}_development
2727
INCLUDES #
2828
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
29+
FILE_SET CXX_MODULES
30+
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/cpptrace"
2931
)
3032

3133
# create config file that points to targets file

include/cpptrace/exceptions.hpp

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define CPPTRACE_EXCEPTIONS_HPP
33

44
#include <cpptrace/basic.hpp>
5+
#include <cpptrace/exceptions_macros.hpp>
56

67
#include <exception>
78
#include <system_error>
@@ -195,23 +196,6 @@ CPPTRACE_BEGIN_NAMESPACE
195196
[[noreturn]] CPPTRACE_EXPORT void rethrow_and_wrap_if_needed(std::size_t skip = 0);
196197
CPPTRACE_END_NAMESPACE
197198

198-
// Exception wrapper utilities
199-
#define CPPTRACE_WRAP_BLOCK(statements) do { \
200-
try { \
201-
statements \
202-
} catch(...) { \
203-
::cpptrace::rethrow_and_wrap_if_needed(); \
204-
} \
205-
} while(0)
206-
207-
#define CPPTRACE_WRAP(expression) [&] () -> decltype((expression)) { \
208-
try { \
209-
return expression; \
210-
} catch(...) { \
211-
::cpptrace::rethrow_and_wrap_if_needed(1); \
212-
} \
213-
} ()
214-
215199
#ifdef _MSC_VER
216200
#pragma warning(pop)
217201
#endif
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef CPPTRACE_EXCEPTIONS_MACROS_HPP
2+
#define CPPTRACE_EXCEPTIONS_MACROS_HPP
3+
4+
// Exception wrapper utilities
5+
#define CPPTRACE_WRAP_BLOCK(statements) do { \
6+
try { \
7+
statements \
8+
} catch(...) { \
9+
::cpptrace::rethrow_and_wrap_if_needed(); \
10+
} \
11+
} while(0)
12+
13+
#define CPPTRACE_WRAP(expression) [&] () -> decltype((expression)) { \
14+
try { \
15+
return expression; \
16+
} catch(...) { \
17+
::cpptrace::rethrow_and_wrap_if_needed(1); \
18+
} \
19+
} ()
20+
21+
#endif // CPPTRACE_EXCEPTIONS_MACROS_HPP

include/cpptrace/from_current.hpp

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,7 @@
1010
#endif
1111

1212
#include <cpptrace/basic.hpp>
13-
14-
// https://godbolt.org/z/4MsT6KqP1
15-
#ifdef _MSC_VER
16-
#define CPPTRACE_UNREACHABLE() __assume(false)
17-
#else
18-
#define CPPTRACE_UNREACHABLE() __builtin_unreachable()
19-
#endif
20-
21-
// https://godbolt.org/z/7neGPEche
22-
// gcc added support in 4.8 but I'm too lazy to check the minor version
23-
#if defined(__GNUC__) && (__GNUC__ < 5)
24-
#define CPPTRACE_NORETURN __attribute__((noreturn))
25-
#else
26-
#define CPPTRACE_NORETURN [[noreturn]]
27-
#endif
13+
#include <cpptrace/from_current_macros.hpp>
2814

2915
CPPTRACE_BEGIN_NAMESPACE
3016
CPPTRACE_EXPORT const raw_trace& raw_trace_from_current_exception();
@@ -100,39 +86,7 @@ CPPTRACE_BEGIN_NAMESPACE
10086
inline void nop(int) {}
10187
#endif
10288
}
103-
CPPTRACE_END_NAMESPACE
10489

105-
#ifdef _MSC_VER
106-
#define CPPTRACE_TYPE_FOR(param) \
107-
::cpptrace::detail::argument<void(param)>::type
108-
// this awful double-IILE is due to C2713 "You can't use structured exception handling (__try/__except) and C++
109-
// exception handling (try/catch) in the same function."
110-
#define CPPTRACE_TRY \
111-
try { \
112-
[&]() { \
113-
__try { \
114-
[&]() {
115-
#define CPPTRACE_CATCH(param) \
116-
}(); \
117-
} __except(::cpptrace::detail::exception_filter<CPPTRACE_TYPE_FOR(param)>(GetExceptionInformation())) {} \
118-
}(); \
119-
} catch(param)
120-
#else
121-
#define CPPTRACE_UNWIND_INTERCEPTOR_FOR(param) \
122-
::cpptrace::detail::unwind_interceptor_for<void(param)>
123-
#define CPPTRACE_TRY \
124-
try { \
125-
try {
126-
#define CPPTRACE_CATCH(param) \
127-
} catch(const CPPTRACE_UNWIND_INTERCEPTOR_FOR(param)&) { \
128-
CPPTRACE_UNREACHABLE(); \
129-
/* force instantiation of the init-er */ \
130-
::cpptrace::detail::nop(CPPTRACE_UNWIND_INTERCEPTOR_FOR(param)::init); \
131-
} \
132-
} catch(param)
133-
#endif
134-
135-
CPPTRACE_BEGIN_NAMESPACE
13690
namespace detail {
13791
template<typename R, typename Arg>
13892
Arg get_callable_argument_helper(R(*) (Arg));
@@ -194,9 +148,4 @@ CPPTRACE_BEGIN_NAMESPACE
194148
}
195149
CPPTRACE_END_NAMESPACE
196150

197-
#ifdef CPPTRACE_UNPREFIXED_TRY_CATCH
198-
#define TRY CPPTRACE_TRY
199-
#define CATCH(param) CPPTRACE_CATCH(param)
200-
#endif
201-
202151
#endif
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#ifndef CPPTRACE_FROM_CURRENT_MACROS_HPP
2+
#define CPPTRACE_FROM_CURRENT_MACROS_HPP
3+
4+
// https://godbolt.org/z/4MsT6KqP1
5+
#ifdef _MSC_VER
6+
#define CPPTRACE_UNREACHABLE() __assume(false)
7+
#else
8+
#define CPPTRACE_UNREACHABLE() __builtin_unreachable()
9+
#endif
10+
11+
// https://godbolt.org/z/7neGPEche
12+
// gcc added support in 4.8 but I'm too lazy to check the minor version
13+
#if defined(__GNUC__) && (__GNUC__ < 5)
14+
#define CPPTRACE_NORETURN __attribute__((noreturn))
15+
#else
16+
#define CPPTRACE_NORETURN [[noreturn]]
17+
#endif
18+
19+
#ifdef _MSC_VER
20+
#define CPPTRACE_TYPE_FOR(param) \
21+
::cpptrace::detail::argument<void(param)>::type
22+
// this awful double-IILE is due to C2713 "You can't use structured exception handling (__try/__except) and C++
23+
// exception handling (try/catch) in the same function."
24+
#define CPPTRACE_TRY \
25+
try { \
26+
[&]() { \
27+
__try { \
28+
[&]() {
29+
#define CPPTRACE_CATCH(param) \
30+
}(); \
31+
} __except(::cpptrace::detail::exception_filter<CPPTRACE_TYPE_FOR(param)>(GetExceptionInformation())) {} \
32+
}(); \
33+
} catch(param)
34+
#else
35+
#define CPPTRACE_UNWIND_INTERCEPTOR_FOR(param) \
36+
::cpptrace::detail::unwind_interceptor_for<void(param)>
37+
#define CPPTRACE_TRY \
38+
try { \
39+
try {
40+
#define CPPTRACE_CATCH(param) \
41+
} catch(const CPPTRACE_UNWIND_INTERCEPTOR_FOR(param)&) { \
42+
CPPTRACE_UNREACHABLE(); \
43+
/* force instantiation of the init-er */ \
44+
::cpptrace::detail::nop(CPPTRACE_UNWIND_INTERCEPTOR_FOR(param)::init); \
45+
} \
46+
} catch(param)
47+
#endif
48+
49+
#ifdef CPPTRACE_UNPREFIXED_TRY_CATCH
50+
#define TRY CPPTRACE_TRY
51+
#define CATCH(param) CPPTRACE_CATCH(param)
52+
#endif
53+
54+
#endif // CPPTRACE_FROM_CURRENT_MACROS_HPP

0 commit comments

Comments
 (0)