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
 
(119 intermediate revisions by the same user not shown)
Line 1: Line 1:
<div style="float:right;">__TOC__</div>
[[File:Rust-dc-logo.png|thumb|Ferris holding his Dreamcast controller]]
Support for Rust on Dreamcast is early, but currently possible if one is willing to endure the experimental nature of setting it up and lack of stability in implementations. Doing so presents a bit of a challenge 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:


* '''rustc_codegen_gcc''': A libgccjit-based codegen backend for rustc (preferred method)
'''Please visit [https://dreamcast.rs/ dreamcast.rs]!'''
* '''gccrs''': a Rust frontend for GCC


=rustc_codegen_gcc=
The Rust for Dreamcast documentation has now [https://dreamcast.rs been migrated into an mdBook]!
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-rust '''kos-rust''' 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 '''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. See the '''rustc_codegen_gcc''' [https://blog.antoyo.xyz/ progress reports] for more information.
 
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 and you have built KallistiOS with it. See [[Getting Started with Dreamcast development]] for more information.
** 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>.
** Your KallistiOS installation will need its floating point precision setting set to <code>m4-single</code>. This setting is available in the <code>environ.sh</code>, but changing the setting may require you to rebuild your main toolchain if you have not built it with <code>m4-single</code> support. 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 for the changes to take effect.
* You must already have a relatively up-to-date Rust installation, either using your operating system's package manager or [https://rustup.rs/ rustup].
 
==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_codegen_gcc.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==
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.
 
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
Set the <code>gcc_path</code> file to the location of our <code>libgccjit.so</code> library file:
echo /opt/toolchains/dc/rust/sh-elf/lib > /opt/toolchains/dc/rust/rustc_codegen_gcc/gcc_path
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 let's 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_codgen_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==
<code>rustc-dc</code> generates <code>.o</code> object files with <code>rustc</code> for inclusion in a KallistiOS <code>Makefile</code>-based project. If we assume the 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.
 
=gccrs=
'''gccrs''' implements a new Rust compiler frontend for GCC. This essentially means creating a separate new Rust compiler from the ground up using the GCC toolchain infrastructure. This project is in early stages and is targeting the Rust 1.49 revision from December 2020. As of this writing (February 2024), it is not yet able to compile Rust's <code>libcore</code>, so many basic language features are unimplemented or not functional. Additionally, Rust standard tooling like <code>cargo</code> is not available. Borrow checking is not implemented, but the project plans to later use the next-generation Rust borrow checker [https://github.com/rust-lang/polonius Polonius] from the official Rust project.
 
It is possible to use this compiler by building the GCC 14.0.1-dev toolchain or the '''gccrs''' latest toolchain. GCC 14.0.1-dev will get you the latest code upstreamed by the '''gccrs''' team into the main development branch of GCC, while the '''gccrs''' git repo will get you the absolute latest bleeding edge updates to '''gccrs'''. The GCC 14.0.1-dev configuration file is available within the official KallistiOS repo's <code>dc-chain</code> script, while the latest '''gccrs''' configuration is available within the [https://github.com/darcagn/rust-for-dreamcast Rust for Dreamcast] repository. Brief instructions follow for setting up the latest '''gccrs''' toolchain. See [[Getting Started with Dreamcast development]] for more detailed information on how to set up and run <code>dc-chain</code>.
 
==Building a gccrs-enabled toolchain==
Follow the [[Getting Started with Dreamcast development]] guide for creating a Dreamcast toolchain until you arrive at the instructions for setting up the <code>dc-chain</code> configuration file. At this point, you should have a shell open to <code>/opt/toolchains/dc/kos/utils/dc-chain</code>.
 
Clone the [https://github.com/darcagn/rust-for-dreamcast Rust for Dreamcast] repository:
git clone https://github.com/darcagn/rust-for-dreamcast.git rust
Copy the GCC patch in place:
cp rust/toolchain/gcc-rs-kos.diff patches/
Copy the <code>dc-chain</code> configuration file into place:
cp rust/toolchain/config.mk.gccrs.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). Note that to avoid conflicting with an existing stable toolchain at the default path (i.e. <code>/opt/toolchains/dc/sh-elf</code>), we will be installing to <code>/opt/toolchains/dc/gccrs/sh-elf</code> instead. To begin compilation and installation, run:
make build-sh4
After building everything, you can clean up the extraneous files in your <code>dc-chain</code> directory by entering:
make clean
 
==Setting up Makefiles to compile Rust modules==
As mentioned before, <code>cargo</code> is not available to use with '''gccrs''', so for our example, we will place our <code>.rs</code> modules within a typical KallistiOS <code>Makefile</code> project. If we assume the module file is named <code>example.rs</code>, you'll need to add <code>example.rox</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>rox</code> object files:
<syntaxhighlight lang="make">
%.rox: %.rs
kos-cc -frust-incomplete-and-experimental-compiler-do-not-use $(CFLAGS) -c $< -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>.
 
In your <code>example.rs</code> file, your <code>main</code> function will need to be declared like so:.
 
<syntaxhighlight lang="rust">
#[no_mangle]
pub extern fn main() -> i32 {
    [...]
}
</syntaxhighlight>
 
Make sure before you compile your code that you set <code>export KOS_CC_BASE="/opt/toolchains/dc/gccrs/sh-elf"</code> in your KallistiOS <code>environ.sh</code> file or <code>make</code> will not find your '''gccrs''' compiler executable.

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!