diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0492697..59a912b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,15 +1,24 @@
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.14)
-if(${CMAKE_VERSION} VERSION_LESS 3.12)
- cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
-endif()
+include(cmake/PreventInSourceBuilds.cmake)
+
+# ---- Initialize Project ----
+
+# Used to support find_package
+set(package_name "cpptrace")
project(
cpptrace
VERSION 0.2.1
+ DESCRIPTION "Simple, portable, and self-contained stacktrace library for C++11 and newer "
+ HOMEPAGE_URL "https://github.com/jeremy-rifkin/cpptrace"
LANGUAGES C CXX
)
+# Don't change include order, OptionVariables checks if project is top level
+include(cmake/ProjectIsTopLevel.cmake)
+include(cmake/OptionVariables.cmake)
+
include(GNUInstallDirs)
include(CheckCXXSourceCompiles)
include(CheckCXXCompilerFlag)
@@ -22,47 +31,6 @@ if(CMAKE_GENERATOR STREQUAL "Ninja")
endif()
endif()
-option(CPPTRACE_STATIC "" OFF)
-
-option(CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE "" OFF)
-option(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF "" OFF)
-option(CPPTRACE_GET_SYMBOLS_WITH_LIBDL "" OFF)
-option(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE "" OFF)
-option(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP "" OFF)
-option(CPPTRACE_GET_SYMBOLS_WITH_NOTHING "" OFF)
-
-option(CPPTRACE_UNWIND_WITH_UNWIND "" OFF)
-option(CPPTRACE_UNWIND_WITH_EXECINFO "" OFF)
-option(CPPTRACE_UNWIND_WITH_WINAPI "" OFF)
-option(CPPTRACE_UNWIND_WITH_DBGHELP "" OFF)
-option(CPPTRACE_UNWIND_WITH_NOTHING "" OFF)
-
-option(CPPTRACE_DEMANGLE_WITH_CXXABI "" OFF)
-option(CPPTRACE_DEMANGLE_WITH_WINAPI "" OFF)
-option(CPPTRACE_DEMANGLE_WITH_NOTHING "" OFF)
-
-set(CPPTRACE_BACKTRACE_PATH "" CACHE STRING "Path to backtrace.h, if the compiler doesn't already know it. Check /usr/lib/gcc/x86_64-linux-gnu/*/include.")
-set(CPPTRACE_HARD_MAX_FRAMES "" CACHE STRING "Hard limit on unwinding depth. Default is 100.")
-set(CPPTRACE_ADDR2LINE_PATH "" CACHE STRING "Absolute path to the addr2line executable you want to use.")
-option(CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH "" OFF)
-
-option(CPPTRACE_BUILD_TEST "" OFF)
-option(CPPTRACE_BUILD_DEMO "" OFF)
-option(CPPTRACE_BUILD_TEST_RDYNAMIC "" OFF)
-
-option(CPPTRACE_USE_SYSTEM_LIBDWARF "" OFF)
-option(CPPTRACE_SANITIZER_BUILD "" OFF)
-
-mark_as_advanced(
- CPPTRACE_BACKTRACE_PATH
- CPPTRACE_ADDR2LINE_PATH
- CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH
- CPPTRACE_BUILD_TEST
- CPPTRACE_BUILD_DEMO
- CPPTRACE_BUILD_TEST_RDYNAMIC
- CPPTRACE_SANITIZER_BUILD
-)
-
if(CPPTRACE_SANITIZER_BUILD)
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)
@@ -82,6 +50,7 @@ else()
set(CPPTRACE_BACKTRACE_PATH_DEFINITION "")
endif()
+# =============================================== Platform Support ===============================================
function(check_support var source includes libraries definitions)
set(CMAKE_REQUIRED_INCLUDES "${includes}")
list(APPEND CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
@@ -195,93 +164,126 @@ endif()
# =============================================== Now define the library ===============================================
-set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
+# Target that we can modify (can't modify ALIAS targets)
+# Target name should not be the same as ${PROJECT_NAME}, causes add_subdirectory issues
+set(target_name "cpptrace-lib")
+add_library(${target_name} ${build_type})
-set(
- sources
- src/cpptrace.cpp
- src/demangle/demangle_with_cxxabi.cpp
- src/demangle/demangle_with_winapi.cpp
- src/demangle/demangle_with_nothing.cpp
- src/symbols/symbols_with_addr2line.cpp
- src/symbols/symbols_with_dbghelp.cpp
- src/symbols/symbols_with_dl.cpp
- src/symbols/symbols_with_libbacktrace.cpp
- src/symbols/symbols_with_libdwarf.cpp
- src/symbols/symbols_with_nothing.cpp
- src/symbols/symbols_core.cpp
- src/unwind/unwind_with_execinfo.cpp
- src/unwind/unwind_with_nothing.cpp
- src/unwind/unwind_with_unwind.cpp
- src/unwind/unwind_with_winapi.cpp
- src/unwind/unwind_with_dbghelp.cpp
+# Alias to cause error at configuration time instead of link time if target is missing
+add_library(cpptrace::cpptrace ALIAS ${target_name})
+
+# Add /include files to target
+# This is solely for IDE benefit, doesn't affect building
+target_sources(
+ ${target_name} PRIVATE
+ include/cpptrace/cpptrace.hpp
)
-if(CPPTRACE_STATIC)
- add_library(cpptrace STATIC ${sources} include/cpptrace/cpptrace.hpp)
-else()
- add_library(cpptrace SHARED ${sources} include/cpptrace/cpptrace.hpp)
- set_property(TARGET cpptrace PROPERTY POSITION_INDEPENDENT_CODE ON)
-endif()
+# add /src files to target
+target_sources(
+ ${target_name} PRIVATE
+ # src
+ src/cpptrace.cpp
+ src/demangle/demangle_with_cxxabi.cpp
+ src/demangle/demangle_with_winapi.cpp
+ src/demangle/demangle_with_nothing.cpp
+ src/symbols/symbols_with_addr2line.cpp
+ src/symbols/symbols_with_dbghelp.cpp
+ src/symbols/symbols_with_dl.cpp
+ src/symbols/symbols_with_libbacktrace.cpp
+ src/symbols/symbols_with_libdwarf.cpp
+ src/symbols/symbols_with_nothing.cpp
+ src/symbols/symbols_core.cpp
+ src/unwind/unwind_with_execinfo.cpp
+ src/unwind/unwind_with_nothing.cpp
+ src/unwind/unwind_with_unwind.cpp
+ src/unwind/unwind_with_winapi.cpp
+ src/unwind/unwind_with_dbghelp.cpp
+)
target_include_directories(
- cpptrace
+ ${target_name}
PUBLIC
$
$
)
-# TODO
-target_compile_features(cpptrace PRIVATE cxx_range_for cxx_constexpr cxx_nullptr cxx_static_assert)
+# ---- Generate Build Info Headers ----
-set_target_properties(
- cpptrace
- PROPERTIES
- CXX_STANDARD_REQUIRED TRUE
- CXX_EXTENSIONS OFF
+# used in export header generated below
+if(NOT CPPTRACE_BUILD_SHARED)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_STATIC_DEFINE)
+endif()
+
+# generate header file with export macros prefixed with BASE_NAME
+include(GenerateExportHeader)
+generate_export_header(
+ ${target_name}
+ BASE_NAME cpptrace
+ EXPORT_FILE_NAME include/cpptrace/cpptrace_export.hpp
)
-target_compile_options(
- cpptrace
- PRIVATE
- $<$>:-Wall -Wextra -Werror=return-type -Wundef>
- $<$:-Wuseless-cast>
- $<$:/W4 /WX /permissive->
+# ---- Library Properties ----
+
+# Hide all symbols by default
+# Use SameMajorVersion versioning for shared library runtime linker lookup
+set_target_properties(
+ ${target_name} PROPERTIES
+ CXX_VISIBILITY_PRESET hidden
+ VISIBILITY_INLINES_HIDDEN YES
+ VERSION "${PROJECT_VERSION}"
+ SOVERSION "${PROJECT_VERSION_MAJOR}"
+ EXPORT_NAME "cpptrace"
+ OUTPUT_NAME "cpptrace"
+)
+
+# Header files generated by CMake
+target_include_directories(
+ ${target_name} SYSTEM PUBLIC
+ "$"
+)
+
+# Header files from /include
+target_include_directories(
+ ${target_name} ${warning_guard} PUBLIC
+ "$"
+)
+
+# Require C++11 support
+target_compile_features(
+ ${target_name}
+ PRIVATE cxx_std_11
)
# =============================================== Apply options to build ===============================================
if(HAS_CXX_EXCEPTION_TYPE)
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_HAS_CXX_EXCEPTION_TYPE)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_HAS_CXX_EXCEPTION_TYPE)
endif()
-function(check_backtrace_error)
- if(NOT HAS_BACKTRACE)
- if(NOT "${CPPTRACE_BACKTRACE_PATH}" STREQUAL "")
- message(WARNING "Cpptrace: CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE specified but libbacktrace doesn't appear installed or configured properly.")
- else()
- message(WARNING "Cpptrace: CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE specified but libbacktrace doesn't appear installed or configured properly. You may need to specify CPPTRACE_BACKTRACE_PATH.")
- endif()
- endif()
-endfunction()
-
# Symbols
if(CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE)
- check_backtrace_error()
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE)
- target_link_libraries(cpptrace PRIVATE backtrace)
+ if(NOT HAS_BACKTRACE)
+ if(NOT "${CPPTRACE_BACKTRACE_PATH}" STREQUAL "")
+ message(WARNING "Cpptrace: Using libbacktrace for symbols but libbacktrace doesn't appear installed or configured properly.")
+ else()
+ message(WARNING "Cpptrace: Using libbacktrace for symbols but libbacktrace doesn't appear installed or configured properly. You may need to specify CPPTRACE_BACKTRACE_PATH.")
+ endif()
+ endif()
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE)
+ target_link_libraries(${target_name} PRIVATE backtrace dl)
endif()
if(CPPTRACE_GET_SYMBOLS_WITH_LIBDL)
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_GET_SYMBOLS_WITH_LIBDL)
- target_link_libraries(cpptrace PRIVATE dl)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_GET_SYMBOLS_WITH_LIBDL)
+ target_link_libraries(${target_name} PRIVATE dl)
endif()
if(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE)
# set(CPPTRACE_ADDR2LINE_PATH "" CACHE STRING "Absolute path to the addr2line executable you want to use.")
# option(CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH "" OFF)
if(CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH)
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH)
else()
if("${CPPTRACE_ADDR2LINE_PATH}" STREQUAL "")
if(APPLE)
@@ -293,35 +295,46 @@ if(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE)
set(CPPTRACE_ADDR2LINE_PATH_FINAL "${CPPTRACE_ADDR2LINE_PATH}")
endif()
message(STATUS "Cpptrace: Using ${CPPTRACE_ADDR2LINE_PATH_FINAL} for addr2line path")
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_ADDR2LINE_PATH="${CPPTRACE_ADDR2LINE_PATH_FINAL}")
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_ADDR2LINE_PATH="${CPPTRACE_ADDR2LINE_PATH_FINAL}")
endif()
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE)
if(UNIX)
- target_link_libraries(cpptrace PRIVATE dl)
+ target_link_libraries(${target_name} PRIVATE dl)
endif()
endif()
if(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF)
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF)
- if(CPPTRACE_USE_SYSTEM_LIBDWARF)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF)
+ if(CPPTRACE_USE_EXTERNAL_LIBDWARF)
find_package(libdwarf REQUIRED)
- target_link_libraries(cpptrace PRIVATE libdwarf)
+ target_link_libraries(${target_name} PRIVATE libdwarf::dwarf-static)
else()
add_subdirectory(bundled/libdwarf)
- target_link_libraries(cpptrace PRIVATE dwarf)
+ target_link_libraries(${target_name} PRIVATE dwarf)
+ # set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
+ # set(PIC_ALWAYS TRUE)
+ # set(BUILD_DWARFDUMP FALSE)
+ # include(FetchContent)
+ # FetchContent_Declare(
+ # libdwarf
+ # GIT_REPOSITORY https://github.com/jeremy-rifkin/libdwarf-code.git
+ # GIT_TAG 4ca6a7bc86b27d56741923f03c15b5aa274efc28 # v0.8.0
+ # )
+ # FetchContent_MakeAvailable(libdwarf)
+ # target_link_libraries(${target_name} PRIVATE dwarf-static)
endif()
if(UNIX)
- target_link_libraries(cpptrace PRIVATE dl)
+ target_link_libraries(${target_name} PRIVATE dl)
endif()
endif()
if(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP)
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_GET_SYMBOLS_WITH_DBGHELP)
- target_link_libraries(cpptrace PRIVATE dbghelp)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_GET_SYMBOLS_WITH_DBGHELP)
+ target_link_libraries(${target_name} PRIVATE dbghelp)
endif()
if(CPPTRACE_GET_SYMBOLS_WITH_NOTHING)
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_GET_SYMBOLS_WITH_NOTHING)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_GET_SYMBOLS_WITH_NOTHING)
endif()
# Unwinding
@@ -329,30 +342,30 @@ if(CPPTRACE_UNWIND_WITH_UNWIND)
if(NOT HAS_UNWIND)
message(WARNING "Cpptrace: CPPTRACE_UNWIND_WITH_UNWIND specified but libgcc unwind doesn't seem to be available.")
endif()
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_UNWIND_WITH_UNWIND)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_UNWIND_WITH_UNWIND)
endif()
if(CPPTRACE_UNWIND_WITH_EXECINFO)
if(NOT HAS_EXECINFO)
message(WARNING "Cpptrace: CPPTRACE_UNWIND_WITH_EXECINFO specified but execinfo.h doesn't seem to be available.")
endif()
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_UNWIND_WITH_EXECINFO)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_UNWIND_WITH_EXECINFO)
endif()
if(CPPTRACE_UNWIND_WITH_WINAPI)
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_UNWIND_WITH_WINAPI)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_UNWIND_WITH_WINAPI)
endif()
if(CPPTRACE_UNWIND_WITH_DBGHELP)
if(NOT HAS_STACKWALK)
message(WARNING "Cpptrace: CPPTRACE_UNWIND_WITH_DBGHELP specified but dbghelp stackwalk64 doesn't seem to be available.")
endif()
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_UNWIND_WITH_DBGHELP)
- target_link_libraries(cpptrace PRIVATE dbghelp)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_UNWIND_WITH_DBGHELP)
+ target_link_libraries(${target_name} PRIVATE dbghelp)
endif()
if(CPPTRACE_UNWIND_WITH_NOTHING)
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_UNWIND_WITH_NOTHING)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_UNWIND_WITH_NOTHING)
endif()
# Demangling
@@ -360,100 +373,38 @@ if(CPPTRACE_DEMANGLE_WITH_CXXABI)
if(NOT HAS_CXXABI)
message(WARNING "Cpptrace: CPPTRACE_DEMANGLE_WITH_CXXABI specified but cxxabi.h doesn't seem to be available.")
endif()
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_DEMANGLE_WITH_CXXABI)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_DEMANGLE_WITH_CXXABI)
endif()
if(CPPTRACE_DEMANGLE_WITH_WINAPI)
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_DEMANGLE_WITH_WINAPI)
- target_link_libraries(cpptrace PRIVATE dbghelp)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_DEMANGLE_WITH_WINAPI)
+ target_link_libraries(${target_name} PRIVATE dbghelp)
endif()
if(CPPTRACE_DEMANGLE_WITH_NOTHING)
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_DEMANGLE_WITH_NOTHING)
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_DEMANGLE_WITH_NOTHING)
endif()
if(NOT "${CPPTRACE_BACKTRACE_PATH}" STREQUAL "")
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_BACKTRACE_PATH=${CPPTRACE_BACKTRACE_PATH})
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_BACKTRACE_PATH=${CPPTRACE_BACKTRACE_PATH})
endif()
if(NOT "${CPPTRACE_HARD_MAX_FRAMES}" STREQUAL "")
- target_compile_definitions(cpptrace PUBLIC CPPTRACE_HARD_MAX_FRAMES=${CPPTRACE_HARD_MAX_FRAMES})
+ target_compile_definitions(${target_name} PUBLIC CPPTRACE_HARD_MAX_FRAMES=${CPPTRACE_HARD_MAX_FRAMES})
endif()
-# ======================================================================================================================
+# =============================================== Install ===============================================
if(NOT CMAKE_SKIP_INSTALL_RULES)
- include(CMakePackageConfigHelpers)
-
- if(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF)
- set(CPPTRACE_STATIC_EXPORT_TARGETS cpptrace dwarf)
- else()
- set(CPPTRACE_STATIC_EXPORT_TARGETS cpptrace)
- endif()
-
- if(CPPTRACE_STATIC)
- install(
- TARGETS ${CPPTRACE_STATIC_EXPORT_TARGETS}
- EXPORT cpptrace_targets
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
- INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
- )
- else()
- install(
- TARGETS cpptrace
- EXPORT cpptrace_targets
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
- INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
- )
- endif()
-
- install(
- FILES
- include/cpptrace/cpptrace.hpp
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cpptrace
- )
-
- export(
- EXPORT cpptrace_targets
- FILE ${CMAKE_CURRENT_BINARY_DIR}/cpptrace/cpptrace_targets.cmake
- NAMESPACE cpptrace::
- )
-
- configure_package_config_file(
- cmake/cpptrace-config.cmake.in
- ${CMAKE_CURRENT_BINARY_DIR}/cpptrace/cpptrace-config.cmake
- INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpptrace
- )
-
- write_basic_package_version_file(
- ${CMAKE_CURRENT_BINARY_DIR}/cpptrace/cpptrace-config-version.cmake
- VERSION ${PACKAGE_VERSION}
- COMPATIBILITY SameMajorVersion
- )
-
- install(
- EXPORT cpptrace_targets
- FILE cpptrace_targets.cmake
- NAMESPACE cpptrace::
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpptrace
- )
-
- install(
- FILES
- ${CMAKE_CURRENT_BINARY_DIR}/cpptrace/cpptrace-config.cmake
- ${CMAKE_CURRENT_BINARY_DIR}/cpptrace/cpptrace-config-version.cmake
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpptrace
- )
+ include(cmake/InstallRules.cmake)
endif()
+# =============================================== Demo/test ===============================================
+
if(CPPTRACE_BUILD_TEST)
add_executable(test test/test.cpp)
target_compile_features(test PRIVATE cxx_range_for cxx_constexpr cxx_nullptr cxx_static_assert)
- target_link_libraries(test PRIVATE cpptrace)
+ target_link_libraries(test PRIVATE ${target_name})
# Clang has been fast to adopt dwarf 5, other tools (e.g. addr2line from binutils) have not
check_cxx_compiler_flag("-gdwarf-4" HAS_DWARF4)
if(HAS_DWARF4)
@@ -474,7 +425,7 @@ endif()
if(CPPTRACE_BUILD_DEMO)
add_executable(demo test/demo.cpp)
target_compile_features(demo PRIVATE cxx_range_for cxx_constexpr cxx_nullptr cxx_static_assert)
- target_link_libraries(demo PRIVATE cpptrace)
+ target_link_libraries(demo PRIVATE ${target_name})
# Clang has been fast to adopt dwarf 5, other tools (e.g. addr2line from binutils) have not
check_cxx_compiler_flag("-gdwarf-4" HAS_DWARF4)
if(HAS_DWARF4)
diff --git a/README.md b/README.md
index 1a36b31..790dd79 100644
--- a/README.md
+++ b/README.md
@@ -585,7 +585,7 @@ configurable with `CPPTRACE_HARD_MAX_FRAMES`.
| Library | CMake config | Platforms | Info |
| ------------ | ---------------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| libdwarf | `CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF` | linux, macos, mingw | Libdwarf is the preferred method for symbol resolution for cpptrace, and it's bundled in this repository for ease of use. |
+| libdwarf | `CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF` | linux, macos, mingw | Libdwarf is the preferred method for symbol resolution for cpptrace. Cpptrace will get it via FetchContent or find_package depending on `CPPTRACE_USE_EXTERNAL_LIBDWARF`. |
| dbghelp | `CPPTRACE_GET_SYMBOLS_WITH_DBGHELP` | windows | Dbghelp.h is the preferred method for symbol resolution on windows under msvc/clang and is supported on all windows machines. |
| libbacktrace | `CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE` | linux, macos*, mingw* | Libbacktrace is already installed on most systems or available through the compiler directly. For clang you must specify the absolute path to `backtrace.h` using `CPPTRACE_BACKTRACE_PATH`. |
| addr2line | `CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE` | linux, macos, mingw | Symbols are resolved by invoking `addr2line` (or `atos` on mac) via `fork()` (on linux/unix, and `popen` under mingw). |
@@ -634,7 +634,6 @@ Back-ends:
- `CPPTRACE_DEMANGLE_WITH_NOTHING=On/Off`
Back-end configuration:
-- `CPPTRACE_STATIC=On/Off`: Create cpptrace as a static library.
- `CPPTRACE_BACKTRACE_PATH=`: Path to libbacktrace backtrace.h, needed when compiling with clang/
- `CPPTRACE_HARD_MAX_FRAMES=`: Some back-ends write to a fixed-size buffer. This is the size of that buffer.
Default is `100`.
@@ -643,7 +642,13 @@ Back-end configuration:
injection).
- `CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH=On/Off`: Specifies whether cpptrace should let the system search the PATH
environment variable directories for the binary.
-- `CPPTRACE_USE_SYSTEM_LIBDWARF=On/Off`: Use libdwarf resolved via `find_package` rather than the bundled libdwarf.
+
+Other userufl configurations:
+- `CPPTRACE_BUILD_SHARED=On/Off`: Override for `BUILD_SHARED_LIBS`.
+- `CPPTRACE_INCLUDES_WITH_SYSTEM=On/Off`: Marks cpptrace headers as `SYSTEM` which will hide any warnings that aren't
+ the fault of your project. Defaults to On.
+- `CPPTRACE_INSTALL_CMAKEDIR`: Override for the installation path for the cmake configs.
+- `CPPTRACE_USE_EXTERNAL_LIBDWARF=On/Off`: Get libdwarf from `find_package` rather than `FetchContent`.
Testing:
- `CPPTRACE_BUILD_TEST` Build a small test program
diff --git a/bundled/libdwarf/CMakeLists.txt b/bundled/libdwarf/CMakeLists.txt
index 148e5df..d04803d 100644
--- a/bundled/libdwarf/CMakeLists.txt
+++ b/bundled/libdwarf/CMakeLists.txt
@@ -430,11 +430,17 @@ set(
libdwarf_private.h
)
+set(
+ libdwarf_export_headers
+ dwarf.h
+ libdwarf.h
+)
+
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
include(GNUInstallDirs)
-add_library(dwarf OBJECT ${libdwarf_sources} ${libdwarf_headers})
+add_library(dwarf STATIC ${libdwarf_sources} ${libdwarf_headers})
set_property(TARGET dwarf PROPERTY POSITION_INDEPENDENT_CODE ON)
target_compile_definitions(dwarf PUBLIC LIBDWARF_BUILD)
@@ -452,53 +458,53 @@ else()
endif()
# TODO: Something will have to be figured out for dynamic linking, but for now there's nothing to install
-# if(NOT CMAKE_SKIP_INSTALL_RULES)
-# include(CMakePackageConfigHelpers)
+if(NOT CMAKE_SKIP_INSTALL_RULES)
+ include(CMakePackageConfigHelpers)
-# install(
-# TARGETS dwarf
-# EXPORT libdwarf_targets
-# LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
-# INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
-# ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
-# RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
-# )
+ install(
+ TARGETS dwarf
+ EXPORT libdwarf_targets
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
-# install(
-# FILES
-# ${libdwarf_headers}
-# DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libdwarf
-# )
+ install(
+ FILES
+ ${libdwarf_export_headers}
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libdwarf
+ )
-# export(
-# EXPORT libdwarf_targets
-# FILE ${CMAKE_CURRENT_BINARY_DIR}/libdwarf/libdwarf_targets.cmake
-# NAMESPACE libdwarf::
-# )
+ export(
+ EXPORT libdwarf_targets
+ FILE ${CMAKE_CURRENT_BINARY_DIR}/libdwarf/libdwarf_targets.cmake
+ NAMESPACE libdwarf::
+ )
-# configure_package_config_file(
-# cmake/libdwarf-config.cmake.in
-# ${CMAKE_CURRENT_BINARY_DIR}/libdwarf/libdwarf-config.cmake
-# INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libdwarf
-# )
+ configure_package_config_file(
+ cmake/libdwarf-config.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}/libdwarf/libdwarf-config.cmake
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libdwarf
+ )
-# write_basic_package_version_file(
-# ${CMAKE_CURRENT_BINARY_DIR}/libdwarf/libdwarf-config-version.cmake
-# VERSION "${VERSION}"
-# COMPATIBILITY SameMajorVersion
-# )
+ write_basic_package_version_file(
+ ${CMAKE_CURRENT_BINARY_DIR}/libdwarf/libdwarf-config-version.cmake
+ VERSION "${VERSION}"
+ COMPATIBILITY SameMajorVersion
+ )
-# install(
-# EXPORT libdwarf_targets
-# FILE libdwarf_targets.cmake
-# NAMESPACE libdwarf::
-# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libdwarf
-# )
+ install(
+ EXPORT libdwarf_targets
+ FILE libdwarf_targets.cmake
+ NAMESPACE libdwarf::
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libdwarf
+ )
-# install(
-# FILES
-# ${CMAKE_CURRENT_BINARY_DIR}/libdwarf/libdwarf-config.cmake
-# ${CMAKE_CURRENT_BINARY_DIR}/libdwarf/libdwarf-config-version.cmake
-# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libdwarf
-# )
-# endif()
+ install(
+ FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/libdwarf/libdwarf-config.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/libdwarf/libdwarf-config-version.cmake
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libdwarf
+ )
+endif()
diff --git a/ci/test-all-configs.py b/ci/test-all-configs.py
index 2e02209..46c0a95 100644
--- a/ci/test-all-configs.py
+++ b/ci/test-all-configs.py
@@ -15,6 +15,9 @@ failed = False
expected_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../test/expected/")
+def get_c_compiler_counterpart(compiler: str) -> str:
+ return compiler.replace("clang++", "clang").replace("g++", "gcc")
+
MAX_LINE_DIFF = 2
def similarity(name: str, target: List[str]) -> int:
@@ -149,6 +152,7 @@ def build(matrix):
"..",
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
f"-DCMAKE_CXX_COMPILER={matrix['compiler']}",
+ f"-DCMAKE_C_COMPILER={get_c_compiler_counterpart(matrix['compiler'])}",
f"-DCMAKE_CXX_STANDARD={matrix['std']}",
f"-D{matrix['unwind']}=On",
f"-D{matrix['symbols']}=On",
@@ -167,6 +171,7 @@ def build(matrix):
"..",
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
f"-DCMAKE_CXX_COMPILER={matrix['compiler']}",
+ f"-DCMAKE_C_COMPILER={get_c_compiler_counterpart(matrix['compiler'])}",
f"-DCMAKE_CXX_STANDARD={matrix['std']}",
f"-D{matrix['unwind']}=On",
f"-D{matrix['symbols']}=On",
@@ -190,6 +195,7 @@ def build_full_or_auto(matrix):
"..",
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
f"-DCMAKE_CXX_COMPILER={matrix['compiler']}",
+ f"-DCMAKE_C_COMPILER={get_c_compiler_counterpart(matrix['compiler'])}",
f"-DCMAKE_CXX_STANDARD={matrix['std']}",
f"-DCPPTRACE_BACKTRACE_PATH=/usr/lib/gcc/x86_64-linux-gnu/10/include/backtrace.h",
"-DCPPTRACE_BUILD_TEST=On"
@@ -205,6 +211,7 @@ def build_full_or_auto(matrix):
"..",
f"-DCMAKE_BUILD_TYPE={matrix['target']}",
f"-DCMAKE_CXX_COMPILER={matrix['compiler']}",
+ f"-DCMAKE_C_COMPILER={get_c_compiler_counterpart(matrix['compiler'])}",
f"-DCMAKE_CXX_STANDARD={matrix['std']}",
"-DCPPTRACE_BUILD_TEST=On"
]
@@ -309,7 +316,8 @@ def main():
#"CPPTRACE_UNWIND_WITH_NOTHING",
],
"symbols": [
- "CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE",
+ # Disabled due to libbacktrace bug
+ # "CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE",
"CPPTRACE_GET_SYMBOLS_WITH_LIBDL",
"CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE",
"CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF",
diff --git a/cmake/InstallRules.cmake b/cmake/InstallRules.cmake
new file mode 100644
index 0000000..fa23e85
--- /dev/null
+++ b/cmake/InstallRules.cmake
@@ -0,0 +1,69 @@
+include(CMakePackageConfigHelpers)
+
+# copy header files to CMAKE_INSTALL_INCLUDEDIR
+# don't include third party header files
+install(
+ DIRECTORY
+ "${PROJECT_SOURCE_DIR}/include/" # our header files
+ "${PROJECT_BINARY_DIR}/include/" # generated header files
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+ COMPONENT ${package_name}-development
+ # PATTERN "**/third_party" EXCLUDE # skip third party directory
+ # PATTERN "**/third_party/**" EXCLUDE # skip third party files
+)
+
+# copy target build output artifacts to OS dependent locations
+# (Except includes, that just sets a compiler flag with the path)
+install(
+ TARGETS ${target_name}
+ EXPORT ${package_name}-targets
+ RUNTIME #
+ COMPONENT ${package_name}-runtime
+ LIBRARY #
+ COMPONENT ${package_name}-runtime
+ NAMELINK_COMPONENT ${package_name}-development
+ ARCHIVE #
+ COMPONENT ${package_name}-development
+ INCLUDES #
+ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+)
+
+# create config file that points to targets file
+configure_file(
+ "${PROJECT_SOURCE_DIR}/cmake/in/cpptrace-config-cmake.in"
+ "${PROJECT_BINARY_DIR}/cmake/${package_name}-config.cmake"
+ @ONLY
+)
+
+# copy config file for find_package to find
+install(
+ FILES "${PROJECT_BINARY_DIR}/cmake/${package_name}-config.cmake"
+ DESTINATION "${CPPTRACE_INSTALL_CMAKEDIR}"
+ COMPONENT ${package_name}-development
+)
+
+# create version file for consumer to check version in CMake
+write_basic_package_version_file(
+ "${package_name}-config-version.cmake"
+ COMPATIBILITY SameMajorVersion # a.k.a SemVer
+)
+
+# copy version file for find_package to find for version check
+install(
+ FILES "${PROJECT_BINARY_DIR}/${package_name}-config-version.cmake"
+ DESTINATION "${CPPTRACE_INSTALL_CMAKEDIR}"
+ COMPONENT ${package_name}-development
+)
+
+# create targets file included by config file with targets for consumers
+install(
+ EXPORT ${package_name}-targets
+ NAMESPACE cpptrace::
+ DESTINATION "${CPPTRACE_INSTALL_CMAKEDIR}"
+ COMPONENT ${package_name}-development
+)
+
+# support packaging library
+if(PROJECT_IS_TOP_LEVEL)
+ include(CPack)
+endif()
diff --git a/cmake/OptionVariables.cmake b/cmake/OptionVariables.cmake
new file mode 100644
index 0000000..239aa0e
--- /dev/null
+++ b/cmake/OptionVariables.cmake
@@ -0,0 +1,170 @@
+# Included further down to avoid interfering with our cache variables
+# include(GNUInstallDirs)
+
+# ---- Options Summary ----
+
+# ---------------------------------------------------------------------------------------------------
+# | Option | Availability | Default |
+# |=================================|===============|===============================================|
+# | BUILD_SHARED_LIBS | Top-Level | OFF |
+# | BUILD_TESTING | Top-Level | OFF |
+# | CMAKE_INSTALL_INCLUDEDIR | Top-Level | include/${package_name}-${PROJECT_VERSION} |
+# |---------------------------------|---------------|-----------------------------------------------|
+# | ASSERT_BUILD_SHARED | Always | ${BUILD_SHARED_LIBS} |
+# | ASSERT_BUILD_TESTING | Always | ${BUILD_TESTING} AND ${PROJECT_IS_TOP_LEVEL} |
+# | ASSERT_INCLUDES_WITH_SYSTEM | Not Top-Level | ON |
+# | ASSERT_INSTALL_CMAKEDIR | Always | ${CMAKE_INSTALL_LIBDIR}/cmake/${package_name} |
+# | CPPTRACE_USE_EXTERNAL_LIBDWARF | Always | OFF |
+# | ... | | |
+# ---------------------------------------------------------------------------------------------------
+
+# ---- Build Shared ----
+
+# Sometimes it's useful to be able to single out a dependency to be built as
+# static or shared, even if obtained from source
+if(PROJECT_IS_TOP_LEVEL)
+ option(BUILD_SHARED_LIBS "Build shared libs" OFF)
+endif()
+option(
+ CPPTRACE_BUILD_SHARED
+ "Override BUILD_SHARED_LIBS for ${package_name} library"
+ ${BUILD_SHARED_LIBS}
+)
+mark_as_advanced(CPPTRACE_BUILD_SHARED)
+set(build_type STATIC)
+if(CPPTRACE_BUILD_SHARED)
+ set(build_type SHARED)
+endif()
+
+# ---- Warning Guard ----
+
+# target_include_directories with SYSTEM modifier will request the compiler to
+# omit warnings from the provided paths, if the compiler supports that.
+# This is to provide a user experience similar to find_package when
+# add_subdirectory or FetchContent is used to consume this project.
+set(warning_guard )
+if(NOT PROJECT_IS_TOP_LEVEL)
+ option(
+ CPPTRACE_INCLUDES_WITH_SYSTEM
+ "Use SYSTEM modifier for ${package_name}'s includes, disabling warnings"
+ ON
+ )
+ mark_as_advanced(CPPTRACE_INCLUDES_WITH_SYSTEM)
+ if(CPPTRACE_INCLUDES_WITH_SYSTEM)
+ set(warning_guard SYSTEM)
+ endif()
+endif()
+
+# ---- Enable Testing ----
+
+# By default tests aren't enabled even with BUILD_TESTING=ON unless the library
+# is built as a top level project.
+# This is in order to cut down on unnecessary compile times, since it's unlikely
+# for users to want to run the tests of their dependencies.
+if(PROJECT_IS_TOP_LEVEL)
+ option(BUILD_TESTING "Build tests" OFF)
+endif()
+if(PROJECT_IS_TOP_LEVEL AND BUILD_TESTING)
+ set(build_testing ON)
+endif()
+option(
+ CPPTRACE_BUILD_TESTING
+ "Override BUILD_TESTING for ${package_name} library"
+ ${build_testing}
+)
+set(build_testing )
+mark_as_advanced(CPPTRACE_BUILD_TESTING)
+
+# ---- Install Include Directory ----
+
+# Adds an extra directory to the include path by default, so that when you link
+# against the target, you get `/include/` added to your
+# include paths rather than `/include`.
+# This doesn't affect include paths used by consumers of this project, but helps
+# prevent consumers having access to other projects in the same include
+# directory (e.g. usr/include).
+# The variable type is STRING rather than PATH, because otherwise passing
+# -DCMAKE_INSTALL_INCLUDEDIR=include on the command line would expand to an
+# absolute path with the base being the current CMake directory, leading to
+# unexpected errors.
+if(PROJECT_IS_TOP_LEVEL)
+ set(
+ CMAKE_INSTALL_INCLUDEDIR "include/${package_name}-${PROJECT_VERSION}"
+ CACHE STRING ""
+ )
+ # marked as advanced in GNUInstallDirs version, so we follow their lead
+ mark_as_advanced(CMAKE_INSTALL_INCLUDEDIR)
+endif()
+
+# do not include earlier or we can't set CMAKE_INSTALL_INCLUDEDIR above
+# include required for CMAKE_INSTALL_LIBDIR below
+include(GNUInstallDirs)
+
+# ---- Install CMake Directory ----
+
+# This allows package maintainers to freely override the installation path for
+# the CMake configs.
+# This doesn't affects include paths used by consumers of this project.
+# The variable type is STRING rather than PATH, because otherwise passing
+# -DCPPTRACE_INSTALL_CMAKEDIR=lib/cmake on the command line would expand to an
+# absolute path with the base being the current CMake directory, leading to
+# unexpected errors.
+set(
+ CPPTRACE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${package_name}"
+ CACHE STRING "CMake package config location relative to the install prefix"
+)
+# depends on CMAKE_INSTALL_LIBDIR which is marked as advanced in GNUInstallDirs
+mark_as_advanced(CPPTRACE_INSTALL_CMAKEDIR)
+
+# ---- Symbol Options ----
+
+option(CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE "" OFF)
+option(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF "" OFF)
+option(CPPTRACE_GET_SYMBOLS_WITH_LIBDL "" OFF)
+option(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE "" OFF)
+option(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP "" OFF)
+option(CPPTRACE_GET_SYMBOLS_WITH_NOTHING "" OFF)
+
+# ---- Unwinding Options ----
+
+option(CPPTRACE_UNWIND_WITH_UNWIND "" OFF)
+option(CPPTRACE_UNWIND_WITH_EXECINFO "" OFF)
+option(CPPTRACE_UNWIND_WITH_WINAPI "" OFF)
+option(CPPTRACE_UNWIND_WITH_DBGHELP "" OFF)
+option(CPPTRACE_UNWIND_WITH_NOTHING "" OFF)
+
+# ---- Demangling Options ----
+
+option(CPPTRACE_DEMANGLE_WITH_CXXABI "" OFF)
+option(CPPTRACE_DEMANGLE_WITH_WINAPI "" OFF)
+option(CPPTRACE_DEMANGLE_WITH_NOTHING "" OFF)
+
+# ---- Back-end configurations ----
+
+set(CPPTRACE_BACKTRACE_PATH "" CACHE STRING "Path to backtrace.h, if the compiler doesn't already know it. Check /usr/lib/gcc/x86_64-linux-gnu/*/include.")
+set(CPPTRACE_HARD_MAX_FRAMES "" CACHE STRING "Hard limit on unwinding depth. Default is 100.")
+set(CPPTRACE_ADDR2LINE_PATH "" CACHE STRING "Absolute path to the addr2line executable you want to use.")
+option(CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH "" OFF)
+
+# ---- Other configurations ----
+
+if(PROJECT_IS_TOP_LEVEL)
+ option(CPPTRACE_BUILD_TEST "" OFF)
+ option(CPPTRACE_BUILD_DEMO "" OFF)
+ option(CPPTRACE_BUILD_TEST_RDYNAMIC "" OFF)
+ mark_as_advanced(
+ CPPTRACE_BUILD_TEST
+ CPPTRACE_BUILD_DEMO
+ CPPTRACE_BUILD_TEST_RDYNAMIC
+ )
+endif()
+
+option(CPPTRACE_USE_EXTERNAL_LIBDWARF "" OFF)
+option(CPPTRACE_SANITIZER_BUILD "" OFF)
+
+mark_as_advanced(
+ CPPTRACE_BACKTRACE_PATH
+ CPPTRACE_ADDR2LINE_PATH
+ CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH
+ CPPTRACE_SANITIZER_BUILD
+)
diff --git a/cmake/PreventInSourceBuilds.cmake b/cmake/PreventInSourceBuilds.cmake
new file mode 100644
index 0000000..43113fe
--- /dev/null
+++ b/cmake/PreventInSourceBuilds.cmake
@@ -0,0 +1,8 @@
+# In-source build guard
+if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
+ message(
+ FATAL_ERROR
+ "In-source builds are not supported. "
+ "You may need to delete 'CMakeCache.txt' and 'CMakeFiles/' before rebuilding this project."
+ )
+endif()
diff --git a/cmake/ProjectIsTopLevel.cmake b/cmake/ProjectIsTopLevel.cmake
new file mode 100644
index 0000000..3435fc0
--- /dev/null
+++ b/cmake/ProjectIsTopLevel.cmake
@@ -0,0 +1,6 @@
+# This variable is set by project() in CMake 3.21+
+string(
+ COMPARE EQUAL
+ "${CMAKE_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}"
+ PROJECT_IS_TOP_LEVEL
+)
diff --git a/cmake/cpptrace-config.cmake.in b/cmake/cpptrace-config.cmake.in
deleted file mode 100644
index c84bed9..0000000
--- a/cmake/cpptrace-config.cmake.in
+++ /dev/null
@@ -1,3 +0,0 @@
-@PACKAGE_INIT@
-
-include(${CMAKE_CURRENT_LIST_DIR}/cpptrace_targets.cmake)
diff --git a/cmake/has_backtrace.cpp b/cmake/has_backtrace.cpp
new file mode 100644
index 0000000..784994a
--- /dev/null
+++ b/cmake/has_backtrace.cpp
@@ -0,0 +1,9 @@
+#ifdef CPPTRACE_BACKTRACE_PATH
+#include CPPTRACE_BACKTRACE_PATH
+#else
+#include
+#endif
+
+int main() {
+ backtrace_state* state = backtrace_create_state(nullptr, true, nullptr, nullptr);
+}
diff --git a/cmake/in/cpptrace-config-cmake.in b/cmake/in/cpptrace-config-cmake.in
new file mode 100644
index 0000000..3361ff5
--- /dev/null
+++ b/cmake/in/cpptrace-config-cmake.in
@@ -0,0 +1,14 @@
+# Init @ variables before doing anything else
+@PACKAGE_INIT@
+
+# Dependencies
+include(CMakeFindDependencyMacro)
+find_dependency(libdwarf REQUIRED)
+
+# We cannot modify an existing IMPORT target
+if(NOT TARGET assert::assert)
+
+ # import targets
+ include("${CMAKE_CURRENT_LIST_DIR}/@package_name@-targets.cmake")
+
+endif()
diff --git a/include/cpptrace/cpptrace.hpp b/include/cpptrace/cpptrace.hpp
index e00e99a..f509d11 100644
--- a/include/cpptrace/cpptrace.hpp
+++ b/include/cpptrace/cpptrace.hpp
@@ -7,6 +7,8 @@
#include
#include
+#include "cpptrace/cpptrace_export.hpp"
+
#if __cplusplus >= 202002L
#ifdef __has_include
#if __has_include()
@@ -16,24 +18,18 @@
#endif
#endif
-#if defined(_WIN32) || defined(__CYGWIN__)
- #define CPPTRACE_API __declspec(dllexport)
-#else
- #define CPPTRACE_API
-#endif
-
namespace cpptrace {
struct object_trace;
struct stacktrace;
- struct raw_trace {
+ struct CPPTRACE_EXPORT raw_trace {
std::vector frames;
- CPPTRACE_API static raw_trace current(std::uint_least32_t skip = 0);
- CPPTRACE_API static raw_trace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
- CPPTRACE_API object_trace resolve_object_trace() const;
- CPPTRACE_API stacktrace resolve() const;
- CPPTRACE_API void clear();
- CPPTRACE_API bool empty() const noexcept;
+ static raw_trace current(std::uint_least32_t skip = 0);
+ static raw_trace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
+ object_trace resolve_object_trace() const;
+ stacktrace resolve() const;
+ void clear();
+ bool empty() const noexcept;
using iterator = std::vector::iterator;
using const_iterator = std::vector::const_iterator;
@@ -45,20 +41,20 @@ namespace cpptrace {
inline const_iterator cend() const noexcept { return frames.cend(); }
};
- struct object_frame {
+ struct CPPTRACE_EXPORT object_frame {
std::string obj_path;
std::string symbol;
std::uintptr_t raw_address = 0;
std::uintptr_t obj_address = 0;
};
- struct object_trace {
+ struct CPPTRACE_EXPORT object_trace {
std::vector frames;
- CPPTRACE_API static object_trace current(std::uint_least32_t skip = 0);
- CPPTRACE_API static object_trace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
- CPPTRACE_API stacktrace resolve() const;
- CPPTRACE_API void clear();
- CPPTRACE_API bool empty() const noexcept;
+ static object_trace current(std::uint_least32_t skip = 0);
+ static object_trace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
+ stacktrace resolve() const;
+ void clear();
+ bool empty() const noexcept;
using iterator = std::vector::iterator;
using const_iterator = std::vector::const_iterator;
@@ -70,7 +66,7 @@ namespace cpptrace {
inline const_iterator cend() const noexcept { return frames.cend(); }
};
- struct stacktrace_frame {
+ struct CPPTRACE_EXPORT stacktrace_frame {
std::uintptr_t address;
std::uint_least32_t line; // TODO: This should use UINT_LEAST32_MAX as a sentinel
std::uint_least32_t column; // UINT_LEAST32_MAX if not present
@@ -89,21 +85,21 @@ namespace cpptrace {
return !operator==(other);
}
- CPPTRACE_API std::string to_string() const;
- CPPTRACE_API friend std::ostream& operator<<(std::ostream& stream, const stacktrace_frame& frame);
+ std::string to_string() const;
+ friend std::ostream& operator<<(std::ostream& stream, const stacktrace_frame& frame);
};
- struct stacktrace {
+ struct CPPTRACE_EXPORT stacktrace {
std::vector frames;
- CPPTRACE_API static stacktrace current(std::uint_least32_t skip = 0);
- CPPTRACE_API static stacktrace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
- CPPTRACE_API void print() const;
- CPPTRACE_API void print(std::ostream& stream) const;
- CPPTRACE_API void print(std::ostream& stream, bool color) const;
- CPPTRACE_API void clear();
- CPPTRACE_API bool empty() const noexcept;
- CPPTRACE_API std::string to_string(bool color = false) const;
- CPPTRACE_API friend std::ostream& operator<<(std::ostream& stream, const stacktrace& trace);
+ static stacktrace current(std::uint_least32_t skip = 0);
+ static stacktrace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
+ void print() const;
+ void print(std::ostream& stream) const;
+ void print(std::ostream& stream, bool color) const;
+ void clear();
+ bool empty() const noexcept;
+ std::string to_string(bool color = false) const;
+ friend std::ostream& operator<<(std::ostream& stream, const stacktrace& trace);
using iterator = std::vector::iterator;
using const_iterator = std::vector::const_iterator;
@@ -114,27 +110,27 @@ namespace cpptrace {
inline const_iterator cbegin() const noexcept { return frames.cbegin(); }
inline const_iterator cend() const noexcept { return frames.cend(); }
private:
- CPPTRACE_API void print(std::ostream& stream, bool color, bool newline_at_end, const char* header) const;
+ void print(std::ostream& stream, bool color, bool newline_at_end, const char* header) const;
friend void print_terminate_trace();
};
- CPPTRACE_API raw_trace generate_raw_trace(std::uint_least32_t skip = 0);
- CPPTRACE_API raw_trace generate_raw_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
- CPPTRACE_API object_trace generate_object_trace(std::uint_least32_t skip = 0);
- CPPTRACE_API object_trace generate_object_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
- CPPTRACE_API stacktrace generate_trace(std::uint_least32_t skip = 0);
- CPPTRACE_API stacktrace generate_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
+ CPPTRACE_EXPORT raw_trace generate_raw_trace(std::uint_least32_t skip = 0);
+ CPPTRACE_EXPORT raw_trace generate_raw_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
+ CPPTRACE_EXPORT object_trace generate_object_trace(std::uint_least32_t skip = 0);
+ CPPTRACE_EXPORT object_trace generate_object_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
+ CPPTRACE_EXPORT stacktrace generate_trace(std::uint_least32_t skip = 0);
+ CPPTRACE_EXPORT stacktrace generate_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
// utilities:
- CPPTRACE_API std::string demangle(const std::string& name);
- CPPTRACE_API void absorb_trace_exceptions(bool absorb);
- CPPTRACE_API bool isatty(int fd);
+ CPPTRACE_EXPORT std::string demangle(const std::string& name);
+ CPPTRACE_EXPORT void absorb_trace_exceptions(bool absorb);
+ CPPTRACE_EXPORT bool isatty(int fd);
- CPPTRACE_API extern const int stdin_fileno;
- CPPTRACE_API extern const int stderr_fileno;
- CPPTRACE_API extern const int stdout_fileno;
+ CPPTRACE_EXPORT extern const int stdin_fileno;
+ CPPTRACE_EXPORT extern const int stderr_fileno;
+ CPPTRACE_EXPORT extern const int stdout_fileno;
- CPPTRACE_API void register_terminate_handler();
+ CPPTRACE_EXPORT void register_terminate_handler();
enum class cache_mode {
// Only minimal lookup tables
@@ -146,15 +142,15 @@ namespace cpptrace {
};
namespace experimental {
- CPPTRACE_API void set_cache_mode(cache_mode mode);
+ CPPTRACE_EXPORT void set_cache_mode(cache_mode mode);
}
namespace detail {
- CPPTRACE_API bool should_absorb_trace_exceptions();
- CPPTRACE_API enum cache_mode get_cache_mode();
+ CPPTRACE_EXPORT bool should_absorb_trace_exceptions();
+ CPPTRACE_EXPORT enum cache_mode get_cache_mode();
}
- class exception : public std::exception {
+ class CPPTRACE_EXPORT exception : public std::exception {
mutable raw_trace trace;
mutable stacktrace resolved_trace;
mutable std::string what_string;
@@ -177,7 +173,7 @@ namespace cpptrace {
const stacktrace& get_trace() const noexcept;
};
- class exception_with_message : public exception {
+ class CPPTRACE_EXPORT exception_with_message : public exception {
mutable std::string message;
protected:
diff --git a/src/cpptrace.cpp b/src/cpptrace.cpp
index 4d77424..c2d81f7 100644
--- a/src/cpptrace.cpp
+++ b/src/cpptrace.cpp
@@ -28,17 +28,16 @@
#define CYAN ESC "36m"
namespace cpptrace {
- CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
+ CPPTRACE_FORCE_NO_INLINE
raw_trace raw_trace::current(std::uint_least32_t skip) {
return generate_raw_trace(skip + 1);
}
- CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
+ CPPTRACE_FORCE_NO_INLINE
raw_trace raw_trace::current(std::uint_least32_t skip, std::uint_least32_t max_depth) {
return generate_raw_trace(skip + 1, max_depth);
}
- CPPTRACE_API
object_trace raw_trace::resolve_object_trace() const {
try {
return object_trace{detail::get_frames_object_info(frames)};
@@ -50,7 +49,6 @@ namespace cpptrace {
}
}
- CPPTRACE_API
stacktrace raw_trace::resolve() const {
try {
std::vector trace = detail::resolve_frames(frames);
@@ -66,27 +64,24 @@ namespace cpptrace {
}
}
- CPPTRACE_API
void raw_trace::clear() {
frames.clear();
}
- CPPTRACE_API
bool raw_trace::empty() const noexcept {
return frames.empty();
}
- CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
+ CPPTRACE_FORCE_NO_INLINE
object_trace object_trace::current(std::uint_least32_t skip) {
return generate_object_trace(skip + 1);
}
- CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
+ CPPTRACE_FORCE_NO_INLINE
object_trace object_trace::current(std::uint_least32_t skip, std::uint_least32_t max_depth) {
return generate_object_trace(skip + 1, max_depth);
}
- CPPTRACE_API
stacktrace object_trace::resolve() const {
try {
return stacktrace{detail::resolve_frames(frames)};
@@ -98,23 +93,21 @@ namespace cpptrace {
}
}
- CPPTRACE_API
void object_trace::clear() {
frames.clear();
}
- CPPTRACE_API
bool object_trace::empty() const noexcept {
return frames.empty();
}
- CPPTRACE_API std::string stacktrace_frame::to_string() const {
+ std::string stacktrace_frame::to_string() const {
std::ostringstream oss;
oss << *this;
return std::move(oss).str();
}
- CPPTRACE_API std::ostream& operator<<(std::ostream& stream, const stacktrace_frame& frame) {
+ std::ostream& operator<<(std::ostream& stream, const stacktrace_frame& frame) {
stream
<< std::hex
<< "0x"
@@ -138,32 +131,28 @@ namespace cpptrace {
return stream;
}
- CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
+ CPPTRACE_FORCE_NO_INLINE
stacktrace stacktrace::current(std::uint32_t skip) {
return generate_trace(skip + 1);
}
- CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
+ CPPTRACE_FORCE_NO_INLINE
stacktrace stacktrace::current(std::uint_least32_t skip, std::uint_least32_t max_depth) {
return generate_trace(skip + 1, max_depth);
}
- CPPTRACE_API
void stacktrace::print() const {
print(std::cerr, true);
}
- CPPTRACE_API
void stacktrace::print(std::ostream& stream) const {
print(stream, true);
}
- CPPTRACE_API
void stacktrace::print(std::ostream& stream, bool color) const {
print(stream, color, true, nullptr);
}
- CPPTRACE_API
void stacktrace::print(std::ostream& stream, bool color, bool newline_at_end, const char* header) const {
if(color) {
detail::enable_virtual_terminal_processing_if_needed();
@@ -224,28 +213,25 @@ namespace cpptrace {
}
}
- CPPTRACE_API
void stacktrace::clear() {
frames.clear();
}
- CPPTRACE_API
bool stacktrace::empty() const noexcept {
return frames.empty();
}
- CPPTRACE_API
std::string stacktrace::to_string(bool color) const {
std::ostringstream oss;
print(oss, color, false, nullptr);
return std::move(oss).str();
}
- CPPTRACE_API std::ostream& operator<<(std::ostream& stream, const stacktrace& trace) {
+ std::ostream& operator<<(std::ostream& stream, const stacktrace& trace) {
return stream << trace.to_string();
}
- CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
+ CPPTRACE_FORCE_NO_INLINE
raw_trace generate_raw_trace(std::uint_least32_t skip) {
try {
return raw_trace{detail::capture_frames(skip + 1, UINT_LEAST32_MAX)};
@@ -257,7 +243,7 @@ namespace cpptrace {
}
}
- CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
+ CPPTRACE_FORCE_NO_INLINE
raw_trace generate_raw_trace(std::uint_least32_t skip, std::uint_least32_t max_depth) {
try {
return raw_trace{detail::capture_frames(skip + 1, max_depth)};
@@ -269,7 +255,7 @@ namespace cpptrace {
}
}
- CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
+ CPPTRACE_FORCE_NO_INLINE
object_trace generate_object_trace(std::uint_least32_t skip) {
try {
return object_trace{detail::get_frames_object_info(detail::capture_frames(skip + 1, UINT_LEAST32_MAX))};
@@ -281,7 +267,7 @@ namespace cpptrace {
}
}
- CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
+ CPPTRACE_FORCE_NO_INLINE
object_trace generate_object_trace(std::uint_least32_t skip, std::uint_least32_t max_depth) {
try {
return object_trace{detail::get_frames_object_info(detail::capture_frames(skip + 1, max_depth))};
@@ -293,12 +279,12 @@ namespace cpptrace {
}
}
- CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
+ CPPTRACE_FORCE_NO_INLINE
stacktrace generate_trace(std::uint_least32_t skip) {
return generate_trace(skip + 1, UINT_LEAST32_MAX);
}
- CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
+ CPPTRACE_FORCE_NO_INLINE
stacktrace generate_trace(std::uint32_t skip, std::uint_least32_t max_depth) {
try {
std::vector frames = detail::capture_frames(skip + 1, max_depth);
@@ -315,19 +301,17 @@ namespace cpptrace {
}
}
- CPPTRACE_API
std::string demangle(const std::string& name) {
return detail::demangle(name);
}
- CPPTRACE_API
bool isatty(int fd) {
return detail::isatty(fd);
}
- CPPTRACE_API extern const int stdin_fileno = detail::fileno(stdin);
- CPPTRACE_API extern const int stdout_fileno = detail::fileno(stdout);
- CPPTRACE_API extern const int stderr_fileno = detail::fileno(stderr);
+ extern const int stdin_fileno = detail::fileno(stdin);
+ extern const int stdout_fileno = detail::fileno(stdout);
+ extern const int stderr_fileno = detail::fileno(stderr);
CPPTRACE_FORCE_NO_INLINE void print_terminate_trace() {
generate_trace(1).print(
@@ -338,7 +322,7 @@ namespace cpptrace {
);
}
- [[noreturn]] CPPTRACE_API void terminate_handler() {
+ [[noreturn]] void terminate_handler() {
try {
auto ptr = std::current_exception();
if(ptr == nullptr) {
@@ -371,7 +355,7 @@ namespace cpptrace {
abort();
}
- CPPTRACE_API void register_terminate_handler() {
+ void register_terminate_handler() {
std::set_terminate(terminate_handler);
}
@@ -380,22 +364,22 @@ namespace cpptrace {
std::atomic cache_mode(cache_mode::prioritize_speed); // NOSONAR
}
- CPPTRACE_API void absorb_trace_exceptions(bool absorb) {
+ void absorb_trace_exceptions(bool absorb) {
detail::absorb_trace_exceptions = absorb;
}
namespace experimental {
- CPPTRACE_API void set_cache_mode(cache_mode mode) {
+ void set_cache_mode(cache_mode mode) {
detail::cache_mode = mode;
}
}
namespace detail {
- CPPTRACE_API bool should_absorb_trace_exceptions() {
+ bool should_absorb_trace_exceptions() {
return absorb_trace_exceptions;
}
- CPPTRACE_API enum cache_mode get_cache_mode() {
+ enum cache_mode get_cache_mode() {
return cache_mode;
}
diff --git a/test/add_subdirectory-integration/CMakeLists.txt b/test/add_subdirectory-integration/CMakeLists.txt
index 94bd9df..46b7a24 100644
--- a/test/add_subdirectory-integration/CMakeLists.txt
+++ b/test/add_subdirectory-integration/CMakeLists.txt
@@ -5,14 +5,14 @@ project(demo_project VERSION 0.0.1 LANGUAGES CXX)
add_executable(main main.cpp)
add_subdirectory(cpptrace)
-target_link_libraries(main cpptrace)
+target_link_libraries(main cpptrace::cpptrace)
target_compile_features(main PRIVATE cxx_std_11)
if(WIN32)
add_custom_command(
TARGET main POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
- $
+ $
$
)
endif()
diff --git a/test/fetchcontent-integration/CMakeLists.txt b/test/fetchcontent-integration/CMakeLists.txt
index 31d3453..e638086 100644
--- a/test/fetchcontent-integration/CMakeLists.txt
+++ b/test/fetchcontent-integration/CMakeLists.txt
@@ -20,7 +20,7 @@ if(WIN32)
add_custom_command(
TARGET main POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
- $
+ $
$
)
endif()
diff --git a/test/speedtest/CMakeLists.txt b/test/speedtest/CMakeLists.txt
index 57ed6fa..6cfd3ee 100644
--- a/test/speedtest/CMakeLists.txt
+++ b/test/speedtest/CMakeLists.txt
@@ -35,6 +35,7 @@ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
set(cpptrace_DIR "../../build/foo/lib/cmake/cpptrace")
+set(libdwarf_DIR "../../build/foo/lib/cmake/libdwarf")
find_package(cpptrace REQUIRED)
add_executable(speedtest speedtest.cpp)