Orocos Real-Time Toolkit
2.6.0
|
00001 #include "ComponentLoader.hpp" 00002 #include <rtt/TaskContext.hpp> 00003 #include <rtt/Logger.hpp> 00004 #include <boost/filesystem.hpp> 00005 #include <boost/version.hpp> 00006 #include <rtt/os/StartStopManager.hpp> 00007 #include <rtt/plugin/PluginLoader.hpp> 00008 #include <rtt/types/TypekitRepository.hpp> 00009 00010 #ifdef HAS_ROSLIB 00011 #include <rospack/rospack.h> 00012 #endif 00013 00014 #ifndef _WIN32 00015 # include <dlfcn.h> 00016 #endif 00017 00018 using namespace RTT; 00019 using namespace RTT::detail; 00020 using namespace std; 00021 using namespace boost::filesystem; 00022 00023 namespace RTT 00024 { 00025 // We have our own copy of the Factories object to store all 00026 // loaded component types. This is pointer is only shared with the DeploymentComponent. 00027 FactoryMap* ComponentFactories::Factories = 0; 00028 } 00029 00030 // chose the file extension and debug postfix applicable to the O/S 00031 #ifdef __APPLE__ 00032 static const std::string SO_EXT(".dylib"); 00033 static const std::string SO_POSTFIX(""); 00034 #else 00035 # ifdef _WIN32 00036 static const std::string SO_EXT(".dll"); 00037 # ifdef _DEBUG 00038 static const std::string SO_POSTFIX("d"); 00039 # else 00040 static const std::string SO_POSTFIX(""); 00041 # endif // _DEBUG 00042 # else 00043 static const std::string SO_EXT(".so"); 00044 static const std::string SO_POSTFIX(""); 00045 # endif 00046 #endif 00047 00048 // The full library suffix must be enforced by the UseOrocos macros 00049 static const std::string FULL_COMPONENT_SUFFIX(string("-") + string(OROCOS_TARGET_NAME) + SO_POSTFIX + SO_EXT); 00050 00051 // choose how the PATH looks like 00052 # ifdef _WIN32 00053 static const std::string delimiters(";"); 00054 static const char default_delimiter(';'); 00055 # else 00056 static const std::string delimiters(":;"); 00057 static const char default_delimiter(':'); 00058 # endif 00059 00068 static bool isExtensionVersion(const std::string& ext) 00069 { 00070 bool isExtensionVersion = false; 00071 00072 if (!ext.empty() && ('.' == ext[0])) 00073 { 00074 std::istringstream iss; 00075 int i; 00076 00077 iss.str(ext.substr((size_t)1)); // take all after the '.' 00078 iss >> std::dec >> std::noskipws >> i; 00079 isExtensionVersion = !iss.fail() && iss.eof(); 00080 } 00081 00082 return isExtensionVersion; 00083 } 00084 00085 /* Is this a dynamic library that we should load from within a directory scan? 00086 00087 Versioned libraries are not loaded, to prevent loading both libfoo.so and 00088 libfoo.so.1 (which is typically a symlink to libfoo.so, and so loading 00089 the same library twice). 00090 00091 Libraries are either (NB x.y.z is version, and could also be x or x.y) 00092 00093 Linux 00094 libfoo.so = load this 00095 libfoo.so.x.y.z = don't load this 00096 00097 Windows 00098 libfoo.dll = load this 00099 00100 Mac OS X 00101 libfoo.dylib = load this 00102 libfoo.x.y.z.dylib = don't load this 00103 00104 All the above also apply without the "lib" prefix. 00105 */ 00106 static bool isLoadableLibrary(const path& filename) 00107 { 00108 bool isLoadable = false; 00109 00110 #if defined(__APPLE__) 00111 std::string ext; 00112 #if BOOST_VERSION >= 104600 00113 ext = filename.extension().string(); 00114 #else 00115 ext = filename.extension(); 00116 #endif 00117 // ends in SO_EXT? 00118 if (0 == ext.compare(SO_EXT)) 00119 { 00120 // Ends in SO_EXT and so must not be a link for us to load 00121 // Links are of the form abc.x.dylib or abc.x.y.dylib or abc.x.y.z.dylib, 00122 // where x,y,z are positive numbers 00123 path name = filename.stem(); // drop SO_EXT 00124 path ext = name.extension(); 00125 isLoadable = 00126 // wasn't just SO_EXT 00127 !name.empty() && 00128 // and if there is and extension then it is not a number 00129 (ext.empty() || !isExtensionVersion(ext.string())); 00130 } 00131 // else is not loadable 00132 00133 #else 00134 // Linux or Windows 00135 00136 // must end in SO_EXT and have a non-extension part 00137 isLoadable = 00138 (filename.extension() == SO_EXT) && 00139 !filename.stem().empty(); 00140 #endif 00141 00142 return isLoadable; 00143 } 00144 00145 namespace RTT { 00146 extern char const* default_comp_path_build; 00147 } 00148 00149 namespace { 00153 int loadComponents() 00154 { 00155 std::string default_comp_path = ::default_comp_path_build; 00156 00157 char* paths = getenv("RTT_COMPONENT_PATH"); 00158 string component_paths; 00159 if (paths) { 00160 component_paths = paths; 00161 // prepend the default search path. 00162 if ( !default_comp_path.empty() ) 00163 component_paths = component_paths + default_delimiter + default_comp_path; 00164 log(Info) <<"RTT_COMPONENT_PATH was set to: " << paths << " . Searching in: "<< component_paths<< endlog(); 00165 } else { 00166 component_paths = default_comp_path; 00167 log(Info) <<"No RTT_COMPONENT_PATH set. Using default: " << component_paths <<endlog(); 00168 } 00169 // we set the component path such that we can search for sub-directories/projects lateron 00170 ComponentLoader::Instance()->setComponentPath(component_paths); 00171 return 0; 00172 } 00173 00174 os::InitFunction component_loader( &loadComponents ); 00175 00176 void unloadComponents() 00177 { 00178 ComponentLoader::Release(); 00179 } 00180 00181 os::CleanupFunction component_unloader( &unloadComponents ); 00182 } 00183 00184 static boost::shared_ptr<ComponentLoader> instance2; 00185 00186 namespace { 00187 00188 // copied from RTT::PluginLoader 00189 static vector<string> splitPaths(string const& str) 00190 { 00191 vector<string> paths; 00192 00193 // Skip delimiters at beginning. 00194 string::size_type lastPos = str.find_first_not_of(delimiters, 0); 00195 // Find first "non-delimiter". 00196 string::size_type pos = str.find_first_of(delimiters, lastPos); 00197 00198 while (string::npos != pos || string::npos != lastPos) 00199 { 00200 // Found a token, add it to the vector. 00201 if ( !str.substr(lastPos, pos - lastPos).empty() ) 00202 paths.push_back(str.substr(lastPos, pos - lastPos)); 00203 // Skip delimiters. Note the "not_of" 00204 lastPos = str.find_first_not_of(delimiters, pos); 00205 // Find next "non-delimiter" 00206 pos = str.find_first_of(delimiters, lastPos); 00207 } 00208 if ( paths.empty() ) 00209 paths.push_back("."); 00210 return paths; 00211 } 00212 00219 static string makeShortFilename(string const& str) { 00220 string ret = str; 00221 if (str.substr(0,3) == "lib") 00222 ret = str.substr(3); 00223 if (ret.rfind(FULL_COMPONENT_SUFFIX) != string::npos) 00224 ret = ret.substr(0, ret.rfind(FULL_COMPONENT_SUFFIX) ); 00225 return ret; 00226 } 00227 00228 } 00229 00230 static bool hasEnding(string const &fullString, string const &ending) 00231 { 00232 if (fullString.length() > ending.length()) { 00233 return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); 00234 } else { 00235 return false; 00236 } 00237 } 00238 00239 boost::shared_ptr<ComponentLoader> ComponentLoader::Instance() { 00240 if (!instance2) 00241 instance2.reset( new ComponentLoader() ); 00242 return instance2; 00243 } 00244 00245 void ComponentLoader::Release() { 00246 instance2.reset(); 00247 } 00248 00249 // This is the dumb import function that takes an existing directory and 00250 // imports components and plugins from it. 00251 bool ComponentLoader::import( std::string const& path_list ) 00252 { 00253 if (path_list.empty() ) { 00254 log(Error) << "import paths: No paths were given for loading ( path_list = '' )."<<endlog(); 00255 return false; 00256 } 00257 00258 // we return false if nothing was found here, or an error happened during loading of a library. 00259 vector<string> paths; 00260 paths = splitPaths( path_list ); // import package or path list. 00261 00262 bool all_good = true, found = false; 00263 // perform search in paths: 00264 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it) 00265 { 00266 // Scan path/* (non recursive) for components 00267 path p = path(*it); 00268 if (is_directory(p)) 00269 { 00270 log(Info) << "Importing directory " << p.string() << " ..."<<endlog(); 00271 for (directory_iterator itr(p); itr != directory_iterator(); ++itr) 00272 { 00273 log(Debug) << "Scanning file " << itr->path().string() << " ..."; 00274 if (is_regular_file(itr->status()) && isLoadableLibrary(itr->path()) ) { 00275 found = true; 00276 std::string libname; 00277 #if BOOST_VERSION >= 104600 00278 libname = itr->path().filename().string(); 00279 #else 00280 libname = itr->path().filename(); 00281 #endif 00282 if(!isCompatibleComponent(libname)) 00283 { 00284 log(Debug) << "not a compatible component: ignored."<<endlog(); 00285 } 00286 else 00287 { 00288 found = true; 00289 all_good = loadInProcess( itr->path().string(), makeShortFilename(libname ), true) && all_good; 00290 } 00291 } else { 00292 if (!is_regular_file(itr->status())) 00293 log(Debug) << "not a regular file: ignored."<<endlog(); 00294 else 00295 log(Debug) << "not a " + SO_EXT + " library: ignored."<<endlog(); 00296 } 00297 } 00298 log(Debug) << "Looking for plugins or typekits in directory " << p.string() << " ..."<<endlog(); 00299 try { 00300 found = PluginLoader::Instance()->loadTypekits( p.string() ) || found; 00301 found = PluginLoader::Instance()->loadPlugins( p.string() ) || found; 00302 } catch (std::exception& e) { 00303 all_good = false; 00304 log(Error) << e.what() <<endlog(); 00305 } 00306 } 00307 else { 00308 // If the path is not complete (not absolute), look it up in the search directories: 00309 log(Debug) << "No such directory: " << p<< endlog(); 00310 } 00311 #if 0 00312 // Repeat for path/OROCOS_TARGET: (already done in other import function) 00313 p = path(*it) / OROCOS_TARGET_NAME; 00314 if (is_directory(p)) 00315 { 00316 log(Info) << "Importing component libraries from directory " << p.string() << " ..."<<endlog(); 00317 for (directory_iterator itr(p); itr != directory_iterator(); ++itr) 00318 { 00319 log(Debug) << "Scanning file " << itr->path().string() << " ..."; 00320 if (is_regular_file(itr->status()) && isLoadableLibrary(itr->path()) ) { 00321 found = true; 00322 #if BOOST_VERSION >= 104600 00323 all_good = loadInProcess( itr->path().string(), makeShortFilename(itr->path().filename().string() ), true) && all_good; 00324 #else 00325 all_good = loadInProcess( itr->path().string(), makeShortFilename(itr->path().filename() ), true) && all_good; 00326 #endif 00327 }else { 00328 if (!is_regular_file(itr->status())) 00329 log(Debug) << "not a regular file: ignored."<<endlog(); 00330 else 00331 log(Debug) << "not a " + SO_EXT + " library: ignored."<<endlog(); 00332 } 00333 } 00334 log(Info) << "Importing plugins and typekits from directory " << p.string() << " ..."<<endlog(); 00335 try { 00336 found = PluginLoader::Instance()->loadTypekits( p.string() ) || found; 00337 found = PluginLoader::Instance()->loadPlugins( p.string() ) || found; 00338 } catch (std::exception& e) { 00339 all_good = false; 00340 log(Error) << e.what() <<endlog(); 00341 } 00342 } 00343 #endif 00344 } 00345 if (!all_good) 00346 throw std::runtime_error("Some found plugins could not be loaded !"); 00347 return found; 00348 } 00349 00350 // this is the smart import function that tries to guess where 'package' lives in path_list or 00351 // the search path. 00352 bool ComponentLoader::import( std::string const& package, std::string const& path_list ) 00353 { 00354 // check first for exact match to *file*: 00355 path arg( package ); 00356 if (is_regular_file(arg) && isLoadableLibrary(arg)) { 00357 #if BOOST_VERSION >= 104600 00358 return loadInProcess(arg.string(), makeShortFilename( arg.filename().string() ), true); 00359 #else 00360 return loadInProcess(arg.string(), makeShortFilename( arg.filename() ), true); 00361 #endif 00362 } 00363 00364 // check for absolute path: 00365 if ( arg.is_complete() ) { 00366 // plain import 00367 bool ret = import(package); 00368 // if not yet given, test for target subdir: 00369 if ( arg.parent_path().leaf() != OROCOS_TARGET_NAME ) 00370 ret = import( (arg / OROCOS_TARGET_NAME).string() ) || ret; 00371 // if something found, return true: 00372 if (ret) 00373 return true; 00374 // both failed: 00375 log(Error) << "Could not import absolute path '"<<package << "': nothing found."<<endlog(); 00376 return false; 00377 } 00378 00379 if ( isImported(package) ) { 00380 log(Info) <<"Component package '"<< package <<"' already imported." <<endlog(); 00381 return true; 00382 } 00383 00384 // from here on: it's a package name or a path. 00385 // package names must be found to return true. 00386 // path will be scanned and will always return true, but will warn when invalid. 00387 if ( importRosPackage(package) ) 00388 return true; 00389 00390 // Try the RTT_COMPONENT_PATH: 00391 return importInstalledPackage(package, path_list); 00392 } 00393 00394 bool ComponentLoader::importRosPackage(std::string const& package) 00395 { 00396 // check for rospack 00397 #ifdef HAS_ROSLIB 00398 using namespace rospack; 00399 try { 00400 bool found = false; 00401 Rospack rpack; 00402 rpack.setQuiet(true); 00403 char* rpp = getenv("ROS_PACKAGE_PATH"); 00404 vector<string> paths; 00405 if (rpp) 00406 paths = splitPaths(rpp); 00407 string ppath; 00408 rpack.crawl(paths,false); 00409 rpack.find(package, ppath); 00410 if ( !ppath.empty() ) { 00411 path rospath = path(ppath) / "lib" / "orocos"; 00412 path rospath_target = rospath / OROCOS_TARGET_NAME; 00413 // + add all dependencies to paths: 00414 vector<string> rospackresult; 00415 rpack.setQuiet(false); 00416 bool valid = rpack.deps(package, false, rospackresult); // false: also indirect deps. 00417 if (!valid) { 00418 log(Error) <<"The ROS package '"<< package <<"' in '"<< ppath << "' caused trouble. Bailing out."<<endlog(); 00419 return false; 00420 } 00421 00422 for(vector<string>::iterator it = rospackresult.begin(); it != rospackresult.end(); ++it) { 00423 if ( isImported(*it) ) { 00424 log(Debug) <<"Package dependency '"<< *it <<"' already imported." <<endlog(); 00425 continue; 00426 } 00427 if ( rpack.find( *it, ppath ) == false ) 00428 throw *it; 00429 path deppath = path(ppath) / "lib" / "orocos"; 00430 path deppath_target = path(deppath) / OROCOS_TARGET_NAME; 00431 // if orocos directory exists and we could import it, mark it as loaded. 00432 if ( is_directory( deppath_target ) ) { 00433 log(Debug) << "Ignoring files under " << deppath.string() << " since " << deppath_target.string() << " was found."<<endlog(); 00434 found = true; 00435 if ( import( deppath_target.string() ) ) { 00436 loadedPackages.push_back( *it ); 00437 } 00438 } 00439 else if ( is_directory( deppath ) ) { 00440 found = true; 00441 if ( import( deppath.string() ) ) { 00442 loadedPackages.push_back( *it ); 00443 } 00444 } 00445 } 00446 // now that all deps are done, import the package itself: 00447 if ( is_directory( rospath_target ) ) { 00448 log(Debug) << "Ignoring files under " << rospath.string() << " since " << rospath_target.string() << " was found."<<endlog(); 00449 found = true; 00450 if ( import( rospath_target.string() ) ) { 00451 loadedPackages.push_back( package ); 00452 } 00453 } else if ( is_directory( rospath ) ) { 00454 found = true; 00455 if ( import( rospath.string() ) ) { 00456 loadedPackages.push_back( package ); 00457 } 00458 } 00459 // since it was a ROS package, we exit here. 00460 if (!found) { 00461 log(Debug) <<"The ROS package '"<< package <<"' in '"<< ppath << "' nor its dependencies contained a lib/orocos directory. I'll look in the RTT_COMPONENT_PATH next."<<endlog(); 00462 } 00463 return found; 00464 } else 00465 log(Info) << "Not a ros package: " << package << endlog(); 00466 } catch(std::string arg) { 00467 log(Info) << "While processing the dependencies of " << package << ": not a ros package: " << arg << endlog(); 00468 } 00469 #endif 00470 return false; 00471 } 00472 00473 bool ComponentLoader::importInstalledPackage(std::string const& package, std::string const& path_list) 00474 { 00475 string paths; 00476 string trypaths; 00477 vector<string> tryouts; 00478 if (path_list.empty()) 00479 paths = component_path + default_delimiter + "."; 00480 else 00481 paths = path_list; 00482 00483 bool path_found = false; 00484 00485 // if ros did not find anything, split the paths above. 00486 // set vpaths from (default) search paths. 00487 vector<string> vpaths; 00488 vpaths = splitPaths(paths); 00489 trypaths = paths; // store for error reporting below. 00490 paths.clear(); 00491 // Detect absolute/relative import: 00492 path p( package ); 00493 if (is_directory( p )) { 00494 path_found = true; 00495 // search in dir + dir/TARGET 00496 paths += p.string() + default_delimiter + (p / OROCOS_TARGET_NAME).string() + default_delimiter; 00497 if ( p.is_complete() ) { 00498 // 2.2.x: path may be absolute or relative to search path. 00499 //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(); 00500 //log(Warning) << "Please modify your XML file or script. I'm importing it now for the sake of backwards compatibility."<<endlog(); 00501 } // else: we allow to import a subdirectory of '.'. 00502 } 00503 // append '/package' or 'target/package' to each plugin path in order to search all of them: 00504 for(vector<string>::iterator it = vpaths.begin(); it != vpaths.end(); ++it) { 00505 p = *it; 00506 p = p / package; 00507 // we only search in existing directories: 00508 if (is_directory( p )) { 00509 path_found = true; 00510 paths += p.string() + default_delimiter ; 00511 } else 00512 tryouts.push_back( p.string() ); 00513 p = *it; 00514 p = p / OROCOS_TARGET_NAME / package; 00515 // we only search in existing directories: 00516 if (is_directory( p )) { 00517 path_found = true; 00518 paths += p.string() + default_delimiter ; 00519 } else 00520 tryouts.push_back( p.string() ); 00521 } 00522 if ( path_found ) 00523 paths.erase( paths.size() - 1 ); // remove trailing delimiter ';' 00524 00525 // when at least one directory exists: 00526 if (path_found) { 00527 if ( import(paths) ) { 00528 loadedPackages.push_back( package ); 00529 return true; 00530 } else { 00531 log(Error) << "Failed to import components, types or plugins from package or directory '"<< package <<"' found in:"<< endlog(); 00532 log(Error) << paths << endlog(); 00533 return false; 00534 } 00535 } 00536 log(Error) << "No such package or directory found in search path: " << package << ". Search path is: "<< endlog(); 00537 log(Error) << trypaths << endlog(); 00538 for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it) 00539 log(Error) << *it << endlog(); 00540 return false; 00541 } 00542 00543 bool ComponentLoader::reloadLibrary(std::string const& name) 00544 { 00545 path arg = name; 00546 // check for direct match: 00547 #if BOOST_VERSION >= 104600 00548 if (is_regular_file( arg ) && reloadInProcess( arg.string(), makeShortFilename( arg.filename().string() ) ) ) 00549 #else 00550 if (is_regular_file( arg ) && reloadInProcess( arg.string(), makeShortFilename( arg.filename() ) ) ) 00551 #endif 00552 return true; 00553 // bail out if not an absolute path 00554 return false; 00555 } 00556 00557 bool ComponentLoader::loadLibrary( std::string const& name ) 00558 { 00559 path arg = name; 00560 // check for direct match: 00561 #if BOOST_VERSION >= 104600 00562 if (is_regular_file( arg ) && loadInProcess( arg.string(), makeShortFilename( arg.filename().string() ), true ) ) 00563 #else 00564 if (is_regular_file( arg ) && loadInProcess( arg.string(), makeShortFilename( arg.filename() ), true ) ) 00565 #endif 00566 return true; 00567 // bail out if absolute path 00568 if ( arg.is_complete() ) 00569 return false; 00570 00571 // search for relative match 00572 vector<string> paths = splitPaths( component_path ); 00573 vector<string> tryouts( paths.size() * 4 ); 00574 tryouts.clear(); 00575 path dir = arg.parent_path(); 00576 #if BOOST_VERSION >= 104600 00577 string file = arg.filename().string(); 00578 #else 00579 string file = arg.filename(); 00580 #endif 00581 00582 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it) 00583 { 00584 path p = path(*it) / dir / (file + FULL_COMPONENT_SUFFIX); 00585 tryouts.push_back( p.string() ); 00586 if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) ) 00587 return true; 00588 p = path(*it) / dir / ("lib" + file + FULL_COMPONENT_SUFFIX); 00589 tryouts.push_back( p.string() ); 00590 if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) ) 00591 return true; 00592 p = path(*it) / OROCOS_TARGET_NAME / dir / (file + FULL_COMPONENT_SUFFIX); 00593 tryouts.push_back( p.string() ); 00594 if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) ) 00595 return true; 00596 p = path(*it) / OROCOS_TARGET_NAME / dir / ("lib" + file + FULL_COMPONENT_SUFFIX); 00597 tryouts.push_back( p.string() ); 00598 if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) ) 00599 return true; 00600 } 00601 log(Debug) << "No such library found in path: " << name << ". Tried:"<< endlog(); 00602 for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it) 00603 log(Debug) << *it << endlog(); 00604 return false; 00605 } 00606 00607 bool ComponentLoader::isImported(string type_name) 00608 { 00609 if (ComponentFactories::Instance().find(type_name) != ComponentFactories::Instance().end() ) 00610 return true; 00611 if (find(loadedPackages.begin(), loadedPackages.end(), type_name) != loadedPackages.end()) 00612 return true; 00613 // hack: in current versions, ocl is loaded most of the times by default because it does not reside in a package subdir 00614 // once ocl is in the 'ocl' package directory, this code becomes obsolete: 00615 if ( type_name == "ocl" && TypekitRepository::hasTypekit("OCLTypekit")) { 00616 return true; 00617 } 00618 return false; 00619 } 00620 00621 bool ComponentLoader::reloadInProcess(string file, string libname) 00622 { 00623 path p(file); 00624 00625 // check if the library is already loaded 00626 // NOTE if this library has been loaded, you can unload and reload it to apply changes (may be you have updated the dynamic library) 00627 // anyway it is safe to do this only if there isn't any instance whose type was loaded from this library 00628 00629 std::vector<LoadedLib>::iterator lib = loadedLibs.begin(); 00630 while (lib != loadedLibs.end()) { 00631 // We only reload if it's exactly the same file. 00632 if ( lib->filename == file) { 00633 log(Info) <<"Component library "<< lib->filename <<" already loaded... " ; 00634 00635 bool can_unload = true; 00636 CompList::iterator cit; 00637 for( std::vector<std::string>::iterator ctype = lib->components_type.begin(); ctype != lib->components_type.end() && can_unload; ++ctype) { 00638 for ( cit = comps.begin(); cit != comps.end(); ++cit) { 00639 if( (*ctype) == cit->second.type ) { 00640 // the type of an allocated component was loaded from this library. it might be unsafe to reload the library 00641 log(Info) << "can NOT reload library because of the instance " << cit->second.type <<"::"<<cit->second.instance->getName() <<endlog(); 00642 can_unload = false; 00643 } 00644 } 00645 } 00646 if( can_unload ) { 00647 log(Info) << "try to RELOAD"<<endlog(); 00648 dlclose(lib->handle); 00649 // remove the library info from the vector 00650 std::vector<LoadedLib>::iterator lib_un = lib; 00651 loadedLibs.erase(lib_un); 00652 return loadInProcess(file, libname, true); 00653 } 00654 else 00655 return false; 00656 } 00657 else lib++; 00658 } 00659 log(Error) << "Can't reload Component library "<< file << " since it was not loaded or is not a component library." <<endlog(); 00660 return false; 00661 } 00662 00663 // loads a single component in the current process. 00664 bool ComponentLoader::loadInProcess(string file, string libname, bool log_error) { 00665 path p(file); 00666 char* error; 00667 void* handle; 00668 bool success=false; 00669 00670 // Last chance to validate component compatibility 00671 if(!isCompatibleComponent(file)) 00672 { 00673 if(log_error) 00674 log(Error) << "Could not load library '"<< p.string() <<"': incompatible." <<endlog(); 00675 return false; 00676 } 00677 00678 handle = dlopen ( p.string().c_str(), RTLD_NOW); 00679 00680 if (!handle) { 00681 if ( log_error ) { 00682 log(Error) << "Could not load library '"<< p.string() <<"':"<<endlog(); 00683 log(Error) << dlerror() << endlog(); 00684 } 00685 return false; 00686 } 00687 00688 //------------- if you get here, the library has been loaded ------------- 00689 log(Debug)<<"Succesfully loaded "<<libname<<endlog(); 00690 LoadedLib loading_lib(file, libname, handle); 00691 dlerror(); /* Clear any existing error */ 00692 00693 // Lookup Component factories (multi component case): 00694 FactoryMap* (*getfactory)(void) = 0; 00695 vector<string> (*getcomponenttypes)(void) = 0; 00696 FactoryMap* fmap = 0; 00697 getfactory = (FactoryMap*(*)(void))( dlsym(handle, "getComponentFactoryMap") ); 00698 if ((error = dlerror()) == NULL) { 00699 // symbol found, register factories... 00700 fmap = (*getfactory)(); 00701 ComponentFactories::Instance().insert( fmap->begin(), fmap->end() ); 00702 log(Info) << "Loaded multi component library '"<< file <<"'"<<endlog(); 00703 getcomponenttypes = (vector<string>(*)(void))(dlsym(handle, "getComponentTypeNames")); 00704 if ((error = dlerror()) == NULL) { 00705 log(Debug) << "Components:"; 00706 vector<string> ctypes = getcomponenttypes(); 00707 for (vector<string>::iterator it = ctypes.begin(); it != ctypes.end(); ++it) 00708 log(Debug) <<" "<< *it; 00709 log(Debug) << endlog(); 00710 } 00711 loadedLibs.push_back(loading_lib); 00712 success = true; 00713 } 00714 00715 // Lookup createComponent (single component case): 00716 dlerror(); /* Clear any existing error */ 00717 00718 RTT::TaskContext* (*factory)(std::string) = 0; 00719 std::string(*tname)(void) = 0; 00720 factory = (RTT::TaskContext*(*)(std::string))(dlsym(handle, "createComponent") ); 00721 string create_error; 00722 error = dlerror(); 00723 if (error) create_error = error; 00724 tname = (std::string(*)(void))(dlsym(handle, "getComponentType") ); 00725 string gettype_error; 00726 error = dlerror(); 00727 if (error) gettype_error = error; 00728 if ( factory && tname ) { 00729 std::string cname = (*tname)(); 00730 if ( ComponentFactories::Instance().count(cname) == 1 ) { 00731 log(Warning) << "Component type name "<<cname<<" already used: overriding."<<endlog(); 00732 } 00733 ComponentFactories::Instance()[cname] = factory; 00734 log(Info) << "Loaded component type '"<< cname <<"'"<<endlog(); 00735 loading_lib.components_type.push_back( cname ); 00736 loadedLibs.push_back(loading_lib); 00737 success = true; 00738 } 00739 00740 if (success) return true; 00741 00742 log(Error) <<"Unloading "<< loading_lib.filename <<": not a valid component library:" <<endlog(); 00743 if (!create_error.empty()) 00744 log(Error) << " " << create_error << endlog(); 00745 if (!gettype_error.empty()) 00746 log(Error) << " " << gettype_error << endlog(); 00747 dlclose(handle); 00748 return false; 00749 } 00750 00751 std::vector<std::string> ComponentLoader::listComponentTypes() const { 00752 vector<string> names; 00753 FactoryMap::iterator it; 00754 for( it = ComponentFactories::Instance().begin(); it != ComponentFactories::Instance().end(); ++it) { 00755 names.push_back( it->first ); 00756 } 00757 return names; 00758 } 00759 00760 std::string ComponentLoader::getComponentPath() const { 00761 string ret = component_path; 00762 // append default delimiter if not present. such that it can be combined with a new path. 00763 if ( ret.length() && ret[ ret.length() -1 ] != default_delimiter ) 00764 ret += default_delimiter; 00765 return ret; 00766 } 00767 00768 void ComponentLoader::setComponentPath( std::string const& newpath ) { 00769 component_path = newpath; 00770 } 00771 00772 00773 RTT::TaskContext *ComponentLoader::loadComponent(const std::string & name, const std::string & type) 00774 { 00775 TaskContext* instance = 0; 00776 RTT::TaskContext* (*factory)(std::string name) = 0; 00777 log(Debug) << "Trying to create component "<< name <<" of type "<< type << endlog(); 00778 00779 // First: try loading from imported libraries. (see: import). 00780 if ( ComponentFactories::Instance().count(type) == 1 ) { 00781 factory = ComponentFactories::Instance()[ type ]; 00782 if (factory == 0 ) { 00783 log(Error) <<"Found empty factory for Component type "<<type<<endlog(); 00784 return 0; 00785 } 00786 } 00787 00788 if ( factory ) { 00789 log(Debug) <<"Found factory for Component type "<<type<<endlog(); 00790 } else { 00791 log(Error) << "Unable to create Orocos Component '"<<type<<"': unknown component type." <<endlog(); 00792 return 0; 00793 } 00794 00795 comps[name].type = type; 00796 00797 try { 00798 comps[name].instance = instance = (*factory)(name); 00799 } catch(...) { 00800 log(Error) <<"The constructor of component type "<<type<<" threw an exception!"<<endlog(); 00801 } 00802 00803 if ( instance == 0 ) { 00804 log(Error) <<"Failed to load component with name "<<name<<": refused to be created."<<endlog(); 00805 } 00806 return instance; 00807 } 00808 00809 bool ComponentLoader::unloadComponent( RTT::TaskContext* tc ) { 00810 if (!tc) 00811 return false; 00812 CompList::iterator it; 00813 it = comps.find( tc->getName() ); 00814 00815 if ( it != comps.end() ) { 00816 delete tc; 00817 comps.erase(it); 00818 return true; 00819 } 00820 log(Error) <<"Refusing to unload a component I didn't load myself."<<endlog(); 00821 return false; 00822 } 00823 00824 std::vector<std::string> ComponentLoader::listComponents() const 00825 { 00826 vector<string> names( comps.size() ); 00827 for(map<string,ComponentData>::const_iterator it = comps.begin(); it != comps.end(); ++it) 00828 names.push_back( it->first ); 00829 return names; 00830 } 00831 00832 bool ComponentLoader::isCompatibleComponent(std::string const& filepath) 00833 { 00834 path p(filepath); 00835 00836 #if BOOST_VERSION >= 104600 00837 string libname = p.filename().string(); 00838 #else 00839 string libname = p.filename(); 00840 #endif 00841 00842 //log(Debug) << "Validating compatility of component file '" + libname + "'" <<endlog(); 00843 00844 #ifdef _WIN32 00845 // On WIN32 target: 00846 // - look if the library name ends with "win32.dll" on release mode 00847 // - look if the library name ends with "win32d.dll" on debug mode 00848 if(!hasEnding(libname, FULL_COMPONENT_SUFFIX)) 00849 { 00850 //log(Debug) << "Component file '" + libname + "' is incompatible because it doesn't have the suffix " << FULL_COMPONENT_SUFFIX << endlog(); 00851 return false; 00852 } 00853 #endif // _WIN32 00854 00855 // There's no validation on other targets 00856 00857 //log(Debug) << "Component file '" + libname + "' is valid." <<endlog(); 00858 00859 return true; 00860 } 00861 00862 const FactoryMap& ComponentLoader::getFactories() const 00863 { 00864 return ComponentFactories::Instance(); 00865 } 00866 00867 void ComponentLoader::addFactory(std::string const& name, ComponentLoaderSignature factory) 00868 { 00869 ComponentFactories::Instance()[name] = factory; 00870 }