47 #include "../TaskContext.hpp" 48 #include "../Logger.hpp" 49 #include <boost/filesystem.hpp> 50 #include <boost/version.hpp> 51 #include "../os/StartStopManager.hpp" 52 #include "../os/MutexLock.hpp" 53 #include "../internal/GlobalService.hpp" 69 static const std::string SO_EXT(
".dylib");
70 static const std::string SO_POSTFIX(
"");
73 static const std::string SO_EXT(
".dll");
75 static const std::string SO_POSTFIX(
"d");
77 static const std::string SO_POSTFIX(
"");
80 static const std::string SO_EXT(
".so");
81 static const std::string SO_POSTFIX(
"");
86 static const std::string FULL_PLUGINS_SUFFIX(
string(
"-") +
string(
OROCOS_TARGET_NAME) + SO_POSTFIX + SO_EXT);
90 static const std::string delimiters(
";");
91 static const std::string default_delimiter(
";");
93 static const std::string delimiters(
":;");
94 static const std::string default_delimiter(
":");
100 #define RTT_UNUSED __attribute__((unused)) 118 if (!ext.empty() && (
'.' == ext[0]))
120 std::istringstream iss;
123 iss.str(ext.substr((
size_t)1));
124 iss >> std::dec >> std::noskipws >> i;
125 isExtensionVersion = !iss.fail() && iss.eof();
154 bool isLoadable =
false;
156 #if defined(__APPLE__) 158 #if BOOST_VERSION >= 104600 159 ext = filename.extension().string();
161 ext = filename.extension();
164 if (0 == ext.compare(SO_EXT))
169 path name = filename.stem();
170 path ext = name.extension();
184 (filename.extension() == SO_EXT) &&
185 !filename.stem().empty();
193 static vector<string> splitPaths(
string const& str)
195 vector<string> paths;
198 string::size_type lastPos = str.find_first_not_of(delimiters, 0);
200 string::size_type pos = str.find_first_of(delimiters, lastPos);
202 while (string::npos != pos || string::npos != lastPos)
205 if ( !str.substr(lastPos, pos - lastPos).empty() )
206 paths.push_back(str.substr(lastPos, pos - lastPos));
208 lastPos = str.find_first_not_of(delimiters, pos);
210 pos = str.find_first_of(delimiters, lastPos);
213 paths.push_back(
".");
217 static void removeDuplicates(
string& path_list)
219 vector<string> paths;
224 paths = splitPaths( path_list );
227 for(vector<string>::const_iterator it = paths.begin(); it != paths.end(); ++it)
234 result = result + *it + default_delimiter;
238 if (result.size() >= default_delimiter.size() && result.substr(result.size() - default_delimiter.size()) == default_delimiter)
239 result = result.substr(0, result.size() - default_delimiter.size());
241 path_list.swap(result);
250 static string makeShortFilename(
string const& str) {
252 if (str.substr(0,3) ==
"lib")
254 if (ret.rfind(FULL_PLUGINS_SUFFIX) != string::npos)
255 ret = ret.substr(0, ret.rfind(FULL_PLUGINS_SUFFIX) );
261 static RTT_UNUSED bool hasEnding(
string const &fullString,
string const &ending)
263 if (fullString.length() > ending.length()) {
264 return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
282 char* paths = getenv(
"RTT_COMPONENT_PATH");
285 plugin_paths = paths;
287 if ( !default_plugin_path.empty() )
288 plugin_paths = plugin_paths + default_delimiter + default_plugin_path;
289 removeDuplicates( plugin_paths );
290 log(
Info) <<
"RTT_COMPONENT_PATH was set to: " << paths <<
" . Searching in: "<< plugin_paths<< endlog();
293 removeDuplicates( plugin_paths );
294 log(
Info) <<
"No RTT_COMPONENT_PATH set. Using default: " << plugin_paths <<endlog();
302 }
catch(std::exception& e) {
303 log(
Warning) << e.what() <<endlog();
304 log(
Warning) <<
"Corrupted files found in '" << plugin_paths <<
"'. Fix or remove these plugins."<<endlog();
319 static boost::shared_ptr<PluginLoader> instance2;
338 return loadPluginsInternal( path_list,
"types",
"typekit");
343 return loadPluginInternal(name, path_list,
"types",
"typekit");
348 return loadPluginInternal(name, path_list,
"plugins",
"plugin");
353 return loadPluginsInternal( path_list,
"plugins",
"plugin");
358 for(vector<LoadedLib>::iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
359 if (it->filename == servicename || it->plugname == servicename || it->shortname == servicename) {
361 log(
Info) <<
"Loading Service or Plugin " << servicename <<
" in TaskContext " << tc->
getName() <<endlog();
363 return it->loadPlugin( tc );
364 }
catch(std::exception& e) {
365 log(
Error) <<
"Service or Plugin "<< servicename <<
" threw an exception during loading in " << tc->
getName() << endlog();
366 log(
Error) <<
"Exception: "<< e.what() << endlog();
369 log(
Error) <<
"Service or Plugin "<< servicename <<
" threw an unknown exception during loading in " << tc->
getName() << endlog();
377 }
catch(std::exception& e) {
378 log(
Error) <<
"Service "<< servicename <<
" threw an exception during loading in global service." << endlog();
379 log(
Error) <<
"Exception: "<< e.what() << endlog();
382 log(
Error) <<
"Service "<< servicename <<
" threw an unknown exception during loading in global service. " << endlog();
385 log(
Error) <<
"Plugin "<< servicename <<
" was found, but it's not a Service." <<endlog();
389 log(
Error) <<
"No such service or plugin: '"<< servicename <<
"'"<< endlog();
394 bool PluginLoader::loadPluginsInternal( std::string
const& path_list, std::string
const& subdir, std::string
const& kind )
397 path arg( path_list );
398 if (is_regular_file(arg)) {
399 #if BOOST_VERSION >= 104600 400 if ( loadInProcess(arg.string(), makeShortFilename(arg.filename().string()), kind,
true) ==
false)
402 if ( loadInProcess(arg.string(), makeShortFilename(arg.filename()), kind,
true) ==
false)
404 throw std::runtime_error(
"The plugin "+path_list+
" was found but could not be loaded !");
405 log(
Warning) <<
"You supplied a filename to 'loadPlugins(path)' or 'loadTypekits(path)'."<< nlog();
406 log(
Warning) <<
"Please use 'loadLibrary(filename)' instead since the function you use will only scan directories in future releases."<<endlog();
411 vector<string> paths;
412 if (path_list.empty())
415 paths = splitPaths( path_list );
417 bool all_good =
true, found =
false;
419 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
422 path p = path(*it) / subdir;
425 log(
Info) <<
"Loading "<<kind<<
" libraries from directory " << p.string() <<
" ..."<<endlog();
426 for (directory_iterator itr(p); itr != directory_iterator(); ++itr)
428 log(
Debug) <<
"Scanning file " << itr->path().string() <<
" ...";
432 #if BOOST_VERSION >= 104600 433 libname = itr->path().filename().string();
435 libname = itr->path().filename();
437 if(!isCompatiblePlugin(libname))
439 log(
Debug) <<
"not a compatible plugin: ignored."<<endlog();
444 all_good = loadInProcess( itr->path().string(), makeShortFilename(libname), kind,
true) && all_good;
447 if (!is_regular_file(itr->status()))
448 log(
Debug) <<
"not a regular file: ignored."<<endlog();
450 log(
Debug) <<
"not a " + SO_EXT +
" library: ignored."<<endlog();
455 log(
Debug) <<
"No such directory: " << p << endlog();
458 throw std::runtime_error(
"Some found plugins could not be loaded !");
466 if (is_regular_file(arg)) {
467 #if BOOST_VERSION >= 104600 468 string subdir = arg.parent_path().filename().string();
470 string subdir = arg.parent_path().leaf();
474 if (subdir ==
"types") kind =
"typekit";
475 if (subdir ==
"plugins") kind =
"plugin";
476 if ( !kind.empty() ) {
477 #if BOOST_VERSION >= 104600 478 string libname = arg.filename().string();
480 string libname = arg.filename();
482 if(!isCompatiblePlugin(libname))
484 log(
Error) <<
"The " << kind <<
" " << name <<
" was found but is incompatible." << endlog();
488 #if BOOST_VERSION >= 104600 489 if ( loadInProcess(arg.string(), makeShortFilename(arg.filename().string()), kind,
true) ==
false)
491 if ( loadInProcess(arg.string(), makeShortFilename(arg.filename()), kind,
true) ==
false)
493 throw std::runtime_error(
"The plugin "+name+
" was found but could not be loaded !");
497 log(
Error) <<
"refusing to load " << name <<
" as I could not autodetect its type (name=" << name <<
", path=" << arg.string() <<
", subdir=" << subdir <<
")" << endlog();
503 if ( arg.is_complete() )
507 path dir = arg.parent_path();
508 #if BOOST_VERSION >= 104600 509 string file = arg.filename().string();
511 string file = arg.filename();
513 vector<string> paths = splitPaths(plugin_path);
514 vector<string> tryouts( paths.size() * 8 );
518 string subdir =
"plugins";
string kind =
"plugin";
520 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
522 path p = path(*it) / dir / subdir / (file + FULL_PLUGINS_SUFFIX);
523 tryouts.push_back( p.string() );
524 if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
526 p = path(*it) / dir / subdir / (
"lib" + file + FULL_PLUGINS_SUFFIX);
527 tryouts.push_back( p.string() );
528 if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
531 tryouts.push_back( p.string() );
532 if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
534 p = path(*it) /
OROCOS_TARGET_NAME / dir / subdir / (
"lib" + file + FULL_PLUGINS_SUFFIX);
535 tryouts.push_back( p.string() );
536 if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
539 if (subdir ==
"types")
544 log(
Debug) <<
"No such "<< kind <<
" found in path: " << name <<
". Tried:"<< endlog();
545 for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it)
546 log(
Debug) << *it << endlog();
551 bool PluginLoader::loadPluginInternal( std::string
const& name, std::string
const& path_list, std::string
const& subdir, std::string
const& kind )
555 if (name !=
"rtt" && loadLibrary(name)) {
556 log(
Warning) <<
"You supplied a filename as first argument to 'loadPlugin(name,path)' or 'loadTypekit(name,path)'."<<nlog();
557 log(
Warning) <<
"Please use 'loadLibrary(filename)' instead since the function you use will only interprete 'name' as a directory name in future releases."<<endlog();
561 if ( isLoadedInternal(name) ) {
562 log(
Debug) <<kind <<
" '"<< name <<
"' already loaded. Not reloading it." <<endlog();
565 log(
Info) << kind <<
" '"<< name <<
"' not loaded before." <<endlog();
568 string paths, trypaths;
569 if (path_list.empty())
570 paths = plugin_path + default_delimiter +
".";
579 vector<string> vpaths = splitPaths(paths);
581 bool path_found =
false;
582 string plugin_dir = name;
585 for(vector<string>::iterator it = vpaths.begin(); it != vpaths.end(); ++it) {
589 if (is_directory( p )) {
591 paths += p.string() + default_delimiter;
593 trypaths += p.string() + default_delimiter;
598 if (is_directory( p )) {
600 paths += p.string() + default_delimiter;
602 trypaths += p.string() + default_delimiter;
608 paths.erase( paths.size() - 1 );
609 return loadPluginsInternal(paths,subdir,kind);
611 log(
Error) <<
"No such "<< kind <<
" found in path: " << name <<
". Looked for these directories: "<< endlog();
612 if ( !paths.empty() )
613 log(
Error) <<
"Exist, but don't contain it: " << paths << endlog();
615 log(
Error) <<
"None of the search paths exist !" << endlog();
616 if ( !trypaths.empty() )
617 log(
Error) <<
"Don't exist: " << trypaths << endlog();
624 return isLoadedInternal(file);
627 bool PluginLoader::isLoadedInternal(
string file)
630 std::vector<LoadedLib>::iterator lib = loadedLibs.begin();
631 while (lib != loadedLibs.end()) {
633 if ( lib->filename == p.filename() || lib->plugname == file || lib->shortname == file ) {
642 bool PluginLoader::loadInProcess(
string file,
string shortname,
string kind,
bool log_error) {
647 if ( isLoadedInternal(shortname) || isLoadedInternal(file) ) {
648 log(
Debug) <<
"plugin '"<< file <<
"' already loaded. Not reloading it." <<endlog() ;
653 if(!isCompatiblePlugin(file))
656 log(
Error) <<
"could not load library '"<< p.string() <<
"': incompatible." <<endlog();
665 log(
Error) <<
"could not load library '"<< p.string() <<
"': "<< e <<endlog();
672 #if BOOST_VERSION >= 104600 673 string libname = p.filename().string();
675 string libname = p.filename();
677 log(
Debug)<<
"Found library "<<libname<<endlog();
678 LoadedLib loading_lib(libname,shortname,handle);
681 std::string(*pluginName)(void) = 0;
682 std::string(*targetName)(void) = 0;
684 if ((error =
dlerror()) == NULL) {
685 string plugname, targetname;
686 pluginName = (std::string(*)(void))(
dlsym(handle,
"getRTTPluginName") );
687 if ((error =
dlerror()) == NULL) {
688 plugname = (*pluginName)();
692 loading_lib.plugname = plugname;
693 targetName = (std::string(*)(void))(
dlsym(handle,
"getRTTTargetName") );
694 if ((error =
dlerror()) == NULL) {
695 targetname = (*targetName)();
700 log(
Error) <<
"Plugin "<< plugname <<
" reports to be compiled for OROCOS_TARGET "<< targetname
701 <<
" while we are running on target "<<
OROCOS_TARGET_NAME <<
". Unloading."<<endlog();
708 if (loading_lib.createService)
709 loading_lib.is_service =
true;
712 bool success =
false;
715 success = (*loading_lib.loadPlugin)( 0 );
716 }
catch(std::exception& e) {
717 log(
Error) <<
"Loading "<< plugname <<
" threw an exception: "<< e.what() << endlog();
719 log(
Error) <<
"Unexpected exception in loadRTTPlugin !"<<endlog();
723 log(
Error) <<
"Failed to load RTT Plugin '" <<plugname<<
"': plugin refused to load into this process. Unloading." <<endlog();
727 if (kind ==
"typekit") {
728 log(
Info) <<
"Loaded RTT TypeKit/Transport '" + plugname +
"' from '" + shortname +
"'"<<endlog();
729 loading_lib.is_typekit =
true;
731 loading_lib.is_typekit =
false;
732 if ( loading_lib.is_service ) {
733 log(
Info) <<
"Loaded RTT Service '" + plugname +
"' from '" + shortname +
"'"<<endlog();
736 log(
Info) <<
"Loaded RTT Plugin '" + plugname +
"' from '" + shortname +
"'"<<endlog();
739 loadedLibs.push_back(loading_lib);
743 log(
Error) <<
"Not a plugin: " << error << endlog();
751 vector<string> names;
752 for(vector<LoadedLib>::const_iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
753 if ( it->is_service )
754 names.push_back( it->plugname );
761 vector<string> names;
762 for(vector<LoadedLib>::const_iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
763 names.push_back( it->plugname );
770 vector<string> names;
771 for(vector<LoadedLib>::const_iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
772 if ( it->is_typekit )
773 names.push_back( it->plugname );
785 plugin_path = newpath;
788 bool PluginLoader::isCompatiblePlugin(std::string
const& filepath)
792 #if BOOST_VERSION >= 104600 793 string libname = p.filename().string();
795 string libname = p.filename();
800 #ifdef OROCOS_TARGET_WIN32 804 if(!hasEnding(libname, FULL_PLUGINS_SUFFIX))
809 #endif // OROCOS_TARGET_WIN32
Use this to register a global cleanup function to the StartStopManager.
Use this to register a global init function to the StartStopManager.
#define OROCOS_TARGET_NAME
bool loadService(std::string const &servicename, TaskContext *tc)
Loads an earlier discovered service into a TaskContext.
RTT_API char * dlerror(void)
RTT_API bool isExtensionVersion(const std::string &ext)
Determine whether a file extension is actually part of a library version.
RTT_API void * dlsym(void *handle, const char *name)
static void Release()
Release the PluginLoader, erasing all knowledge of loaded libraries.
RTT_API int dlclose(void *handle)
Loads plugins found on the filesystem and keeps track of found plugins, typekits and services...
boost::shared_ptr< Service > shared_ptr
bool loadTypekits(std::string const &path_list)
Load any typekit found in the 'types/' subdirectory of each path in path_list in the process...
Convenient short notation for every sub-namespace of RTT.
bool loadTypekit(std::string const &name, std::string const &path_list)
Load a typekit found in the 'types/' subdirectory of a package present in path_list.
std::vector< std::string > listTypekits() const
Lists all typekits discovered by the PluginLoader.
bool loadLibrary(std::string const &path)
Loads a library as plugin or typekit.
char const * default_plugin_path
std::vector< std::string > listPlugins() const
Lists all plugins (= services + typekits) discovered by the PluginLoader.
void setPluginPath(std::string const &newpath)
Sets the plugin path list.
bool isLoaded(std::string name)
Checks if a given plugin or filename has been loaded.
The TaskContext is the C++ representation of an Orocos component.
static boost::shared_ptr< PluginLoader > Instance()
Create the instance of the PluginLoader.
std::vector< std::string > listServices() const
Lists all services discovered by the PluginLoader.
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
std::string getPluginPath() const
Returns the current plugin path list.
RTT_API bool isLoadableLibrary(const path &filename)
bool loadPlugin(std::string const &name, std::string const &path_list)
Loads a plugin found in the 'plugins/' subdirectory of each path in path_list in the current process...
bool loadPlugins(std::string const &path_list)
Loads any plugin found in the 'plugins/' subdirectory of each path in path_list in the current proces...
static RTT_API Service::shared_ptr Instance()
virtual const std::string & getName() const
Returns the name of this TaskContext.
RTT_API void * dlopen(const char *file, int mode)
MutexLock is a scope based Monitor, protecting critical sections with a Mutex object through locking ...