'Installing different pre-requisites in bazel build depending on architecture?
I want to make a build for a C++ project so that developers can seamlessly build both in MacOS and Linux, but they need different pre-requisites.
Can I configure Bazel to run different commands depending on the architecture, as a pre-requisite to compiling C++ files?
Solution 1:[1]
You certainly can, there are two approaches I will suggest.
Approach 1 (recommended)
The best way to do this is to include all of your deps for each arch/os in your WORKSPACE file e.g.
# WORKSPACE
http_archive(
name = "foo_repo_mac",
# ...
)
http_archive(
name = "foo_repo_linux",
# ...
)
NOTE: While the example here uses http_archive, this approach works with other repository rules as well e.g. local_repository (for system deps), git_repository (for git deps) etc.
Then depend on your mac/linux version os these libs using a select statement e.g.
# //:BUILD.bazel
cc_library(
name = "foo_cross_platform",
deps = select({
"@platforms//os:macos": ["@foo_repo_mac//:foo"],
"@platforms//os:linux": ["@foo_repo_linux//:foo"],
}) + ["//other:deps"],
)
Now what happens here is that when you build the target //:foo_cross_platform Bazel will first evaluate the deps in the select statement. Let's say we are running on linux it will select "@foo_repo_linux//:foo" as a dep. Now that Bazel knows there is a dependency in an external repository it will go ahead and download the @foo_repo_linux repository. But because there is no dependency in @foo_repo_macos it won't download/configure that dependency. So in the case of a build on Linux this will work;
bazel build //...
bazel build //:foo_cross_platform
However it is unlikely that running running the following on linux would work.
bazel build @foo_repo_macos//:foo
By default you can select based on cpu/os/distro. A full list of the configurations that are included in default Bazel are listed here. For more complex configurable builds take a look over the Bazel docs on configuration.
Approach 2 (not recommended)
If the approach 1 does not meet your needs there is a second approach that you could take and that is to write your own [repository_rule] (https://docs.bazel.build/versions/main/skylark/repository_rules.html), that uses the repository_ctx.os field with a skylark if statement. e.g.
# my_custom_repository.bzl
def _my_custom_repository_rule_impl(rctx):
if rctx.os.name == "linux":
rctx.download_and_extract(
url = "http//:www.my_linux_dep.com/foo",
#...
)
elif rctx.os.name == "macos":
rctx.download_and_extract(
url = "http//:www.my_macos_dep.com/foo",
#...
)
else:
fail("No dependency for this os")
# ... Generate a BUILD.bazel file etc.
my_custom_repository = repository_rule(_my_custom_repository_rule_impl)
Then add the following to your WORKSPACE;
# WORKSPACE
load("//:my_custom_repository.bzl", "my_custom_repository")
my_custom_repository(
name = "foo"
)
Then depend on it directly in your build file (This depends on how you generate your BUILD.bazel file).
The reason I don't recommend this approach is that, repository_ctx.os.name is not particularly stable and in general the configurations using selects is far more expressive.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | silvergasp |
