Orocos Real-Time Toolkit
2.6.0
|
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 static 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 static 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 static 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 }