I am making a simple helper application that changes the brightness of my screen, but I need to cache a value. How do I get the path for the user’s .cache directory so I can write a file there?
dimdin
March 10, 2025, 7:37pm
2
Getting the cache directory is platform specific.
XDG Base Directory Specification specifies:
$XDG_CACHE_HOME
defines the base directory relative to which user-specific non-essential data files should be stored. If $XDG_CACHE_HOME
is either not set or empty, a default equal to $HOME
/.cache should be used.
Macos uses: ~/Library/Caches
Windows uses: %LOCALAPPDATA%\Temp
You can use the known-folders library to get the .cache
folder or other well known folders.
2 Likes
Thank you. I was messing with std.fs.realpath and felt like something was wrong lol.
1 Like
Here’s what I use to get a path to a subdir within the cache directory FWIW:
pub fn getCachePath(allocator: Allocator, appname: []const u8) error{OutOfMemory}!?[]const u8 {
switch (builtin.os.tag) {
.windows => {
const local_app_data = std.process.getEnvVarOwned(allocator, "LOCALAPPDATA") catch |err| switch (err) {
error.EnvironmentVariableNotFound => return null,
error.InvalidWtf8 => unreachable,
else => |e| return e,
};
defer allocator.free(local_app_data);
return try std.fs.path.join(allocator, &.{ local_app_data, "Temp", appname });
},
.macos => {
const home = std.posix.getenv("HOME") orelse return null;
return try std.fs.path.join(allocator, &.{ home, "Library/Caches", appname });
},
else => {
if (std.posix.getenv("XDG_CACHE_HOME")) |cache| {
return try std.fs.path.join(allocator, &.{ cache, appname });
}
const home = std.posix.getenv("HOME") orelse return null;
This file has been truncated. show original
(it’s basically the same as what @dimdin describes and what known-folders
does)
4 Likes
known-folders
is probably a better solution, but if you only need the cache directory, you can just yank this function from the compiler.
/// Caller owns returned memory.
pub fn resolveGlobalCacheDir(allocator: mem.Allocator) ![]u8 {
if (builtin.os.tag == .wasi)
@compileError("on WASI the global cache dir must be resolved with preopens");
if (try std.zig.EnvVar.ZIG_GLOBAL_CACHE_DIR.get(allocator)) |value| return value;
const appname = "zig";
if (builtin.os.tag != .windows) {
if (std.zig.EnvVar.XDG_CACHE_HOME.getPosix()) |cache_root| {
if (cache_root.len > 0) {
return fs.path.join(allocator, &[_][]const u8{ cache_root, appname });
}
}
if (std.zig.EnvVar.HOME.getPosix()) |home| {
return fs.path.join(allocator, &[_][]const u8{ home, ".cache", appname });
}
}
This file has been truncated. show original
2 Likes
Note that this code is for getting the zig cache directory.
1 Like
I’m a bit confused about the preferred path to cache on Windows.
Both the Go std and Zig compiler use %LocalAppData%
, but resinator
and known-folders
use %LocalAppData%/Temp
.
This usage is not documented in Environment variable - Wikipedia and, personally, the last path should be Cache
, instead of Temp
.