Compare commits

...

2 Commits

Author SHA1 Message Date
Philipp Oppermann
7262bf0f90 Merge pull request #1427 from phil-opp/blog-test-false
Update first post to set `test=false` for binary
2025-08-07 18:41:29 +02:00
Philipp Oppermann
9894147b30 Update first post to set test=false for binary
As implemented in #1412
2025-08-07 14:04:24 +02:00
2 changed files with 77 additions and 0 deletions

View File

@@ -516,6 +516,78 @@ cargo rustc -- -C link-args="-e __start -static -nostartfiles"
Note that this is just a minimal example of a freestanding Rust binary. This binary expects various things, for example, that a stack is initialized when the `_start` function is called. **So for any real use of such a binary, more steps are required**. Note that this is just a minimal example of a freestanding Rust binary. This binary expects various things, for example, that a stack is initialized when the `_start` function is called. **So for any real use of such a binary, more steps are required**.
## Making `rust-analyzer` happy
The [`rust-analyzer`](https://rust-analyzer.github.io/) project is a great way to get code completion and "go to definition" support (and many other features) for Rust code in your editor.
It works really well for `#![no_std]` projects too, so I recommend using it for kernel development!
If you're using the [`checkOnSave`](https://rust-analyzer.github.io/book/configuration.html#checkOnSave) feature of `rust-analyzer` (enabled by default), it might report an error for the panic function of our kernel:
```
found duplicate lang item `panic_impl`
```
The reason for this error is that `rust-analyzer` invokes `cargo check --all-targets` by default, which also tries to build the binary in [test](https://doc.rust-lang.org/book/ch11-01-writing-tests.html) and [benchmark](https://doc.rust-lang.org/rustc/tests/index.html#benchmarks) mode.
<div class="note">
### The two meanings of "target"
The `--all-targets` flag is completely unrelated to the `--target` argument.
There are two different meanings of the term "target" in `cargo`:
- The `--target` flag specifies the **[_compilation target_]** that should be passed to the `rustc` compiler. This should be set to the [target triple] of the machine that should run our code.
- The `--all-targets` flag references the **[_package target_]** of Cargo. Cargo packages can be a library and binary at the same time, so you can specify in which way you like to build your crate. In addition, Cargo also has package targets for [examples](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#examples), [tests](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#tests), and [benchmarks](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#benchmarks). These package targets can co-exist, so you can build/check the same crate in e.g. library or test mode.
[_compilation target_]: https://doc.rust-lang.org/rustc/targets/index.html
[target triple]: https://clang.llvm.org/docs/CrossCompilation.html#target-triple
[_package target_]: https://doc.rust-lang.org/cargo/reference/cargo-targets.html
</div>
By default, `cargo check` only builds the _library_ and _binary_ package targets.
However, `rust-analyzer` chooses to check all package targets by default when [`checkOnSave`](https://rust-analyzer.github.io/book/configuration.html#checkOnSave) is enabled.
This is the reason that `rust-analyzer` reports the above `lang item` error that we don't see in `cargo check`.
If we run `cargo check --all-targets`, we see the error too:
```
error[E0152]: found duplicate lang item `panic_impl`
--> src/main.rs:13:1
|
13 | / fn panic(_info: &PanicInfo) -> ! {
14 | | loop {}
15 | | }
| |_^
|
= note: the lang item is first defined in crate `std` (which `test` depends on)
= note: first definition in `std` loaded from /home/[...]/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-8df6be531efb3fd0.rlib
= note: second definition in the local crate (`blog_os`)
```
The first `note` tells us that the panic language item is already defined in the `std` crate, which is a dependency of the `test` crate.
The `test` crate is automatically included when building a crate in [test mode](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#tests).
This does not make sense for our `#![no_std]` kernel as there is no way to support the standard library on bare metal.
So this error is not relevant to our project and we can safely ignore it.
The proper way to avoid this error is to specify in our `Cargo.toml` that our binary does not support building in `test` and `bench` modes.
We can do that by adding a `[[bin]]` section to our `Cargo.toml` to [configure the build](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target) of our binary:
```toml
# in Cargo.toml
[[bin]]
name = "blog_os"
test = false
bench = false
```
The double-brackets around `bin` are not a mistake, this is how the TOML format defines keys that can appear multiple times.
Since a crate can have multiple binaries, the `[[bin]]` section can appear multiple times in the `Cargo.toml` as well.
This is also the reason for the mandatory `name` field, which needs to match the name of the binary (so that `cargo` knows which settings should be applied to whick binary).
By setting the [`test`](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-test-field) and [`bench` ](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-bench-field) fields to `false`, we instruct `cargo` to not build our binary in test or benchmark mode.
Now `cargo check --all-targets` should not throw any errors anymore, and the `checkOnSave` implementation of `rust-analyzer` should be happy too.
## What's next? ## What's next?
The [next post] explains the steps needed for turning our freestanding binary into a minimal operating system kernel. This includes creating a custom target, combining our executable with a bootloader, and learning how to print something to the screen. The [next post] explains the steps needed for turning our freestanding binary into a minimal operating system kernel. This includes creating a custom target, combining our executable with a bootloader, and learning how to print something to the screen.

View File

@@ -818,6 +818,11 @@ div.note p:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
div.note h2, div.note h3, div.note h4 {
margin-top: 0rem;
}
div.warning { div.warning {
padding: 0.7rem 1rem; padding: 0.7rem 1rem;
margin: 1rem 0.2rem; margin: 1rem 0.2rem;