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