23 #ifndef CASADI_PLUGIN_INTERFACE_HPP
24 #define CASADI_PLUGIN_INTERFACE_HPP
26 #include "function_internal.hpp"
27 #include "global_options.hpp"
28 #include "serializing_stream.hpp"
29 #include "casadi_os.hpp"
30 #include <casadi/core/casadi_common.hpp>
31 #include "casadi_meta.hpp"
40 T check_exposed(T t) {
41 casadi_assert(t!=0,
"Static function not implemented for plugin");
45 typedef ProtoFunction* (*Deserialize)(DeserializingStream&);
53 template<
class Derived>
54 class PluginInterface {
60 typename Derived::Creator creator;
64 typename Derived::Exposed exposed;
65 const Options* options;
66 Deserialize deserialize;
68 Plugin() : creator(nullptr), name(nullptr), doc(nullptr), version(0),
69 exposed(), options(nullptr), deserialize(nullptr) {}
73 typedef int (*RegFcn)(Plugin* plugin);
76 static bool has_plugin(
const std::string& pname,
bool verbose=
false);
79 static const Options& plugin_options(
const std::string& pname);
82 static Deserialize plugin_deserialize(
const std::string& pname);
85 static Plugin pluginFromRegFcn(RegFcn regfcn);
88 static Plugin load_plugin(
const std::string& pname,
89 bool register_plugin=
true,
bool needs_lock=
true);
92 static handle_t load_library(
const std::string& libname, std::string& resultpath,
96 static void registerPlugin(
const Plugin& plugin,
bool needs_lock=
true);
99 static void registerPlugin(RegFcn regfcn,
bool needs_lock=
true);
102 static Plugin& getPlugin(
const std::string& pname);
105 template<
class Problem>
106 static Derived* instantiate(
const std::string& fname,
107 const std::string& pname, Problem problem);
109 virtual const char* plugin_name()
const = 0;
112 virtual void deps_version_check(
const std::string& stage)
const {}
117 void serialize_type(SerializingStream& s)
const {
118 s.pack(
"PluginInterface::plugin_name", std::string(plugin_name()));
124 static ProtoFunction* deserialize(DeserializingStream& s) {
125 std::string class_name, plugin_name;
126 s.unpack(
"PluginInterface::plugin_name", plugin_name);
127 Deserialize deserialize = plugin_deserialize(plugin_name);
128 return deserialize(s);
133 template<
class Derived>
134 bool PluginInterface<Derived>::has_plugin(
const std::string& pname,
bool verbose) {
136 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
137 std::lock_guard<std::mutex> lock(Derived::mutex_solvers_);
141 if (Derived::solvers_.find(pname) != Derived::solvers_.end()) {
147 (void)load_plugin(pname,
false,
false);
149 }
catch (CasadiException& ex) {
151 casadi_warning(ex.what());
157 template<
class Derived>
158 const Options& PluginInterface<Derived>::plugin_options(
const std::string& pname) {
159 const Options *op = getPlugin(pname).options;
160 casadi_assert(op!=
nullptr,
"Plugin \"" + pname +
"\" does not support options");
164 template<
class Derived>
165 Deserialize PluginInterface<Derived>::plugin_deserialize(
const std::string& pname) {
166 Deserialize m = getPlugin(pname).deserialize;
167 casadi_assert(m,
"Plugin \"" + pname +
"\" does not support deserialize");
171 template<
class Derived>
172 typename PluginInterface<Derived>::Plugin
173 PluginInterface<Derived>::pluginFromRegFcn(RegFcn regfcn) {
178 int flag = regfcn(&plugin);
179 casadi_assert(flag==0,
"Registration of plugin failed.");
185 template<
class Derived>
186 handle_t PluginInterface<Derived>::load_library(
const std::string& libname,
187 std::string& resultpath,
bool global) {
190 casadi_error(
"WITH_DL option needed for dynamic loading");
198 std::vector<std::string> search_paths = get_search_paths();
199 return open_shared_library(lib, search_paths, resultpath,
200 "PluginInterface::load_plugin", global);
205 template<
class Derived>
206 typename PluginInterface<Derived>::Plugin
207 PluginInterface<Derived>::load_plugin(
const std::string& pname,
208 bool register_plugin,
bool needs_lock) {
210 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
211 casadi::conditional_lock_guard<std::mutex> lock(Derived::mutex_solvers_, needs_lock);
215 if (Derived::solvers_.find(pname) != Derived::solvers_.end()) {
216 casadi_warning(
"PluginInterface: Solver " + pname +
" is already in use. Ignored.");
227 casadi_error(
"WITH_DL option needed for dynamic loading");
233 std::string regName =
"casadi_register_" + Derived::infix_ +
"_" + pname;
235 std::string searchpath;
236 handle_t handle = load_library(
"casadi_" + Derived::infix_ +
"_" + pname, searchpath,
242 #pragma GCC diagnostic push
243 #pragma GCC diagnostic ignored "-Wcast-function-type"
245 reg =
reinterpret_cast<RegFcn
>(GetProcAddress(handle, TEXT(regName.c_str())));
247 #pragma GCC diagnostic pop
255 reg =
reinterpret_cast<RegFcn
>(dlsym(handle, regName.c_str()));
257 casadi_assert(reg!=
nullptr,
258 "PluginInterface::load_plugin: no \"" + regName +
"\" found in " + searchpath +
".");
261 Plugin plugin = pluginFromRegFcn(reg);
263 if (register_plugin) {
264 registerPlugin(plugin,
false);
272 template<
class Derived>
273 void PluginInterface<Derived>::registerPlugin(RegFcn regfcn,
bool needs_lock) {
274 registerPlugin(pluginFromRegFcn(regfcn), needs_lock);
277 template<
class Derived>
278 void PluginInterface<Derived>::registerPlugin(
const Plugin& plugin,
bool needs_lock) {
280 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
281 casadi::conditional_lock_guard<std::mutex> lock(Derived::mutex_solvers_, needs_lock);
285 typename std::map<std::string, Plugin>::iterator it=Derived::solvers_.find(plugin.name);
286 casadi_assert(it==Derived::solvers_.end(),
287 "Solver " + str(plugin.name) +
" is already in use");
290 Derived::solvers_[plugin.name] = plugin;
293 template<
class Derived>
294 typename PluginInterface<Derived>::Plugin&
295 PluginInterface<Derived>::getPlugin(
const std::string& pname) {
297 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
298 std::lock_guard<std::mutex> lock(Derived::mutex_solvers_);
302 auto it=Derived::solvers_.find(pname);
305 if (it==Derived::solvers_.end()) {
306 load_plugin(pname,
true,
false);
307 it=Derived::solvers_.find(pname);
309 casadi_assert_dev(it!=Derived::solvers_.end());
313 template<
class Derived>
314 template<
class Problem>
315 Derived* PluginInterface<Derived>::
316 instantiate(
const std::string& fname,
317 const std::string& pname, Problem problem) {
320 if (!has_plugin(pname,
true)) {
321 casadi_error(
"Plugin '" + pname +
"' is not found.");
323 return getPlugin(pname).creator(fname, problem);
CASADI_EXPORT std::ostream & uout()
CASADI_EXPORT std::ostream & uerr()