00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
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
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
00084 static const std::string FULL_PLUGINS_SUFFIX(string("-") + string(OROCOS_TARGET_NAME) + SO_POSTFIX + SO_EXT);
00085
00086
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));
00113 iss >> std::dec >> std::noskipws >> i;
00114 isExtensionVersion = !iss.fail() && iss.eof();
00115 }
00116
00117 return isExtensionVersion;
00118 }
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
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
00153 if (0 == ext.compare(SO_EXT))
00154 {
00155
00156
00157
00158 path name = filename.stem();
00159 path ext = name.extension();
00160 isLoadable =
00161
00162 !name.empty() &&
00163
00164 (ext.empty() || !isExtensionVersion(ext.string()));
00165 }
00166
00167
00168 #else
00169
00170
00171
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
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
00205 PluginLoader::Instance()->setPluginPath(plugin_paths);
00206
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
00236 string::size_type lastPos = str.find_first_not_of(delimiters, 0);
00237
00238 string::size_type pos = str.find_first_of(delimiters, lastPos);
00239
00240 while (string::npos != pos || string::npos != lastPos)
00241 {
00242
00243 if ( !str.substr(lastPos, pos - lastPos).empty() )
00244 paths.push_back(str.substr(lastPos, pos - lastPos));
00245
00246 lastPos = str.find_first_not_of(delimiters, pos);
00247
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
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
00354 bool PluginLoader::loadPluginsInternal( std::string const& path_list, std::string const& subdir, std::string const& kind )
00355 {
00356
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
00371 vector<string> paths;
00372 if (path_list.empty())
00373 return false;
00374 else
00375 paths = splitPaths( path_list );
00376
00377 bool all_good = true, found = false;
00378
00379 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
00380 {
00381
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
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
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
00459 return false;
00460 }
00461
00462
00463 if ( arg.is_complete() )
00464 return false;
00465
00466
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
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
00514
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
00535 if (paths.empty())
00536 paths = ".";
00537
00538
00539 vector<string> vpaths = splitPaths(paths);
00540 paths.clear();
00541 bool path_found = false;
00542 string plugin_dir = name;
00543 if (name == "rtt" )
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
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
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
00567 if (path_found) {
00568 paths.erase( paths.size() - 1 );
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
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
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
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
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();
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
00667 loading_lib.createService = (Service::shared_ptr(*)(void))(dlsym(handle, "createService") );
00668 if (loading_lib.createService)
00669 loading_lib.is_service = true;
00670
00671
00672 bool success = false;
00673 try {
00674
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
00757
00758 #ifdef OROCOS_TARGET_WIN32
00759
00760
00761
00762 if(!hasEnding(libname, FULL_PLUGINS_SUFFIX))
00763 {
00764
00765 return false;
00766 }
00767 #endif // OROCOS_TARGET_WIN32
00768
00769
00770
00771
00772
00773 return true;
00774 }