Introduction
Welcome!
This guide aims to facilitate your initial steps in developing applications for the Wii U using the Rust programming language. It will walk you through the necessary environment setup and the process of writing your first lines of code for the platform. While more detailed information can always be found in the documentation of the specific Rust crates utilized, this book will provide you with the foundational knowledge to get started and running quickly.
Need assistance?
Please consult the FAQ for answers to common questions. For further inquiries or to engage with the development community, please reach out through our community channels.
Discord
Requirements
This page provides a brief overview and checklist of recommended items to begin Wii U development. Required items are marked with an asterisk (*). For more comprehensive explanations, please refer to the Installation section.
Software
Skills
- Rust*
- C / C++
- Debugging 1
This guide assumes a foundational understanding of the Rust programming language. It will not cover Rust basics, as numerous excellent free resources are readily available. However, concepts related to no_std
environments will be briefly introduced and explained as they arise.
While the underlying SDK is built upon C libraries, direct interaction with them will generally not be necessary unless you intend to extend beyond the provided standard library-like features and venture into unsafe Rust. Most C functions are bound using extern "C"
and can be called directly which requires some understanding of the C calling convention / ABI. This should be mainly relevant for contributors to this project.
Hardware
- Wii U Console
- SD Card
- SD Card Reader
While a physical Wii U console is not strictly required for development, it is strongly recommended. Emulators, while valuable, may not accurately replicate the behavior of all application types or features due to incomplete implementations, inherent differences, or other platform-specific quirks. Consequently, software that functions correctly on an emulator may encounter issues on actual Wii U hardware, and vice versa.
-
While debugging tools like the Cemu PPC Debugger can be useful in certain situations, the Rust compiler is generally effective at catching many potential issues during the development process. ↩
Wii U Architecture
This document provides essential insights and relevant information about the Wii U platform, specifically tailored for developers. Its purpose is to familiarize you with the system's capabilities and constraints. For those seeking a more comprehensive understanding, a list of detailed resources discussing the platform extensively is provided below.
Summary
- CPU: "Espresso" PowerPC
- 32-bit architecture
- Big-endian byte order
- GPU: "Latte" AMD
- Memory: 2 GB DDR3 RAM
- 1 GB reserved for the operating system
- 1 GB available for user applications
- Operating System: CafeOS
- POSIX-like?
- Supports foreground and background applications
- Implements threads and scheduling mechanisms
- Features a separation between user space and kernel space
- Utilizes virtual memory addressing
- Includes an OpenGL-like graphics library
Further Information
- Wii U - Wikipedia: A general overview of the platform and trivia.
- Hardware - WiiUBrew: A concise summary of the Wii U's hardware components.
- Wii U Architecture - copetti.org: An in-depth exploration of the Wii U's hardware and software architecture.
- Cafe OS - WiiUBrew: Detailed information about the Wii U's operating system, CafeOS.
Installation
This chapter will guide you through the installation and setup process required to begin development.
Homebrew
warning
Modifying your system carries inherent risks. However, the Wii U homebrew community generally considers the process reasonably safe. If you encounter any issues, do not hesitate to seek assistance from the community.
Currently, Aroma is the recommended homebrew environment for the Wii U. For installation, we suggest following the comprehensive guide available at https://wiiu.hacks.guide. Numerous other resources, including tutorials on Google and YouTube, are also available.
After successfully installing Aroma, we highly recommend setting up the Homebrew App Store. This application streamlines the installation and updating of homebrew software. Any Wii U software recommended within this documentation should be accessible through this store. Some essential tools include:
- Wiiload Plugin: This plugin eliminates the need for repeated SD card removal and insertion. It enables direct uploading of executables from your command line interface, avoiding system reboots.
- FTPiiU Plugin: Facilitate the transfer of general files between your PC1 and the Wii U using the FTP protocol. This tool also provides the capability to inspect the Wii U's local file system, which can be valuable for debugging purposes.
-
To transfer files between your PC and the Wii U, an FTP client is required. We use FileZilla for a GUI and curl for a CLI, but you are free to use any FTP client that meets your requirements. ↩
Emulator
Utilizing an emulator during the development process offers significant time savings by minimizing the overhead associated with compilation and testing cycles. In particular, when encountering crashes (which are not uncommon, especially when working with advanced features of WUT), restarting an emulator is considerably faster than rebooting a physical console.
Fortunately, a free and open-source Wii U emulator, Cemu, is available. This emulator is actively maintained and widely recognized as the standard for Wii U emulation. Cemu facilitates rapid testing and provides valuable debugging capabilities, including memory viewers and call stack inspection, among others. These tools are invaluable for diagnosing and resolving issues that are not immediately apparent. You can download Cemu here and extract the archive to a convenient directory on your system.
Other emulators like decaf-emu exist, but we recommend you sticking with Cemu.
Development
Docker
To ensure a consistent and reproducible build environment for rust-wiiu
projects, a Docker image is available on the rust-wiiu/build repository. Leveraging this Docker image eliminates the "It works on my machine" problem and mitigates potential issues arising from version discrepancies and differing local configurations.
By utilizing Docker, developers can build rust-wiiu
code with only Docker installed on their system. For detailed instructions and further information on using this Docker image, please refer to the README file within the repository.
Local Install
tip
For developers working on Windows, utilizing the Windows Subsystem for Linux (WSL) is highly recommended. WSL significantly streamlines development workflows by providing a seamless integration of Windows and Linux environments. Popular IDEs such as VSCode offer excellent support for WSL.
For developers intending to engage in Wii U homebrew development on an ongoing basis, establishing a local development environment is recommended. The following setup instructions primarily target Linux and Windows Subsystem for Linux (WSL) environments. Installation guides for the respective tools on other operating systems can be found on their official websites. Refer to the rust-wiiu/build repository for the currently supported versions of key build dependencies.
DevkitPro
DevkitPro serves as the foundational toolchain for Wii U homebrew development, with additional support for other Nintendo platforms such as the GBA, DS, GameCube, Wii, and Switch. It provides essential toolchains for compiling code targeting specific Nintendo consoles. For Wii U development, the devkitPPC (PowerPC) toolchain is required.
To install DevkitPro, please follow the comprehensive Getting Started guide available on their website. Once dkp-pacman
is configured, install the necessary wiiu-dev
package using the following command in your terminal:
sudo dkp-pacman -S wiiu-dev
Rust
An up-to-date installation of the Rust programming language is required. You can set up Rust by adhering to the official installation guide. After installation, verify the Rust version and confirm successful installation by executing the following command:
cargo --version
cargo-make
cargo-make is a versatile task runner that uses a simple TOML configuration to define and execute multi-platform build scripts by a single command. It is used to hide the more complex build- and linking commands.
cargo install cargo-make
cargo-generate
Optional! cargo-generate is a utility that facilitates starting new projects from predefined templates instead of creating empty Cargo projects. While this functionality can be achieved through a few manual commands, cargo-generate can streamline the initial project setup.
cargo install cargo-generate
Crates within rust-wiiu
The rust-wiiu
project is structured as a collection of interconnected crates (Rust's package management units). These crates serve various purposes:
- Fundamental Toolchain Crates: These provide the core building blocks for Wii U development, such as rust-wiiu/wut and rust-wiiu/wups.
- C Library Wrappers: These crates encapsulate and extend the functionality of existing C libraries, offering a safer and more idiomatic Rust interface. Examples include rust-wiiu/notifications and rust-wiiu/kernel.
- Pure Rust Crates: These are newly developed crates written entirely in Rust and do not rely on pre-existing C code.
From a developer's perspective, all these crates are used in the same way. However, understanding their underlying nature can be helpful when troubleshooting errors, particularly during the compilation phase.
While it is technically possible to install these crates in arbitrary locations, it would necessitate manual configuration adjustments and is generally not recommended. Instead, the suggested approach is to create a dedicated parent directory to house all rust-wiiu
code. This facilitates easier access to files across different crates using relative paths. (Note: The feasibility of utilizing Cargo's Git dependencies for this purpose is currently under investigation.)
Once you have created a parent folder in your preferred location, you can obtain any of the provided crates by cloning their respective repositories into this directory. For example, to get the wut
crate, you would execute the following command:
git clone https://github.com/rust-wiiu/wut.git
Getting Started
Now that everything is setup, lets get to working Homebrew software.
Project Initialization
This section outlines the steps to create a new Wii U development project using provided templates. Several project templates are available, catering to different application types:
- Rust Crates: For creating Rust wrappers around existing C libraries. (
rust-wiiu/library-template
) - RPX Applications: For developing standalone Wii U executable applications. (
rust-wiiu/application-template
) - WUPS Plugins: For creating plugins that extend the functionality of existing Wii U software. (
rust-wiiu/plugin-template
) - RPL Libraries: (TODO)
- WUMS Modules: (TODO)
Refer to the different file formats documentation for detailed information on Wii U file formats.
Recommended Method: cargo-generate
The recommended method for creating a new project is using the cargo-generate
tool. This provides an interactive CLI to streamline the setup process.
cargo generate rust-wiiu/application-template
Executing this command will prompt you for the project name. This name will be used for the project directory and the final binary name.
Alternative Method: Git Template
Alternatively, you can utilize the "Use this template" button on the respective GitHub repository to create a new repository based on the chosen template.
-
Create a new repository: On GitHub, use the "Use this template" button and name your new repository according to your project (e.g.,
<Project>
). -
Clone the repository: Clone the newly created repository to your local machine, replacing
<Username>
and<Project>
with your GitHub username and project name respectively.
git clone https://github.com/<Username>/<Project>.git
- Configure
Cargo.toml
: Navigate to the cloned project directory and open theCargo.toml
file. Modify the{{project-name}}
and{{authors}}
placeholders with the appropriate values for your project.
Building and Running
This section describes the initial build and execution process for your new project.
1. Build the project
Execute the following command to compile your project in release mode.
cargo make --profile release build
Upon successful compilation, the resulting RPX executable will be located at /target/powerpc-none-eabi/release/<Project>.rpx
.
2. Run the application (via Cemu)
To execute the compiled application, you can use the Cemu Wii U emulator.
- Open Cemu.
- Navigate to
File
>Load
. - Select the generated RPX file (
/target/powerpc-none-eabi/release/<Project>.rpx
).
If the setup is correct, your application should now run within the emulator.
Automated Execution (Optional)
You can configure the run
task within the Makefile.toml
file1 to automatically launch Cemu with your compiled application. Modify the path to your Cemu installation within the run
task definition. Once configured, you can execute the application using:
cargo make --profile release run
3. Run on hardware
You can remove the comments and add your Wii U's IP to the upload
task to upload the build file via FTP. Then you can upload and start the application from the Wii U Home-Menu so see the same result as Cemu.
cargo make --profile release upload
Congratulations! You have successfully set up your development environment and are now ready to develop Wii U software using Rust.
-
The documentation of cargo-make can be found at: github.com/sagiegurari/cargo-make. ↩
First Homebrew Application
With the development environment now set up, let's examine the fundamental code structure of a basic rust-wiiu
application. Upon opening the src/main.rs
file, you will typically find code resembling the following:
#![no_std] #![no_main] use wut; use wut::prelude::*; use wut::time::Duration; #[wut::main(Console)] fn main() { while wut::process::running() { println!("{}", wut::time::DateTime::now()); wut::thread::sleep(Duration::from_secs(1)); } }
Let's dissect this code snippet part by part to understand its function and significance within the Wii U environment.
1. !#[no_std]
Attribute
The !#[no_std]
attribute signifies that this Rust code will not link against the standard Rust library (std
). Unlike typical desktop or server environments, embedded systems like the Wii U require a more minimal runtime environment. The Rust ecosystem provides a tiered approach to library support:
core
: This is the foundational tier, providing essential language features without any platform-specific dependencies or dynamic memory allocation. Only stack-based memory management is available here.alloc
: This tier builds uponcore
and introduces an interface to a memory allocator, enabling dynamic memory allocation capabilities such asString
andVec
. However, it still requires platform-specific implementations for the allocator itself.std
: This is the default tier for typical platforms1, offering the complete Rust standard library with platform-specific implementations for functionalities like file I/O, networking, and concurrency.
While the Wii U / CafeOS does not have official Rust support in the traditional sense, rust-wiiu
bridges this gap by providing a custom allocator and implementing many relevant std
features. This allows developers to leverage their existing Rust knowledge while targeting the Wii U. The !#[no_std]
attribute informs the compiler and linker about this embedded environment.
2. !#[no_main]
Attribute
The !#[no_main]
attribute is another embedded Rust macro. It instructs the linker not to generate the conventional main
function that serves as the program's entry point in standard Rust environments. In embedded systems, the program execution flow often involves platform-specific initialization routines that occur before the user's main
function would typically be called. In the context of Wii U homebrew development using devkitPro, the toolchain provides its own pre-main
setup procedures. Therefore, we use !#[no_main]
to prevent Rust from generating its default main
entry point.
3. use
Statements
These lines are standard Rust import statements, bringing specific modules and types into the current scope for easier use.
use wut;
: Imports the top-levelwut
crate, which contains the Wii U-specific functionalities provided byrust-wiiu
.use wut::prelude::*;
: Imports commonly used items from thewut
prelude. This is a convention to bring frequently used types and traits into scope for convenience.use wut::time::Duration;
: Imports theDuration
type specifically from thewut::time
module, representing a span of time.
It's worth noting that wut::time::Duration
is semantically equivalent to std::time::Duration
. Both are ultimately re-exports of core::time::Duration
, which houses the fundamental implementation. The wut
crate, like std
, re-exports parts of the core
module for a more unified and accessible API.
4. !#[wut::main(Console)]
Attribute
This macro performs platform-specific initialization tasks that enhance the development experience by mimicking a more standard environment. While not strictly necessary for the program to execute, it provides conveniences such as initializing a logging mechanism and ensuring a cleaner program exit. You can consult the rust-wiiu
documentation for a comprehensive understanding of its functionality. This macro can be replaced with custom initialization code if needed.
The Console
attribute passed to the wut::main
macro is particularly important for early development and debugging. It configures the system to output log messages and println!
statements to an on-screen console. Be aware that this on-screen console output may conflict with any graphical rendering you implement later in your application. The Console
attribute can be omitted, changed to a different logger type, or combined with other logging configurations as detailed in the rust-wiiu
documentation.
6. while wut::process::running() {…}
Loop
This is the primary execution loop of the application. The code within this loop will continue to execute indefinitely until the application is terminated. An alternative, but functionally similar, way to write this loop is:
#![allow(unused)] fn main() { loop { if !wut::process::running() { break; } } }
A crucial aspect of this loop is the frequent call to wut::process::running()
. This function checks if the application is still running in the foreground. It is essential for the proper functioning of the foreground release mechanism, specifically the HOME button. When the HOME button is pressed, the system relies on this check to move the application out of the foreground. Therefore, if the main thread within this loop becomes blocked for an extended period without calling wut::process::running()
, the application may become unresponsive to the HOME button.
7. println!(…)
Macro
The println!()
macro is used for printing formatted text to the console. While typically defined in the standard library (std
), in this no_std
environment, its functionality is provided by the wut
crate and is set up by the wut::main(Console)
macro. It is part of the commonly used items imported via wut::prelude::*
.
8. wut::time::DateTime::now() & wut::thread::sleep()
Functions
These are examples of standard library-like features that have been implemented within the wut
crate to provide familiar functionalities in the embedded Wii U environment. They are designed to behave similarly to their counterparts in the standard Rust library, offering time-related operations and thread pausing capabilities.
-
For a comprehensive list of officially supported Rust platforms, please refer to the Rust Platform Support documentation. ↩
Your Second Homebrew Application
Having grasped the fundamentals of writing Rust code for the Wii U, it's now time to put that knowledge into practice and embark on your own creative endeavors. Feel free to explore and implement any functionality that sparks your interest.
The rust-wiiu
documentation serves as a valuable resource, detailing the available standard library-like features and additional tools at your disposal. These include modules such as wut::screen
for rendering basic graphics and wut::gamepad
for handling controller inputs.
A highly effective way to gain inspiration and accelerate your learning is to examine existing homebrew applications. By studying their code, understanding their design patterns, and adapting their techniques to your specific needs, you can significantly enhance your development skills and create compelling Wii U applications.
Example 1
TODO: An example on how to use screen
Example 2
TODO: An example on how to use fs
& path
Exploring Unsafe Territory
important
While the raw bindings are primarily intended for contributors to rust-wiiu
, there are scenarios where the currently available high-level features may not suffice, necessitating their use.
As you've likely gathered by now, rust-wiiu
aims to be more than just a thin wrapper around C libraries; it provides a comprehensive, Rusty abstraction layer for Wii U development. However, for situations requiring direct interaction with the underlying system or when higher-level abstractions are insufficient, rust-wiiu
exposes raw bindings to most C symbols through the wut::bindings
module. These bindings are automatically generated using bindgen, leveraging Rust's Foreign Function Interface (FFI).
It is crucial to understand that these FFI functions are inherently marked as unsafe
in Rust. This is because the Rust compiler cannot provide any guarantees regarding memory safety, ownership, or the behavior of the external C code being called. When interacting with these raw bindings, it is the developer's responsibility to ensure the correctness and safety of the operations performed.
TODO: Refer to the wut docs and explain an example using the C ABI
Frequently Asked Questions
What is Homebrew?
Homebrew software encompasses unofficial applications and tools created by the community, operating outside of the manufacturer's officially supported ecosystem. It empowers users to expand a console's capabilities, unlocking functionalities such as custom games, supplementary software, and system modifications.
Will it every be a real std version?
It is highly unlikely that rust-wiiu
will ever become a fully integrated standard Rust environment. Several aspects of the underlying toolchain are fundamentally incompatible with standard Rust configurations. While a future integration might theoretically be possible given sufficient interest and a dedicated team of contributors, it is not feasible in the foreseeable future. Therefore, rust-wiiu
will continue to exist as an external toolchain that strives to offer a developer experience (DX) as close as possible to a standard Rust environment.
Furthermore, the freedom from strict adherence to the standard library (std
) API can offer significant convenience, particularly for rapid development. While this flexibility might occasionally result in APIs that are less optimal or non-standardized in terms of performance, security, or other aspects, the trade-off in terms of ease and speed of development is often considered worthwhile.
How to learn Rust?
Start using it. If you have no prior programming experience, it's worth noting that Rust, with its explicit and strict nature (qualities that ultimately contribute to its strength and reliability), might present a steeper initial learning curve compared to some other languages. However, I would never want to discourage anyone from embarking on the journey of learning Rust. To support you in this endeavor, here's a curated list of resources that I personally recommend or that are highly regarded within the Rust community:
- Comprehensive Rust 🦀: A complete course about Rust by Google.
- The Rust Programming Language: The "official" Rust book by and for the community
- Rust By Example: Collection of Rust code examples
Why Rust on the Wii U?
I am a Rust developer. Of course, I’ve spent six months rewriting everything in Rust. So let me tell you about it...
I was tired of the chaos that is C & C++. The fragmented compiler ecosystem, the ever-evolving standards, and the compiler's tendency to let programmers reek havoc can make C feel less like a language and more like an intricate maze. Add to that the sheer number of opportunities for bugs or undefined behavior, and you have a recipe for frustration. Rust, by comparison, feels like a breath of fresh air: modern, well-structured, and designed to make your code both safe and sane.
But it’s not just about my personal vendetta against C. I firmly believe that modern languages like Rust have a valuable role to play even especially on legacy hardware. They lowers the barrier to entry for new developers. Okay, I know Rust has a reputation for a steeper learning curve, but at least Rust comes with fantastic default tools for managing packages, formatting, error handling, ... and the compiler is flipping awesome once you develop Stockholm syndrome.
Ultimately, there's a bigger vision here. By introducing Rust to legacy environments, we can help sustain niche communities and ensure their codebases remain manageable, readable, and understandable. So much existing homebrew code reflects individual formatting and coding styles, making it challenging for others to contribute. Rust, with its inherent clean structure, great tooling, and increasing popularity, offers a promising path forward. So, whether you're drawn by the technical sophistication, the desire for a bit of nostalgia, or simply the curiosity to explore something new, welcome—let's build something great together.
Contributions
Here is a list of the contributors who have helped to write this book.
If you contributed to this book, feel free to add yourself in a PR.