Add LoadableLibraryManager and refactor StimBuffApiManager to use it.
Centralize dlopen/search in LoadableLibraryManager so typed library managers can share one loaded-shlib registry without duplicating load/unload logic. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <loadableLib/loadableLibraryManager.h>
|
||||
#include <opts.h>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace smo {
|
||||
namespace loadable_lib {
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<std::string> buildSmoLibrarySearchPaths()
|
||||
{
|
||||
std::vector<std::string> 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<std::string>& 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<void, LoadableLibraryManager::SharedLibraryDeleter>
|
||||
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<LoadedSharedLibrary>& loadedLibrary)
|
||||
{
|
||||
s.rsrc.loadedSharedLibraries.push_back(loadedLibrary);
|
||||
}
|
||||
|
||||
void LoadableLibraryManager::removeLoadedSharedLibrary(
|
||||
const std::shared_ptr<LoadedSharedLibrary>& loadedLibrary)
|
||||
{
|
||||
auto& loadedLibs = s.rsrc.loadedSharedLibraries;
|
||||
auto it = std::find(loadedLibs.begin(), loadedLibs.end(), loadedLibrary);
|
||||
if (it != loadedLibs.end()) {
|
||||
loadedLibs.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> LoadableLibraryManager::searchForLibInSmoSearchPaths(
|
||||
const std::string& libraryPath) const
|
||||
{
|
||||
const std::vector<std::string> 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::LoadedSharedLibrary>
|
||||
LoadableLibraryManager::loadSharedLibrary(const std::string& libraryPath)
|
||||
{
|
||||
const std::optional<std::string> 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<LoadedSharedLibrary>(
|
||||
libraryPath,
|
||||
resolvedPath,
|
||||
std::move(dlopenHandle));
|
||||
|
||||
appendLoadedSharedLibrary(loadedLibrary);
|
||||
return loadedLibrary;
|
||||
}
|
||||
|
||||
void LoadableLibraryManager::unloadSharedLibrary(
|
||||
const std::shared_ptr<LoadedSharedLibrary>& loadedLibrary)
|
||||
{
|
||||
if (!loadedLibrary) {
|
||||
return;
|
||||
}
|
||||
|
||||
removeLoadedSharedLibrary(loadedLibrary);
|
||||
loadedLibrary->dlopenHandle.reset();
|
||||
}
|
||||
|
||||
} // namespace loadable_lib
|
||||
} // namespace smo
|
||||
Reference in New Issue
Block a user