Commit 00af63567 for llama.cpp

commit 00af63567a3ac073919be039db8492f229de5ffc
Author: Adrien Gallouët <angt@huggingface.co>
Date:   Tue Sep 29 17:22:49 2026 +0200

    common : use fs::path for config dir (#29649)

    Signed-off-by: Adrien Gallouët <angt@huggingface.co>

diff --git a/common/arg.cpp b/common/arg.cpp
index b70da5e9e..56ca9d3bf 100644
--- a/common/arg.cpp
+++ b/common/arg.cpp
@@ -717,24 +717,24 @@ void common_models_handler_apply(common_models_handler & handler, common_params
 // 1. system-wide: /etc/llama.cpp/config.ini (%PROGRAMDATA%\llama.cpp\config.ini on windows)
 // 2. user-level: ${XDG_CONFIG_HOME:-~/.config}/llama.cpp/config.ini (%APPDATA%\llama.cpp\config.ini on windows)
 static void common_params_apply_system_config(common_params & params, llama_example ex) {
-    std::vector<std::string> paths;
+    std::vector<std::filesystem::path> paths;

 #if defined(_WIN32)
-    const std::string program_data = common_get_env("PROGRAMDATA");
+    const std::filesystem::path program_data = common_get_path_from_env("PROGRAMDATA");
     if (!program_data.empty()) {
-        paths.push_back(program_data + "\\llama.cpp\\config.ini");
+        paths.push_back(program_data / "llama.cpp" / "config.ini");
     }
 #else
     paths.push_back("/etc/llama.cpp/config.ini");
 #endif

     try {
-        paths.push_back(fs_get_config_directory() + "config.ini");
+        paths.push_back(fs_get_config_directory() / "config.ini");
     } catch (const std::exception & e) {
         LOG_DBG("cannot read user-level config file, skipping: %s\n", e.what());
     }

-    std::vector<std::string> found;
+    std::vector<std::filesystem::path> found;
     for (const auto & path : paths) {
         std::error_code ec;
         if (std::filesystem::exists(path, ec)) {
@@ -748,7 +748,7 @@ static void common_params_apply_system_config(common_params & params, llama_exam
     common_preset_context ctx(ex);
     ctx.ignore_unknown_keys = true; // the same config file is shared by all programs
     for (const auto & path : found) {
-        LOG_INF("using config file: %s\n", path.c_str());
+        LOG_INF("using config file: %s\n", fs_path_to_utf8(path).c_str());
         common_preset global;
         common_presets presets = ctx.load_from_ini(path, global);
         global.apply_to_params(params);
diff --git a/common/common.cpp b/common/common.cpp
index d1e7b7e5d..598a97d10 100644
--- a/common/common.cpp
+++ b/common/common.cpp
@@ -49,7 +49,7 @@
 #include <unistd.h>
 #endif

-#if !defined(_WIN32) && !defined(__APPLE__)
+#if !defined(_WIN32)
 #include <sys/types.h>
 #include <pwd.h>
 #endif
@@ -968,86 +968,55 @@ std::filesystem::path common_get_path_from_env(const std::string & name) {
 #endif
 }

+#if !defined(_WIN32)
+static std::filesystem::path get_home_directory() {
+    std::filesystem::path home = common_get_path_from_env("HOME");
+    if (!home.empty()) {
+        return home;
+    }
+    const struct passwd * pw = getpwuid(getuid());
+    if (!pw || !pw->pw_dir || !*pw->pw_dir) {
+        throw std::runtime_error("Failed to find $HOME directory");
+    }
+    return pw->pw_dir;
+}
+#endif
+
 std::filesystem::path fs_get_cache_directory() {
     std::filesystem::path cache_directory = common_get_path_from_env("LLAMA_CACHE");
     if (!cache_directory.empty()) {
         return cache_directory;
     }
-
 #if defined(_WIN32)
     cache_directory = common_get_path_from_env("LOCALAPPDATA");
     if (cache_directory.empty()) {
         throw std::runtime_error("Failed to find %LOCALAPPDATA% directory");
     }
 #elif defined(__APPLE__)
-    cache_directory = common_get_path_from_env("HOME");
-    if (cache_directory.empty()) {
-        throw std::runtime_error("Failed to find $HOME directory");
-    }
-    cache_directory /= "Library/Caches";
+    cache_directory = get_home_directory() / "Library/Caches";
 #else
     cache_directory = common_get_path_from_env("XDG_CACHE_HOME");
     if (cache_directory.empty()) {
-        cache_directory = common_get_path_from_env("HOME");
-        if (!cache_directory.empty()) {
-            cache_directory /= ".cache";
-        } else {
-            /* no $HOME is defined, fallback to getpwuid */
-            const struct passwd * pw = getpwuid(getuid());
-            if (!pw || !pw->pw_dir || !*pw->pw_dir) {
-                throw std::runtime_error("Failed to find $HOME directory");
-            }
-            cache_directory = pw->pw_dir;
-            cache_directory /= ".cache";
-        }
+        cache_directory = get_home_directory() / ".cache";
     }
 #endif
     return cache_directory / "llama.cpp";
 }

-std::string fs_get_config_directory() {
-    std::string config_directory = "";
-    auto ensure_trailing_slash = [](std::string p) {
-        if (p.empty() || p.back() != DIRECTORY_SEPARATOR) {
-            p += DIRECTORY_SEPARATOR;
-        }
-        return p;
-    };
-#if defined(__linux__) || defined(__FreeBSD__) || defined(_AIX) || \
-        defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
-    const std::string xdg_config_home = common_get_env("XDG_CONFIG_HOME");
-    const std::string home            = common_get_env("HOME");
-    if (!xdg_config_home.empty()) {
-        config_directory = xdg_config_home;
-    } else if (!home.empty()) {
-        config_directory = home + "/.config/";
-    } else {
-#if defined(__linux__)
-        /* no $HOME is defined, fallback to getpwuid */
-        struct passwd *pw = getpwuid(getuid());
-        if ((!pw) || (!pw->pw_dir)) {
-            throw std::runtime_error("Failed to find $HOME directory");
-        }
-
-        config_directory = std::string(pw->pw_dir) + std::string("/.config/");
-#else
-        throw std::runtime_error("Failed to find $HOME directory");
-#endif
-    }
-#elif defined(_WIN32)
-    config_directory = common_get_env("APPDATA");
+std::filesystem::path fs_get_config_directory() {
+    std::filesystem::path config_directory;
+#if defined(_WIN32)
+    config_directory = common_get_path_from_env("APPDATA");
     if (config_directory.empty()) {
         throw std::runtime_error("Failed to find %APPDATA% directory");
     }
-#elif defined(__EMSCRIPTEN__)
-    // caller decides what to do when there is no config directory
-    throw std::runtime_error("not implemented on this platform");
 #else
-#  error Unknown architecture
+    config_directory = common_get_path_from_env("XDG_CONFIG_HOME");
+    if (config_directory.empty()) {
+        config_directory = get_home_directory() / ".config";
+    }
 #endif
-    config_directory = ensure_trailing_slash(config_directory);
-    config_directory += "llama.cpp";
-    return ensure_trailing_slash(config_directory);
+    return config_directory / "llama.cpp";
 }

 std::filesystem::path fs_get_cache_file(const std::string & filename) {
diff --git a/common/common.h b/common/common.h
index 01726247b..e95eb2fd0 100644
--- a/common/common.h
+++ b/common/common.h
@@ -916,7 +916,7 @@ bool fs_is_directory(const std::string & path);

 std::filesystem::path fs_get_cache_directory();
 std::filesystem::path fs_get_cache_file(const std::string & filename);
-std::string fs_get_config_directory();
+std::filesystem::path fs_get_config_directory();

 struct common_file_info {
     std::string path;
diff --git a/common/preset.cpp b/common/preset.cpp
index 4c61e93ee..7ca24ec38 100644
--- a/common/preset.cpp
+++ b/common/preset.cpp
@@ -167,16 +167,16 @@ void common_preset::apply_to_params(common_params & params, const std::set<std::
     }
 }

-static std::map<std::string, std::map<std::string, std::string>> parse_ini_from_file(const std::string & path) {
+static std::map<std::string, std::map<std::string, std::string>> parse_ini_from_file(const std::filesystem::path & path) {
     std::map<std::string, std::map<std::string, std::string>> parsed;

     if (!std::filesystem::exists(path)) {
-        throw std::runtime_error("preset file does not exist: " + path);
+        throw std::runtime_error("preset file does not exist: " + fs_path_to_utf8(path));
     }

     std::ifstream file(path);
     if (!file.good()) {
-        throw std::runtime_error("failed to open server preset file: " + path);
+        throw std::runtime_error("failed to open server preset file: " + fs_path_to_utf8(path));
     }

     std::string contents((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
@@ -225,7 +225,7 @@ static std::map<std::string, std::map<std::string, std::string>> parse_ini_from_
     common_peg_parse_context ctx(contents);
     const auto result = parser.parse(ctx);
     if (!result.success()) {
-        throw std::runtime_error("failed to parse server config file: " + path);
+        throw std::runtime_error("failed to parse server config file: " + fs_path_to_utf8(path));
     }

     std::string current_section = COMMON_PRESET_DEFAULT_NAME;
@@ -282,7 +282,7 @@ common_preset_context::common_preset_context(llama_example ex)
     key_to_opt = get_map_key_opt(ctx_params);
 }

-common_presets common_preset_context::load_from_ini(const std::string & path, common_preset & global) const {
+common_presets common_preset_context::load_from_ini(const std::filesystem::path & path, common_preset & global) const {
     common_presets out;
     auto ini_data = parse_ini_from_file(path);

@@ -323,7 +323,7 @@ common_presets common_preset_context::load_from_ini(const std::string & path, co
                 }
                 LOG_DBG("accepted option: %s = %s\n", key.c_str(), preset.options[opt].c_str());
             } else if (ignore_unknown_keys) {
-                LOG_WRN("ignoring option '%s' from %s: not supported by this program\n", key.c_str(), path.c_str());
+                LOG_WRN("ignoring option '%s' from %s: not supported by this program\n", key.c_str(), fs_path_to_utf8(path).c_str());
             } else {
                 throw std::runtime_error(string_format(
                     "option '%s' not recognized in preset '%s'",
diff --git a/common/preset.h b/common/preset.h
index d8fc3915b..e03d186f1 100644
--- a/common/preset.h
+++ b/common/preset.h
@@ -67,7 +67,7 @@ struct common_preset_context {
     common_preset_context(llama_example ex);

     // load presets from INI file
-    common_presets load_from_ini(const std::string & path, common_preset & global) const;
+    common_presets load_from_ini(const std::filesystem::path & path, common_preset & global) const;

     // generate presets from cached models
     common_presets load_from_cache() const;
diff --git a/tools/rpc/rpc-server.cpp b/tools/rpc/rpc-server.cpp
index 5c30e6fe4..c0c55df59 100644
--- a/tools/rpc/rpc-server.cpp
+++ b/tools/rpc/rpc-server.cpp
@@ -18,12 +18,13 @@
 #include <thread>
 #include <vector>

-#if !defined(_WIN32) && !defined(__APPLE__)
+#if !defined(_WIN32)
 #include <sys/types.h>
 #include <pwd.h>
 #endif


+// NOTE: this is copied from common.cpp to avoid linking with libcommon
 static std::string fs_path_to_utf8(const std::filesystem::path & path) {
     const auto value = path.u8string();
     return std::string(value.begin(), value.end());
@@ -44,39 +45,38 @@ static std::filesystem::path common_get_path_from_env(const std::string & name)
 #endif
 }

+// NOTE: this is copied from common.cpp to avoid linking with libcommon
+#if !defined(_WIN32)
+static std::filesystem::path get_home_directory() {
+    std::filesystem::path home = common_get_path_from_env("HOME");
+    if (!home.empty()) {
+        return home;
+    }
+    const struct passwd * pw = getpwuid(getuid());
+    if (!pw || !pw->pw_dir || !*pw->pw_dir) {
+        throw std::runtime_error("Failed to find $HOME directory");
+    }
+    return pw->pw_dir;
+}
+#endif
+
 // NOTE: this is copied from common.cpp to avoid linking with libcommon
 static std::filesystem::path fs_get_cache_directory() {
     std::filesystem::path cache_directory = common_get_path_from_env("LLAMA_CACHE");
     if (!cache_directory.empty()) {
         return cache_directory;
     }
-
 #if defined(_WIN32)
     cache_directory = common_get_path_from_env("LOCALAPPDATA");
     if (cache_directory.empty()) {
         throw std::runtime_error("Failed to find %LOCALAPPDATA% directory");
     }
 #elif defined(__APPLE__)
-    cache_directory = common_get_path_from_env("HOME");
-    if (cache_directory.empty()) {
-        throw std::runtime_error("Failed to find $HOME directory");
-    }
-    cache_directory /= "Library/Caches";
+    cache_directory = get_home_directory() / "Library/Caches";
 #else
     cache_directory = common_get_path_from_env("XDG_CACHE_HOME");
     if (cache_directory.empty()) {
-        cache_directory = common_get_path_from_env("HOME");
-        if (!cache_directory.empty()) {
-            cache_directory /= ".cache";
-        } else {
-            /* no $HOME is defined, fallback to getpwuid */
-            const struct passwd * pw = getpwuid(getuid());
-            if (!pw || !pw->pw_dir || !*pw->pw_dir) {
-                throw std::runtime_error("Failed to find $HOME directory");
-            }
-            cache_directory = pw->pw_dir;
-            cache_directory /= ".cache";
-        }
+        cache_directory = get_home_directory() / ".cache";
     }
 #endif
     return cache_directory / "llama.cpp";