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