Skip to content

Commit 4d47403

Browse files
committed
using shared for qt in sanitizers
1 parent 0bd3238 commit 4d47403

2 files changed

Lines changed: 74 additions & 57 deletions

File tree

gemc_options.cc

Lines changed: 63 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,50 @@ namespace gemc {
115115

116116
// Scan every YAML file present in argv. For each file:
117117
// - collect any plugin_path value declared there
118-
// - collect gsystem names to probe for a definePluginOptions symbol
118+
// - collect gsystem and gstreamer plugin names to probe for a definePluginOptions symbol
119119
std::set<std::string> seen_names; // deduplicate across multiple YAML files
120+
121+
// Helper: resolve a plugin basename through the search path, open it, call
122+
// definePluginOptions() if the symbol exists, and merge the result into `merged`.
123+
auto probe_plugin = [&](const std::string& basename) {
124+
std::string full_search = search_path;
125+
if (const char* env = std::getenv("GEMC_PLUGIN_PATH")) {
126+
if (!full_search.empty()) full_search += ':';
127+
full_search += env;
128+
}
129+
130+
std::string lib_path;
131+
if (!full_search.empty()) {
132+
std::istringstream ss(full_search);
133+
std::string dir;
134+
while (std::getline(ss, dir, ':')) {
135+
if (dir.empty()) continue;
136+
const auto candidate = dir + "/" + basename;
137+
if (std::filesystem::exists(candidate)) { lib_path = candidate; break; }
138+
}
139+
}
140+
if (lib_path.empty() && std::filesystem::exists(basename)) lib_path = basename;
141+
if (lib_path.empty()) return; // no plugin — normal
142+
143+
// On Linux, RTLD_NODELETE keeps it resident so that the later GManager dlopen
144+
// gets the exact same handle without re-executing static initialisers.
145+
#if defined(__linux__) && defined(RTLD_NODELETE)
146+
const auto h = dlopen(lib_path.c_str(), RTLD_NOW | RTLD_NODELETE);
147+
#else
148+
const auto h = dlopen(lib_path.c_str(), RTLD_NOW);
149+
#endif
150+
if (!h) return; // library not loadable — skip silently
151+
152+
// The definePluginOptions symbol is optional. Plugins that need no custom
153+
// options simply omit it and are silently skipped here.
154+
using opt_fptr = GOptions* (*)();
155+
const auto sym = reinterpret_cast<opt_fptr>(dlsym(h, "definePluginOptions"));
156+
if (!sym) return;
157+
158+
std::unique_ptr<GOptions> plugin_opts(sym());
159+
merged += *plugin_opts;
160+
};
161+
120162
for (int i = 1; i < argc; ++i) {
121163
const std::string arg = argv[i];
122164
if (!std::filesystem::exists(arg)) continue;
@@ -137,56 +179,29 @@ namespace gemc {
137179
} catch (...) {}
138180
}
139181

140-
if (!root["gsystem"]) continue;
141-
for (const auto& entry : root["gsystem"]) {
142-
if (!entry["name"]) continue;
143-
std::string name;
144-
try { name = entry["name"].as<std::string>(); } catch (...) { continue; }
145-
if (name.empty() || !seen_names.insert(name).second) continue;
146-
147-
// Resolve <name>.gplugin using the accumulated search path plus
148-
// GEMC_PLUGIN_PATH and, as a last resort, the current directory.
149-
std::string full_search = search_path;
150-
if (const char* env = std::getenv("GEMC_PLUGIN_PATH")) {
151-
if (!full_search.empty()) full_search += ':';
152-
full_search += env;
182+
// Probe gsystem plugins for definePluginOptions.
183+
if (root["gsystem"]) {
184+
for (const auto& entry : root["gsystem"]) {
185+
if (!entry["name"]) continue;
186+
std::string name;
187+
try { name = entry["name"].as<std::string>(); } catch (...) { continue; }
188+
if (name.empty() || !seen_names.insert(name).second) continue;
189+
probe_plugin(name + ".gplugin");
153190
}
191+
}
154192

155-
const std::string basename = name + ".gplugin";
156-
std::string lib_path;
157-
158-
if (!full_search.empty()) {
159-
std::istringstream ss(full_search);
160-
std::string dir;
161-
while (std::getline(ss, dir, ':')) {
162-
if (dir.empty()) continue;
163-
const auto candidate = dir + "/" + basename;
164-
if (std::filesystem::exists(candidate)) { lib_path = candidate; break; }
165-
}
193+
// Probe gstreamer plugins for definePluginOptions so that verbosity domains
194+
// registered by those plugins (e.g. "hipo") are available before the factories
195+
// are instantiated.
196+
if (root["gstreamer"]) {
197+
for (const auto& entry : root["gstreamer"]) {
198+
if (!entry["format"]) continue;
199+
std::string format;
200+
try { format = entry["format"].as<std::string>(); } catch (...) { continue; }
201+
const std::string plugin_name = "gstreamer_" + format + "_plugin";
202+
if (plugin_name.empty() || !seen_names.insert(plugin_name).second) continue;
203+
probe_plugin(plugin_name + ".gplugin");
166204
}
167-
if (lib_path.empty() && std::filesystem::exists(basename)) lib_path = basename;
168-
if (lib_path.empty()) continue; // no plugin for this system — normal
169-
170-
// Open the library. On Linux, RTLD_NODELETE keeps it resident so that the
171-
// later GManager dlopen gets the exact same handle without re-executing
172-
// static initialisers. On macOS the reference count achieves the same effect.
173-
#if defined(__linux__) && defined(RTLD_NODELETE)
174-
const auto h = dlopen(lib_path.c_str(), RTLD_NOW | RTLD_NODELETE);
175-
#else
176-
const auto h = dlopen(lib_path.c_str(), RTLD_NOW);
177-
#endif
178-
if (!h) continue; // library not loadable — skip silently
179-
180-
// The definePluginOptions symbol is optional. Plugins that need no custom
181-
// options simply omit it and are silently skipped here.
182-
// The symbol returns GOptions* (heap-allocated) so that extern "C" linkage
183-
// is not applied to a by-value C++ return type.
184-
using opt_fptr = GOptions* (*)();
185-
const auto sym = reinterpret_cast<opt_fptr>(dlsym(h, "definePluginOptions"));
186-
if (!sym) continue;
187-
188-
std::unique_ptr<GOptions> plugin_opts(sym());
189-
merged += *plugin_opts;
190205
}
191206
}
192207

meson/meson.build

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
sanitize = get_option('b_sanitize') # string option: 'none', 'address', 'undefined', etc.
2+
3+
# only use shared libraries if a sanitizer option is passed
4+
# this will avoid duplicate symbols errors when sanitizer is used, coming from static library usage
5+
use_sharedl = (sanitize != 'none')
6+
17
# qt
28
qt6 = import('qt6')
39
qt6_deps = dependency('qt6',
@@ -6,7 +12,7 @@ qt6_deps = dependency('qt6',
612
'Widgets',
713
'OpenGLWidgets',
814
'Svg'],
9-
static : true,
15+
static : not use_sharedl,
1016
include_type : 'system') # treat as system include paths - no warnings
1117

1218
sys = host_machine.system()
@@ -100,10 +106,11 @@ geant4_deps = [geant4_dep]
100106
geant4_core_deps = [geant4_core_dep]
101107
if sys == 'linux'
102108
# Only on Linux: pull in GLX/X11 stack for G4OpenGL(.a)
109+
# Force shared so static non-PIC archives (libX11.a on aarch64) are not linked into shared libs
103110
geant4_deps += [
104-
dependency('x11', required : true),
105-
dependency('xmu', required : true),
106-
dependency('gl', required : true),
111+
dependency('x11', static : false, required : true),
112+
dependency('xmu', static : false, required : true),
113+
dependency('gl', static : false, required : true),
107114
]
108115
endif
109116

@@ -132,11 +139,6 @@ cmake_opts.add_cmake_defines({
132139
'CMAKE_POLICY_VERSION_MINIMUM' : '4.0',
133140
})
134141

135-
sanitize = get_option('b_sanitize') # string option: 'none', 'address', 'undefined', etc.
136-
137-
# only use shared libraries if a sanitizer option is passed
138-
# this will avoid duplicate symbols errors when sanitizer is used, coming from static library usage
139-
use_sharedl = (sanitize != 'none')
140142
cmake_opts.add_cmake_defines({
141143
'BUILD_SHARED_LIBS' : use_sharedl,
142144
# Avoid pulling GUI/sample/tooling deps like X11

0 commit comments

Comments
 (0)