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