Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
cc_library(
name = "cpptrace",
srcs = glob([
"src/**/*.hpp",
"src/**/*.cpp",
]),
srcs = glob(
[
"src/**/*.hpp",
"src/**/*.cpp",
],
exclude=["src/cpptrace_modules.cpp"] # Disabled until https://github.com/bazelbuild/bazel/pull/19940
),
local_defines = [
"CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
"CPPTRACE_DEMANGLE_WITH_CXXABI",
Expand Down
10 changes: 9 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.14)
cmake_minimum_required(VERSION 3.15...4.0)

include(cmake/PreventInSourceBuilds.cmake)

Expand Down Expand Up @@ -156,6 +156,14 @@ target_sources(
src/platform/dbghelp_utils.cpp
)

if(HAS_CXX20_MODULES)
target_sources(
${target_name} PUBLIC
FILE_SET CXX_MODULES
FILES "src/cpptrace_module.cpp"
)
endif()

target_include_directories(
${target_name}
PUBLIC
Expand Down
14 changes: 8 additions & 6 deletions ci/test-all-configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ def build(runner: MatrixRunner):
args = [
"cmake",
"..",
"-GNinja",
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
f"-DCMAKE_CXX_COMPILER={matrix['compiler']}",
f"-DCMAKE_C_COMPILER={get_c_compiler_counterpart(matrix['compiler'])}",
Expand All @@ -138,7 +139,7 @@ def build(runner: MatrixRunner):
args.append("-DCPPTRACE_BUILD_TEST_RDYNAMIC=On")
succeeded = runner.run_command(*args)
if succeeded:
return runner.run_command("make", "-j")
return runner.run_command("ninja")
else:
args = [
"cmake",
Expand All @@ -158,11 +159,11 @@ def build(runner: MatrixRunner):
f"-DBUILD_SHARED_LIBS={matrix['shared']}"
]
if matrix["compiler"] == "g++":
args.append("-GUnix Makefiles")
args.append("-GNinja")
succeeded = runner.run_command(*args)
if succeeded:
if matrix["compiler"] == "g++":
return runner.run_command("make", "-j")
return runner.run_command("ninja")
else:
return runner.run_command("msbuild", "cpptrace.sln")
return False
Expand All @@ -173,6 +174,7 @@ def build_full_or_auto(runner: MatrixRunner):
args = [
"cmake",
"..",
"-GNinja",
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
f"-DCMAKE_CXX_COMPILER={matrix['compiler']}",
f"-DCMAKE_C_COMPILER={get_c_compiler_counterpart(matrix['compiler'])}",
Expand All @@ -189,7 +191,7 @@ def build_full_or_auto(runner: MatrixRunner):
args.append(f"{matrix['config']}")
succeeded = runner.run_command(*args)
if succeeded:
return runner.run_command("make", "-j")
return runner.run_command("ninja")
else:
args = [
"cmake",
Expand All @@ -208,11 +210,11 @@ def build_full_or_auto(runner: MatrixRunner):
if matrix["config"] != "":
args.append(f"{matrix['config']}")
if matrix["compiler"] == "g++":
args.append("-GUnix Makefiles")
args.append("-GNinja")
succeeded = runner.run_command(*args)
if succeeded:
if matrix["compiler"] == "g++":
return runner.run_command("make", "-j")
return runner.run_command("ninja")
else:
return runner.run_command("msbuild", "cpptrace.sln")
return False
Expand Down
31 changes: 31 additions & 0 deletions cmake/Autoconfig.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,37 @@ else()
check_support(HAS_STACKWALK has_stackwalk.cpp "" "dbghelp" "")
endif()

if(CMAKE_CXX_STANDARD GREATER_EQUAL 20)
# # check_cxx_source_compiles doesn't support modules (yet?) so we need to drop
# # to a raw try_compile.
# try_compile(
# HAS_CXX20_MODULES
# SOURCES_TYPE CXX_MODULE
# SOURCES "${CMAKE_CURRENT_LIST_DIR}/has_modules.cpp"
# CXX_STANDARD 20
# CXX_STANDARD_REQUIRED Yes
# CXX_EXTENSIONS Yes
# )
# https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html#compiler-support
# msvc 14.34+/19.34+
# clang 16+
# gcc 15 and newer
set(HAS_CXX20_MODULES FALSE)
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.34)
set(HAS_CXX20_MODULES TRUE)
endif()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)
set(HAS_CXX20_MODULES TRUE)
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15.0)
set(HAS_CXX20_MODULES TRUE)
endif()
endif()
endif()

if(NOT WIN32 OR MINGW)
check_support(HAS_BACKTRACE has_backtrace.cpp "" "backtrace" "${CPPTRACE_BACKTRACE_PATH_DEFINITION}")
set(STACKTRACE_LINK_LIB "stdc++_libbacktrace")
Expand Down
1 change: 1 addition & 0 deletions cmake/InstallRules.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ install(
ARCHIVE #
COMPONENT ${package_name}_development
INCLUDES #
FILE_SET CXX_MODULES
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with this option but I'll trust this does something reasonable :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This installs the module interface unit :)

DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)

Expand Down
4 changes: 4 additions & 0 deletions cmake/has_modules.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export module cpptrace;

int main()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note main is not by current standard allowed to be attached to a named module and at least GCC15 will diagnose this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was surprised this worked at all. The correct thing to do was to add -fsyntax-only to the try_compile job, but I think this file is redundant now anyway.

{}
18 changes: 1 addition & 17 deletions include/cpptrace/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define CPPTRACE_EXCEPTIONS_HPP

#include <cpptrace/basic.hpp>
#include <cpptrace/exceptions_macros.hpp>

#include <exception>
#include <system_error>
Expand Down Expand Up @@ -195,23 +196,6 @@ CPPTRACE_BEGIN_NAMESPACE
[[noreturn]] CPPTRACE_EXPORT void rethrow_and_wrap_if_needed(std::size_t skip = 0);
CPPTRACE_END_NAMESPACE

// Exception wrapper utilities
#define CPPTRACE_WRAP_BLOCK(statements) do { \
try { \
statements \
} catch(...) { \
::cpptrace::rethrow_and_wrap_if_needed(); \
} \
} while(0)

#define CPPTRACE_WRAP(expression) [&] () -> decltype((expression)) { \
try { \
return expression; \
} catch(...) { \
::cpptrace::rethrow_and_wrap_if_needed(1); \
} \
} ()

#ifdef _MSC_VER
#pragma warning(pop)
#endif
Expand Down
21 changes: 21 additions & 0 deletions include/cpptrace/exceptions_macros.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef CPPTRACE_EXCEPTIONS_MACROS_HPP
#define CPPTRACE_EXCEPTIONS_MACROS_HPP

// Exception wrapper utilities
#define CPPTRACE_WRAP_BLOCK(statements) do { \
try { \
statements \
} catch(...) { \
::cpptrace::rethrow_and_wrap_if_needed(); \
} \
} while(0)

#define CPPTRACE_WRAP(expression) [&] () -> decltype((expression)) { \
try { \
return expression; \
} catch(...) { \
::cpptrace::rethrow_and_wrap_if_needed(1); \
} \
} ()

#endif // CPPTRACE_EXCEPTIONS_MACROS_HPP
53 changes: 1 addition & 52 deletions include/cpptrace/from_current.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,7 @@
#endif

#include <cpptrace/basic.hpp>

// https://godbolt.org/z/4MsT6KqP1
#ifdef _MSC_VER
#define CPPTRACE_UNREACHABLE() __assume(false)
#else
#define CPPTRACE_UNREACHABLE() __builtin_unreachable()
#endif

// https://godbolt.org/z/7neGPEche
// gcc added support in 4.8 but I'm too lazy to check the minor version
#if defined(__GNUC__) && (__GNUC__ < 5)
#define CPPTRACE_NORETURN __attribute__((noreturn))
#else
#define CPPTRACE_NORETURN [[noreturn]]
#endif
#include <cpptrace/from_current_macros.hpp>

CPPTRACE_BEGIN_NAMESPACE
CPPTRACE_EXPORT const raw_trace& raw_trace_from_current_exception();
Expand Down Expand Up @@ -100,39 +86,7 @@ CPPTRACE_BEGIN_NAMESPACE
inline void nop(int) {}
#endif
}
CPPTRACE_END_NAMESPACE

#ifdef _MSC_VER
#define CPPTRACE_TYPE_FOR(param) \
::cpptrace::detail::argument<void(param)>::type
// this awful double-IILE is due to C2713 "You can't use structured exception handling (__try/__except) and C++
// exception handling (try/catch) in the same function."
#define CPPTRACE_TRY \
try { \
[&]() { \
__try { \
[&]() {
#define CPPTRACE_CATCH(param) \
}(); \
} __except(::cpptrace::detail::exception_filter<CPPTRACE_TYPE_FOR(param)>(GetExceptionInformation())) {} \
}(); \
} catch(param)
#else
#define CPPTRACE_UNWIND_INTERCEPTOR_FOR(param) \
::cpptrace::detail::unwind_interceptor_for<void(param)>
#define CPPTRACE_TRY \
try { \
try {
#define CPPTRACE_CATCH(param) \
} catch(const CPPTRACE_UNWIND_INTERCEPTOR_FOR(param)&) { \
CPPTRACE_UNREACHABLE(); \
/* force instantiation of the init-er */ \
::cpptrace::detail::nop(CPPTRACE_UNWIND_INTERCEPTOR_FOR(param)::init); \
} \
} catch(param)
#endif

CPPTRACE_BEGIN_NAMESPACE
namespace detail {
template<typename R, typename Arg>
Arg get_callable_argument_helper(R(*) (Arg));
Expand Down Expand Up @@ -194,9 +148,4 @@ CPPTRACE_BEGIN_NAMESPACE
}
CPPTRACE_END_NAMESPACE

#ifdef CPPTRACE_UNPREFIXED_TRY_CATCH
#define TRY CPPTRACE_TRY
#define CATCH(param) CPPTRACE_CATCH(param)
#endif

#endif
54 changes: 54 additions & 0 deletions include/cpptrace/from_current_macros.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#ifndef CPPTRACE_FROM_CURRENT_MACROS_HPP
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, is there a sensible way to make either of the following work instead of a new macros header?

#include <cpptrace/from_current.hpp>
import cpptrace;
// or
import cpptrace;
#include <cpptrace/from_current.hpp>

If a macros header is the best way to do this I think it's good with me - and I'm guessing if so other libraries might follow the same pattern. But I'd love to be able to keep #include <cpptrace/from_current.hpp> under modules if possible as that is currently in a sense part of the library interface.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do the former, but not the latter (yet). Having said that, including cpptrace/from_current.hpp will undo some or all of the hard work that modules is accomplishing. I'm not aware of a better way to import macros from a module library than to do

#include <cpptrace/from_current_macros.hpp>

import cpptrace;

Once support for modules stabilises, I'd recommend the docs encourage header users not include the _macros.hpp headers, and instead just stick with the original headers (which export the macros).

#define CPPTRACE_FROM_CURRENT_MACROS_HPP

// https://godbolt.org/z/4MsT6KqP1
#ifdef _MSC_VER
#define CPPTRACE_UNREACHABLE() __assume(false)
#else
#define CPPTRACE_UNREACHABLE() __builtin_unreachable()
#endif

// https://godbolt.org/z/7neGPEche
// gcc added support in 4.8 but I'm too lazy to check the minor version
#if defined(__GNUC__) && (__GNUC__ < 5)
#define CPPTRACE_NORETURN __attribute__((noreturn))
#else
#define CPPTRACE_NORETURN [[noreturn]]
#endif

#ifdef _MSC_VER
#define CPPTRACE_TYPE_FOR(param) \
::cpptrace::detail::argument<void(param)>::type
// this awful double-IILE is due to C2713 "You can't use structured exception handling (__try/__except) and C++
// exception handling (try/catch) in the same function."
#define CPPTRACE_TRY \
try { \
[&]() { \
__try { \
[&]() {
#define CPPTRACE_CATCH(param) \
}(); \
} __except(::cpptrace::detail::exception_filter<CPPTRACE_TYPE_FOR(param)>(GetExceptionInformation())) {} \
}(); \
} catch(param)
#else
#define CPPTRACE_UNWIND_INTERCEPTOR_FOR(param) \
::cpptrace::detail::unwind_interceptor_for<void(param)>
#define CPPTRACE_TRY \
try { \
try {
#define CPPTRACE_CATCH(param) \
} catch(const CPPTRACE_UNWIND_INTERCEPTOR_FOR(param)&) { \
CPPTRACE_UNREACHABLE(); \
/* force instantiation of the init-er */ \
::cpptrace::detail::nop(CPPTRACE_UNWIND_INTERCEPTOR_FOR(param)::init); \
} \
} catch(param)
#endif

#ifdef CPPTRACE_UNPREFIXED_TRY_CATCH
#define TRY CPPTRACE_TRY
#define CATCH(param) CPPTRACE_CATCH(param)
#endif

#endif // CPPTRACE_FROM_CURRENT_MACROS_HPP
Loading
Loading