Cleaning up the build system, a walk through a git log.

Posted on December 4, 2015

This post is unfortunately written some 13 days after the changes it describes. Terrible, now I'm referencing things from the git log.

But don't worry, I'm going to have a full recap post afterwards showing how it all works with cargo, so this is just bonus material. Here's a link to the next post.

This time we go from this:

#!/bin/bash -ex

clang -nostdlib -target arm-none-eabi -mcpu=arm7tdmi -c second.c -o second.o

# Compile gba_crt0.s using gcc still.
arm-none-eabi-gcc -nostdlib -mthumb-interwork -mthumb \
    -c gba_crt0.s -o gba_crt0.o

mkdir -p libs
# Call rustc to compile libcore for us.
# This is slow, maybe switch to a makefile?
[ -e libs/libcore.rlib ] ||
  rustc --target=target.json -Z no-landing-pads ../rust/src/libcore/lib.rs --out-dir libs/ --emit link,obj

# I don't want to use anything in here, but it needs to exist.
[ -e libs/libcompiler-rt.a ] ||
    arm-none-eabi-ar m libcompiler-rt.a

# Call rustc to compile our first Rust object
rustc -L libs -Z no-landing-pads --target=target.json --emit obj  rust-gba.rs

clang -nostdlib -target arm-none-eabi -Tgba_cart.ld \
    -Wl,--gc-sections \
    rust-gba.o libs/core.o \
    gba_crt0.o crti.o -o rust-gba.elf

arm-none-eabi-objcopy -O binary rust-gba.elf rust-gba.gba
gbafix rust-gba.gba
open rust-gba.gba

To this.

#!/bin/bash -ex

# Compile gba_crt0.s using gcc still.
arm-none-eabi-gcc -nostdlib -mthumb-interwork -mthumb \
    -c gba_crt0.s -o gba_crt0.o

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

rustc -L libs -Z no-landing-pads --target=target.json rust-gba.rs -o rust-gba.elf

arm-none-eabi-objcopy -O binary rust-gba.elf rust-gba.gba
gbafix rust-gba.gba
open rust-gba.gba

Pretty diff view [on github][diff].

This is possible because we added things to our target.json

{
	"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"       : [
		"-Tgba_cart.ld",
		"-nostdlib"
	],
	"post-link-args": [
		"gba_crt0.o",
		"crti.o"
	]
}

In particular, no-compiler-rt means that we don't need the empty compiler-rt lib, and relocation-model: "static" means that GOT sections are not generated, and the pre-link-args and post-link-args means we don't need to call clang at all ourselves, since now rustc will call arm-none-eabi-gcc for us, and pass the link args.

Now, I also felt like it would be a good idea to call this gba.json instead of target.json, since I do intent to get this working for a DS too at some point, and it'll be nicer down the road.

In commit ef292c5 I (questionably) decide to just pass the gba.specs file again on the linker args. Now pre-link-args is just:

	"pre-link-args"       : [
		"-specs=gba.specs",
		"-lsysbase",
		"-lc"
	]

like we had at the very start. But we have to pass sysbase and libc to avoid missing symbol sadness, so I might revert this change in the future when I want more direct control. Also I don't have to have gba_crt0.s, or gba_cart.ld anymore, I just use DEVKITARM's.

Also notable at commit 0b0d3d5c I can finally start using cargo. It isn't actually super functional at this point, but I can switch from

# Old way
rustc -L libs -Z no-landing-pads --target=target.json src/rust-gba.rs -o out/rust-gba.elf

# New way
cargo build --target=target.json --release

I dropped the no-landing-pads, those will eventually make a comeback, I'm sure, to save on binary size, but it's not super important right now.

But using cargo is great, now I can split my code into a generic gba crate, and an example specific crate.

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

This is great. But I also needed to move the .git folder up a directory so that both would be tracked in one repo. The folder we've been working in so far has been named after the example I started with, first.

Lets stop at commit bcea609 for now. See you in the next post.