bash: Add a toolchain for local Bash. Bazel automatically detects the local Bash and creates a custom toolchain rule for it. Later, rules that use Bash will require this toolchain and retrieve Bash's path from it instead of relying on hardcoded paths or the `--shell_executable` flag. See https://github.com/bazelbuild/bazel/issues/4319 Change-Id: Idd8242a20d202b1f5a56cddac95b625c6c08ede9 Closes #4980. Change-Id: Ic2406a4da260b284e15852070d58472ca18340af PiperOrigin-RevId: 193022708
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java index 8594e633..865a521 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java
@@ -18,6 +18,7 @@ import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.bazel.rules.cpp.BazelCppRuleClasses; +import com.google.devtools.build.lib.bazel.rules.sh.BazelShRuleClasses; import com.google.devtools.build.lib.rules.cpp.FdoSupportFunction; import com.google.devtools.build.lib.rules.cpp.FdoSupportValue; import com.google.devtools.build.lib.runtime.BlazeModule; @@ -41,6 +42,8 @@ ResourceFileLoader.loadResource(BazelCppRuleClasses.class, "cc_configure.WORKSPACE")); builder.addWorkspaceFileSuffix( ResourceFileLoader.loadResource(BazelRulesModule.class, "xcode_configure.WORKSPACE")); + builder.addWorkspaceFileSuffix( + ResourceFileLoader.loadResource(BazelShRuleClasses.class, "sh_configure.WORKSPACE")); } catch (IOException e) { throw new IllegalStateException(e); }
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/sh_configure.WORKSPACE b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/sh_configure.WORKSPACE new file mode 100644 index 0000000..c41037c --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/sh_configure.WORKSPACE
@@ -0,0 +1,2 @@ +load("@bazel_tools//tools/sh:sh_configure.bzl", "sh_configure") +sh_configure()
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoaderTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoaderTest.java index 9fee906..b31f2ac 100644 --- a/src/test/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoaderTest.java +++ b/src/test/java/com/google/devtools/build/lib/skyframe/packages/BazelPackageLoaderTest.java
@@ -70,6 +70,11 @@ tools.getRelative("tools/osx/xcode_configure.bzl"), "def xcode_configure(*args, **kwargs):", " pass"); + FileSystemUtils.writeIsoLatin1(tools.getRelative("tools/sh/BUILD"), ""); + FileSystemUtils.writeIsoLatin1( + tools.getRelative("tools/sh/sh_configure.bzl"), + "def sh_configure(*args, **kwargs):", + " pass"); } private void fetchExternalRepo(RepositoryName externalRepo) {
diff --git a/src/test/shell/integration/discard_graph_edges_test.sh b/src/test/shell/integration/discard_graph_edges_test.sh index b64a62b..d2da4cf 100755 --- a/src/test/shell/integration/discard_graph_edges_test.sh +++ b/src/test/shell/integration/discard_graph_edges_test.sh
@@ -231,7 +231,7 @@ package_count="$(extract_histogram_count "$histo_file" \ 'devtools\.build\.lib\..*\.Package$')" # A few packages aren't cleared. - [[ "$package_count" -le 8 ]] \ + [[ "$package_count" -le 10 ]] \ || fail "package count $package_count too high" glob_count="$(extract_histogram_count "$histo_file" "GlobValue$")" [[ "$glob_count" -le 1 ]] \
diff --git a/tools/BUILD b/tools/BUILD index 21a95fc..0b5835a 100644 --- a/tools/BUILD +++ b/tools/BUILD
@@ -31,6 +31,7 @@ "//tools/test:srcs", "//tools/python:srcs", "//tools/runfiles:srcs", + "//tools/sh:srcs", "//tools/whitelists:srcs", "//tools/zip:srcs", ], @@ -62,6 +63,7 @@ "//tools/test:srcs", "//tools/osx/crosstool:srcs", "//tools/osx:srcs", + "//tools/sh:embedded_tools", "//tools/whitelists:srcs", "//tools/zip:srcs", ],
diff --git a/tools/sh/BUILD b/tools/sh/BUILD new file mode 100644 index 0000000..66f710a --- /dev/null +++ b/tools/sh/BUILD
@@ -0,0 +1,23 @@ +package(default_visibility = ["//visibility:private"]) + +filegroup( + name = "srcs", + srcs = glob( + ["**"], + exclude = [ + "*~", + ".*", + ], + ), + visibility = ["//tools:__pkg__"], +) + +filegroup( + name = "embedded_tools", + srcs = [ + "BUILD.tools", + "sh_configure.bzl", + "sh_toolchain.bzl", + ], + visibility = ["//tools:__pkg__"], +)
diff --git a/tools/sh/BUILD.tools b/tools/sh/BUILD.tools new file mode 100644 index 0000000..d5d9d48 --- /dev/null +++ b/tools/sh/BUILD.tools
@@ -0,0 +1,6 @@ +exports_files(["sh_toolchain.bzl", "sh_configure.bzl"]) + +toolchain_type( + name = "toolchain_type", + visibility = ["//visibility:public"], +)
diff --git a/tools/sh/sh_configure.bzl b/tools/sh/sh_configure.bzl new file mode 100644 index 0000000..7ba056c --- /dev/null +++ b/tools/sh/sh_configure.bzl
@@ -0,0 +1,94 @@ +# 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. +"""Configure the shell toolchain on the local machine.""" + +def _is_windows(repository_ctx): + """Returns true if the host OS is Windows.""" + return repository_ctx.os.name.startswith("windows") + +def _sh_config_impl(repository_ctx): + """sh_config rule implementation. + + Detects the path of the shell interpreter on the local machine and + stores it in a sh_toolchain rule. + + Args: + repository_ctx: the repository rule context object + """ + sh_path = repository_ctx.os.environ.get("BAZEL_SH") + if not sh_path: + if _is_windows(repository_ctx): + sh_path = repository_ctx.which("bash.exe") + if sh_path: + # When the Windows Subsystem for Linux is installed there's a + # bash.exe under %WINDIR%\system32\bash.exe that launches Ubuntu + # Bash which cannot run native Windows programs so it's not what + # we want. + windir = repository_ctx.os.environ.get("WINDIR") + if windir and sh_path.startswith(windir): + sh_path = None + else: + sh_path = repository_ctx.which("bash") + if not sh_path: + sh_path = repository_ctx.which("sh") + + if not sh_path: + sh_path = "" + + if sh_path and _is_windows(repository_ctx): + sh_path = sh_path.replace("\\", "/") + + os_label = None + if _is_windows(repository_ctx): + os_label = "@bazel_tools//platforms:windows" + elif repository_ctx.os.name.startswith("linux"): + os_label = "@bazel_tools//platforms:linux" + elif repository_ctx.os.name.startswith("mac"): + os_label = "@bazel_tools//platforms:osx" + else: + fail("Unknown OS") + + repository_ctx.file("BUILD", """ +load("@bazel_tools//tools/sh:sh_toolchain.bzl", "sh_toolchain") + +sh_toolchain( + name = "local_sh", + path = "{sh_path}", + visibility = ["//visibility:public"], +) + +toolchain( + name = "local_sh_toolchain", + exec_compatible_with = [ + "@bazel_tools//platforms:x86_64", + "{os_label}", + ], + toolchain = ":local_sh", + toolchain_type = "@bazel_tools//tools/sh:toolchain_type", +) +""".format(sh_path = sh_path, os_label = os_label)) + +sh_config = repository_rule( + environ = [ + "WINDIR", + "PATH", + ], + local = True, + implementation = _sh_config_impl, +) + +def sh_configure(): + """Detect the local shell interpreter and register its toolchain.""" + sh_config(name = "local_config_sh") + native.register_toolchains("@local_config_sh//:local_sh_toolchain")
diff --git a/tools/sh/sh_toolchain.bzl b/tools/sh/sh_toolchain.bzl new file mode 100644 index 0000000..ddd7de7 --- /dev/null +++ b/tools/sh/sh_toolchain.bzl
@@ -0,0 +1,26 @@ +# 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. +"""Define a toolchain rule for the shell.""" + +def _sh_toolchain_impl(ctx): + """sh_toolchain rule implementation.""" + return [platform_common.ToolchainInfo(path = ctx.attr.path)] + +sh_toolchain = rule( + attrs = { + # Absolute path to the shell interpreter. + "path": attr.string(), + }, + implementation = _sh_toolchain_impl, +)