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