Embedded Swift for the Nintendo Wii.
Homebrew examples written in Embedded Swift and linked against
libogc with the devkitPPC toolchain — ports of the classic devkitPro C
examples. Each example is a self-contained top-level folder built into a .dol
that runs on the Wii (or in Dolphin).
common.mk Shared build rules (swiftc -> PowerPC .o -> link -> .dol)
common/runtime.c posix_memalign shim for the Embedded Swift allocator
tools/build-ppc-stdlib.sh Build the powerpc embedded stdlib without a full build
helloworld/ Video + console "Hello World!"
wiimote/ Wii Remote IR input
usbkeyboard/ USB keyboard stdin (wiikeyboard)
gckeyboard/ GameCube keyboard over the SI bus (Dolphin-emulated)
triangle/ GX 3D: a coloured triangle (matrices, float ABI)
crypto/ AES + SHA hardware engines
<example>/Makefile Two lines: TARGET + include ../common.mk
<example>/Sources/main.swift The Swift port
<example>/Support/ BridgingHeader.h (+ shims.c where needed)
The Wii's Broadway CPU is a 32-bit big-endian PowerPC 750. Embedded Swift
compiles through LLVM, whose PowerPC backend emits elf32-powerpc, so Swift
code can be produced for the Wii directly. All hardware access goes through
libogc via C interop — the Swift in main.swift is a thin, readable mirror of
the original C. Support/BridgingHeader.h pulls in the libogc headers and adds
small static inline shims for the pieces libogc exposes as function-like
macros (e.g. MEM_K0_TO_K1), which the Clang importer cannot surface on its own.
sudo dkp-pacman -S wii-dev # devkitPPC, libogc, libfat, tools, ...
export DEVKITPRO=/opt/devkitpro
export DEVKITPPC=$DEVKITPRO/devkitPPCPowerPC is not a supported Swift target out of the box; two changes are needed, both built into a toolchain once:
-
Embedded stdlib for
powerpc-none-none-eabi. A stock toolchain ships prebuilt embedded modules only for ARM/RISC-V/x86/wasm/AVR. Register the triple instdlib/public/CMakeLists.txtand build with--build-embedded-stdlib-cross-compiling. (Or, to avoid a full build, usetools/build-ppc-stdlib.sh, which compiles just the embeddedSwift.swiftmodulefor PowerPC with an existingswiftc.) Without this,import Swiftfails for the target. -
PowerPC
swiftccsupport in clang/LLVM. Stock clang initializes noSwiftABIInfofor 32-bit PowerPC, so IRGen aborts withAssertion failed: SwiftInfo && "Swift ABI info has not been initialized". APPC32SwiftABIInfothat acceptsswiftcc/swifttailccin the 32-bit SVR4 call lowering is required in the clang/LLVM fork the compiler is built from.
A toolchain built from a Swift checkout that includes both changes can target
the Wii. On a disk-constrained machine, build to an external volume via
build-script --build-dir <path>.
Build any example by running make in its folder, pointing SWIFTC at the
patched compiler (a build tree or an installed toolchain):
cd helloworld
make SWIFTC=/path/to/build/swift-macosx-arm64/bin/swiftcUseful overrides: DEVKITPRO, DEVKITPPC, SWIFTC (or SWIFT_TOOLCHAIN for an
.xctoolchain layout).
Each example compiles Sources/main.swift to a PowerPC object, links it with
libogc plus the shared common/runtime.c (a posix_memalign shim, since the
Embedded Swift allocator needs it and newlib lacks it), and packages
<example>.dol via elf2dol.
- Dolphin emulator: open
<example>.dol(orDolphin -b -e <example>.dol). - Real hardware: with the Homebrew Channel running and
wiiloadreachable,make run WIILOAD=tcp:<wii-ip>.
Working. With a toolchain built from the two changes above, each example's
make produces a valid .dol: a big-endian PowerPC Wii executable (entry
0x80003f00) that links Swift main against libogc. Boots in Dolphin and on
hardware via the Homebrew Channel.