Commit 76a5bc86d for llama.cpp
commit 76a5bc86d1bdfae96feccdc7a41fea535e792e6e
Author: Adrien Gallouët <angt@huggingface.co>
Date: Tue Sep 29 07:24:03 2026 +0200
common : use fs::path for cache dirs (#29595)
- Avoid useless string conversions on Windows.
- No need for BSD or emscripten special cases.
Signed-off-by: Adrien Gallouët <angt@huggingface.co>
diff --git a/common/arg.cpp b/common/arg.cpp
index 2acac3b5c..b70da5e9e 100644
--- a/common/arg.cpp
+++ b/common/arg.cpp
@@ -351,7 +351,7 @@ static bool parse_bool_value(const std::string & value) {
static std::string get_default_local_path(const std::string & url) {
auto f = string_split<std::string>(url, '#').front();
f = string_split<std::string>(f, '?').front();
- return fs_get_cache_file(string_split<std::string>(f, '/').back());
+ return fs_path_to_utf8(fs_get_cache_file(string_split<std::string>(f, '/').back()));
}
static bool spec_types_is_default(const common_params & params) {
diff --git a/common/common.cpp b/common/common.cpp
index 6f443f1bf..6d57b5421 100644
--- a/common/common.cpp
+++ b/common/common.cpp
@@ -49,7 +49,7 @@
#include <unistd.h>
#endif
-#if defined(__linux__)
+#if !defined(_WIN32) && !defined(__APPLE__)
#include <sys/types.h>
#include <pwd.h>
#endif
@@ -912,13 +912,6 @@ std::string fs_path_to_utf8(const std::filesystem::path & path) {
return std::string(value.begin(), value.end());
}
-// returns true if successful, false otherwise
-bool fs_create_directory_with_parents(const std::string & path) {
- std::error_code ec;
- std::filesystem::create_directories(std::filesystem::u8path(path), ec);
- return !ec;
-}
-
bool fs_is_directory(const std::string & path) {
std::filesystem::path dir(path);
return std::filesystem::exists(dir) && std::filesystem::is_directory(dir);
@@ -952,58 +945,41 @@ std::filesystem::path common_get_path_from_env(const std::string & name) {
#endif
}
-std::string fs_get_cache_directory() {
- std::string cache_directory = "";
- auto ensure_trailing_slash = [](std::string p) {
- // Make sure to add trailing slash
- if (p.empty() || p.back() != DIRECTORY_SEPARATOR) {
- p += DIRECTORY_SEPARATOR;
- }
- return p;
- };
- cache_directory = common_get_env("LLAMA_CACHE");
+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()) {
-#if defined(__linux__) || defined(__FreeBSD__) || defined(_AIX) || \
- defined(__OpenBSD__) || defined(__NetBSD__)
- const std::string xdg_cache_home = common_get_env("XDG_CACHE_HOME");
- const std::string home = common_get_env("HOME");
- if (!xdg_cache_home.empty()) {
- cache_directory = xdg_cache_home;
- } else if (!home.empty()) {
- cache_directory = home + "/.cache/";
+ 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";
+#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 {
-#if defined(__linux__)
/* no $HOME is defined, fallback to getpwuid */
- struct passwd *pw = getpwuid(getuid());
- if ((!pw) || (!pw->pw_dir)) {
+ 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 = std::string(pw->pw_dir) + std::string("/.cache/");
-#else /* defined(__linux__) */
- throw std::runtime_error("Failed to find $HOME directory");
-#endif /* defined(__linux__) */
- }
-#elif defined(__APPLE__)
- cache_directory = common_get_env("HOME");
- if (cache_directory.empty()) {
- throw std::runtime_error("Failed to find $HOME directory");
+ cache_directory = pw->pw_dir;
+ cache_directory /= ".cache";
}
- cache_directory += "/Library/Caches/";
-#elif defined(_WIN32)
- cache_directory = common_get_env("LOCALAPPDATA");
- if (cache_directory.empty()) {
- throw std::runtime_error("Failed to find %LOCALAPPDATA% directory");
- }
-#elif defined(__EMSCRIPTEN__)
- GGML_ABORT("not implemented on this platform");
-#else
-# error Unknown architecture
-#endif
- cache_directory = ensure_trailing_slash(cache_directory);
- cache_directory += "llama.cpp";
}
- return ensure_trailing_slash(cache_directory);
+#endif
+ return cache_directory / "llama.cpp";
}
std::string fs_get_config_directory() {
@@ -1051,14 +1027,15 @@ std::string fs_get_config_directory() {
return ensure_trailing_slash(config_directory);
}
-std::string fs_get_cache_file(const std::string & filename) {
+std::filesystem::path fs_get_cache_file(const std::string & filename) {
GGML_ASSERT(filename.find(DIRECTORY_SEPARATOR) == std::string::npos);
- std::string cache_directory = fs_get_cache_directory();
- const bool success = fs_create_directory_with_parents(cache_directory);
- if (!success) {
- throw std::runtime_error("failed to create cache directory: " + cache_directory);
+ const std::filesystem::path cache_directory = fs_get_cache_directory();
+ std::error_code ec;
+ std::filesystem::create_directories(cache_directory, ec);
+ if (ec) {
+ throw std::runtime_error("failed to create cache directory: " + fs_path_to_utf8(cache_directory));
}
- return cache_directory + filename;
+ return cache_directory / std::filesystem::u8path(filename);
}
std::vector<common_file_info> fs_list(const std::string & path, bool include_directories) {
diff --git a/common/common.h b/common/common.h
index 45b15def7..0a09fed7f 100644
--- a/common/common.h
+++ b/common/common.h
@@ -912,11 +912,10 @@ std::filesystem::path common_get_path_from_env(const std::string & name);
//
bool fs_validate_filename(const std::string & filename, bool allow_subdirs = false);
-bool fs_create_directory_with_parents(const std::string & path);
bool fs_is_directory(const std::string & path);
-std::string fs_get_cache_directory();
-std::string fs_get_cache_file(const std::string & filename);
+std::filesystem::path fs_get_cache_directory();
+std::filesystem::path fs_get_cache_file(const std::string & filename);
std::string fs_get_config_directory();
struct common_file_info {
diff --git a/common/download.cpp b/common/download.cpp
index 2edd2a11c..d7875078c 100644
--- a/common/download.cpp
+++ b/common/download.cpp
@@ -943,7 +943,7 @@ std::string common_docker_resolve_model(const std::string & docker) {
std::string model_filename = repo;
std::replace(model_filename.begin(), model_filename.end(), '/', '_');
model_filename += "_" + tag + ".gguf";
- std::string local_path = fs_get_cache_file(model_filename);
+ std::string local_path = fs_path_to_utf8(fs_get_cache_file(model_filename));
const std::string blob_url = url_prefix + "/blobs/" + gguf_digest;
common_download_opts opts;
diff --git a/tests/gguf-model-data.cpp b/tests/gguf-model-data.cpp
index fe8b4ca76..3e2147dd2 100644
--- a/tests/gguf-model-data.cpp
+++ b/tests/gguf-model-data.cpp
@@ -371,8 +371,8 @@ static std::optional<gguf_remote_model> gguf_parse_meta(const std::vector<char>
}
// cache handling for local download
-static std::string get_default_cache_dir() {
- return fs_get_cache_directory() + "gguf-headers/";
+static std::filesystem::path get_default_cache_dir() {
+ return fs_get_cache_directory() / "gguf-headers";
}
static std::string sanitize_for_path(const std::string & s) {
@@ -385,7 +385,7 @@ static std::string sanitize_for_path(const std::string & s) {
return out;
}
-static bool read_file(const std::string & path, std::vector<char> & out) {
+static bool read_file(const std::filesystem::path & path, std::vector<char> & out) {
std::ifstream f(path, std::ios::binary | std::ios::ate);
if (!f.good()) {
return false;
@@ -400,7 +400,7 @@ static bool read_file(const std::string & path, std::vector<char> & out) {
return f.good();
}
-static bool write_file(const std::string & path, const std::vector<char> & data) {
+static bool write_file(const std::filesystem::path & path, const std::vector<char> & data) {
std::ofstream f(path, std::ios::binary | std::ios::trunc);
if (!f.good()) {
return false;
@@ -516,7 +516,7 @@ static std::string detect_gguf_filename(const std::string & repo, const std::str
static std::optional<gguf_remote_model> fetch_and_parse(
const std::string & repo,
const std::string & filename,
- const std::string & cache_path,
+ const std::filesystem::path & cache_path,
bool verbose) {
std::string url = "https://huggingface.co/" + repo + "/resolve/main/" + filename;
@@ -564,19 +564,19 @@ static std::optional<gguf_remote_model> fetch_and_parse(
return std::nullopt;
}
-static std::string get_cache_file_path(const std::string& cdir, const std::string& repo_part, const std::string& filename) {
+static std::filesystem::path get_cache_file_path(const std::filesystem::path & cdir, const std::string & repo_part, const std::string & filename) {
std::string fname_part = sanitize_for_path(filename);
- return cdir + "/" + repo_part + "--" + fname_part + ".partial";
+ return cdir / std::filesystem::u8path(repo_part + "--" + fname_part + ".partial");
}
// Try cache first, then fetch and parse a single GGUF shard.
static std::optional<gguf_remote_model> fetch_or_cached(
const std::string & repo,
const std::string & filename,
- const std::string & cdir,
+ const std::filesystem::path & cdir,
const std::string & repo_part,
bool verbose) {
- std::string cache_path = get_cache_file_path(cdir, repo_part, filename);
+ std::filesystem::path cache_path = get_cache_file_path(cdir, repo_part, filename);
{
std::vector<char> cached;
@@ -584,14 +584,15 @@ static std::optional<gguf_remote_model> fetch_or_cached(
auto result = gguf_parse_meta(cached);
if (result.has_value()) {
if (verbose) {
- fprintf(stderr, "gguf_fetch: loaded from cache: %s\n", cache_path.c_str());
+ fprintf(stderr, "gguf_fetch: loaded from cache: %s\n", fs_path_to_utf8(cache_path).c_str());
}
return result;
}
}
}
- fs_create_directory_with_parents(cdir);
+ std::error_code ec;
+ std::filesystem::create_directories(cdir, ec);
return fetch_and_parse(repo, filename, cache_path, verbose);
}
@@ -600,7 +601,7 @@ std::optional<gguf_remote_model> gguf_fetch_model_meta(
const std::string & quant,
const std::string & cache_dir,
bool verbose) {
- std::string cdir = cache_dir.empty() ? get_default_cache_dir() : cache_dir;
+ const std::filesystem::path cdir = cache_dir.empty() ? get_default_cache_dir() : std::filesystem::u8path(cache_dir);
std::string repo_part = sanitize_for_path(repo);
std::string split_prefix;
@@ -661,7 +662,7 @@ gguf_context_ptr gguf_fetch_gguf_ctx(
const std::string & quant,
const std::string & cache_dir,
bool verbose) {
- std::string cdir = cache_dir.empty() ? get_default_cache_dir() : cache_dir;
+ const std::filesystem::path cdir = cache_dir.empty() ? get_default_cache_dir() : std::filesystem::u8path(cache_dir);
std::string repo_part = sanitize_for_path(repo);
std::string split_prefix;
@@ -679,12 +680,12 @@ gguf_context_ptr gguf_fetch_gguf_ctx(
auto & model = model_opt.value();
- const std::string cache_path = get_cache_file_path(cdir, repo_part, filename);
+ const std::filesystem::path cache_path = get_cache_file_path(cdir, repo_part, filename);
ggml_context_ptr ggml_ctx_ptr;
ggml_context * ggml_ctx{};
gguf_init_params params{true, &ggml_ctx};
- gguf_context_ptr ctx{gguf_init_from_file(cache_path.c_str(), params)};
+ gguf_context_ptr ctx{gguf_init_from_file(fs_path_to_utf8(cache_path).c_str(), params)};
ggml_ctx_ptr.reset(ggml_ctx);
if (ctx == nullptr) {
@@ -718,11 +719,11 @@ gguf_context_ptr gguf_fetch_gguf_ctx(
}
// Load tensors from shard and add to main gguf_context
- const std::string shard_path = get_cache_file_path(cdir, repo_part, shard_name);
+ const std::filesystem::path shard_path = get_cache_file_path(cdir, repo_part, shard_name);
ggml_context_ptr shard_ggml_ctx_ptr;
ggml_context * shard_ggml_ctx{};
gguf_init_params shard_params{true, &shard_ggml_ctx};
- gguf_context_ptr shard_ctx{gguf_init_from_file(shard_path.c_str(), shard_params)};
+ gguf_context_ptr shard_ctx{gguf_init_from_file(fs_path_to_utf8(shard_path).c_str(), shard_params)};
shard_ggml_ctx_ptr.reset(shard_ggml_ctx);
if (shard_ctx == nullptr) {
diff --git a/tools/rpc/rpc-server.cpp b/tools/rpc/rpc-server.cpp
index 100df3c40..5c30e6fe4 100644
--- a/tools/rpc/rpc-server.cpp
+++ b/tools/rpc/rpc-server.cpp
@@ -2,12 +2,10 @@
#include "ggml-rpc.h"
#ifdef _WIN32
# define NOMINMAX
-# define DIRECTORY_SEPARATOR '\\'
# include <windows.h>
# include <fcntl.h>
# include <io.h>
#else
-# define DIRECTORY_SEPARATOR '/'
# include <unistd.h>
#endif
#include <algorithm>
@@ -20,64 +18,68 @@
#include <thread>
#include <vector>
-#if defined(__linux__)
+#if !defined(_WIN32) && !defined(__APPLE__)
#include <sys/types.h>
#include <pwd.h>
#endif
-// NOTE: this is copied from common.cpp to avoid linking with libcommon
-// returns true if successful, false otherwise
-static bool fs_create_directory_with_parents(const std::string & path) {
- std::error_code ec;
- std::filesystem::create_directories(std::filesystem::u8path(path), ec);
- return !ec;
+
+static std::string fs_path_to_utf8(const std::filesystem::path & path) {
+ const auto value = path.u8string();
+ return std::string(value.begin(), value.end());
+}
+
+// common_get_path_from_env() is adapted to avoid utf8_to_wstring
+static std::filesystem::path common_get_path_from_env(const std::string & name) {
+#ifdef _WIN32
+ std::wstring wname;
+ for (const char * p = name.c_str(); *p; ++p) {
+ wname.push_back((wchar_t)*p);
+ }
+ const wchar_t * wvalue = _wgetenv(wname.c_str());
+ return wvalue ? std::filesystem::path(wvalue) : std::filesystem::path();
+#else
+ const char * value = std::getenv(name.c_str());
+ return value ? std::filesystem::path(value) : std::filesystem::path();
+#endif
}
// NOTE: this is copied from common.cpp to avoid linking with libcommon
-static std::string fs_get_cache_directory() {
- std::string cache_directory = "";
- auto ensure_trailing_slash = [](std::string p) {
- // Make sure to add trailing slash
- if (p.back() != DIRECTORY_SEPARATOR) {
- p += DIRECTORY_SEPARATOR;
- }
- return p;
- };
- if (getenv("LLAMA_CACHE")) {
- cache_directory = std::getenv("LLAMA_CACHE");
- } else {
-#if defined(__linux__) || defined(__FreeBSD__) || defined(_AIX) || \
- defined(__OpenBSD__) || defined(__NetBSD__)
- if (std::getenv("XDG_CACHE_HOME")) {
- cache_directory = std::getenv("XDG_CACHE_HOME");
- } else if (std::getenv("HOME")) {
- cache_directory = std::getenv("HOME") + std::string("/.cache/");
+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";
+#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 {
-#if defined(__linux__)
/* no $HOME is defined, fallback to getpwuid */
- struct passwd *pw = getpwuid(getuid());
- if ((!pw) || (!pw->pw_dir)) {
+ 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 = std::string(pw->pw_dir) + std::string("/.cache/");
-#else /* defined(__linux__) */
- throw std::runtime_error("Failed to find $HOME directory");
-#endif /* defined(__linux__) */
+ cache_directory = pw->pw_dir;
+ cache_directory /= ".cache";
}
-#elif defined(__APPLE__)
- cache_directory = std::getenv("HOME") + std::string("/Library/Caches/");
-#elif defined(_WIN32)
- cache_directory = std::getenv("LOCALAPPDATA");
-#elif defined(__EMSCRIPTEN__)
- GGML_ABORT("not implemented on this platform");
-#else
-# error Unknown architecture
-#endif
- cache_directory = ensure_trailing_slash(cache_directory);
- cache_directory += "llama.cpp";
}
- return ensure_trailing_slash(cache_directory);
+#endif
+ return cache_directory / "llama.cpp";
}
struct rpc_server_params {
@@ -229,11 +231,14 @@ int main(int argc, char * argv[]) {
const char * cache_dir = nullptr;
std::string cache_dir_str;
if (params.use_cache) {
- cache_dir_str = fs_get_cache_directory() + "rpc" + DIRECTORY_SEPARATOR;
- if (!fs_create_directory_with_parents(cache_dir_str)) {
- fprintf(stderr, "Failed to create cache directory: %s\n", cache_dir_str.c_str());
+ const std::filesystem::path cache_dir_path = fs_get_cache_directory() / "rpc";
+ std::error_code ec;
+ std::filesystem::create_directories(cache_dir_path, ec);
+ if (ec) {
+ fprintf(stderr, "Failed to create cache directory: %s\n", fs_path_to_utf8(cache_dir_path).c_str());
return 1;
}
+ cache_dir_str = fs_path_to_utf8(cache_dir_path);
cache_dir = cache_dir_str.c_str();
}