@@ -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
0 commit comments