From 768f81aedcbfa92b9c147d19c6f96b4888d4316f Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sun, 28 Oct 2018 13:00:42 +0100 Subject: [PATCH] Use a nightly Rust version from the beginning --- .../01-freestanding-rust-binary/index.md | 15 +++++++++-- .../posts/02-minimal-rust-kernel/index.md | 26 ++++--------------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/blog/content/second-edition/posts/01-freestanding-rust-binary/index.md b/blog/content/second-edition/posts/01-freestanding-rust-binary/index.md index 1765b450..df1edb75 100644 --- a/blog/content/second-edition/posts/01-freestanding-rust-binary/index.md +++ b/blog/content/second-edition/posts/01-freestanding-rust-binary/index.md @@ -32,6 +32,17 @@ In order to create an OS kernel in Rust, we need to create an executable that ca This post describes the necessary steps to create a freestanding Rust binary and explains why the steps are needed. If you're just interested in a minimal example, you can **[jump to the summary](#summary)**. +## Installing Rust Nightly +Rust has three release channels: _stable_, _beta_, and _nightly_. The Rust Book explains the difference between these channels really well, so take a minute and [check it out](https://doc.rust-lang.org/book/second-edition/appendix-07-nightly-rust.html#choo-choo-release-channels-and-riding-the-trains). For building an operating system we will need some experimental features that are only available on the nightly channel, so we need to install a nightly version of Rust. + +To manage Rust installations I highly recommend [rustup]. It allows you to install nightly, beta, and stable compilers side-by-side and makes it easy to update them. With rustup you can use a nightly compiler for the current directory by running `rustup override add nightly`. Alternatively, you can add a file called `rust-toolchain` with the content `nightly` to the project's root directory. You can check that you have a nightly version installed by running `rustc --version`: The version number should contain `-nightly` at the end. + +[rustup]: https://www.rustup.rs/ + +The nightly compiler allows us to opt-in to various experimental features by using so-called _feature flags_ at the top of our file. For example, we could enable the experimental [`asm!` macro] for inline assembly by adding `#![feature(asm)]` to the top of our `main.rs`. Note that such experimental features are completely unstable, which means that future Rust versions might change or remove them without prior warning. For this reason we will only use them if absolutely necessary. + +[`asm!` macro]: https://doc.rust-lang.org/nightly/unstable-book/language-features/asm.html + ## Disabling the Standard Library By default, all Rust crates link the [standard library], which depends on the operating system for features such as threads, files, or networking. It also depends on the C standard library `libc`, which closely interacts with OS services. Since our plan is to write an operating system, we can not use any OS-dependent libraries. So we have to disable the automatic inclusion of the standard library through the [`no_std` attribute]. @@ -239,13 +250,13 @@ error: linking with `cc` failed: exit code: 1 The problem is that we still link the startup routine of the C runtime, which requires some symbols of the C standard library `libc`, which we don't link due to the `no_std` attribute. So we need to get rid of the C startup routine. We can do that by passing the `-nostartfiles` flag to the linker. -One way to pass linker attributes via cargo is the `cargo rustc` command. The command behaves exactly like `cargo build`, but allows to pass options to `rustc`, the underlying Rust compiler. `rustc` has the (unstable) `-Z pre-link-arg` flag, which passes an argument to the linker. Combined, our new build command looks like this: +One way to pass linker attributes via cargo is the `cargo rustc` command. The command behaves exactly like `cargo build`, but allows to pass options to `rustc`, the underlying Rust compiler. `rustc` has the `-Z pre-link-arg` flag, which passes an argument to the linker. Combined, our new build command looks like this: ``` > cargo rustc -- -Z pre-link-arg=-nostartfiles ``` -With this command, our crate finally builds as a freestanding executable! +Note that all `-Z` flags are unstable, so the command only works with nightly Rust. Now our crate finally builds as a freestanding executable! #### Windows On Windows, the linker requires two entry points [depending on the used subsystem]. For the `CONSOLE` subsystem, we need a function called `mainCRTStartup`, which calls a function called `main`. Like on Linux, we overwrite the entry points by defining `no_mangle` functions: diff --git a/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md b/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md index 2dabf47f..2ac8037c 100644 --- a/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md +++ b/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md @@ -249,37 +249,21 @@ The command depends on the rust source code, which we can install with `rustup c Now we can rerun the above command with `xbuild` instead of `build`: -``` -> cargo xbuild --target x86_64-blog_os.json -``` - -Depending on your version of the Rust compiler you might get the following error: - -``` -error: The sysroot can't be built for the Stable channel. Switch to nightly. -``` - -To understand this error, you need to know that the Rust compiler has three release channels: _stable_, _beta_, and _nightly_. The Rust Book explains the difference between these channels really well, so take a minute and [check it out](https://doc.rust-lang.org/book/second-edition/appendix-07-nightly-rust.html#choo-choo-release-channels-and-riding-the-trains). - -Some experimental features are only available on the nightly channel. Since Rust uses many of these features for the internal implementation of `core` and other built-in libraries, we need to use a nightly compiler when invoking `cargo xbuild` (since it rebuilds these libraries). - -To manage Rust installations I highly recommend [rustup]. It allows you to install nightly, beta, and stable compilers side-by-side and makes it easy to update them. With rustup you can use a nightly compiler for the current directory by running `rustup override add nightly`. Alternatively, you can add a file called `rust-toolchain` with the content `nightly` to the project's root directory. - -[rustup]: https://www.rustup.rs/ - -With a nightly compiler the build finally succeeds: - ``` > cargo xbuild --target x86_64-blog_os.json Compiling core v0.0.0 (file:///…/rust/src/libcore) Finished release [optimized] target(s) in 52.75 secs Compiling compiler_builtins v0.1.0 (file:///…/rust/src/libcompiler_builtins) Finished release [optimized] target(s) in 3.92 secs + Compiling alloc v0.0.0 (/tmp/xargo.9I97eR3uQ3Cq) + Finished release [optimized] target(s) in 7.61s Compiling blog_os v0.1.0 (file:///…/blog_os) Finished dev [unoptimized + debuginfo] target(s) in 0.29 secs ``` -We see that `cargo xbuild` cross-compiled the `core`, `compiler_builtin`, and `alloc` libraries for our new custom target and then continued to compile our `blog_os` crate. +We see that `cargo xbuild` cross-compiles the `core`, `compiler_builtin`, and `alloc` libraries for our new custom target. Since these libraries use a lot of unstable features internally, this only works with a [nightly Rust compiler]. Afterwards, `cargo xbuild` successfully compiles our `blog_os` crate. + +[nightly Rust compiler]: ./second-edition/posts/01-freestanding-rust-binary/index.md#installing-rust-nightly Now we are able to build our kernel for a bare metal target. However, our `_start` entry point, which will be called by the boot loader, is still empty. So let's output something to screen from it.