#include #include #include #include #include #include namespace fs = std::filesystem; namespace smo { namespace loadable_lib { namespace { std::vector buildSmoLibrarySearchPaths() { std::vector searchPaths = { fs::current_path().string(), fs::path("/proc/self/exe").parent_path().string() }; const auto& options = OptionParser::getOptions(); if (!options.senseApiLibPath.empty()) { searchPaths.insert( searchPaths.begin(), options.senseApiLibPath.begin(), options.senseApiLibPath.end()); } return searchPaths; } void logLibraryNotInSearchPaths( const std::string& libraryPath, const std::vector& searchPaths) { std::cerr << "searchForLibInSmoSearchPaths: library '" << libraryPath << "' isn't in search bespoke search paths: "; for (const auto& path : searchPaths) { std::cerr << path << " "; } std::cerr << std::endl; std::cerr << "Trying to load " << libraryPath << " from system default search paths\n"; } std::unique_ptr tryDlopenPath(const std::string& path) { dlerror(); void* handle = dlopen(path.c_str(), RTLD_LAZY); if (!handle) { return {}; } return std::unique_ptr< void, LoadableLibraryManager::SharedLibraryDeleter>(handle); } } // namespace LoadableLibraryManager::~LoadableLibraryManager() = default; void LoadableLibraryManager::SharedLibraryDeleter::operator()(void* handle) const { if (handle) { dlclose(handle); } } void LoadableLibraryManager::appendLoadedSharedLibrary( const std::shared_ptr& loadedLibrary) { s.rsrc.loadedSharedLibraries.push_back(loadedLibrary); } void LoadableLibraryManager::removeLoadedSharedLibrary( const std::shared_ptr& loadedLibrary) { auto& loadedLibs = s.rsrc.loadedSharedLibraries; auto it = std::find(loadedLibs.begin(), loadedLibs.end(), loadedLibrary); if (it != loadedLibs.end()) { loadedLibs.erase(it); } } std::optional LoadableLibraryManager::searchForLibInSmoSearchPaths( const std::string& libraryPath) const { const std::vector searchPaths = buildSmoLibrarySearchPaths(); for (const auto& path : searchPaths) { fs::path fullPath = fs::path(path) / libraryPath; if (fs::exists(fullPath)) { return fullPath.string(); } } logLibraryNotInSearchPaths(libraryPath, searchPaths); return std::nullopt; } std::shared_ptr LoadableLibraryManager::loadSharedLibrary(const std::string& libraryPath) { const std::optional fullPath = searchForLibInSmoSearchPaths(libraryPath); const std::string resolvedPath = fullPath.value_or(libraryPath); auto dlopenHandle = tryDlopenPath(resolvedPath); if (!dlopenHandle && fullPath.has_value()) { dlopenHandle = tryDlopenPath(libraryPath); } if (!dlopenHandle) { const char* dlerr = dlerror(); const std::string error = (dlerr ? dlerr : "Unknown error while opening shlib"); throw std::runtime_error( std::string("loadSharedLibrary: Cannot load library '") + libraryPath + "': " + error); } auto loadedLibrary = std::make_shared( libraryPath, resolvedPath, std::move(dlopenHandle)); appendLoadedSharedLibrary(loadedLibrary); return loadedLibrary; } void LoadableLibraryManager::unloadSharedLibrary( const std::shared_ptr& loadedLibrary) { if (!loadedLibrary) { return; } removeLoadedSharedLibrary(loadedLibrary); loadedLibrary->dlopenHandle.reset(); } } // namespace loadable_lib } // namespace smo