Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
build_fingerprint.hpp
Go to the documentation of this file.
1#pragma once
2
16
17#include <cstdint>
18#include <cstdio>
19#include <cstring>
20#include <string>
21#include <vector>
22
24
26inline constexpr uint32_t kBuildFingerprintSchema = 1;
27
29 uint32_t schema_version = 0;
30 int32_t cpp_standard = 0; // __cplusplus (_MSVC_LANG under MSVC)
31 uint8_t sample_precision = 0; // bits: 32 (float) / 64 (double)
32 char compiler[64] = {}; // "clang 17.0.0" / "gcc 13.2.0" / "msvc 1939"
33 char target[48] = {}; // "arm64-macos"
34 char stdlib[48] = {}; // "libc++ 170000" / "libstdc++ 20230801"
35 char abi_flags[160] = {}; // ndebug/exc/rtti/cxx11abi/itdbg/hardening/libcppabi
36 char sanitizers[48] = {}; // "asan,tsan" or "none"
37 char sdk_version[48] = {}; // Pulp SDK version (shell+logic share a checkout)
38};
39
40static_assert(sizeof(BuildFingerprint) > 0);
41
42namespace detail {
43inline void set_field(char* dst, std::size_t cap, const char* src) {
44 std::snprintf(dst, cap, "%s", src ? src : "");
45}
46} // namespace detail
47
53#if defined(_MSVC_LANG)
54 // MSVC reports __cplusplus as 199711 unless /Zc:__cplusplus is set;
55 // _MSVC_LANG always carries the selected language standard.
56 fp.cpp_standard = static_cast<int32_t>(_MSVC_LANG);
57#else
58 fp.cpp_standard = static_cast<int32_t>(__cplusplus);
59#endif
60 fp.sample_precision = static_cast<uint8_t>(sizeof(float) * 8);
61
62#if defined(__clang__)
63 std::snprintf(fp.compiler, sizeof fp.compiler, "clang %d.%d.%d",
64 __clang_major__, __clang_minor__, __clang_patchlevel__);
65#elif defined(__GNUC__)
66 std::snprintf(fp.compiler, sizeof fp.compiler, "gcc %d.%d.%d",
67 __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
68#elif defined(_MSC_VER)
69 std::snprintf(fp.compiler, sizeof fp.compiler, "msvc %d", _MSC_VER);
70#else
71 detail::set_field(fp.compiler, sizeof fp.compiler, "unknown-compiler");
72#endif
73
74 {
75#if defined(__aarch64__) || defined(_M_ARM64)
76 const char* arch = "arm64";
77#elif defined(__x86_64__) || defined(_M_X64)
78 const char* arch = "x86_64";
79#else
80 const char* arch = "unknown-arch";
81#endif
82#if defined(__APPLE__)
83 const char* os = "macos";
84#elif defined(__linux__)
85 const char* os = "linux";
86#elif defined(_WIN32)
87 const char* os = "windows";
88#else
89 const char* os = "unknown-os";
90#endif
91 std::snprintf(fp.target, sizeof fp.target, "%s-%s", arch, os);
92 }
93
94#if defined(_LIBCPP_VERSION)
95 std::snprintf(fp.stdlib, sizeof fp.stdlib, "libc++ %d", _LIBCPP_VERSION);
96#elif defined(__GLIBCXX__)
97 std::snprintf(fp.stdlib, sizeof fp.stdlib, "libstdc++ %d", __GLIBCXX__);
98#elif defined(_MSVC_STL_VERSION)
99 std::snprintf(fp.stdlib, sizeof fp.stdlib, "msvcstl %d", _MSVC_STL_VERSION);
100#else
101 detail::set_field(fp.stdlib, sizeof fp.stdlib, "unknown-stdlib");
102#endif
103
104 {
105#if defined(NDEBUG)
106 const int ndebug = 1;
107#else
108 const int ndebug = 0;
109#endif
110#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
111 const int exc = 1;
112#else
113 const int exc = 0;
114#endif
115#if defined(__GXX_RTTI) || defined(_CPPRTTI)
116 const int rtti = 1;
117#else
118 const int rtti = 0;
119#endif
120#if defined(_GLIBCXX_USE_CXX11_ABI)
121 const int cxx11abi = _GLIBCXX_USE_CXX11_ABI;
122#else
123 const int cxx11abi = -1; // n/a (not libstdc++)
124#endif
125#if defined(_ITERATOR_DEBUG_LEVEL)
126 const int itdbg = _ITERATOR_DEBUG_LEVEL;
127#elif defined(_LIBCPP_DEBUG)
128 const int itdbg = _LIBCPP_DEBUG;
129#else
130 const int itdbg = 0;
131#endif
132#if defined(_LIBCPP_HARDENING_MODE)
133 const int hardening = _LIBCPP_HARDENING_MODE;
134#elif defined(_GLIBCXX_ASSERTIONS)
135 const int hardening = 1;
136#else
137 const int hardening = 0;
138#endif
139#if defined(_LIBCPP_ABI_VERSION)
140 const int libcppabi = _LIBCPP_ABI_VERSION;
141#else
142 const int libcppabi = -1;
143#endif
144 std::snprintf(fp.abi_flags, sizeof fp.abi_flags,
145 "ndebug=%d;exc=%d;rtti=%d;cxx11abi=%d;itdbg=%d;harden=%d;libcppabi=%d",
146 ndebug, exc, rtti, cxx11abi, itdbg, hardening, libcppabi);
147 }
148
149 {
150 char buf[48] = {};
151 std::size_t n = 0;
152 [[maybe_unused]] auto append = [&](const char* tag) {
153 if (n) n += static_cast<std::size_t>(std::snprintf(buf + n, sizeof buf - n, ","));
154 n += static_cast<std::size_t>(std::snprintf(buf + n, sizeof buf - n, "%s", tag));
155 };
156#if defined(__SANITIZE_ADDRESS__)
157 append("asan");
158#elif defined(__has_feature)
159# if __has_feature(address_sanitizer)
160 append("asan");
161# endif
162#endif
163#if defined(__has_feature)
164# if __has_feature(thread_sanitizer)
165 append("tsan");
166# endif
167# if __has_feature(memory_sanitizer)
168 append("msan");
169# endif
170#endif
171#if defined(__SANITIZE_THREAD__)
172 append("tsan");
173#endif
174#if defined(UNDEFINED_BEHAVIOR_SANITIZER) || defined(__SANITIZE_UNDEFINED__)
175 append("ubsan");
176#endif
177 detail::set_field(fp.sanitizers, sizeof fp.sanitizers, n ? buf : "none");
178 }
179
180#if defined(PULP_SDK_VERSION)
181 detail::set_field(fp.sdk_version, sizeof fp.sdk_version, PULP_SDK_VERSION);
182#else
183 detail::set_field(fp.sdk_version, sizeof fp.sdk_version, "dev");
184#endif
185
186 return fp;
187}
188
191inline bool fingerprints_match(const BuildFingerprint& a, const BuildFingerprint& b) {
192 return a.schema_version == b.schema_version &&
193 a.cpp_standard == b.cpp_standard &&
194 a.sample_precision == b.sample_precision &&
195 std::strncmp(a.compiler, b.compiler, sizeof a.compiler) == 0 &&
196 std::strncmp(a.target, b.target, sizeof a.target) == 0 &&
197 std::strncmp(a.stdlib, b.stdlib, sizeof a.stdlib) == 0 &&
198 std::strncmp(a.abi_flags, b.abi_flags, sizeof a.abi_flags) == 0 &&
199 std::strncmp(a.sanitizers, b.sanitizers, sizeof a.sanitizers) == 0 &&
200 std::strncmp(a.sdk_version, b.sdk_version, sizeof a.sdk_version) == 0;
201}
202
204inline std::vector<std::string> fingerprint_diff(const BuildFingerprint& shell,
205 const BuildFingerprint& logic) {
206 std::vector<std::string> out;
207 auto cmp_str = [&](const char* field, const char* s, const char* l) {
208 if (std::strncmp(s, l, 64) != 0)
209 out.push_back(std::string(field) + ": shell='" + s + "' logic='" + l + "'");
210 };
211 auto cmp_int = [&](const char* field, long s, long l) {
212 if (s != l)
213 out.push_back(std::string(field) + ": shell=" + std::to_string(s) +
214 " logic=" + std::to_string(l));
215 };
216 cmp_int("schema_version", shell.schema_version, logic.schema_version);
217 cmp_int("cpp_standard", shell.cpp_standard, logic.cpp_standard);
218 cmp_int("sample_precision", shell.sample_precision, logic.sample_precision);
219 cmp_str("compiler", shell.compiler, logic.compiler);
220 cmp_str("target", shell.target, logic.target);
221 cmp_str("stdlib", shell.stdlib, logic.stdlib);
222 cmp_str("abi_flags", shell.abi_flags, logic.abi_flags);
223 cmp_str("sanitizers", shell.sanitizers, logic.sanitizers);
224 cmp_str("sdk_version", shell.sdk_version, logic.sdk_version);
225 return out;
226}
227
228} // namespace pulp::format::reload
Definition build_fingerprint.hpp:42
void set_field(char *dst, std::size_t cap, const char *src)
Definition build_fingerprint.hpp:43
Definition build_fingerprint.hpp:23
BuildFingerprint current_build_fingerprint()
Capture THIS translation unit's build fingerprint.
Definition build_fingerprint.hpp:50
bool fingerprints_match(const BuildFingerprint &a, const BuildFingerprint &b)
Field-by-field equality (the gate).
Definition build_fingerprint.hpp:191
constexpr uint32_t kBuildFingerprintSchema
Bump when the fingerprint layout/semantics change.
Definition build_fingerprint.hpp:26
std::vector< std::string > fingerprint_diff(const BuildFingerprint &shell, const BuildFingerprint &logic)
Human-readable per-field differences (diagnostics only). Empty == identical.
Definition build_fingerprint.hpp:204
Definition build_fingerprint.hpp:28
uint32_t schema_version
Definition build_fingerprint.hpp:29
char compiler[64]
Definition build_fingerprint.hpp:32
char sdk_version[48]
Definition build_fingerprint.hpp:37
char stdlib[48]
Definition build_fingerprint.hpp:34
char sanitizers[48]
Definition build_fingerprint.hpp:36
uint8_t sample_precision
Definition build_fingerprint.hpp:31
int32_t cpp_standard
Definition build_fingerprint.hpp:30
char abi_flags[160]
Definition build_fingerprint.hpp:35
char target[48]
Definition build_fingerprint.hpp:33