YARP
Yet Another Robot Platform
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
18using namespace yarp::os;
19using namespace yarp::os::impl;
20
21namespace {
22#ifndef YARP_NO_DEPRECATED // since YARP 3.4
23// The log component cannot be const because we still support setVerboseMode
24YARP_OS_NON_CONST_LOG_COMPONENT(YARPPLUGINSETTINGS, "yarp.os.YarpPluginSettings")
25#else
26YARP_OS_LOG_COMPONENT(YARPPLUGINSETTINGS, "yarp.os.YarpPluginSettings")
27#endif
28} // namespace
29
30#ifndef YARP_NO_DEPRECATED // since YARP 3.4
31void YarpPluginSettings::setVerboseMode(bool verbose)
32{
33 YARPPLUGINSETTINGS().setMinimumPrintLevel(verbose ? yarp::os::Log::DebugType : yarp::os::Log::InfoType);
34}
35#endif // YARP_NO_DEPRECATED
36
38 const std::string& dll_name,
39 const std::string& fn_name)
40{
41 return subopen(factory, dll_name, fn_name);
42}
43
44bool YarpPluginSettings::subopen(SharedLibraryFactory& factory,
45 const std::string& dll_name,
46 const std::string& fn_name)
47{
48 yCDebug(YARPPLUGINSETTINGS,
49 "Trying plugin [dll: %s] [fn: %s]",
50 dll_name.c_str(),
51 fn_name.c_str());
52 bool ok = factory.open(dll_name.c_str(), fn_name.c_str());
53 yCDebug(YARPPLUGINSETTINGS,
54 "Trying to find library '%s' containing function '%s' -- %s",
55 dll_name.c_str(),
56 fn_name.c_str(), ok ? "found" : "fail");
57 if (ok) {
58 yCDebug(YARPPLUGINSETTINGS,
59 "Found plugin [dll: %s] [fn: %s]",
60 dll_name.c_str(),
61 fn_name.c_str());
62 this->dll_name = dll_name;
63 this->fn_name = fn_name;
64 } else {
66 yCError(YARPPLUGINSETTINGS,
67 "Error while opening %s:\n %s",
68 dll_name.c_str(),
69 factory.getError().c_str());
70 } else {
71 yCDebug(YARPPLUGINSETTINGS,
72 "Error while opening %s:\n %s",
73 dll_name.c_str(),
74 factory.getError().c_str());
75 }
76 }
77 return ok;
78}
79
81{
82 yCDebug(YARPPLUGINSETTINGS,
83 "Plugin [name: %s] [dll: %s] [fn: %s]",
84 name.c_str(),
85 dll_name.c_str(),
86 fn_name.c_str());
87 if (selector != nullptr && !name.empty()) {
88 // we may have a YARP-specific search path available,
89 // and a proper name for the DLL
90 Bottle paths = selector->getSearchPath();
91 for (size_t i = 0; i < paths.size(); i++) {
92 Searchable& options = paths.get(i);
93 std::string path = options.find("path").asString();
94 std::string ext = options.find("extension").asString();
95 std::string basename = (dll_name.find('.') != std::string::npos) ? name : dll_name;
96 std::string fn = (fn_name.empty()) ? name : fn_name;
97
98 std::string fullpath;
99
100#if defined(_MSC_VER) && !defined(NDEBUG)
101 // MSVC DEBUG build: try debug name before basic name
102 fullpath = std::string(path).append("/").append(basename).append("d").append(ext);
103 if (subopen(factory, fullpath, fn))
104 return true;
105#endif // defined(_MSC_VER) && !defined(NDEBUG)
106
107 // Basic name
108 fullpath = std::string(path).append("/").append(basename).append(ext);
109 if (subopen(factory, fullpath, fn)) {
110 return true;
111 }
112
113#if defined(_MSC_VER) && defined(NDEBUG)
114 // MSVC RELEASE build: try debug name after basic name
115 fullpath = std::string(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
121#ifdef CMAKE_INTDIR
122 // On multi-config system, try to find the plugin in the
123 // current config subdirectory
124
125# if defined(_MSC_VER) && !defined(NDEBUG)
126 // MSVC DEBUG build: try debug name before basic name
127 fullpath = std::string(path).append("/" CMAKE_INTDIR "/").append(dll_name).append("d").append(ext);
128 if (subopen(factory, fullpath, fn))
129 return true;
130# endif // defined(_MSC_VER) && !defined(NDEBUG)
131
132 // Basic name
133 fullpath = std::string(path).append("/" CMAKE_INTDIR "/").append(dll_name).append(ext);
134 if (subopen(factory, fullpath, fn))
135 return true;
136
137# if defined(_MSC_VER) && defined(NDEBUG)
138 // MSVC RELEASE build: try debug name after basic name
139 fullpath = std::string(path).append("/" CMAKE_INTDIR "/").append(dll_name).append("d").append(ext);
140 if (subopen(factory, fullpath, fn))
141 return true;
142# endif // defined(_MSC_VER) && defined(NDEBUG)
143
144#endif // CMAKE_INTDIR
145 }
146 }
147 if (!dll_name.empty() || !fn_name.empty()) {
148 return open(factory, dll_name, fn_name);
149 }
150 return factory.open((std::string("yarp_") + name).c_str(),
151 (fn_name.empty()) ? name.c_str() : fn_name.c_str());
152}
153
155{
156 int problem = factory.getStatus();
157 if (problem == 0) {
158 return;
159 }
160 switch (problem) {
162 yCDebug(YARPPLUGINSETTINGS, "Cannot load plugin from shared library (%s)", dll_name.c_str());
163 yCDebug(YARPPLUGINSETTINGS, "(%s)", factory.getError().c_str());
164 break;
166 yCWarning(YARPPLUGINSETTINGS, "Cannot load plugin from shared library (%s)", dll_name.c_str());
167 yCWarning(YARPPLUGINSETTINGS, "(%s)", factory.getError().c_str());
168 break;
170 yCWarning(YARPPLUGINSETTINGS, "Cannot find YARP hook in shared library (%s:%s)", dll_name.c_str(), fn_name.c_str());
171 yCWarning(YARPPLUGINSETTINGS, "(%s)", factory.getError().c_str());
172 break;
174 yCWarning(YARPPLUGINSETTINGS, "YARP hook in shared library misbehaved (%s:%s)", dll_name.c_str(), fn_name.c_str());
175 yCWarning(YARPPLUGINSETTINGS, "(the library may be too old/new and need to be recompiled to match YARP version)");
176 yCWarning(YARPPLUGINSETTINGS, "(%s)", factory.getError().c_str());
177 break;
178 default:
179 yCWarning(YARPPLUGINSETTINGS, "Unknown error (%s:%s)", dll_name.c_str(), fn_name.c_str());
180 yCWarning(YARPPLUGINSETTINGS, "(%s)", factory.getError().c_str());
181 break;
182 }
183}
184
186{
187 yCError(YARPPLUGINSETTINGS, "Failed to create %s from shared library %s", fn_name.c_str(), dll_name.c_str());
188}
189
190bool YarpPluginSettings::readFromSelector(const std::string& name)
191{
192 if (!selector) {
193 return false;
194 }
195 Bottle plugins = selector->getSelectedPlugins();
196 Bottle group = plugins.findGroup(name).tail();
197 if (group.isNull()) {
198 yCError(YARPPLUGINSETTINGS,
199 "Cannot find \"%s\" plugin (not built in, and no .ini file found for it)"
200 "Check that YARP_DATA_DIRS leads to at least one directory with plugins/%s.ini "
201 "or share/yarp/plugins/%s.ini in it",
202 name.c_str(),
203 name.c_str(),
204 name.c_str());
205 return false;
206 }
207 return readFromSearchable(group, name);
208}
209
211{
212 // This method needs to be accessed by one thread only
213 std::lock_guard<std::mutex> guard(mutex);
214
215 // If it was scanned in the last 5 seconds, there is no need to scan again
216 bool need_scan = true;
217 if (config.check("last_update_time")) {
218 if (SystemClock::nowSystem() - config.find("last_update_time").asFloat64() < 5) {
219 need_scan = false;
220 }
221 }
222 if (!need_scan) {
223 return;
224 }
225
226 yCDebug(YARPPLUGINSETTINGS, "Scanning. I'm scanning. I hope you like scanning too.");
227
228 // Search plugins directories
230 static std::mutex rf_mutex;
231 std::lock_guard<std::mutex> rf_guard(rf_mutex);
232
233 if (!rf.isConfigured()) {
234 rf.configure(0, nullptr);
235 }
236 Bottle plugin_paths = rf.findPaths("plugins");
237 if (plugin_paths.size() == 0) {
238 plugin_paths = rf.findPaths("share/yarp/plugins");
239 }
240
241 // Search .ini files in plugins directories
242 config.clear();
243 if (plugin_paths.size() > 0) {
244 for (size_t i = 0; i < plugin_paths.size(); i++) {
245 std::string target = plugin_paths.get(i).asString();
246 yCDebug(YARPPLUGINSETTINGS, "Loading configuration files related to plugins from %s.",
247 target.c_str());
248 config.fromConfigDir(target, "inifile", false);
249 }
250 } else {
251 yCDebug(YARPPLUGINSETTINGS, "Plugin directory not found");
252 }
253
254 // Read the .ini files and populate the lists
255 plugins.clear();
256 search_path.clear();
257 Bottle inilst = config.findGroup("inifile").tail();
258 for (size_t i = 0; i < inilst.size(); i++) {
259 std::string inifile = inilst.get(i).asString();
260 Bottle inigroup = config.findGroup(inifile);
261 Bottle lst = inigroup.findGroup("plugin").tail();
262 for (size_t i = 0; i < lst.size(); i++) {
263 std::string plugin_name = lst.get(i).asString();
264 Bottle group = inigroup.findGroup(plugin_name);
265 group.add(Value::makeValue(std::string("(inifile \"") + inifile + "\")"));
266 if (select(group)) {
267 plugins.addList() = group;
268 }
269 }
270 lst = inigroup.findGroup("search").tail();
271 for (size_t i = 0; i < lst.size(); i++) {
272 std::string search_name = lst.get(i).asString();
273 Bottle group = inigroup.findGroup(search_name);
274 search_path.addList() = group;
275 }
276 }
277
278 // Update last_update_time
279 config.put("last_update_time", SystemClock::nowSystem());
280}
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:336
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:302
Bottle tail() const
Get all but the first element of a bottle.
Definition: Bottle.cpp:388
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:370
@ DebugType
Definition: Log.h:92
@ InfoType
Definition: Log.h:93
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Property.cpp:1051
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:1015
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition: Property.cpp:1041
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().
Definition: Property.cpp:1093
void clear()
Remove all associations.
Definition: Property.cpp:1057
Bottle & findGroup(const std::string &key) const override
Gets a list corresponding to a given keyword.
Definition: Property.cpp:1142
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:63
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()
Definition: SystemClock.cpp:34
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.
Definition: YarpPlugin.cpp:210
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.
Definition: YarpPlugin.cpp:80
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.
Definition: YarpPlugin.cpp:154
void reportFailure() const
Give a human-readable failure-to-load report, summarizing the active hints.
Definition: YarpPlugin.cpp:185
#define yCError(component,...)
Definition: LogComponent.h:213
#define yCWarning(component,...)
Definition: LogComponent.h:192
#define yCDebug(component,...)
Definition: LogComponent.h:128
#define YARP_OS_LOG_COMPONENT(name, name_string)
Definition: LogComponent.h:29
#define YARP_OS_NON_CONST_LOG_COMPONENT(name, name_string)
Definition: LogComponent.h:40
The components from which ports and connections are built.
An interface to the operating system, including Port based communication.