minimal_rt_build/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#![expect(missing_docs)]
5#![forbid(unsafe_code)]
6
7/// Initializes compiler flags for building a minimal kernel using the
8/// `minimal_rt` crate.
9///
10/// Only does anything if the `MINIMAL_RT_BUILD` environment variable is set.
11///
12/// Also, sets the `minimal_rt` `cfg` so that code can detect that it should
13/// build for running as a minimal kernel.
14pub fn init() -> bool {
15    println!("cargo:rustc-check-cfg=cfg(minimal_rt)");
16
17    // If the user sets this environment variable, build the binary for use as a
18    // boot loader. Otherwise, just build a stub binary for unit tests, clippy,
19    // rust-analyzer, etc.
20    //
21    // We don't use a feature for this because because this would break
22    // `--all-features`. We don't use a profile or something for this because
23    // cargo doesn't want us to know about custom profiles. There's no other
24    // mechanism I know of to communicate this information through cargo.
25    println!("cargo:rerun-if-env-changed=MINIMAL_RT_BUILD");
26    if matches!(
27        std::env::var("MINIMAL_RT_BUILD").as_deref().ok(),
28        None | Some("")
29    ) {
30        return false;
31    }
32
33    let triple = std::env::var("TARGET").unwrap();
34    let unsupported = |supported_triple| {
35        panic!(
36            "build is only supported with the {} target, not {}, clear MINIMAL_RT_BUILD",
37            supported_triple, triple
38        );
39    };
40    // xtask-fmt allow-target-arch sys-crate
41    match std::env::var("CARGO_CFG_TARGET_ARCH").unwrap().as_str() {
42        "x86_64" => {
43            // This is the supported triple for x86-64 because, compared to a
44            // linux target, it disables the red zone (needed to prevent
45            // interrupts from overwriting the stack) and it disables use of SSE
46            // by default (needed to avoid accidentally using SSE intrinstics in
47            // various places).
48            //
49            // No special linker flags are needed.
50            if triple != "x86_64-unknown-none" {
51                unsupported("x86_64-unknown-none");
52            }
53        }
54        "aarch64" => {
55            match triple.as_str() {
56                "aarch64-minimal_rt-none" => {
57                    // This is a custom target, defined via
58                    // aarch64-minimal_rt-none.json. So, it requires
59                    // RUSTC_BOOTSTRAP=1 or an unstable toolchain in order to
60                    // use `-Zbuild-std`.
61                    //
62                    // It is aarch64-unknown-none with support for static PIE
63                    // binaries, which we need to support loading the image
64                    // anywhere in PA space.
65                }
66                "aarch64-unknown-linux-musl" => {
67                    // This target works (it supports static PIE binaries) and
68                    // does not require an unstable toolchain, but it is
69                    // difficult to build from non-Linux host environments.
70                    //
71                    // This does require some tweaks to the linker flags.
72                    //
73                    // Don't include the _start entry point.
74                    println!("cargo:rustc-link-arg=-nostartfiles");
75                    // Make the executable relocatable.
76                    println!("cargo:rustc-link-arg=-static-pie");
77                }
78                _ => {
79                    unsupported("aarch64-unknown-linux-musl");
80                }
81            }
82        }
83        arch => panic!("unsupported arch {arch}"),
84    }
85
86    println!("cargo:rustc-cfg=minimal_rt");
87    true
88}