2
2
#include " ggml-backend.h"
3
3
#include " ggml-impl.h"
4
4
#include < algorithm>
5
- #include < codecvt>
6
5
#include < cstring>
7
6
#include < filesystem>
8
- #include < locale>
9
7
#include < memory>
10
8
#include < string>
11
9
#include < type_traits>
72
70
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
73
71
#endif
74
72
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;
79
74
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;
83
82
}
84
83
85
84
#if defined(__clang__)
@@ -96,12 +95,12 @@ struct dl_handle_deleter {
96
95
}
97
96
};
98
97
99
- static dl_handle * dl_load_library (const std::wstring & path) {
98
+ static dl_handle * dl_load_library (const fs::path & path) {
100
99
// suppress error dialogs for missing DLLs
101
100
DWORD old_mode = SetErrorMode (SEM_FAILCRITICALERRORS);
102
101
SetErrorMode (old_mode | SEM_FAILCRITICALERRORS);
103
102
104
- HMODULE handle = LoadLibraryW (path.c_str ());
103
+ HMODULE handle = LoadLibraryW (path.wstring (). c_str ());
105
104
106
105
SetErrorMode (old_mode);
107
106
@@ -129,8 +128,8 @@ struct dl_handle_deleter {
129
128
}
130
129
};
131
130
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);
134
133
135
134
return handle;
136
135
}
@@ -217,27 +216,27 @@ struct ggml_backend_registry {
217
216
devices.push_back (device);
218
217
}
219
218
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) {
221
220
dl_handle_ptr handle { dl_load_library (path) };
222
221
if (!handle) {
223
222
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 ());
225
224
}
226
225
return nullptr ;
227
226
}
228
227
229
228
auto score_fn = (ggml_backend_score_t ) dl_get_sym (handle.get (), " ggml_backend_score" );
230
229
if (score_fn && score_fn () == 0 ) {
231
230
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 ());
233
232
}
234
233
return nullptr ;
235
234
}
236
235
237
236
auto backend_init_fn = (ggml_backend_init_t ) dl_get_sym (handle.get (), " ggml_backend_init" );
238
237
if (!backend_init_fn) {
239
238
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 ());
241
240
}
242
241
return nullptr ;
243
242
}
@@ -246,16 +245,17 @@ struct ggml_backend_registry {
246
245
if (!reg || reg->api_version != GGML_BACKEND_API_VERSION) {
247
246
if (!silent) {
248
247
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 ());
250
250
} else {
251
251
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);
253
253
}
254
254
}
255
255
return nullptr ;
256
256
}
257
257
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 ());
259
259
260
260
register_backend (reg, std::move (handle));
261
261
@@ -391,14 +391,14 @@ ggml_backend_t ggml_backend_init_best(void) {
391
391
392
392
// Dynamic loading
393
393
ggml_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 );
395
395
}
396
396
397
397
void ggml_backend_unload (ggml_backend_reg_t reg) {
398
398
get_reg ().unload_backend (reg, true );
399
399
}
400
400
401
- static std::wstring get_executable_path () {
401
+ static fs::path get_executable_path () {
402
402
#if defined(__APPLE__)
403
403
// get executable path
404
404
std::vector<char > path;
@@ -416,7 +416,7 @@ static std::wstring get_executable_path() {
416
416
if (last_slash != std::string::npos) {
417
417
base_path = base_path.substr (0 , last_slash);
418
418
}
419
- return utf8_to_utf16 ( base_path + " /" ) ;
419
+ return base_path + " /" ;
420
420
#elif defined(__linux__) || defined(__FreeBSD__)
421
421
std::string base_path = " ." ;
422
422
std::vector<char > path (1024 );
@@ -442,7 +442,7 @@ static std::wstring get_executable_path() {
442
442
path.resize (path.size () * 2 );
443
443
}
444
444
445
- return utf8_to_utf16 ( base_path + " /" ) ;
445
+ return base_path + " /" ;
446
446
#elif defined(_WIN32)
447
447
std::vector<wchar_t > path (MAX_PATH);
448
448
DWORD len = GetModuleFileNameW (NULL , path.data (), path.size ());
@@ -461,74 +461,69 @@ static std::wstring get_executable_path() {
461
461
#endif
462
462
}
463
463
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 () {
473
465
#ifdef _WIN32
474
- return L" .dll " ;
466
+ return fs::u8path ( " ggml- " ) ;
475
467
#else
476
- return L" .so " ;
468
+ return fs::u8path ( " libggml- " ) ;
477
469
#endif
478
470
}
479
471
480
- static std::wstring path_separator () {
472
+ static fs::path backend_filename_extension () {
481
473
#ifdef _WIN32
482
- return L" \\ " ;
474
+ return fs::u8path ( " .dll " ) ;
483
475
#else
484
- return L" / " ;
476
+ return fs::u8path ( " .so " ) ;
485
477
#endif
486
478
}
487
479
488
480
static ggml_backend_reg_t ggml_backend_load_best (const char * name, bool silent, const char * user_search_path) {
489
481
// 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;
493
487
if (user_search_path == nullptr ) {
494
- search_paths. push_back ( L" . " + path_separator ());
488
+ // default search paths: executable directory, current directory
495
489
search_paths.push_back (get_executable_path ());
490
+ search_paths.push_back (fs::current_path ());
496
491
} else {
497
- search_paths.push_back (utf8_to_utf16 ( user_search_path) + path_separator () );
492
+ search_paths.push_back (user_search_path);
498
493
}
499
494
500
495
int best_score = 0 ;
501
- std::wstring best_path;
496
+ fs::path best_path;
502
497
503
- namespace fs = std::filesystem;
504
498
for (const auto & search_path : search_paths) {
505
499
if (!fs::exists (search_path)) {
500
+ GGML_LOG_DEBUG (" %s: search path %s does not exist\n " , __func__, path_str (search_path).c_str ());
506
501
continue ;
507
502
}
508
503
fs::directory_iterator dir_it (search_path, fs::directory_options::skip_permission_denied);
509
504
for (const auto & entry : dir_it) {
510
505
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) };
515
510
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 ());
517
512
}
518
513
if (handle) {
519
514
auto score_fn = (ggml_backend_score_t ) dl_get_sym (handle.get (), " ggml_backend_score" );
520
515
if (score_fn) {
521
516
int s = score_fn ();
522
517
#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);
524
519
#endif
525
520
if (s > best_score) {
526
521
best_score = s;
527
- best_path = entry.path (). wstring () ;
522
+ best_path = entry.path ();
528
523
}
529
524
} else {
530
525
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 ());
532
527
}
533
528
}
534
529
}
@@ -540,7 +535,8 @@ static ggml_backend_reg_t ggml_backend_load_best(const char * name, bool silent,
540
535
if (best_score == 0 ) {
541
536
// try to load the base backend
542
537
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 ();
544
540
if (fs::exists (path)) {
545
541
return get_reg ().load_backend (path, silent);
546
542
}
0 commit comments