Make Bazel Work in MacOS for Iceoryx2¶
In iceoryx2, it uses bazel
to build C/C++ bindings. Hence, they want to use bazel for rust for a better unification in iceoryx2.
Currently foreign_cc is used to build the C binding and cc_library to build the C++ bindings. In order to fully exhaust the capabilities of bazel, the C binding and therefore the Rust code should be build with rules_rust.
When I tried it, I found it doesn't work in my MacOS. This blog records some knowledge when I learned bazel and how I solved the problem. It doesn't talk about why we use bazel in a rust project.
Blockers when I learned Bazel¶
Bazel looks like a light-weight nix, when I first saw it. But well, I didn't master nix as well:( So it's syntax took me a lot of time to learn. The gpt-4o and claude-3.5 did quite bad for bazel questions. It's worthy reading the bazel concept guides.
The label notation such as @blabla//a/b/c
, //a/b/c
and //a/b/c:d/f
is quite confusing at beginning.
The single-@
notates an apparent repo, which depends on the context. You can use this to access the repos you defined(usually they're defined by http_archive or git_repository).
Problems and how I solve them¶
Download different binary for different OS¶
I was amazing that bazel doesn't support automatically selection based on OS. However, it will strictly follow the configuration and then macos cannot recognize the downloaded binary for linux.
maybe(
name = "bindgen",
repo_rule = http_archive,
sha256 = "b7e2321ee8c617f14ccc5b9f39b3a804db173ee217e924ad93ed16af6bc62b1d",
strip_prefix = "bindgen-cli-x86_64-unknown-linux-gnu",
urls = ["https://github.com/rust-lang/rust-bindgen/releases/download/v0.69.5/bindgen-cli-x86_64-unknown-linux-gnu.tar.xz"],
build_file_content = """
filegroup(
name = "bindgen-cli",
srcs = ["bindgen"],
visibility = ["//visibility:public"],
)
""",
)
To fix this, we need to allow bazel download different bindgen
based on OS so another target is required.
maybe(
name = "bindgen-macos",
repo_rule = http_archive,
strip_prefix = "bindgen-cli-aarch64-apple-darwin",
urls = ["https://github.com/rust-lang/rust-bindgen/releases/download/v0.69.5/bindgen-cli-aarch64-apple-darwin.tar.xz"],
build_file_content = """
filegroup(
name = "bindgen-cli",
srcs = ["bindgen"],
visibility = ["//visibility:public"],
)
""",
)
Now the target bindgen-cli
could be accessed by @bindgen-macos//:bindgen-cli
and @bindgen//:bindgen-cli
. When we use the bindgen
, we need to define an alias to select so the user won't care about the underlying downloading tool.
alias(
name = "bindgen-cli",
actual = select({
"@bazel_tools//src/conditions:darwin": "@bindgen-macos//:bindgen-cli",
"//conditions:default": "@bindgen//:bindgen-cli",
}),
)
genrule(
name = "iceoryx2-pal-posix-bindgen",
srcs = [
"src/c/posix.h",
],
outs = ["posix_generated.rs"],
cmd = "$(execpath :bindgen-cli) --use-core --blocklist-type max_align_t $(location src/c/posix.h) --output $(OUTS)",
tools = [":bindgen-cli"],
)
Build cbindgen from source¶
Unlike bindgen, cbindgen only provides a binary release for ubuntu. To support cbindgen on macOS, we need to build the cbindgen from source. You can view rust_binary example for more details.
1. download source code by http_archive¶
rust_repositories()
http_archive(
name = "cbindgen_source",
urls = ["https://github.com/mozilla/cbindgen/archive/refs/tags/0.26.0.tar.gz"],
strip_prefix = "cbindgen-0.26.0",
build_file_content = """
filegroup(
name = "srcs",
srcs = glob(["src/**/*.rs", "build.rs", "Cargo.toml", "Cargo.lock"]),
visibility = ["//visibility:public"],
)
exports_files(["Cargo.toml", "Cargo.lock"], visibility = ["//visibility:public"])
"""
)
2. define and download deps by crates_repository¶
crates_repository is a rule for defining and downloading Rust dependencies (crates). There is no automatically downloading when building in bazel, so we need to define the deps manually.
load("@rules_rust//rust:defs.bzl", "rust_library")
load("@rules_rust//crate_universe:defs.bzl", "crates_repository")
crates_repository(
name = "cbindgen_deps",
cargo_lockfile = "@cbindgen_source//:Cargo.lock",
manifests = ["@cbindgen_source//:Cargo.toml"],
)
load("@cbindgen_deps//:defs.bzl", cbindgen_deps = "crate_repositories")
cbindgen_deps()
3. build binary by rust_binary¶
After downloading the source and its deps, we can use rust_binary
to build. Here we need to fill the deps
manually by checking the project's Cargo.toml
.
load("@rules_rust//rust:defs.bzl", "rust_binary")
# load("@cbindgen_source//:BUILD.bazel", "srcs")
rust_binary(
name = "cbindgen-cli",
srcs = [
"@cbindgen_source//:srcs",
],
data = [
"@cbindgen_source//:Cargo.toml",
"@cbindgen_source//:Cargo.lock",
],
edition = "2018",
deps = [
"@cbindgen_deps//:clap",
"@cbindgen_deps//:indexmap",
"@cbindgen_deps//:log",
"@cbindgen_deps//:serde",
"@cbindgen_deps//:serde_json",
"@cbindgen_deps//:tempfile",
"@cbindgen_deps//:toml",
"@cbindgen_deps//:proc-macro2",
"@cbindgen_deps//:quote",
"@cbindgen_deps//:heck",
"@cbindgen_deps//:syn",
],
)