There is a strange lack of guides and tools online for compiling Gameboy Advance homebrew programs on Linux. I didn't want to use devkitpro - their installation method of requiring you to use a forked version of pacman is extemely strange and I didn't want to install all of that on my system just to complile some programs.
The only other guides I found for Linux were this one and this one which both involve compiling custom versions of GCC and assosicated libraries. This lead me down a road of pain, after spending multiple hours fixing compiler errors only to create new errors I gave up. I thought that their had to be a simpler way, and there is!
Debian already has a version of GCC that can compile ARM programs in the repos, no manual compiling necessary! The package is called arm-none-eabi-gcc
.
sudo apt install arm-none-eabi-gcc
After installing you will need to download this example project (it's from one of the guides I linked earlier).
The structure of this project is as follows:
.
├── crt0.s
├── example.c
├── lnkscript
└── Makefile
From this we need lnkscript
(a script used for linking) and crt0.s
which contains setup routines. Both of these files were created by Jeff Frohwein (original code here).
We won't be using the Makefile, although I used it to determine the necessary compiler flags. If you want to use the makefile it will need to be adapted because the path for GCC and other utilities won't be correct.
Let's try compiling the example.c
program. If compiled correctly it should turn the screen red.
When compiling we need to include both our program and crt0.s
, as well as a bunch of flags. The full command is:
arm-none-eabi-gcc crt0.s example.c -mcpu=arm7tdmi -nostartfiles -Tlnkscript
We can then run our program using the mGBA
emulator. If you don't have that installed it's very simple:
sudo apt install mgba-sdl
And then:
mgba a.out
And you should see a red screen.
Now you can compile and run GBA programs and you didn't have to build any software from source or install pacman!
While the executable that GCC spits out from the above steps will run in most emulators, it won't run on actual harware. We need to strip the binary and "fix" the header so that the checksums that the GBA checks are correct.
Stripping the binary is simple, using the objcopy version also included in the gcc-arm-none-eabi package
.
arm-none-eabi-objcopy -O binary <input> <output>
So lets run
arm-none-eabi-objcopy -O binary a.out a.gba
We then need to use a simple header fixing tool. gbafix is a simple, single C file tool from devkit pro and there is also Header Tool (ht.pl), a simple perl script. I don't know which is better but I will use header tool here because it also allows you to check if the headers are correct.
Lets check our binary:
./ht.pl -cl a.gba
rom name :
logo: ok!
checksum: ok!
In this case our headers are fine! crt0.s
seems to handle setting them correctly for us. I am not sure if they will always be set correctly, or if there will be cases where they need to be fixed. Almost every guide I've looked at explicitly mentions the need to manually fix headers so I might as well explain it here incase it ever is needed.
It's extemely simple. With gbafix:
./gbafix a.gba
(overwrites the original file)
With ht.pl
./ht.pl -clo fixed.gba a.gba
You can also use these tools to set various metadata. Not sure if any of it is used by the GBA but apparently some emulators read it.
Your program is now theoretically capable of running on real harware, although I don't have a flash cart or link cable to actually confirm this. Please let me know if you do manage to do this or if extra steps were needed.
I can confirm: your example runs on a real hardware (GBA) from a flash cart (an actual flash cart, not everdrive/ez flash/...), doesn't even need "fixing". However this simple program (also compiled your way) runs in an emulator, but not on a real hardware without "fixing". After fixing, it does.
(NB. The ht.pl link is broken now.) Thank you for this writeup!