diff --git a/src/module/usModuleInitialization.h b/src/module/usModuleInitialization.h index b0df114839..9e0bc294ad 100644 --- a/src/module/usModuleInitialization.h +++ b/src/module/usModuleInitialization.h @@ -1,170 +1,174 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include #include #include #include #include +#include + #ifndef USMODULEINITIALIZATION_H #define USMODULEINITIALIZATION_H /** * \ingroup MicroServices * * \brief Creates initialization code for a module. * * Each module which wants to register itself with the CppMicroServices library * has to put a call to this macro in one of its source files. * * Example call for a module with file-name "libmylibname.so": * \code * US_INITIALIZE_MODULE("My Service Implementation", "mylibname") * \endcode * * This will initialize the module for use with the CppMicroServices library, using a default * auto-load directory named after the provided library name in \c _module_libname. * * \sa MicroServices_AutoLoading * * \remarks If you are using CMake, consider using the provided CMake macro * usFunctionGenerateModuleInit(). * * \param _module_name A human-readable name for the module. * If you use this macro in a source file for an executable, the module name must * be a valid C-identifier (no spaces etc.). * \param _module_libname The physical name of the module, withou prefix or suffix. * * \note If you want to create initialization code for an executable, see * #US_INITIALIZE_EXECUTABLE. */ #define US_INITIALIZE_MODULE(_module_name, _module_libname) \ US_BEGIN_NAMESPACE \ \ /* Declare a file scoped ModuleInfo object */ \ US_GLOBAL_STATIC_WITH_ARGS(ModuleInfo, moduleInfo, (_module_name, _module_libname)) \ \ /* This class is used to statically initialize the library within the C++ Micro services \ library. It looks up a library specific C-style function returning an instance \ of the ModuleActivator interface. */ \ class US_ABI_LOCAL ModuleInitializer { \ \ public: \ \ ModuleInitializer() \ { \ ModuleInfo*(*moduleInfoPtr)() = moduleInfo; \ - std::string location = ModuleUtils::GetLibraryPath(moduleInfo()->libName, \ - *reinterpret_cast(&moduleInfoPtr)); \ + void* moduleInfoSym = NULL; \ + std::memcpy(&moduleInfoSym, &moduleInfoPtr, sizeof(void*)); \ + std::string location = ModuleUtils::GetLibraryPath(moduleInfo()->libName, moduleInfoSym); \ std::string activator_func = "_us_module_activator_instance_"; \ if(moduleInfo()->libName.empty()) \ { \ activator_func.append(moduleInfo()->name); \ } \ else \ { \ activator_func.append(moduleInfo()->libName); \ } \ \ moduleInfo()->location = location; \ \ if (moduleInfo()->libName.empty()) \ { \ /* make sure we retrieve symbols from the executable, if "libName" is empty */ \ location.clear(); \ } \ - *reinterpret_cast(&moduleInfo()->activatorHook) = ModuleUtils::GetSymbol(location, activator_func.c_str()); \ + void* activatorHookSym = ModuleUtils::GetSymbol(location, activator_func.c_str()); \ + std::memcpy(&moduleInfo()->activatorHook, &activatorHookSym, sizeof(void*)); \ \ Register(); \ } \ \ static void Register() \ { \ ModuleRegistry::Register(moduleInfo()); \ } \ \ ~ModuleInitializer() \ { \ ModuleRegistry::UnRegister(moduleInfo()); \ } \ \ }; \ \ US_ABI_LOCAL ModuleContext* GetModuleContext() \ { \ /* make sure the module is registered */ \ if (moduleInfo()->id == 0) \ { \ ModuleInitializer::Register(); \ } \ \ return ModuleRegistry::GetModule(moduleInfo()->id)->GetModuleContext(); \ } \ \ US_END_NAMESPACE \ \ static US_PREPEND_NAMESPACE(ModuleInitializer) _InitializeModule; /** * \ingroup MicroServices * * \brief Creates initialization code for an executable. * * Each executable which wants to register itself with the CppMicroServices library * has to put a call to this macro in one of its source files. This ensures that the * executable will get its own ModuleContext instance and can access the service registry. * * Example call for an executable: * \code * US_INITIALIZE_EXECUTABLE("my_executable") * \endcode * * This will initialize the executable for use with the CppMicroServices library, using a default * auto-load directory named after the provided executable id in \c _executable_id. * * \sa MicroServices_AutoLoading * * \remarks If you are using CMake, consider using the provided CMake macro * usFunctionGenerateExecutableInit(). * * \param _executable_id A valid C identifier for the executable (no spaces etc.). */ #define US_INITIALIZE_EXECUTABLE(_executable_id) \ US_INITIALIZE_MODULE(_executable_id, "") // If the CppMicroServices library was statically build, executables will share the // initialization code with the CppMicroServices library. #ifndef US_BUILD_SHARED_LIBS #undef US_INITIALIZE_EXECUTABLE #define US_INITIALIZE_EXECUTABLE(_a) #endif // Static modules usually don't get initialization code. They are initialized within the // module importing the static module(s). #if defined(US_STATIC_MODULE) && !defined(US_FORCE_MODULE_INIT) #undef US_INITIALIZE_MODULE #define US_INITIALIZE_MODULE(_a,_b) #endif #endif // USMODULEINITIALIZATION_H diff --git a/src/module/usModulePrivate.cpp b/src/module/usModulePrivate.cpp index 6c99393e4a..cee3afcd9a 100644 --- a/src/module/usModulePrivate.cpp +++ b/src/module/usModulePrivate.cpp @@ -1,267 +1,271 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include "usModulePrivate.h" #include "usModule.h" #include "usModuleActivator.h" #include "usModuleUtils_p.h" #include "usModuleResource.h" #include "usModuleResourceStream.h" #include "usCoreModuleContext_p.h" #include "usServiceRegistration.h" #include "usServiceReferenceBasePrivate.h" #include #include #include +#include US_BEGIN_NAMESPACE AtomicInt ModulePrivate::idCounter; ModulePrivate::ModulePrivate(Module* qq, CoreModuleContext* coreCtx, ModuleInfo* info) : coreCtx(coreCtx) , info(*info) , moduleContext(0) , moduleActivator(0) , q(qq) { // Parse the statically imported module library names typedef const char*(*GetImportedModulesFunc)(void); std::string getImportedModulesSymbol("_us_get_imported_modules_for_"); getImportedModulesSymbol += this->info.libName; std::string location = this->info.location; if (this->info.libName.empty()) { /* make sure we retrieve symbols from the executable, if "libName" is empty */ location.clear(); } - GetImportedModulesFunc getImportedModulesFunc = reinterpret_cast( - ModuleUtils::GetSymbol(location, getImportedModulesSymbol.c_str())); + GetImportedModulesFunc getImportedModulesFunc = NULL; + void* getImportedModulesSym = ModuleUtils::GetSymbol(location, getImportedModulesSymbol.c_str()); + std::memcpy(&getImportedModulesFunc, &getImportedModulesSym, sizeof(void*)); if (getImportedModulesFunc != NULL) { std::string importedStaticModuleLibNames = getImportedModulesFunc(); std::istringstream iss(importedStaticModuleLibNames); std::copy(std::istream_iterator(iss), std::istream_iterator(), std::back_inserter >(this->staticModuleLibNames)); } InitializeResources(location); // Check if the module provides a manifest.json file and if yes, parse it. ModuleResource manifestRes; std::map::iterator resourceTreeIter = mapLibNameToResourceTrees.find(this->info.libName); if (resourceTreeIter != mapLibNameToResourceTrees.end() && resourceTreeIter->second->IsValid()) { manifestRes = ModuleResource("/manifest.json", resourceTreeIter->second, resourceTreePtrs); if (manifestRes) { ModuleResourceStream manifestStream(manifestRes); try { moduleManifest.Parse(manifestStream); } catch (const std::exception& e) { US_ERROR << "Parsing of manifest.json for module " << info->location << " failed: " << e.what(); } } } // Check if we got version information and validate the version identifier if (moduleManifest.Contains(Module::PROP_VERSION())) { Any versionAny = moduleManifest.GetValue(Module::PROP_VERSION()); std::string errMsg; if (versionAny.Type() != typeid(std::string)) { errMsg = std::string("The version identifier must be a string"); } try { version = ModuleVersion(versionAny.ToString()); } catch (const std::exception& e) { errMsg = std::string("The version identifier is invalid: ") + e.what(); } if (!errMsg.empty()) { throw std::invalid_argument(std::string("The Json value for ") + Module::PROP_VERSION() + " for module " + info->location + " is not valid: " + errMsg); } } std::stringstream propId; propId << this->info.id; moduleManifest.SetValue(Module::PROP_ID(), propId.str()); moduleManifest.SetValue(Module::PROP_LOCATION(), this->info.location); moduleManifest.SetValue(Module::PROP_NAME(), this->info.name); if (moduleManifest.Contains(Module::PROP_AUTOLOAD_DIR())) { this->info.autoLoadDir = moduleManifest.GetValue(Module::PROP_AUTOLOAD_DIR()).ToString(); } else { // default to the library name or a special name for executables if (!this->info.libName.empty()) { this->info.autoLoadDir = this->info.libName; moduleManifest.SetValue(Module::PROP_AUTOLOAD_DIR(), Any(this->info.autoLoadDir)); } else { this->info.autoLoadDir = "main"; moduleManifest.SetValue(Module::PROP_AUTOLOAD_DIR(), Any(this->info.autoLoadDir)); } } } ModulePrivate::~ModulePrivate() { delete moduleContext; for (std::size_t i = 0; i < this->resourceTreePtrs.size(); ++i) { delete resourceTreePtrs[i]; } } void ModulePrivate::RemoveModuleResources() { coreCtx->listeners.RemoveAllListeners(moduleContext); std::vector srs; coreCtx->services.GetRegisteredByModule(this, srs); for (std::vector::iterator i = srs.begin(); i != srs.end(); ++i) { try { i->Unregister(); } catch (const std::logic_error& /*ignore*/) { // Someone has unregistered the service after stop completed. // This should not occur, but we don't want get stuck in // an illegal state so we catch it. } } srs.clear(); coreCtx->services.GetUsedByModule(q, srs); for (std::vector::const_iterator i = srs.begin(); i != srs.end(); ++i) { i->GetReference(std::string()).d->UngetService(q, false); } for (std::size_t i = 0; i < resourceTreePtrs.size(); ++i) { resourceTreePtrs[i]->Invalidate(); } } void ModulePrivate::StartStaticModules() { std::string location = this->info.location; if (this->info.libName.empty()) { /* make sure we retrieve symbols from the executable, if "libName" is empty */ location.clear(); } for (std::vector::iterator i = staticModuleLibNames.begin(); i != staticModuleLibNames.end(); ++i) { std::string staticActivatorSymbol = "_us_module_activator_instance_"; staticActivatorSymbol += *i; - ModuleInfo::ModuleActivatorHook staticActivator = - reinterpret_cast(ModuleUtils::GetSymbol(location, staticActivatorSymbol.c_str())); + ModuleInfo::ModuleActivatorHook staticActivator = NULL; + void* staticActivatorSym = ModuleUtils::GetSymbol(location, staticActivatorSymbol.c_str()); + std::memcpy(&staticActivator, &staticActivatorSym, sizeof(void*)); if (staticActivator) { US_DEBUG << "Loading static activator " << *i; staticActivators.push_back(staticActivator); staticActivator()->Load(moduleContext); } else { US_DEBUG << "Could not find an activator for the static module " << (*i) << ". It propably does not provide an activator on purpose.\n Or you either " "forgot a US_IMPORT_MODULE macro call in " << info.libName << " or to link " << (*i) << " to " << info.libName << "."; } } } void ModulePrivate::StopStaticModules() { for (std::list::iterator i = staticActivators.begin(); i != staticActivators.end(); ++i) { (*i)()->Unload(moduleContext); } } void ModulePrivate::InitializeResources(const std::string& location) { // Get the resource data from static modules and this module std::vector moduleLibNames; moduleLibNames.push_back(this->info.libName); moduleLibNames.insert(moduleLibNames.end(), this->staticModuleLibNames.begin(), this->staticModuleLibNames.end()); std::string initResourcesSymbolPrefix = "_us_init_resources_"; for (std::size_t i = 0; i < moduleLibNames.size(); ++i) { std::string initResourcesSymbol = initResourcesSymbolPrefix + moduleLibNames[i]; - ModuleInfo::InitResourcesHook initResourcesFunc = reinterpret_cast( - ModuleUtils::GetSymbol(location, initResourcesSymbol.c_str())); + ModuleInfo::InitResourcesHook initResourcesFunc = NULL; + void* initResourcesSym = ModuleUtils::GetSymbol(location, initResourcesSymbol.c_str()); + std::memcpy(&initResourcesFunc, &initResourcesSym, sizeof(void*)); if (initResourcesFunc) { initResourcesFunc(&this->info); } } // Initialize this modules resource trees assert(this->info.resourceData.size() == this->info.resourceNames.size()); assert(this->info.resourceNames.size() == this->info.resourceTree.size()); for (std::size_t i = 0; i < this->info.resourceData.size(); ++i) { resourceTreePtrs.push_back(new ModuleResourceTree(this->info.resourceTree[i], this->info.resourceNames[i], this->info.resourceData[i])); mapLibNameToResourceTrees[moduleLibNames[i]] = resourceTreePtrs.back(); } } US_END_NAMESPACE