I have implemented such functionality in libraries for the JVM and Rust. Here is what I learned:
Deal with application names, because your users can't or won't.
Provide APIs that compute the full path (including the application name!) to configuration, cache, etc. directories. Not doing this will result in code that is guaranteed to be wrong on at least 2 of 3 major platforms, as the conventions differ dramatically.
Consider an application written by company MegaCorp (web address MegaCorp.co.uk) named Foo App.
Under Linux, the path segment naming the application should be fooapp/
(lower-cased, no spaces), on Windows it should be MegaCorp\Foo App\
(note the two folders), and on macOS it should be uk.co.MegaCorp.Foo-App
(invalid characters replaced with -
).
For instance, my library does not offer a runtimeDir
on macOS or Windows, because XDG_RUNTIME_DIR
is very different from e. g. %TEMP%
on Windows.
This is a potential source of security issues, as the runtime dir on Linux guarantees that it can only be accessed by the owner, is deleted when the user logs off, etc.
Also, I only offer fontDir
on Linux and macOS. Windows does have a font directory, but unlike on Linux and macOS, it is not user-writable.
On the other hand, I offer both dataDir
(%APPDATA%
) and dataLocalDir
(%LOCALAPPDATA%
) across all three platforms. On macOS and Linux those directories return the same path – this is an explicit design decision, considering how users would write code if one of those directories would not be available: Users would either forget to handle it, or just fallback to the other directory. With the chosen design this just works out of the box, without users needing to think about it.
Avoid issues before the user encounters them.
This is why the general cache, config etc. directory paths return %LOCALAPPDATA%
and %APPDATA%
, but application-specific cache and config directory paths return %LOCALAPPDATA%\Company\Application\cache
and %APPDATA%\Company\Application\config
.
Note the sub-directories! This is to guarantee a clean separation of an application's cache, config and data directory, regardless of what weird Windows settings a user might have.
Split use cases into separate modules.
There are three distinct modules in my library, with clearly defined, separated use cases:
BaseDirs, which queries the paths of user-invisible standard directories (cache, config, data, executable, runtime directories) and strongly suggests using ProjectDirs instead.
ProjectDirs, which computes the location of cache, config or data directories for your own application or project, which are derived from the standard directories.
UserDirs, which queries the paths of user-facing standard directories (Audio, Documents, Downloads, etc.).
While BaseDirs
and UserDirs
have fairly uninteresting constructors (new()
), ProjectDirs
provides this factory method:
ProjectDirs::from(qualifier: &str, organization: &str, application: &str)
This method ensures that users end up with correct, standards-compliant paths to their applications' cache, config, etc. directories – without them needing to be aware of all the intricacies of each individual platform.
One last suggestion: I would keep a library named "XDG Basedir Library" focused on Linux, and publish a library with a more general name, like "Standard Directory Library" that deals with Linux, Windows, etc. to avoid confusion.
Hope this was helpful!
XDG_DATA_DIRS
should not be in the user's profile, because its value is/usr/local/share/:/usr/share/
on POSIX systems by default. Those directories are for all normal users, not just the current one, so you should pick the AppData for all users, which isC:\ProgramData
which seems to be%PROGRAMDATA%
as well as%ALLUSERSPROFILE%
these days. Long story short:$XDG_DATA_DIRS
=%PROGRAMDATA%
. – Nonexistence$XDG_CONFIG_HOME
should be%APPDATA%
so it gets shared across the devices in the same domain.$XDG_DATA_HOME
should then use%LOCALAPPDATA
as suggested. In the main specification these folders are not the same by default and I think this should also be the case in Windows environments. – Nonexistence