4 #include <boost/filesystem.hpp> 5 #include <boost/version.hpp> 31 static const std::string SO_EXT(
".dylib");
32 static const std::string SO_POSTFIX(
"");
35 static const std::string SO_EXT(
".dll");
37 static const std::string SO_POSTFIX(
"d");
39 static const std::string SO_POSTFIX(
"");
42 static const std::string SO_EXT(
".so");
43 static const std::string SO_POSTFIX(
"");
48 static const std::string FULL_COMPONENT_SUFFIX(
string(
"-") +
string(
OROCOS_TARGET_NAME) + SO_POSTFIX + SO_EXT);
52 static const std::string delimiters(
";");
53 static const char default_delimiter(
';');
55 static const std::string delimiters(
":;");
56 static const char default_delimiter(
':');
62 #define RTT_UNUSED __attribute__((unused)) 80 if (!ext.empty() && (
'.' == ext[0]))
82 std::istringstream iss;
85 iss.str(ext.substr((
size_t)1));
86 iss >> std::dec >> std::noskipws >> i;
87 isExtensionVersion = !iss.fail() && iss.eof();
116 bool isLoadable =
false;
118 #if defined(__APPLE__) 120 #if BOOST_VERSION >= 104600 121 ext = filename.extension().string();
123 ext = filename.extension();
126 if (0 == ext.compare(SO_EXT))
131 path name = filename.stem();
132 path ext = name.extension();
146 (filename.extension() == SO_EXT) &&
147 !filename.stem().empty();
156 static vector<string> splitPaths(
string const& str)
158 vector<string> paths;
161 string::size_type lastPos = str.find_first_not_of(delimiters, 0);
163 string::size_type pos = str.find_first_of(delimiters, lastPos);
165 while (string::npos != pos || string::npos != lastPos)
168 if ( !str.substr(lastPos, pos - lastPos).empty() )
169 paths.push_back(str.substr(lastPos, pos - lastPos));
171 lastPos = str.find_first_not_of(delimiters, pos);
173 pos = str.find_first_of(delimiters, lastPos);
176 paths.push_back(
".");
180 static void removeDuplicates(
string& path_list)
182 vector<string> paths;
187 paths = splitPaths( path_list );
190 for(vector<string>::const_iterator it = paths.begin(); it != paths.end(); ++it)
197 result = result + *it + default_delimiter;
201 if (result.size() > 0 && result.at(result.size() - 1) == default_delimiter)
202 result = result.substr(0, result.size() - 1);
204 path_list.swap(result);
213 static string makeShortFilename(
string const& str) {
215 if (str.substr(0,3) ==
"lib")
217 if (ret.rfind(FULL_COMPONENT_SUFFIX) != string::npos)
218 ret = ret.substr(0, ret.rfind(FULL_COMPONENT_SUFFIX) );
224 static RTT_UNUSED bool hasEnding(
string const &fullString,
string const &ending)
226 if (fullString.length() > ending.length()) {
227 return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
245 char* paths = getenv(
"RTT_COMPONENT_PATH");
246 string component_paths;
248 component_paths = paths;
250 if ( !default_comp_path.empty() )
251 component_paths = component_paths + default_delimiter + default_comp_path;
252 removeDuplicates( component_paths );
253 log(
Info) <<
"RTT_COMPONENT_PATH was set to: " << paths <<
" . Searching in: "<< component_paths<< endlog();
255 component_paths = default_comp_path;
256 removeDuplicates( component_paths );
257 log(
Info) <<
"No RTT_COMPONENT_PATH set. Using default: " << component_paths <<endlog();
266 void unloadComponents()
274 static boost::shared_ptr<ComponentLoader> instance2;
292 if (path_list.empty() ) {
293 log(
Error) <<
"import paths: No paths were given for loading ( path_list = '' )."<<endlog();
298 vector<string> paths;
299 paths = splitPaths( path_list );
301 bool all_good =
true, found =
false;
303 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
309 log(
Info) <<
"Importing directory " << p.string() <<
" ..."<<endlog();
310 for (directory_iterator itr(p); itr != directory_iterator(); ++itr)
312 log(
Debug) <<
"Scanning file " << itr->path().string() <<
" ...";
316 #if BOOST_VERSION >= 104600 317 libname = itr->path().filename().string();
319 libname = itr->path().filename();
321 if(!isCompatibleComponent(libname))
323 log(
Debug) <<
"not a compatible component: ignored."<<endlog();
328 all_good = loadInProcess( itr->path().string(), makeShortFilename(libname ),
true) && all_good;
331 if (!is_regular_file(itr->status()))
332 log(
Debug) <<
"not a regular file: ignored."<<endlog();
334 log(
Debug) <<
"not a " + SO_EXT +
" library: ignored."<<endlog();
337 log(
Debug) <<
"Looking for plugins or typekits in directory " << p.string() <<
" ..."<<endlog();
341 }
catch (std::exception& e) {
343 log(
Error) << e.what() <<endlog();
348 log(
Debug) <<
"No such directory: " << p<< endlog();
355 log(
Info) <<
"Importing component libraries from directory " << p.string() <<
" ..."<<endlog();
356 for (directory_iterator itr(p); itr != directory_iterator(); ++itr)
358 log(
Debug) <<
"Scanning file " << itr->path().string() <<
" ...";
361 #if BOOST_VERSION >= 104600 362 all_good = loadInProcess( itr->path().string(), makeShortFilename(itr->path().filename().string() ),
true) && all_good;
364 all_good = loadInProcess( itr->path().string(), makeShortFilename(itr->path().filename() ),
true) && all_good;
367 if (!is_regular_file(itr->status()))
368 log(
Debug) <<
"not a regular file: ignored."<<endlog();
370 log(
Debug) <<
"not a " + SO_EXT +
" library: ignored."<<endlog();
373 log(
Info) <<
"Importing plugins and typekits from directory " << p.string() <<
" ..."<<endlog();
377 }
catch (std::exception& e) {
379 log(
Error) << e.what() <<endlog();
385 throw std::runtime_error(
"Some found plugins could not be loaded !");
398 #if BOOST_VERSION >= 104600 399 return loadInProcess(arg.string(), makeShortFilename( arg.filename().string() ),
true);
401 return loadInProcess(arg.string(), makeShortFilename( arg.filename() ),
true);
406 if ( arg.is_complete() ) {
408 bool ret =
import(package);
416 log(
Error) <<
"Could not import absolute path '"<<
package << "': nothing found."<<endlog();
420 if ( isImported(package) ) {
421 log(
Info) <<
"Component package '"<<
package <<"' already imported." <<endlog();
426 return importInstalledPackage(package, path_list);
429 bool ComponentLoader::importInstalledPackage(std::string
const& package, std::string
const& path_list)
431 RTT::Logger::In in(
"ComponentLoader::importInstalledPackage(package, path_list)");
435 vector<string> tryouts;
436 if (path_list.empty())
437 paths = component_path + default_delimiter +
".";
441 bool path_found =
false;
445 vector<string> vpaths;
446 vpaths = splitPaths(paths);
451 if (is_directory( p )) {
454 paths += p.string() + default_delimiter + (p /
OROCOS_TARGET_NAME).
string() + default_delimiter;
455 if ( p.is_complete() ) {
462 for(vector<string>::iterator it = vpaths.begin(); it != vpaths.end(); ++it) {
466 if (is_directory( p )) {
468 paths += p.string() + default_delimiter ;
470 tryouts.push_back( p.string() );
474 if (is_directory( p )) {
476 paths += p.string() + default_delimiter ;
478 tryouts.push_back( p.string() );
481 paths.erase( paths.size() - 1 );
485 if (
import(paths) ) {
486 loadedPackages.push_back( package );
489 log(
Error) <<
"Failed to import components, types or plugins from package or directory '"<<
package <<"' found in:"<< endlog();
490 log(
Error) << paths << endlog();
494 log(
Error) <<
"No such package or directory found in search path: " <<
package << ". Search path is: " << trypaths << endlog();
495 log(
Error) <<
"Directories searched include the following: " << endlog();
496 for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it)
497 log(
Error) <<
" - " << *it << endlog();
505 #if BOOST_VERSION >= 104600 506 if (is_regular_file( arg ) && reloadInProcess( arg.string(), makeShortFilename( arg.filename().string() ) ) )
508 if (is_regular_file( arg ) && reloadInProcess( arg.string(), makeShortFilename( arg.filename() ) ) )
519 #if BOOST_VERSION >= 104600 520 if (is_regular_file( arg ) && loadInProcess( arg.string(), makeShortFilename( arg.filename().string() ),
true ) )
522 if (is_regular_file( arg ) && loadInProcess( arg.string(), makeShortFilename( arg.filename() ),
true ) )
526 if ( arg.is_complete() )
530 vector<string> paths = splitPaths( component_path );
531 vector<string> tryouts( paths.size() * 4 );
533 path dir = arg.parent_path();
534 #if BOOST_VERSION >= 104600 535 string file = arg.filename().string();
537 string file = arg.filename();
540 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
542 path p = path(*it) / dir / (file + FULL_COMPONENT_SUFFIX);
543 tryouts.push_back( p.string() );
544 if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
546 p = path(*it) / dir / (
"lib" + file + FULL_COMPONENT_SUFFIX);
547 tryouts.push_back( p.string() );
548 if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
551 tryouts.push_back( p.string() );
552 if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
555 tryouts.push_back( p.string() );
556 if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
559 log(
Debug) <<
"No such library found in path: " << name <<
". Tried:"<< endlog();
560 for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it)
561 log(
Debug) << *it << endlog();
569 if (find(loadedPackages.begin(), loadedPackages.end(), type_name) != loadedPackages.end())
579 bool ComponentLoader::reloadInProcess(
string file,
string libname)
587 std::vector<LoadedLib>::iterator lib = loadedLibs.begin();
588 while (lib != loadedLibs.end()) {
590 if ( lib->filename == file) {
591 log(
Info) <<
"Component library "<< lib->filename <<
" already loaded... " ;
593 bool can_unload =
true;
594 CompList::iterator cit;
595 for( std::vector<std::string>::iterator ctype = lib->components_type.begin(); ctype != lib->components_type.end() && can_unload; ++ctype) {
596 for ( cit = comps.begin(); cit != comps.end(); ++cit) {
597 if( (*ctype) == cit->second.type ) {
599 log(
Info) <<
"can NOT reload library because of the instance " << cit->second.type <<
"::"<<cit->first <<endlog();
605 log(
Info) <<
"try to RELOAD"<<endlog();
608 std::vector<LoadedLib>::iterator lib_un = lib;
609 loadedLibs.erase(lib_un);
610 return loadInProcess(file, libname,
true);
617 log(
Error) <<
"Can't reload Component library "<< file <<
" since it was not loaded or is not a component library." <<endlog();
622 bool ComponentLoader::loadInProcess(
string file,
string libname,
bool log_error) {
629 if(!isCompatibleComponent(file))
632 log(
Error) <<
"Could not load library '"<< p.string() <<
"': incompatible." <<endlog();
640 log(
Error) <<
"Could not load library '"<< p.string() <<
"':"<<endlog();
647 log(
Debug)<<
"Succesfully loaded "<<libname<<endlog();
648 LoadedLib loading_lib(file, libname, handle);
653 vector<string> (*getcomponenttypes)(void) = 0;
655 getfactory = (
FactoryMap*(*)(void))(
dlsym(handle,
"getComponentFactoryMap") );
656 if ((error =
dlerror()) == NULL) {
658 fmap = (*getfactory)();
660 log(
Info) <<
"Loaded multi component library '"<< file <<
"'"<<endlog();
661 getcomponenttypes = (vector<string>(*)(void))(
dlsym(handle,
"getComponentTypeNames"));
662 if ((error =
dlerror()) == NULL) {
663 log(
Debug) <<
"Components:";
664 vector<string> ctypes = getcomponenttypes();
665 for (vector<string>::iterator it = ctypes.begin(); it != ctypes.end(); ++it)
666 log(
Debug) <<
" "<< *it;
667 log(
Debug) << endlog();
669 loadedLibs.push_back(loading_lib);
677 std::string(*tname)(void) = 0;
681 if (error) create_error = error;
682 tname = (std::string(*)(void))(
dlsym(handle,
"getComponentType") );
683 string gettype_error;
685 if (error) gettype_error = error;
686 if ( factory && tname ) {
687 std::string cname = (*tname)();
689 log(
Warning) <<
"Component type name "<<cname<<
" already used: overriding."<<endlog();
692 log(
Info) <<
"Loaded component type '"<< cname <<
"'"<<endlog();
693 loading_lib.components_type.push_back( cname );
694 loadedLibs.push_back(loading_lib);
698 if (success)
return true;
700 log(
Error) <<
"Unloading "<< loading_lib.filename <<
": not a valid component library:" <<endlog();
701 if (!create_error.empty())
702 log(
Error) <<
" " << create_error << endlog();
703 if (!gettype_error.empty())
704 log(
Error) <<
" " << gettype_error << endlog();
710 vector<string> names;
711 FactoryMap::iterator it;
713 names.push_back( it->first );
719 string ret = component_path;
721 if ( ret.length() && ret[ ret.length() -1 ] != default_delimiter )
722 ret += default_delimiter;
727 component_path = newpath;
735 log(
Debug) <<
"Trying to create component "<< name <<
" of type "<< type << endlog();
741 log(
Error) <<
"Found empty factory for Component type "<<type<<endlog();
747 log(
Debug) <<
"Found factory for Component type "<<type<<endlog();
749 log(
Error) <<
"Unable to create Orocos Component '"<<type<<
"': unknown component type." <<endlog();
753 comps[name].type = type;
756 comps[name].instance = instance = (*factory)(name);
758 log(
Error) <<
"The constructor of component type "<<type<<
" threw an exception!"<<endlog();
761 if ( instance == 0 ) {
762 log(
Error) <<
"Failed to load component with name "<<name<<
": refused to be created."<<endlog();
770 CompList::iterator it = comps.begin();
771 for(; it != comps.end(); ++it ) {
772 if ( it->second.instance == tc)
break;
775 if ( it != comps.end() ) {
776 delete it->second.instance;
780 log(
Error) <<
"Refusing to unload a component I didn't load myself."<<endlog();
786 vector<string> names( comps.size() );
787 for(map<string,ComponentData>::const_iterator it = comps.begin(); it != comps.end(); ++it)
788 names.push_back( it->first );
792 bool ComponentLoader::isCompatibleComponent(std::string
const& filepath)
796 #if BOOST_VERSION >= 104600 797 string libname = p.filename().string();
799 string libname = p.filename();
808 if(!hasEnding(libname, FULL_COMPONENT_SUFFIX))
static bool hasTypekit(const std::string &typekitname)
Check if a typekit with given name was already imported.
TaskContext *(* ComponentLoaderSignature)(std::string instance_name)
This signature defines how a component can be instantiated.
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
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.
bool isImported(std::string type_name)
Checks if a given Component type, filename or package name has been imported.
RTT_API void * dlsym(void *handle, const char *name)
RTT::TaskContext * loadComponent(std::string const &name, std::string const &type)
Creates a new component an earlier discovered component type.
void addFactory(std::string const &name, ComponentLoaderSignature factory)
Adds a factory to the component factory map.
static RTT_HIDE FactoryMap & Instance()
static boost::shared_ptr< ComponentLoader > Instance()
Create the instance of the ComponentLoader.
RTT_API int dlclose(void *handle)
std::map< std::string, ComponentLoaderSignature > FactoryMap
char const * default_comp_path_build
std::vector< std::string > listComponents() const
Lists all Component created by loadComponent().
Convenient short notation for every sub-namespace of RTT.
std::string getComponentPath() const
Returns the current Component path list.
bool loadLibrary(std::string const &path)
Loads a library as component library.
bool import(std::string const &path_list)
Imports any Component library found in each path in path_list in the current process.
std::vector< std::string > listComponentTypes() const
Lists all Component types discovered by the ComponentLoader.
bool reloadLibrary(std::string const &filepath)
Reloads a component library.
void setComponentPath(std::string const &newpath)
Sets the Component path list.
bool unloadComponent(RTT::TaskContext *tc)
Destroys an earlier created component.
Notify the Logger in which 'module' the message occured.
The TaskContext is the C++ representation of an Orocos component.
static boost::shared_ptr< PluginLoader > Instance()
Create the instance of the PluginLoader.
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
static void Release()
Release the ComponentLoader, erasing all knowledge of loaded libraries.
RTT_API bool isLoadableLibrary(const path &filename)
const FactoryMap & getFactories() const
Returns the factory singleton which creates all types of components for the ComponentLoader.
RTT_API void * dlopen(const char *file, int mode)