In this edition, lets get the first executable built successfully for RISC-V target in Cargo workspace.

Once the rust toolchain is installed for RISC-V target, cargo build would still throw errors. Lets resolve one by one.

  1. error[E0463]: can't find crate for ‘std’

error[E0463]: can't find crate for `std`
  |
  = note: the `riscv32imac-unknown-none-elf` target may not support the standard library
  = note: `std` is required by `libs` because it does not declare `#![no_std]`

error[E0463]: can't find crate for `std`

Its obvious from the error message that cargo could n’t find the std crate. If you are new to rust, the std crate is the standard library. Here the RISC-V target riscv32imac-unknown-none-elf don’t have the support for std crate yet and std library is huge in size with default support of many advanced data structures and IO operations.

For now, we don’t need any advanced data structures and stay with only with the support of basic types and few basic operations which is the core crate (can also be called as core library). One of the crate either std or core is necessary in rust, if std crate is excluded, rust would automatically include the core crate. Lets exclude the std crate from execs and libs crate.

The #![no_std] is a crate attribute placed at the very beginning of the file to indicate the crate should NOT use std library.

bootstrap-ws $cat execs/src/main.rs 
#![no_std]

fn main() {
    println!("Hello, world!");
}
bootstrap-ws $cat libs/src/lib.rs 
#![no_std]

pub fn add(left: usize, right: usize) -> usize {
    left + right
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }
}

cargo build now don’t throw the the error message error[E0463]: can't find crate for ‘std’. But cargo build still throws other messages.

  1. error: cannot find macro println in this scope

error: cannot find macro `println` in this scope
 --> execs/src/main.rs:4:5
  |
4 |     println!("Hello, world!");

Since std crate is excluded, rust could n’t find the println macro which is part of std crate. So, lets remove the println! macro usage from our code and build

bootstrap-ws $cargo build
   Compiling execs v0.1.0 (bootstrap-ws/execs)
error: `#[panic_handler]` function required, but not found
  1. error: #[panic_handler] function required, but not found

Rust requires every project to implment panic_handler to handle when systems panics (unknown event). std library has a default panic handler implementation, since we excluded it, rust forces to implement a panic handler with core library.

The panic handler function from core library takes PanicInfo structure . Lets bring the core PanicInfo structure in scope write our own panic handler function with loop{} so that if system panics, it stuck in this loop for ever.

bootstrap-ws $cat execs/src/main.rs 
#![no_std]

use core::panic::PanicInfo;

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop{}
}

fn main() {
}
bootstrap-ws $cargo build
   Compiling execs v0.1.0 (bootstrap-ws/execs)
error: requires `start` lang_item

error: could not compile `execs` due to previous error
bootstrap-ws $

Now, cargo build throws another error message error: requires `start` lang_item

  1. error: requires `start` lang_item

With std library rust’s entry point would be main and rust performs few operations before it jumps into main. Rust requires a entry function ‘start’ when built with core library. Since our crate is built with core library, lets change the entry function name to start and instruct crate NOT to look for main entry with attribute #![no_main].

bootstrap-ws $cat execs/src/main.rs 
#![no_std]
#![no_main]

use core::panic::PanicInfo;

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop{}
}

fn _start() {
}
  1. First executable built for RISC-V

bootstrap-ws $cargo build
    Finished dev [unoptimized + debuginfo] target(s) in 0.03s
bootstrap-ws $cargo clean
bootstrap-ws $cargo build
   Compiling libs v0.1.0 (bootstrap-ws/libs)
   Compiling execs v0.1.0 (bootstrap-ws/execs)
    Finished dev [unoptimized + debuginfo] target(s) in 1.23s

This brings to the end of this edition. In the next session, lets inspect what’s present in the binary(executable) we built?

Keep reading