Repository: bazelbuild/bazel
Issue: Windows, C++: windows_cc_configure.bzl requires BAZEL_SH
Labels: type: bug
area-Windows
team-OSS

### Description of the problem / feature request:

`windows_cc_configure.bzl` breaks if `BAZEL_SH` is unset.

Setting `BAZEL_SH` to point to a fake Bash (`c:\src\fake-msys\usr\bin\bash.exe` -- a binary I wrote that just dumps its arguments and exits with 1) works around the problem.

### Bugs: what's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.

1. Check out Bazel's sources at https://github.com/bazelbuild/bazel/commit/2fda17d46088f2bb07b049fa35759002ea1dd5db
2. Comment out the line https://github.com/bazelbuild/bazel/blob/2fda17d46088f2bb07b049fa35759002ea1dd5db/src/main/cpp/blaze.cc#L1543
3. Build Bazel
4. Unset `BAZEL_SH` (with `set BAZEL_SH=`)
5. Run `bazel info` with the Bazel you built.

```
C:\src\tmp>c:\src\bazel\bazel-bin\src\bazel.exe info
WARNING: The following rc files are no longer being read, please transfer their contents or import their path into one of the standard rc files:
C:\Users\laszlocsomor/.bazelrc
Extracting Bazel installation...
Starting local Bazel server and connecting to it...
INFO: Invocation ID: baac9c71-b583-4c1a-9429-3ee26164b0f4
ERROR: in target '//external:cc_toolchain': no such package '@local_config_cc//': Traceback (most recent call last):
        File "C:/_bazel/zovul4l7/external/bazel_tools/tools/cpp/cc_configure.bzl", line 51
                configure_windows_toolchain(repository_ctx)
        File "C:/_bazel/zovul4l7/external/bazel_tools/tools/cpp/windows_cc_configure.bzl", line 344, in configure_windows_toolchain
                repository_ctx.template("CROSSTOOL", paths["@bazel_tools//..."], ...}": ""})
        File "C:/_bazel/zovul4l7/external/bazel_tools/tools/cpp/windows_cc_configure.bzl", line 361, in repository_ctx.template
                _get_escaped_windows_msys_crosstool_content(repository_ctx)
        File "C:/_bazel/zovul4l7/external/bazel_tools/tools/cpp/windows_cc_configure.bzl", line 35, in _get_escaped_windows_msys_crosstool_content
                get_env_var(repository_ctx, "BAZEL_SH")
        File "C:/_bazel/zovul4l7/external/bazel_tools/tools/cpp/lib_cc_configure.bzl", line 125, in get_env_var
                auto_configure_fail(("'%s' environment variable is n...))
        File "C:/_bazel/zovul4l7/external/bazel_tools/tools/cpp/lib_cc_configure.bzl", line 109, in auto_configure_fail
                fail(("\n%sAuto-Configuration Error:%...)))

Auto-Configuration Error: 'BAZEL_SH' environment variable is not set
```

### What operating system are you running Bazel on?

Windows 10

### If `bazel info release` returns "development version" or "(@non-git)", tell us how you built Bazel.

See repro instructions above.

Issue comments:
This is a bad first-time user experience: MSYS is required just to run `bazel info`. (And also to build C++ without any genrule dependencies.) See https://github.com/bazelbuild/bazel/issues/5254
The reason I care about this scenario, even though the repro requires commenting out code, is because I'd like to fix https://github.com/bazelbuild/bazel/issues/6462 by not erroring out if Bash is missing.
Understand, I will fix this.

Pull request review comments:
2018?
don't you have to enable extensions to use `::` for comments?
stale comment?
`exit /b 1` ?
Flipping the branches to get `if [condition] then [action] else [alternative]` is easier to read than `if not [condition] then [alternative] else [action]`.
Done
No, `::` is just like `#` in python
Thanks!
Sounds good
Indeed!

Patch that resolved the issue:
diff --git a/tools/cpp/msys_gcc_installation_error.bat b/tools/cpp/msys_gcc_installation_error.bat
new file mode 100644
index 00000000000000..25c35534f97533
--- /dev/null
+++ b/tools/cpp/msys_gcc_installation_error.bat
@@ -0,0 +1,23 @@
+:: Copyright 2018 The Bazel Authors. All rights reserved.
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::    http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+
+@echo OFF
+
+echo. 1>&2
+echo The target you are compiling requires MSYS gcc / MINGW gcc. 1>&2
+echo Bazel couldn't find gcc installation on your machine. 1>&2
+echo Please install MSYS gcc / MINGW gcc and set BAZEL_SH environment variable 1>&2
+echo. 1>&2
+
+exit /b 1
diff --git a/tools/cpp/vc_installation_error.bat.tpl b/tools/cpp/vc_installation_error.bat.tpl
index cb44b1413f77d7..b7965856cc9221 100644
--- a/tools/cpp/vc_installation_error.bat.tpl
+++ b/tools/cpp/vc_installation_error.bat.tpl
@@ -12,7 +12,6 @@
 :: See the License for the specific language governing permissions and
 :: limitations under the License.
 
-:: Invoke the python script under pydir with the same basename
 @echo OFF
 
 echo. 1>&2
@@ -22,4 +21,4 @@ echo Bazel couldn't find a valid Visual C++ build tools installation on your mac
 echo Please check your installation following https://docs.bazel.build/versions/master/windows.html#using 1>&2
 echo. 1>&2
 
-exit -1
+exit /b 1
diff --git a/tools/cpp/windows_cc_configure.bzl b/tools/cpp/windows_cc_configure.bzl
index 77d901fe533ab9..1beca5727eaf97 100644
--- a/tools/cpp/windows_cc_configure.bzl
+++ b/tools/cpp/windows_cc_configure.bzl
@@ -31,20 +31,24 @@ def _auto_configure_warning_maybe(repository_ctx, msg):
         auto_configure_warning(msg)
 
 def _get_escaped_windows_msys_crosstool_content(repository_ctx, use_mingw = False):
-    """Return the content of msys crosstool which is still the default CROSSTOOL on Windows."""
-    bazel_sh = get_env_var(repository_ctx, "BAZEL_SH").replace("\\", "/").lower()
+    """Return the content of msys crosstool."""
+    bazel_sh = get_env_var(repository_ctx, "BAZEL_SH", "", False).replace("\\", "/").lower()
     tokens = bazel_sh.rsplit("/", 1)
-    prefix = "mingw64" if use_mingw else "usr"
-    msys_root = None
+    msys_root = ""
     if tokens[0].endswith("/usr/bin"):
         msys_root = tokens[0][:len(tokens[0]) - len("usr/bin")]
     elif tokens[0].endswith("/bin"):
         msys_root = tokens[0][:len(tokens[0]) - len("bin")]
-    if not msys_root:
-        auto_configure_fail(
-            "Could not determine MSYS/Cygwin root from BAZEL_SH (%s)" % bazel_sh,
-        )
-    escaped_msys_root = escape_string(msys_root)
+    prefix = "mingw64" if use_mingw else "usr"
+    tool_path_prefix = escape_string(msys_root) + prefix
+    tool_path = {}
+
+    for tool in ["ar", "compat-ld", "cpp", "dwp", "gcc", "gcov", "ld", "nm", "objcopy", "objdump", "strip"]:
+        if msys_root:
+            tool_path[tool] = tool_path_prefix + "/bin/" + tool
+        else:
+            tool_path[tool] = "msys_gcc_installation_error.bat"
+
     return (((
                 '   abi_version: "local"\n' +
                 '   abi_libc_version: "local"\n' +
@@ -56,23 +60,23 @@ def _get_escaped_windows_msys_crosstool_content(repository_ctx, use_mingw = Fals
                 '   target_cpu: "x64_windows"\n' +
                 '   target_system_name: "local"\n'
             ) if not use_mingw else "") +
-            '   tool_path { name: "ar" path: "%s%s/bin/ar" }\n' % (escaped_msys_root, prefix) +
-            '   tool_path { name: "compat-ld" path: "%s%s/bin/ld" }\n' % (escaped_msys_root, prefix) +
-            '   tool_path { name: "cpp" path: "%s%s/bin/cpp" }\n' % (escaped_msys_root, prefix) +
-            '   tool_path { name: "dwp" path: "%s%s/bin/dwp" }\n' % (escaped_msys_root, prefix) +
-            '   tool_path { name: "gcc" path: "%s%s/bin/gcc" }\n' % (escaped_msys_root, prefix) +
+            '   tool_path { name: "ar" path: "%s" }\n' % tool_path["ar"] +
+            '   tool_path { name: "compat-ld" path: "%s" }\n' % tool_path["ld"] +
+            '   tool_path { name: "cpp" path: "%s" }\n' % tool_path["cpp"] +
+            '   tool_path { name: "dwp" path: "%s" }\n' % tool_path["dwp"] +
+            '   tool_path { name: "gcc" path: "%s" }\n' % tool_path["gcc"] +
+            '   tool_path { name: "gcov" path: "%s" }\n' % tool_path["gcov"] +
+            '   tool_path { name: "ld" path: "%s" }\n' % tool_path["ld"] +
+            '   tool_path { name: "nm" path: "%s" }\n' % tool_path["nm"] +
+            '   tool_path { name: "objcopy" path: "%s" }\n' % tool_path["objcopy"] +
+            '   tool_path { name: "objdump" path: "%s" }\n' % tool_path["objdump"] +
+            '   tool_path { name: "strip" path: "%s" }\n' % tool_path["strip"] +
+            ((' cxx_builtin_include_directory: "%s/include"\n' % tool_path_prefix) if msys_root else "") +
             '   artifact_name_pattern { category_name: "executable" prefix: "" extension: ".exe"}\n' +
             '   cxx_flag: "-std=gnu++0x"\n' +
             '   linker_flag: "-lstdc++"\n' +
-            '   cxx_builtin_include_directory: "%s%s/"\n' % (escaped_msys_root, prefix) +
-            '   tool_path { name: "gcov" path: "%s%s/bin/gcov" }\n' % (escaped_msys_root, prefix) +
-            '   tool_path { name: "ld" path: "%s%s/bin/ld" }\n' % (escaped_msys_root, prefix) +
-            '   tool_path { name: "nm" path: "%s%s/bin/nm" }\n' % (escaped_msys_root, prefix) +
-            '   tool_path { name: "objcopy" path: "%s%s/bin/objcopy" }\n' % (escaped_msys_root, prefix) +
             '   objcopy_embed_flag: "-I"\n' +
             '   objcopy_embed_flag: "binary"\n' +
-            '   tool_path { name: "objdump" path: "%s%s/bin/objdump" }\n' % (escaped_msys_root, prefix) +
-            '   tool_path { name: "strip" path: "%s%s/bin/strip" }' % (escaped_msys_root, prefix) +
             '   feature { name: "targets_windows" implies: "copy_dynamic_libraries_to_binary" enabled: true }' +
             '   feature { name: "copy_dynamic_libraries_to_binary" }')
 
@@ -264,9 +268,12 @@ def configure_windows_toolchain(repository_ctx):
         "@bazel_tools//tools/cpp:CROSSTOOL",
         "@bazel_tools//tools/cpp:CROSSTOOL.tpl",
         "@bazel_tools//tools/cpp:vc_installation_error.bat.tpl",
+        "@bazel_tools//tools/cpp:msys_gcc_installation_error.bat",
     ])
 
     repository_ctx.symlink(paths["@bazel_tools//tools/cpp:BUILD.static.windows"], "BUILD")
+    repository_ctx.symlink(paths["@bazel_tools//tools/cpp:msys_gcc_installation_error.bat"],
+                           "msys_gcc_installation_error.bat")
 
     vc_path = find_vc_path(repository_ctx)
     missing_tools = None


Test patch: