diff --git a/rtt/Component.hpp b/rtt/Component.hpp index 5acaff1f3..6a0387d55 100644 --- a/rtt/Component.hpp +++ b/rtt/Component.hpp @@ -53,54 +53,7 @@ #include "rtt-fwd.hpp" #include "rtt-config.h" -namespace RTT -{ - /** - * This signature defines how a component can be instantiated. - */ - typedef TaskContext* (*ComponentLoaderSignature)(std::string instance_name); - typedef std::map FactoryMap; - - /** - * A global variable storing all component factories added with - * \a ORO_LIST_COMPONENT_TYPE. - * This factory needs to be present in both static and dynamic library - * deployments. - */ - class ComponentFactories - { - /** - * When static linking is used, the Component library loaders can be - * found in this map. - */ - RTT_HIDE static FactoryMap* Factories; - public: - RTT_HIDE static FactoryMap& Instance() { - if ( Factories == 0) - Factories = new FactoryMap(); - return *Factories; - } - }; - - /** - * A helper class storing a single component factory - * in case of static library deployments. - */ - template - class ComponentFactoryLoader - { - public: - ComponentFactoryLoader(std::string type_name) - { - ComponentFactories::Instance()[type_name] = &ComponentFactoryLoader::createComponent; - } - - static TaskContext* createComponent(std::string instance_name) - { - return new C(instance_name); - } - }; -} +#include // Helper macros. #define ORO_CONCAT_LINE2(x,y) x##y @@ -110,6 +63,35 @@ namespace RTT #define ORO_LIST_COMPONENT_TYPE_str(s) ORO_LIST_COMPONENT_TYPE__str(s) #define ORO_LIST_COMPONENT_TYPE__str(s) #s +#if defined(__GNUC__) + #define ORO_PP_PRAGMA(x) _Pragma(#x) + #define ORO_PP_WARNING(text) ORO_PP_PRAGMA(GCC warning text) + #define ORO_PP_ERROR(text) ORO_PP_PRAGMA(GCC error text) +#else + #define ORO_PP_WARNING(text) + #define ORO_PP_ERROR(text) +#endif + +/** + * Use this macro to register multiple components in a shared library (plug-in). + * For each component, add this line in the .cpp file. Use this macro in combination with + * ORO_CREATE_COMPONENT_LIBRARY. + * + * The advantage of this approach is that one library can create different component + * \a types and that you may link multiple component libraries with each other. + * + * This macro can be used for both shared and static libraries. In case of a shared library, + * the component factory will be registered to the shared library's local FactoryMap. In case + * of a static library, the component factory will be registered in the static library's global + * FactoryMap. In both cases, the DeploymentComponent can access these factories and + * create the registered component types. + * + * @param CLASS_NAME the class name of the component you are adding to the library. + */ + +#define ORO_LIST_COMPONENT_TYPE(CLASS_NAME) namespace { namespace ORO_CONCAT_LINE(LOADER_) { RTT::ComponentFactoryLoader m_cloader(ORO_LIST_COMPONENT_TYPE_str(CLASS_NAME)); } } + + // ORO_CREATE_COMPONENT and ORO_CREATE_COMPONENT_LIBRARY are only used in shared libraries. #if defined(OCL_DLL_EXPORT) || defined (RTT_COMPONENT) @@ -121,36 +103,6 @@ namespace RTT #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #endif -/** - * Use this macro to register a single component in a shared library (plug-in). - * You can only use this macro \b once in a .cpp file for the whole shared library \b and - * you may \b not link with another component library when using this macro. Use - * ORO_CREATE_COMPONENT_LIBRARY if you are in that situation. - * - * It adds a function 'createComponent', which will return a new instance of - * the library's component type and a function 'getComponentType', which returns - * the type (namespace::class) name of the component. - * - * The advantage of this approach is that the user does not need to know the - * class name of the component, he just needs to locate the shared library itself. - * The disadvantage is that only one component \a type per shared library can be created. - * - * @param CNAME the class name of the component you are adding to the library. - */ -#define ORO_CREATE_COMPONENT(CNAME) \ -extern "C" { \ - RTT_EXPORT RTT::TaskContext* createComponent(std::string instance_name); \ - RTT::TaskContext* createComponent(std::string instance_name) \ - { \ - return new CNAME(instance_name); \ - } \ - RTT_EXPORT std::string getComponentType(); \ - std::string getComponentType() \ - { \ - return ORO_LIST_COMPONENT_TYPE_str(CNAME); \ - } \ -} /* extern "C" */ - /** * Use this macro to create a component library which contains all components listed with * ORO_LIST_COMPONENT_TYPE. @@ -179,10 +131,31 @@ extern "C" { \ RTT_EXPORT RTT::FactoryMap* getComponentFactoryMap() { return &RTT::ComponentFactories::Instance(); } \ } /* extern "C" */ + +/** + * Use this macro to register a single component in a shared library (plug-in). + * You can only use this macro \b once in a .cpp file for the whole shared library \b and + * you may \b not link with another component library when using this macro. Use + * ORO_CREATE_COMPONENT_LIBRARY if you are in that situation. + * + * It adds a function 'createComponent', which will return a new instance of + * the library's component type and a function 'getComponentType', which returns + * the type (namespace::class) name of the component. + * + * The advantage of this approach is that the user does not need to know the + * class name of the component, he just needs to locate the shared library itself. + * The disadvantage is that only one component \a type per shared library can be created. + * + * @param CNAME the class name of the component you are adding to the library. + */ +#define ORO_CREATE_COMPONENT(CNAME) \ +ORO_LIST_COMPONENT_TYPE(CNAME) \ +ORO_CREATE_COMPONENT_LIBRARY() + #else #if !defined(OCL_STATIC) && !defined(RTT_STATIC) && !defined(RTT_DLL_EXPORT) -#warning "You're compiling with static library settings. The resulting component library \ +#error "You're compiling with static library settings. The resulting component library \ will not be loadable at runtime with the deployer.\ Compile with -DRTT_COMPONENT to enable dynamic loadable components, \ or use -DRTT_STATIC to suppress this warning." @@ -190,34 +163,17 @@ extern "C" { \ // Static OCL library: // Identical to ORO_LIST_COMPONENT_TYPE: -#define ORO_CREATE_COMPONENT(CLASS_NAME) namespace { namespace ORO_CONCAT_LINE(LOADER_) { RTT::ComponentFactoryLoader m_cloader(ORO_LIST_COMPONENT_TYPE_str(CLASS_NAME)); } } +#define ORO_CREATE_COMPONENT(CLASS_NAME) ORO_LIST_COMPONENT_TYPE(CLASS_NAME) #define ORO_CREATE_COMPONENT_LIBRARY() __attribute__((weak)) RTT::FactoryMap* RTT::ComponentFactories::Factories = 0; #endif -/** - * Use this macro to register multiple components in a shared library (plug-in). - * For each component, add this line in the .cpp file. Use this macro in combination with - * ORO_CREATE_COMPONENT_LIBRARY. - * - * The advantage of this approach is that one library can create different component - * \a types and that you may link multiple component libraries with each other. - * - * This macro can be used for both shared and static libraries. In case of a shared library, - * the component factory will be registered to the shared library's local FactoryMap. In case - * of a static library, the component factory will be registered in the static library's global - * FactoryMap. In both cases, the DeploymentComponent can access these factories and - * create the registered component types. - * - * @param CLASS_NAME the class name of the component you are adding to the library. - */ - -#define ORO_LIST_COMPONENT_TYPE(CLASS_NAME) namespace { namespace ORO_CONCAT_LINE(LOADER_) { RTT::ComponentFactoryLoader m_cloader(ORO_LIST_COMPONENT_TYPE_str(CLASS_NAME)); } } - /** * Backwards compatibility macro which is now replaced by ORO_CREATE_COMPONENT_LIBRARY( ) */ -#define ORO_CREATE_COMPONENT_TYPE( ) ORO_CREATE_COMPONENT_LIBRARY( ) +#define ORO_CREATE_COMPONENT_TYPE( ) \ + ORO_PP_WARNING("ORO_CREATE_COMPONENT_TYPE() is deprecated. Please use ORO_CREATE_COMPONENT_LIBRARY() instead.") \ + ORO_CREATE_COMPONENT_LIBRARY( ) #endif diff --git a/rtt/deployment/ComponentLoader.cpp b/rtt/deployment/ComponentLoader.cpp index d7e1e6215..2c6921cb1 100644 --- a/rtt/deployment/ComponentLoader.cpp +++ b/rtt/deployment/ComponentLoader.cpp @@ -629,7 +629,7 @@ bool ComponentLoader::loadInProcess(string file, string libname, bool log_error) return false; } - handle = dlopen ( p.string().c_str(), RTLD_NOW); + handle = dlopen ( p.string().c_str(), RTLD_NOW | RTLD_GLOBAL ); if (!handle) { if ( log_error ) { @@ -652,8 +652,15 @@ bool ComponentLoader::loadInProcess(string file, string libname, bool log_error) if ((error = dlerror()) == NULL) { // symbol found, register factories... fmap = (*getfactory)(); - ComponentFactories::Instance().insert( fmap->begin(), fmap->end() ); - log(Info) << "Loaded multi component library '"<< file <<"'"<begin(); it != fmap->end(); ++it ) { + if ( ComponentFactories::Instance().count(it->first) == 1 ) { + log(Warning) << "Component type name " << it->first << " already used: overriding." << endlog(); + } + ComponentFactories::Instance().insert(*it); + log(Info) << "Loaded component type '" << it->first << "'" << endlog(); + loading_lib.components_type.push_back( it->first ); + } + log(Info) << "Loaded component library '"<< file <<"'"<(*)(void))(dlsym(handle, "getComponentTypeNames")); if ((error = dlerror()) == NULL) { log(Debug) << "Components:"; @@ -666,7 +673,9 @@ bool ComponentLoader::loadInProcess(string file, string libname, bool log_error) success = true; } - // Lookup createComponent (single component case): + if (success) return true; + + // Lookup deprecated createComponent (single component case): dlerror(); /* Clear any existing error */ RTT::TaskContext* (*factory)(std::string) = 0; @@ -680,6 +689,8 @@ bool ComponentLoader::loadInProcess(string file, string libname, bool log_error) error = dlerror(); if (error) gettype_error = error; if ( factory && tname ) { + log(Warning) << "Component library '" << libname << "' is a deprecated single component library. " + "Consider to rebuild it with the latest version of RTT or it might break in the future." << endlog(); std::string cname = (*tname)(); if ( ComponentFactories::Instance().count(cname) == 1 ) { log(Warning) << "Component type name "< #include #include -#include +#include namespace RTT { + + /** + * This signature defines how a component can be instantiated. + */ + typedef TaskContext* (*ComponentLoaderSignature)(std::string instance_name); + typedef std::map FactoryMap; + + /** + * A global variable storing all component factories added with + * \a ORO_LIST_COMPONENT_TYPE. + * This factory needs to be present in both static and dynamic library + * deployments. + */ + class ComponentFactories + { + /** + * When static linking is used, the Component library loaders can be + * found in this map. + */ + RTT_HIDE static FactoryMap* Factories; + public: + RTT_HIDE static FactoryMap& Instance() { + if ( Factories == 0) + Factories = new FactoryMap(); + return *Factories; + } + }; + + /** + * A helper class storing a single component factory + * in case of static library deployments. + */ + template + class ComponentFactoryLoader + { + public: + ComponentFactoryLoader(std::string type_name) + { + ComponentFactories::Instance()[type_name] = &ComponentFactoryLoader::createComponent; + } + + static TaskContext* createComponent(std::string instance_name) + { + return new C(instance_name); + } + }; + /** * Locates Component libraries found on the filesystem and keeps track of loaded Components. * In case a no components of a component library are running, the library can be unloaded.