Rust on Dreamcast: Difference between revisions

From dreamcast.wiki
Jump to navigation Jump to search
(Replaced content with "thumb|Ferris holding his Dreamcast controller '''Please visit [https://dreamcast.rs/ dreamcast.rs]!''' The Rust for Dreamcast documentation has now [https://dreamcast.rs been migrated into an mdBook]!")
Tag: Replaced
 
(96 intermediate revisions by the same user not shown)
Line 1: Line 1:
[[File:Rust-dc-logo.png|thumb|Ferris holding his Dreamcast controller]]
[[File:Rust-dc-logo.png|thumb|Ferris holding his Dreamcast controller]]


'''WIP''': This article is currently under construction. The repos linked to below are not yet live.
'''Please visit [https://dreamcast.rs/ dreamcast.rs]!'''


'''Rust''' is a systems programming language rising in popularity which emphasizes memory safety and performance. Due to its operating at a low level, it is an ideal candidate for running on the Dreamcast. Doing so presents a bit of a challenge, however, as the official Rust compiler is based on the [https://llvm.org/ LLVM] toolchain infrastructure, which does not support the Dreamcast CPU's SuperH architecture. Dreamcast programming is instead done with [https://gcc.gnu.org/ GCC], the GNU Compiler Collection. There are currently two viable solutions to this challenge:
The Rust for Dreamcast documentation has now [https://dreamcast.rs been migrated into an mdBook]!
 
* '''rustc_codegen_gcc''': A libgccjit-based codegen backend for rustc (preferred method)
* '''gccrs''': a Rust frontend for GCC
 
Neither solution is complete at this time, and both are under active development. Using either of them to target the Dreamcast should be considered experimental. '''rustc_codegen_gcc''' is quite further along, however, and is usable with some patience with limitations and rapid change. '''libcore''' and '''liballoc''' work, and [[KallistiOS]] bindings are planned. On the other hand, '''gccrs''' can compile for Dreamcast, but is in a very early stage, with much of the language unimplemented and no '''libcore''' support. Below we will focus on using '''rustc_codegen_gcc'''. For more information on using '''gccrs''', see the [[gccrs]] page.
 
=Using rustc_codegen_gcc to develop on Dreamcast=
With [https://github.com/rust-lang/rustc_codegen_gcc rustc_codegen_gcc], we can interface the standard '''rustc''' compiler frontend with '''libgccjit''', a GCC code-generation API. With the help of the [https://github.com/darcagn/rust-for-dreamcast '''Rust-for-Dreamcast''' repo] and the [https://github.com/darcagn/kos-rs '''kos-rs''' crate] containing [[KallistiOS]] bindings, we can set up '''rustc_codegen_gcc''' to compile Rust programs with [https://doc.rust-lang.org/core/ '''core'''] and [https://doc.rust-lang.org/alloc/ '''alloc'''] support (but not the entirety of [https://doc.rust-lang.org/std/ '''std''']). Rust-for-Dreamcast includes wrapper scripts to invoke the rustc and '''cargo''' tools in a familiar way. The familiar borrow checker still works, and one can import and use <code>no_std</code> crates. Despite this support, '''rustc_codegen_gcc''' is still in active development, so if using such a setup, expect that things may change rapidly over time. We will need to use some patches and workarounds to make this solution work. See the rustc_codegen_gcc [https://blog.antoyo.xyz/ progress reports] for more information on the project's progress.
 
'''What Works'''
* '''libcore''' -- the core components of the language for running on bare metal
* '''liballoc''' -- the core components of the language that require a heap, including collections
* linking to KallistiOS -- KallistiOS can be used if one manually manages interoperating with C via '''unsafe'''
'''What's Planned'''
* libc support -- Adding KallistiOS support to Rust's libc crate
* '''libstd''' support -- built-in language support for I/O, networking, threads, time and date, HashMap/HashSet, unwinding on panic, etc.
* KallistiOS bindings -- properly idiomatic Rust support for KallistiOS
 
==Prerequisites==
 
We will build rustc_codegen_gcc support for the Dreamcast in the instructions below. Before we begin, though:
* You must already have a KallistiOS development environment set up. This means you have created a cross-compiling toolchain for SH4, you have set up your KallistiOS <code>environ.sh</code> file, and you have built KallistiOS with it. Ideally, you will already have some familiarity with KallistiOS. See [[Getting Started with Dreamcast development]] for more information, as well as the [https://kos-docs.dreamcast.wiki/ KallistiOS Doxygen].
** For the purposes of this guide, we will assume you are using the standard paths for Dreamcast development tools; i.e. your environment is set up in  <code>/opt/toolchains/dc</code>. Some included scripts and examples may assume this.
** Your KallistiOS installation will need its floating point precision setting set to <code>m4-single</code>. At this time, rustc_codegen_gcc support will not compile with KallistiOS's default <code>-m4-single-only</code> setting. This setting can be changed in KallistiOS's <code>environ.sh</code>, but changing the setting may require you to rebuild your toolchain if you have not built it with <code>m4-single</code> support (which is off by default, but can be enabled in the <code>config.mk</code> file). Once you modify the setting in your <code>environ.sh</code> and re-source the <code>environ.sh</code>, you'll need to rebuild KallistiOS with a <code>make clean</code> and <code>make</code> for the changes to take effect. Keep in mind, however, that because KallistiOS doesn't officially support <code>-m4-single</code> yet, some things may be broken, especially libraries in '''kos-ports''' that haven't been heavily tested.
* You must already have a relatively up-to-date Rust installation, either using your operating system's package manager or [https://rustup.rs/ rustup]. Ideally, you will already have some familiarity with Rust's tools.
 
==Building a cross-compiling libgccjit.so for rustc_codegen_gcc==
Before we can use '''rustc_codegen_gcc''', we must compile <code>libgccjit.so</code>, the '''libgccjit''' library, for your system. This entails building a unique copy of the SH4 toolchain in its own directory under <code>/opt/toolchains/dc/rust</code>, using a forked version of GCC with enhancements made to '''libgccjit'''.
 
We will first clone the <code>rust-for-dreamcast</code> repository, which contains various supporting files needed to create Rust support for Dreamcast. Using <code>git</code>, clone the <code>rust-for-dreamcast</code> repository to <code>/opt/toolchains/dc/rust</code>:
git clone https://github.com/darcagn/rust-for-dreamcast /opt/toolchains/dc/rust
Enter your KallistiOS installation's <code>dc-chain</code> directory:
cd /opt/toolchains/dc/kos/utils/dc-chain
Clear out any existing build files:
make clean-keep-archives
Copy the necessary toolchain patches to your <code>dc-chain</code> setup:
cp /opt/toolchains/dc/rust/toolchain/*.diff patches/
Copy the '''rustc_codegen_gcc''' configuration file into place:
cp /opt/toolchains/dc/rust/toolchain/config.mk.rustc.sample config.mk
Make any desired changes to the configuration (e.g., change <code>makejobs=-j2</code> to the number of CPU threads you'd like to use during compilation), and then compile the SH4 toolchain:
make build-sh4
When this command is completed successfully, a <code>libgccjit.so</code> will be installed to <code>/opt/toolchains/dc/rust/sh-elf/lib/libgccjit.so</code>.
 
==Building rustc_codegen_gcc==
Clone the '''rustc_codegen_gcc''' to your rust directory:
git clone https://github.com/rust-lang/rustc_codegen_gcc.git /opt/toolchains/dc/rust/rustc_codegen_gcc
'''rustc_codegen_gcc''' needs a <code>config.toml</code> file that specifies the location of <code>libgccjit.so</code>. Let's write the the <code>gcc-path</code> to the location of our <code>libgccjit.so</code> library file in this file:
echo 'gcc-path = "/opt/toolchains/dc/rust/sh-elf/lib"' > /opt/toolchains/dc/rust/rustc_codegen_gcc/config.toml
The <code>rust-for-dreamcast</code> repository contains scripts and wrappers to assist you in building '''rustc_codegen_gcc''' and using it in conjunction with <code>cargo</code> and <code>rustc</code>. We'll need to add the path to those scripts to our <code>PATH</code> environment variable:
export PATH="/opt/toolchains/dc/rust/bin:$PATH"
You may also want to add the above lines to your shell's startup file or else you'll need to run them every time you open a new shell.
 
Now we can use the included scripts to set up '''rustc_codegen_gcc'''. Various patches need to be applied to '''rustc_codegen_gcc''' for it to compile properly for our target platform. Let's apply them:
rcg-dc patch
Now we can prepare and build '''rustc_codegen_gcc'''!
rcg-dc prepare
rcg-dc build
If all went well, '''rustc_codegen_gcc''' will have built successfully. You'll be able to invoke '''rcg-dc''' to manage the '''rustc_codegen_gcc''' for Dreamcast installation, and you'll be able to invoke '''rustc''' for Dreamcast through a wrapper script command '''rustc-dc''', and likewise with '''cargo''' and its wrapper '''cargo-dc'''.
 
==Compiling individual modules into object files with rustc==
To incorporate Rust source files into a standard KallistiOS <code>Makefile</code>-based project, you can use the <code>rustc-dc</code> wrapper. If we assume the Rust module file is named <code>example.rs</code>, you'll need to add <code>example.o</code> as an object file in your <code>Makefile</code>'s <code>OBJS =</code> declaration. Additionally, you'll need to add the following lines so that <code>make</code> knows how to compile Rust modules into <code>.o</code> object files:
<syntaxhighlight lang="make">
%.o: %.rs
rustc-dc $< -o $@
</syntaxhighlight>
Alternatively, you can add those lines to your KallistiOS <code>Makefile.rules</code> file to avoid having to place it in every project's <code>Makefile</code>.
 
An example "Hello, world!" program built in this style which also demonstrates basic C interoperation is included with the Rust-for-Dreamcast repository, located at [https://github.com/darcagn/rust-for-dreamcast/tree/master/examples/rustc-hello <code>examples/rustc-hello</code>].
 
==Creating a new project using Cargo==
<code>cargo-dc</code> simplifies invoking <code>cargo</code> and creating Dreamcast crates. When using <code>cargo</code> in this setup, we will need to compile our program and all crate code into a static library <code>.a</code> file, and link it with a KallistiOS trampoline function to start the Rust code. Your Rust code will start with the function you specify as <code>rust_main()</code>. Once you <code>cargo-dc build</code> your Dreamcast code into a <code>.a</code> file, use <code>cargo-dc link</code> to automatically link it with this KallistiOS trampoline function and generate an ELF file. Instructions to do this follow.
 
First, let's clone the [https://github.com/darcagn/kos-rs '''kos-rs'''] repo:
git clone https://github.com/darcagn/kos-rs /opt/toolchains/dc/rust/kos-rs
Create a new crate using <code>cargo-dc</code>:
cargo-dc new example --lib
Change the crate to a static library in <code>Cargo.toml</code> by changing the <code>crate-type</code> as follows:
<syntaxhighlight lang="toml">
crate-type = ["staticlib"]
</syntaxhighlight>
Add the '''kos-rs''' crate to your <code>Cargo.toml</code> file:
<syntaxhighlight lang="toml">
[dependencies]
kos = { package = "kos-rs",  path = "/opt/toolchains/dc/rust/kos-rs" }
</syntaxhighlight>
 
Add the following function to your crate's <code>src/lib.rs</code> file:
<syntaxhighlight lang="rust">
#[no_mangle]
pub extern "C" fn rust_main(_argc: i32, _argv: *const u8) -> i32 {
    [...]
    return 0;
}
</syntaxhighlight>
The <code>rust_main()</code> function will serve as the entry point to your Rust code.
 
An example "Hello, world!" style program built using '''kos-rs''' and <code>cargo-dc</code> is included with the Rust-for-Dreamcast repository, located at [https://github.com/darcagn/rust-for-dreamcast/tree/master/examples/cargo-hello <code>examples/cargo-hello</code>]. Type <code>cargo-dc build</code> to build the project, then <code>cargo-dc link</code> to link against KallistiOS and generate a <code>cargo-hello.elf</code>. Make sure you have your KallistiOS <code>environ.sh</code> sourced in your terminal before running the link command.
 
==Integrating a Cargo project with a KallistiOS project==
We can also build a crate based on '''kos-rs''' and integrate the Rust code with other C code and KOS libraries. An example rotating 3D cube program built using '''kos-rs''' and <code>cargo-dc</code> combined with a <code>Makefile</code>-based KallistiOS project is included with the '''Rust-for-Dreamcast''' repository, located at [https://github.com/darcagn/rust-for-dreamcast/tree/master/examples/rust_cube <code>examples/rust_cube</code>]. Type <code>cargo-dc build</code> to build the project, then invoke <code>make</code> to build the KallistiOS project and link the Rust code within it.
 
==In-progress/future goals==
* Create implementation for KOS/newlib in Rust's <code>libc</code> crate
* Create implementation for Rust's <code>std</code> library using libc support
* Expand bindings for KOS APIs in the <code>kos-rs</code> crate
* Continue to evolve KOS/Dreamcast support alongside the maturation of <code>rustc_codegen_gcc</code>
** Add sh-dreamcast as an official tier 3 Rust target
* Expand <code>cargo-dc</code> functionality, including integrating Rust-based disc tools to generate disc images

Latest revision as of 01:19, 2 January 2025

Ferris holding his Dreamcast controller

Please visit dreamcast.rs!

The Rust for Dreamcast documentation has now been migrated into an mdBook!