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 
6 #include <yarp/os/YarpPlugin.h>
7 
8 #include <yarp/os/Network.h>
9 #include <yarp/os/Property.h>
10 #include <yarp/os/ResourceFinder.h>
11 #include <yarp/os/SystemClock.h>
14 
15 #include <cstdio>
16 #include <cstdlib>
17 
18 using namespace yarp::os;
19 using namespace yarp::os::impl;
20 
21 namespace {
22 #ifndef YARP_NO_DEPRECATED // since YARP 3.4
23 // The log component cannot be const because we still support setVerboseMode
24 YARP_OS_NON_CONST_LOG_COMPONENT(YARPPLUGINSETTINGS, "yarp.os.YarpPluginSettings")
25 #else
26 YARP_OS_LOG_COMPONENT(YARPPLUGINSETTINGS, "yarp.os.YarpPluginSettings")
27 #endif
28 } // namespace
29 
30 #ifndef YARP_NO_DEPRECATED // since YARP 3.4
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 
44 bool 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 
190 bool 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:73
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
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
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
bool open(SharedLibraryFactory &factory)
Initialize a factory object based on the hints available.
Definition: YarpPlugin.cpp:80
void reportStatus(SharedLibraryFactory &factory) const
Give a human-readable report of the status of a factory.
Definition: YarpPlugin.cpp:154
void setVerboseMode(bool verbose)
Should messages be printed showing what searches YARP is trying out?
Definition: YarpPlugin.cpp:31
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.