Reputation: 13
How can I configure Bazel to pick one toolchain over the other? I am okay with defining which toolchain to use via command-line argument or specifying which should be used in a specific target.
There are currently two toolchains being defined in my WORKSPACE file. I have two Python toolchains. One of them builds Python from source and includes it in the executable .zip
output, and the other one does not.
When building, the toolchain that gets used is always the first toolchain which is registered. In this case, python3_tooolchain
is used even though the build target imports requirement
from hermetic_python3_toolchain
.
# WORKSPACE
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@rules_python//python:pip.bzl", "pip_install")
http_archive(
name = "rules_python",
url = "https://github.com/bazelbuild/rules_python/releases/download/0.5.0/rules_python-0.5.0.tar.gz",
sha256 = "cd6730ed53a002c56ce4e2f396ba3b3be262fd7cb68339f0377a45e8227fe332",
)
# Non-hermetic toolchain
register_toolchains("//src:python3_toolchain")
pip_install(
quiet = False,
name = "python_dependencies",
requirements = "//:requirements.txt",
python_interpreter = "/usr/bin/python3"
)
load("@python_dependencies//:requirements.bzl", "requirement")
# Hermetic toolchain
_py_configure = """
if [[ "$OSTYPE" == "darwin"* ]]; then
./configure --prefix=$(pwd)/bazel_install --with-openssl=$(brew --prefix openssl)
else
./configure --prefix=$(pwd)/bazel_install
fi
"""
http_archive(
name = "hermetic_interpreter",
urls = ["https://www.python.org/ftp/python/3.11.0/Python-3.11.0.tar.xz"],
sha256 = "a57dc82d77358617ba65b9841cee1e3b441f386c3789ddc0676eca077f2951c3",
strip_prefix = "Python-3.11.0",
patch_cmds = [
"mkdir $(pwd)/bazel_install",
_py_configure,
"make",
"make install",
"ln -s bazel_install/bin/python3 python_bin",
],
build_file_content = """
exports_files(["python_bin"])
filegroup(
name = "files",
srcs = glob(["bazel_install/**"], exclude = ["**/* *"]),
visibility = ["//visibility:public"],
)
""",
)
pip_install(
name = "hermetic_python3_dependencies",
requirements = "//:requirements.txt",
python_interpreter_target = "@hermetic_interpreter//:python_bin",
)
load("@hermetic_python3_dependencies//:requirements.bzl", "requirement")
load("@rules_python//python:defs.bzl", "py_binary")
load("@rules_python//python:defs.bzl", "py_library")
register_toolchains("//src:hermetic_python3_toolchain")
# src/BUILD
load("@bazel_tools//tools/python:toolchain.bzl", "py_runtime_pair")
# Non-hermetic toolchain
py_runtime(
name = "python3_runtime",
interpreter_path = "/usr/bin/python3",
python_version = "PY3",
visibility = ["//visibility:public"],
)
py_runtime_pair(
name = "python3_runtime_pair",
py2_runtime = None,
py3_runtime = ":python3_runtime",
)
toolchain(
name = "python3_toolchain",
toolchain = ":python3_runtime_pair",
toolchain_type = "@bazel_tools//tools/python:toolchain_type",
)
# Hermetic toolchain
py_runtime(
name = "hermetic_python3_runtime",
files = ["@hermetic_interpreter//:files"],
interpreter = "@hermetic_interpreter//:python_bin",
python_version = "PY3",
visibility = ["//visibility:public"],
)
py_runtime_pair(
name = "hermetic_python3_runtime_pair",
py2_runtime = None,
py3_runtime = ":hermetic_python3_runtime",
)
toolchain(
name = "hermetic_python3_toolchain",
toolchain = ":hermetic_python3_runtime_pair",
toolchain_type = "@bazel_tools//tools/python:toolchain_type",
)
package(default_visibility = ["//visibility:public"])
# /src/some_tool/BUILD
load("@hermetic_python3_dependencies//:requirements.bzl", "requirement") # Can load this rule from either `hermetic_python3_dependencies` or `python3_dependencies`, but does not seem to make a difference
py_binary(
name = "some-tool",
main = "some_tool.py",
srcs = ["some_tool_file.py"],
python_version = "PY3",
srcs_version = "PY3",
deps = [
requirement("requests"),
"//src/common/some-library:library",
]
)
package(default_visibility = ["//visibility:public"])
Upvotes: 1
Views: 4735
Reputation: 373
Consider upgrading rules_python
, as that ruleset includes a hermetic python toolchain since https://github.com/bazelbuild/rules_python/releases/tag/0.7.0.
If that is not an option:
Currently you are registering two toolchains in your WORKSPACE.bazel
file and bazel
will use its toolchain resolution to pick one of them. You can debug that resolution with the --toolchain_resolution_debug=regex
flag to see what is going on.
If you want to force the entire build to use one of the toolchains, remove registering the toolchains from the WORKSPACE.bazel
file and create a .bazelrc
:
build:hermetic_python --extra_toolchains=//src:hermetic_python3_toolchain
build:system_python --extra_toolchains=//src:python3_toolchain
Now you can switch between these toolchains by using bazel build --config=hermetic_python
or bazel build --config=system_python
.
Beware however, that this does not influence which of the python toolchains was used to run the pip_parse()
. You need to take extra care from which you load the requirement()
function. Simply by load()
ing the function you force the evaluation of the pip_parse()
and therefor the fetching/compilation of the corresponding python interpreter.
Upvotes: 1