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


rtt
Author(s): RTT Developers
autogenerated on Thu Jan 2 2014 11:35:19