void PluginManager::loadDynamicPlugins(std::string& plugins_path) { LOG_DEBUG("Loading dynamic plugins"); Poco::Path plugin_directory = Poco::Path::forDirectory(plugins_path); plugin_directory.popDirectory(); plugin_directory.pushDirectory("plugins"); LOG_DEBUG("Plugin directory: " << plugin_directory.toString()); std::set<std::string> dll_files; Poco::Glob::glob(plugin_directory.append(DynamicLibrary::DL_PREFIX+ "*."+ DynamicLibrary::DL_SUFFIX), dll_files); for (std::set<std::string>::iterator it = dll_files.begin(); it!=dll_files.end(); ++it) { std::string plugin_file = *it; LOG_DEBUG("Loading library " << plugin_file); DynamicLibrary* dl = DynamicLibrary::load(plugin_file); registerPluginFunction registerPlugin = (registerPluginFunction)dl->getSymbol("registerPlugin"); if (registerPlugin) { LOG_DEBUG("Initialize Plugin " << *it); registerPlugin(this); } else { LOG_WARN("Couldn't find registerPlugin for " << *it); } } }
Engine::ModuleSpec Engine::createModule(const String& Filename) { try { DynamicLibrary* lib = AURORA_NEW DynamicLibrary(Filename); Module* (*moduleCreateFunc)(); // Ugly, ugly cast moduleCreateFunc = reinterpret_cast<Module*(*)()>(lib->getSymbol("createInstance")); if (moduleCreateFunc) { Module* m = moduleCreateFunc(); if (!m) throw BadModuleException(); else { ModuleSpec spec; spec.Category = m->getCategory(); spec.Name = m->getName(); spec.Lib = lib; spec.Mod = m; spec.SourceFilename = Filename; spec.Installed = false; return spec; } } else throw BadModuleException(); } catch (LibraryCallException&) { // Something's bad in the module, don't rethrow an internal error to the caller throw BadModuleException(); } }
void DynamicLibraryTest::RunTests() { DynamicLibrary * d = NULL; // Try to load "empty" library { string errorString; d = DynamicLibrary::load("", errorString); TEST2("Shouldn't be able to load \"\" library", d == NULL); TEST2("Should have non-empty error string", errorString.size() != 0); } // Try to load non-existent library string s("non_exisiting_file"); Path path(s); TEST2("Make sure file doesn't exist", !path.exists()); { string errorString; d = DynamicLibrary::load(s, errorString); } TEST2("Shouldn't be able to load non-existent library", d == NULL); delete d; // just to satisfy coverity, not really needed, but harmless // Try to load corrupt library (this source file) #ifdef WIN32 s = "lib\\cpp_region.dll"; path = getPath(s); #else s = "share/test/data/fake.dynamic.library"; path = getPath(s); TEST2("Make sure \"corrupt\" file exists", path.exists()); { string errorString; d = DynamicLibrary::load(std::string(path), errorString); } TEST2("Shouldn't be able to load corrupt library", d == NULL); // Load good library (very inelegant way to handle different suffix on mac and linux) s = "lib/libcpp_region.dylib"; path = getPath(s); if (!path.exists()) { s = "lib/libcpp_region.so"; path = getPath(s); } #endif std::cout << "Looking for path '" << path << "'\n"; TEST2("Make sure file exists", path.exists()); { string errorString; d = DynamicLibrary::load(std::string(path), errorString); TEST2("Should be able to load good library", d != NULL); TEST2("Should have empty error string", errorString.empty()); if (!errorString.empty()) { std::cout << "Error String: " << errorString << "\n"; } } if (d) { // Get existing symbol void * sym = d->getSymbol("NTA_initPython"); TEST2("Should be able to get 'NTA_initPython' symbol", sym != NULL); // Get non-existing symbol sym = d->getSymbol("non exisitng symbol"); TEST2("Should NOT be able to get 'non exisitng symbol' symbol", sym == NULL); delete d; } }
SteerLib::ModuleMetaInformation * SimulationEngine::_loadModule(const std::string & moduleName, const std::string & searchPath) { // check that the requested moduleName is not already "blacklisted" as a conflict from some other loaded module. if (_moduleConflicts.find(moduleName) != _moduleConflicts.end()) { std::stringstream conflictingNames; std::multimap<std::string, std::string>::iterator iter; pair< std::multimap<std::string, std::string>::iterator, std::multimap<std::string, std::string>::iterator > bounds; bounds = _moduleConflicts.equal_range(moduleName); for ( iter = bounds.first; iter != bounds.second; ++iter ) { conflictingNames << " " << (*iter).second << "\n"; } throw GenericException("Cannot load module \"" + moduleName + "\", because it conflicts with the following modules:\n" + conflictingNames.str()); } ModuleMetaInformation * newMetaInfo = NULL; std::map<std::string, ModuleMetaInformation*>::iterator iter; // THREE POSSIBLE STATES OF THE MODULE when we are trying to load it: // 1. metaInfo not allocated // 2. metaInfo allocated, but module not loaded // 3. metaInfo allocated and module loaded. iter = _moduleMetaInfoByName.find(moduleName); if (iter == _moduleMetaInfoByName.end()) { // CASE #1: module was not allocated yet. // This is the usual case, and module loading can proceed normally. // action: go ahead and allocate it here, and then finish loading it below. newMetaInfo = new ModuleMetaInformation; newMetaInfo->isLoaded = false; newMetaInfo->isInitialized = false; // note, this syntax inserts the newMetaInfo when it does not already exist (which is the case here). _moduleMetaInfoByName[moduleName] = newMetaInfo; } else { newMetaInfo = ((*iter).second); if (!newMetaInfo->isLoaded) { // CASE #2: module is allocated, not loaded. // That means the module was recursively loading dependencies, and somehow // ended up trying to re-load itself. In other words, it is a cyclic dependency. // action: throw an exception. /// @todo make a more informative error message here. throw GenericException("Detected a cyclic dependency while loading a module. Please examine a stack trace to see more details."); } else { // CASE #4: module is already loaded. // action: just return. return newMetaInfo; } } // at this point we are ready to "load" the module. // "loading" the module means that we can initialize everything in the ModuleMetaInformation struct // and update all the engine's data structures that have knowledge of the module. Essentially, // everything except establishing execution order and calling init(). ModuleInterface * newModule = NULL; DynamicLibrary * newModuleLib = NULL; // first, check if the requested module is built-in, and create it if it was built in. newModule = _createBuiltInModule(moduleName); if (newModule == NULL) { // In this case, the module was not built-in. #ifdef _WIN32 std::string extension = ".dll"; #else std::string extension = ".o"; #endif std::string moduleFileName = searchPath + moduleName + extension; if (!isExistingFile(moduleFileName)) { moduleFileName = _options->engineOptions.moduleSearchPath + moduleName + extension; // if module wasn't found in the searchPath directory, try with the default search path. if (!isExistingFile(moduleFileName)) { moduleFileName = moduleName + extension; // if it still wasnt found, try without the search path if (!isExistingFile(moduleFileName)) { // if it still didn't work, then cause an error. throw GenericException("Could not find the module named \"" + moduleName + "\".\n" + " tried user-specified search path: " + searchPath + moduleName + extension +"\n" + " tried engine's search path: " + _options->engineOptions.moduleSearchPath + moduleName + extension +"\n" + " tried the current directory: " + moduleName + extension +"\n"); } } } // load the dynamic library newModuleLib = new DynamicLibrary(moduleFileName); // get the "createModule" function from the dynamic library typedef ModuleInterface* (*createModuleFuncPtr)(); createModuleFuncPtr createModule = (createModuleFuncPtr) newModuleLib->getSymbol("createModule", true); // create the module itself newModule = createModule(); if (newModule == NULL) { throw GenericException("Could not create module \"" + moduleName + "\", createModule() returned NULL."); } } // the next several chunks of code initialize newMetaInfo: // get the dependencies and conflicts from the module, and parse them. std::istringstream conflicts(newModule->getConflicts()); std::istringstream dependencies(newModule->getDependencies()); std::string token; while (conflicts >> token) { // the token is one of the conflicts declared by the module // make sure it does not yet exist in the set of loaded modules // and add it to the list of conflicting modules if (_moduleMetaInfoByName.find(token) != _moduleMetaInfoByName.end()) { // if the token is found here, that means we have a conflict. throw GenericException("Cannot load module \"" + moduleName + "\", because it conflicts with already loaded module \"" + (*_moduleMetaInfoByName.find(token)).second->moduleName); } newMetaInfo->conflicts.insert(token); _moduleConflicts.insert( std::pair<std::string, std::string>(token , moduleName)); } // initialize the simpler data of meta information here newMetaInfo->moduleName = moduleName; newMetaInfo->module = newModule; newMetaInfo->dll = newModuleLib; // note, this will be NULL for a built-in library. newMetaInfo->isLoaded = true; // at this point, everything in newMetaInfo should be initialized except for: // - isLoaded is still false until we finish loading below // - isInitialized is still false until we call init() later, outside this function // - list of dependencies is not populated until we load the dependencies // - list of modulesDependentOnThis is initialized at this point, but its contents may change, // if other modules are loaded that are dependent on this. // next, add the newMetaInfo and module to the engine's organizational data structures. // _moduleMetaInfoByName is updated earlier // _modulesInExecutionOrder is updated after loading all dependencies, so that execution order is maintained _moduleMetaInfoByReference[newModule] = newMetaInfo; //================ // everything is loaded except for dependencies; recursively load all dependencies here. while (dependencies >> token) { ModuleMetaInformation * dependency = _loadModule(token,searchPath); dependency->modulesDependentOnThis.insert(newMetaInfo); newMetaInfo->dependencies.insert(dependency); } //================ // If an entry in the moduleOptionsDatabase did not yet exist, then create one. // recall that the [] operator for an STL map will create a new entry if one did not exist by that key already, _options->moduleOptionsDatabase[newMetaInfo->moduleName]; //================ // if all went well up to this point, the module and its dependencies is loaded, so add it to the end of the list of modules // (i.e. it executes after all its dependencies) and return! _modulesInExecutionOrder.push_back(newModule); std::cout << "loaded module " << newMetaInfo->moduleName << "\n"; return newMetaInfo; }