lupyuen.org/articles/rust4.html
Lup Yuen Lee 6e2f142414
Some checks are pending
Build Articles / build (push) Waiting to run
Commit from GitHub Actions
2025-01-04 06:09:02 +00:00

1066 lines
No EOL
53 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 Wont Double-Float">2 Rust Wont 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="Whats Next">7 Whats 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&#39;t link soft-float modules with double-float modules</code></pre></div>
<p>Lets 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>doesnt 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 wont 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 &quot;Hello Rust Example&quot;
## Build NuttX bundled with the Rust App
$ make
riscv64-unknown-elf-ld: libapps.a
hello_rust_1.o:
can&#39;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 couldnt link the NuttX Binaries with the Rust Binaries.</p>
<p>Heres 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 wont 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>Thats why GCC Linker <strong>wont 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 wont 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 wont mix! Lets fix this…</p>
<p><img src="https://lupyuen.github.io/images/rust4-flow3.jpg" alt="Rust Wont Double-Float" /></p>
<h1 id="rust-wont-double-float"><a class="doc-anchor" href="#rust-wont-double-float">§</a>2 Rust Wont Double-Float</h1>
<p><em>What if we ask Rust Compiler to compile for Double-Float? RV32IMAFDC (Pic above)</em></p>
<p>Lets 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>wont work</strong></p>
<div class="example-wrap"><pre class="language-bash"><code>Error loading target specification:
Could not find specification for target &quot;riscv32gc-unknown-none-elf&quot;.
Run `rustc --print target-list` for a list of built-in targets</code></pre></div>
<p>Thats because <strong><code>riscv32gc</code></strong> isnt 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>Wont 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>Thats 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>Well 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
{
&quot;arch&quot;: &quot;riscv32&quot;,
&quot;atomic-cas&quot;: false,
&quot;cpu&quot;: &quot;generic-rv32&quot;,
&quot;data-layout&quot;: &quot;e-m:e-p:32:32-i64:64-n32-S128&quot;,
&quot;eh-frame-header&quot;: false,
&quot;emit-debug-gdb-scripts&quot;: false,
&quot;is-builtin&quot;: true,
&quot;linker&quot;: &quot;rust-lld&quot;,
&quot;linker-flavor&quot;: &quot;ld.lld&quot;,
&quot;llvm-target&quot;: &quot;riscv32&quot;,
&quot;max-atomic-width&quot;: 0,
&quot;panic-strategy&quot;: &quot;abort&quot;,
&quot;relocation-model&quot;: &quot;static&quot;,
&quot;target-pointer-width&quot;: &quot;32&quot;
}</code></pre></div>
<p>Thats 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
{
&quot;arch&quot;: &quot;riscv64&quot;,
&quot;code-model&quot;: &quot;medium&quot;,
&quot;cpu&quot;: &quot;generic-rv64&quot;,
&quot;data-layout&quot;: &quot;e-m:e-p:64:64-i64:64-i128:128-n32:64-S128&quot;,
&quot;eh-frame-header&quot;: false,
&quot;emit-debug-gdb-scripts&quot;: false,
&quot;features&quot;: &quot;+m,+a,+f,+d,+c&quot;,
&quot;is-builtin&quot;: true,
&quot;linker&quot;: &quot;rust-lld&quot;,
&quot;linker-flavor&quot;: &quot;ld.lld&quot;,
&quot;llvm-abiname&quot;: &quot;lp64d&quot;,
&quot;llvm-target&quot;: &quot;riscv64&quot;,
&quot;max-atomic-width&quot;: 64,
&quot;panic-strategy&quot;: &quot;abort&quot;,
&quot;relocation-model&quot;: &quot;static&quot;,
&quot;supported-sanitizers&quot;: [ &quot;kernel-address&quot; ],
&quot;target-pointer-width&quot;: &quot;64&quot;
}</code></pre></div>
<p>Which has more goodies inside: features, llvm-abiname, …</p>
<p><em>Were 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>{
&quot;arch&quot;: &quot;riscv32&quot;,
&quot;cpu&quot;: &quot;generic-rv32&quot;,
&quot;data-layout&quot;: &quot;e-m:e-p:32:32-i64:64-n32-S128&quot;,
&quot;eh-frame-header&quot;: false,
&quot;emit-debug-gdb-scripts&quot;: false,
&quot;features&quot;: &quot;+m,+a,+f,+d,+c&quot;,
&quot;linker&quot;: &quot;rust-lld&quot;,
&quot;linker-flavor&quot;: &quot;ld.lld&quot;,
&quot;llvm-abiname&quot;: &quot;ilp32d&quot;,
&quot;llvm-target&quot;: &quot;riscv32&quot;,
&quot;max-atomic-width&quot;: 0,
&quot;panic-strategy&quot;: &quot;abort&quot;,
&quot;relocation-model&quot;: &quot;static&quot;,
&quot;target-pointer-width&quot;: &quot;32&quot;
}</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>(Its 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, were 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&#39;s because Rust Core Library for `riscv32gc` is missing
error[E0463]: can&#39;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 its 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&#39;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&#39;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>(Well 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: Whats 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&gt; 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 &quot;Hello Rust Example&quot;
$ make
RUSTC: hello_rust_main.rs error: Error loading target specification:
Could not find specification for target &quot;riscv64i-unknown-none-elf&quot;.
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> isnt 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 Whats 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>doesnt support Double-Float</strong></p>
<p>(Built-In Target doesnt 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 wouldnt 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=&quot;$HOME/xpack-riscv-none-elf-gcc-13.2.0-2/bin:$PATH&quot;
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&#39;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&#39;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&#39;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 \
&gt;nuttx.S \
2&gt;&amp;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 \
&gt;hello_rust_1.S \
2&gt;&amp;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>, heres 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&#39;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&#39;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 &#39;feature=&quot;compiler-builtins&quot;&#39;
--cfg &#39;feature=&quot;core&quot;&#39;
--cfg &#39;feature=&quot;default&quot;&#39;
--cfg &#39;feature=&quot;rustc-dep-of-std&quot;&#39;
-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 &#39;feature=&quot;compiler-builtins&quot;&#39;
--cfg &#39;feature=&quot;core&quot;&#39;
--cfg &#39;feature=&quot;default&quot;&#39;
--cfg &#39;feature=&quot;rustc-dep-of-std&quot;&#39;
-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 &#39;feature=&quot;unstable&quot;&#39;
--cfg &#39;feature=&quot;mem&quot;&#39;`
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 &#39;noprelude:alloc=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/liballoc-5d7bc2e4f3c29e08.rlib&#39;
--extern &#39;noprelude:compiler_builtins=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/libcompiler_builtins-cd0d33c2bd30ca51.rlib&#39;
--extern &#39;noprelude:core=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/libcore-d271c6ebb87f9b41.rlib&#39;
-Z unstable-options`
## Ignore this error. Rust Standard Library and `println` won&#39;t work for `riscv32gc`
error[E0463]: can&#39;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
--&gt; src/main.rs:2:5
|
2 | println!(&quot;Hello, world!&quot;);
| ^^^^^^^
error: `#[panic_handler]` function required, but not found
For more information about this error, try `rustc --explain E0463`.
error: could not compile `app` (bin &quot;app&quot;) due to 3 previous errors
Caused by:
process didn&#39;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 &#39;noprelude:alloc=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/liballoc-5d7bc2e4f3c29e08.rlib&#39; --extern &#39;noprelude:compiler_builtins=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/libcompiler_builtins-cd0d33c2bd30ca51.rlib&#39; --extern &#39;noprelude:core=$HOME/riscv/nuttx-rust-app/app/target/riscv32gc-unknown-none-elf/debug/deps/libcore-d271c6ebb87f9b41.rlib&#39; -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>