diff --git a/site/en/remote/output-directories.md b/site/en/remote/output-directories.md index 7a3965819b175e..49d42a94e4c9da 100644 --- a/site/en/remote/output-directories.md +++ b/site/en/remote/output-directories.md @@ -29,9 +29,10 @@ The solution that's currently implemented: * Bazel must be invoked from a directory containing a WORKSPACE file (the "_workspace directory_"), or a subdirectory thereof. It reports an error if it is not. -* The _outputRoot_ directory defaults to `~/.cache/bazel` on Linux, - `/private/var/tmp` on macOS, and on Windows it defaults to `%HOME%` if set, - else `%USERPROFILE%` if set, else the result of calling +* The _outputRoot_ directory defaults to `${XDG_CACHE_HOME}/bazel` (or + `~/.cache/bazel`, if the `XDG_CACHE_HOME` environment variable is not set) on + Linux, `/private/var/tmp` on macOS, and on Windows it defaults to `%HOME%` if + set, else `%USERPROFILE%` if set, else the result of calling `SHGetKnownFolderPath()` with the `FOLDERID_Profile` flag set. If the environment variable `$TEST_TMPDIR` is set, as in a test of Bazel itself, then that value overrides the default. diff --git a/src/main/cpp/blaze_util_bsd.cc b/src/main/cpp/blaze_util_bsd.cc index 8987e0c0f2c6e2..9a80750c826a79 100644 --- a/src/main/cpp/blaze_util_bsd.cc +++ b/src/main/cpp/blaze_util_bsd.cc @@ -60,17 +60,24 @@ namespace blaze { using blaze_util::GetLastErrorString; using std::string; +// ${XDG_CACHE_HOME}/bazel, a.k.a. ~/.cache/bazel by default (which is the +// fallback when XDG_CACHE_HOME is not set) string GetOutputRoot() { - char buf[2048]; - struct passwd pwbuf; - struct passwd *pw = nullptr; - int uid = getuid(); - int r = getpwuid_r(uid, &pwbuf, buf, 2048, &pw); - if (r == 0 && pw != nullptr) { - return blaze_util::JoinPath(pw->pw_dir, ".cache/bazel"); - } else { - return "/tmp"; + string xdg_cache_home = GetPathEnv("XDG_CACHE_HOME"); + if (xdg_cache_home.empty()) { + char buf[2048]; + struct passwd pwbuf; + struct passwd *pw = nullptr; + int uid = getuid(); + int r = getpwuid_r(uid, &pwbuf, buf, 2048, &pw); + if (r == 0 && pw != nullptr) { + xdg_cache_home = blaze_util::JoinPath(pw->pw_dir, ".cache"); + } else { + return "/tmp"; + } } + + return blaze_util::JoinPath(xdg_cache_home, "bazel"); } void WarnFilesystemType(const blaze_util::Path &output_base) { diff --git a/src/main/cpp/blaze_util_linux.cc b/src/main/cpp/blaze_util_linux.cc index 0f6c61777f2830..51423d3cb3e6d5 100644 --- a/src/main/cpp/blaze_util_linux.cc +++ b/src/main/cpp/blaze_util_linux.cc @@ -43,27 +43,29 @@ using blaze_util::GetLastErrorString; using std::string; using std::vector; +// ${XDG_CACHE_HOME}/bazel, a.k.a. ~/.cache/bazel by default (which is the +// fallback when XDG_CACHE_HOME is not set) string GetOutputRoot() { - string base; - string home = GetHomeDir(); - if (!home.empty()) { - base = home; - } else { - char buf[2048]; - struct passwd pwbuf; - struct passwd *pw = nullptr; - int uid = getuid(); - int r = getpwuid_r(uid, &pwbuf, buf, 2048, &pw); - if (r == 0 && pw != nullptr) { - base = pw->pw_dir; + string xdg_cache_home = GetPathEnv("XDG_CACHE_HOME"); + if (xdg_cache_home.empty()) { + string home = GetHomeDir(); // via $HOME env variable + if (home.empty()) { + // Fall back to home dir from password database + char buf[2048]; + struct passwd pwbuf; + struct passwd *pw = nullptr; + int uid = getuid(); + int r = getpwuid_r(uid, &pwbuf, buf, 2048, &pw); + if (r == 0 && pw != nullptr) { + home = pw->pw_dir; + } else { + return "/tmp"; + } } + xdg_cache_home = blaze_util::JoinPath(home, ".cache"); } - if (!base.empty()) { - return blaze_util::JoinPath(base, ".cache/bazel"); - } - - return "/tmp"; + return blaze_util::JoinPath(xdg_cache_home, "bazel"); } void WarnFilesystemType(const blaze_util::Path &output_base) { diff --git a/src/test/cpp/startup_options_test.cc b/src/test/cpp/startup_options_test.cc index 52debb7b7b9cc3..afbb786c9235c7 100644 --- a/src/test/cpp/startup_options_test.cc +++ b/src/test/cpp/startup_options_test.cc @@ -92,15 +92,27 @@ TEST_F(StartupOptionsTest, JavaLoggingOptions) { #ifdef __linux TEST_F(StartupOptionsTest, OutputRootPreferTestTmpdirIfSet) { SetEnv("HOME", "/nonexistent/home"); + SetEnv("XDG_CACHE_HOME", "/nonexistent/cache"); SetEnv("TEST_TMPDIR", "/nonexistent/tmpdir"); ReinitStartupOptions(); ASSERT_EQ("/nonexistent/tmpdir", startup_options_->output_root); } +TEST_F(StartupOptionsTest, + OutputRootPreferXdgCacheHomeIfSetAndTestTmpdirUnset) { + SetEnv("HOME", "/nonexistent/home"); + SetEnv("XDG_CACHE_HOME", "/nonexistent/cache"); + UnsetEnv("TEST_TMPDIR"); + ReinitStartupOptions(); + + ASSERT_EQ("/nonexistent/cache/bazel", startup_options_->output_root); +} + TEST_F(StartupOptionsTest, OutputRootUseHomeDirectory) { SetEnv("HOME", "/nonexistent/home"); UnsetEnv("TEST_TMPDIR"); + UnsetEnv("XDG_CACHE_HOME"); ReinitStartupOptions(); ASSERT_EQ("/nonexistent/home/.cache/bazel", startup_options_->output_root);