26 namespace plugin_manager
31 std::unordered_map<std::string, std::tuple<std::unique_ptr<BasePluginInterface>, std::unique_ptr<RuntimeLibrary>>> m_loaded_plugins;
34 std::unordered_map<std::string, std::vector<PluginFeature>> m_plugin_features;
37 std::unordered_map<std::string, std::string> m_cli_option_to_plugin_name[2];
40 CallbackHook<void(
bool, std::string
const&, std::string
const&)> m_hook;
52 std::string m_current_loading;
54 bool solve_dependencies(std::string plugin_name, std::set<std::string> dep_file_name)
56 if (plugin_name.empty())
58 log_error(
"core",
"parameter 'plugin_name' is empty");
61 if (dep_file_name.empty())
63 log_debug(
"core",
"no dependency for plugin '{}'", plugin_name);
66 for (
const auto& file_name : dep_file_name)
68 auto dep_plugin_name = std::filesystem::path(file_name).stem().string();
71 if (m_loaded_plugins.find(dep_plugin_name) != m_loaded_plugins.end())
78 if (file_path.empty() || !
load(dep_plugin_name, file_path))
80 log_error(
"core",
"cannot solve dependency '{}' for plugin '{}'", dep_plugin_name, plugin_name);
84 log_debug(
"core",
"solved dependency '{}' for plugin '{}'", dep_plugin_name, plugin_name);
86 log_debug(
"core",
"solved {} dependencies for plugin '{}'", dep_file_name.size(), plugin_name);
94 std::filesystem::path retval;
95 if (plugin_name.empty())
return retval;
105 #if defined(__APPLE__) && defined(__MACH__)
108 if (file_name.string().find(
".so") != std::string::npos)
125 std::set<std::string>
names;
126 for (
const auto& it : m_loaded_plugins)
128 names.insert(it.first);
135 auto it = m_plugin_features.find(
name);
136 if (it == m_plugin_features.end())
return std::vector<PluginFeature>();
142 return m_cli_option_to_plugin_name[0];
147 return m_cli_option_to_plugin_name[1];
152 return m_plugin_options;
157 auto directories = (!directory_names.empty()) ? directory_names : m_plugin_folders;
158 for (
const auto& directory : directories)
160 if (!std::filesystem::exists(directory))
164 u32 num_of_loaded_plugins = 0;
170 auto plugin_name =
file.path().stem().string();
173 num_of_loaded_plugins++;
176 log_debug(
"core",
"loaded {} plugins from '{}'", num_of_loaded_plugins, directory.string());
181 bool load(
const std::string& plugin_name,
const std::filesystem::path& file_path_or_empty)
183 if (plugin_name.empty())
185 log_error(
"core",
"parameter 'plugin_name' is empty");
189 std::filesystem::path file_path = file_path_or_empty;
190 if (file_path.empty())
195 if (file_path.empty())
197 log_error(
"core",
"path for plugin '{}' not found", plugin_name);
202 log_info(
"core",
"loading plugin '{}'...", file_path.string());
204 if (m_loaded_plugins.find(plugin_name) != m_loaded_plugins.end())
206 log_debug(
"core",
"plugin '{}' is already loaded", plugin_name);
211 auto lib = std::make_unique<RuntimeLibrary>();
212 if (!lib->load_library(file_path.string()))
219 if (factory ==
nullptr)
221 log_error(
"core",
"file does not seem to be a HAL plugin since it does not contain a factory function 'create_plugin_instance'.");
224 auto instance = factory();
225 if (instance ==
nullptr)
227 log_error(
"core",
"factory constructor for plugin '{}' returned a nullptr", plugin_name);
232 std::set<std::string> dep_file_name = instance->get_dependencies();
233 if (!solve_dependencies(plugin_name, dep_file_name))
243 if (plugin ==
nullptr)
250 for (
const auto& cli_option : cli_options.get_options())
252 for (
const auto& flag : std::get<0>(cli_option))
254 if (m_existing_options.is_registered(flag))
256 log_error(
"core",
"command line option '{}' is already used by generic program options -- use another one.", flag);
260 for (
int iplugType = 0; iplugType<2; iplugType++)
261 if (m_cli_option_to_plugin_name[iplugType].find(flag) != m_cli_option_to_plugin_name[iplugType].end())
263 log_error(
"core",
"command line option '{}' is already used by plugin '{}' -- use another option in plugin '{}'.", flag, m_cli_option_to_plugin_name[iplugType][flag], plugin_name);
266 m_cli_option_to_plugin_name[ui_plugin?1:0][flag] = plugin_name;
267 log_debug(
"core",
"registered command line option '{}' for plugin '{}'.", flag, plugin->
get_name());
270 m_plugin_options.add(cli_options);
273 instance->initialize_logging();
275 m_current_loading = plugin_name;
283 m_plugin_features[plugin_name].push_back({feif->
get_feature(),
316 m_current_loading.clear();
318 m_loaded_plugins[plugin_name] = std::make_tuple(std::move(instance), std::move(lib));
321 m_hook(
true, plugin_name, file_path.string());
323 log_debug(
"core",
"loaded plugin '{}'.", plugin_name);
329 if (m_loaded_plugins.size() == 0)
331 log_debug(
"core",
"no plugins to unload");
335 for (
const auto&
name : loaded_plugin_names)
342 log_info(
"core",
"unloaded all {} plugins", loaded_plugin_names.size());
346 bool unload(
const std::string& plugin_name)
348 auto loaded_it = m_loaded_plugins.find(plugin_name);
349 if (loaded_it == m_loaded_plugins.end())
351 log_debug(
"core",
"cannot find plugin '{}' to unload it", plugin_name);
355 log_info(
"core",
"unloading plugin '{}'...", plugin_name);
358 auto rt_library = std::move(std::get<1>(loaded_it->second));
359 auto plugin_inst = std::move(std::get<0>(loaded_it->second));
363 auto it = m_cli_option_to_plugin_name[iplugType].begin();
364 while (it != m_cli_option_to_plugin_name[iplugType].end())
366 auto flag = it->first;
367 auto name = it->second;
368 if (
name == plugin_name)
370 m_plugin_options.remove(flag);
371 it = m_cli_option_to_plugin_name[iplugType].erase(it);
380 m_loaded_plugins.erase(loaded_it);
405 auto file_name = rt_library->get_file_name();
406 plugin_inst->on_unload();
415 m_hook(
false, plugin_name, file_name);
417 log_debug(
"core",
"unloaded plugin '{}'", plugin_name);
423 auto it = m_loaded_plugins.find(plugin_name);
424 if (it == m_loaded_plugins.end())
427 log_error(
"core",
"plugin '{}' is not loaded", plugin_name);
431 auto instance = std::get<0>(it->second).get();
434 instance->initialize();
441 if (callback ==
nullptr)
443 log_error(
"core",
"parameter 'callback' is nullptr");
446 return m_hook.add_callback(callback);
451 m_hook.remove_callback(
id);
456 m_existing_options.add(existing_options);
within a display generated by the Derivative if and wherever such third party notices normally appear The contents of the NOTICE file are for informational purposes only and do not modify the License You may add Your own attribution notices within Derivative Works that You alongside or as an addendum to the NOTICE text from the provided that such additional attribution notices cannot be construed as modifying the License You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for or distribution of Your or for any such Derivative Works as a provided Your and distribution of the Work otherwise complies with the conditions stated in this License Submission of Contributions Unless You explicitly state any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this without any additional terms or conditions Notwithstanding the nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions Trademarks This License does not grant permission to use the trade names
then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file
#define LIBRARY_FILE_EXTENSION
#define ALTERNATE_LIBRARY_FILE_EXTENSION
virtual std::string get_name() const =0
virtual ProgramOptions get_cli_options() const =0
AbstractFactoryProvider * factory_provider
std::vector< std::string > get_supported_file_extensions() const
std::string get_description() const
Feature get_feature() const
File-Access Factory class.
std::function< std::unique_ptr< T >)> m_factory
#define log_error(channel,...)
#define log_debug(channel,...)
#define log_info(channel,...)
void unregister_parser(const std::string &name)
void register_parser(const std::string &name, const ParserFactory &parser_factory, const std::vector< std::string > &supported_file_extensions)
void unregister_writer(const std::string &name)
void register_writer(const std::string &name, const WriterFactory &writer_factory, const std::vector< std::string > &supported_file_extensions)
void unregister_parser(const std::string &name)
void register_parser(const std::string &name, const ParserFactory &parser_factory, const std::vector< std::string > &supported_file_extensions)
void unregister_writer(const std::string &name)
void register_writer(const std::string &name, const WriterFactory &writer_factory, const std::vector< std::string > &supported_file_extensions)
void add_existing_options_description(const ProgramOptions &existing_options)
u64 add_model_changed_callback(std::function< void(bool, std::string const &, std::string const &)> callback)
bool has_valid_file_extension(std::filesystem::path file_name)
bool unload(const std::string &plugin_name)
std::set< std::string > get_plugin_names()
BasePluginInterface * get_plugin_instance(const std::string &plugin_name, bool initialize, bool silent)
std::unordered_map< std::string, std::string > get_cli_plugin_flags()
std::unordered_map< std::string, std::string > get_ui_plugin_flags()
bool unload_all_plugins()
std::filesystem::path get_plugin_path(std::string plugin_name)
ProgramOptions get_cli_plugin_options()
void remove_model_changed_callback(u64 id)
bool load_all_plugins(const std::vector< std::filesystem::path > &directory_names)
std::vector< PluginFeature > get_plugin_features(std::string name)
bool load(const std::string &plugin_name, const std::filesystem::path &file_path_or_empty)
CORE_API bool ends_with(const T &s, const T &end)
std::vector< std::filesystem::path > get_plugin_directories()
std::filesystem::path get_file(std::string file_name, std::vector< std::filesystem::path > path_hints)
std::unique_ptr< BasePluginInterface >(*)() instantiate_plugin_function