Files
ANSCORE/core/ANSLibsLoader/DynLibUtils.cpp

126 lines
5.0 KiB
C++
Raw Normal View History

2026-03-28 16:54:11 +11:00
// ============================================================================
// DynLibUtils.cpp — Shared dynamic library loading utilities
// ============================================================================
#include "DynLibUtils.h"
#ifndef _WIN32
# include <sys/stat.h>
#endif
namespace ANSCENTER {
namespace DynLib {
// ── FileExists ───────────────────────────────────────────────────────────
bool FileExists(const std::string& path)
{
#ifdef _WIN32
DWORD attr = GetFileAttributesA(path.c_str());
return (attr != INVALID_FILE_ATTRIBUTES) &&
!(attr & FILE_ATTRIBUTE_DIRECTORY);
#else
struct stat st {};
return (::stat(path.c_str(), &st) == 0) && S_ISREG(st.st_mode);
#endif
}
// ── JoinPath ─────────────────────────────────────────────────────────────
std::string JoinPath(const std::string& base, const std::string& component)
{
#ifdef _WIN32
const char sep = '\\';
#else
const char sep = '/';
#endif
if (base.empty()) return component;
if (base.back() == sep || base.back() == '/')
return base + component;
return base + sep + component;
}
// ── InjectDllSearchPath ──────────────────────────────────────────────────
void InjectDllSearchPath(const std::string& dir)
{
#ifdef _WIN32
// Safe UTF-8 → wide-string conversion (handles non-ASCII paths correctly)
int wlen = MultiByteToWideChar(CP_UTF8, 0, dir.c_str(), -1, nullptr, 0);
std::wstring wdir(static_cast<size_t>(wlen > 0 ? wlen - 1 : 0), L'\0');
if (wlen > 0)
MultiByteToWideChar(CP_UTF8, 0, dir.c_str(), -1, wdir.data(), wlen);
DLL_DIRECTORY_COOKIE cookie = AddDllDirectory(wdir.c_str());
if (!cookie)
std::cerr << "[DynLib] WARNING: AddDllDirectory failed for: "
<< dir << " (error " << GetLastError() << ")" << std::endl;
char existing_path[32767] = {};
GetEnvironmentVariableA("PATH", existing_path, sizeof(existing_path));
std::string new_path = dir + ";" + existing_path;
if (!SetEnvironmentVariableA("PATH", new_path.c_str()))
std::cerr << "[DynLib] WARNING: SetEnvironmentVariable PATH failed."
<< std::endl;
#else
const char* existing = getenv("LD_LIBRARY_PATH");
std::string new_path = dir +
(existing ? (":" + std::string(existing)) : "");
setenv("LD_LIBRARY_PATH", new_path.c_str(), 1);
#endif
std::cout << "[DynLib] DLL search path injected: " << dir << std::endl;
}
// ── LoadLib ──────────────────────────────────────────────────────────────
LibHandle LoadLib(const std::string& path, bool globalLoad)
{
#ifdef _WIN32
(void)globalLoad;
return LoadLibraryExA(path.c_str(), nullptr,
LOAD_WITH_ALTERED_SEARCH_PATH);
#else
return globalLoad
? ::dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL)
: ::dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
#endif
}
// ── FreeLib ──────────────────────────────────────────────────────────────
void FreeLib(LibHandle h)
{
if (!h) return;
#ifdef _WIN32
::FreeLibrary(h);
#else
::dlclose(h);
#endif
}
// ── GetSymbol ────────────────────────────────────────────────────────────
void* GetSymbol(LibHandle h, const char* sym)
{
if (!h) return nullptr;
#ifdef _WIN32
return reinterpret_cast<void*>(::GetProcAddress(h, sym));
#else
return ::dlsym(h, sym);
#endif
}
// ── FindAndLoad ──────────────────────────────────────────────────────────
LibHandle FindAndLoad(const std::vector<std::string>& candidates,
std::string& loadedPath,
bool verbose,
bool globalLoad)
{
for (const auto& name : candidates) {
LibHandle h = LoadLib(name, globalLoad);
if (h) {
loadedPath = name;
if (verbose)
std::cout << "[DynLib] Loaded: " << name << std::endl;
return h;
}
}
return LIB_INVALID;
}
} // namespace DynLib
} // namespace ANSCENTER