|
24 | 24 | #include <unistd.h> |
25 | 25 | #endif |
26 | 26 |
|
| 27 | +#if defined(__APPLE__) && defined(__MACH__) |
| 28 | +// macOS: use _NSGetExecutablePath to get the executable path |
| 29 | +#include <mach-o/dyld.h> |
| 30 | +#include <limits.h> |
| 31 | +#endif |
| 32 | + |
27 | 33 | #define CMD_EXIT "exit" |
28 | 34 |
|
| 35 | +static std::filesystem::path get_server_exec_path() { |
| 36 | +#if defined(_WIN32) |
| 37 | + wchar_t buf[32768] = { 0 }; // Large buffer to handle long paths |
| 38 | + DWORD len = GetModuleFileNameW(nullptr, buf, _countof(buf)); |
| 39 | + if (len == 0 || len >= _countof(buf)) { |
| 40 | + throw std::runtime_error("GetModuleFileNameW failed or path too long"); |
| 41 | + } |
| 42 | + return std::filesystem::path(buf); |
| 43 | +#elif defined(__APPLE__) && defined(__MACH__) |
| 44 | + char small_path[PATH_MAX]; |
| 45 | + uint32_t size = sizeof(small_path); |
| 46 | + |
| 47 | + if (_NSGetExecutablePath(small_path, &size) == 0) { |
| 48 | + // resolve any symlinks to get absolute path |
| 49 | + try { |
| 50 | + return std::filesystem::canonical(std::filesystem::path(small_path)); |
| 51 | + } catch (...) { |
| 52 | + return std::filesystem::path(small_path); |
| 53 | + } |
| 54 | + } else { |
| 55 | + // buffer was too small, allocate required size and call again |
| 56 | + std::vector<char> buf(size); |
| 57 | + if (_NSGetExecutablePath(buf.data(), &size) == 0) { |
| 58 | + try { |
| 59 | + return std::filesystem::canonical(std::filesystem::path(buf.data())); |
| 60 | + } catch (...) { |
| 61 | + return std::filesystem::path(buf.data()); |
| 62 | + } |
| 63 | + } |
| 64 | + throw std::runtime_error("_NSGetExecutablePath failed after buffer resize"); |
| 65 | + } |
| 66 | +#else |
| 67 | + char path[FILENAME_MAX]; |
| 68 | + ssize_t count = readlink("/proc/self/exe", path, FILENAME_MAX); |
| 69 | + if (count <= 0) { |
| 70 | + throw std::runtime_error("failed to resolve /proc/self/exe"); |
| 71 | + } |
| 72 | + return std::filesystem::path(std::string(path, count)); |
| 73 | +#endif |
| 74 | +} |
| 75 | + |
29 | 76 | struct local_model { |
30 | 77 | std::string name; |
31 | 78 | std::string path; |
@@ -99,6 +146,14 @@ server_models::server_models( |
99 | 146 | for (char ** env = envp; *env != nullptr; env++) { |
100 | 147 | base_env.push_back(std::string(*env)); |
101 | 148 | } |
| 149 | + GGML_ASSERT(!base_args.empty()); |
| 150 | + // set binary path |
| 151 | + try { |
| 152 | + base_args[0] = get_server_exec_path().string(); |
| 153 | + } catch (const std::exception & e) { |
| 154 | + LOG_WRN("failed to get server executable path: %s\n", e.what()); |
| 155 | + LOG_WRN("using original argv[0] as fallback: %s\n", base_args[0].c_str()); |
| 156 | + } |
102 | 157 | // TODO: allow refreshing cached model list |
103 | 158 | // add cached models |
104 | 159 | auto cached_models = common_list_cached_models(); |
|
0 commit comments