Make the system bazelrc configurable.

The master bazelrc is now defined by preprocessor macro at (Bazel's) compile time. The default is still /etc/bazel.bazelrc for most platforms, but windows now has a %ProgramData% relative default value as well. Users wishing to change this default when building Bazel for a new platform should edit BAZEL_SYSTEM_BAZELRC_PATH in src/main/cpp/BUILD.

Part of https://github.com/bazelbuild/bazel/issues/4502, relevant to the duplicate issue #4809.

TESTED: default settings were tested manually, since they cannot be tested in a sandbox

RELNOTES: Windows default system bazelrc is read from the user's ProgramData if present.
PiperOrigin-RevId: 201423446
diff --git a/src/main/cpp/BUILD b/src/main/cpp/BUILD
index 73bbf5d..f6b3110 100644
--- a/src/main/cpp/BUILD
+++ b/src/main/cpp/BUILD
@@ -122,6 +122,20 @@
         "option_processor.h",
         "option_processor-internal.h",
     ],
+    # The system bazelrc can be voided by setting BAZEL_SYSTEM_BAZELRC_PATH to
+    # /dev/null.
+    copts = select({
+        # We need to escape for multiple levels, here, this becomes
+        # /DBAZEL_SYSTEM_BAZELRC_PATH="%%ProgramData%%/bazel.bazelrc"',
+        # and the double % get reduced down to 1 by the compiler. A forward
+        # slash is used because \b is a special character, backspace.
+        "//src/conditions:windows": [
+            "/DBAZEL_SYSTEM_BAZELRC_PATH#\\\"%%ProgramData%%/bazel.bazelrc\\\"",
+        ],
+        "//conditions:default": [
+            "-DBAZEL_SYSTEM_BAZELRC_PATH=\\\"/etc/bazel.bazelrc\\\"",
+        ],
+    }),
     visibility = [
         "//src:__pkg__",
         "//src/test/cpp:__pkg__",
diff --git a/src/main/cpp/blaze_util_platform.h b/src/main/cpp/blaze_util_platform.h
index 078e271..29596df 100644
--- a/src/main/cpp/blaze_util_platform.h
+++ b/src/main/cpp/blaze_util_platform.h
@@ -61,9 +61,6 @@
 // On Linux/macOS, this is $HOME. On Windows this is %USERPROFILE%.
 std::string GetHomeDir();
 
-// Returns the location of the global bazelrc file if it exists, otherwise "".
-std::string FindSystemWideBlazerc();
-
 // Warn about dubious filesystem types, such as NFS, case-insensitive (?).
 void WarnFilesystemType(const std::string& output_base);
 
diff --git a/src/main/cpp/blaze_util_posix.cc b/src/main/cpp/blaze_util_posix.cc
index 156b021..2398e17 100644
--- a/src/main/cpp/blaze_util_posix.cc
+++ b/src/main/cpp/blaze_util_posix.cc
@@ -142,14 +142,6 @@
 
 string GetHomeDir() { return GetEnv("HOME"); }
 
-string FindSystemWideBlazerc() {
-  string path = "/etc/bazel.bazelrc";
-  if (blaze_util::CanReadFile(path)) {
-    return path;
-  }
-  return "";
-}
-
 string GetJavaBinaryUnderJavabase() { return "bin/java"; }
 
 // NB: execve() requires pointers to non-const char arrays but .c_str() returns
diff --git a/src/main/cpp/option_processor-internal.h b/src/main/cpp/option_processor-internal.h
index 8ebfb64..47f0df4 100644
--- a/src/main/cpp/option_processor-internal.h
+++ b/src/main/cpp/option_processor-internal.h
@@ -30,6 +30,8 @@
 std::vector<std::string> DedupeBlazercPaths(
     const std::vector<std::string>& paths);
 
+std::string FindSystemWideRc();
+
 std::string FindRcAlongsideBinary(const std::string& cwd,
                                   const std::string& path_to_binary);
 
diff --git a/src/main/cpp/option_processor.cc b/src/main/cpp/option_processor.cc
index 582833a..11da52a 100644
--- a/src/main/cpp/option_processor.cc
+++ b/src/main/cpp/option_processor.cc
@@ -47,6 +47,10 @@
 constexpr char WorkspaceLayout::WorkspacePrefix[];
 static std::vector<std::string> GetProcessedEnv();
 
+// Path to the system-wide bazelrc configuration file.
+// This is a mutable global for testing purposes only.
+const char* system_bazelrc_path = BAZEL_SYSTEM_BAZELRC_PATH;
+
 OptionProcessor::OptionProcessor(
     const WorkspaceLayout* workspace_layout,
     std::unique_ptr<StartupOptions> default_startup_options)
@@ -187,6 +191,20 @@
   return result;
 }
 
+string FindSystemWideRc() {
+  // MakeAbsoluteAndResolveWindowsEnvvars will standardize the form of the
+  // provided path. This also means we accept relative paths, which is
+  // is convenient for testing.
+  const string path = blaze_util::MakeAbsoluteAndResolveWindowsEnvvars(
+      system_bazelrc_path);
+  if (blaze_util::CanReadFile(path)) {
+    return path;
+  }
+  BAZEL_LOG(INFO) << "Looked for a system bazelrc at path '" << path
+                  << "', but none was found.";
+  return "";
+}
+
 string FindRcAlongsideBinary(const string& cwd, const string& path_to_binary) {
   const string path = blaze_util::IsAbsolute(path_to_binary)
                           ? path_to_binary
@@ -231,9 +249,13 @@
   if (SearchNullaryOption(cmd_line->startup_args, "master_bazelrc", true)) {
     const string workspace_rc =
         workspace_layout->GetWorkspaceRcPath(workspace, cmd_line->startup_args);
+    // TODO(b/36168162): Remove the alongside-binary rc file. (Part of GitHub
+    // issue #4502)
     const string binary_rc =
         internal::FindRcAlongsideBinary(cwd, cmd_line->path_to_binary);
-    const string system_rc = FindSystemWideBlazerc();
+    // TODO(b/36168162): This is not the desired order, see
+    // https://github.com/bazelbuild/bazel/issues/4502#issuecomment-372697374.
+    const string system_rc = internal::FindSystemWideRc();
     BAZEL_LOG(INFO)
         << "Looking for master bazelrcs in the following three paths: "
         << workspace_rc << ", " << binary_rc << ", " << system_rc;
diff --git a/src/main/cpp/workspace_layout.cc b/src/main/cpp/workspace_layout.cc
index b1d3ff2..d781993 100644
--- a/src/main/cpp/workspace_layout.cc
+++ b/src/main/cpp/workspace_layout.cc
@@ -61,6 +61,9 @@
 std::string WorkspaceLayout::GetWorkspaceRcPath(
     const std::string &workspace,
     const std::vector<std::string> &startup_args) const {
+  // TODO(b/36168162): Rename and remove the tools/ prefix. See
+  // https://github.com/bazelbuild/bazel/issues/4502#issuecomment-372697374
+  // for the final set of bazelrcs we want to have.
   return blaze_util::JoinPath(workspace, "tools/bazel.rc");
 }