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     RTT::Logger::In in("ComponentLoader::import(path_list)");
00295 
00296     if (path_list.empty() ) {
00297         log(Error) << "import paths: No paths were given for loading ( path_list = '' )."<<endlog();
00298         return false;
00299     }
00300 
00301     // we return false if nothing was found here, or an error happened during loading of a library.
00302     vector<string> paths;
00303     paths = splitPaths( path_list ); // import package or path list.
00304 
00305     bool all_good = true, found = false;
00306     // perform search in paths:
00307     for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
00308     {
00309         // Scan path/* (non recursive) for components
00310         path p = path(*it);
00311         if (is_directory(p))
00312         {
00313             log(Info) << "Importing directory " << p.string() << " ..."<<endlog();
00314             for (directory_iterator itr(p); itr != directory_iterator(); ++itr)
00315             {
00316                 log(Debug) << "Scanning file " << itr->path().string() << " ...";
00317                 if (is_regular_file(itr->status()) && isLoadableLibrary(itr->path()) ) {
00318                     found = true;
00319                     std::string libname;
00320 #if BOOST_VERSION >= 104600
00321                     libname = itr->path().filename().string();
00322 #else
00323                     libname = itr->path().filename();
00324 #endif
00325                     if(!isCompatibleComponent(libname))
00326                     {
00327                         log(Debug) << "not a compatible component: ignored."<<endlog();
00328                     }
00329                     else
00330                     {
00331                         found = true;
00332                         all_good = loadInProcess( itr->path().string(), makeShortFilename(libname ),  true) && all_good;
00333                     }
00334                 } else {
00335                     if (!is_regular_file(itr->status()))
00336                         log(Debug) << "not a regular file: ignored."<<endlog();
00337                     else
00338                         log(Debug) << "not a " + SO_EXT + " library: ignored."<<endlog();
00339                 }
00340             }
00341             log(Debug) << "Looking for plugins or typekits in directory " << p.string() << " ..."<<endlog();
00342             try {
00343                 found = PluginLoader::Instance()->loadTypekits( p.string() ) || found;
00344                 found = PluginLoader::Instance()->loadPlugins( p.string() ) || found;
00345             } catch (std::exception& e) {
00346                 all_good = false;
00347                 log(Error) << e.what() <<endlog();
00348             }
00349         }
00350         else {
00351             // If the path is not complete (not absolute), look it up in the search directories:
00352             log(Debug) << "No such directory: " << p<< endlog();
00353         }
00354 #if 0
00355         // Repeat for path/OROCOS_TARGET: (already done in other import function)
00356         p = path(*it) / OROCOS_TARGET_NAME;
00357         if (is_directory(p))
00358         {
00359             log(Info) << "Importing component libraries from directory " << p.string() << " ..."<<endlog();
00360             for (directory_iterator itr(p); itr != directory_iterator(); ++itr)
00361             {
00362                 log(Debug) << "Scanning file " << itr->path().string() << " ...";
00363                 if (is_regular_file(itr->status()) && isLoadableLibrary(itr->path()) ) {
00364                     found = true;
00365 #if BOOST_VERSION >= 104600
00366                     all_good = loadInProcess( itr->path().string(), makeShortFilename(itr->path().filename().string() ),  true) && all_good;
00367 #else
00368                     all_good = loadInProcess( itr->path().string(), makeShortFilename(itr->path().filename() ),  true) && all_good;
00369 #endif
00370                 }else {
00371                     if (!is_regular_file(itr->status()))
00372                         log(Debug) << "not a regular file: ignored."<<endlog();
00373                     else
00374                         log(Debug) << "not a " + SO_EXT + " library: ignored."<<endlog();
00375                 }
00376             }
00377             log(Info) << "Importing plugins and typekits from directory " << p.string() << " ..."<<endlog();
00378             try {
00379                 found = PluginLoader::Instance()->loadTypekits( p.string() ) || found;
00380                 found = PluginLoader::Instance()->loadPlugins( p.string() ) || found;
00381             } catch (std::exception& e) {
00382                 all_good = false;
00383                 log(Error) << e.what() <<endlog();
00384             }
00385         }
00386 #endif
00387     }
00388     if (!all_good)
00389         throw std::runtime_error("Some found plugins could not be loaded !");
00390     return found;
00391 }
00392 
00393 // this is the smart import function that tries to guess where 'package' lives in path_list or
00394 // the search path.
00395 bool ComponentLoader::import( std::string const& package, std::string const& path_list )
00396 {
00397     RTT::Logger::In in("ComponentLoader::import(package, path_list)");
00398 
00399     // check first for exact match to *file*:
00400     path arg( package );
00401     if (is_regular_file(arg) && isLoadableLibrary(arg)) {
00402 #if BOOST_VERSION >= 104600
00403             return loadInProcess(arg.string(), makeShortFilename( arg.filename().string() ), true);
00404 #else
00405             return loadInProcess(arg.string(), makeShortFilename( arg.filename() ), true);
00406 #endif
00407     }
00408 
00409     // check for absolute path:
00410     if ( arg.is_complete() ) {
00411         // plain import
00412         bool ret = import(package);
00413         // if not yet given, test for target subdir:
00414         if ( arg.parent_path().leaf() != OROCOS_TARGET_NAME )
00415             ret = import( (arg / OROCOS_TARGET_NAME).string() ) || ret;
00416         // if something found, return true:
00417         if (ret)
00418             return true;
00419         // both failed:
00420         log(Error) << "Could not import absolute path '"<<package << "': nothing found."<<endlog();
00421         return false;
00422     }
00423 
00424     if ( isImported(package) ) {
00425         log(Info) <<"Component package '"<< package <<"' already imported." <<endlog();
00426         return true;
00427     }
00428 
00429     // Try the RTT_COMPONENT_PATH:
00430     return importInstalledPackage(package, path_list);
00431 }
00432 
00433 bool ComponentLoader::importInstalledPackage(std::string const& package, std::string const& path_list)
00434 {
00435     RTT::Logger::In in("ComponentLoader::importInstalledPackage(package, path_list)");
00436 
00437     string paths;
00438     string trypaths;
00439     vector<string> tryouts;
00440     if (path_list.empty())
00441         paths = component_path + default_delimiter + ".";
00442     else
00443         paths = path_list;
00444 
00445     bool path_found = false;
00446 
00447     // if ros did not find anything, split the paths above.
00448     // set vpaths from (default) search paths.
00449     vector<string> vpaths;
00450     vpaths = splitPaths(paths);
00451     trypaths = paths; // store for error reporting below.
00452     paths.clear();
00453     // Detect absolute/relative import:
00454     path p( package );
00455     if (is_directory( p )) {
00456         path_found = true;
00457         // search in dir + dir/TARGET
00458         paths += p.string() + default_delimiter + (p / OROCOS_TARGET_NAME).string() + default_delimiter;
00459         if ( p.is_complete() ) {
00460             // 2.2.x: path may be absolute or relative to search path.
00461             //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();
00462             //log(Warning) << "Please modify your XML file or script. I'm importing it now for the sake of backwards compatibility."<<endlog();
00463         } // else: we allow to import a subdirectory of '.'.
00464     }
00465     // append '/package' or 'target/package' to each plugin path in order to search all of them:
00466     for(vector<string>::iterator it = vpaths.begin(); it != vpaths.end(); ++it) {
00467         p = *it;
00468         p = p / package;
00469         // we only search in existing directories:
00470         if (is_directory( p )) {
00471             path_found = true;
00472             paths += p.string() + default_delimiter ;
00473         } else
00474             tryouts.push_back( p.string() );
00475         p = *it;
00476         p = p / OROCOS_TARGET_NAME / package;
00477         // we only search in existing directories:
00478         if (is_directory( p )) {
00479             path_found = true;
00480             paths += p.string() + default_delimiter ;
00481         } else
00482             tryouts.push_back( p.string() );
00483     }
00484     if ( path_found )
00485         paths.erase( paths.size() - 1 ); // remove trailing delimiter ';'
00486 
00487     // when at least one directory exists:
00488     if (path_found) {
00489         if ( import(paths) ) {
00490             loadedPackages.push_back( package );
00491             return true;
00492         } else {
00493             log(Error) << "Failed to import components, types or plugins from package or directory '"<< package <<"' found in:"<< endlog();
00494             log(Error) << paths << endlog();
00495             return false;
00496         }
00497     }
00498     log(Error) << "No such package or directory found in search path: " << package << ". Search path is: " << trypaths << endlog();
00499     log(Error) << "Directories searched include the following: " << endlog();
00500     for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it)
00501         log(Error) << " - " << *it << endlog();
00502     return false;
00503 }
00504 
00505 bool ComponentLoader::reloadLibrary(std::string const& name)
00506 {
00507     path arg = name;
00508     // check for direct match:
00509 #if BOOST_VERSION >= 104600
00510     if (is_regular_file( arg ) && reloadInProcess( arg.string(), makeShortFilename( arg.filename().string() ) ) )
00511 #else
00512     if (is_regular_file( arg ) && reloadInProcess( arg.string(), makeShortFilename( arg.filename() ) ) )
00513 #endif
00514         return true;
00515     // bail out if not an absolute path
00516     return false;
00517 }
00518 
00519 bool ComponentLoader::loadLibrary( std::string const& name )
00520 {
00521     path arg = name;
00522     // check for direct match:
00523 #if BOOST_VERSION >= 104600
00524     if (is_regular_file( arg ) && loadInProcess( arg.string(), makeShortFilename( arg.filename().string() ), true ) )
00525 #else
00526     if (is_regular_file( arg ) && loadInProcess( arg.string(), makeShortFilename( arg.filename() ), true ) )
00527 #endif
00528         return true;
00529     // bail out if absolute path
00530     if ( arg.is_complete() )
00531         return false;
00532 
00533     // search for relative match
00534     vector<string> paths = splitPaths( component_path );
00535     vector<string> tryouts( paths.size() * 4 );
00536     tryouts.clear();
00537     path dir = arg.parent_path();
00538 #if BOOST_VERSION >= 104600
00539     string file = arg.filename().string();
00540 #else
00541     string file = arg.filename();
00542 #endif
00543 
00544     for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
00545     {
00546         path p = path(*it) / dir / (file + FULL_COMPONENT_SUFFIX);
00547         tryouts.push_back( p.string() );
00548         if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
00549             return true;
00550         p = path(*it) / dir / ("lib" + file + FULL_COMPONENT_SUFFIX);
00551         tryouts.push_back( p.string() );
00552         if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
00553             return true;
00554         p = path(*it) / OROCOS_TARGET_NAME / dir / (file + FULL_COMPONENT_SUFFIX);
00555         tryouts.push_back( p.string() );
00556         if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
00557             return true;
00558         p = path(*it) / OROCOS_TARGET_NAME / dir / ("lib" + file + FULL_COMPONENT_SUFFIX);
00559         tryouts.push_back( p.string() );
00560         if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
00561             return true;
00562     }
00563     log(Debug) << "No such library found in path: " << name << ". Tried:"<< endlog();
00564     for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it)
00565         log(Debug) << *it << endlog();
00566     return false;
00567 }
00568 
00569 bool ComponentLoader::isImported(string type_name)
00570 {
00571     if (ComponentFactories::Instance().find(type_name) != ComponentFactories::Instance().end() )
00572         return true;
00573     if (find(loadedPackages.begin(), loadedPackages.end(), type_name) != loadedPackages.end())
00574         return true;
00575     // hack: in current versions, ocl is loaded most of the times by default because it does not reside in a package subdir
00576     // once ocl is in the 'ocl' package directory, this code becomes obsolete:
00577     if ( type_name == "ocl" && TypekitRepository::hasTypekit("OCLTypekit")) {
00578         return true;
00579     }
00580     return false;
00581 }
00582 
00583 bool ComponentLoader::reloadInProcess(string file, string libname)
00584 {
00585     path p(file);
00586 
00587     // check if the library is already loaded
00588     // NOTE if this library has been loaded, you can unload and reload it to apply changes (may be you have updated the dynamic library)
00589     // anyway it is safe to do this only if there isn't any instance whose type was loaded from this library
00590 
00591     std::vector<LoadedLib>::iterator lib = loadedLibs.begin();
00592     while (lib != loadedLibs.end()) {
00593         // We only reload if it's exactly the same file.
00594         if ( lib->filename == file) {
00595             log(Info) <<"Component library "<< lib->filename <<" already loaded... " ;
00596 
00597             bool can_unload = true;
00598             CompList::iterator cit;
00599             for( std::vector<std::string>::iterator ctype = lib->components_type.begin();  ctype != lib->components_type.end() && can_unload; ++ctype) {
00600                 for ( cit = comps.begin(); cit != comps.end(); ++cit) {
00601                     if( (*ctype) == cit->second.type ) {
00602                         // the type of an allocated component was loaded from this library. it might be unsafe to reload the library
00603                         log(Info) << "can NOT reload library because of the instance " << cit->second.type  <<"::"<<cit->second.instance->getName()  <<endlog();
00604                         can_unload = false;
00605                     }
00606                 }
00607             }
00608             if( can_unload ) {
00609                 log(Info) << "try to RELOAD"<<endlog();
00610                 dlclose(lib->handle);
00611                 // remove the library info from the vector
00612                 std::vector<LoadedLib>::iterator lib_un = lib;
00613                 loadedLibs.erase(lib_un);
00614                 return loadInProcess(file, libname, true);
00615             }
00616             else
00617                 return false;
00618         }
00619         else lib++;
00620     }
00621     log(Error) << "Can't reload Component library "<< file << " since it was not loaded or is not a component library." <<endlog();
00622     return false;
00623 }
00624 
00625 // loads a single component in the current process.
00626 bool ComponentLoader::loadInProcess(string file, string libname, bool log_error) {
00627     path p(file);
00628     char* error;
00629     void* handle;
00630     bool success=false;
00631 
00632     // Last chance to validate component compatibility
00633     if(!isCompatibleComponent(file))
00634     {
00635         if(log_error)
00636             log(Error) << "Could not load library '"<< p.string() <<"': incompatible." <<endlog();
00637         return false;
00638     }
00639 
00640     handle = dlopen ( p.string().c_str(), RTLD_NOW);
00641 
00642     if (!handle) {
00643         if ( log_error ) {
00644             log(Error) << "Could not load library '"<< p.string() <<"':"<<endlog();
00645             log(Error) << dlerror() << endlog();
00646         }
00647         return false;
00648     }
00649 
00650     //------------- if you get here, the library has been loaded -------------
00651     log(Debug)<<"Succesfully loaded "<<libname<<endlog();
00652     LoadedLib loading_lib(file, libname, handle);
00653     dlerror();    /* Clear any existing error */
00654 
00655     // Lookup Component factories (multi component case):
00656     FactoryMap* (*getfactory)(void) = 0;
00657     vector<string> (*getcomponenttypes)(void) = 0;
00658     FactoryMap* fmap = 0;
00659     getfactory = (FactoryMap*(*)(void))( dlsym(handle, "getComponentFactoryMap") );
00660     if ((error = dlerror()) == NULL) {
00661         // symbol found, register factories...
00662         fmap = (*getfactory)();
00663         ComponentFactories::Instance().insert( fmap->begin(), fmap->end() );
00664         log(Info) << "Loaded multi component library '"<< file <<"'"<<endlog();
00665         getcomponenttypes = (vector<string>(*)(void))(dlsym(handle, "getComponentTypeNames"));
00666         if ((error = dlerror()) == NULL) {
00667             log(Debug) << "Components:";
00668             vector<string> ctypes = getcomponenttypes();
00669             for (vector<string>::iterator it = ctypes.begin(); it != ctypes.end(); ++it)
00670                 log(Debug) <<" "<< *it;
00671             log(Debug) << endlog();
00672         }
00673         loadedLibs.push_back(loading_lib);
00674         success = true;
00675     }
00676 
00677     // Lookup createComponent (single component case):
00678     dlerror();    /* Clear any existing error */
00679 
00680     RTT::TaskContext* (*factory)(std::string) = 0;
00681     std::string(*tname)(void) = 0;
00682     factory = (RTT::TaskContext*(*)(std::string))(dlsym(handle, "createComponent") );
00683     string create_error;
00684     error = dlerror();
00685     if (error) create_error = error;
00686     tname = (std::string(*)(void))(dlsym(handle, "getComponentType") );
00687     string gettype_error;
00688     error = dlerror();
00689     if (error) gettype_error = error;
00690     if ( factory && tname ) {
00691         std::string cname = (*tname)();
00692         if ( ComponentFactories::Instance().count(cname) == 1 ) {
00693             log(Warning) << "Component type name "<<cname<<" already used: overriding."<<endlog();
00694         }
00695         ComponentFactories::Instance()[cname] = factory;
00696         log(Info) << "Loaded component type '"<< cname <<"'"<<endlog();
00697         loading_lib.components_type.push_back( cname );
00698         loadedLibs.push_back(loading_lib);
00699         success = true;
00700     }
00701 
00702     if (success) return true;
00703 
00704     log(Error) <<"Unloading "<< loading_lib.filename  <<": not a valid component library:" <<endlog();
00705     if (!create_error.empty())
00706         log(Error) << "   " << create_error << endlog();
00707     if (!gettype_error.empty())
00708         log(Error) << "   " << gettype_error << endlog();
00709     dlclose(handle);
00710     return false;
00711 }
00712 
00713 std::vector<std::string> ComponentLoader::listComponentTypes() const {
00714     vector<string> names;
00715     FactoryMap::iterator it;
00716     for( it = ComponentFactories::Instance().begin(); it != ComponentFactories::Instance().end(); ++it) {
00717         names.push_back( it->first );
00718     }
00719     return names;
00720 }
00721 
00722 std::string ComponentLoader::getComponentPath() const {
00723     string ret = component_path;
00724     // append default delimiter if not present. such that it can be combined with a new path.
00725     if ( ret.length() && ret[ ret.length() -1 ] != default_delimiter )
00726         ret += default_delimiter;
00727     return ret;
00728 }
00729 
00730 void ComponentLoader::setComponentPath( std::string const& newpath ) {
00731     component_path = newpath;
00732 }
00733 
00734 
00735 RTT::TaskContext *ComponentLoader::loadComponent(const std::string & name, const std::string & type)
00736 {
00737     TaskContext* instance = 0;
00738     RTT::TaskContext* (*factory)(std::string name) = 0;
00739     log(Debug) << "Trying to create component "<< name <<" of type "<< type << endlog();
00740 
00741     // First: try loading from imported libraries. (see: import).
00742     if ( ComponentFactories::Instance().count(type) == 1 ) {
00743         factory = ComponentFactories::Instance()[ type ];
00744         if (factory == 0 ) {
00745             log(Error) <<"Found empty factory for Component type "<<type<<endlog();
00746             return 0;
00747         }
00748     }
00749 
00750     if ( factory ) {
00751         log(Debug) <<"Found factory for Component type "<<type<<endlog();
00752     } else {
00753         log(Error) << "Unable to create Orocos Component '"<<type<<"': unknown component type." <<endlog();
00754         return 0;
00755     }
00756 
00757     comps[name].type = type;
00758 
00759     try {
00760         comps[name].instance = instance = (*factory)(name);
00761     } catch(...) {
00762         log(Error) <<"The constructor of component type "<<type<<" threw an exception!"<<endlog();
00763     }
00764 
00765     if ( instance == 0 ) {
00766         log(Error) <<"Failed to load component with name "<<name<<": refused to be created."<<endlog();
00767     }
00768     return instance;
00769 }
00770 
00771 bool ComponentLoader::unloadComponent( RTT::TaskContext* tc ) {
00772     if (!tc)
00773         return false;
00774     CompList::iterator it;
00775     it = comps.find( tc->getName() );
00776 
00777     if ( it != comps.end() ) {
00778         delete tc;
00779         comps.erase(it);
00780         return true;
00781     }
00782     log(Error) <<"Refusing to unload a component I didn't load myself."<<endlog();
00783     return false;
00784 }
00785 
00786 std::vector<std::string> ComponentLoader::listComponents() const
00787 {
00788     vector<string> names( comps.size() );
00789     for(map<string,ComponentData>::const_iterator it = comps.begin(); it != comps.end(); ++it)
00790         names.push_back( it->first );
00791     return names;
00792 }
00793 
00794 bool ComponentLoader::isCompatibleComponent(std::string const& filepath)
00795 {
00796     path p(filepath);
00797 
00798 #if BOOST_VERSION >= 104600
00799     string libname = p.filename().string();
00800 #else
00801     string libname = p.filename();
00802 #endif
00803 
00804     //log(Debug) << "Validating compatility of component file '" + libname + "'" <<endlog();
00805 
00806 #ifdef _WIN32
00807     // On WIN32 target:
00808     // - look if the library name ends with "win32.dll" on release mode
00809     // - look if the library name ends with "win32d.dll" on debug mode
00810     if(!hasEnding(libname, FULL_COMPONENT_SUFFIX))
00811     {
00812         //log(Debug) << "Component file '" + libname + "' is incompatible because it doesn't have the suffix " << FULL_COMPONENT_SUFFIX << endlog();
00813         return false;
00814     }
00815 #endif // _WIN32
00816 
00817     // There's no validation on other targets
00818 
00819     //log(Debug) << "Component file '" + libname + "' is valid." <<endlog();
00820 
00821     return true;
00822 }
00823 
00824 const FactoryMap& ComponentLoader::getFactories() const
00825 {
00826   return ComponentFactories::Instance();
00827 }
00828 
00829 void ComponentLoader::addFactory(std::string const& name, ComponentLoaderSignature factory)
00830 {
00831   ComponentFactories::Instance()[name] = factory;
00832 }


rtt
Author(s): RTT Developers
autogenerated on Sat Jun 8 2019 18:46:06