From 2ec0250b5fe71fbbd8373e84002c3a16993bf5cc Mon Sep 17 00:00:00 2001 From: Laszlo Csomor Date: Mon, 9 Apr 2018 11:00:44 +0200 Subject: [PATCH] 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 --- .../build/lib/bazel/rules/tools.WORKSPACE | 3 + tools/bash/BUILD | 6 +- tools/bash/BUILD.tools | 6 ++ tools/bash/bash_def.bzl | 75 +++++++++++++++++++ 4 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 tools/bash/BUILD.tools create mode 100644 tools/bash/bash_def.bzl diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/tools.WORKSPACE b/src/main/java/com/google/devtools/build/lib/bazel/rules/tools.WORKSPACE index 49f1b5d85a1f3e..06879176e7708f 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/tools.WORKSPACE +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/tools.WORKSPACE @@ -1,3 +1,6 @@ local_repository(name = "bazel_tools", path = __embedded_dir__ + "/embedded_tools") bind(name = "cc_toolchain", actual = "@bazel_tools//tools/cpp:default-toolchain") bind(name = "java_toolchain", actual = "%java_toolchain%") + +load("@bazel_tools//tools/bash:bash_def.bzl", "bash_repositories") +bash_repositories() diff --git a/tools/bash/BUILD b/tools/bash/BUILD index 2d0c314e460eee..abad770c878a87 100644 --- a/tools/bash/BUILD +++ b/tools/bash/BUILD @@ -16,6 +16,10 @@ filegroup( filegroup( name = "embedded_tools", - srcs = ["//tools/bash/runfiles:embedded_tools"], + srcs = [ + "BUILD.tools", + "bash_def.bzl", + "//tools/bash/runfiles:embedded_tools", + ], visibility = ["//tools:__pkg__"], ) diff --git a/tools/bash/BUILD.tools b/tools/bash/BUILD.tools new file mode 100644 index 00000000000000..640cfad81e8b39 --- /dev/null +++ b/tools/bash/BUILD.tools @@ -0,0 +1,6 @@ +exports_files(["bash_def.bzl"]) + +toolchain_type( + name = "bash_toolchain_type", + visibility = ["//visibility:public"], +) diff --git a/tools/bash/bash_def.bzl b/tools/bash/bash_def.bzl new file mode 100644 index 00000000000000..628226a4045436 --- /dev/null +++ b/tools/bash/bash_def.bzl @@ -0,0 +1,75 @@ +def _bash_toolchain_impl(ctx): + return [platform_common.ToolchainInfo(path = ctx.attr.path)] + +def _is_windows(repository_ctx): + return repository_ctx.os.name.startswith("windows") + +def _bash_config_impl(repository_ctx): + bash_path = repository_ctx.os.environ.get("BAZEL_SH") + if not bash_path: + if _is_windows(repository_ctx): + bash_path = repository_ctx.which("bash.exe") + if bash_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 bash_path.startswith(windir): + bash_path = None + else: + bash_path = repository_ctx.which("bash") + + if not bash_path: + bash_path = "" + + if bash_path and _is_windows(repository_ctx): + bash_path = bash_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/bash:bash_def.bzl", "bash_toolchain") + +bash_toolchain( + name = "local_bash", + path = "{bash_path}", + visibility = ["//visibility:public"], +) + +toolchain( + name = "local_bash_toolchain", + exec_compatible_with = [ + "@bazel_tools//platforms:x86_64", + "{os_label}", + ], + toolchain = ":local_bash", + toolchain_type = "@bazel_tools//tools/bash:bash_toolchain_type", +) +""".format(bash_path = bash_path, os_label = os_label)) + +bash_toolchain = rule( + attrs = {"path": attr.string()}, + implementation = _bash_toolchain_impl, +) + +bash_config = repository_rule( + environ = [ + "WINDIR", + "PATH", + ], + local = True, + implementation = _bash_config_impl, +) + +def bash_repositories(): + """Detect the local Bash and register it as a toolchain.""" + bash_config(name = "local_config_bash") + native.register_toolchains("@local_config_bash//:local_bash_toolchain")