Index: include/llvm/Support/Path.h =================================================================== --- include/llvm/Support/Path.h +++ include/llvm/Support/Path.h @@ -325,6 +325,16 @@ /// @result True if a home directory is set, false otherwise. bool home_directory(SmallVectorImpl &result); +/// @brief Get the user's cache directory. +/// +/// Expect the resulting path to be a directory shared with other +/// applications/services used by the user. At least an application/service name +/// should be appended to the path before storing any files. +/// +/// @param result Holds the resulting path. +/// @result True if a cache directory path is set, false otherwise. +bool user_cache_directory(SmallVectorImpl &result); + /// @brief Has root name? /// /// root_name != "" Index: lib/Support/Unix/Path.inc =================================================================== --- lib/Support/Unix/Path.inc +++ lib/Support/Unix/Path.inc @@ -560,6 +560,56 @@ return false; } +namespace { +bool getDarwinConfDir(bool TempDir, SmallVectorImpl &Result) { + #if defined(_CS_DARWIN_USER_TEMP_DIR) && defined(_CS_DARWIN_USER_CACHE_DIR) + // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR. + // macros defined in on darwin >= 9 + int ConfName = TempDir ? _CS_DARWIN_USER_TEMP_DIR + : _CS_DARWIN_USER_CACHE_DIR; + size_t ConfLen = confstr(ConfName, nullptr, 0); + if (ConfLen > 0) { + do { + Result.resize(ConfLen); + ConfLen = confstr(ConfName, Result.data(), Result.size()); + } while (ConfLen > 0 && ConfLen != Result.size()); + + if (ConfLen > 0) { + assert(Result.back() == 0); + Result.pop_back(); + return true; + } + + Result.clear(); + } + #endif + return false; +} +} + +bool user_cache_directory(SmallVectorImpl &result) { + // First try using XDS_CACHE_HOME env variable, + // as specified in XDG Base Directory Specification at + // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + if (const char *xdsCacheDir = std::getenv("XDS_CACHE_HOME")) { + result.clear(); + result.append(xdsCacheDir, xdsCacheDir + strlen(xdsCacheDir)); + return true; + } + + // Try Darwin configuration query + if (getDarwinConfDir(false, result)) + return true; + + // Use "$HOME/.cache" if $HOME is available + if (home_directory(result)) { + append(result, ".cache"); + return true; + } + + return false; +} + static const char *getEnvTempDir() { // Check whether the temporary directory is specified by an environment // variable. @@ -594,27 +644,8 @@ } } -#if defined(_CS_DARWIN_USER_TEMP_DIR) && defined(_CS_DARWIN_USER_CACHE_DIR) - // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR. - // macros defined in on darwin >= 9 - int ConfName = ErasedOnReboot? _CS_DARWIN_USER_TEMP_DIR - : _CS_DARWIN_USER_CACHE_DIR; - size_t ConfLen = confstr(ConfName, nullptr, 0); - if (ConfLen > 0) { - do { - Result.resize(ConfLen); - ConfLen = confstr(ConfName, Result.data(), Result.size()); - } while (ConfLen > 0 && ConfLen != Result.size()); - - if (ConfLen > 0) { - assert(Result.back() == 0); - Result.pop_back(); - return; - } - - Result.clear(); - } -#endif + if (getDarwinConfDir(ErasedOnReboot, Result)) + return; const char *RequestedDir = getDefaultTempDir(ErasedOnReboot); Result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); Index: lib/Support/Windows/Path.inc =================================================================== --- lib/Support/Windows/Path.inc +++ lib/Support/Windows/Path.inc @@ -771,6 +771,10 @@ return getKnownFolderPath(FOLDERID_Profile, result); } +bool user_cache_directory(SmallVectorImpl &result) { + return getKnownFolderPath(FOLDERID_LocalAppData, result); +} + static bool getTempDirEnvVar(const char *Var, SmallVectorImpl &Res) { SmallVector NameUTF16; if (windows::UTF8ToUTF16(Var, NameUTF16)) Index: unittests/Support/Path.cpp =================================================================== --- unittests/Support/Path.cpp +++ unittests/Support/Path.cpp @@ -322,6 +322,12 @@ } } +TEST(Support, UserCacheDirectory) { + SmallString<13> cacheDir; + auto status = path::user_cache_directory(cacheDir); + EXPECT_TRUE(status ^ cacheDir.empty()); +} + class FileSystemTest : public testing::Test { protected: /// Unique temporary directory in which all created filesystem entities must