126 lines
5.0 KiB
C++
126 lines
5.0 KiB
C++
// ============================================================================
|
|
// 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
|