Skip to content

Commit 040c8b0

Browse files
committed
Add backend selection option
1 parent 8f3166f commit 040c8b0

4 files changed

Lines changed: 126 additions & 121 deletions

File tree

‎CMakeLists.txt‎

Lines changed: 60 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -137,27 +137,14 @@ if(MSVC)
137137
)
138138
endif()
139139

140-
# -- Backend selection -----------------------------------------------------
140+
# -- Backend helpers -------------------------------------------------------
141141

142-
# eggs_stacktrace_want_backend(<name> <out-var>)
142+
# eggs_stacktrace_add_backend(<name>)
143143
#
144-
# Sets <out-var> ON if <name> should be attempted: always, unless
145-
# EGGS_STACKTRACE_BACKENDS is non-empty and doesn't list it.
146-
macro(eggs_stacktrace_want_backend name out_var)
147-
if(
148-
EGGS_STACKTRACE_BACKENDS
149-
AND NOT "${name}" IN_LIST EGGS_STACKTRACE_BACKENDS
150-
)
151-
set(${out_var} OFF)
152-
else()
153-
set(${out_var} ON)
154-
endif()
155-
endmacro()
156-
157-
# -- Backend macro -------------------------------------------------------------
158-
159-
macro(eggs_stacktrace_add_backend name)
144+
# Defines the _eggs_stacktrace_<name> target.
145+
function(eggs_stacktrace_add_backend name)
160146
set(_export "${EGGS_STACKTRACE_BACKEND_EXPORT_${name}}")
147+
string(TOUPPER "${name}" _upper)
161148
add_library(
162149
_eggs_stacktrace_${name}
163150
STATIC
@@ -171,6 +158,12 @@ macro(eggs_stacktrace_add_backend name)
171158
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
172159
)
173160
target_compile_features(_eggs_stacktrace_${name} PUBLIC cxx_std_11)
161+
if(EGGS_STACKTRACE_${_upper}_DEFINITIONS)
162+
target_compile_definitions(
163+
_eggs_stacktrace_${name}
164+
PRIVATE ${EGGS_STACKTRACE_${_upper}_DEFINITIONS}
165+
)
166+
endif()
174167
set_target_properties(
175168
_eggs_stacktrace_${name}
176169
PROPERTIES
@@ -187,76 +180,53 @@ macro(eggs_stacktrace_add_backend name)
187180
"${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>"
188181
)
189182
endif()
190-
if(NOT "${ARGN}" STREQUAL "")
191-
target_link_libraries(_eggs_stacktrace_${name} PUBLIC ${ARGN})
192-
endif()
193-
add_library(Eggs::Stacktrace::${_export} ALIAS _eggs_stacktrace_${name})
194-
unset(_export)
195-
endmacro()
196-
197-
# -- Backend targets -----------------------------------------------------------
198-
199-
eggs_stacktrace_add_backend(null)
200-
201-
eggs_stacktrace_want_backend(execinfo _want_execinfo)
202-
if(_want_execinfo)
203-
include(CheckExecinfoBackend)
204-
eggs_stacktrace_check_execinfo_backend(EGGS_STACKTRACE_HAVE_EXECINFO)
205-
if(EGGS_STACKTRACE_HAVE_EXECINFO)
206-
eggs_stacktrace_add_backend(execinfo _eggs_stacktrace_execinfo_support)
207-
elseif("execinfo" IN_LIST EGGS_STACKTRACE_BACKENDS)
208-
message(
209-
FATAL_ERROR
210-
"Eggs.Stacktrace: backend 'execinfo' was requested in "
211-
"EGGS_STACKTRACE_BACKENDS but is not available on this platform."
183+
if(TARGET _eggs_stacktrace_${name}_support)
184+
target_link_libraries(
185+
_eggs_stacktrace_${name}
186+
PUBLIC _eggs_stacktrace_${name}_support
212187
)
213188
endif()
214-
else()
215-
set(EGGS_STACKTRACE_HAVE_EXECINFO OFF)
216-
endif()
189+
add_library(Eggs::Stacktrace::${_export} ALIAS _eggs_stacktrace_${name})
190+
endfunction()
217191

218-
eggs_stacktrace_want_backend(libbacktrace _want_libbacktrace)
219-
if(_want_libbacktrace)
220-
include(CheckLibbacktraceBackend)
221-
eggs_stacktrace_check_libbacktrace_backend(
222-
EGGS_STACKTRACE_HAVE_LIBBACKTRACE
192+
# eggs_stacktrace_add_checked_backend(<name>)
193+
#
194+
# Adds backend <name> if it is wanted and its dependencies check out.
195+
macro(eggs_stacktrace_add_checked_backend name)
196+
string(TOUPPER "${name}" _upper)
197+
if(
198+
NOT EGGS_STACKTRACE_BACKENDS
199+
OR "${name}" IN_LIST EGGS_STACKTRACE_BACKENDS
223200
)
224-
if(EGGS_STACKTRACE_HAVE_LIBBACKTRACE)
225-
eggs_stacktrace_add_backend(
226-
libbacktrace
227-
_eggs_stacktrace_libbacktrace_support
228-
)
229-
target_compile_definitions(
230-
_eggs_stacktrace_libbacktrace
231-
PRIVATE
232-
EGGS_STACKTRACE_BACKTRACE_INCLUDE_FILE="${EGGS_STACKTRACE_LIBBACKTRACE_HEADER}"
233-
)
234-
elseif("libbacktrace" IN_LIST EGGS_STACKTRACE_BACKENDS)
235-
message(
236-
FATAL_ERROR
237-
"Eggs.Stacktrace: backend 'libbacktrace' was requested in "
238-
"EGGS_STACKTRACE_BACKENDS but is not available on this platform."
201+
include(Check${EGGS_STACKTRACE_BACKEND_EXPORT_${name}}Backend)
202+
cmake_language(
203+
CALL eggs_stacktrace_check_${name}_backend
204+
EGGS_STACKTRACE_HAVE_${_upper}
239205
)
206+
if(EGGS_STACKTRACE_HAVE_${_upper})
207+
eggs_stacktrace_add_backend(${name})
208+
list(
209+
APPEND EGGS_STACKTRACE_CHECKED_BACKENDS
210+
${EGGS_STACKTRACE_BACKEND_EXPORT_${name}}
211+
)
212+
elseif("${name}" IN_LIST EGGS_STACKTRACE_BACKENDS)
213+
message(
214+
FATAL_ERROR
215+
"Eggs.Stacktrace: backend '${name}' was requested in "
216+
"EGGS_STACKTRACE_BACKENDS but is not available on this platform."
217+
)
218+
endif()
240219
endif()
241-
else()
242-
set(EGGS_STACKTRACE_HAVE_LIBBACKTRACE OFF)
243-
endif()
220+
unset(_upper)
221+
endmacro()
244222

245-
eggs_stacktrace_want_backend(win32 _want_win32)
246-
if(_want_win32)
247-
if(WIN32)
248-
set(EGGS_STACKTRACE_HAVE_WIN32 ON)
249-
eggs_stacktrace_add_backend(win32 DbgHelp)
250-
elseif("win32" IN_LIST EGGS_STACKTRACE_BACKENDS)
251-
message(
252-
FATAL_ERROR
253-
"Eggs.Stacktrace: backend 'win32' was requested in "
254-
"EGGS_STACKTRACE_BACKENDS but is not available on this platform."
255-
)
256-
endif()
257-
else()
258-
set(EGGS_STACKTRACE_HAVE_WIN32 OFF)
259-
endif()
223+
# -- Backend targets -----------------------------------------------------------
224+
225+
set(EGGS_STACKTRACE_CHECKED_BACKENDS)
226+
eggs_stacktrace_add_backend(null)
227+
eggs_stacktrace_add_checked_backend(execinfo)
228+
eggs_stacktrace_add_checked_backend(libbacktrace)
229+
eggs_stacktrace_add_checked_backend(win32)
260230

261231
# An empty EGGS_STACKTRACE_BACKENDS means auto-detect.
262232
if(NOT EGGS_STACKTRACE_BACKENDS)
@@ -284,15 +254,14 @@ if(EGGS_STACKTRACE_DEFAULT_BACKEND)
284254
)
285255
endif()
286256
else()
287-
if(TARGET _eggs_stacktrace_libbacktrace)
288-
set(EGGS_STACKTRACE_DEFAULT_BACKEND libbacktrace)
289-
elseif(TARGET _eggs_stacktrace_execinfo)
290-
set(EGGS_STACKTRACE_DEFAULT_BACKEND execinfo)
291-
elseif(TARGET _eggs_stacktrace_win32)
292-
set(EGGS_STACKTRACE_DEFAULT_BACKEND win32)
293-
else()
294-
set(EGGS_STACKTRACE_DEFAULT_BACKEND null)
295-
endif()
257+
set(EGGS_STACKTRACE_DEFAULT_BACKEND null)
258+
foreach(_backend IN ITEMS libbacktrace execinfo win32)
259+
if(TARGET _eggs_stacktrace_${_backend})
260+
set(EGGS_STACKTRACE_DEFAULT_BACKEND ${_backend})
261+
break()
262+
endif()
263+
endforeach()
264+
unset(_backend)
296265
endif()
297266

298267
add_library(
@@ -377,6 +346,7 @@ if(ENABLE_INSTALL)
377346
FILES
378347
cmake/CheckExecinfoBackend.cmake
379348
cmake/CheckLibbacktraceBackend.cmake
349+
cmake/CheckWin32Backend.cmake
380350
cmake/FindLibbacktrace.cmake
381351
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/eggs.stacktrace
382352
)

‎cmake/CheckLibbacktraceBackend.cmake‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,18 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
1515
#
1616
# Checks whether libbacktrace is present and links successfully.
1717
# Sets <out-var> as an internal cache boolean. On success, also defines the
18-
# INTERFACE library _eggs_stacktrace_libbacktrace_support. Additionaly,
19-
# sets EGGS_STACKTRACE_LIBBACKTRACE_HEADER to the resolved header path..
18+
# INTERFACE library _eggs_stacktrace_libbacktrace_support. Additionally,
19+
# sets EGGS_STACKTRACE_LIBBACKTRACE_DEFINITIONS to the private compile
20+
# definitions the backend needs, including the resolved header path.
2021
function(eggs_stacktrace_check_libbacktrace_backend out_var)
2122
find_package(Libbacktrace QUIET)
2223
set(${out_var} ${Libbacktrace_FOUND} CACHE INTERNAL "")
2324
if(NOT Libbacktrace_FOUND)
2425
return()
2526
endif()
2627

27-
set(EGGS_STACKTRACE_LIBBACKTRACE_HEADER
28-
"${Libbacktrace_HEADER}"
28+
set(EGGS_STACKTRACE_LIBBACKTRACE_DEFINITIONS
29+
"EGGS_STACKTRACE_BACKTRACE_INCLUDE_FILE=\"${Libbacktrace_HEADER}\""
2930
PARENT_SCOPE
3031
)
3132
if(NOT TARGET _eggs_stacktrace_libbacktrace_support)

‎cmake/CheckWin32Backend.cmake‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Eggs.Stacktrace
2+
#
3+
# Copyright (c) 2026 Agustin Berge
4+
#
5+
# Distributed under the Boost Software License, Version 1.0. (See accompanying
6+
# file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7+
8+
include_guard()
9+
10+
include(CheckCXXSourceCompiles)
11+
12+
# eggs_stacktrace_check_win32_backend(<out-var>)
13+
#
14+
# Checks whether the win32 backend's dependencies (CaptureStackBackTrace()
15+
# and the DbgHelp symbol APIs) are all present and link successfully.
16+
# Sets <out-var> as an internal cache boolean. On success, also defines the
17+
# INTERFACE library _eggs_stacktrace_win32_support.
18+
function(eggs_stacktrace_check_win32_backend out_var)
19+
set(CMAKE_REQUIRED_LIBRARIES DbgHelp)
20+
check_cxx_source_compiles(
21+
"
22+
#include <windows.h>
23+
#include <dbghelp.h>
24+
int main()
25+
{
26+
void* buf[1];
27+
USHORT const n = ::CaptureStackBackTrace(0, 1, buf, nullptr);
28+
HANDLE const process = ::GetCurrentProcess();
29+
::SymInitialize(process, nullptr, TRUE);
30+
::SymRefreshModuleList(process);
31+
::SymGetLineFromAddr64(process, 0, nullptr, nullptr);
32+
::SymFromAddr(process, 0, nullptr, nullptr);
33+
::SymCleanup(process);
34+
return n;
35+
}
36+
"
37+
${out_var}
38+
)
39+
if(NOT ${out_var})
40+
return()
41+
endif()
42+
43+
if(NOT TARGET _eggs_stacktrace_win32_support)
44+
add_library(_eggs_stacktrace_win32_support INTERFACE)
45+
target_link_libraries(_eggs_stacktrace_win32_support INTERFACE DbgHelp)
46+
endif()
47+
endfunction()

‎cmake/eggs.stacktrace-config.cmake.in‎

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,28 @@
22

33
include("${CMAKE_CURRENT_LIST_DIR}/eggs.stacktrace-targets.cmake")
44

5-
if(@EGGS_STACKTRACE_HAVE_EXECINFO@)
6-
include("${CMAKE_CURRENT_LIST_DIR}/CheckExecinfoBackend.cmake")
7-
eggs_stacktrace_check_execinfo_backend(EGGS_STACKTRACE_HAVE_EXECINFO)
8-
if(EGGS_STACKTRACE_HAVE_EXECINFO)
9-
include(
10-
"${CMAKE_CURRENT_LIST_DIR}/eggs.stacktrace-execinfo-targets.cmake"
11-
)
12-
else()
13-
message(
14-
WARNING
15-
"eggs.stacktrace: execinfo backend dependencies could not be resolved on this machine; the Execinfo backend will not be available"
16-
)
17-
endif()
18-
endif()
19-
20-
if(@EGGS_STACKTRACE_HAVE_LIBBACKTRACE@)
21-
include("${CMAKE_CURRENT_LIST_DIR}/CheckLibbacktraceBackend.cmake")
22-
eggs_stacktrace_check_libbacktrace_backend(
23-
EGGS_STACKTRACE_HAVE_LIBBACKTRACE
5+
foreach(_export IN ITEMS @EGGS_STACKTRACE_CHECKED_BACKENDS@)
6+
string(TOLOWER "${_export}" _backend)
7+
string(TOUPPER "${_export}" _upper)
8+
include("${CMAKE_CURRENT_LIST_DIR}/Check${_export}Backend.cmake")
9+
cmake_language(
10+
CALL eggs_stacktrace_check_${_backend}_backend
11+
EGGS_STACKTRACE_HAVE_${_upper}
2412
)
25-
if(EGGS_STACKTRACE_HAVE_LIBBACKTRACE)
13+
if(EGGS_STACKTRACE_HAVE_${_upper})
2614
include(
27-
"${CMAKE_CURRENT_LIST_DIR}/eggs.stacktrace-libbacktrace-targets.cmake"
15+
"${CMAKE_CURRENT_LIST_DIR}/eggs.stacktrace-${_backend}-targets.cmake"
2816
)
2917
else()
3018
message(
3119
WARNING
32-
"eggs.stacktrace: libbacktrace could not be found on this machine; the Libbacktrace backend will not be available"
20+
"eggs.stacktrace: ${_backend} backend dependencies could not be resolved on this machine; the ${_export} backend will not be available"
3321
)
3422
endif()
35-
endif()
36-
37-
if(@EGGS_STACKTRACE_HAVE_WIN32@)
38-
include("${CMAKE_CURRENT_LIST_DIR}/eggs.stacktrace-win32-targets.cmake")
39-
endif()
23+
endforeach()
24+
unset(_export)
25+
unset(_backend)
26+
unset(_upper)
4027

4128
# Create the canonical Eggs::Stacktrace alias for the configured default backend.
4229
if(NOT TARGET Eggs::Stacktrace)

0 commit comments

Comments
 (0)