22#include " ggml-backend.h"
33#include " ggml-impl.h"
44#include < algorithm>
5- #include < codecvt>
65#include < cstring>
76#include < filesystem>
8- #include < locale>
97#include < memory>
108#include < string>
119#include < type_traits>
7270# pragma clang diagnostic ignored "-Wdeprecated-declarations"
7371#endif
7472
75- static std::wstring utf8_to_utf16 (const std::string & str) {
76- std::wstring_convert<std::codecvt_utf8_utf16<wchar_t >> converter;
77- return converter.from_bytes (str);
78- }
73+ namespace fs = std::filesystem;
7974
80- static std::string utf16_to_utf8 (const std::wstring & str) {
81- std::wstring_convert<std::codecvt_utf8_utf16<wchar_t >> converter;
82- return converter.to_bytes (str);
75+ static std::string path_str (const fs::path & path) {
76+ std::string u8path;
77+ try {
78+ u8path = path.u8string ();
79+ } catch (...) {
80+ }
81+ return u8path;
8382}
8483
8584#if defined(__clang__)
@@ -96,12 +95,12 @@ struct dl_handle_deleter {
9695 }
9796};
9897
99- static dl_handle * dl_load_library (const std::wstring & path) {
98+ static dl_handle * dl_load_library (const fs::path & path) {
10099 // suppress error dialogs for missing DLLs
101100 DWORD old_mode = SetErrorMode (SEM_FAILCRITICALERRORS);
102101 SetErrorMode (old_mode | SEM_FAILCRITICALERRORS);
103102
104- HMODULE handle = LoadLibraryW (path.c_str ());
103+ HMODULE handle = LoadLibraryW (path.wstring (). c_str ());
105104
106105 SetErrorMode (old_mode);
107106
@@ -129,8 +128,8 @@ struct dl_handle_deleter {
129128 }
130129};
131130
132- static void * dl_load_library (const std::wstring & path) {
133- dl_handle * handle = dlopen (utf16_to_utf8 ( path).c_str (), RTLD_NOW | RTLD_LOCAL);
131+ static void * dl_load_library (const fs::path & path) {
132+ dl_handle * handle = dlopen (path. string ( ).c_str (), RTLD_NOW | RTLD_LOCAL);
134133
135134 return handle;
136135}
@@ -217,27 +216,27 @@ struct ggml_backend_registry {
217216 devices.push_back (device);
218217 }
219218
220- ggml_backend_reg_t load_backend (const std::wstring & path, bool silent) {
219+ ggml_backend_reg_t load_backend (const fs::path & path, bool silent) {
221220 dl_handle_ptr handle { dl_load_library (path) };
222221 if (!handle) {
223222 if (!silent) {
224- GGML_LOG_ERROR (" %s: failed to load %s\n " , __func__, utf16_to_utf8 (path).c_str ());
223+ GGML_LOG_ERROR (" %s: failed to load %s\n " , __func__, path_str (path).c_str ());
225224 }
226225 return nullptr ;
227226 }
228227
229228 auto score_fn = (ggml_backend_score_t ) dl_get_sym (handle.get (), " ggml_backend_score" );
230229 if (score_fn && score_fn () == 0 ) {
231230 if (!silent) {
232- GGML_LOG_INFO (" %s: backend %s is not supported on this system\n " , __func__, utf16_to_utf8 (path).c_str ());
231+ GGML_LOG_INFO (" %s: backend %s is not supported on this system\n " , __func__, path_str (path).c_str ());
233232 }
234233 return nullptr ;
235234 }
236235
237236 auto backend_init_fn = (ggml_backend_init_t ) dl_get_sym (handle.get (), " ggml_backend_init" );
238237 if (!backend_init_fn) {
239238 if (!silent) {
240- GGML_LOG_ERROR (" %s: failed to find ggml_backend_init in %s\n " , __func__, utf16_to_utf8 (path).c_str ());
239+ GGML_LOG_ERROR (" %s: failed to find ggml_backend_init in %s\n " , __func__, path_str (path).c_str ());
241240 }
242241 return nullptr ;
243242 }
@@ -246,16 +245,17 @@ struct ggml_backend_registry {
246245 if (!reg || reg->api_version != GGML_BACKEND_API_VERSION) {
247246 if (!silent) {
248247 if (!reg) {
249- GGML_LOG_ERROR (" %s: failed to initialize backend from %s: ggml_backend_init returned NULL\n " , __func__, utf16_to_utf8 (path).c_str ());
248+ GGML_LOG_ERROR (" %s: failed to initialize backend from %s: ggml_backend_init returned NULL\n " ,
249+ __func__, path_str (path).c_str ());
250250 } else {
251251 GGML_LOG_ERROR (" %s: failed to initialize backend from %s: incompatible API version (backend: %d, current: %d)\n " ,
252- __func__, utf16_to_utf8 (path).c_str (), reg->api_version , GGML_BACKEND_API_VERSION);
252+ __func__, path_str (path).c_str (), reg->api_version , GGML_BACKEND_API_VERSION);
253253 }
254254 }
255255 return nullptr ;
256256 }
257257
258- GGML_LOG_INFO (" %s: loaded %s backend from %s\n " , __func__, ggml_backend_reg_name (reg), utf16_to_utf8 (path).c_str ());
258+ GGML_LOG_INFO (" %s: loaded %s backend from %s\n " , __func__, ggml_backend_reg_name (reg), path_str (path).c_str ());
259259
260260 register_backend (reg, std::move (handle));
261261
@@ -391,14 +391,14 @@ ggml_backend_t ggml_backend_init_best(void) {
391391
392392// Dynamic loading
393393ggml_backend_reg_t ggml_backend_load (const char * path) {
394- return get_reg ().load_backend (utf8_to_utf16 ( path) , false );
394+ return get_reg ().load_backend (path, false );
395395}
396396
397397void ggml_backend_unload (ggml_backend_reg_t reg) {
398398 get_reg ().unload_backend (reg, true );
399399}
400400
401- static std::wstring get_executable_path () {
401+ static fs::path get_executable_path () {
402402#if defined(__APPLE__)
403403 // get executable path
404404 std::vector<char > path;
@@ -416,7 +416,7 @@ static std::wstring get_executable_path() {
416416 if (last_slash != std::string::npos) {
417417 base_path = base_path.substr (0 , last_slash);
418418 }
419- return utf8_to_utf16 ( base_path + " /" ) ;
419+ return base_path + " /" ;
420420#elif defined(__linux__) || defined(__FreeBSD__)
421421 std::string base_path = " ." ;
422422 std::vector<char > path (1024 );
@@ -442,7 +442,7 @@ static std::wstring get_executable_path() {
442442 path.resize (path.size () * 2 );
443443 }
444444
445- return utf8_to_utf16 ( base_path + " /" ) ;
445+ return base_path + " /" ;
446446#elif defined(_WIN32)
447447 std::vector<wchar_t > path (MAX_PATH);
448448 DWORD len = GetModuleFileNameW (NULL , path.data (), path.size ());
@@ -461,74 +461,69 @@ static std::wstring get_executable_path() {
461461#endif
462462}
463463
464- static std::wstring backend_filename_prefix () {
465- #ifdef _WIN32
466- return L" ggml-" ;
467- #else
468- return L" libggml-" ;
469- #endif
470- }
471-
472- static std::wstring backend_filename_suffix () {
464+ static fs::path backend_filename_prefix () {
473465#ifdef _WIN32
474- return L" .dll " ;
466+ return fs::u8path ( " ggml- " ) ;
475467#else
476- return L" .so " ;
468+ return fs::u8path ( " libggml- " ) ;
477469#endif
478470}
479471
480- static std::wstring path_separator () {
472+ static fs::path backend_filename_extension () {
481473#ifdef _WIN32
482- return L" \\ " ;
474+ return fs::u8path ( " .dll " ) ;
483475#else
484- return L" / " ;
476+ return fs::u8path ( " .so " ) ;
485477#endif
486478}
487479
488480static ggml_backend_reg_t ggml_backend_load_best (const char * name, bool silent, const char * user_search_path) {
489481 // enumerate all the files that match [lib]ggml-name-*.[so|dll] in the search paths
490- // TODO: search system paths
491- std::wstring file_prefix = backend_filename_prefix () + utf8_to_utf16 (name) + L" -" ;
492- std::vector<std::wstring> search_paths;
482+ const fs::path name_path = fs::u8path (name);
483+ const fs::path file_prefix = backend_filename_prefix ().native () + name_path.native () + fs::u8path (" -" ).native ();
484+ const fs::path file_extension = backend_filename_extension ();
485+
486+ std::vector<fs::path> search_paths;
493487 if (user_search_path == nullptr ) {
494- search_paths. push_back ( L" . " + path_separator ());
488+ // default search paths: executable directory, current directory
495489 search_paths.push_back (get_executable_path ());
490+ search_paths.push_back (fs::current_path ());
496491 } else {
497- search_paths.push_back (utf8_to_utf16 ( user_search_path) + path_separator () );
492+ search_paths.push_back (user_search_path);
498493 }
499494
500495 int best_score = 0 ;
501- std::wstring best_path;
496+ fs::path best_path;
502497
503- namespace fs = std::filesystem;
504498 for (const auto & search_path : search_paths) {
505499 if (!fs::exists (search_path)) {
500+ GGML_LOG_DEBUG (" %s: search path %s does not exist\n " , __func__, path_str (search_path).c_str ());
506501 continue ;
507502 }
508503 fs::directory_iterator dir_it (search_path, fs::directory_options::skip_permission_denied);
509504 for (const auto & entry : dir_it) {
510505 if (entry.is_regular_file ()) {
511- std::wstring filename = entry.path ().filename ().wstring ();
512- std::wstring ext = entry.path ().extension ().wstring ();
513- if (filename.find (file_prefix) == 0 && ext == backend_filename_suffix () ) {
514- dl_handle_ptr handle { dl_load_library (entry. path (). wstring () ) };
506+ auto filename = entry.path ().filename ().native ();
507+ auto ext = entry.path ().extension ().native ();
508+ if (filename.find (file_prefix) == 0 && ext == file_extension ) {
509+ dl_handle_ptr handle { dl_load_library (entry) };
515510 if (!handle && !silent) {
516- GGML_LOG_ERROR (" %s: failed to load %s\n " , __func__, utf16_to_utf8 (entry.path (). wstring ()).c_str ());
511+ GGML_LOG_ERROR (" %s: failed to load %s\n " , __func__, path_str (entry.path ()).c_str ());
517512 }
518513 if (handle) {
519514 auto score_fn = (ggml_backend_score_t ) dl_get_sym (handle.get (), " ggml_backend_score" );
520515 if (score_fn) {
521516 int s = score_fn ();
522517#ifndef NDEBUG
523- GGML_LOG_DEBUG (" %s: %s score: %d\n " , __func__, utf16_to_utf8 (entry.path (). wstring ()).c_str (), s);
518+ GGML_LOG_DEBUG (" %s: %s score: %d\n " , __func__, path_str (entry.path ()).c_str (), s);
524519#endif
525520 if (s > best_score) {
526521 best_score = s;
527- best_path = entry.path (). wstring () ;
522+ best_path = entry.path ();
528523 }
529524 } else {
530525 if (!silent) {
531- GGML_LOG_INFO (" %s: failed to find ggml_backend_score in %s\n " , __func__, utf16_to_utf8 (entry.path (). wstring ()).c_str ());
526+ GGML_LOG_INFO (" %s: failed to find ggml_backend_score in %s\n " , __func__, path_str (entry.path ()).c_str ());
532527 }
533528 }
534529 }
@@ -540,7 +535,8 @@ static ggml_backend_reg_t ggml_backend_load_best(const char * name, bool silent,
540535 if (best_score == 0 ) {
541536 // try to load the base backend
542537 for (const auto & search_path : search_paths) {
543- std::wstring path = search_path + backend_filename_prefix () + utf8_to_utf16 (name) + backend_filename_suffix ();
538+ fs::path filename = backend_filename_prefix ().native () + name_path.native () + backend_filename_extension ().native ();
539+ fs::path path = search_path.native () + filename.native ();
544540 if (fs::exists (path)) {
545541 return get_reg ().load_backend (path, silent);
546542 }
0 commit comments