Awhile ago I decided to invest some time and learn how to build the Dreamcast homebrew programming tools using the latest source (C++11 for the win!). These include a customized version of the GNU compiler collection along with the KallistiOS operating system.
I've finally gotten it working, and I feel like I somewhat understand the process, so I thought I'd share what I learned.
Getting Started (Summary: Learn it by using Linux First)
The first mistake I made was trying to build it against MinGW, so I could avoid working with Cygwin. I'd seen so cool people on dcemulation.org do it that way in the past, and had previously built the tools that way by following one a tutorial. However, it quickly overwhelmed me. There is a lot of great, recent information out there on building GCC, but little of it pertains to Cygwin and far less pertains to MinGW.
I decided I'd bitten off too much to chew and instead opted to get the build working in a Ubuntu VM. I created a script to do this, which I've put on GitHub. Since then, I've been able to build on both a VM and on my Netbook, which runs Lubuntu. I can verify the script works right this minute, which means by the time you read it it will format your primary hard drive and destroy your computer.
So, first lesson: start off in the reference operating system of the tool you're building, especially if you're trying to learn it.
If you're using Ubuntu you can clone the script and run it and probably be fine (if you're using a VM, don't be a wise ass like me and try to make the directory where GCC builds a shared folder or the script will fail). The point of this post is to explain the process in general and how to run it in Cygwin.
Installing the GCC dependencies.
Like anything complex, GCC has a lot of dependencies. If you miss one or more, the build scripts will fail after running for hours and wasting a lot of your time, and the error message won't make any sense either. So its important you get all the dependencies installed right off the bat.
I kept missing things, which scuttled my ability to build GCC for hours. I finally went to the #dreamcastdev channel on FreeNode, where I begged for help. I'd like to thank kenws for providing a list of all the packages necessary in Ubuntu, along with BlueCrab for giving me some great instruction on how the KOS build scripts worked.
Cygwin doesn't have a nice command line package installer like Debian, so to install anything you need you'll need to run the setup.exe which installed Cygwin initially (just download it again if you've misplaced it) and select new packages. It might feel awkard to have to run the installer again just to add packages, but make peace with it as its the only way and doesn't hurt anything. Note that you can run the installer to add packages even as you keep other Cygwin processes open.
When the install GUI gets to “Select Packages”, you'll need to search for and select all of the packages below (this is equivalent to running the “install_gcc_prerequisites” function in the Ubuntu bash script).
- gcc
- make
- bison
- flex
- libelf-dev - In Cygwin this is called something else. I had luck installing packages called libelf0-devel and ELFIO.
- texinfo
- git
- wget
- sed
- lyx
- patchutils - This isn't in the bash script, but needs to be installed since Cygwin doesn't have this by default.
- libiconv - Ditto.
Note that “latex2html” is in the bash script but isn't necessary (it just creates documentation).
At this point running each command executed by the Ubuntu script I created should work (although you'll need to exclude sudo from a few lines). I'll spend the rest of this blog post walking through the functions though and offering some commentary on what exactly is going on.
“download_kos_source” - basically this just git clones the KallistiOS code. I put this at ~/Tools/dreamcast, which means the “tool chain” will be put at ~/Tools/dreamcast/KallistiOS/utils/dc-chain. If anything goes wrong, this is the directory you'll find yourself living in.
“prepare_gcc_source” - This runs a script written by the KOS authors which downloads and unzips the GCC source code. It also runs a script stored in the GCC code base which downloads and installs three big dependencies which the GCC docs always talk about as being necessary, which are gmp, mpfr, and mpc. I got a lot of advice to install these using a package manager, but it turns out once I had the earlier dependencies right, the “./contrib/download_prerequisites” script just worked.
Also, this function creates directories like “/opt/toolchains/dc/sh-elf/sh-elf/include” which is where the built tools eventually end up. I did this because I kept having the build process fail on me at the end because it couldn't store files there. In other OSes or environments such as Cygwin it might not be necessary but since having the build process fail after taking so long is a real drag it's probably worth your time to do what the script says and create those directories.
The last bit of the function calls a make file in the KOS dc-chain directory. According to the KallistiOS docs you can just run “make all” and everything will work from here, but what fun is that? Besides, if anything fails you'll end up confused as to where the process stopped working. So I recommend running it in the order of my bash script so you can have a fuzzy idea of whats going on.
Anyway, “make patch” actually modifies the GCC code using patch files included with the KOS source. As Marty would say, pretty heavy right?
Next up in the script is the functions “build_sh4_tools”, which just calls the KOS dc-chain make file multiple times to build GCC to target the Hitachi 200 MHz SH-4 processor, which is the main CPU the Dreamcast uses.
“make build-sh4-binutils” and “make build-sh4-gcc-pass1” seem to create some preliminary version of GCC which is then used to compile GCC. If that sounds confusing, its because it totally is. I think the name of this proto-GCC is “xgcc” or something.
BTW, if a dependency is missing, this is where fit will hit the shan. If it does, it may be tempting to proceed to the next step, because the scripts will run most of the way before failing, which will give you a brief period of hope. But that hope is an illusion! Don't fall for it! Instead back up, see if you missed a dependency, and try again.
Next up we run “make build-sh4-newlib-only”, “make fixup-sh4-newlib”, and “make build-sh4-gcc-pass2”. The last step creates the SH-4 version of GCC.
After that, it's time to build the ARM processor targetting version of GCC. Once I got the SH4 version to build the ARM version never gave me any problems. My script just runs “make build-arm-binutils” and “make build-arm-gcc”. About the whole proto-version of GCC… there's a gap in my understanding of this process, and I'm not sure why no “pass1” step is necessary like it was with the SH4.
Create an Environ.sh script
If everything else worked, you're nearly home scott-free. Now you just need an “environ.sh” script. This script sets environment variables needed to do anything useful with the Dreamcast tool chain.
I'm creating a bash script in the home directory of Cygwin to do this. Keep in mind, Cygwin maps the “home” directory, denoted by “~”, to C:\cygwin\home\%USER%, where %USER% is your Windows user name. So you can add the file that way too.
Anyway, create a file called “dcdev_environ.sh” (or whatever you want) containing this:
# KallistiOS environment variable settings
export KOS_ARCH='dreamcast'
export KOS_SUBARCH='pristine'
export KOS_BASE="$HOME/Tools/dreamcast/KallistiOS"
# Make utility
export KOS_MAKE="make"
# Load utility
export KOS_LOADER="dc-tool -x" # dcload, preconfigured
# Genromfs utility
export KOS_GENROMFS="${KOS_BASE}/utils/genromfs/genromfs"
# Compiler prefixes
export KOS_CC_BASE="/opt/toolchains/dc/sh-elf" # DC
export KOS_CC_PREFIX="sh-elf"
export DC_ARM_BASE="/opt/toolchains/dc/arm-eabi"
export DC_ARM_PREFIX="arm-eabi"
export PATH="${PATH}:${KOS_CC_BASE}/bin:/usr/local/dc/bin"
export KOS_INC_PATHS="-I${KOS_BASE}/../kos-ports/include"
export KOS_CFLAGS=""
export KOS_CPPFLAGS=""
export KOS_LDFLAGS=""
export KOS_AFLAGS=""
export KOS_CFLAGS="-O2 -fomit-frame-pointer"
. ${KOS_BASE}/environ_base.sh
Then, in Cygwin, run the file:
$ source ~/dcdev_environ.sh
echo $KOS_BASE
/home/Tim/Tools/dreamcast/KallistiOS
With $KOS_BASE and other environment variables defined, we're in the home stretch and can build KOS itself.
Building KallistiOS
If all is well, building KOS should be uneventful. Simply enter the directory where you cloned KallistiOS (~/Tools/dreamcast/KallistiOS, aka $KOS_BASE) and type “make”. This creates all the phenomenal Dreamcast library and boot up code needed to write apps on the Dreamcast.
Next up, enter the “kos-ports” directory. This was the second thing that we git cloned way up above. These are a bunch of tools ported to KOS (including lib SDL(!)). Again, just enter the directory (~/Tools/dreamcast/kos-ports) and type “make”.
The End…?
To make sure everything actually worked, try building some of the KOS examples. Enter $KOS_BASE/examples/dreamcast/pvr/pvrmark_strips_direct and type “make”. Do an “ls” and you should see the file “pvrmark_strips_direct.elf.”
Congratulations! You now can now use GCC 4.7.0 to compile code for the Dreamcast! Being able to actually run the code on a real Dreamcast is a topic best left for a fresh blog post.