Build with Cargo

Posted on December 5, 2015

Alright, lets just take a look at commit bcea609, and see how everything works.

tree
.
├── rust/ ...
├── first
│   ├── Cargo.lock
│   ├── Cargo.toml
│   ├── do-rust.sh
│   ├── gba.json
│   └── src
│       ├── lang.rs
│       └── main.rs
└── gba
    ├── Cargo.toml
    └── src
        ├── gfx.rs
        └── lib.rs

4 directories, 9 files

We've split out our generic gba code to the gba folder, which is it's own cargo crate. It currently just contains the gfx module from last time, with no real modifications.

Then, we have our crate first for our first example, which looks like a cargo crate, but with two extra aditions only, do-rust.sh, and gba.json.

We really still require our shell script do-rust.sh for a few reasons. Lets take a look:

#!/bin/bash -ex

mkdir -p out
LIBS=~/.multirust/toolchains/nightly/lib/rustlib/gba.json/lib
mkdir -p $LIBS

# Call rustc to compile libcore for us.
# This is slow, maybe switch to a makefile?
[ -e $LIBS/libcore.rlib ] ||
  rustc --target=gba.json -Z no-landing-pads ../rust/src/libcore/lib.rs \
    --out-dir $LIBS

cargo build --target=gba.json --release

# I have no idea what it's in target/gba
arm-none-eabi-objcopy -O binary target/gba/release/first out/first.gba
gbafix out/first.gba
open out/first.gba

So, the main steps are: 1. Compiling libcore. 2. Calling cargo build 3. Doing the objcopy and gbafix.

Note I store the libcore binaries in

LIBS=~/.multirust/toolchains/nightly/lib/rustlib/gba.json/lib

which is automatically searched by cargo. I am using multirust, and I've set the entire project to use the nightly compiler (rustc 1.6.0-nightly (9303055f3 2015-11-19)).

There's nothing special in our first/Cargo.toml at all, just a path dependancy on gba

[package]

name = "first"
version = "0.0.1"
authors = ["Theo Belaire"]


[dependencies]
gba = {path = "../gba"}

And the gba crate has even less. (For now!).

So we just need to pass gba.json, (the new name of target.json) to cargo when building.

{
	"data-layout"         : "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a:0:64-n32",
	"llvm-target"         : "arm-none-eabi",
	"ar"                  : "arm-none-eabi-ar",
	"linker"              : "arm-none-eabi-gcc",
	"target-endian"       : "little",
	"target-pointer-width": "32",
	"cpu"                 : "arm7tdmi",
	"arch"                : "arm",
	"relocation-model"    : "static",
	"dynamic-linking"     : "false",
	"os"                  : "none",
	"executables"         : true,
	"no-compiler-rt"      : true,
	"no-default-libraries": true,
	"archive-format"      : "gnu",
	"pre-link-args"       : [
		"-specs=gba.specs",
		"-lsysbase",
		"-lc"
	]
}

It's just passing the gba.specs file from before to arm-none-eabi-gcc. We already saw how that file looked in gba-rust-1. Turns out we didn't actually need to use clang at all, nor take it apart. Ah, we live and learn.

This is actually a pretty nice minimal example now, you can clone it, and place a copy of the rust source at rust, and compile away, and it'll Just Work (TM).

Next time, we invoke build.rs magic to link against a C file I steal from TONC nicely, and also play around with the different modes of rendering bitmaps on the gba. I lied. We're playing with Input next. Then build.rs after that.