PluginLoader.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002   tag: The SourceWorks  Tue Sep 7 00:55:18 CEST 2010  PluginLoader.cpp
00003 
00004                         PluginLoader.cpp -  description
00005                            -------------------
00006     begin                : Tue September 07 2010
00007     copyright            : (C) 2010 The SourceWorks
00008     email                : peter@thesourceworks.com
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU General Public                   *
00013  *   License as published by the Free Software Foundation;                 *
00014  *   version 2 of the License.                                             *
00015  *                                                                         *
00016  *   As a special exception, you may use this file as part of a free       *
00017  *   software library without restriction.  Specifically, if other files   *
00018  *   instantiate templates or use macros or inline functions from this     *
00019  *   file, or you compile this file and link it with other files to        *
00020  *   produce an executable, this file does not by itself cause the         *
00021  *   resulting executable to be covered by the GNU General Public          *
00022  *   License.  This exception does not however invalidate any other        *
00023  *   reasons why the executable file might be covered by the GNU General   *
00024  *   Public License.                                                       *
00025  *                                                                         *
00026  *   This library is distributed in the hope that it will be useful,       *
00027  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00028  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00029  *   Lesser General Public License for more details.                       *
00030  *                                                                         *
00031  *   You should have received a copy of the GNU General Public             *
00032  *   License along with this library; if not, write to the Free Software   *
00033  *   Foundation, Inc., 59 Temple Place,                                    *
00034  *   Suite 330, Boston, MA  02111-1307  USA                                *
00035  *                                                                         *
00036  ***************************************************************************/
00037 
00038 
00046 #include "PluginLoader.hpp"
00047 #include "../TaskContext.hpp"
00048 #include "../Logger.hpp"
00049 #include <boost/filesystem.hpp>
00050 #include <boost/version.hpp>
00051 #include "../os/StartStopManager.hpp"
00052 #include "../os/MutexLock.hpp"
00053 #include "../internal/GlobalService.hpp"
00054 
00055 #include <cstdlib>
00056 #include <dlfcn.h>
00057 
00058 #include <vector>
00059 #include <set>
00060 
00061 using namespace RTT;
00062 using namespace RTT::detail;
00063 using namespace plugin;
00064 using namespace std;
00065 using namespace boost::filesystem;
00066 
00067 // chose the file extension and debug postfix applicable to the O/S
00068 #ifdef  __APPLE__
00069 static const std::string SO_EXT(".dylib");
00070 static const std::string SO_POSTFIX("");
00071 #else
00072 # ifdef _WIN32
00073 static const std::string SO_EXT(".dll");
00074 #  ifdef _DEBUG
00075 static const std::string SO_POSTFIX("d");
00076 #  else
00077 static const std::string SO_POSTFIX("");
00078 #  endif // _DEBUG
00079 # else
00080 static const std::string SO_EXT(".so");
00081 static const std::string SO_POSTFIX("");
00082 # endif
00083 #endif
00084 
00085 // The full library suffix must be enforced by the UseOrocos macros
00086 static const std::string FULL_PLUGINS_SUFFIX(string("-") + string(OROCOS_TARGET_NAME) + SO_POSTFIX + SO_EXT);
00087 
00088 // choose how the PATH looks like
00089 # ifdef _WIN32
00090 static const std::string delimiters(";");
00091 static const std::string default_delimiter(";");
00092 # else
00093 static const std::string delimiters(":;");
00094 static const std::string default_delimiter(":");
00095 # endif
00096 
00097 // define RTT_UNUSED macro
00098 #ifndef RTT_UNUSED
00099   #ifdef __GNUC__
00100     #define RTT_UNUSED __attribute__((unused))
00101   #else
00102     #define RTT_UNUSED
00103   #endif
00104 #endif
00105 
00114 RTT_API bool isExtensionVersion(const std::string& ext)
00115 {
00116     bool isExtensionVersion = false;
00117 
00118         if (!ext.empty() && ('.' == ext[0]))
00119         {
00120         std::istringstream      iss;
00121         int                                     i;
00122 
00123                 iss.str(ext.substr((size_t)1));     // take all after the '.'
00124         iss >> std::dec >> std::noskipws >> i;
00125         isExtensionVersion = !iss.fail() && iss.eof();
00126     }
00127 
00128     return isExtensionVersion;
00129 }
00130 
00131 /* Is this a dynamic library that we should load from within a directory scan?
00132 
00133    Versioned libraries are not loaded, to prevent loading both libfoo.so and
00134    libfoo.so.1 (which is typically a symlink to libfoo.so, and so loading
00135    the same library twice).
00136 
00137    Libraries are either (NB x.y.z is version, and could also be x or x.y)
00138 
00139    Linux
00140    libfoo.so          = load this
00141    libfoo.so.x.y.z    = don't load this
00142 
00143    Windows
00144    libfoo.dll         = load this
00145 
00146    Mac OS X
00147    libfoo.dylib       = load this
00148    libfoo.x.y.z.dylib = don't load this
00149 
00150    All the above also apply without the "lib" prefix.
00151 */
00152 RTT_API bool isLoadableLibrary(const path& filename)
00153 {
00154     bool isLoadable = false;
00155 
00156 #if     defined(__APPLE__)
00157         std::string     ext;
00158 #if BOOST_VERSION >= 104600
00159         ext = filename.extension().string();
00160 #else
00161         ext = filename.extension();
00162 #endif
00163     // ends in SO_EXT?
00164         if (0 == ext.compare(SO_EXT))
00165         {
00166                 // Ends in SO_EXT and so must not be a link for us to load
00167                 // Links are of the form abc.x.dylib or abc.x.y.dylib or abc.x.y.z.dylib,
00168                 // where x,y,z are positive numbers
00169                 path    name    = filename.stem();          // drop SO_EXT
00170                 path    ext     = name.extension();
00171                 isLoadable =
00172                         // wasn't just SO_EXT
00173                         !name.empty() &&
00174                         // and if there is and extension then it is not a number
00175                         (ext.empty() || !isExtensionVersion(ext.string()));
00176     }
00177     // else is not loadable
00178 
00179 #else
00180     // Linux or Windows
00181 
00182     // must end in SO_EXT and have a non-extension part
00183     isLoadable =
00184         (filename.extension() == SO_EXT) &&
00185         !filename.stem().empty();
00186 #endif
00187 
00188     return isLoadable;
00189 }
00190 
00191 namespace {
00192 
00193 static vector<string> splitPaths(string const& str)
00194 {
00195     vector<string> paths;
00196 
00197     // Skip delimiters at beginning.
00198     string::size_type lastPos = str.find_first_not_of(delimiters, 0);
00199     // Find first "non-delimiter".
00200     string::size_type pos = str.find_first_of(delimiters, lastPos);
00201 
00202     while (string::npos != pos || string::npos != lastPos)
00203     {
00204         // Found a token, add it to the vector.
00205         if ( !str.substr(lastPos, pos - lastPos).empty() )
00206             paths.push_back(str.substr(lastPos, pos - lastPos));
00207         // Skip delimiters.  Note the "not_of"
00208         lastPos = str.find_first_not_of(delimiters, pos);
00209         // Find next "non-delimiter"
00210         pos = str.find_first_of(delimiters, lastPos);
00211     }
00212     if ( paths.empty() )
00213         paths.push_back(".");
00214     return paths;
00215 }
00216 
00217 static void removeDuplicates(string& path_list)
00218 {
00219     vector<string> paths;
00220     set<string> seen;
00221     string result;
00222 
00223     // split path_lists
00224     paths = splitPaths( path_list );
00225 
00226     // iterate over paths and append to result
00227     for(vector<string>::const_iterator it = paths.begin(); it != paths.end(); ++it)
00228     {
00229         if (seen.count(*it))
00230             continue;
00231         else
00232             seen.insert(*it);
00233 
00234         result = result + *it + default_delimiter;
00235     }
00236 
00237     // remove trailing delimiter
00238     if (result.size() >= default_delimiter.size() && result.substr(result.size() - default_delimiter.size()) == default_delimiter)
00239         result = result.substr(0, result.size() - default_delimiter.size());
00240 
00241     path_list.swap(result);
00242 }
00243 
00250 static string makeShortFilename(string const& str) {
00251     string ret = str;
00252     if (str.substr(0,3) == "lib")
00253         ret = str.substr(3);
00254     if (ret.rfind(FULL_PLUGINS_SUFFIX) != string::npos)
00255         ret = ret.substr(0, ret.rfind(FULL_PLUGINS_SUFFIX) );
00256     return ret;
00257 }
00258 
00259 }
00260 
00261 static RTT_UNUSED bool hasEnding(string const &fullString, string const &ending)
00262 {
00263     if (fullString.length() > ending.length()) {
00264         return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
00265     } else {
00266         return false;
00267     }
00268 }
00269 
00270 namespace RTT { namespace plugin {
00271     extern char const* default_plugin_path;
00272 }}
00273 
00274 namespace {
00278     int loadPlugins()
00279     {
00280         std::string default_plugin_path = ::default_plugin_path;
00281 
00282         char* paths = getenv("RTT_COMPONENT_PATH");
00283         string plugin_paths;
00284         if (paths) {
00285             plugin_paths = paths;
00286             // prepend the default search path.
00287             if ( !default_plugin_path.empty() )
00288                 plugin_paths = plugin_paths + default_delimiter + default_plugin_path;
00289             removeDuplicates( plugin_paths );
00290             log(Info) <<"RTT_COMPONENT_PATH was set to: " << paths << " . Searching in: "<< plugin_paths<< endlog();
00291         } else {
00292             plugin_paths = default_plugin_path;
00293             removeDuplicates( plugin_paths );
00294             log(Info) <<"No RTT_COMPONENT_PATH set. Using default: " << plugin_paths <<endlog();
00295         }
00296         // we set the plugin path such that we can search for sub-directories/projects lateron
00297         PluginLoader::Instance()->setPluginPath(plugin_paths);
00298         // we load the plugins/typekits which are in each plugin path directory (but not subdirectories).
00299         try {
00300             PluginLoader::Instance()->loadPlugin("rtt", plugin_paths);
00301             PluginLoader::Instance()->loadTypekit("rtt", plugin_paths);
00302         } catch(std::exception& e) {
00303             log(Warning) << e.what() <<endlog();
00304             log(Warning) << "Corrupted files found in '" << plugin_paths << "'. Fix or remove these plugins."<<endlog();
00305         }
00306         return 0;
00307     }
00308 
00309     os::InitFunction plugin_loader( &loadPlugins );
00310 
00311     void unloadPlugins()
00312     {
00313         PluginLoader::Release();
00314     }
00315 
00316     os::CleanupFunction plugin_unloader( &unloadPlugins );
00317 }
00318 
00319 static boost::shared_ptr<PluginLoader> instance2;
00320 
00321 PluginLoader::PluginLoader() { log(Debug) <<"PluginLoader Created" <<endlog(); }
00322 PluginLoader::~PluginLoader(){ log(Debug) <<"PluginLoader Destroyed" <<endlog(); }
00323 
00324 
00325 boost::shared_ptr<PluginLoader> PluginLoader::Instance() {
00326     if (!instance2) {
00327         instance2.reset( new PluginLoader() );
00328     }
00329     return instance2;
00330 }
00331 
00332 void PluginLoader::Release() {
00333     instance2.reset();
00334 }
00335 
00336 bool PluginLoader::loadTypekits(string const& path_list) {
00337     MutexLock lock( listlock );
00338     return loadPluginsInternal( path_list, "types", "typekit");
00339 }
00340 
00341 bool PluginLoader::loadTypekit(std::string const& name, std::string const& path_list) {
00342     MutexLock lock( listlock );
00343     return loadPluginInternal(name, path_list, "types", "typekit");
00344 }
00345 
00346 bool PluginLoader::loadPlugin(std::string const& name, std::string const& path_list) {
00347     MutexLock lock( listlock );
00348     return loadPluginInternal(name, path_list, "plugins", "plugin");
00349 }
00350 
00351 bool PluginLoader::loadPlugins(string const& path_list) {
00352     MutexLock lock( listlock );
00353     return loadPluginsInternal( path_list, "plugins", "plugin");
00354 }
00355 
00356 bool PluginLoader::loadService(string const& servicename, TaskContext* tc) {
00357     MutexLock lock( listlock );
00358     for(vector<LoadedLib>::iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
00359         if (it->filename == servicename || it->plugname == servicename || it->shortname == servicename) {
00360             if (tc) {
00361                 log(Info) << "Loading Service or Plugin " << servicename << " in TaskContext " << tc->getName() <<endlog();
00362                 try {
00363                     return it->loadPlugin( tc );
00364                 } catch(std::exception& e) {
00365                     log(Error) << "Service or Plugin "<< servicename <<" threw an exception during loading in " << tc->getName() << endlog();
00366                     log(Error) << "Exception: "<< e.what() << endlog();
00367                     return false;
00368                 } catch(...) {
00369                     log(Error) << "Service or Plugin "<< servicename <<" threw an unknown exception during loading in " << tc->getName() << endlog();
00370                     return false;
00371                 }
00372             } else {
00373                 // loadPlugin( 0 ) was already called. So drop the service in the global service.
00374                 if (it->is_service)
00375                     try {
00376                         return internal::GlobalService::Instance()->addService( it->createService()  );
00377                     } catch(std::exception& e) {
00378                         log(Error) << "Service "<< servicename <<" threw an exception during loading in global service." << endlog();
00379                         log(Error) << "Exception: "<< e.what() << endlog();
00380                         return false;
00381                     } catch(...) {
00382                         log(Error) << "Service "<< servicename <<" threw an unknown exception during loading in global service. " << endlog();
00383                         return false;
00384                     }
00385                 log(Error) << "Plugin "<< servicename << " was found, but it's not a Service." <<endlog();
00386             }
00387         }
00388     }
00389     log(Error) << "No such service or plugin: '"<< servicename << "'"<< endlog();
00390     return false;
00391 }
00392 
00393 // This is a DUMB function and does not scan subdirs, possible filenames etc.
00394 bool PluginLoader::loadPluginsInternal( std::string const& path_list, std::string const& subdir, std::string const& kind )
00395 {
00396         // If exact match, load it directly:
00397     path arg( path_list );
00398     if (is_regular_file(arg)) {
00399 #if BOOST_VERSION >= 104600
00400         if ( loadInProcess(arg.string(), makeShortFilename(arg.filename().string()), kind, true) == false)
00401 #else
00402         if ( loadInProcess(arg.string(), makeShortFilename(arg.filename()), kind, true) == false)
00403 #endif
00404             throw std::runtime_error("The plugin "+path_list+" was found but could not be loaded !");
00405         log(Warning) << "You supplied a filename to 'loadPlugins(path)' or 'loadTypekits(path)'."<< nlog();
00406         log(Warning) << "Please use 'loadLibrary(filename)' instead since the function you use will only scan directories in future releases."<<endlog();
00407         return true;
00408     }
00409 
00410     // prepare search path:
00411     vector<string> paths;
00412     if (path_list.empty())
00413         return false; // nop: if no path is given, nothing to be searched.
00414     else
00415         paths = splitPaths( path_list );
00416 
00417     bool all_good = true, found = false;
00418     // perform search in paths:
00419     for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
00420     {
00421         // Scan path/types/* (non recursive)
00422         path p = path(*it) / subdir;
00423         if (is_directory(p))
00424         {
00425             log(Info) << "Loading "<<kind<<" libraries from directory " << p.string() << " ..."<<endlog();
00426             for (directory_iterator itr(p); itr != directory_iterator(); ++itr)
00427             {
00428                 log(Debug) << "Scanning file " << itr->path().string() << " ...";
00429                 if (is_regular_file(itr->status()) && isLoadableLibrary(itr->path()) ) {
00430                     found = true;
00431                     std::string libname;
00432 #if BOOST_VERSION >= 104600
00433                     libname = itr->path().filename().string();
00434 #else
00435                     libname = itr->path().filename();
00436 #endif
00437                     if(!isCompatiblePlugin(libname))
00438                     {
00439                         log(Debug) << "not a compatible plugin: ignored."<<endlog();
00440                     }
00441                     else
00442                     {
00443                         found = true;
00444                         all_good = loadInProcess( itr->path().string(), makeShortFilename(libname), kind, true) && all_good;
00445                     }
00446                 } else {
00447                     if (!is_regular_file(itr->status()))
00448                         log(Debug) << "not a regular file: ignored."<<endlog();
00449                     else
00450                         log(Debug) << "not a " + SO_EXT + " library: ignored."<<endlog();
00451                 }
00452             }
00453         }
00454         else
00455             log(Debug) << "No such directory: " << p << endlog();
00456     }
00457     if (!all_good)
00458         throw std::runtime_error("Some found plugins could not be loaded !");
00459     return found;
00460 }
00461 
00462 bool PluginLoader::loadLibrary( std::string const& name )
00463 {
00464     // If exact match, load it directly:
00465     path arg( name );
00466     if (is_regular_file(arg)) {
00467 #if BOOST_VERSION >= 104600
00468         string subdir = arg.parent_path().filename().string();
00469 #else
00470         string subdir = arg.parent_path().leaf();
00471 #endif
00472         string kind;
00473         // we only load it if it is in types or plugins subdir:
00474         if (subdir == "types") kind = "typekit";
00475         if (subdir == "plugins") kind = "plugin";
00476         if ( !kind.empty() ) {
00477 #if BOOST_VERSION >= 104600
00478             string libname = arg.filename().string();
00479 #else
00480             string libname = arg.filename();
00481 #endif
00482             if(!isCompatiblePlugin(libname))
00483             {
00484                 log(Error) << "The " << kind << " " << name << " was found but is incompatible." << endlog();
00485                 return false;
00486             }
00487 
00488 #if BOOST_VERSION >= 104600
00489             if ( loadInProcess(arg.string(), makeShortFilename(arg.filename().string()), kind, true) == false)
00490 #else
00491             if ( loadInProcess(arg.string(), makeShortFilename(arg.filename()), kind, true) == false)
00492 #endif
00493                 throw std::runtime_error("The plugin "+name+" was found but could not be loaded !");
00494             return true;
00495         }
00496 
00497         log(Error) << "refusing to load " << name << " as I could not autodetect its type (name=" << name << ", path=" << arg.string() << ", subdir=" << subdir << ")" << endlog();
00498         // file exists but not typekit or plugin:
00499         return false;
00500     }
00501 
00502     // bail out if absolute path
00503     if ( arg.is_complete() )
00504         return false;
00505 
00506     // try relative match:
00507     path dir = arg.parent_path();
00508 #if BOOST_VERSION >= 104600
00509     string file = arg.filename().string();
00510 #else
00511     string file = arg.filename();
00512 #endif
00513     vector<string> paths = splitPaths(plugin_path);
00514     vector<string> tryouts( paths.size() * 8 );
00515     tryouts.clear();
00516 
00517     // search in plugins/types:
00518     string subdir = "plugins"; string kind = "plugin";
00519     while (true) {
00520         for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
00521         {
00522             path p = path(*it) / dir / subdir / (file + FULL_PLUGINS_SUFFIX);
00523             tryouts.push_back( p.string() );
00524             if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
00525                 return true;
00526             p = path(*it) / dir / subdir / ("lib" + file + FULL_PLUGINS_SUFFIX);
00527             tryouts.push_back( p.string() );
00528             if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
00529                 return true;
00530             p = path(*it) / OROCOS_TARGET_NAME / dir / subdir / (file + FULL_PLUGINS_SUFFIX);
00531             tryouts.push_back( p.string() );
00532             if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
00533                 return true;
00534             p = path(*it) / OROCOS_TARGET_NAME / dir / subdir / ("lib" + file + FULL_PLUGINS_SUFFIX);
00535             tryouts.push_back( p.string() );
00536             if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
00537                 return true;
00538         }
00539         if (subdir == "types")
00540             break;
00541         subdir = "types";
00542         kind   = "typekit";
00543     }
00544     log(Debug) << "No such "<< kind << " found in path: " << name << ". Tried:"<< endlog();
00545     for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it)
00546         log(Debug) << *it << endlog();
00547 
00548     return false;
00549 }
00550 
00551 bool PluginLoader::loadPluginInternal( std::string const& name, std::string const& path_list, std::string const& subdir, std::string const& kind )
00552 {
00553         // If exact match, load it directly:
00554     // special case for ourselves, rtt plugins are not in an 'rtt' subdir:
00555     if (name != "rtt" && loadLibrary(name)) {
00556         log(Warning) << "You supplied a filename as first argument to 'loadPlugin(name,path)' or 'loadTypekit(name,path)'."<<nlog();
00557         log(Warning) << "Please use 'loadLibrary(filename)' instead since the function you use will only interprete 'name' as a directory name in future releases."<<endlog();
00558         return true;
00559     }
00560 
00561     if ( isLoadedInternal(name) ) {
00562         log(Debug) <<kind << " '"<< name <<"' already loaded. Not reloading it." <<endlog();
00563         return true;
00564     } else {
00565         log(Info) << kind << " '"<< name <<"' not loaded before." <<endlog();
00566     }
00567 
00568     string paths, trypaths;
00569     if (path_list.empty())
00570         paths = plugin_path + default_delimiter + ".";
00571     else
00572         paths = path_list;
00573 
00574     // search in '.' if really no paths are given.
00575     if (paths.empty())
00576         paths = ".";
00577 
00578     // append '/name' to each plugin path in order to search all of them:
00579     vector<string> vpaths = splitPaths(paths);
00580     paths.clear();
00581     bool path_found = false;
00582     string plugin_dir = name;
00583     if (name == "rtt" ) // special case for ourselves, rtt plugins are not in an 'rtt' subdir:
00584         plugin_dir = ".";
00585     for(vector<string>::iterator it = vpaths.begin(); it != vpaths.end(); ++it) {
00586         path p(*it);
00587         p = p / plugin_dir;
00588         // we only search in existing directories:
00589         if (is_directory( p )) {
00590             path_found = true;
00591             paths += p.string() + default_delimiter;
00592         } else {
00593             trypaths += p.string() + default_delimiter;
00594         }
00595         p = *it;
00596         p = p / OROCOS_TARGET_NAME / plugin_dir;
00597         // we only search in existing directories:
00598         if (is_directory( p )) {
00599             path_found = true;
00600             paths += p.string() + default_delimiter;
00601         } else {
00602             trypaths += p.string() + default_delimiter;
00603         }
00604     }
00605 
00606     // when at least one directory exists:
00607     if (path_found) {
00608         paths.erase( paths.size() - 1 ); // remove trailing delimiter ';'
00609         return loadPluginsInternal(paths,subdir,kind);
00610     }
00611     log(Error) << "No such "<< kind << " found in path: " << name << ". Looked for these directories: "<< endlog();
00612     if ( !paths.empty() )
00613         log(Error) << "Exist, but don't contain it: " << paths << endlog();
00614     else
00615         log(Error) << "None of the search paths exist !" << endlog();
00616     if ( !trypaths.empty() )
00617         log(Error) << "Don't exist: " << trypaths << endlog();
00618     return false;
00619 }
00620 
00621 bool PluginLoader::isLoaded(string file)
00622 {
00623     MutexLock lock( listlock );
00624     return isLoadedInternal(file);
00625 }
00626 
00627 bool PluginLoader::isLoadedInternal(string file)
00628 {
00629     path p(file);
00630     std::vector<LoadedLib>::iterator lib = loadedLibs.begin();
00631     while (lib != loadedLibs.end()) {
00632         // there is already a library with the same name
00633         if ( lib->filename == p.filename() || lib->plugname == file || lib->shortname == file ) {
00634             return true;
00635         }
00636         ++lib;
00637     }
00638     return false;
00639 }
00640 
00641 // loads a single plugin in the current process.
00642 bool PluginLoader::loadInProcess(string file, string shortname, string kind, bool log_error) {
00643     path p(file);
00644     char* error;
00645     void* handle;
00646 
00647     if ( isLoadedInternal(shortname) || isLoadedInternal(file) ) {
00648         log(Debug) <<"plugin '"<< file <<"' already loaded. Not reloading it." <<endlog() ;
00649         return true;
00650     }
00651 
00652     // Last chance to validate plugin compatibility
00653     if(!isCompatiblePlugin(file))
00654     {
00655         if(log_error)
00656             log(Error) << "could not load library '"<< p.string() <<"': incompatible." <<endlog();
00657         return false;
00658     }
00659 
00660     handle = dlopen ( p.string().c_str(), RTLD_NOW | RTLD_GLOBAL );
00661 
00662     if (!handle) {
00663         string e( dlerror() );
00664         if (log_error)
00665             log(Error) << "could not load library '"<< p.string() <<"': "<< e <<endlog();
00666         else
00667             endlog();
00668         return false;
00669     }
00670 
00671     //------------- if you get here, the library has been loaded -------------
00672 #if BOOST_VERSION >= 104600
00673     string libname = p.filename().string();
00674 #else
00675     string libname = p.filename();
00676 #endif
00677     log(Debug)<<"Found library "<<libname<<endlog();
00678     LoadedLib loading_lib(libname,shortname,handle);
00679     dlerror();    /* Clear any existing error */
00680 
00681     std::string(*pluginName)(void) = 0;
00682     std::string(*targetName)(void) = 0;
00683     loading_lib.loadPlugin = (bool(*)(RTT::TaskContext*))(dlsym(handle, "loadRTTPlugin") );
00684     if ((error = dlerror()) == NULL) {
00685         string plugname, targetname;
00686         pluginName = (std::string(*)(void))(dlsym(handle, "getRTTPluginName") );
00687         if ((error = dlerror()) == NULL) {
00688             plugname = (*pluginName)();
00689         } else {
00690             plugname  = libname;
00691         }
00692         loading_lib.plugname = plugname;
00693         targetName = (std::string(*)(void))(dlsym(handle, "getRTTTargetName") );
00694         if ((error = dlerror()) == NULL) {
00695             targetname = (*targetName)();
00696         } else {
00697             targetname  = OROCOS_TARGET_NAME;
00698         }
00699         if ( targetname != OROCOS_TARGET_NAME ) {
00700             log(Error) << "Plugin "<< plugname <<" reports to be compiled for OROCOS_TARGET "<< targetname
00701                     << " while we are running on target "<< OROCOS_TARGET_NAME <<". Unloading."<<endlog();
00702             dlclose(handle);
00703             return false;
00704         }
00705 
00706         // check if it is a service plugin:
00707         loading_lib.createService = (Service::shared_ptr(*)(void))(dlsym(handle, "createService") );
00708         if (loading_lib.createService)
00709             loading_lib.is_service = true;
00710 
00711         // ok; try to load it.
00712         bool success = false;
00713         try {
00714             // Load into process (TaskContext* == 0):
00715             success = (*loading_lib.loadPlugin)( 0 );
00716         } catch(std::exception& e) {
00717             log(Error) << "Loading "<< plugname <<" threw an exception: "<< e.what() << endlog();
00718         } catch(...) {
00719             log(Error) << "Unexpected exception in loadRTTPlugin !"<<endlog();
00720         }
00721 
00722         if ( !success ) {
00723             log(Error) << "Failed to load RTT Plugin '" <<plugname<<"': plugin refused to load into this process. Unloading." <<endlog();
00724             dlclose(handle);
00725             return false;
00726         }
00727         if (kind == "typekit") {
00728             log(Info) << "Loaded RTT TypeKit/Transport '" + plugname + "' from '" + shortname +"'"<<endlog();
00729             loading_lib.is_typekit = true;
00730         } else {
00731             loading_lib.is_typekit = false;
00732             if ( loading_lib.is_service ) {
00733                 log(Info) << "Loaded RTT Service '" + plugname + "' from '" + shortname +"'"<<endlog();
00734             }
00735             else {
00736                 log(Info) << "Loaded RTT Plugin '" + plugname + "' from '" + shortname +"'"<<endlog();
00737             }
00738         }
00739         loadedLibs.push_back(loading_lib);
00740         return true;
00741     } else {
00742         if (log_error)
00743             log(Error) <<"Not a plugin: " << error << endlog();
00744     }
00745     dlclose(handle);
00746     return false;
00747 }
00748 
00749 std::vector<std::string> PluginLoader::listServices() const {
00750     MutexLock lock( listlock );
00751     vector<string> names;
00752     for(vector<LoadedLib>::const_iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
00753         if ( it->is_service )
00754             names.push_back( it->plugname );
00755     }
00756     return names;
00757 }
00758 
00759 std::vector<std::string> PluginLoader::listPlugins() const {
00760     MutexLock lock( listlock );
00761     vector<string> names;
00762     for(vector<LoadedLib>::const_iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
00763         names.push_back( it->plugname );
00764     }
00765     return names;
00766 }
00767 
00768 std::vector<std::string> PluginLoader::listTypekits() const {
00769     MutexLock lock( listlock );
00770     vector<string> names;
00771     for(vector<LoadedLib>::const_iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
00772         if ( it->is_typekit )
00773             names.push_back( it->plugname );
00774     }
00775     return names;
00776 }
00777 
00778 std::string PluginLoader::getPluginPath() const {
00779     MutexLock lock( listlock );
00780     return plugin_path;
00781 }
00782 
00783 void PluginLoader::setPluginPath( std::string const& newpath ) {
00784     MutexLock lock( listlock );
00785     plugin_path = newpath;
00786 }
00787 
00788 bool PluginLoader::isCompatiblePlugin(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 plugin file '" + libname + "'" <<endlog();
00799 
00800 #ifdef OROCOS_TARGET_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_PLUGINS_SUFFIX))
00805     {
00806         //log(Debug) << "Plugin file '" + libname + "' is incompatible because it doesn't have the suffix " << FULL_PLUGINS_SUFFIX << endlog();
00807         return false;
00808     }
00809 #endif // OROCOS_TARGET_WIN32
00810 
00811     // There's no validation on other targets
00812 
00813     //log(Debug) << "Plugin file '" + libname + "' is compatible." <<endlog();
00814 
00815     return true;
00816 }


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