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

This is the third part of the series "Cross compilation of rust with bazel". Previous topics:

Next challenge is to cross-compile for armv7.


This part we did together with my colleague Dima and we did it on linux.

First thing, that we need is to add the target platform into our root BUILD.bazel

platform(
name = "armv7-linux-musleabihf",
constraint_values = [
"@platforms//cpu:armv7",
"@platforms//os:linux",
],
)

And rust toolchain for the new target in the WORKSPACE file:

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


And as we remember from the part 1, we need to add a C++ toolchain as well.

We need to do something similar to what we did for the macOS->Linux crosscompilation toolchain in Part 2.

  • get the C++ toolchain binary and sysroot
  • add toolchain definition to bazel BUILD.bazel files.

Our host system is Linux now, so we can get a toolchain from the cross compilation docker files.
We just run a container ghcr.io/cross-rs/armv7-unknown-linux-musleabihf:edge and copy the content of /usr/local directory from there into our repo.

Why /usr/local? Because after looking onto content of this container we figured out that it contains all tools that we need, and the structure of the directory is similar to the toolchain from the Part 2

Now we can copy the the BUILD.bazel file from the other toolchain, and adjust it to for the new architecture:

load("@bazel_tools//tools/cpp:unix_cc_toolchain_config.bzl", "cc_toolchain_config")
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")

BIN_PREFIX = "bin/arm-linux-musleabihf-"

cc_toolchain_config(
name = "armv7-linux-musleabihf_toolchain_config",
abi_libc_version = "unknown",
abi_version = "unknown",
compiler = "gcc",
cpu = "armv7",
host_system_name = "local",
target_libc = "unknown",
target_system_name = "armv7-linux-musleabihf",
toolchain_identifier = "armv7-linux-musleabihf",
tool_paths = {
"ar": BIN_PREFIX + "ar",
"cpp": BIN_PREFIX + "g++",
"gcc": BIN_PREFIX + "gcc",
"dwp": BIN_PREFIX + "dwp",
"gcov": BIN_PREFIX + "gcov",
"ld": BIN_PREFIX + "ld",
"nm": BIN_PREFIX + "nm",
"objcopy": BIN_PREFIX + "objcopy",
"objdump": BIN_PREFIX + "objdump",
"strip": BIN_PREFIX + "strip",
"llvm-cov": BIN_PREFIX + "llvm-cov",
},
compile_flags = [
"-isystem", "toolchains/thirdparty/armv7-unknown-linux-musleabihf/armv7-linux-musleabihf/include/",
],
link_libs = [
"-lstdc++",
],
)

filegroup(
name = "all",
srcs = glob(["**/**"]),
)

cc_toolchain(
name = "armv7-linux-musleabihf_toolchain",
# We tell the toolchain, that for every command, all the files are needed
# This is not ideal, but simple.
all_files = ":all",
compiler_files = ":all",
dwp_files = ":all",
linker_files = ":all",
objcopy_files = ":all",
strip_files = ":all",
toolchain_config = ":armv7-linux-musleabihf_toolchain_config",
)

toolchain(
name = "armv7-unknown-linux-musleabihf",
target_compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:armv7",
],
toolchain = ":armv7-linux-musleabihf_toolchain",
toolchain_type = "@rules_cc//cc:toolchain_type",
)

And register the toolchain in the workspace:

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

Now we can test it:
$ bazel build \
    //rust/pure_rust_example:hello_world \
    --platforms=//:armv7-linux-musleabihf \
    --incompatible_enable_cc_toolchain_resolution

Unfortunatelly, it fails with error:
error: could not exec the linker `toolchains/thirdparty/x86_64-unknown-linux-musl/bin/x86_64-unknown-linux-musl-gcc`

But wait, isn't it part of our toolchain, for crosscompiling from macOS to linux? Why it is used here, if we want to compile for ARM?

If we look at the long command that actually failed. Then we can see that it was building some "process_wrapper" tool, apparently needed for building rust with bazel.
Since our current system is x86_64-linux, the toolchain resolved for it is actually the toolchain, that we used in int the previous chapter. To resolve it we need to specify, that our old toolchain is only compatible with mac os:

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

And now it builds.

Target //rust/pure_rust_example:hello_world up-to-date:
  bazel-bin/rust/pure_rust_example/hello_world

We can copy the result to some host with armv7 architecture and ensure that it works. I've tested it on one of my development boards and it does.

The result of this chapter corresponds to this git revision.

PS

There was a couple of things, that I've noticed while doing this part:

  • the linux toolchain has files with different only in the upper/lower case. This means on macOS they may ovewrite each other. Because mac OS by default has case-insensitive file names.
  • the linux toolchain is huge and has huge files, and it doesn't work with github without git-lfs. It is not a great idea to store the toochain in the repository.
     




Comments

Popular posts from this blog

Левиафан

Key West, FL

How prototype Arduino-based fan controller and break 3 boards