Fetching toolchains at build time. Cross compilation of the rust code with bazel. Part 4

Adding toolchain binaries directly int the repository isn't actually a good idea: the repository is getting bigger and bigger. It takes a while to check it out even in a the case, you want just to take a look.

So to add new toolchain, we will try to fetch it on "runtime", i.e. when we execute some bazel command.

Today we will add a toolchain, that compiles aarch64 binaries from macOS.

For fetching something from internet, bazel has an "http_archive" rule, we have already used it to fetch the rust_rules in the Part 1.

We can fetch arbitrary archives with this rule, in our case the toolchain tarball.

http_archive(
name = "aarch64-unknown-linux-musl",
sha256 = "4fbe95500c327828b437f380bb15851e9a8126cf95180fbf15b76b78e0322ae3",
urls = ["https://github.com/messense/homebrew-macos-cross-toolchains/releases/download/v11.2.0-1/aarch64-unknown-linux-musl-x86_64-darwin.tar.gz"],
strip_prefix = "aarch64-unknown-linux-musl",
)

This will fetch the data, untar it, and will remove the first layer of directory tree (aarch64-unknown-linux-musl).

To describe the toolchain, that we downloaded, we need to provide a build-file.

Let's copy the BUILD.bazel file from previous Parts into 'toolchains/thirdparty/aarch64-unknown-linux-musl' directory. But this time we name it somehow else, e.g. toolchain.BUILD.bazel. We do it because it is not a description of the package in our repository. We will use it to describe a package in the toolchain repository.

To attach this BUILD file to the archive (and therefore create a repository with rules), we pass it to the http_achive call.

http_archive(
... 
build_file = "//toolchains/thirdparty/aarch64-unknown-linux-musl:toolchain.BUILD.bazel",
)

If we try to build it, it won't work,  it fails with an error:

(10:03:58) ERROR: Analysis of target '//rust/pure_rust_example:hello_world' failed; build aborted: Unable to load package for //toolchains/thirdparty/aarc
h64-unknown-linux-musl:toolchain.BUILD.bazel: BUILD file not found in any of the following directories. Add a BUILD file to a directory to mark it as a pa
ckage.
- /Volumes/KINGSTON/bazel_cross_compilation/toolchains/thirdparty/aarch64-unknown-linux-musl

The solution is in the error message itself, we need to provide a BUILD file for the package, where the toolchain.BUILD.bazel is located. In our case it could be just an empty file:

% touch toolchains/thirdparty/aarch64-unknown-linux-musl/BUILD.bazel

We need to modify our new toolchain.BUILD.bazel file for new platform (rename everything to "aarch64....")
Don't forget to specify the execution restrictioins (it is only compatible with macOS).

toolchain(
name = "aarch64-linux-musl",
exec_compatible_with = [
"@platforms//os:macos",
"@platforms//cpu:x86_64",
],
target_compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:aarch64",
],
toolchain = ":aarch64-linux-musl_toolchain",
toolchain_type = "@rules_cc//cc:toolchain_type",
)

We register our toolchain in the WORKSPACE slightly different now.

register_toolchains(
"//toolchains/thirdparty/x86_64-unknown-linux-musl:x86_64-linux-musl",
"//toolchains/thirdparty/armv7-unknown-linux-musleabihf:armv7-unknown-linux-musleabihf",

"@aarch64-unknown-linux-musl//:aarch64-linux-musl",
)

Now we reference the new bazel repository, "aarch64-unknown-linux-musl" and the target " iaarch64-linux-musl" in its root repository. It is because we pulled the toolchain as an external repository now, instead of having it as part of our workspace.

We can try to compile our C++ example, and it fails because some includes, are not listed as dependencies.

(10:27:32) ERROR: /Volumes/KINGSTON/bazel_cross_compilation/cpp/hello_world/BUILD.bazel:1:10: Compiling cpp/hello_world/main.cpp failed: undeclared inclus
ion(s) in rule '//cpp/hello_world:hello-world':
this rule is missing dependency declarations for the following files included by 'cpp/hello_world/main.cpp':
'/private/var/tmp/_bazel_evgenypetrov/b3421e2abe4893fe7dfa5811f29c7f0c/external/aarch64-unknown-linux-musl/aarch64-unknown-linux-musl/sysroot/usr/includ
e/stdc-predef.h'
'/private/var/tmp/_bazel_evgenypetrov/b3421e2abe4893fe7dfa5811f29c7f0c/external/aarch64-unknown-linux-musl/aarch64-unknown-linux-musl/sysroot/usr/includ
e/wchar.h'
'/private/var/tmp/_bazel_evgenypetrov/b3421e2abe4893fe7dfa5811f29c7f0c/external/aarch64-unknown-linux-musl/aarch64-unknown-linux-musl/sysroot/usr/includ
e/features.h'

We have seen this error before, and need to list them as system includes in our toolchain in our 'toolchain.BUILD.bazel':

compile_flags = [
"-isystem", "external/aarch64-unknown-linux-musl/arch64-unknown-linux-musl/include",
"-isystem", "external/aarch64-unknown-linux-musl/aarch64-unknown-linux-musl/include/c++/11.2.0",
"-isystem", "external/aarch64-unknown-linux-musl/aarch64-unknown-linux-musl/include/c++/11.2.0/aarch64-unknown-linux-musl/",
"-isystem", "external/aarch64-unknown-linux-musl/aarch64-unknown-linux-musl/sysroot/usr/include",
],

Not that now these are located in "external/aarch64-unknown-linux-musl", where "external" is a common prefix for all extra repositories that we pull, and "aarch64-unknown-linux-musl" is a name of our repository (the name that we use in the WORKSPACE).

No it works for both C++ and rust, for rust we of cause need to add the target-triplet into the WORKSPACE file.

rust_register_toolchains(
edition = "2021",
extra_target_triples = [
"x86_64-unknown-linux-musl",
"armv7-unknown-linux-musleabihf",
"aarch64-unknown-linux-musl", # NEW
],
)

Now we can adapt the previous two toolchains to be fetched at runtime. These are the same steps.

The state of the code after all these modifications, is in the github.

 What we see now, is that adding new architectures, is mostly copying the file, and registering it in the WORKSPCE, so to simplify the process in the next steps we need to generate files dynamically based on list of the architectures we want to support. This would be the next step.


Comments

Popular posts from this blog

Compilation from macOS(Intel) to linux x86_64 finaly works. Cross compilation of the rust code with bazel. Part 2.

Cross compilation for ARM v7. Cross compilation of the rust code with bazel. Part 3.

Scaling number of supported platforms. Cross compilation of the rust code with bazel. Part 5