Line data Source code
1 :
2 : /* Copyright (c) 2013-2016, EPFL/Blue Brain Project
3 : * Raphael Dumusc <raphael.dumusc@epfl.ch>
4 : * Stefan.Eilemann@epfl.ch
5 : *
6 : * This file is part of Lunchbox <https://github.com/Eyescale/Lunchbox>
7 : *
8 : * This library is free software; you can redistribute it and/or modify it under
9 : * the terms of the GNU Lesser General Public License version 2.1 as published
10 : * by the Free Software Foundation.
11 : *
12 : * This library is distributed in the hope that it will be useful, but WITHOUT
13 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15 : * details.
16 : *
17 : * You should have received a copy of the GNU Lesser General Public License
18 : * along with this library; if not, write to the Free Software Foundation, Inc.,
19 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 : */
21 :
22 : namespace lunchbox
23 : {
24 : template <typename T>
25 12 : PluginFactory<T>& PluginFactory<T>::getInstance()
26 : {
27 12 : static PluginFactory<T> factory;
28 12 : return factory;
29 : }
30 :
31 : template <typename T>
32 1 : PluginFactory<T>::~PluginFactory()
33 : {
34 : // Do not do this: dtor is called in atexit(), at which point the other DSOs
35 : // might be unloaded already, causing dlclose to trip. It's pointless
36 : // anyways, we're in atexit, so the OS will dispose the DSOs for us anyways.
37 : // Let's call this a static deinitializer fiasco.
38 : // deregisterAll(); // unload the DSO libraries
39 1 : }
40 :
41 : template <typename T>
42 : bool PluginFactory<T>::handles(const typename T::InitDataT& initData)
43 : {
44 : for (auto& plugin : _plugins)
45 : if (plugin.handles(initData))
46 : return true;
47 : return false;
48 : }
49 :
50 : template <typename T>
51 4 : T* PluginFactory<T>::create(const typename T::InitDataT& initData)
52 : {
53 6 : for (auto& plugin : _plugins)
54 4 : if (plugin.handles(initData))
55 4 : return plugin.construct(initData);
56 :
57 2 : LBTHROW(std::runtime_error("No plugin implementation available for " +
58 : std::to_string(initData)));
59 : }
60 :
61 : template <typename T>
62 4 : void PluginFactory<T>::register_(const PluginT& plugin)
63 : {
64 4 : _plugins.push_back(plugin);
65 4 : }
66 :
67 : template <typename T>
68 : bool PluginFactory<T>::deregister(const PluginT& plugin)
69 : {
70 : typename Plugins::iterator i =
71 : std::find(_plugins.begin(), _plugins.end(), plugin);
72 : if (i == _plugins.end())
73 : return false;
74 :
75 : _plugins.erase(i);
76 : return true;
77 : }
78 :
79 : template <typename T>
80 4 : void PluginFactory<T>::deregisterAll()
81 : {
82 4 : _plugins.clear();
83 4 : for (auto& plugin : _libraries)
84 0 : delete plugin.first;
85 4 : _libraries.clear();
86 4 : }
87 :
88 : template <typename T>
89 2 : std::string PluginFactory<T>::getDescriptions() const
90 : {
91 2 : std::string descriptions;
92 5 : for (const auto& plugin : _plugins)
93 6 : descriptions +=
94 3 : (descriptions.empty() ? "" : "\n\n") + plugin.getDescription();
95 2 : return descriptions;
96 : }
97 :
98 : template <typename T>
99 : void PluginFactory<T>::load(const int version, const Strings& paths,
100 : const std::string& pattern)
101 : {
102 : Strings unique = paths;
103 : lunchbox::usort(unique);
104 :
105 : for (const auto& path : unique)
106 : load(version, path, pattern);
107 : }
108 :
109 : template <typename T>
110 : void PluginFactory<T>::load(const int version, const std::string& path,
111 : const std::string& pattern)
112 : {
113 : #ifdef _MSC_VER
114 : const std::string regex(pattern + ".dll");
115 : #elif __APPLE__
116 : const std::string regex("lib" + pattern + ".dylib");
117 : #else
118 : const std::string regex("lib" + pattern + ".so");
119 : #endif
120 : const Strings& libs = searchDirectory(path, regex);
121 :
122 : for (const auto& lib : libs)
123 : {
124 : lunchbox::DSO* dso = new lunchbox::DSO(path + "/" + lib);
125 : if (!dso->isOpen())
126 : {
127 : delete dso;
128 : continue;
129 : }
130 :
131 : typedef int (*GetVersion_t)();
132 : typedef bool (*Register_t)();
133 :
134 : GetVersion_t getVersion =
135 : dso->getFunctionPointer<GetVersion_t>("LunchboxPluginGetVersion");
136 : Register_t registerFunc =
137 : dso->getFunctionPointer<Register_t>("LunchboxPluginRegister");
138 : const bool matchesVersion = getVersion && (getVersion() == version);
139 :
140 : if (!getVersion || !registerFunc || !matchesVersion)
141 : {
142 : LBERROR << "Disable " << lib << ": "
143 : << (getVersion
144 : ? ""
145 : : "Symbol for LunchboxPluginGetVersion missing ")
146 : << (registerFunc
147 : ? ""
148 : : "Symbol for LunchboxPluginRegister missing ");
149 : if (getVersion && !matchesVersion)
150 : LBERROR << "Plugin version " << getVersion() << " does not"
151 : << " match application version " << version;
152 : LBERROR << std::endl;
153 :
154 : delete dso;
155 : continue;
156 : }
157 :
158 : if (registerFunc())
159 : {
160 : _libraries.insert(std::make_pair(dso, _plugins.back()));
161 : LBINFO << "Loaded plugin " << lib << std::endl;
162 : }
163 : else
164 : delete dso;
165 : }
166 : }
167 : }
|