YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
YarpPlugin.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
7
8#include <yarp/os/Network.h>
9#include <yarp/os/Property.h>
11#include <yarp/os/SystemClock.h>
14
15#include <cstdio>
16#include <cstdlib>
17#include <filesystem>
18
19using namespace yarp::os;
20using namespace yarp::os::impl;
21
22namespace {
23#ifndef YARP_NO_DEPRECATED // since YARP 3.4
24// The log component cannot be const because we still support setVerboseMode
25YARP_OS_NON_CONST_LOG_COMPONENT(YARPPLUGINSETTINGS, "yarp.os.YarpPluginSettings")
26#else
27YARP_OS_LOG_COMPONENT(YARPPLUGINSETTINGS, "yarp.os.YarpPluginSettings")
28#endif
29} // namespace
30
31#ifndef YARP_NO_DEPRECATED // since YARP 3.4
33{
35}
36#endif // YARP_NO_DEPRECATED
37
39 const std::string& dll_name,
40 const std::string& fn_name)
41{
42 return subopen(factory, dll_name, fn_name);
43}
44
45bool YarpPluginSettings::subopen(SharedLibraryFactory& factory,
46 const std::string& dll_name,
47 const std::string& fn_name)
48{
50 "Trying plugin [dll: %s] [fn: %s]",
51 dll_name.c_str(),
52 fn_name.c_str());
53 bool ok = factory.open(dll_name.c_str(), fn_name.c_str());
55 "Trying to find library '%s' containing function '%s' -- %s",
56 dll_name.c_str(),
57 fn_name.c_str(), ok ? "found" : "fail");
58 if (ok) {
60 "Found plugin [dll: %s] [fn: %s]",
61 dll_name.c_str(),
62 fn_name.c_str());
63 this->dll_name = dll_name;
64 this->fn_name = fn_name;
65 } else {
68 "Error while opening %s:\n %s",
69 dll_name.c_str(),
70 factory.getError().c_str());
71 } else {
73 "Error while opening %s:\n %s",
74 dll_name.c_str(),
75 factory.getError().c_str());
76 }
77 }
78 return ok;
79}
80
82{
84 "Plugin [name: %s] [dll: %s] [fn: %s]",
85 name.c_str(),
86 dll_name.c_str(),
87 fn_name.c_str());
88 if (selector != nullptr && !name.empty()) {
89 // we may have a YARP-specific search path available,
90 // and a proper name for the DLL
91 Bottle paths = selector->getSearchPath();
92 for (size_t i = 0; i < paths.size(); i++) {
93 Searchable& options = paths.get(i);
94 std::string absolute_search_path;
95 if (options.check("path")) {
96 // If path is present in the .ini file generated by yarp_configure_plugins_installation,
97 // we use it directly
98 absolute_search_path = options.find("path").asString();
99 } else if (options.check("relative_path")) {
100 // If instead relative_path is present, we use it to build absolute_search_path
101 // using relative_path and the absolute path to hte .ini file, contained in inifile
102 std::filesystem::path relative_search_path = std::filesystem::path(options.find("relative_path").asString());
103 std::filesystem::path absolute_ini_file_path = std::filesystem::path(options.find("inifile").asString());
104 absolute_search_path = std::filesystem::weakly_canonical(absolute_ini_file_path.parent_path() / relative_search_path).string();
105 }
106
107 std::string ext = options.find("extension").asString();
108 std::string basename = (dll_name.find('.') != std::string::npos) ? name : dll_name;
109 std::string fn = (fn_name.empty()) ? name : fn_name;
110
111 std::string fullpath;
112
113#if defined(_MSC_VER) && !defined(NDEBUG)
114 // MSVC DEBUG build: try debug name before basic name
115 fullpath = std::string(absolute_search_path).append("/").append(basename).append("d").append(ext);
116 if (subopen(factory, fullpath, fn))
117 return true;
118#endif // defined(_MSC_VER) && !defined(NDEBUG)
119
120 // Basic name
121 fullpath = std::string(absolute_search_path).append("/").append(basename).append(ext);
122 if (subopen(factory, fullpath, fn)) {
123 return true;
124 }
125
126#if defined(_MSC_VER) && defined(NDEBUG)
127 // MSVC RELEASE build: try debug name after basic name
128 fullpath = std::string(absolute_search_path).append("/").append(basename).append("d").append(ext);
129 if (subopen(factory, fullpath, fn))
130 return true;
131#endif // defined(_MSC_VER) && defined(NDEBUG)
132
133
134#ifdef CMAKE_INTDIR
135 // On multi-config system, try to find the plugin in the
136 // current config subdirectory
137
138# if defined(_MSC_VER) && !defined(NDEBUG)
139 // MSVC DEBUG build: try debug name before basic name
140 fullpath = std::string(absolute_search_path).append("/" CMAKE_INTDIR "/").append(dll_name).append("d").append(ext);
141 if (subopen(factory, fullpath, fn))
142 return true;
143# endif // defined(_MSC_VER) && !defined(NDEBUG)
144
145 // Basic name
146 fullpath = std::string(absolute_search_path).append("/" CMAKE_INTDIR "/").append(dll_name).append(ext);
147 if (subopen(factory, fullpath, fn))
148 return true;
149
150# if defined(_MSC_VER) && defined(NDEBUG)
151 // MSVC RELEASE build: try debug name after basic name
152 fullpath = std::string(absolute_search_path).append("/" CMAKE_INTDIR "/").append(dll_name).append("d").append(ext);
153 if (subopen(factory, fullpath, fn))
154 return true;
155# endif // defined(_MSC_VER) && defined(NDEBUG)
156
157#endif // CMAKE_INTDIR
158 }
159 }
160 if (!dll_name.empty() || !fn_name.empty()) {
161 return open(factory, dll_name, fn_name);
162 }
163 return factory.open((std::string("yarp_") + name).c_str(),
164 (fn_name.empty()) ? name.c_str() : fn_name.c_str());
165}
166
168{
169 int problem = factory.getStatus();
170 if (problem == 0) {
171 return;
172 }
173 switch (problem) {
175 yCDebug(YARPPLUGINSETTINGS, "Cannot load plugin from shared library (%s)", dll_name.c_str());
176 yCDebug(YARPPLUGINSETTINGS, "(%s)", factory.getError().c_str());
177 break;
179 yCWarning(YARPPLUGINSETTINGS, "Cannot load plugin from shared library (%s)", dll_name.c_str());
180 yCWarning(YARPPLUGINSETTINGS, "(%s)", factory.getError().c_str());
181 break;
183 yCWarning(YARPPLUGINSETTINGS, "Cannot find YARP hook in shared library (%s:%s)", dll_name.c_str(), fn_name.c_str());
184 yCWarning(YARPPLUGINSETTINGS, "(%s)", factory.getError().c_str());
185 break;
187 yCWarning(YARPPLUGINSETTINGS, "YARP hook in shared library misbehaved (%s:%s)", dll_name.c_str(), fn_name.c_str());
188 yCWarning(YARPPLUGINSETTINGS, "(the library may be too old/new and need to be recompiled to match YARP version)");
189 yCWarning(YARPPLUGINSETTINGS, "(%s)", factory.getError().c_str());
190 break;
191 default:
192 yCWarning(YARPPLUGINSETTINGS, "Unknown error (%s:%s)", dll_name.c_str(), fn_name.c_str());
193 yCWarning(YARPPLUGINSETTINGS, "(%s)", factory.getError().c_str());
194 break;
195 }
196}
197
199{
200 yCError(YARPPLUGINSETTINGS, "Failed to create %s from shared library %s", fn_name.c_str(), dll_name.c_str());
201}
202
203bool YarpPluginSettings::readFromSelector(const std::string& name)
204{
205 if (!selector) {
206 return false;
207 }
208 Bottle plugins = selector->getSelectedPlugins();
209 Bottle group = plugins.findGroup(name).tail();
210 if (group.isNull()) {
212 "Cannot find \"%s\" plugin (not built in, and no .ini file found for it)"
213 "Check that YARP_DATA_DIRS leads to at least one directory with plugins/%s.ini "
214 "or share/yarp/plugins/%s.ini in it",
215 name.c_str(),
216 name.c_str(),
217 name.c_str());
218 return false;
219 }
220 return readFromSearchable(group, name);
221}
222
224{
225 // This method needs to be accessed by one thread only
226 std::lock_guard<std::mutex> guard(mutex);
227
228 // If it was scanned in the last 5 seconds, there is no need to scan again
229 bool need_scan = true;
230 if (config.check("last_update_time")) {
231 if (SystemClock::nowSystem() - config.find("last_update_time").asFloat64() < 5) {
232 need_scan = false;
233 }
234 }
235 if (!need_scan) {
236 return;
237 }
238
239 yCDebug(YARPPLUGINSETTINGS, "Scanning. I'm scanning. I hope you like scanning too.");
240
241 // Search plugins directories
243 static std::mutex rf_mutex;
244 std::lock_guard<std::mutex> rf_guard(rf_mutex);
245
246 if (!rf.isConfigured()) {
247 rf.configure(0, nullptr);
248 }
249 Bottle plugin_paths = rf.findPaths("plugins");
250 if (plugin_paths.size() == 0) {
251 plugin_paths = rf.findPaths("share/yarp/plugins");
252 }
253
254 // Search .ini files in plugins directories
255 config.clear();
256 if (plugin_paths.size() > 0) {
257 for (size_t i = 0; i < plugin_paths.size(); i++) {
258 std::string target = plugin_paths.get(i).asString();
259 yCDebug(YARPPLUGINSETTINGS, "Loading configuration files related to plugins from %s.",
260 target.c_str());
261 config.fromConfigDir(target, "inifile", false);
262 }
263 } else {
264 yCDebug(YARPPLUGINSETTINGS, "Plugin directory not found");
265 }
266
267 // Read the .ini files and populate the lists
268 plugins.clear();
269 search_path.clear();
270 Bottle inilst = config.findGroup("inifile").tail();
271 for (size_t i = 0; i < inilst.size(); i++) {
272 std::string inifile = inilst.get(i).asString();
274
275 // If a .ini file containes a "plugin" key, it identifies a plugin
276 Bottle lst = inigroup.findGroup("plugin").tail();
277 for (size_t i = 0; i < lst.size(); i++) {
278 std::string plugin_name = lst.get(i).asString();
279 Bottle group = inigroup.findGroup(plugin_name);
280 group.add(Value::makeValue(std::string("(inifile \"") + inifile + "\")"));
281 if (select(group)) {
282 plugins.addList() = group;
283 }
284 }
285
286 // If a .ini file containes a "search" key, it is a .ini file used to identify
287 // a search path, created by the yarp_configure_plugins_installation CMake macro
288 // from YarpInstallationHelpers.cmake
289 lst = inigroup.findGroup("search").tail();
290 for (size_t i = 0; i < lst.size(); i++) {
291 std::string search_name = lst.get(i).asString();
292 Bottle group = inigroup.findGroup(search_name);
293 // Propagate the inifile absolute path, so it can be used in YarpPluginSettings::open
294 // to obtain the absolute search path given the relative_path contained in the .ini file
295 // generated by yarp_configure_plugins_installation
296 group.add(Value::makeValue(std::string("(inifile \"") + inifile + "\")"));
297 search_path.addList() = group;
298 }
299 }
300
301 // Update last_update_time
302 config.put("last_update_time", SystemClock::nowSystem());
303}
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
void add(const Value &value)
Add a Value to the bottle, at the end of the list.
Definition Bottle.cpp:309
Bottle & addList()
Places an empty nested list in the bottle, at the end of the list.
Definition Bottle.cpp:182
size_type size() const
Gets the number of elements in the bottle.
Definition Bottle.cpp:251
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition Bottle.cpp:246
Bottle & findGroup(const std::string &key) const override
Gets a list corresponding to a given keyword.
Definition Bottle.cpp:293
Bottle tail() const
Get all but the first element of a bottle.
Definition Bottle.cpp:361
void clear()
Empties the bottle of any objects it contains.
Definition Bottle.cpp:121
bool isNull() const override
Checks if the object is invalid.
Definition Bottle.cpp:343
A mini-server for performing network communication in the background.
@ DebugType
Definition Log.h:93
@ InfoType
Definition Log.h:94
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition Property.cpp:987
bool check(const std::string &key) const override
Check if there exists a property of the given name.
bool fromConfigDir(const std::string &dirname, const std::string &section=std::string(), bool wipe=true)
Interprets all files in a directory as lists of properties as described in fromConfigFile().
void clear()
Remove all associations.
Bottle & findGroup(const std::string &key) const override
Gets a list corresponding to a given keyword.
Helper class for finding config files and other external resources.
bool configure(int argc, char *argv[], bool skipFirstArgument=true)
Sets up the ResourceFinder.
static ResourceFinder & getResourceFinderSingleton()
Access a ResourceFinder singleton whose lifetime will match that of the YARP library.
yarp::os::Bottle findPaths(const std::string &name)
Expand a partial path to a list of paths.
A base class for nested structures that can be searched.
Definition Searchable.h:31
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
A wrapper for a named factory method in a named shared library.
@ STATUS_FACTORY_NOT_FUNCTIONAL
Named method is not working right.
@ STATUS_FACTORY_NOT_FOUND
Named method wasn't present in library.
@ STATUS_LIBRARY_NOT_LOADED
Named shared library failed to load.
@ STATUS_LIBRARY_NOT_FOUND
Named shared library was not found.
bool open(const char *dll_name, const char *fn_name=nullptr)
Configure the factory.
int getStatus() const
Get the status of the factory.
std::string getError() const
Get the latest error of the factory.
static double nowSystem()
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
Definition Value.cpp:222
static Value * makeValue(const std::string &txt)
Create a Value from a text description.
Definition Value.cpp:456
virtual std::string asString() const
Get string value.
Definition Value.cpp:234
void scan()
Find plugin configuration files, and run [plugin] sections through the select method.
virtual bool select(Searchable &options)
Determine whether a plugin is of interest.
bool open(SharedLibraryFactory &factory)
Initialize a factory object based on the hints available.
bool readFromSearchable(Searchable &options, const std::string &name)
Configure settings from a configuration file or other searchable object.
void reportStatus(SharedLibraryFactory &factory) const
Give a human-readable report of the status of a factory.
void setVerboseMode(bool verbose)
Should messages be printed showing what searches YARP is trying out?
void reportFailure() const
Give a human-readable failure-to-load report, summarizing the active hints.
#define yCError(component,...)
#define yCWarning(component,...)
#define yCDebug(component,...)
#define YARP_OS_LOG_COMPONENT(name, name_string)
#define YARP_OS_NON_CONST_LOG_COMPONENT(name, name_string)
The components from which ports and connections are built.
An interface to the operating system, including Port based communication.