Windows, Bazel client: detect Bash early enough
Detect Bash's path early enough to compute the
--windows_unix_root host JVM flag's value.
Now Bazel forwards Bash's location to the Bazel
server even if BAZEL_SH is undefined, and no
longer crashes when --compiler=msys-gcc but
BAZEL_SH is undefined.
Fixes https://github.com/bazelbuild/bazel/issues/6651
Closes #7289.
PiperOrigin-RevId: 231931801
diff --git a/src/main/cpp/blaze.cc b/src/main/cpp/blaze.cc
index e62b821..267fc30 100644
--- a/src/main/cpp/blaze.cc
+++ b/src/main/cpp/blaze.cc
@@ -1537,10 +1537,12 @@
// Must be done before command line parsing.
ComputeWorkspace(workspace_layout);
+#if defined(_WIN32) || defined(__CYGWIN__)
// Must be done before command line parsing.
// ParseOptions already populate --client_env, so detect bash before it
// happens.
DetectBashOrDie();
+#endif // if defined(_WIN32) || defined(__CYGWIN__)
globals->binary_path = CheckAndGetBinaryPath(argv[0]);
ParseOptions(argc, argv);
diff --git a/src/main/cpp/blaze_util_platform.h b/src/main/cpp/blaze_util_platform.h
index 2e13acf..7ed5373 100644
--- a/src/main/cpp/blaze_util_platform.h
+++ b/src/main/cpp/blaze_util_platform.h
@@ -260,7 +260,10 @@
// raised; false otherwise.
bool UnlimitCoredumps();
+#if defined(_WIN32) || defined(__CYGWIN__)
+std::string DetectBashAndExportBazelSh();
void DetectBashOrDie();
+#endif // if defined(_WIN32) || defined(__CYGWIN__)
// This function has no effect on Unix platforms.
// On Windows, this function looks into PATH to find python.exe, if python
diff --git a/src/main/cpp/blaze_util_posix.cc b/src/main/cpp/blaze_util_posix.cc
index 11de625..1398efb 100644
--- a/src/main/cpp/blaze_util_posix.cc
+++ b/src/main/cpp/blaze_util_posix.cc
@@ -830,10 +830,6 @@
return UnlimitResource(RLIMIT_CORE, true);
}
-void DetectBashOrDie() {
- // do nothing.
-}
-
void EnsurePythonPathOption(vector<string>* options) {
// do nothing.
}
diff --git a/src/main/cpp/blaze_util_windows.cc b/src/main/cpp/blaze_util_windows.cc
index a8ccacb..038ad50 100644
--- a/src/main/cpp/blaze_util_windows.cc
+++ b/src/main/cpp/blaze_util_windows.cc
@@ -1458,12 +1458,15 @@
return result;
}
-void DetectBashOrDie() {
- if (!blaze::GetEnv("BAZEL_SH").empty()) return;
+string DetectBashAndExportBazelSh() {
+ string bash = blaze::GetEnv("BAZEL_SH");
+ if (!bash.empty()) {
+ return bash;
+ }
uint64_t start = blaze::GetMillisecondsMonotonic();
- string bash = LocateBash();
+ bash = LocateBash();
uint64_t end = blaze::GetMillisecondsMonotonic();
BAZEL_LOG(INFO) << "BAZEL_SH detection took " << end - start
<< " msec, found " << bash.c_str();
@@ -1471,7 +1474,13 @@
if (!bash.empty()) {
// Set process environment variable.
blaze::SetEnv("BAZEL_SH", bash);
- } else {
+ }
+ return bash;
+}
+
+void DetectBashOrDie() {
+ string bash = DetectBashAndExportBazelSh();
+ if (bash.empty()) {
// TODO(bazel-team) should this be printed to stderr? If so, it should use
// BAZEL_LOG(ERROR)
printf(
diff --git a/src/main/cpp/startup_options.cc b/src/main/cpp/startup_options.cc
index c259bb6..9fc35fb 100644
--- a/src/main/cpp/startup_options.cc
+++ b/src/main/cpp/startup_options.cc
@@ -112,7 +112,7 @@
}
#if defined(_WIN32) || defined(__CYGWIN__)
- string windows_unix_root = WindowsUnixRoot(blaze::GetEnv("BAZEL_SH"));
+ string windows_unix_root = DetectBashAndExportBazelSh();
if (!windows_unix_root.empty()) {
host_jvm_args.push_back(string("-Dbazel.windows_unix_root=") +
windows_unix_root);
@@ -593,32 +593,4 @@
return blaze_exit_code::SUCCESS;
}
-#if defined(_WIN32) || defined(__CYGWIN__)
-// Extract the Windows path of "/" from $BAZEL_SH.
-// $BAZEL_SH usually has the form `<prefix>/usr/bin/bash.exe` or
-// `<prefix>/bin/bash.exe`, and this method returns that `<prefix>` part.
-// If $BAZEL_SH doesn't end with "usr/bin/bash.exe" or "bin/bash.exe" then this
-// method returns an empty string.
-string StartupOptions::WindowsUnixRoot(const string &bazel_sh) {
- if (bazel_sh.empty()) {
- return string();
- }
- std::pair<string, string> split = blaze_util::SplitPath(bazel_sh);
- if (blaze_util::AsLower(split.second) != "bash.exe") {
- return string();
- }
- split = blaze_util::SplitPath(split.first);
- if (blaze_util::AsLower(split.second) != "bin") {
- return string();
- }
-
- std::pair<string, string> split2 = blaze_util::SplitPath(split.first);
- if (blaze_util::AsLower(split2.second) == "usr") {
- return split2.first;
- } else {
- return split.first;
- }
-}
-#endif // defined(_WIN32) || defined(__CYGWIN__)
-
} // namespace blaze
diff --git a/src/main/cpp/startup_options.h b/src/main/cpp/startup_options.h
index 07f641c..23105e3 100644
--- a/src/main/cpp/startup_options.h
+++ b/src/main/cpp/startup_options.h
@@ -326,10 +326,6 @@
std::string default_server_javabase_;
// Contains the collection of startup flags that Bazel accepts.
std::set<std::unique_ptr<StartupFlag>> valid_startup_flags;
-
-#if defined(_WIN32) || defined(__CYGWIN__)
- static std::string WindowsUnixRoot(const std::string &bazel_sh);
-#endif
};
} // namespace blaze
diff --git a/src/test/cpp/option_processor_test.cc b/src/test/cpp/option_processor_test.cc
index f008d03..461b425 100644
--- a/src/test/cpp/option_processor_test.cc
+++ b/src/test/cpp/option_processor_test.cc
@@ -28,11 +28,11 @@
class OptionProcessorTest : public ::testing::Test {
protected:
- OptionProcessorTest() :
- workspace_(
- blaze_util::JoinPath(blaze::GetEnv("TEST_TMPDIR"), "testdir")),
- cwd_("cwd"),
- workspace_layout_(new WorkspaceLayout()) {}
+ OptionProcessorTest()
+ : workspace_(
+ blaze_util::JoinPath(blaze::GetEnv("TEST_TMPDIR"), "testdir")),
+ cwd_("cwd"),
+ workspace_layout_(new WorkspaceLayout()) {}
~OptionProcessorTest() override {}
@@ -98,21 +98,32 @@
};
TEST_F(OptionProcessorTest, CanParseOptions) {
- const std::vector<std::string> args =
- {"bazel",
- "--host_jvm_args=MyParam", "--nobatch",
- "command",
- "--flag", "//my:target", "--flag2=42"};
+ const std::vector<std::string> args = {"bazel", "--host_jvm_args=MyParam",
+ "--nobatch", "command",
+ "--flag", "//my:target",
+ "--flag2=42"};
std::string error;
ASSERT_EQ(blaze_exit_code::SUCCESS,
option_processor_->ParseOptions(args, workspace_, cwd_, &error))
- << error;
+ << error;
ASSERT_EQ("", error);
+#if defined(_WIN32) || defined(__CYGWIN__)
+ ASSERT_EQ(size_t(2),
+ option_processor_->GetParsedStartupOptions()->host_jvm_args.size());
+ const std::string win_unix_root("-Dbazel.windows_unix_root=");
+ const std::string host_jvm_args_0 =
+ option_processor_->GetParsedStartupOptions()->host_jvm_args[0];
+ EXPECT_EQ(host_jvm_args_0.find(win_unix_root), 0) << host_jvm_args_0;
+ EXPECT_GT(host_jvm_args_0.size(), win_unix_root.size());
+ EXPECT_EQ("MyParam",
+ option_processor_->GetParsedStartupOptions()->host_jvm_args[1]);
+#else // ! (defined(_WIN32) || defined(__CYGWIN__))
ASSERT_EQ(size_t(1),
option_processor_->GetParsedStartupOptions()->host_jvm_args.size());
EXPECT_EQ("MyParam",
option_processor_->GetParsedStartupOptions()->host_jvm_args[0]);
+#endif // defined(_WIN32) || defined(__CYGWIN__)
EXPECT_FALSE(option_processor_->GetParsedStartupOptions()->batch);
EXPECT_EQ("command", option_processor_->GetCommand());
@@ -122,21 +133,32 @@
}
TEST_F(OptionProcessorTest, CanParseHelpCommandSurroundedByOtherArgs) {
- const std::vector<std::string> args =
- {"bazel",
- "--host_jvm_args=MyParam", "--nobatch",
- "help",
- "--flag", "//my:target", "--flag2=42"};
+ const std::vector<std::string> args = {"bazel", "--host_jvm_args=MyParam",
+ "--nobatch", "help",
+ "--flag", "//my:target",
+ "--flag2=42"};
std::string error;
ASSERT_EQ(blaze_exit_code::SUCCESS,
option_processor_->ParseOptions(args, workspace_, cwd_, &error))
- << error;
+ << error;
ASSERT_EQ("", error);
+#if defined(_WIN32) || defined(__CYGWIN__)
+ ASSERT_EQ(size_t(2),
+ option_processor_->GetParsedStartupOptions()->host_jvm_args.size());
+ const std::string win_unix_root("-Dbazel.windows_unix_root=");
+ const std::string host_jvm_args_0 =
+ option_processor_->GetParsedStartupOptions()->host_jvm_args[0];
+ EXPECT_EQ(host_jvm_args_0.find(win_unix_root), 0) << host_jvm_args_0;
+ EXPECT_GT(host_jvm_args_0.size(), win_unix_root.size());
+ EXPECT_EQ("MyParam",
+ option_processor_->GetParsedStartupOptions()->host_jvm_args[1]);
+#else // ! (defined(_WIN32) || defined(__CYGWIN__))
ASSERT_EQ(size_t(1),
option_processor_->GetParsedStartupOptions()->host_jvm_args.size());
EXPECT_EQ("MyParam",
option_processor_->GetParsedStartupOptions()->host_jvm_args[0]);
+#endif // defined(_WIN32) || defined(__CYGWIN__)
EXPECT_FALSE(option_processor_->GetParsedStartupOptions()->batch);
EXPECT_EQ("help", option_processor_->GetCommand());
@@ -181,12 +203,26 @@
<< error;
ASSERT_EQ("", error);
+#if defined(_WIN32) || defined(__CYGWIN__)
+ ASSERT_EQ(size_t(3),
+ option_processor_->GetParsedStartupOptions()->host_jvm_args.size());
+ const std::string win_unix_root("-Dbazel.windows_unix_root=");
+ const std::string host_jvm_args_0 =
+ option_processor_->GetParsedStartupOptions()->host_jvm_args[0];
+ EXPECT_EQ(host_jvm_args_0.find(win_unix_root), 0) << host_jvm_args_0;
+ EXPECT_GT(host_jvm_args_0.size(), win_unix_root.size());
+ EXPECT_EQ("MyParam",
+ option_processor_->GetParsedStartupOptions()->host_jvm_args[1]);
+ EXPECT_EQ("42",
+ option_processor_->GetParsedStartupOptions()->host_jvm_args[2]);
+#else // ! (defined(_WIN32) || defined(__CYGWIN__))
ASSERT_EQ(size_t(2),
option_processor_->GetParsedStartupOptions()->host_jvm_args.size());
EXPECT_EQ("MyParam",
option_processor_->GetParsedStartupOptions()->host_jvm_args[0]);
EXPECT_EQ("42",
option_processor_->GetParsedStartupOptions()->host_jvm_args[1]);
+#endif // defined(_WIN32) || defined(__CYGWIN__)
EXPECT_EQ("", option_processor_->GetCommand());