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(
":");
109 if (!ext.empty() && (
'.' == ext[0]))
111 std::istringstream iss;
114 iss.str(ext.substr((
size_t)1));
115 iss >> std::dec >> std::noskipws >> i;
116 isExtensionVersion = !iss.fail() && iss.eof();
145 bool isLoadable =
false;
147 #if defined(__APPLE__) 149 #if BOOST_VERSION >= 104600 150 ext = filename.extension().string();
152 ext = filename.extension();
155 if (0 == ext.compare(SO_EXT))
160 path name = filename.stem();
161 path ext = name.extension();
175 (filename.extension() == SO_EXT) &&
176 !filename.stem().empty();
184 static vector<string> splitPaths(
string const& str)
186 vector<string> paths;
189 string::size_type lastPos = str.find_first_not_of(delimiters, 0);
191 string::size_type pos = str.find_first_of(delimiters, lastPos);
193 while (string::npos != pos || string::npos != lastPos)
196 if ( !str.substr(lastPos, pos - lastPos).empty() )
197 paths.push_back(str.substr(lastPos, pos - lastPos));
199 lastPos = str.find_first_not_of(delimiters, pos);
201 pos = str.find_first_of(delimiters, lastPos);
204 paths.push_back(
".");
208 static void removeDuplicates(
string& path_list)
210 vector<string> paths;
215 paths = splitPaths( path_list );
218 for(vector<string>::const_iterator it = paths.begin(); it != paths.end(); ++it)
225 result = result + *it + default_delimiter;
229 if (result.size() >= default_delimiter.size() && result.substr(result.size() - default_delimiter.size()) == default_delimiter)
230 result = result.substr(0, result.size() - default_delimiter.size());
232 path_list.swap(result);
241 static string makeShortFilename(
string const& str) {
243 if (str.substr(0,3) ==
"lib")
245 if (ret.rfind(FULL_PLUGINS_SUFFIX) != string::npos)
246 ret = ret.substr(0, ret.rfind(FULL_PLUGINS_SUFFIX) );
252 static RTT_UNUSED bool hasEnding(
string const &fullString,
string const &ending)
254 if (fullString.length() > ending.length()) {
255 return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
273 char* paths = getenv(
"RTT_COMPONENT_PATH");
276 plugin_paths = paths;
278 if ( !default_plugin_path.empty() )
279 plugin_paths = plugin_paths + default_delimiter + default_plugin_path;
280 removeDuplicates( plugin_paths );
281 log(
Info) <<
"RTT_COMPONENT_PATH was set to: " << paths <<
" . Searching in: "<< plugin_paths<< endlog();
284 removeDuplicates( plugin_paths );
285 log(
Info) <<
"No RTT_COMPONENT_PATH set. Using default: " << plugin_paths <<endlog();
293 }
catch(std::exception& e) {
294 log(
Warning) << e.what() <<endlog();
295 log(
Warning) <<
"Corrupted files found in '" << plugin_paths <<
"'. Fix or remove these plugins."<<endlog();
310 static boost::shared_ptr<PluginLoader> instance2;
329 return loadPluginsInternal( path_list,
"types",
"typekit");
334 return loadPluginInternal(name, path_list,
"types",
"typekit");
339 return loadPluginInternal(name, path_list,
"plugins",
"plugin");
344 return loadPluginsInternal( path_list,
"plugins",
"plugin");
349 for(vector<LoadedLib>::iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
350 if (it->filename == servicename || it->plugname == servicename || it->shortname == servicename) {
352 log(
Info) <<
"Loading Service or Plugin " << servicename <<
" in TaskContext " << tc->
getName() <<endlog();
354 return it->loadPlugin( tc );
355 }
catch(std::exception& e) {
356 log(
Error) <<
"Service or Plugin "<< servicename <<
" threw an exception during loading in " << tc->
getName() << endlog();
357 log(
Error) <<
"Exception: "<< e.what() << endlog();
360 log(
Error) <<
"Service or Plugin "<< servicename <<
" threw an unknown exception during loading in " << tc->
getName() << endlog();
365 if (it->is_service) {
371 log(
Error) <<
"Service " << servicename <<
" cannot be loaded into the global service." << endlog();
374 }
catch(std::exception& e) {
375 log(
Error) <<
"Service "<< servicename <<
" threw an exception during loading in global service." << endlog();
376 log(
Error) <<
"Exception: "<< e.what() << endlog();
379 log(
Error) <<
"Service "<< servicename <<
" threw an unknown exception during loading in global service. " << endlog();
383 log(
Error) <<
"Plugin "<< servicename <<
" was found, but it's not a Service." <<endlog();
390 log(
Error) <<
"No such service or plugin: '"<< servicename <<
"'"<< endlog();
395 bool PluginLoader::loadPluginsInternal( std::string
const& path_list, std::string
const& subdir, std::string
const& kind )
398 path arg( path_list );
399 if (is_regular_file(arg)) {
400 #if BOOST_VERSION >= 104600 401 if ( loadInProcess(arg.string(), makeShortFilename(arg.filename().string()), kind,
true) ==
false)
403 if ( loadInProcess(arg.string(), makeShortFilename(arg.filename()), kind,
true) ==
false)
405 throw std::runtime_error(
"The plugin "+path_list+
" was found but could not be loaded !");
406 log(
Warning) <<
"You supplied a filename to 'loadPlugins(path)' or 'loadTypekits(path)'."<< nlog();
407 log(
Warning) <<
"Please use 'loadLibrary(filename)' instead since the function you use will only scan directories in future releases."<<endlog();
412 vector<string> paths;
413 if (path_list.empty())
416 paths = splitPaths( path_list );
418 bool all_good =
true, found =
false;
420 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
423 path p = path(*it) / subdir;
426 log(
Info) <<
"Loading "<<kind<<
" libraries from directory " << p.string() <<
" ..."<<endlog();
427 for (directory_iterator itr(p); itr != directory_iterator(); ++itr)
429 log(
Debug) <<
"Scanning file " << itr->path().string() <<
" ...";
433 #if BOOST_VERSION >= 104600 434 libname = itr->path().filename().string();
436 libname = itr->path().filename();
438 if(!isCompatiblePlugin(libname))
440 log(
Debug) <<
"not a compatible plugin: ignored."<<endlog();
445 all_good = loadInProcess( itr->path().string(), makeShortFilename(libname), kind,
true) && all_good;
448 if (!is_regular_file(itr->status()))
449 log(
Debug) <<
"not a regular file: ignored."<<endlog();
451 log(
Debug) <<
"not a " + SO_EXT +
" library: ignored."<<endlog();
456 log(
Debug) <<
"No such directory: " << p << endlog();
459 throw std::runtime_error(
"Some found plugins could not be loaded !");
467 if (is_regular_file(arg)) {
468 #if BOOST_VERSION >= 104600 469 string subdir = arg.parent_path().filename().string();
471 string subdir = arg.parent_path().leaf();
475 if (subdir ==
"types") kind =
"typekit";
476 if (subdir ==
"plugins") kind =
"plugin";
477 if ( !kind.empty() ) {
478 #if BOOST_VERSION >= 104600 479 string libname = arg.filename().string();
481 string libname = arg.filename();
483 if(!isCompatiblePlugin(libname))
485 log(
Error) <<
"The " << kind <<
" " << name <<
" was found but is incompatible." << endlog();
489 #if BOOST_VERSION >= 104600 490 if ( loadInProcess(arg.string(), makeShortFilename(arg.filename().string()), kind,
true) ==
false)
492 if ( loadInProcess(arg.string(), makeShortFilename(arg.filename()), kind,
true) ==
false)
494 throw std::runtime_error(
"The plugin "+name+
" was found but could not be loaded !");
498 log(
Error) <<
"refusing to load " << name <<
" as I could not autodetect its type (name=" << name <<
", path=" << arg.string() <<
", subdir=" << subdir <<
")" << endlog();
504 if ( arg.is_complete() )
508 path dir = arg.parent_path();
509 #if BOOST_VERSION >= 104600 510 string file = arg.filename().string();
512 string file = arg.filename();
514 vector<string> paths = splitPaths(plugin_path);
515 vector<string> tryouts( paths.size() * 8 );
519 string subdir =
"plugins";
string kind =
"plugin";
521 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
523 path p = path(*it) / dir / subdir / (file + FULL_PLUGINS_SUFFIX);
524 tryouts.push_back( p.string() );
525 if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
527 p = path(*it) / dir / subdir / (
"lib" + file + FULL_PLUGINS_SUFFIX);
528 tryouts.push_back( p.string() );
529 if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
532 tryouts.push_back( p.string() );
533 if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
535 p = path(*it) /
OROCOS_TARGET_NAME / dir / subdir / (
"lib" + file + FULL_PLUGINS_SUFFIX);
536 tryouts.push_back( p.string() );
537 if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
540 if (subdir ==
"types")
545 log(
Debug) <<
"No such "<< kind <<
" found in path: " << name <<
". Tried:"<< endlog();
546 for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it)
547 log(
Debug) << *it << endlog();
552 bool PluginLoader::loadPluginInternal( std::string
const& name, std::string
const& path_list, std::string
const& subdir, std::string
const& kind )
556 if (name !=
"rtt" && loadLibrary(name)) {
557 log(
Warning) <<
"You supplied a filename as first argument to 'loadPlugin(name,path)' or 'loadTypekit(name,path)'."<<nlog();
558 log(
Warning) <<
"Please use 'loadLibrary(filename)' instead since the function you use will only interprete 'name' as a directory name in future releases."<<endlog();
562 if ( isLoadedInternal(name) ) {
563 log(
Debug) <<kind <<
" '"<< name <<
"' already loaded. Not reloading it." <<endlog();
566 log(
Info) << kind <<
" '"<< name <<
"' not loaded before." <<endlog();
569 string paths, trypaths;
570 if (path_list.empty())
571 paths = plugin_path + default_delimiter +
".";
580 vector<string> vpaths = splitPaths(paths);
582 bool path_found =
false;
583 string plugin_dir = name;
586 for(vector<string>::iterator it = vpaths.begin(); it != vpaths.end(); ++it) {
590 if (is_directory( p )) {
592 paths += p.string() + default_delimiter;
594 trypaths += p.string() + default_delimiter;
599 if (is_directory( p )) {
601 paths += p.string() + default_delimiter;
603 trypaths += p.string() + default_delimiter;
609 paths.erase( paths.size() - 1 );
610 return loadPluginsInternal(paths,subdir,kind);
612 log(
Error) <<
"No such "<< kind <<
" found in path: " << name <<
". Looked for these directories: "<< endlog();
613 if ( !paths.empty() )
614 log(
Error) <<
"Exist, but don't contain it: " << paths << endlog();
616 log(
Error) <<
"None of the search paths exist !" << endlog();
617 if ( !trypaths.empty() )
618 log(
Error) <<
"Don't exist: " << trypaths << endlog();
625 return isLoadedInternal(file);
628 bool PluginLoader::isLoadedInternal(
string file)
631 std::vector<LoadedLib>::iterator lib = loadedLibs.begin();
632 while (lib != loadedLibs.end()) {
634 if ( lib->filename == p.filename() || lib->plugname == file || lib->shortname == file ) {
643 bool PluginLoader::loadInProcess(
string file,
string shortname,
string kind,
bool log_error) {
648 if ( isLoadedInternal(shortname) || isLoadedInternal(file) ) {
649 log(
Debug) <<
"plugin '"<< file <<
"' already loaded. Not reloading it." <<endlog() ;
654 if(!isCompatiblePlugin(file))
657 log(
Error) <<
"could not load library '"<< p.string() <<
"': incompatible." <<endlog();
666 log(
Error) <<
"could not load library '"<< p.string() <<
"': "<< e <<endlog();
673 #if BOOST_VERSION >= 104600 674 string libname = p.filename().string();
676 string libname = p.filename();
678 log(
Debug)<<
"Found library "<<libname<<endlog();
679 LoadedLib loading_lib(libname,shortname,handle);
682 std::string(*pluginName)(void) = 0;
683 std::string(*targetName)(void) = 0;
685 if ((error =
dlerror()) == NULL) {
686 string plugname, targetname;
687 pluginName = (std::string(*)(void))(
dlsym(handle,
"getRTTPluginName") );
688 if ((error =
dlerror()) == NULL) {
689 plugname = (*pluginName)();
693 loading_lib.plugname = plugname;
694 targetName = (std::string(*)(void))(
dlsym(handle,
"getRTTTargetName") );
695 if ((error =
dlerror()) == NULL) {
696 targetname = (*targetName)();
701 log(
Error) <<
"Plugin "<< plugname <<
" reports to be compiled for OROCOS_TARGET "<< targetname
702 <<
" while we are running on target "<<
OROCOS_TARGET_NAME <<
". Unloading."<<endlog();
709 if (loading_lib.createService)
710 loading_lib.is_service =
true;
713 bool success =
false;
716 success = (*loading_lib.loadPlugin)( 0 );
717 }
catch(std::exception& e) {
718 log(
Error) <<
"Loading "<< plugname <<
" threw an exception: "<< e.what() << endlog();
720 log(
Error) <<
"Unexpected exception in loadRTTPlugin !"<<endlog();
724 log(
Error) <<
"Failed to load RTT Plugin '" <<plugname<<
"': plugin refused to load into this process. Unloading." <<endlog();
728 if (kind ==
"typekit") {
729 log(
Info) <<
"Loaded RTT TypeKit/Transport '" + plugname +
"' from '" + shortname +
"'"<<endlog();
730 loading_lib.is_typekit =
true;
732 loading_lib.is_typekit =
false;
733 if ( loading_lib.is_service ) {
734 log(
Info) <<
"Loaded RTT Service '" + plugname +
"' from '" + shortname +
"'"<<endlog();
737 log(
Info) <<
"Loaded RTT Plugin '" + plugname +
"' from '" + shortname +
"'"<<endlog();
740 loadedLibs.push_back(loading_lib);
744 log(
Error) <<
"Not a plugin: " << error << endlog();
752 vector<string> names;
753 for(vector<LoadedLib>::const_iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
754 if ( it->is_service )
755 names.push_back( it->plugname );
762 vector<string> names;
763 for(vector<LoadedLib>::const_iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
764 names.push_back( it->plugname );
771 vector<string> names;
772 for(vector<LoadedLib>::const_iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
773 if ( it->is_typekit )
774 names.push_back( it->plugname );
786 plugin_path = newpath;
789 bool PluginLoader::isCompatiblePlugin(std::string
const& filepath)
793 #if BOOST_VERSION >= 104600 794 string libname = p.filename().string();
796 string libname = p.filename();
801 #ifdef OROCOS_TARGET_WIN32 805 if(!hasEnding(libname, FULL_PLUGINS_SUFFIX))
810 #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 ...