6666#include " ggml-kompute.h"
6767#endif
6868
69+ // disable C++17 deprecation warning for std::codecvt_utf8
70+ #if defined(__clang__)
71+ # pragma clang diagnostic push
72+ # pragma clang diagnostic ignored "-Wdeprecated-declarations"
73+ #endif
74+
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+ }
79+
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);
83+ }
84+
85+ #if defined(__clang__)
86+ # pragma clang diagnostic pop
87+ #endif
88+
6989#ifdef _WIN32
7090
7191using dl_handle = std::remove_pointer_t <HMODULE>;
@@ -88,11 +108,6 @@ static dl_handle * dl_load_library(const std::wstring & path) {
88108 return handle;
89109}
90110
91- static dl_handle * dl_load_library (const std::string & path) {
92- std::wstring_convert<std::codecvt_utf8_utf16<wchar_t >> converter;
93- return dl_load_library (converter.from_bytes (path));
94- }
95-
96111static void * dl_get_sym (dl_handle * handle, const char * name) {
97112 DWORD old_mode = SetErrorMode (SEM_FAILCRITICALERRORS);
98113 SetErrorMode (old_mode | SEM_FAILCRITICALERRORS);
@@ -114,8 +129,8 @@ struct dl_handle_deleter {
114129 }
115130};
116131
117- static void * dl_load_library (const std::string & path) {
118- dl_handle * handle = dlopen (path.c_str (), RTLD_NOW | RTLD_LOCAL);
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);
119134
120135 return handle;
121136}
@@ -202,27 +217,27 @@ struct ggml_backend_registry {
202217 devices.push_back (device);
203218 }
204219
205- ggml_backend_reg_t load_backend (const char * path, bool silent) {
220+ ggml_backend_reg_t load_backend (const std::wstring & path, bool silent) {
206221 dl_handle_ptr handle { dl_load_library (path) };
207222 if (!handle) {
208223 if (!silent) {
209- GGML_LOG_ERROR (" %s: failed to load %s\n " , __func__, path);
224+ GGML_LOG_ERROR (" %s: failed to load %s\n " , __func__, utf16_to_utf8 ( path). c_str () );
210225 }
211226 return nullptr ;
212227 }
213228
214229 auto score_fn = (ggml_backend_score_t ) dl_get_sym (handle.get (), " ggml_backend_score" );
215230 if (score_fn && score_fn () == 0 ) {
216231 if (!silent) {
217- GGML_LOG_INFO (" %s: backend %s is not supported on this system\n " , __func__, path);
232+ GGML_LOG_INFO (" %s: backend %s is not supported on this system\n " , __func__, utf16_to_utf8 ( path). c_str () );
218233 }
219234 return nullptr ;
220235 }
221236
222237 auto backend_init_fn = (ggml_backend_init_t ) dl_get_sym (handle.get (), " ggml_backend_init" );
223238 if (!backend_init_fn) {
224239 if (!silent) {
225- GGML_LOG_ERROR (" %s: failed to find ggml_backend_init in %s\n " , __func__, path);
240+ GGML_LOG_ERROR (" %s: failed to find ggml_backend_init in %s\n " , __func__, utf16_to_utf8 ( path). c_str () );
226241 }
227242 return nullptr ;
228243 }
@@ -231,16 +246,16 @@ struct ggml_backend_registry {
231246 if (!reg || reg->api_version != GGML_BACKEND_API_VERSION) {
232247 if (!silent) {
233248 if (!reg) {
234- GGML_LOG_ERROR (" %s: failed to initialize backend from %s: ggml_backend_init returned NULL\n " , __func__, path);
249+ GGML_LOG_ERROR (" %s: failed to initialize backend from %s: ggml_backend_init returned NULL\n " , __func__, utf16_to_utf8 ( path). c_str () );
235250 } else {
236251 GGML_LOG_ERROR (" %s: failed to initialize backend from %s: incompatible API version (backend: %d, current: %d)\n " ,
237- __func__, path, reg->api_version , GGML_BACKEND_API_VERSION);
252+ __func__, utf16_to_utf8 ( path). c_str () , reg->api_version , GGML_BACKEND_API_VERSION);
238253 }
239254 }
240255 return nullptr ;
241256 }
242257
243- GGML_LOG_INFO (" %s: loaded %s backend from %s\n " , __func__, ggml_backend_reg_name (reg), path);
258+ GGML_LOG_INFO (" %s: loaded %s backend from %s\n " , __func__, ggml_backend_reg_name (reg), utf16_to_utf8 ( path). c_str () );
244259
245260 register_backend (reg, std::move (handle));
246261
@@ -376,14 +391,14 @@ ggml_backend_t ggml_backend_init_best(void) {
376391
377392// Dynamic loading
378393ggml_backend_reg_t ggml_backend_load (const char * path) {
379- return get_reg ().load_backend (path, false );
394+ return get_reg ().load_backend (utf8_to_utf16 ( path) , false );
380395}
381396
382397void ggml_backend_unload (ggml_backend_reg_t reg) {
383398 get_reg ().unload_backend (reg, true );
384399}
385400
386- static std::string get_executable_path () {
401+ static std::wstring get_executable_path () {
387402#if defined(__APPLE__)
388403 // get executable path
389404 std::vector<char > path;
@@ -401,7 +416,7 @@ static std::string get_executable_path() {
401416 if (last_slash != std::string::npos) {
402417 base_path = base_path.substr (0 , last_slash);
403418 }
404- return base_path + " /" ;
419+ return utf8_to_utf16 ( base_path + " /" ) ;
405420#elif defined(__linux__) || defined(__FreeBSD__)
406421 std::string base_path = " ." ;
407422 std::vector<char > path (1024 );
@@ -427,57 +442,63 @@ static std::string get_executable_path() {
427442 path.resize (path.size () * 2 );
428443 }
429444
430- return base_path + " /" ;
445+ return utf8_to_utf16 ( base_path + " /" ) ;
431446#elif defined(_WIN32)
432- std::vector<char > path (MAX_PATH);
433- DWORD len = GetModuleFileNameA (NULL , path.data (), path.size ());
447+ std::vector<wchar_t > path (MAX_PATH);
448+ DWORD len = GetModuleFileNameW (NULL , path.data (), path.size ());
434449 if (len == 0 ) {
435- return " " ;
450+ return {} ;
436451 }
437- std::string base_path (path.data (), len);
452+ std::wstring base_path (path.data (), len);
438453 // remove executable name
439454 auto last_slash = base_path.find_last_of (' \\ ' );
440455 if (last_slash != std::string::npos) {
441456 base_path = base_path.substr (0 , last_slash);
442457 }
443- return base_path + " \\ " ;
458+ return base_path + L" \\ " ;
459+ #else
460+ return {};
461+ #endif
462+ }
463+
464+ static std::wstring backend_filename_prefix () {
465+ #ifdef _WIN32
466+ return L" ggml-" ;
467+ #else
468+ return L" libggml-" ;
444469#endif
445470}
446471
447- static std::string backend_filename_prefix () {
472+ static std::wstring backend_filename_suffix () {
448473#ifdef _WIN32
449- return " ggml- " ;
474+ return L" .dll " ;
450475#else
451- return " libggml- " ;
476+ return L" .so " ;
452477#endif
453478}
454479
455- static std::string backend_filename_suffix () {
480+ static std::wstring path_separator () {
456481#ifdef _WIN32
457- return " .dll " ;
482+ return L" \\ " ;
458483#else
459- return " .so " ;
484+ return L" / " ;
460485#endif
461486}
462487
463488static ggml_backend_reg_t ggml_backend_load_best (const char * name, bool silent, const char * user_search_path) {
464489 // enumerate all the files that match [lib]ggml-name-*.[so|dll] in the search paths
465490 // TODO: search system paths
466- std::string file_prefix = backend_filename_prefix () + name + " -" ;
467- std::vector<std::string > search_paths;
491+ std::wstring file_prefix = backend_filename_prefix () + utf8_to_utf16 ( name) + L " -" ;
492+ std::vector<std::wstring > search_paths;
468493 if (user_search_path == nullptr ) {
469- search_paths.push_back (" ./ " );
494+ search_paths.push_back (L" . " + path_separator () );
470495 search_paths.push_back (get_executable_path ());
471496 } else {
472- #if defined(_WIN32)
473- search_paths.push_back (std::string (user_search_path) + " \\ " );
474- #else
475- search_paths.push_back (std::string (user_search_path) + " /" );
476- #endif
497+ search_paths.push_back (utf8_to_utf16 (user_search_path) + path_separator ());
477498 }
478499
479500 int best_score = 0 ;
480- std::string best_path;
501+ std::wstring best_path;
481502
482503 namespace fs = std::filesystem;
483504 for (const auto & search_path : search_paths) {
@@ -487,27 +508,27 @@ static ggml_backend_reg_t ggml_backend_load_best(const char * name, bool silent,
487508 fs::directory_iterator dir_it (search_path, fs::directory_options::skip_permission_denied);
488509 for (const auto & entry : dir_it) {
489510 if (entry.is_regular_file ()) {
490- std::string filename = entry.path ().filename ().string ();
491- std::string ext = entry.path ().extension ().string ();
511+ std::wstring filename = entry.path ().filename ().wstring ();
512+ std::wstring ext = entry.path ().extension ().wstring ();
492513 if (filename.find (file_prefix) == 0 && ext == backend_filename_suffix ()) {
493- dl_handle_ptr handle { dl_load_library (entry.path ().c_str ()) };
514+ dl_handle_ptr handle { dl_load_library (entry.path ().wstring ()) };
494515 if (!handle && !silent) {
495- GGML_LOG_ERROR (" %s: failed to load %s\n " , __func__, entry.path ().string ( ).c_str ());
516+ GGML_LOG_ERROR (" %s: failed to load %s\n " , __func__, utf16_to_utf8 ( entry.path ().wstring () ).c_str ());
496517 }
497518 if (handle) {
498519 auto score_fn = (ggml_backend_score_t ) dl_get_sym (handle.get (), " ggml_backend_score" );
499520 if (score_fn) {
500521 int s = score_fn ();
501522#ifndef NDEBUG
502- GGML_LOG_DEBUG (" %s: %s score: %d\n " , __func__, entry.path ().string ( ).c_str (), s);
523+ GGML_LOG_DEBUG (" %s: %s score: %d\n " , __func__, utf16_to_utf8 ( entry.path ().wstring () ).c_str (), s);
503524#endif
504525 if (s > best_score) {
505526 best_score = s;
506- best_path = entry.path ().string ();
527+ best_path = entry.path ().wstring ();
507528 }
508529 } else {
509530 if (!silent) {
510- GGML_LOG_INFO (" %s: failed to find ggml_backend_score in %s\n " , __func__, entry.path ().string ( ).c_str ());
531+ GGML_LOG_INFO (" %s: failed to find ggml_backend_score in %s\n " , __func__, utf16_to_utf8 ( entry.path ().wstring () ).c_str ());
511532 }
512533 }
513534 }
@@ -519,15 +540,15 @@ static ggml_backend_reg_t ggml_backend_load_best(const char * name, bool silent,
519540 if (best_score == 0 ) {
520541 // try to load the base backend
521542 for (const auto & search_path : search_paths) {
522- std::string path = search_path + backend_filename_prefix () + name + backend_filename_suffix ();
543+ std::wstring path = search_path + backend_filename_prefix () + utf8_to_utf16 ( name) + backend_filename_suffix ();
523544 if (fs::exists (path)) {
524- return get_reg ().load_backend (path. c_str () , silent);
545+ return get_reg ().load_backend (path, silent);
525546 }
526547 }
527548 return nullptr ;
528549 }
529550
530- return get_reg ().load_backend (best_path. c_str () , silent);
551+ return get_reg ().load_backend (best_path, silent);
531552}
532553
533554void ggml_backend_load_all () {
0 commit comments