ComponentLoader.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Thu Feb 1 16:30:11 2007 +0000 ComponentLoader.cpp
3 
4  ComponentLoader.cpp - description
5  -------------------
6  begin : Thu Feb 1 2007
7  copyright : (C) 2007 Peter Soetens
8  email : peter@thesourceworks.com
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 
39 #include "ComponentLoader.hpp"
40 #include <rtt/TaskContext.hpp>
41 #include <rtt/Logger.hpp>
42 #include <boost/filesystem.hpp>
43 #include <boost/version.hpp>
47 
48 #ifndef _WIN32
49 # include <dlfcn.h>
50 #endif
51 
52 #include <vector>
53 #include <set>
54 
55 using namespace RTT;
56 using namespace RTT::detail;
57 using namespace std;
58 using namespace boost::filesystem;
59 
60 namespace RTT
61 {
62  // We have our own copy of the Factories object to store all
63  // loaded component types. This is pointer is only shared with the DeploymentComponent.
65 }
66 
67 // chose the file extension and debug postfix applicable to the O/S
68 #ifdef __APPLE__
69 static const std::string SO_EXT(".dylib");
70 static const std::string SO_POSTFIX("");
71 #else
72 # ifdef _WIN32
73 static const std::string SO_EXT(".dll");
74 # ifdef _DEBUG
75 static const std::string SO_POSTFIX("d");
76 # else
77 static const std::string SO_POSTFIX("");
78 # endif // _DEBUG
79 # else
80 static const std::string SO_EXT(".so");
81 static const std::string SO_POSTFIX("");
82 # endif
83 #endif
84 
85 // The full library suffix must be enforced by the UseOrocos macros
86 static const std::string FULL_COMPONENT_SUFFIX(string("-") + string(OROCOS_TARGET_NAME) + SO_POSTFIX + SO_EXT);
87 
88 // choose how the PATH looks like
89 # ifdef _WIN32
90 static const std::string delimiters(";");
91 static const char default_delimiter(';');
92 # else
93 static const std::string delimiters(":;");
94 static const char default_delimiter(':');
95 # endif
96 
105 static RTT_UNUSED bool isExtensionVersion(const std::string& ext)
106 {
107  bool isExtensionVersion = false;
108 
109  if (!ext.empty() && ('.' == ext[0]))
110  {
111  std::istringstream iss;
112  int i;
113 
114  iss.str(ext.substr((size_t)1)); // take all after the '.'
115  iss >> std::dec >> std::noskipws >> i;
116  isExtensionVersion = !iss.fail() && iss.eof();
117  }
118 
119  return isExtensionVersion;
120 }
121 
122 /* Is this a dynamic library that we should load from within a directory scan?
123 
124  Versioned libraries are not loaded, to prevent loading both libfoo.so and
125  libfoo.so.1 (which is typically a symlink to libfoo.so, and so loading
126  the same library twice).
127 
128  Libraries are either (NB x.y.z is version, and could also be x or x.y)
129 
130  Linux
131  libfoo.so = load this
132  libfoo.so.x.y.z = don't load this
133 
134  Windows
135  libfoo.dll = load this
136 
137  Mac OS X
138  libfoo.dylib = load this
139  libfoo.x.y.z.dylib = don't load this
140 
141  All the above also apply without the "lib" prefix.
142 */
143 static bool isLoadableLibrary(const path& filename)
144 {
145  bool isLoadable = false;
146 
147 #if defined(__APPLE__)
148  std::string ext;
149 #if BOOST_VERSION >= 104600
150  ext = filename.extension().string();
151 #else
152  ext = filename.extension();
153 #endif
154  // ends in SO_EXT?
155  if (0 == ext.compare(SO_EXT))
156  {
157  // Ends in SO_EXT and so must not be a link for us to load
158  // Links are of the form abc.x.dylib or abc.x.y.dylib or abc.x.y.z.dylib,
159  // where x,y,z are positive numbers
160  path name = filename.stem(); // drop SO_EXT
161  path ext = name.extension();
162  isLoadable =
163  // wasn't just SO_EXT
164  !name.empty() &&
165  // and if there is and extension then it is not a number
166  (ext.empty() || !isExtensionVersion(ext.string()));
167  }
168  // else is not loadable
169 
170 #else
171  // Linux or Windows
172 
173  // must end in SO_EXT and have a non-extension part
174  isLoadable =
175  (filename.extension() == SO_EXT) &&
176  !filename.stem().empty();
177 #endif
178 
179  return isLoadable;
180 }
181 
182 namespace {
183 
184 // copied from RTT::PluginLoader
185 static vector<string> splitPaths(string const& str)
186 {
187  vector<string> paths;
188 
189  // Skip delimiters at beginning.
190  string::size_type lastPos = str.find_first_not_of(delimiters, 0);
191  // Find first "non-delimiter".
192  string::size_type pos = str.find_first_of(delimiters, lastPos);
193 
194  while (string::npos != pos || string::npos != lastPos)
195  {
196  // Found a token, add it to the vector.
197  if ( !str.substr(lastPos, pos - lastPos).empty() )
198  paths.push_back(str.substr(lastPos, pos - lastPos));
199  // Skip delimiters. Note the "not_of"
200  lastPos = str.find_first_not_of(delimiters, pos);
201  // Find next "non-delimiter"
202  pos = str.find_first_of(delimiters, lastPos);
203  }
204  if ( paths.empty() )
205  paths.push_back(".");
206  return paths;
207 }
208 
209 static void removeDuplicates(string& path_list)
210 {
211  vector<string> paths;
212  set<string> seen;
213  string result;
214 
215  // split path_lists
216  paths = splitPaths( path_list );
217 
218  // iterate over paths and append to result
219  for(vector<string>::const_iterator it = paths.begin(); it != paths.end(); ++it)
220  {
221  if (seen.count(*it))
222  continue;
223  else
224  seen.insert(*it);
225 
226  result = result + *it + default_delimiter;
227  }
228 
229  // remove trailing delimiter
230  if (result.size() > 0 && result.at(result.size() - 1) == default_delimiter)
231  result = result.substr(0, result.size() - 1);
232 
233  path_list.swap(result);
234 }
235 
242 static string makeShortFilename(string const& str) {
243  string ret = str;
244  if (str.substr(0,3) == "lib")
245  ret = str.substr(3);
246  if (ret.rfind(FULL_COMPONENT_SUFFIX) != string::npos)
247  ret = ret.substr(0, ret.rfind(FULL_COMPONENT_SUFFIX) );
248  return ret;
249 }
250 
251 }
252 
253 static RTT_UNUSED bool hasEnding(string const &fullString, string const &ending)
254 {
255  if (fullString.length() > ending.length()) {
256  return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
257  } else {
258  return false;
259  }
260 }
261 
262 namespace RTT {
263  extern char const* default_comp_path_build;
264 }
265 
266 namespace {
270  int loadComponents()
271  {
272  std::string default_comp_path = ::default_comp_path_build;
273 
274  char* paths = getenv("RTT_COMPONENT_PATH");
275  string component_paths;
276  if (paths) {
277  component_paths = paths;
278  // prepend the default search path.
279  if ( !default_comp_path.empty() )
280  component_paths = component_paths + default_delimiter + default_comp_path;
281  removeDuplicates( component_paths );
282  log(Info) <<"RTT_COMPONENT_PATH was set to: " << paths << " . Searching in: "<< component_paths<< endlog();
283  } else {
284  component_paths = default_comp_path;
285  removeDuplicates( component_paths );
286  log(Info) <<"No RTT_COMPONENT_PATH set. Using default: " << component_paths <<endlog();
287  }
288  // we set the component path such that we can search for sub-directories/projects lateron
289  ComponentLoader::Instance()->setComponentPath(component_paths);
290  return 0;
291  }
292 
293  os::InitFunction component_loader( &loadComponents );
294 
295  void unloadComponents()
296  {
298  }
299 
300  os::CleanupFunction component_unloader( &unloadComponents );
301 }
302 
303 static boost::shared_ptr<ComponentLoader> instance2;
304 
305 boost::shared_ptr<ComponentLoader> ComponentLoader::Instance() {
306  if (!instance2)
307  instance2.reset( new ComponentLoader() );
308  return instance2;
309 }
310 
312  instance2.reset();
313 }
314 
315 // This is the dumb import function that takes an existing directory and
316 // imports components and plugins from it.
317 bool ComponentLoader::import( std::string const& path_list )
318 {
319  RTT::Logger::In in("ComponentLoader::import(path_list)");
320 
321  if (path_list.empty() ) {
322  log(Error) << "import paths: No paths were given for loading ( path_list = '' )."<<endlog();
323  return false;
324  }
325 
326  // we return false if nothing was found here, or an error happened during loading of a library.
327  vector<string> paths;
328  paths = splitPaths( path_list ); // import package or path list.
329 
330  bool all_good = true, found = false;
331  // perform search in paths:
332  for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
333  {
334  // Scan path/* (non recursive) for components
335  path p = path(*it);
336  if (is_directory(p))
337  {
338  log(Info) << "Importing directory " << p.string() << " ..."<<endlog();
339  for (directory_iterator itr(p); itr != directory_iterator(); ++itr)
340  {
341  log(Debug) << "Scanning file " << itr->path().string() << " ...";
342  if (is_regular_file(itr->status()) && isLoadableLibrary(itr->path()) ) {
343  found = true;
344  std::string libname;
345 #if BOOST_VERSION >= 104600
346  libname = itr->path().filename().string();
347 #else
348  libname = itr->path().filename();
349 #endif
350  if(!isCompatibleComponent(libname))
351  {
352  log(Debug) << "not a compatible component: ignored."<<endlog();
353  }
354  else
355  {
356  found = true;
357  all_good = loadInProcess( itr->path().string(), makeShortFilename(libname ), true) && all_good;
358  }
359  } else {
360  if (!is_regular_file(itr->status()))
361  log(Debug) << "not a regular file: ignored."<<endlog();
362  else
363  log(Debug) << "not a " + SO_EXT + " library: ignored."<<endlog();
364  }
365  }
366  log(Debug) << "Looking for plugins or typekits in directory " << p.string() << " ..."<<endlog();
367  try {
368  found = PluginLoader::Instance()->loadTypekits( p.string() ) || found;
369  found = PluginLoader::Instance()->loadPlugins( p.string() ) || found;
370  } catch (std::exception& e) {
371  all_good = false;
372  log(Error) << e.what() <<endlog();
373  }
374  }
375  else {
376  // If the path is not complete (not absolute), look it up in the search directories:
377  log(Debug) << "No such directory: " << p<< endlog();
378  }
379  }
380  if (!all_good)
381  throw std::runtime_error("Some found plugins could not be loaded !");
382  return found;
383 }
384 
385 // this is the smart import function that tries to guess where 'package' lives in path_list or
386 // the search path.
387 bool ComponentLoader::import( std::string const& package, std::string const& path_list )
388 {
389  RTT::Logger::In in("ComponentLoader::import(package, path_list)");
390 
391  // check first for exact match to *file*:
392  path arg( package );
393  if (is_regular_file(arg) && isLoadableLibrary(arg)) {
394 #if BOOST_VERSION >= 104600
395  return loadInProcess(arg.string(), makeShortFilename( arg.filename().string() ), true);
396 #else
397  return loadInProcess(arg.string(), makeShortFilename( arg.filename() ), true);
398 #endif
399  }
400 
401  // check for absolute path:
402  if ( arg.is_complete() ) {
403  // plain import
404  bool ret = import(package);
405  // if not yet given, test for target subdir:
406  if ( arg.parent_path().leaf() != OROCOS_TARGET_NAME )
407  ret = import( (arg / OROCOS_TARGET_NAME).string() ) || ret;
408  // if something found, return true:
409  if (ret)
410  return true;
411  // both failed:
412  log(Error) << "Could not import absolute path '"<<package << "': nothing found."<<endlog();
413  return false;
414  }
415 
416  if ( isImported(package) ) {
417  log(Info) <<"Component package '"<< package <<"' already imported." <<endlog();
418  return true;
419  }
420 
421  // Try the RTT_COMPONENT_PATH:
422  return importInstalledPackage(package, path_list);
423 }
424 
425 bool ComponentLoader::importInstalledPackage(std::string const& package, std::string const& path_list)
426 {
427  RTT::Logger::In in("ComponentLoader::importInstalledPackage(package, path_list)");
428 
429  string paths;
430  string trypaths;
431  vector<string> tryouts;
432  if (path_list.empty())
433  paths = component_path + default_delimiter + ".";
434  else
435  paths = path_list;
436 
437  bool path_found = false;
438 
439  // if ros did not find anything, split the paths above.
440  // set vpaths from (default) search paths.
441  vector<string> vpaths;
442  vpaths = splitPaths(paths);
443  trypaths = paths; // store for error reporting below.
444  paths.clear();
445  // Detect absolute/relative import:
446  path p( package );
447  if (is_directory( p )) {
448  path_found = true;
449  // search in dir + dir/TARGET
450  paths += p.string() + default_delimiter + (p / OROCOS_TARGET_NAME).string() + default_delimiter;
451  if ( p.is_complete() ) {
452  // 2.2.x: path may be absolute or relative to search path.
453  //log(Warning) << "You supplied an absolute directory to the import directive. Use 'path' to set absolute directories and 'import' only for packages (sub directories)."<<endlog();
454  //log(Warning) << "Please modify your XML file or script. I'm importing it now for the sake of backwards compatibility."<<endlog();
455  } // else: we allow to import a subdirectory of '.'.
456  }
457  // append '/package' or 'target/package' to each plugin path in order to search all of them:
458  for(vector<string>::iterator it = vpaths.begin(); !path_found && it != vpaths.end(); ++it) {
459  p = *it;
460  p = p / package;
461  // we only search in existing directories:
462  if (is_directory( p )) {
463  path_found = true;
464  paths += p.string() + default_delimiter ;
465  } else
466  tryouts.push_back( p.string() );
467  p = *it;
468  p = p / OROCOS_TARGET_NAME / package;
469  // we only search in existing directories:
470  if (is_directory( p )) {
471  path_found = true;
472  paths += p.string() + default_delimiter ;
473  } else
474  tryouts.push_back( p.string() );
475  }
476  if ( path_found )
477  paths.erase( paths.size() - 1 ); // remove trailing delimiter ';'
478 
479  // when at least one directory exists:
480  if (path_found) {
481  if ( import(paths) ) {
482  loadedPackages.push_back( package );
483  return true;
484  } else {
485  log(Error) << "Failed to import components, types or plugins from package or directory '"<< package <<"' found in:"<< endlog();
486  log(Error) << paths << endlog();
487  return false;
488  }
489  }
490  log(Error) << "No such package or directory found in search path: " << package << ". Search path is: " << trypaths << endlog();
491  log(Error) << "Directories searched include the following: " << endlog();
492  for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it)
493  log(Error) << " - " << *it << endlog();
494  return false;
495 }
496 
497 bool ComponentLoader::reloadLibrary(std::string const& name)
498 {
499  path arg = name;
500  // check for direct match:
501 #if BOOST_VERSION >= 104600
502  if (is_regular_file( arg ) && reloadInProcess( arg.string(), makeShortFilename( arg.filename().string() ) ) )
503 #else
504  if (is_regular_file( arg ) && reloadInProcess( arg.string(), makeShortFilename( arg.filename() ) ) )
505 #endif
506  return true;
507  // bail out if not an absolute path
508  return false;
509 }
510 
511 bool ComponentLoader::loadLibrary( std::string const& name )
512 {
513  path arg = name;
514  // check for direct match:
515 #if BOOST_VERSION >= 104600
516  if (is_regular_file( arg ) && loadInProcess( arg.string(), makeShortFilename( arg.filename().string() ), true ) )
517 #else
518  if (is_regular_file( arg ) && loadInProcess( arg.string(), makeShortFilename( arg.filename() ), true ) )
519 #endif
520  return true;
521  // bail out if absolute path
522  if ( arg.is_complete() )
523  return false;
524 
525  // search for relative match
526  vector<string> paths = splitPaths( component_path );
527  vector<string> tryouts( paths.size() * 4 );
528  tryouts.clear();
529  path dir = arg.parent_path();
530 #if BOOST_VERSION >= 104600
531  string file = arg.filename().string();
532 #else
533  string file = arg.filename();
534 #endif
535 
536  for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
537  {
538  path p = path(*it) / dir / (file + FULL_COMPONENT_SUFFIX);
539  tryouts.push_back( p.string() );
540  if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
541  return true;
542  p = path(*it) / dir / ("lib" + file + FULL_COMPONENT_SUFFIX);
543  tryouts.push_back( p.string() );
544  if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
545  return true;
546  p = path(*it) / OROCOS_TARGET_NAME / dir / (file + FULL_COMPONENT_SUFFIX);
547  tryouts.push_back( p.string() );
548  if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
549  return true;
550  p = path(*it) / OROCOS_TARGET_NAME / dir / ("lib" + file + FULL_COMPONENT_SUFFIX);
551  tryouts.push_back( p.string() );
552  if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
553  return true;
554  }
555  log(Debug) << "No such library found in path: " << name << ". Tried:"<< endlog();
556  for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it)
557  log(Debug) << *it << endlog();
558  return false;
559 }
560 
561 bool ComponentLoader::isImported(string type_name)
562 {
563  if (ComponentFactories::Instance().find(type_name) != ComponentFactories::Instance().end() )
564  return true;
565  if (find(loadedPackages.begin(), loadedPackages.end(), type_name) != loadedPackages.end())
566  return true;
567  // hack: in current versions, ocl is loaded most of the times by default because it does not reside in a package subdir
568  // once ocl is in the 'ocl' package directory, this code becomes obsolete:
569  if ( type_name == "ocl" && TypekitRepository::hasTypekit("OCLTypekit")) {
570  return true;
571  }
572  return false;
573 }
574 
575 bool ComponentLoader::reloadInProcess(string file, string libname)
576 {
577  path p(file);
578 
579  // check if the library is already loaded
580  // NOTE if this library has been loaded, you can unload and reload it to apply changes (may be you have updated the dynamic library)
581  // anyway it is safe to do this only if there isn't any instance whose type was loaded from this library
582 
583  std::vector<LoadedLib>::iterator lib = loadedLibs.begin();
584  while (lib != loadedLibs.end()) {
585  // We only reload if it's exactly the same file.
586  if ( lib->filename == file) {
587  log(Info) <<"Component library "<< lib->filename <<" already loaded... " ;
588 
589  bool can_unload = true;
590  CompList::iterator cit;
591  for( std::vector<std::string>::iterator ctype = lib->components_type.begin(); ctype != lib->components_type.end() && can_unload; ++ctype) {
592  for ( cit = comps.begin(); cit != comps.end(); ++cit) {
593  if( (*ctype) == cit->second.type ) {
594  // the type of an allocated component was loaded from this library. it might be unsafe to reload the library
595  log(Info) << "can NOT reload library because of the instance " << cit->second.type <<"::"<<cit->first <<endlog();
596  can_unload = false;
597  }
598  }
599  }
600  if( can_unload ) {
601  log(Info) << "try to RELOAD"<<endlog();
602  dlclose(lib->handle);
603  // remove the library info from the vector
604  std::vector<LoadedLib>::iterator lib_un = lib;
605  loadedLibs.erase(lib_un);
606  return loadInProcess(file, libname, true);
607  }
608  else
609  return false;
610  }
611  else lib++;
612  }
613  log(Error) << "Can't reload Component library "<< file << " since it was not loaded or is not a component library." <<endlog();
614  return false;
615 }
616 
617 // loads a single component in the current process.
618 bool ComponentLoader::loadInProcess(string file, string libname, bool log_error) {
619  path p(file);
620  char* error;
621  void* handle;
622  bool success=false;
623 
624  // Last chance to validate component compatibility
625  if(!isCompatibleComponent(file))
626  {
627  if(log_error)
628  log(Error) << "Could not load library '"<< p.string() <<"': incompatible." <<endlog();
629  return false;
630  }
631 
632  handle = dlopen ( p.string().c_str(), RTLD_NOW);
633 
634  if (!handle) {
635  if ( log_error ) {
636  log(Error) << "Could not load library '"<< p.string() <<"':"<<endlog();
637  log(Error) << dlerror() << endlog();
638  }
639  return false;
640  }
641 
642  //------------- if you get here, the library has been loaded -------------
643  log(Debug)<<"Succesfully loaded "<<libname<<endlog();
644  LoadedLib loading_lib(file, libname, handle);
645  dlerror(); /* Clear any existing error */
646 
647  // Lookup Component factories (multi component case):
648  FactoryMap* (*getfactory)(void) = 0;
649  vector<string> (*getcomponenttypes)(void) = 0;
650  FactoryMap* fmap = 0;
651  getfactory = (FactoryMap*(*)(void))( dlsym(handle, "getComponentFactoryMap") );
652  if ((error = dlerror()) == NULL) {
653  // symbol found, register factories...
654  fmap = (*getfactory)();
655  ComponentFactories::Instance().insert( fmap->begin(), fmap->end() );
656  log(Info) << "Loaded multi component library '"<< file <<"'"<<endlog();
657  getcomponenttypes = (vector<string>(*)(void))(dlsym(handle, "getComponentTypeNames"));
658  if ((error = dlerror()) == NULL) {
659  log(Debug) << "Components:";
660  vector<string> ctypes = getcomponenttypes();
661  for (vector<string>::iterator it = ctypes.begin(); it != ctypes.end(); ++it)
662  log(Debug) <<" "<< *it;
663  log(Debug) << endlog();
664  }
665  loadedLibs.push_back(loading_lib);
666  success = true;
667  }
668 
669  // Lookup createComponent (single component case):
670  dlerror(); /* Clear any existing error */
671 
672  RTT::TaskContext* (*factory)(std::string) = 0;
673  std::string(*tname)(void) = 0;
674  factory = (RTT::TaskContext*(*)(std::string))(dlsym(handle, "createComponent") );
675  string create_error;
676  error = dlerror();
677  if (error) create_error = error;
678  tname = (std::string(*)(void))(dlsym(handle, "getComponentType") );
679  string gettype_error;
680  error = dlerror();
681  if (error) gettype_error = error;
682  if ( factory && tname ) {
683  std::string cname = (*tname)();
684  if ( ComponentFactories::Instance().count(cname) == 1 ) {
685  log(Warning) << "Component type name "<<cname<<" already used: overriding."<<endlog();
686  }
687  ComponentFactories::Instance()[cname] = factory;
688  log(Info) << "Loaded component type '"<< cname <<"'"<<endlog();
689  loading_lib.components_type.push_back( cname );
690  loadedLibs.push_back(loading_lib);
691  success = true;
692  }
693 
694  if (success) return true;
695 
696  log(Error) <<"Unloading "<< loading_lib.filename <<": not a valid component library:" <<endlog();
697  if (!create_error.empty())
698  log(Error) << " " << create_error << endlog();
699  if (!gettype_error.empty())
700  log(Error) << " " << gettype_error << endlog();
701  dlclose(handle);
702  return false;
703 }
704 
705 std::vector<std::string> ComponentLoader::listComponentTypes() const {
706  vector<string> names;
707  FactoryMap::iterator it;
708  for( it = ComponentFactories::Instance().begin(); it != ComponentFactories::Instance().end(); ++it) {
709  names.push_back( it->first );
710  }
711  return names;
712 }
713 
715  string ret = component_path;
716  // append default delimiter if not present. such that it can be combined with a new path.
717  if ( ret.length() && ret[ ret.length() -1 ] != default_delimiter )
718  ret += default_delimiter;
719  return ret;
720 }
721 
722 void ComponentLoader::setComponentPath( std::string const& newpath ) {
723  component_path = newpath;
724 }
725 
726 
727 RTT::TaskContext *ComponentLoader::loadComponent(const std::string & name, const std::string & type)
728 {
729  TaskContext* instance = 0;
730  RTT::TaskContext* (*factory)(std::string name) = 0;
731  log(Debug) << "Trying to create component "<< name <<" of type "<< type << endlog();
732 
733  // First: try loading from imported libraries. (see: import).
734  if ( ComponentFactories::Instance().count(type) == 1 ) {
735  factory = ComponentFactories::Instance()[ type ];
736  if (factory == 0 ) {
737  log(Error) <<"Found empty factory for Component type "<<type<<endlog();
738  return 0;
739  }
740  }
741 
742  if ( factory ) {
743  log(Debug) <<"Found factory for Component type "<<type<<endlog();
744  } else {
745  log(Error) << "Unable to create Orocos Component '"<<type<<"': unknown component type." <<endlog();
746  return 0;
747  }
748 
749  comps[name].type = type;
750 
751  try {
752  comps[name].instance = instance = (*factory)(name);
753  } catch(...) {
754  log(Error) <<"The constructor of component type "<<type<<" threw an exception!"<<endlog();
755  }
756 
757  if ( instance == 0 ) {
758  log(Error) <<"Failed to load component with name "<<name<<": refused to be created."<<endlog();
759  }
760  return instance;
761 }
762 
764  if (!tc)
765  return false;
766  CompList::iterator it = comps.begin();
767  for(; it != comps.end(); ++it ) {
768  if ( it->second.instance == tc) break;
769  }
770 
771  if ( it != comps.end() ) {
772  delete it->second.instance;
773  comps.erase(it);
774  return true;
775  }
776  log(Error) <<"Refusing to unload a component I didn't load myself."<<endlog();
777  return false;
778 }
779 
780 std::vector<std::string> ComponentLoader::listComponents() const
781 {
782  vector<string> names( comps.size() );
783  for(map<string,ComponentData>::const_iterator it = comps.begin(); it != comps.end(); ++it)
784  names.push_back( it->first );
785  return names;
786 }
787 
788 bool ComponentLoader::isCompatibleComponent(std::string const& filepath)
789 {
790  path p(filepath);
791 
792 #if BOOST_VERSION >= 104600
793  string libname = p.filename().string();
794 #else
795  string libname = p.filename();
796 #endif
797 
798  //log(Debug) << "Validating compatility of component file '" + libname + "'" <<endlog();
799 
800 #ifdef _WIN32
801  // On WIN32 target:
802  // - look if the library name ends with "win32.dll" on release mode
803  // - look if the library name ends with "win32d.dll" on debug mode
804  if(!hasEnding(libname, FULL_COMPONENT_SUFFIX))
805  {
806  //log(Debug) << "Component file '" + libname + "' is incompatible because it doesn't have the suffix " << FULL_COMPONENT_SUFFIX << endlog();
807  return false;
808  }
809 #endif // _WIN32
810 
811  // There's no validation on other targets
812 
813  //log(Debug) << "Component file '" + libname + "' is valid." <<endlog();
814 
815  return true;
816 }
817 
819 {
821 }
822 
823 void ComponentLoader::addFactory(std::string const& name, ComponentLoaderSignature factory)
824 {
825  ComponentFactories::Instance()[name] = factory;
826 }
static bool hasTypekit(const std::string &typekitname)
TaskContext *(* ComponentLoaderSignature)(std::string instance_name)
Definition: Component.hpp:61
static const char default_delimiter(':')
void * dlsym(void *handle, const char *name)
Definition: dlfcn.c:261
#define RTLD_NOW
Definition: dlfcn.h:33
bool loadInProcess(std::string filename, std::string shortname, bool log_error)
bool isImported(std::string type_name)
RTT::TaskContext * loadComponent(std::string const &name, std::string const &type)
void addFactory(std::string const &name, ComponentLoaderSignature factory)
Definition: mystd.hpp:163
static RTT_UNUSED bool hasEnding(string const &fullString, string const &ending)
static boost::shared_ptr< ComponentLoader > instance2
static RTT_UNUSED bool isExtensionVersion(const std::string &ext)
static RTT_HIDE FactoryMap & Instance()
Definition: Component.hpp:78
static boost::shared_ptr< ComponentLoader > Instance()
std::map< std::string, ComponentLoaderSignature > FactoryMap
Definition: Component.hpp:62
void * dlopen(const char *file, int mode)
Definition: dlfcn.c:169
char const * default_comp_path_build
static const std::string FULL_COMPONENT_SUFFIX(string("-")+string(OROCOS_TARGET_NAME)+SO_POSTFIX+SO_EXT)
std::vector< std::string > listComponents() const
static RTT_HIDE FactoryMap * Factories
Definition: Component.hpp:76
std::string getComponentPath() const
bool loadLibrary(std::string const &path)
bool import(std::string const &path_list)
static const std::string SO_EXT(".so")
int dlclose(void *handle)
Definition: dlfcn.c:238
std::vector< std::string > listComponentTypes() const
bool reloadLibrary(std::string const &filepath)
void setComponentPath(std::string const &newpath)
static const std::string SO_POSTFIX("")
std::vector< std::string > components_type
bool unloadComponent(RTT::TaskContext *tc)
static boost::shared_ptr< PluginLoader > Instance()
char * dlerror(void)
Definition: dlfcn.c:304
bool importInstalledPackage(std::string const &package, std::string const &path_list)
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:53
static const std::string delimiters(":;")
static Logger & log()
Definition: Logger.hpp:350
bool reloadInProcess(std::string filename, std::string shortname)
static Logger::LogFunction endlog()
Definition: Logger.hpp:362
const FactoryMap & getFactories() const
static bool isLoadableLibrary(const path &filename)
bool isCompatibleComponent(std::string const &filepath)


rtt
Author(s): RTT Developers
autogenerated on Tue Jun 25 2019 19:33:22