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(
':');
71 if (!ext.empty() && (
'.' == ext[0]))
73 std::istringstream iss;
76 iss.str(ext.substr((
size_t)1));
77 iss >> std::dec >> std::noskipws >> i;
78 isExtensionVersion = !iss.fail() && iss.eof();
107 bool isLoadable =
false;
109 #if defined(__APPLE__) 111 #if BOOST_VERSION >= 104600 112 ext = filename.extension().string();
114 ext = filename.extension();
117 if (0 == ext.compare(SO_EXT))
122 path name = filename.stem();
123 path ext = name.extension();
137 (filename.extension() == SO_EXT) &&
138 !filename.stem().empty();
147 static vector<string> splitPaths(
string const& str)
149 vector<string> paths;
152 string::size_type lastPos = str.find_first_not_of(delimiters, 0);
154 string::size_type pos = str.find_first_of(delimiters, lastPos);
156 while (string::npos != pos || string::npos != lastPos)
159 if ( !str.substr(lastPos, pos - lastPos).empty() )
160 paths.push_back(str.substr(lastPos, pos - lastPos));
162 lastPos = str.find_first_not_of(delimiters, pos);
164 pos = str.find_first_of(delimiters, lastPos);
167 paths.push_back(
".");
171 static void removeDuplicates(
string& path_list)
173 vector<string> paths;
178 paths = splitPaths( path_list );
181 for(vector<string>::const_iterator it = paths.begin(); it != paths.end(); ++it)
188 result = result + *it + default_delimiter;
192 if (result.size() > 0 && result.at(result.size() - 1) == default_delimiter)
193 result = result.substr(0, result.size() - 1);
195 path_list.swap(result);
204 static string makeShortFilename(
string const& str) {
206 if (str.substr(0,3) ==
"lib")
208 if (ret.rfind(FULL_COMPONENT_SUFFIX) != string::npos)
209 ret = ret.substr(0, ret.rfind(FULL_COMPONENT_SUFFIX) );
215 static RTT_UNUSED bool hasEnding(
string const &fullString,
string const &ending)
217 if (fullString.length() > ending.length()) {
218 return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
236 char* paths = getenv(
"RTT_COMPONENT_PATH");
237 string component_paths;
239 component_paths = paths;
241 if ( !default_comp_path.empty() )
242 component_paths = component_paths + default_delimiter + default_comp_path;
243 removeDuplicates( component_paths );
244 log(
Info) <<
"RTT_COMPONENT_PATH was set to: " << paths <<
" . Searching in: "<< component_paths<< endlog();
246 component_paths = default_comp_path;
247 removeDuplicates( component_paths );
248 log(
Info) <<
"No RTT_COMPONENT_PATH set. Using default: " << component_paths <<endlog();
257 void unloadComponents()
265 static boost::shared_ptr<ComponentLoader> instance2;
283 if (path_list.empty() ) {
284 log(
Error) <<
"import paths: No paths were given for loading ( path_list = '' )."<<endlog();
289 vector<string> paths;
290 paths = splitPaths( path_list );
292 bool all_good =
true, found =
false;
294 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
300 log(
Info) <<
"Importing directory " << p.string() <<
" ..."<<endlog();
301 for (directory_iterator itr(p); itr != directory_iterator(); ++itr)
303 log(
Debug) <<
"Scanning file " << itr->path().string() <<
" ...";
307 #if BOOST_VERSION >= 104600 308 libname = itr->path().filename().string();
310 libname = itr->path().filename();
312 if(!isCompatibleComponent(libname))
314 log(
Debug) <<
"not a compatible component: ignored."<<endlog();
319 all_good = loadInProcess( itr->path().string(), makeShortFilename(libname ),
true) && all_good;
322 if (!is_regular_file(itr->status()))
323 log(
Debug) <<
"not a regular file: ignored."<<endlog();
325 log(
Debug) <<
"not a " + SO_EXT +
" library: ignored."<<endlog();
328 log(
Debug) <<
"Looking for plugins or typekits in directory " << p.string() <<
" ..."<<endlog();
332 }
catch (std::exception& e) {
334 log(
Error) << e.what() <<endlog();
339 log(
Debug) <<
"No such directory: " << p<< endlog();
346 log(
Info) <<
"Importing component libraries from directory " << p.string() <<
" ..."<<endlog();
347 for (directory_iterator itr(p); itr != directory_iterator(); ++itr)
349 log(
Debug) <<
"Scanning file " << itr->path().string() <<
" ...";
352 #if BOOST_VERSION >= 104600 353 all_good = loadInProcess( itr->path().string(), makeShortFilename(itr->path().filename().string() ),
true) && all_good;
355 all_good = loadInProcess( itr->path().string(), makeShortFilename(itr->path().filename() ),
true) && all_good;
358 if (!is_regular_file(itr->status()))
359 log(
Debug) <<
"not a regular file: ignored."<<endlog();
361 log(
Debug) <<
"not a " + SO_EXT +
" library: ignored."<<endlog();
364 log(
Info) <<
"Importing plugins and typekits from directory " << p.string() <<
" ..."<<endlog();
368 }
catch (std::exception& e) {
370 log(
Error) << e.what() <<endlog();
376 throw std::runtime_error(
"Some found plugins could not be loaded !");
389 #if BOOST_VERSION >= 104600 390 return loadInProcess(arg.string(), makeShortFilename( arg.filename().string() ),
true);
392 return loadInProcess(arg.string(), makeShortFilename( arg.filename() ),
true);
397 if ( arg.is_complete() ) {
399 bool ret =
import(package);
407 log(
Error) <<
"Could not import absolute path '"<<
package << "': nothing found."<<endlog();
411 if ( isImported(package) ) {
412 log(
Info) <<
"Component package '"<<
package <<"' already imported." <<endlog();
417 return importInstalledPackage(package, path_list);
420 bool ComponentLoader::importInstalledPackage(std::string
const& package, std::string
const& path_list)
422 RTT::Logger::In in(
"ComponentLoader::importInstalledPackage(package, path_list)");
426 vector<string> tryouts;
427 if (path_list.empty())
428 paths = component_path + default_delimiter +
".";
432 bool path_found =
false;
436 vector<string> vpaths;
437 vpaths = splitPaths(paths);
442 if (is_directory( p )) {
445 paths += p.string() + default_delimiter + (p /
OROCOS_TARGET_NAME).
string() + default_delimiter;
446 if ( p.is_complete() ) {
453 for(vector<string>::iterator it = vpaths.begin(); it != vpaths.end(); ++it) {
457 if (is_directory( p )) {
459 paths += p.string() + default_delimiter ;
461 tryouts.push_back( p.string() );
465 if (is_directory( p )) {
467 paths += p.string() + default_delimiter ;
469 tryouts.push_back( p.string() );
472 paths.erase( paths.size() - 1 );
476 if (
import(paths) ) {
477 loadedPackages.push_back( package );
480 log(
Error) <<
"Failed to import components, types or plugins from package or directory '"<<
package <<"' found in:"<< endlog();
481 log(
Error) << paths << endlog();
485 log(
Error) <<
"No such package or directory found in search path: " <<
package << ". Search path is: " << trypaths << endlog();
486 log(
Error) <<
"Directories searched include the following: " << endlog();
487 for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it)
488 log(
Error) <<
" - " << *it << endlog();
496 #if BOOST_VERSION >= 104600 497 if (is_regular_file( arg ) && reloadInProcess( arg.string(), makeShortFilename( arg.filename().string() ) ) )
499 if (is_regular_file( arg ) && reloadInProcess( arg.string(), makeShortFilename( arg.filename() ) ) )
510 #if BOOST_VERSION >= 104600 511 if (is_regular_file( arg ) && loadInProcess( arg.string(), makeShortFilename( arg.filename().string() ),
true ) )
513 if (is_regular_file( arg ) && loadInProcess( arg.string(), makeShortFilename( arg.filename() ),
true ) )
517 if ( arg.is_complete() )
521 vector<string> paths = splitPaths( component_path );
522 vector<string> tryouts( paths.size() * 4 );
524 path dir = arg.parent_path();
525 #if BOOST_VERSION >= 104600 526 string file = arg.filename().string();
528 string file = arg.filename();
531 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
533 path p = path(*it) / dir / (file + FULL_COMPONENT_SUFFIX);
534 tryouts.push_back( p.string() );
535 if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
537 p = path(*it) / dir / (
"lib" + file + FULL_COMPONENT_SUFFIX);
538 tryouts.push_back( p.string() );
539 if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
542 tryouts.push_back( p.string() );
543 if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
546 tryouts.push_back( p.string() );
547 if (is_regular_file( p ) && loadInProcess( p.string(), makeShortFilename(file), true ) )
550 log(
Debug) <<
"No such library found in path: " << name <<
". Tried:"<< endlog();
551 for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it)
552 log(
Debug) << *it << endlog();
560 if (find(loadedPackages.begin(), loadedPackages.end(), type_name) != loadedPackages.end())
570 bool ComponentLoader::reloadInProcess(
string file,
string libname)
578 std::vector<LoadedLib>::iterator lib = loadedLibs.begin();
579 while (lib != loadedLibs.end()) {
581 if ( lib->filename == file) {
582 log(
Info) <<
"Component library "<< lib->filename <<
" already loaded... " ;
584 bool can_unload =
true;
585 CompList::iterator cit;
586 for( std::vector<std::string>::iterator ctype = lib->components_type.begin(); ctype != lib->components_type.end() && can_unload; ++ctype) {
587 for ( cit = comps.begin(); cit != comps.end(); ++cit) {
588 if( (*ctype) == cit->second.type ) {
590 log(
Info) <<
"can NOT reload library because of the instance " << cit->second.type <<
"::"<<cit->first <<endlog();
596 log(
Info) <<
"try to RELOAD"<<endlog();
599 std::vector<LoadedLib>::iterator lib_un = lib;
600 loadedLibs.erase(lib_un);
601 return loadInProcess(file, libname,
true);
608 log(
Error) <<
"Can't reload Component library "<< file <<
" since it was not loaded or is not a component library." <<endlog();
613 bool ComponentLoader::loadInProcess(
string file,
string libname,
bool log_error) {
620 if(!isCompatibleComponent(file))
623 log(
Error) <<
"Could not load library '"<< p.string() <<
"': incompatible." <<endlog();
631 log(
Error) <<
"Could not load library '"<< p.string() <<
"':"<<endlog();
638 log(
Debug)<<
"Succesfully loaded "<<libname<<endlog();
639 LoadedLib loading_lib(file, libname, handle);
644 vector<string> (*getcomponenttypes)(void) = 0;
646 getfactory = (
FactoryMap*(*)(void))(
dlsym(handle,
"getComponentFactoryMap") );
647 if ((error =
dlerror()) == NULL) {
649 fmap = (*getfactory)();
651 log(
Info) <<
"Loaded multi component library '"<< file <<
"'"<<endlog();
652 getcomponenttypes = (vector<string>(*)(void))(
dlsym(handle,
"getComponentTypeNames"));
653 if ((error =
dlerror()) == NULL) {
654 log(
Debug) <<
"Components:";
655 vector<string> ctypes = getcomponenttypes();
656 for (vector<string>::iterator it = ctypes.begin(); it != ctypes.end(); ++it)
657 log(
Debug) <<
" "<< *it;
658 log(
Debug) << endlog();
660 loadedLibs.push_back(loading_lib);
668 std::string(*tname)(void) = 0;
672 if (error) create_error = error;
673 tname = (std::string(*)(void))(
dlsym(handle,
"getComponentType") );
674 string gettype_error;
676 if (error) gettype_error = error;
677 if ( factory && tname ) {
678 std::string cname = (*tname)();
680 log(
Warning) <<
"Component type name "<<cname<<
" already used: overriding."<<endlog();
683 log(
Info) <<
"Loaded component type '"<< cname <<
"'"<<endlog();
684 loading_lib.components_type.push_back( cname );
685 loadedLibs.push_back(loading_lib);
689 if (success)
return true;
691 log(
Error) <<
"Unloading "<< loading_lib.filename <<
": not a valid component library:" <<endlog();
692 if (!create_error.empty())
693 log(
Error) <<
" " << create_error << endlog();
694 if (!gettype_error.empty())
695 log(
Error) <<
" " << gettype_error << endlog();
701 vector<string> names;
702 FactoryMap::iterator it;
704 names.push_back( it->first );
710 string ret = component_path;
712 if ( ret.length() && ret[ ret.length() -1 ] != default_delimiter )
713 ret += default_delimiter;
718 component_path = newpath;
726 log(
Debug) <<
"Trying to create component "<< name <<
" of type "<< type << endlog();
732 log(
Error) <<
"Found empty factory for Component type "<<type<<endlog();
738 log(
Debug) <<
"Found factory for Component type "<<type<<endlog();
740 log(
Error) <<
"Unable to create Orocos Component '"<<type<<
"': unknown component type." <<endlog();
744 comps[name].type = type;
747 comps[name].instance = instance = (*factory)(name);
749 log(
Error) <<
"The constructor of component type "<<type<<
" threw an exception!"<<endlog();
752 if ( instance == 0 ) {
753 log(
Error) <<
"Failed to load component with name "<<name<<
": refused to be created."<<endlog();
761 CompList::iterator it = comps.begin();
762 for(; it != comps.end(); ++it ) {
763 if ( it->second.instance == tc)
break;
766 if ( it != comps.end() ) {
767 delete it->second.instance;
771 log(
Error) <<
"Refusing to unload a component I didn't load myself."<<endlog();
777 vector<string> names( comps.size() );
778 for(map<string,ComponentData>::const_iterator it = comps.begin(); it != comps.end(); ++it)
779 names.push_back( it->first );
783 bool ComponentLoader::isCompatibleComponent(std::string
const& filepath)
787 #if BOOST_VERSION >= 104600 788 string libname = p.filename().string();
790 string libname = p.filename();
799 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)