mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-08-05 10:03:23 +00:00
backend: support non-ASCII characters in path to llmodel libs on Windows (#2388)
* backend: refactor dlhandle.h into oscompat.{cpp,h} Signed-off-by: Jared Van Bortel <jared@nomic.ai> * llmodel: alias std::filesystem Signed-off-by: Jared Van Bortel <jared@nomic.ai> * llmodel: use wide strings for paths on Windows Using the native path representation allows us to manipulate paths and call LoadLibraryEx without mangling non-ASCII characters. Signed-off-by: Jared Van Bortel <jared@nomic.ai> * llmodel: prefer built-in std::filesystem functionality Signed-off-by: Jared Van Bortel <jared@nomic.ai> * oscompat: fix string type error Signed-off-by: Jared Van Bortel <jared@nomic.ai> * backend: rename oscompat back to dlhandle Signed-off-by: Jared Van Bortel <jared@nomic.ai> * dlhandle: fix #includes Signed-off-by: Jared Van Bortel <jared@nomic.ai> * dlhandle: remove another #include Signed-off-by: Jared Van Bortel <jared@nomic.ai> * dlhandle: move dlhandle #include Signed-off-by: Jared Van Bortel <jared@nomic.ai> * dlhandle: remove #includes that are covered by dlhandle.h Signed-off-by: Jared Van Bortel <jared@nomic.ai> * llmodel: fix #include order Signed-off-by: Jared Van Bortel <jared@nomic.ai> --------- Signed-off-by: Jared Van Bortel <jared@nomic.ai>
This commit is contained in:
parent
8a70f770a2
commit
4e89a9c44f
@ -149,7 +149,7 @@ endforeach()
|
|||||||
add_library(llmodel
|
add_library(llmodel
|
||||||
llmodel.h llmodel.cpp llmodel_shared.cpp
|
llmodel.h llmodel.cpp llmodel_shared.cpp
|
||||||
llmodel_c.h llmodel_c.cpp
|
llmodel_c.h llmodel_c.cpp
|
||||||
dlhandle.h
|
dlhandle.cpp
|
||||||
)
|
)
|
||||||
target_compile_definitions(llmodel PRIVATE LIB_FILE_EXT="${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
target_compile_definitions(llmodel PRIVATE LIB_FILE_EXT="${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||||
|
|
||||||
|
56
gpt4all-backend/dlhandle.cpp
Normal file
56
gpt4all-backend/dlhandle.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "dlhandle.h"
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
# include <dlfcn.h>
|
||||||
|
#else
|
||||||
|
# include <sstream>
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# ifndef NOMINMAX
|
||||||
|
# define NOMINMAX
|
||||||
|
# endif
|
||||||
|
# include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
|
||||||
|
Dlhandle::Dlhandle(const fs::path &fpath) {
|
||||||
|
chandle = dlopen(fpath.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
||||||
|
if (!chandle) {
|
||||||
|
throw Exception("dlopen(\"" + fpath.filename().string() + "\"): " + dlerror());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dlhandle::~Dlhandle() {
|
||||||
|
if (chandle) dlclose(chandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Dlhandle::get_internal(const char *symbol) const {
|
||||||
|
return dlsym(chandle, symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // defined(_WIN32)
|
||||||
|
|
||||||
|
Dlhandle::Dlhandle(const fs::path &fpath) {
|
||||||
|
auto afpath = fs::absolute(fpath);
|
||||||
|
chandle = LoadLibraryExW(afpath.c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
|
||||||
|
|
||||||
|
if (!chandle) {
|
||||||
|
auto err = GetLastError();
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << "LoadLibraryExW(\"" << fpath.filename().string() << "\") failed with error 0x" << std::hex << err;
|
||||||
|
throw Exception(ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dlhandle::~Dlhandle() {
|
||||||
|
if (chandle) FreeLibrary(HMODULE(chandle));
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Dlhandle::get_internal(const char *symbol) const {
|
||||||
|
return GetProcAddress(HMODULE(chandle), symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // defined(_WIN32)
|
@ -1,74 +1,15 @@
|
|||||||
#ifndef DLHANDLE_H
|
#pragma once
|
||||||
#define DLHANDLE_H
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <string>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <utility>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Dlhandle {
|
|
||||||
void *chandle;
|
|
||||||
|
|
||||||
public:
|
|
||||||
class Exception : public std::runtime_error {
|
|
||||||
public:
|
|
||||||
using std::runtime_error::runtime_error;
|
|
||||||
};
|
|
||||||
|
|
||||||
Dlhandle() : chandle(nullptr) {}
|
|
||||||
Dlhandle(const std::string& fpath, int flags = RTLD_LAZY | RTLD_LOCAL) {
|
|
||||||
chandle = dlopen(fpath.c_str(), flags);
|
|
||||||
if (!chandle) {
|
|
||||||
throw Exception("dlopen(\""+fpath+"\"): "+dlerror());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Dlhandle(const Dlhandle& o) = delete;
|
|
||||||
Dlhandle(Dlhandle&& o) : chandle(o.chandle) {
|
|
||||||
o.chandle = nullptr;
|
|
||||||
}
|
|
||||||
~Dlhandle() {
|
|
||||||
if (chandle) dlclose(chandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator =(Dlhandle&& o) {
|
|
||||||
chandle = std::exchange(o.chandle, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_valid() const {
|
|
||||||
return chandle != nullptr;
|
|
||||||
}
|
|
||||||
operator bool() const {
|
|
||||||
return is_valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T* get(const std::string& fname) const {
|
|
||||||
auto fres = reinterpret_cast<T*>(dlsym(chandle, fname.c_str()));
|
|
||||||
return (dlerror()==NULL)?fres:nullptr;
|
|
||||||
}
|
|
||||||
auto get_fnc(const std::string& fname) const {
|
|
||||||
return get<void*(...)>(fname);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
#include <algorithm>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string>
|
|
||||||
#include <exception>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
namespace fs = std::filesystem;
|
||||||
#ifndef NOMINMAX
|
|
||||||
# define NOMINMAX
|
|
||||||
#endif
|
|
||||||
#include <windows.h>
|
|
||||||
#include <libloaderapi.h>
|
|
||||||
|
|
||||||
|
|
||||||
class Dlhandle {
|
class Dlhandle {
|
||||||
HMODULE chandle;
|
void *chandle = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class Exception : public std::runtime_error {
|
class Exception : public std::runtime_error {
|
||||||
@ -76,34 +17,31 @@ public:
|
|||||||
using std::runtime_error::runtime_error;
|
using std::runtime_error::runtime_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
Dlhandle() : chandle(nullptr) {}
|
Dlhandle() = default;
|
||||||
Dlhandle(const std::string& fpath) {
|
Dlhandle(const fs::path &fpath);
|
||||||
std::string afpath = std::filesystem::absolute(fpath).string();
|
Dlhandle(const Dlhandle &o) = delete;
|
||||||
std::replace(afpath.begin(), afpath.end(), '/', '\\');
|
Dlhandle(Dlhandle &&o)
|
||||||
chandle = LoadLibraryExA(afpath.c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
|
: chandle(o.chandle)
|
||||||
if (!chandle) {
|
{
|
||||||
throw Exception("dlopen(\""+fpath+"\"): Error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Dlhandle(const Dlhandle& o) = delete;
|
|
||||||
Dlhandle(Dlhandle&& o) : chandle(o.chandle) {
|
|
||||||
o.chandle = nullptr;
|
o.chandle = nullptr;
|
||||||
}
|
}
|
||||||
~Dlhandle() {
|
|
||||||
if (chandle) FreeLibrary(chandle);
|
~Dlhandle();
|
||||||
|
|
||||||
|
Dlhandle &operator=(Dlhandle &&o) {
|
||||||
|
chandle = std::exchange(o.chandle, nullptr);
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_valid() const {
|
template <typename T>
|
||||||
return chandle != nullptr;
|
T *get(const std::string &symbol) const {
|
||||||
|
return reinterpret_cast<T *>(get_internal(symbol.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
auto get_fnc(const std::string &symbol) const {
|
||||||
T* get(const std::string& fname) const {
|
return get<void*(...)>(symbol);
|
||||||
return reinterpret_cast<T*>(GetProcAddress(chandle, fname.c_str()));
|
|
||||||
}
|
|
||||||
auto get_fnc(const std::string& fname) const {
|
|
||||||
return get<void*(...)>(fname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void *get_internal(const char *symbol) const;
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
#endif // DLHANDLE_H
|
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
#include "llmodel.h"
|
#include "llmodel.h"
|
||||||
#include "dlhandle.h"
|
|
||||||
#include "sysinfo.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@ -15,6 +13,9 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "dlhandle.h"
|
||||||
|
#include "sysinfo.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# define WIN32_LEAN_AND_MEAN
|
# define WIN32_LEAN_AND_MEAN
|
||||||
# ifndef NOMINMAX
|
# ifndef NOMINMAX
|
||||||
@ -27,6 +28,8 @@
|
|||||||
# include <intrin.h>
|
# include <intrin.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
#ifndef __APPLE__
|
#ifndef __APPLE__
|
||||||
static const std::string DEFAULT_BACKENDS[] = {"kompute", "cpu"};
|
static const std::string DEFAULT_BACKENDS[] = {"kompute", "cpu"};
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
@ -129,17 +132,17 @@ const std::vector<LLModel::Implementation> &LLModel::Implementation::implementat
|
|||||||
std::string path;
|
std::string path;
|
||||||
// Split the paths string by the delimiter and process each path.
|
// Split the paths string by the delimiter and process each path.
|
||||||
while (std::getline(ss, path, ';')) {
|
while (std::getline(ss, path, ';')) {
|
||||||
std::filesystem::path fs_path(path);
|
std::u8string u8_path(path.begin(), path.end());
|
||||||
// Iterate over all libraries
|
// Iterate over all libraries
|
||||||
for (const auto& f : std::filesystem::directory_iterator(fs_path)) {
|
for (const auto &f : fs::directory_iterator(u8_path)) {
|
||||||
const std::filesystem::path& p = f.path();
|
const fs::path &p = f.path();
|
||||||
|
|
||||||
if (p.extension() != LIB_FILE_EXT) continue;
|
if (p.extension() != LIB_FILE_EXT) continue;
|
||||||
if (!std::regex_search(p.stem().string(), re)) continue;
|
if (!std::regex_search(p.stem().string(), re)) continue;
|
||||||
|
|
||||||
// Add to list if model implementation
|
// Add to list if model implementation
|
||||||
try {
|
try {
|
||||||
Dlhandle dl(p.string());
|
Dlhandle dl(p);
|
||||||
if (!isImplementation(dl))
|
if (!isImplementation(dl))
|
||||||
continue;
|
continue;
|
||||||
fres.emplace_back(Implementation(std::move(dl)));
|
fres.emplace_back(Implementation(std::move(dl)));
|
||||||
|
Loading…
Reference in New Issue
Block a user