Skip to content

bazel: build and test bare-metal examples#3220

Open
mgeisler wants to merge 1 commit into
mainfrom
bazel-bare-metal
Open

bazel: build and test bare-metal examples#3220
mgeisler wants to merge 1 commit into
mainfrom
bazel-bare-metal

Conversation

@mgeisler

Copy link
Copy Markdown
Collaborator

This configures Bazel targets for the bare-metal examples. We now also have test targets for them:

bazel test //:bare_metal_tests

will compile all the code and run a simple test in QEMU (boot the binaries, send "q" to them on stdin).

The Cargo-based workflow has been kept: I expect that students will keep using it in class, so we should keep testing it in CI.

@mgeisler mgeisler force-pushed the bazel-bare-metal branch 4 times, most recently from ec71ec2 to 5f19e2c Compare June 21, 2026 07:13

@djmitche djmitche left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I admit I'm not quite sure why all of this is happening!

3. We wrap each binary target in a platform transition
(`aarch64_binary`) so they are built for the AArch64 bare-metal
target platform during host-executed tests.
"""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is quite repetitive -- could it be improved with a rule or a macro?

@mgeisler

Copy link
Copy Markdown
Collaborator Author

I admit I'm not quite sure why all of this is happening!

Hey @djmitche, yeah, fair point! #1168 is in some sense the starting point — it has bothered me for years that

  1. we build too much in every CI run and
  2. we don't have an easy way to locally replicate what publish.yml does

At Proton, I've been part of introducing Bazel for our monorepo: building Rust, Kotlin, Swift, Typescript with it... So I naturally started looking deeper into it and realized that it's not so complicated. I kind of knew this from Google where we also use Bazel (Blaze) with rules_rust.

What you, @qwandor and @gribozavr haven't seen yet is the Bazel build rules that actually do something interesting: namely configure Bazel "repositories" (those things that start with @...) to contain the back-dated sources for each language.

With that logic neatly wrapped in a repository rule in Bazel, it becomes easy to do (typed from memory):

mdbook(
  name = "da_html",
  srcs = "@backdated_sources//:da_content",
  book = "@backdated_sources//:da_book",
)

and this gives you a mdbook generated HTML book for Danish. You then simply bazel build //:da_html to get this generated.

I have this on my laptop which is not infront of me right now. But that is the end goal: generate per-language repositories which in turn are used to generate HTML, PDF, exerciser, ... outputs.

Now, I must admit that the step towards that have been more bumpy that I expected! The LLVM toolchain sage (resolved for now in #3221) made things strangely unstable, unlike what I've seen on my own laptop. So I was expecting

image

but it has been a little more than 20 minutes by now 😄

I will try and put up the other bits and pieces next so you and the rest of the admins can look at the whole thing together.

edition = "2024",
rustc_flags = [
"-C",
"linker=rust-lld",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have this flag in the Cargo.toml, why is it needed here?

linker_script = ":image.ld",
rustc_flags = [
"-C",
"linker=rust-lld",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, why does this need to be specified here?

rust_binary(
name = "improved",
srcs = glob(["src/**/*.rs"]),
compile_data = glob(["src/**/*.S"]),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between srcs and compile_data?

fi

echo "Running ${BIN_NAME}.bin under QEMU..."
if [ -n "$NON_INTERACTIVE" ]; then

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the point of this script is to test the binaries, why does it need to be different in interactive shells? If they intention is to use it to run examples interactive then I think the script should be called run_example.sh rather than run_test.sh, and maybe take a flag rather than detecting whether it is interactive. Though I'm still not really keen on the parallel build systems, who is going to actually use this?

"""Bazel BUILD file for ARM Cortex-M Microcontroller Examples.

This package defines board support and hardware abstraction layer
(HAL) binaries for microcontrollers. Because this code targets ARM

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this description is misleading, the binaries are examples of how to use PAC, HAL and BSP libraries, they aren't in themselves the HAL or anything.

"-C",
"link-arg=-Tlink.x",
],
target_compatible_with = ["@platforms//os:none"],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do you specify the architecture?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this file be included in the generated exercise template that students download? We should make sure it isn't, as it presumably won't work in that context and will be confusing.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, we should make sure this isn't included in the exercise template to confuse students.


echo "Running rtc.bin under QEMU..."
if [ -n "$NON_INTERACTIVE" ]; then
echo "q" | qemu-system-aarch64 -machine virt,gic-version=3 -cpu max -serial mon:stdio -display none -kernel "$BIN_PATH"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the point of this? The model solution doesn't read any input from the serial console.

Comment thread MODULE.bazel
"aarch64-unknown-none",
],
)
use_repo(crate, "bare_metal_alloc_example")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need both these and the build files in the various directories? How do they interact?

@djmitche

Copy link
Copy Markdown
Collaborator

Thanks for the explanation! We use bazel at $WORK too and roughly the same experience: conceptually really need, in practice lots of unexpected sharp edges!

This configures Bazel targets for the bare-metal examples. We now also
have test targets for them:

    bazel test //:bare_metal_tests

will compile all the code and run a simple test in QEMU (boot the
binaries, send `"q"` to them on stdin).

The Cargo-based workflow has been kept: I expect that students will
keep using it in class, so we should keep testing it in CI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants