mirror of
https://github.com/lupyuen/lupyuen.github.io.git
synced 2025-01-13 02:08:32 +08:00
1066 lines
No EOL
53 KiB
HTML
1066 lines
No EOL
53 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="generator" content="rustdoc">
|
||
<title>Rust Custom Target for QEMU RISC-V on Apache NuttX RTOS</title>
|
||
|
||
|
||
<!-- Begin scripts/articles/*-header.html: Article Header for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
<meta property="og:title"
|
||
content="Rust Custom Target for QEMU RISC-V on Apache NuttX RTOS"
|
||
data-rh="true">
|
||
<meta property="og:description"
|
||
content="Our Rust App compiles for Software Floating-Point, but Apache NuttX RTOS expects Hardware Floating-Point... Let's fix this with a Rust Custom Target for QEMU RISC-V"
|
||
data-rh="true">
|
||
<meta name="description"
|
||
content="Our Rust App compiles for Software Floating-Point, but Apache NuttX RTOS expects Hardware Floating-Point... Let's fix this with a Rust Custom Target for QEMU RISC-V">
|
||
<meta property="og:image"
|
||
content="https://lupyuen.github.io/images/rust4-title.jpg">
|
||
<meta property="og:type"
|
||
content="article" data-rh="true">
|
||
<link rel="canonical"
|
||
href="https://lupyuen.org/articles/rust4.html" />
|
||
<!-- End scripts/articles/*-header.html -->
|
||
<!-- Begin scripts/rustdoc-header.html: Header for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
<link rel="alternate" type="application/rss+xml" title="RSS Feed for lupyuen" href="/rss.xml" />
|
||
<link rel="stylesheet" type="text/css" href="../normalize.css">
|
||
<link rel="stylesheet" type="text/css" href="../rustdoc.css" id="mainThemeStyle">
|
||
<link rel="stylesheet" type="text/css" href="../dark.css">
|
||
<link rel="stylesheet" type="text/css" href="../light.css" id="themeStyle">
|
||
<link rel="stylesheet" type="text/css" href="../prism.css">
|
||
<script src="../storage.js"></script><noscript>
|
||
<link rel="stylesheet" href="../noscript.css"></noscript>
|
||
<link rel="shortcut icon" href="../favicon.ico">
|
||
<style type="text/css">
|
||
#crate-search {
|
||
background-image: url("../down-arrow.svg");
|
||
}
|
||
</style>
|
||
<!-- End scripts/rustdoc-header.html -->
|
||
|
||
|
||
</head>
|
||
<body class="rustdoc">
|
||
<!--[if lte IE 8]>
|
||
<div class="warning">
|
||
This old browser is unsupported and will most likely display funky
|
||
things.
|
||
</div>
|
||
<![endif]-->
|
||
|
||
|
||
<!-- Begin scripts/rustdoc-before.html: Pre-HTML for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
|
||
<!-- Begin Theme Picker -->
|
||
<div class="theme-picker" style="left: 0"><button id="theme-picker" aria-label="Pick another theme!"><img src="../brush.svg"
|
||
width="18" alt="Pick another theme!"></button>
|
||
<div id="theme-choices"></div>
|
||
</div>
|
||
<!-- Theme Picker -->
|
||
|
||
<!-- End scripts/rustdoc-before.html -->
|
||
|
||
|
||
<h1 class="title">Rust Custom Target for QEMU RISC-V on Apache NuttX RTOS</h1>
|
||
<nav id="rustdoc"><ul>
|
||
<li><a href="#software-vs-hardware-floating-point" title="Software vs Hardware Floating-Point">1 Software vs Hardware Floating-Point</a><ul></ul></li>
|
||
<li><a href="#rust-wont-double-float" title="Rust Won’t Double-Float">2 Rust Won’t Double-Float</a><ul></ul></li>
|
||
<li><a href="#custom-target-for-rust" title="Custom Target for Rust">3 Custom Target for Rust</a><ul></ul></li>
|
||
<li><a href="#build-the-rust-core-library" title="Build the Rust Core Library">4 Build the Rust Core Library</a><ul></ul></li>
|
||
<li><a href="#nuttx-links-ok-with-rust" title="NuttX Links OK with Rust">5 NuttX Links OK with Rust</a><ul></ul></li>
|
||
<li><a href="#rust-build-for-64-bit-risc-v" title="Rust Build for 64-bit RISC-V">6 Rust Build for 64-bit RISC-V</a><ul></ul></li>
|
||
<li><a href="#whats-next" title="What’s Next">7 What’s Next</a><ul></ul></li>
|
||
<li><a href="#appendix-build-nuttx-for-qemu" title="Appendix: Build NuttX for QEMU">8 Appendix: Build NuttX for QEMU</a><ul></ul></li>
|
||
<li><a href="#appendix-rust-compiler-options" title="Appendix: Rust Compiler Options">9 Appendix: Rust Compiler Options</a><ul></ul></li></ul></nav><p>📝 <em>21 Apr 2024</em></p>
|
||
<p><img src="https://lupyuen.github.io/images/rust4-title.jpg" alt="Rust Apps on Apache NuttX RTOS and QEMU RISC-V" /></p>
|
||
<div style="text-align: center">
|
||
<p><a href="https://github.com/Swordfish90/cool-retro-term"><em>Thanks to cool-retro-term!</em></a></p>
|
||
</div>
|
||
<p>Last article we were compiling <a href="https://lupyuen.github.io/articles/rust3"><strong>Rust Apps</strong></a> for <a href="https://nuttx.apache.org/docs/latest/index.html"><strong>Apache NuttX RTOS</strong></a> (QEMU Emulator, RISC-V 32-bit). And we hit a <strong>baffling error</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>$ make
|
||
riscv64-unknown-elf-ld: libapps.a
|
||
hello_rust_1.o:
|
||
can't link soft-float modules with double-float modules</code></pre></div>
|
||
<p>Let’s solve the problem! We dive inside the internals of <strong>C-to-Rust Interop</strong>…</p>
|
||
<ul>
|
||
<li>
|
||
<p>Rust compiles for <strong>Soft-Float</strong>, NuttX expects <strong>Double-Float</strong></p>
|
||
<p>(Software vs Hardware Floating-Point)</p>
|
||
</li>
|
||
<li>
|
||
<p>But Rust <strong>doesn’t support Double-Float</strong> (by default)</p>
|
||
</li>
|
||
<li>
|
||
<p>So we create a <strong>Rust Custom Target</strong> for Double-Float</p>
|
||
</li>
|
||
<li>
|
||
<p>Rebuild the <strong>Rust Core Library</strong> for Double-Float</p>
|
||
</li>
|
||
<li>
|
||
<p>And our Rust App <strong>builds OK with NuttX</strong>!</p>
|
||
</li>
|
||
</ul>
|
||
<p><img src="https://lupyuen.github.io/images/rust4-flow2a.jpg" alt="Double-Float vs Soft-Float: GCC Linker won’t link the binaries" /></p>
|
||
<h1 id="software-vs-hardware-floating-point"><a class="doc-anchor" href="#software-vs-hardware-floating-point">§</a>1 Software vs Hardware Floating-Point</h1>
|
||
<p><em>Why did our NuttX Build fail? (Pic above)</em></p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Download the NuttX Source Code
|
||
$ mkdir nuttx
|
||
$ cd nuttx
|
||
$ git clone https://github.com/apache/nuttx nuttx
|
||
$ git clone https://github.com/apache/nuttx-apps apps
|
||
|
||
## Configure NuttX for QEMU RISC-V 32-bit
|
||
$ cd nuttx
|
||
$ tools/configure.sh rv-virt:nsh
|
||
$ make menuconfig
|
||
## TODO: Enable "Hello Rust Example"
|
||
|
||
## Build NuttX bundled with the Rust App
|
||
$ make
|
||
riscv64-unknown-elf-ld: libapps.a
|
||
hello_rust_1.o:
|
||
can't link soft-float modules with double-float modules</code></pre></div>
|
||
<p><a href="https://lupyuen.github.io/articles/rust3#build-nuttx-for-qemu-risc-v">(See the <strong>Complete Steps</strong>)</a></p>
|
||
<p><strong>GCC Linker</strong> failed because it couldn’t link the NuttX Binaries with the Rust Binaries.</p>
|
||
<p>Here’s Why: NuttX Build calls <strong>GCC Compiler</strong> to compile our C Modules…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Build NuttX Firmware with Tracing Enabled
|
||
$ make --trace
|
||
...
|
||
## GCC compiles `hello_main.c` to `hello.o`
|
||
## for RISC-V 32-bit with Double-Float
|
||
riscv64-unknown-elf-gcc \
|
||
-march=rv32imafdc \
|
||
-mabi=ilp32d \
|
||
-c \
|
||
hello_main.c \
|
||
-o ...hello.o \
|
||
...</code></pre></div>
|
||
<p><a href="https://gist.github.com/lupyuen/7e68b69d0d5879f77b1404ae2db6fb9d">(See the <strong>GCC Options</strong>)</a></p>
|
||
<p>Then NuttX Build calls <strong>Rust Compiler</strong> to compile our Rust App…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Build NuttX Firmware with Tracing Enabled
|
||
$ make --trace
|
||
...
|
||
## Rust Compiler compiles `hello_rust_main.rs` to `hello_rust.o`
|
||
## for RISC-V 32-bit with Soft-Float
|
||
rustc \
|
||
--target riscv32i-unknown-none-elf \
|
||
--edition 2021 \
|
||
--emit obj \
|
||
-g \
|
||
-C panic=abort \
|
||
-O \
|
||
hello_rust_main.rs \
|
||
-o ...hello_rust.o</code></pre></div>
|
||
<p>Which looks like this…</p>
|
||
<p><img src="https://lupyuen.github.io/images/rust4-flow2b.jpg" alt="Double-Float vs Soft-Float: GCC Linker won’t link the binaries" /></p>
|
||
<p><em>Is there a problem?</em></p>
|
||
<p>Watch closely as we compare <strong>GCC Compiler</strong> with <strong>Rust Compiler</strong> (pic above)…</p>
|
||
<span style="font-size:90%">
|
||
<div><table><thead><tr><th style="text-align: left">GCC Compiler</th><th style="text-align: left">Rust Compiler</th></tr></thead><tbody>
|
||
<tr><td style="text-align: left"><em>riscv64-unknown-elf-gcc</em> <br> <em>hello_main.c</em></td><td style="text-align: left"><em>rustc</em> <br> <em>hello_rust_main.rs</em></td></tr>
|
||
<tr><td style="text-align: left"><em>-march</em> <br> <strong>rv32imafdc</strong></td><td style="text-align: left"><em>–target</em> <br> <strong>riscv32i-unknown-none-elf</strong></td></tr>
|
||
<tr><td style="text-align: left"><em>-mabi</em> <br> <strong>ilp32d</strong></td><td style="text-align: left"></td></tr>
|
||
</tbody></table>
|
||
</div></span>
|
||
<p><em>Hmmm the Floats look different…</em></p>
|
||
<p>GCC compiles for (Double-Precision) <strong>Hardware Floating-Point</strong>…</p>
|
||
<p>But Rust Compiler emits <strong>Software Floating-Point</strong>.</p>
|
||
<p>That’s why GCC Linker <strong>won’t link the binaries</strong>: Hard-Float vs Soft-Float!</p>
|
||
<span style="font-size:90%">
|
||
<div><table><thead><tr><th style="text-align: left">GCC Compiler</th><th style="text-align: left">Rust Compiler</th></tr></thead><tbody>
|
||
<tr><td style="text-align: left"><strong>rv32imafdc</strong></td><td style="text-align: left"><strong>riscv32i</strong></td></tr>
|
||
<tr><td style="text-align: left">- <strong>I</strong>: Integer</td><td style="text-align: left">- <strong>I</strong>: Integer</td></tr>
|
||
<tr><td style="text-align: left">- <strong>F</strong>: Single Hard-Float</td><td style="text-align: left"><em>(Default is Soft-Float)</em></td></tr>
|
||
<tr><td style="text-align: left">- <strong>D</strong>: Double Hard-Float</td><td style="text-align: left"><em>(Default is Soft-Float)</em></td></tr>
|
||
</tbody></table>
|
||
</div></span>
|
||
<p><img src="https://lupyuen.github.io/images/rust4-flow2.jpg" alt="Double-Float vs Soft-Float: GCC Linker won’t link the binaries" /></p>
|
||
<p>To verify, we dump the <a href="https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header"><strong>ELF Header</strong></a> for <strong>GCC Compiler Output</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Dump the ELF Header for GCC Output
|
||
$ riscv64-unknown-elf-readelf \
|
||
--file-header --arch-specific \
|
||
../apps/examples/hello/*hello.o
|
||
|
||
## GCC Compiler Output is
|
||
## Double-Precision Hardware Floating-Point
|
||
Flags: 0x5, RVC, double-float ABI</code></pre></div>
|
||
<p><a href="https://gist.github.com/lupyuen/d8b4f793cd463230393326cef7dbedbe">(See the <strong>GCC ELF Header</strong>)</a></p>
|
||
<p>And the ELF Header for <strong>Rust Compiler Output</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Dump the ELF Header for Rust Compiler Output
|
||
$ riscv64-unknown-elf-readelf \
|
||
--file-header --arch-specific \
|
||
../apps/examples/hello_rust/*hello_rust.o
|
||
|
||
## Rust Compiler Output is
|
||
## Software Floating-Point
|
||
Flags: 0x0</code></pre></div>
|
||
<p><a href="https://gist.github.com/lupyuen/413830fed9cdb2b02d5f9d0d062beb3e">(See the <strong>Rust ELF Header</strong>)</a></p>
|
||
<p>Indeed we have a problem: Double-Float and Soft-Float won’t mix! Let’s fix this…</p>
|
||
<p><img src="https://lupyuen.github.io/images/rust4-flow3.jpg" alt="Rust Won’t Double-Float" /></p>
|
||
<h1 id="rust-wont-double-float"><a class="doc-anchor" href="#rust-wont-double-float">§</a>2 Rust Won’t Double-Float</h1>
|
||
<p><em>What if we ask Rust Compiler to compile for Double-Float? RV32IMAFDC (Pic above)</em></p>
|
||
<p>Let’s harmonise Rust Compiler with GCC Compiler…</p>
|
||
<ul>
|
||
<li>
|
||
<p>Our Build Target is <a href="https://www.qemu.org/docs/master/system/riscv/virt.html"><strong>QEMU Emulator</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p>Which offically supports <a href="https://www.qemu.org/docs/master/system/riscv/virt.html#supported-devices"><strong><code>riscv32gc</code></strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p>“<strong><code>gc</code></strong>” in “<strong><code>riscv32gc</code></strong>” denotes <a href="https://en.wikipedia.org/wiki/RISC-V#ISA_base_and_extensions"><strong>IMAFDC</strong></a></p>
|
||
</li>
|
||
</ul>
|
||
<p>Hence we could do this…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Compile `hello_rust_main.rs` to `hello_rust.o`
|
||
## for Double-Precision Hardware Floating-Point
|
||
rustc \
|
||
--target riscv32gc-unknown-none-elf \
|
||
--edition 2021 \
|
||
--emit obj \
|
||
-g \
|
||
-C panic=abort \
|
||
-O \
|
||
hello_rust_main.rs \
|
||
-o hello_rust.o</code></pre></div>
|
||
<p>Sorry nope it <strong>won’t work</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>Error loading target specification:
|
||
Could not find specification for target "riscv32gc-unknown-none-elf".
|
||
Run `rustc --print target-list` for a list of built-in targets</code></pre></div>
|
||
<p>That’s because <strong><code>riscv32gc</code></strong> isn’t a <strong>Built-In Rust Target</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## List the Built-In Rust Targets for RISC-V
|
||
$ rustup target list | grep riscv
|
||
|
||
## Nope no riscv32gc!
|
||
riscv32i-unknown-none-elf
|
||
riscv32imac-unknown-none-elf
|
||
riscv32imc-unknown-none-elf
|
||
riscv64gc-unknown-linux-gnu
|
||
riscv64gc-unknown-none-elf
|
||
riscv64imac-unknown-none-elf</code></pre></div>
|
||
<p>But we can create a <a href="https://docs.rust-embedded.org/embedonomicon/custom-target.html"><strong>Custom Rust Target</strong></a> for <strong><code>riscv32gc</code></strong>.</p>
|
||
<p>(Coming up next section)</p>
|
||
<p><em>Won’t GCC Compiler have the same problem with Double-Float?</em></p>
|
||
<p>When we list the <strong>Built-In GCC Targets</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## List the Built-In Targets for GCC RISC-V.
|
||
## ABI means Application Binary Interface
|
||
$ riscv64-unknown-elf-gcc --target-help
|
||
|
||
Supported ABIs (for use with the -mabi= option):
|
||
ilp32 ilp32d ilp32e ilp32f lp64 lp64d lp64f</code></pre></div>
|
||
<p>We see that <strong>GCC supports Double-Float</strong>: <strong><code>ilp32d</code></strong></p>
|
||
<ul>
|
||
<li><strong><code>ilp32</code></strong>: <strong>32-bit</strong> Int, Long and Pointer</li>
|
||
<li><strong><code>d</code></strong>: <strong>Double-Precision</strong> Hardware Floating-Point</li>
|
||
</ul>
|
||
<p>That’s why we saw <strong><code>ilp32d</code></strong> earlier…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## GCC compiles for RISC-V 32-bit (Double-Float)
|
||
riscv64-unknown-elf-gcc \
|
||
-march=rv32imafdc \
|
||
-mabi=ilp32d \
|
||
...</code></pre></div>
|
||
<p>We’ll make something similar for Rust Compiler…</p>
|
||
<p><a href="https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Options.html#index-mabi-5">(More about <strong>Application Binary Interface</strong>)</a></p>
|
||
<p><img src="https://lupyuen.github.io/images/rust4-flow1a.jpg" alt="Custom Target for Rust" /></p>
|
||
<h1 id="custom-target-for-rust"><a class="doc-anchor" href="#custom-target-for-rust">§</a>3 Custom Target for Rust</h1>
|
||
<p><em>To compile Rust for Double-Float, we need a Custom Target: riscv32gc</em></p>
|
||
<p><em>How to create the Custom Target?</em></p>
|
||
<p>According to the <a href="https://docs.rust-embedded.org/embedonomicon/custom-target.html"><strong>Official Rust Docs</strong></a>, we shall…</p>
|
||
<ul>
|
||
<li>
|
||
<p>Copy from a <strong>Built-In Rust Target</strong></p>
|
||
<p>(Like <strong><code>riscv32i</code></strong>)</p>
|
||
</li>
|
||
<li>
|
||
<p>Tweak it to fit our <strong>Custom Rust Target</strong></p>
|
||
<p>(Which becomes <strong><code>riscv32gc</code></strong>)</p>
|
||
</li>
|
||
</ul>
|
||
<p>This is how we dump a Built-In Rust Target: <a href="https://gist.github.com/lupyuen/dd6a2ee58902e7925efd2a889bc0a833"><strong><code>riscv32i</code></strong></a></p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Dump the Built-In Rust Target:
|
||
## riscv32i (32-bit RISC-V with Soft-Float)
|
||
$ rustc \
|
||
+nightly \
|
||
-Z unstable-options \
|
||
--print target-spec-json \
|
||
--target riscv32i-unknown-none-elf
|
||
|
||
{
|
||
"arch": "riscv32",
|
||
"atomic-cas": false,
|
||
"cpu": "generic-rv32",
|
||
"data-layout": "e-m:e-p:32:32-i64:64-n32-S128",
|
||
"eh-frame-header": false,
|
||
"emit-debug-gdb-scripts": false,
|
||
"is-builtin": true,
|
||
"linker": "rust-lld",
|
||
"linker-flavor": "ld.lld",
|
||
"llvm-target": "riscv32",
|
||
"max-atomic-width": 0,
|
||
"panic-strategy": "abort",
|
||
"relocation-model": "static",
|
||
"target-pointer-width": "32"
|
||
}</code></pre></div>
|
||
<p>That’s the Rust Definition of <a href="https://gist.github.com/lupyuen/dd6a2ee58902e7925efd2a889bc0a833"><strong><code>riscv32i</code></strong></a>: <strong>32-bit</strong> RISC-V with <strong>Soft-Float</strong>.</p>
|
||
<p>We do the same for <a href="https://gist.github.com/lupyuen/9f269598bda11215832bd91a592d00a2"><strong><code>riscv64gc</code></strong></a>: <strong>64-bit</strong> RISC-V with <strong>Double-Float</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Dump the Built-In Rust Target:
|
||
## riscv64gc (64-bit RISC-V with Double-Float)
|
||
$ rustc \
|
||
+nightly \
|
||
-Z unstable-options \
|
||
--print target-spec-json \
|
||
--target riscv64gc-unknown-none-elf
|
||
|
||
{
|
||
"arch": "riscv64",
|
||
"code-model": "medium",
|
||
"cpu": "generic-rv64",
|
||
"data-layout": "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
|
||
"eh-frame-header": false,
|
||
"emit-debug-gdb-scripts": false,
|
||
"features": "+m,+a,+f,+d,+c",
|
||
"is-builtin": true,
|
||
"linker": "rust-lld",
|
||
"linker-flavor": "ld.lld",
|
||
"llvm-abiname": "lp64d",
|
||
"llvm-target": "riscv64",
|
||
"max-atomic-width": 64,
|
||
"panic-strategy": "abort",
|
||
"relocation-model": "static",
|
||
"supported-sanitizers": [ "kernel-address" ],
|
||
"target-pointer-width": "64"
|
||
}</code></pre></div>
|
||
<p>Which has more goodies inside: features, llvm-abiname, …</p>
|
||
<p><em>We’re mashing the Two Targets into a New Target?</em></p>
|
||
<p>Exactly! Based on the above, we create our <strong>Rust Custom Target</strong>: <a href="https://github.com/lupyuen/nuttx-rust-app/blob/main/riscv32gc-unknown-none-elf.json"><em>riscv32gc-unknown-none-elf.json</em></a></p>
|
||
<div class="example-wrap"><pre class="language-json"><code>{
|
||
"arch": "riscv32",
|
||
"cpu": "generic-rv32",
|
||
"data-layout": "e-m:e-p:32:32-i64:64-n32-S128",
|
||
"eh-frame-header": false,
|
||
"emit-debug-gdb-scripts": false,
|
||
"features": "+m,+a,+f,+d,+c",
|
||
"linker": "rust-lld",
|
||
"linker-flavor": "ld.lld",
|
||
"llvm-abiname": "ilp32d",
|
||
"llvm-target": "riscv32",
|
||
"max-atomic-width": 0,
|
||
"panic-strategy": "abort",
|
||
"relocation-model": "static",
|
||
"target-pointer-width": "32"
|
||
}</code></pre></div>
|
||
<p>Which is <a href="https://gist.github.com/lupyuen/dd6a2ee58902e7925efd2a889bc0a833"><strong><code>riscv32i</code></strong></a> plus these changes…</p>
|
||
<ul>
|
||
<li>
|
||
<p>Remove <em>“is-builtin”: true</em></p>
|
||
<p>(It’s a <strong>Custom Target</strong>, not Built-In)</p>
|
||
</li>
|
||
<li>
|
||
<p>Remove <em>“atomic-cas”: false</em></p>
|
||
<p><a href="https://en.m.wikipedia.org/wiki/Compare-and-swap">(Enable <strong>Atomic Compare-And-Swap</strong>)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Add <em>“features”: “+m,+a,+f,+d,+c”</em></p>
|
||
<p><a href="https://lupyuen.github.io/articles/rust4#software-vs-hardware-floating-point">(Because we need <strong>IMAFDC</strong>)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Add <em>“llvm-abiname”: “ilp32d”</em></p>
|
||
<p><a href="https://lupyuen.github.io/articles/rust4#software-vs-hardware-floating-point">(<strong><code>ilp32d</code></strong> comes from <strong><code>make</code> <code>--trace</code></strong>)</a></p>
|
||
<p><a href="https://lupyuen.github.io/articles/rust#custom-rust-target-for-bl602">(More about <strong><code>llvm-abiname</code></strong>)</a></p>
|
||
</li>
|
||
</ul>
|
||
<p>In Summary: We spliced Two Built-In Targets into Custom Target <strong><code>riscv32gc</code></strong>…</p>
|
||
<span style="font-size:80%">
|
||
<div><table><thead><tr><th></th><th style="text-align: center"><a href="https://gist.github.com/lupyuen/dd6a2ee58902e7925efd2a889bc0a833">riscv32i</a> <br> <em>(Built-In)</em></th><th style="text-align: center"><a href="https://gist.github.com/lupyuen/9f269598bda11215832bd91a592d00a2">riscv64gc</a> <br> <em>(Built-In)</em></th><th style="text-align: center"><a href="https://github.com/lupyuen/nuttx-rust-app/blob/main/riscv32gc-unknown-none-elf.json">riscv32gc</a> <br> <em>(Custom)</em></th></tr></thead><tbody>
|
||
<tr><td><em>arch</em></td><td style="text-align: center"><strong>riscv32</strong></td><td style="text-align: center">riscv64</td><td style="text-align: center"><strong>riscv32</strong></td></tr>
|
||
<tr><td><em>atomic-cas</em></td><td style="text-align: center">false</td><td style="text-align: center"></td><td style="text-align: center"></td></tr>
|
||
<tr><td><em>cpu</em></td><td style="text-align: center"><strong>generic-rv32</strong></td><td style="text-align: center">generic-rv64</td><td style="text-align: center"><strong>generic-rv32</strong></td></tr>
|
||
<tr><td><em>data-layout</em></td><td style="text-align: center"><strong>e-m:e-p:32…</strong></td><td style="text-align: center">e-m:e-p:64…</td><td style="text-align: center"><strong>e-m:e-p:32…</strong></td></tr>
|
||
<tr><td><em>features</em></td><td style="text-align: center"></td><td style="text-align: center"><strong>+m,+a,+f,+d,+c</strong></td><td style="text-align: center"><strong>+m,+a,+f,+d,+c</strong></td></tr>
|
||
<tr><td><em>is-builtin</em></td><td style="text-align: center">true</td><td style="text-align: center">true</td><td style="text-align: center"></td></tr>
|
||
<tr><td><em>llvm-abiname</em></td><td style="text-align: center"></td><td style="text-align: center">lp64d</td><td style="text-align: center">ilp32d</td></tr>
|
||
<tr><td><em>llvm-target</em></td><td style="text-align: center"><strong>riscv32</strong></td><td style="text-align: center">riscv64</td><td style="text-align: center"><strong>riscv32</strong></td></tr>
|
||
<tr><td><em>max-atomic-width</em></td><td style="text-align: center"></td><td style="text-align: center">64</td><td style="text-align: center">0</td></tr>
|
||
<tr><td><em>target-pointer-width</em></td><td style="text-align: center"><strong>32</strong></td><td style="text-align: center">64</td><td style="text-align: center"><strong>32</strong></td></tr>
|
||
</tbody></table>
|
||
</div></span>
|
||
<blockquote>
|
||
<p><img src="https://lupyuen.github.io/images/rust4-flow1b.jpg" alt="Build the Rust Core Library" /></p>
|
||
</blockquote>
|
||
<h1 id="build-the-rust-core-library"><a class="doc-anchor" href="#build-the-rust-core-library">§</a>4 Build the Rust Core Library</h1>
|
||
<p><em>Are we ready to rebuild with Double-Float?</em></p>
|
||
<p>Not quite, we’re not done with the <strong>System Library</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Rust Compiler fails to compile with our Custom Target `riscv32gc`
|
||
$ rustc \
|
||
--target riscv32gc-unknown-none-elf.json \
|
||
--edition 2021 \
|
||
--emit obj \
|
||
-g \
|
||
-C panic=abort \
|
||
-O \
|
||
hello_rust_main.rs \
|
||
-o hello_rust.o
|
||
|
||
## That's because Rust Core Library for `riscv32gc` is missing
|
||
error[E0463]: can't find crate for `core`</code></pre></div>
|
||
<p>Why? Remember…</p>
|
||
<ul>
|
||
<li>
|
||
<p><strong>GCC Compiler</strong> supports Double-Float…</p>
|
||
<p>Because it’s bundled with <strong>C Standard Library</strong> for Double-Float</p>
|
||
</li>
|
||
<li>
|
||
<p>Thus <strong>Rust Compiler</strong> will support Double-Float…</p>
|
||
<p>Only when it has the <a href="https://lupyuen.github.io/articles/rust3#standard-vs-embedded-rust"><strong>Rust Core Library</strong></a> for Double-Float</p>
|
||
</li>
|
||
</ul>
|
||
<p><em>And the Rust Core Library comes from?</em></p>
|
||
<p>We call Rust Compiler to build the <strong>Rust Core Library</strong> for Double-Float <strong><code>riscv32gc</code></strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Download our Custom Target for `riscv32gc`
|
||
rm -f riscv32gc-unknown-none-elf.json
|
||
wget https://raw.githubusercontent.com/lupyuen/nuttx-rust-app/main/riscv32gc-unknown-none-elf.json
|
||
|
||
## Custom Target needs Nightly Build of Rust Compiler
|
||
rustup override set nightly
|
||
rustup component add rust-src --toolchain nightly
|
||
|
||
## Verify our Custom Target, make sure it's OK
|
||
rustc \
|
||
--print cfg \
|
||
--target riscv32gc-unknown-none-elf.json
|
||
|
||
## `cargo build` requires a Rust Project, so we create an empty one.
|
||
rm -rf app
|
||
cargo new app
|
||
|
||
## Build the Rust Core Library for `riscv32gc`
|
||
## Include the `alloc` library, which will support Heap Memory in future.
|
||
## Ignore the error: `can't find crate for std`
|
||
pushd app
|
||
cargo build \
|
||
-Zbuild-std=core,alloc \
|
||
--target ../riscv32gc-unknown-none-elf.json \
|
||
|| true
|
||
popd</code></pre></div>
|
||
<p><a href="https://lupyuen.github.io/articles/rust4#appendix-build-nuttx-for-qemu">(See the <strong>Build Script</strong>)</a></p>
|
||
<p><strong>Rust Core Library</strong> for Double-Float <strong><code>riscv32gc</code></strong> is done!</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Show the Rust Core Library for `riscv32gc`
|
||
$ ls app/target/riscv32gc-unknown-none-elf/debug/deps
|
||
|
||
alloc-254848389e7e2c53.d
|
||
app-cf88b81a5fca23b3.d
|
||
compiler_builtins-d5922d64507adf16.d
|
||
core-ec2ec78e26b8c830.d
|
||
liballoc-254848389e7e2c53.rlib
|
||
liballoc-254848389e7e2c53.rmeta
|
||
libcompiler_builtins-d5922d64507adf16.rlib
|
||
libcompiler_builtins-d5922d64507adf16.rmeta
|
||
libcore-ec2ec78e26b8c830.rlib
|
||
libcore-ec2ec78e26b8c830.rmeta
|
||
librustc_std_workspace_core-3cc5bcc9f701a6e7.rlib
|
||
librustc_std_workspace_core-3cc5bcc9f701a6e7.rmeta
|
||
rustc_std_workspace_core-3cc5bcc9f701a6e7.d</code></pre></div>
|
||
<p>Now we <strong>rebuild our Rust App</strong> with the Custom Target (linked to our Rust Core Library)…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Compile our Rust App with Rust Core Library for `riscv32gc`
|
||
## We changed the Target to `riscv32gc-unknown-none-elf.json`
|
||
## TODO: Change `../apps` to the NuttX Apps Folder
|
||
rustc \
|
||
--target riscv32gc-unknown-none-elf.json \
|
||
--edition 2021 \
|
||
--emit obj \
|
||
-g \
|
||
-C panic=abort \
|
||
-O \
|
||
../apps/examples/hello_rust/hello_rust_main.rs \
|
||
-o ../apps/examples/hello_rust/*hello_rust.o \
|
||
\
|
||
-C incremental=app/target/riscv32gc-unknown-none-elf/debug/incremental \
|
||
-L dependency=app/target/riscv32gc-unknown-none-elf/debug/deps \
|
||
-L dependency=app/target/debug/deps \
|
||
--extern noprelude:alloc=`ls app/target/riscv32gc-unknown-none-elf/debug/deps/liballoc-*.rlib` \
|
||
--extern noprelude:compiler_builtins=`ls app/target/riscv32gc-unknown-none-elf/debug/deps/libcompiler_builtins-*.rlib` \
|
||
--extern noprelude:core=`ls app/target/riscv32gc-unknown-none-elf/debug/deps/libcore-*.rlib` \
|
||
-Z unstable-options</code></pre></div>
|
||
<p><a href="https://lupyuen.github.io/articles/rust4#appendix-build-nuttx-for-qemu">(See the <strong>Build Script</strong>)</a></p>
|
||
<p>(We’ll talk about the loooong options)</p>
|
||
<p><em>Are we Double-Floating yet?</em></p>
|
||
<p>Yep we have a <strong>Yummy Double-Float</strong> with 2 scoops of ice cream…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Dump the ELF Header of our Compiled Rust App
|
||
## TODO: Change `../apps` to the NuttX Apps Folder
|
||
$ riscv64-unknown-elf-readelf \
|
||
--file-header --arch-specific \
|
||
../apps/examples/hello_rust/*hello_rust.o
|
||
|
||
## We have Double-Float `riscv32gc` yay!
|
||
Flags: 0x5, RVC, double-float ABI</code></pre></div>
|
||
<p><a href="https://gist.github.com/lupyuen/e7cdef603bdb16fbc82c2bf940b5d2d8">(See the <strong>ELF Header</strong>)</a></p>
|
||
<p><em>How did we get the Rust Compiler Options?</em></p>
|
||
<p>We copied the above options from <strong><code>cargo</code> <code>build</code> <code>-v</code></strong>…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/rust4#appendix-rust-compiler-options"><strong>“Rust Compiler Options”</strong></a></li>
|
||
</ul>
|
||
<p><em>rustc vs cargo build: What’s the diff?</em></p>
|
||
<ul>
|
||
<li>
|
||
<p><strong><code>rustc</code></strong> is the Rust Compiler that compiles Rust Programs to Rust Binaries</p>
|
||
<p>(Works like GCC Compiler)</p>
|
||
</li>
|
||
<li>
|
||
<p><strong><code>cargo</code> <code>build</code></strong> wraps around <strong><code>rustc</code></strong> for Multi-Step Builds</p>
|
||
<p><a href="https://lupyuen.github.io/articles/rust3#standard-vs-embedded-rust">(Like for <strong>Rust Core Library</strong>)</a></p>
|
||
</li>
|
||
</ul>
|
||
<p>We could have called <strong><code>rustc</code></strong> for building the Rust Core Library. But it will be a bunch of steps with <a href="https://lupyuen.github.io/articles/rust4#appendix-rust-compiler-options"><strong>many many options</strong></a>.</p>
|
||
<p><img src="https://lupyuen.github.io/images/rust4-flow.jpg" alt="NuttX Links OK with Rust" /></p>
|
||
<h1 id="nuttx-links-ok-with-rust"><a class="doc-anchor" href="#nuttx-links-ok-with-rust">§</a>5 NuttX Links OK with Rust</h1>
|
||
<p><em>We compiled our Rust App with Double-Float riscv32gc…</em></p>
|
||
<p><em>Is our NuttX Build hunky dory now?</em></p>
|
||
<p>Yep <strong>NuttX builds OK now</strong>! GCC Compiler and Rust Compiler are harmonised to Double-Float…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Copy the Rust Binary that will be linked with NuttX
|
||
## TODO: Change `../apps` to the NuttX Apps Folder
|
||
cp \
|
||
../apps/examples/hello_rust/*hello_rust.o \
|
||
../apps/examples/hello_rust/*hello_rust_1.o
|
||
|
||
## NuttX should link correctly now.
|
||
## TODO: Change `../nuttx` to the NuttX Kernel Folder
|
||
pushd ../nuttx
|
||
make
|
||
popd</code></pre></div>
|
||
<p><a href="https://lupyuen.github.io/articles/rust4#appendix-build-nuttx-for-qemu">(See the <strong>Build Script</strong>)</a></p>
|
||
<p>We boot <strong>NuttX in QEMU Emulator</strong> for 32-bit RISC-V…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## For macOS:
|
||
brew install qemu
|
||
|
||
## For Debian and Ubuntu:
|
||
sudo apt install qemu-system-riscv32
|
||
|
||
## Boot NuttX in QEMU RISC-V (32-bit)
|
||
## TODO: Change `../nuttx` to the NuttX Kernel Folder
|
||
pushd ../nuttx
|
||
qemu-system-riscv32 \
|
||
-semihosting \
|
||
-M virt,aclint=on \
|
||
-cpu rv32 \
|
||
-bios none \
|
||
-kernel nuttx \
|
||
-nographic
|
||
popd</code></pre></div>
|
||
<p>Our <strong>Rust App</strong> works wonderfully on NuttX! (Pic below)</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>NuttShell (NSH) NuttX-12.4.0-RC0
|
||
|
||
nsh> hello_rust
|
||
Hello, Rust!!
|
||
|
||
## Exit QEMU: Press `Ctrl-A` then `x`</code></pre></div>
|
||
<p><a href="https://gist.github.com/lupyuen/31c78de72ade71bbdf63372b44749cd4#file-rust-on-nuttx-build-log-L356-L384">(See the <strong>NuttX Log</strong>)</a></p>
|
||
<p><em>Phew so much work to build a tiny Rust App?</em></p>
|
||
<p>Yeah. And integrating this into the <strong>NuttX Makefiles</strong> will be challenging.</p>
|
||
<p>(How would <a href="https://rust-for-linux.com/"><strong>Linux Kernel</strong></a> handle Custom Rust Targets?)</p>
|
||
<p><a href="https://github.com/rust-lang/rust/issues/65024">(More about <strong>Hard-Float Targets</strong> in RISC-V)</a></p>
|
||
<p><img src="https://lupyuen.github.io/images/rust4-title.jpg" alt="Rust Apps on Apache NuttX RTOS and QEMU RISC-V" /></p>
|
||
<h1 id="rust-build-for-64-bit-risc-v"><a class="doc-anchor" href="#rust-build-for-64-bit-risc-v">§</a>6 Rust Build for 64-bit RISC-V</h1>
|
||
<p>From 32-bit to 64-bit: We tried compiling our Rust App for <strong>64-bit RISC-V QEMU</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Build NuttX for QEMU RISC-V 64-bit
|
||
$ tools/configure.sh rv-virt:nsh64
|
||
$ make menuconfig
|
||
## TODO: Enable "Hello Rust Example"
|
||
$ make
|
||
|
||
RUSTC: hello_rust_main.rs error: Error loading target specification:
|
||
Could not find specification for target "riscv64i-unknown-none-elf".
|
||
Run `rustc --print target-list` for a list of built-in targets</code></pre></div>
|
||
<p>But Rust Compiler says that <strong><code>riscv64i</code></strong> isn’t a valid Rust Target for 64-bit RISC-V.</p>
|
||
<p><strong>Exercise for the Reader:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Is <strong><code>riscv64i</code></strong> the correct target for QEMU?</p>
|
||
<p><a href="https://www.qemu.org/docs/master/system/riscv/virt.html#supported-devices">(<strong>Hint:</strong> See this)</a></p>
|
||
<p><em>[10 points]</em></p>
|
||
<hr>
|
||
</li>
|
||
<li>
|
||
<p>How should we <strong>Fix the Build</strong>?</p>
|
||
<p><em>[10 points]</em></p>
|
||
<hr>
|
||
</li>
|
||
<li>
|
||
<p>Do we need a <strong>Custom Target</strong>?</p>
|
||
<p>(<strong>Hint:</strong> Answer is printed in this article somewhere)</p>
|
||
<p><em>[10 points]</em></p>
|
||
<hr>
|
||
</li>
|
||
<li>
|
||
<p>Will it run on <a href="https://www.hackster.io/lupyuen/8-risc-v-sbc-on-a-real-time-operating-system-ox64-nuttx-474358"><strong>Ox64 BL808 SBC</strong></a>?</p>
|
||
<p><em>[10 points]</em></p>
|
||
<hr>
|
||
</li>
|
||
</ol>
|
||
<p><img src="https://lupyuen.github.io/images/rust4-flow.jpg" alt="NuttX Links OK with Rust" /></p>
|
||
<h1 id="whats-next"><a class="doc-anchor" href="#whats-next">§</a>7 What’s Next</h1>
|
||
<p>Today we learnt a bit more about <strong>C-to-Rust Interop</strong> (pic above)…</p>
|
||
<ul>
|
||
<li>
|
||
<p>NuttX failed to link our Rust App because Rust compiles for <strong>Soft-Float</strong>, NuttX expects <strong>Double-Float</strong></p>
|
||
<p>(Software vs Hardware Floating-Point)</p>
|
||
</li>
|
||
<li>
|
||
<p>But Rust <strong>doesn’t support Double-Float</strong></p>
|
||
<p>(Built-In Target doesn’t exist for 32-bit RISC-V)</p>
|
||
</li>
|
||
<li>
|
||
<p>So we created a <strong>Rust Custom Target</strong> for Double-Float: RISCV32GC</p>
|
||
<p>(By mashing up RISCV32I and RISCV64GC)</p>
|
||
</li>
|
||
<li>
|
||
<p>We rebuilt the <strong>Rust Core Library</strong> for Double-Float</p>
|
||
<p>(With <strong><code>cargo</code> <code>build</code></strong>)</p>
|
||
</li>
|
||
<li>
|
||
<p>And our Rust App <strong>builds OK with NuttX</strong></p>
|
||
<p>(Runs perfectly on QEMU Emulator for RISC-V)</p>
|
||
</li>
|
||
</ul>
|
||
<p>Many Thanks to my <a href="https://lupyuen.github.io/articles/sponsor"><strong>GitHub Sponsors</strong></a> (and the awesome NuttX Community) for supporting my work! This article wouldn’t have been possible without your support.</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/sponsor"><strong>Sponsor me a coffee</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://news.ycombinator.com/item?id=40101628"><strong>Discuss this article on Hacker News</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/nuttx-ox64"><strong>My Current Project: “Apache NuttX RTOS for Ox64 BL808”</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/nuttx-star64"><strong>My Other Project: “NuttX for Star64 JH7110”</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/pinephone-nuttx"><strong>Older Project: “NuttX for PinePhone”</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io"><strong>Check out my articles</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/rss.xml"><strong>RSS Feed</strong></a></p>
|
||
</li>
|
||
</ul>
|
||
<p><em>Got a question, comment or suggestion? Create an Issue or submit a Pull Request here…</em></p>
|
||
<p><a href="https://github.com/lupyuen/lupyuen.github.io/blob/master/src/rust4.md"><strong>lupyuen.github.io/src/rust4.md</strong></a></p>
|
||
<p><img src="https://lupyuen.github.io/images/rust4-flow.jpg" alt="Build NuttX for QEMU with Rust App" /></p>
|
||
<h1 id="appendix-build-nuttx-for-qemu"><a class="doc-anchor" href="#appendix-build-nuttx-for-qemu">§</a>8 Appendix: Build NuttX for QEMU</h1>
|
||
<p>Follow these steps to build <strong>NuttX for QEMU Emulator</strong> (32-bit RISC-V) bundled with our <strong>Rust App</strong> (pic above)…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>#!/usr/bin/env bash
|
||
# Build NuttX for QEMU RISC-V 32-bit with Rust App
|
||
|
||
## TODO: Set PATH
|
||
export PATH="$HOME/xpack-riscv-none-elf-gcc-13.2.0-2/bin:$PATH"
|
||
|
||
set -e # Exit when any command fails
|
||
set -x # Echo commands
|
||
|
||
## Build NuttX
|
||
function build_nuttx {
|
||
|
||
## Go to NuttX Folder
|
||
pushd ../nuttx
|
||
|
||
## Build NuttX
|
||
make -j 8
|
||
|
||
## Return to previous folder
|
||
popd
|
||
}
|
||
|
||
## Build Rust App for QEMU RISC-V 32-bit with Rust Custom Target
|
||
function build_rust_riscv32 {
|
||
|
||
## Go to NuttX Folder
|
||
pushd ../nuttx
|
||
|
||
## Download our Custom Target for `riscv32gc`
|
||
rm -f riscv32gc-unknown-none-elf.json
|
||
wget https://raw.githubusercontent.com/lupyuen/nuttx-rust-app/main/riscv32gc-unknown-none-elf.json
|
||
|
||
## Custom Target needs Nightly Build of Rust Compiler
|
||
rustup override set nightly
|
||
rustup component add rust-src --toolchain nightly
|
||
|
||
## Verify our Custom Target, make sure it's OK
|
||
rustc \
|
||
--print cfg \
|
||
--target riscv32gc-unknown-none-elf.json
|
||
|
||
## `cargo build` requires a Rust Project, so we create an empty one.
|
||
rm -rf app
|
||
cargo new app
|
||
|
||
## Build the Rust Core Library for `riscv32gc`
|
||
## Include the `alloc` library, which will support Heap Memory in future.
|
||
## Ignore the error: `can't find crate for std`
|
||
pushd app
|
||
cargo build \
|
||
-Zbuild-std=core,alloc \
|
||
--target ../riscv32gc-unknown-none-elf.json \
|
||
|| true
|
||
popd
|
||
|
||
## Compile our Rust App with Rust Core Library for `riscv32gc`
|
||
## We changed the Target to `riscv32gc-unknown-none-elf.json`
|
||
rustc \
|
||
--target riscv32gc-unknown-none-elf.json \
|
||
--edition 2021 \
|
||
--emit obj \
|
||
-g \
|
||
-C panic=abort \
|
||
-O \
|
||
../apps/examples/hello_rust/hello_rust_main.rs \
|
||
-o ../apps/examples/hello_rust/*hello_rust.o \
|
||
\
|
||
-C incremental=app/target/riscv32gc-unknown-none-elf/debug/incremental \
|
||
-L dependency=app/target/riscv32gc-unknown-none-elf/debug/deps \
|
||
-L dependency=app/target/debug/deps \
|
||
--extern noprelude:alloc=`ls app/target/riscv32gc-unknown-none-elf/debug/deps/liballoc-*.rlib` \
|
||
--extern noprelude:compiler_builtins=`ls app/target/riscv32gc-unknown-none-elf/debug/deps/libcompiler_builtins-*.rlib` \
|
||
--extern noprelude:core=`ls app/target/riscv32gc-unknown-none-elf/debug/deps/libcore-*.rlib` \
|
||
-Z unstable-options
|
||
|
||
## NuttX Build need us to copy hello_rust.o to hello_rust_1.o
|
||
cp \
|
||
../apps/examples/hello_rust/*hello_rust.o \
|
||
../apps/examples/hello_rust/*hello_rust_1.o
|
||
|
||
## Return to previous folder
|
||
popd
|
||
}
|
||
|
||
## Configure the NuttX Build
|
||
make distclean
|
||
tools/configure.sh rv-virt:nsh
|
||
|
||
## Enable the Hello Rust App
|
||
kconfig-tweak --enable CONFIG_EXAMPLES_HELLO_RUST
|
||
|
||
## Update the Kconfig Dependencies
|
||
make olddefconfig
|
||
|
||
## Build NuttX. Ignore the error: `can't link soft-float modules with double-float modules`
|
||
build_nuttx || true
|
||
|
||
## Build the Rust App with Custom Target
|
||
build_rust_riscv32
|
||
|
||
## Link the Rust App with NuttX
|
||
build_nuttx
|
||
|
||
## Show the size
|
||
riscv-none-elf-size nuttx
|
||
|
||
## Export the Binary Image to nuttx.bin
|
||
riscv-none-elf-objcopy \
|
||
-O binary \
|
||
nuttx \
|
||
nuttx.bin
|
||
|
||
## Copy the config
|
||
cp .config nuttx.config
|
||
|
||
## Dump the NuttX Kernel Disassembly to nuttx.S
|
||
riscv-none-elf-objdump \
|
||
--syms --source --reloc --demangle --line-numbers --wide \
|
||
--debugging \
|
||
nuttx \
|
||
>nuttx.S \
|
||
2>&1
|
||
|
||
## Dump the Rust App Disassembly to hello_rust_1.S
|
||
riscv-none-elf-objdump \
|
||
--syms --source --reloc --demangle --line-numbers --wide \
|
||
--debugging \
|
||
../apps/examples/hello_rust/*1.o \
|
||
>hello_rust_1.S \
|
||
2>&1
|
||
|
||
## Start the emulator
|
||
qemu-system-riscv32 \
|
||
-semihosting \
|
||
-M virt,aclint=on \
|
||
-cpu rv32 \
|
||
-kernel nuttx \
|
||
-nographic \
|
||
-bios none</code></pre></div>
|
||
<p><a href="https://gist.github.com/lupyuen/69da35a027cf780680944010b4a85fe7">(See the <strong>Build Script</strong>)</a></p>
|
||
<blockquote>
|
||
<p><img src="https://lupyuen.github.io/images/rust4-flow1b.jpg" alt="Building our Rust App" /></p>
|
||
</blockquote>
|
||
<h1 id="appendix-rust-compiler-options"><a class="doc-anchor" href="#appendix-rust-compiler-options">§</a>9 Appendix: Rust Compiler Options</h1>
|
||
<p><em>How did we get the Rust Compiler Options for riscv32gc?</em></p>
|
||
<p>Earlier we compiled our Rust App with Rust Core Library for <strong><code>riscv32gc</code></strong>…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/rust4#build-the-rust-core-library"><strong>“Build the Rust Core Library”</strong></a></li>
|
||
</ul>
|
||
<p>And we saw these <strong>Rust Compiler Options</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Compile our Rust App with Rust Core Library for `riscv32gc`
|
||
## We changed the Target to `riscv32gc-unknown-none-elf.json`
|
||
## TODO: Change `../apps` to the NuttX Apps Folder
|
||
rustc \
|
||
--target riscv32gc-unknown-none-elf.json \
|
||
--edition 2021 \
|
||
--emit obj \
|
||
-g \
|
||
-C panic=abort \
|
||
-O \
|
||
../apps/examples/hello_rust/hello_rust_main.rs \
|
||
-o ../apps/examples/hello_rust/*hello_rust.o \
|
||
\
|
||
-C incremental=app/target/riscv32gc-unknown-none-elf/debug/incremental \
|
||
-L dependency=app/target/riscv32gc-unknown-none-elf/debug/deps \
|
||
-L dependency=app/target/debug/deps \
|
||
--extern noprelude:alloc=`ls app/target/riscv32gc-unknown-none-elf/debug/deps/liballoc-*.rlib` \
|
||
--extern noprelude:compiler_builtins=`ls app/target/riscv32gc-unknown-none-elf/debug/deps/libcompiler_builtins-*.rlib` \
|
||
--extern noprelude:core=`ls app/target/riscv32gc-unknown-none-elf/debug/deps/libcore-*.rlib` \
|
||
-Z unstable-options</code></pre></div>
|
||
<p>The above options were copied from <strong><code>cargo</code> <code>build</code> <code>-v</code></strong>, here’s how…</p>
|
||
<p>Remember we ran <a href="https://lupyuen.github.io/articles/rust4#build-the-rust-core-library"><strong><code>cargo</code> <code>build</code></strong></a> to compile the <a href="https://lupyuen.github.io/articles/rust3#standard-vs-embedded-rust"><strong>Rust Core Library</strong></a>?</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Download our Custom Target for `riscv32gc`
|
||
rm -f riscv32gc-unknown-none-elf.json
|
||
wget https://raw.githubusercontent.com/lupyuen/nuttx-rust-app/main/riscv32gc-unknown-none-elf.json
|
||
|
||
## Custom Target needs Nightly Build of Rust Compiler
|
||
rustup override set nightly
|
||
rustup component add rust-src --toolchain nightly
|
||
|
||
## Verify our Custom Target, make sure it's OK
|
||
rustc \
|
||
--print cfg \
|
||
--target riscv32gc-unknown-none-elf.json
|
||
|
||
## `cargo build` requires a Rust Project, so we create an empty one.
|
||
rm -rf app
|
||
cargo new app
|
||
|
||
## Build the Rust Core Library for `riscv32gc`
|
||
## Include the `alloc` library, which will support Heap Memory in future.
|
||
## Ignore the error: `can't find crate for std`
|
||
pushd app
|
||
cargo build \
|
||
-Zbuild-std=core,alloc \
|
||
--target ../riscv32gc-unknown-none-elf.json \
|
||
|| true
|
||
popd</code></pre></div>
|
||
<ul>
|
||
<li>
|
||
<p><strong><code>cargo</code> <code>build</code></strong> will call <strong><code>rustc</code></strong> with a whole bunch of options.</p>
|
||
</li>
|
||
<li>
|
||
<p>We switched it to <strong><code>cargo</code> <code>build</code> <code>-v</code></strong>, which will dump the <strong><code>rustc</code></strong> options.</p>
|
||
</li>
|
||
<li>
|
||
<p>Hence we see the options that will compile a Rust App with our Rust Core Library for <strong><code>riscv32gc</code></strong>…</p>
|
||
<p>(TODO: Will these options change in future versions of <strong><code>cargo</code></strong>?)</p>
|
||
</li>
|
||
</ul>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Build the Rust Core Library for `riscv32gc`
|
||
## And the Empty Rust Project for `riscv32gc`
|
||
## `-v` will dump the `rustc` options
|
||
$ cargo build -v \
|
||
-Zbuild-std=core,alloc \
|
||
--target ../riscv32gc-unknown-none-elf.json
|
||
|
||
Compiling compiler_builtins v0.1.101
|
||
Compiling core v0.0.0 ($HOME/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/core)
|
||
|
||
## Generate the Rust Build Script for `riscv32gc`
|
||
|
||
Running `$HOME/.rustup/toolchains/nightly-x86_64-apple-darwin/bin/rustc
|
||
--crate-name build_script_build
|
||
--edition=2018
|
||
$HOME/.cargo/registry/src/index.crates.io-6f17d22bba15001f/compiler_builtins-0.1.101/build.rs
|
||
--error-format=json
|
||
--json=diagnostic-rendered-ansi,artifacts,future-incompat
|
||
--diagnostic-width=94
|
||
--crate-type bin
|
||
--emit=dep-info,link
|
||
-C embed-bitcode=no
|
||
-C debuginfo=2
|
||
-C split-debuginfo=unpacked
|
||
--cfg 'feature="compiler-builtins"'
|
||
--cfg 'feature="core"'
|
||
--cfg 'feature="default"'
|
||
--cfg 'feature="rustc-dep-of-std"'
|
||
-C metadata=9bd0bac7535b33a8
|
||
-C extra-filename=-9bd0bac7535b33a8
|
||
--out-dir $HOME/riscv/nuttx-rust-app/app/target/debug/build/compiler_builtins-9bd0bac7535b33a8
|
||
-Z force-unstable-if-unmarked
|
||
-L dependency=$HOME/riscv/nuttx-rust-app/app/target/debug/deps
|
||
--cap-lints allow`
|
||
|
||
## Build the Rust Core Library for `riscv32gc`
|
||
|
||
Running `$HOME/.rustup/toolchains/nightly-x86_64-apple-darwin/bin/rustc
|
||
--crate-name core
|
||
--edition=2021
|
||
$HOME/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/lib.rs
|
||
--error-format=json
|
||
--json=diagnostic-rendered-ansi,artifacts,future-incompat
|
||
--diagnostic-width=94
|
||
--crate-type lib
|
||
--emit=dep-info,metadata,link
|
||
-C embed-bitcode=no
|
||
-C debuginfo=2
|
||
-C metadata=d271c6ebb87f9b41
|
||
-C extra-filename=-d271c6ebb87f9b41
|
||
--out-dir $HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps
|
||
--target $HOME/riscv/nuttx-rust-app/riscv32gc-unknown-none-elf.json
|
||
-Z force-unstable-if-unmarked
|
||
-L dependency=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps
|
||
-L dependency=$HOME/riscv/nuttx-rust-app/app/target/debug/deps
|
||
--cap-lints allow`
|
||
|
||
Running `$HOME/riscv/nuttx-rust-app/app/target/debug/build/compiler_builtins-9bd0bac7535b33a8/build-script-build`
|
||
|
||
Compiling rustc-std-workspace-core v1.99.0 ($HOME/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/rustc-std-workspace-core)
|
||
|
||
## Build the Rust Workspace Core for `riscv32gc`
|
||
|
||
Running `$HOME/.rustup/toolchains/nightly-x86_64-apple-darwin/bin/rustc
|
||
--crate-name rustc_std_workspace_core
|
||
--edition=2021
|
||
$HOME/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/rustc-std-workspace-core/lib.rs
|
||
--error-format=json
|
||
--json=diagnostic-rendered-ansi,artifacts,future-incompat
|
||
--diagnostic-width=94
|
||
--crate-type lib
|
||
--emit=dep-info,metadata,link
|
||
-C embed-bitcode=no
|
||
-C debuginfo=2
|
||
-C metadata=52e0df2b2cc19b6e
|
||
-C extra-filename=-52e0df2b2cc19b6e
|
||
--out-dir $HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps
|
||
--target $HOME/riscv/nuttx-rust-app/riscv32gc-unknown-none-elf.json
|
||
-Z force-unstable-if-unmarked
|
||
-L dependency=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps
|
||
-L dependency=$HOME/riscv/nuttx-rust-app/app/target/debug/deps
|
||
--extern core=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/libcore-d271c6ebb87f9b41.rmeta
|
||
--cap-lints allow`
|
||
|
||
## Build the Rust Compiler Builtins for `riscv32gc`
|
||
|
||
Running `$HOME/.rustup/toolchains/nightly-x86_64-apple-darwin/bin/rustc
|
||
--crate-name compiler_builtins
|
||
--edition=2018
|
||
$HOME/.cargo/registry/src/index.crates.io-6f17d22bba15001f/compiler_builtins-0.1.101/src/lib.rs
|
||
--error-format=json
|
||
--json=diagnostic-rendered-ansi,artifacts,future-incompat
|
||
--diagnostic-width=94
|
||
--crate-type lib
|
||
--emit=dep-info,metadata,link
|
||
-C embed-bitcode=no
|
||
-C debuginfo=2
|
||
--cfg 'feature="compiler-builtins"'
|
||
--cfg 'feature="core"'
|
||
--cfg 'feature="default"'
|
||
--cfg 'feature="rustc-dep-of-std"'
|
||
-C metadata=cd0d33c2bd30ca51
|
||
-C extra-filename=-cd0d33c2bd30ca51
|
||
--out-dir $HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps
|
||
--target $HOME/riscv/nuttx-rust-app/riscv32gc-unknown-none-elf.json
|
||
-Z force-unstable-if-unmarked
|
||
-L dependency=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps
|
||
-L dependency=$HOME/riscv/nuttx-rust-app/app/target/debug/deps
|
||
--extern core=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/librustc_std_workspace_core-52e0df2b2cc19b6e.rmeta
|
||
--cap-lints allow
|
||
--cfg 'feature="unstable"'
|
||
--cfg 'feature="mem"'`
|
||
|
||
Compiling alloc v0.0.0 ($HOME/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/alloc)
|
||
|
||
## Build the Rust Alloc Library for `riscv32gc`
|
||
## Which will support Heap Memory in future
|
||
|
||
Running `$HOME/.rustup/toolchains/nightly-x86_64-apple-darwin/bin/rustc
|
||
--crate-name alloc
|
||
--edition=2021
|
||
$HOME/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/lib.rs
|
||
--error-format=json
|
||
--json=diagnostic-rendered-ansi,artifacts,future-incompat
|
||
--diagnostic-width=94
|
||
--crate-type lib
|
||
--emit=dep-info,metadata,link
|
||
-C embed-bitcode=no
|
||
-C debuginfo=2
|
||
-C metadata=5d7bc2e4f3c29e08
|
||
-C extra-filename=-5d7bc2e4f3c29e08
|
||
--out-dir $HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps
|
||
--target $HOME/riscv/nuttx-rust-app/riscv32gc-unknown-none-elf.json
|
||
-Z force-unstable-if-unmarked
|
||
-L dependency=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps
|
||
-L dependency=$HOME/riscv/nuttx-rust-app/app/target/debug/deps
|
||
--extern compiler_builtins=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/libcompiler_builtins-cd0d33c2bd30ca51.rmeta
|
||
--extern core=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/libcore-d271c6ebb87f9b41.rmeta
|
||
--cap-lints allow`
|
||
|
||
Compiling app v0.1.0 ($HOME/riscv/nuttx-rust-app/app)
|
||
|
||
## Compile our Empty Rust Project with Rust Core Library for `riscv32gc`
|
||
## These are the options that we copied into NuttX Build...
|
||
|
||
Running `$HOME/.rustup/toolchains/nightly-x86_64-apple-darwin/bin/rustc
|
||
--crate-name app
|
||
--edition=2021
|
||
src/main.rs
|
||
--error-format=json
|
||
--json=diagnostic-rendered-ansi,artifacts,future-incompat
|
||
--diagnostic-width=94
|
||
--crate-type bin
|
||
--emit=dep-info,link
|
||
-C embed-bitcode=no
|
||
-C debuginfo=2
|
||
-C metadata=1ff442e6481e1397
|
||
-C extra-filename=-1ff442e6481e1397
|
||
--out-dir $HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps
|
||
--target $HOME/riscv/nuttx-rust-app/riscv32gc-unknown-none-elf.json
|
||
-C incremental=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/incremental
|
||
-L dependency=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps
|
||
-L dependency=$HOME/riscv/nuttx-rust-app/app/target/debug/deps
|
||
--extern 'noprelude:alloc=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/liballoc-5d7bc2e4f3c29e08.rlib'
|
||
--extern 'noprelude:compiler_builtins=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/libcompiler_builtins-cd0d33c2bd30ca51.rlib'
|
||
--extern 'noprelude:core=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/libcore-d271c6ebb87f9b41.rlib'
|
||
-Z unstable-options`
|
||
|
||
## Ignore this error. Rust Standard Library and `println` won't work for `riscv32gc`
|
||
|
||
error[E0463]: can't find crate for `std`
|
||
|
|
||
= note: the `riscv32gc-unknown-none-elf` target may not support the standard library
|
||
= note: `std` is required by `app` because it does not declare `#![no_std]`
|
||
= help: consider building the standard library from source with `cargo build -Zbuild-std`
|
||
|
||
error: cannot find macro `println` in this scope
|
||
--> src/main.rs:2:5
|
||
|
|
||
2 | println!("Hello, world!");
|
||
| ^^^^^^^
|
||
|
||
error: `#[panic_handler]` function required, but not found
|
||
|
||
For more information about this error, try `rustc --explain E0463`.
|
||
error: could not compile `app` (bin "app") due to 3 previous errors
|
||
|
||
Caused by:
|
||
process didn't exit successfully: `$HOME/.rustup/toolchains/nightly-x86_64-apple-darwin/bin/rustc --crate-name app --edition=2021 src/main.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=94 --crate-type bin --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 -C metadata=1ff442e6481e1397 -C extra-filename=-1ff442e6481e1397 --out-dir $HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps --target $HOME/riscv/nuttx-rust-app/riscv32gc-unknown-none-elf.json -C incremental=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/incremental -L dependency=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps -L dependency=$HOME/riscv/nuttx-rust-app/app/target/debug/deps --extern 'noprelude:alloc=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/liballoc-5d7bc2e4f3c29e08.rlib' --extern 'noprelude:compiler_builtins=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/libcompiler_builtins-cd0d33c2bd30ca51.rlib' --extern 'noprelude:core=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/libcore-d271c6ebb87f9b41.rlib' -Z unstable-options` (exit status: 1)</code></pre></div>
|
||
|
||
<!-- Begin scripts/rustdoc-after.html: Post-HTML for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
|
||
<!-- Begin Theme Picker and Prism Theme -->
|
||
<script src="../theme.js"></script>
|
||
<script src="../prism.js"></script>
|
||
<!-- Theme Picker and Prism Theme -->
|
||
|
||
<!-- End scripts/rustdoc-after.html -->
|
||
|
||
|
||
</body>
|
||
</html> |