Files
salmanoff/smocore/loadableLib/loadableLibraryManager.cpp
T
hayodea 7eda755c15 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>
2026-06-10 21:14:55 -04:00

151 lines
3.6 KiB
C++

#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