Skip to content

Commit ab882e0

Browse files
support platform-independent feature toggles
Replace hardcoded platform checks with feature toggles to allow users to configure gunit for their platform, e.g. if lacking POSIX features like backtrace() and popen(). Feature Flags added: 1. GUNIT_HAS_BACKTRACE - Controls backtrace() and backtrace_symbols() support 2. GUNIT_HAS_ADDR2LINE - Controls popen()/pclose() and addr2line functionality 3. GUNIT_HAS_DEMANGLE - Controls C++ name demangling via cxxabi.h 4. GUNIT_HAS_PROGNAME - Controls program name retrieval
1 parent 0847c10 commit ab882e0

File tree

1 file changed

+61
-21
lines changed

1 file changed

+61
-21
lines changed

include/GUnit/Detail/ProgUtils.h

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,43 @@
77
//
88
#pragma once
99

10-
#if !defined(_WIN32) && !defined(_WIN64)
10+
// Feature detection: backtrace support
11+
#if !defined(GUNIT_HAS_BACKTRACE)
12+
#if (defined(__APPLE__) || defined(__linux__)) && !defined(__ZEPHYR__)
13+
#define GUNIT_HAS_BACKTRACE 1
14+
#else
15+
#define GUNIT_HAS_BACKTRACE 0
16+
#endif
17+
#endif
18+
19+
// Feature detection: addr2line support (requires popen/pclose)
20+
#if !defined(GUNIT_HAS_ADDR2LINE)
21+
#if (defined(__APPLE__) || defined(__linux__)) && !defined(__ZEPHYR__)
22+
#define GUNIT_HAS_ADDR2LINE 1
23+
#else
24+
#define GUNIT_HAS_ADDR2LINE 0
25+
#endif
26+
#endif
27+
28+
// Feature detection: C++ name demangling
29+
#if !defined(GUNIT_HAS_DEMANGLE)
30+
#if !defined(_WIN32) && !defined(_WIN64) && !defined(__ZEPHYR__)
31+
#define GUNIT_HAS_DEMANGLE 1
32+
#else
33+
#define GUNIT_HAS_DEMANGLE 0
34+
#endif
35+
#endif
36+
37+
// Feature detection: program name
38+
#if !defined(GUNIT_HAS_PROGNAME)
39+
#if (defined(__APPLE__) || defined(__linux__)) && !defined(__ZEPHYR__)
40+
#define GUNIT_HAS_PROGNAME 1
41+
#else
42+
#define GUNIT_HAS_PROGNAME 0
43+
#endif
44+
#endif
45+
46+
#if GUNIT_HAS_DEMANGLE
1147
#include <cxxabi.h>
1248
#endif
1349

@@ -16,13 +52,13 @@
1652

1753
#include "gtest/gtest.h"
1854

19-
#if defined(__APPLE__) || defined(__linux__)
55+
#if GUNIT_HAS_BACKTRACE
2056
#include <execinfo.h>
2157
#endif
2258

2359
#if defined(__APPLE__)
2460
#include <libproc.h>
25-
#elif defined(__linux__)
61+
#elif GUNIT_HAS_PROGNAME && defined(__linux__)
2662
extern const char *__progname_full;
2763
#elif defined(_WIN32)
2864
static const char *__progname_full = "progname_not_availabe_on_WIN32";
@@ -37,43 +73,42 @@ inline namespace v1 {
3773
namespace detail {
3874

3975
inline std::string demangle(const std::string &mangled) {
40-
#if !defined(_WIN32) && !defined(_WIN64)
76+
#if GUNIT_HAS_DEMANGLE
4177
const auto demangled = abi::__cxa_demangle(mangled.c_str(), 0, 0, 0);
4278
if (demangled) {
4379
std::shared_ptr<char> free{demangled, std::free};
4480
return demangled;
4581
}
82+
return {};
4683
#else
4784
return mangled;
4885
#endif
49-
return {};
5086
}
5187

5288
inline auto &progname() {
53-
#if defined(__linux__)
54-
static auto self = __progname_full;
55-
#elif defined(__APPLE__)
56-
static char self[PROC_PIDPATHINFO_MAXSIZE] = {};
57-
proc_pidpath(getpid(), self, sizeof(self));
89+
#if GUNIT_HAS_PROGNAME
90+
#if defined(__APPLE__)
91+
static char self[PROC_PIDPATHINFO_MAXSIZE] = {};
92+
proc_pidpath(getpid(), self, sizeof(self));
93+
#elif defined(__linux__)
94+
static auto self = __progname_full;
95+
#endif
5896
#elif defined(_WIN32)
5997
static auto self = __progname_full;
98+
#else
99+
static const char *self = "embedded_target";
60100
#endif
61101
return self;
62102
}
63103

64104
inline std::string call_stack(const std::string &newline, int stack_begin = 1,
65105
int stack_size = GUNIT_SHOW_STACK_SIZE) {
66-
#if defined(_WIN32)
67-
(void)newline;
68-
(void)stack_begin;
69-
(void)stack_size;
70-
return "callstack not availabe on WIN32";
71-
#else
106+
#if GUNIT_HAS_BACKTRACE
72107
static constexpr auto MAX_CALL_STACK_SIZE = 64;
73108
void *bt[MAX_CALL_STACK_SIZE];
74109
const auto frames = backtrace(bt, sizeof(bt) / sizeof(bt[0]));
75110
const auto symbols = backtrace_symbols(bt, frames);
76-
std::shared_ptr<char *> free{symbols, std::free};
111+
std::shared_ptr<char*> free{symbols, [](char** p) { std::free(p); }};
77112
std::stringstream result;
78113
stack_size += stack_begin;
79114

@@ -100,14 +135,16 @@ inline std::string call_stack(const std::string &newline, int stack_begin = 1,
100135
}
101136
}
102137
return result.str();
138+
#else
139+
(void)newline;
140+
(void)stack_begin;
141+
(void)stack_size;
142+
return "callstack disabled or not available";
103143
#endif
104144
}
105145

106146
inline std::pair<std::string, int> addr2line(void *addr) {
107-
#if defined(_WIN32)
108-
(void)addr;
109-
return {"addr2line not availabe on WIN32", 0};
110-
#else
147+
#if GUNIT_HAS_ADDR2LINE
111148
std::stringstream cmd;
112149
cmd << "addr2line -Cpe " << progname() << " " << addr;
113150

@@ -128,6 +165,9 @@ inline std::pair<std::string, int> addr2line(void *addr) {
128165
std::string res2 = data.substr(0, space);
129166
const auto colon = res2.find(":");
130167
return {res2.substr(0, colon), std::atoi(res2.substr(colon + 1).c_str())};
168+
#else
169+
std::ignore = addr;
170+
return {"addr2line disabled or not available", 0};
131171
#endif
132172
}
133173

0 commit comments

Comments
 (0)