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
 
(77 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 typically 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 quite usable with some patience with its current limitations and rapid change. On the other hand, while '''gccrs''' can compile for Dreamcast, it 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 (basics like integers, floats, enums, bools, chars, tuples, arrays, slices, closures, iterators, etc.)
* '''liballoc''' -- the core components of the language that require a heap, including collections (Vec, String, Box, etc.)
* linking to KallistiOS -- KallistiOS and kos-ports can be used if one manually manages interoperating with C via '''unsafe'''
* including <code>no_std</code> crates with the <code>cargo</code> build system
'''Future Goals'''
* 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
* Inclusion as a tier 3 target officially
* Expansion of <code>cargo-dc</code> to support more dcdev-specific functionallity like generating Dreamcast disc images
 
==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 installed the typical dependencies, 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 at least some familiarity with KallistiOS dev already. 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 <code>KOS_SH4_PRECISION</code> 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. '''kos-ports''' being used will also need rebuilding with <code>-m4-single</code>. 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 with this setting.
* 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.
 
''If you run into any errors or other challenges while following this tutorial, or simply need clarification on any of the steps, feel free to ask for assistance on the [https://dcemulation.org/phpBB/viewforum.php?f=29 message board] and we would be happy to aid you and update the guide for the benefit of future readers and others in the community.''
 
==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'''. The forked version is based on the latest GCC 14.0.1 development branch.
* '''NOTE''': This forked version of GCC 14.0.1 with libgccjit changes is actively developed alongside rustc_codegen_gcc itself, so if you update your rustc_codegen_gcc installation, you may also need to rebuild libgccjit to pull down changes rustc_codegen_gcc depends upon.
 
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
 
==Using Rust for Dreamcast==
If all went well, rustc_codegen_gcc will have built successfully.
 
You can now use the scripts included in the Rust for Dreamcast repo:
* <code>rcg-dc</code> script can be used to rebuild the rustc_codegen_gcc code after updating or editing it
* <code>rustc-dc</code> script can be used to compile Rust modules
* <code>cargo-dc</code> script can be used to build Rust crates
 
Examples are included with the Rust for Dreamcast repo to help you get started:
* <code>cargo-hello</code> demonstrates how to create a simple "Hello, world!" application with KallistiOS using <code>cargo</code>
* <code>cargo-cube</code> demonstrates a Rust project using KallistiOS with GLdc
* <code>cargo-addlib</code> demonstrates how to create a Rust library that can be included with a KallistiOS project
* <code>rustc-hello</code> demonstrates how to compile and include a Rust module into a standard KallistiOS <code>Makefile</code>-based project
 
These examples rely on the [https://github.com/darcagn/kos-rs '''kos-rs'''] crate being present on your computer locally, so let's pull it down now:
git clone https://github.com/darcagn/kos-rs /opt/toolchains/dc/rust/kos-rs
 
==Creating a new Rust project with Cargo==
* This will follow the <code>cargo-hello</code> example
 
==Creating a Rust project using kos-ports libraries==
* This will follow the <code>cargo-cube</code> example
 
==Creating a Rust library for Dreamcast==
* This will follow the <code>cargo-addlib</code> example
 
==Compiling individual modules into object files with rustc==
* This will follow the <code>rustc-hello</code> example
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.

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!