Friday, April 22, 2011

Build ZDoom from source in Xcode 4

Update 5/8/2011 I have received word that this tutorial works with Xcode 3.2.4 as well as Xcode 4. Thanks to andreb. I'd like to thank him for pointing out I could use the $SRCROOT variable instead of /absolute/path/to/workspace/ZDoom-Xcode.

When I was younger, I used to make maps and other mods for the popular old school game Doom. The community of mappers for the game was already quite established by the time I got into it, due to Doom being one of the original games to develop a large modding community. Even after it's heyday (and still to this day) the community thrives due to two things: the game is classically enjoyable and fun to mod for and the existence of source ports has kept the game relatively up to date. Almost no one runs vanilla Doom these days, due to the slow but steady deprecation of DOS support on many systems but plenty of programmers have kept the game alive by creating modified engines (or source ports) which run on modern operating systems without a hitch and add features to the game to make it more interesting while allowing it to keep it's charm and simplicity. This is thanks to John Carmack and id Software's open sourcing of the Doom engine back in 1997. ZDoom is one of the more popular updated engines and has been around for a long time.

A few years ago, I switched from PC to Mac and although I am happy with this change the one thing I left behind was gaming. Although I don't care too much these days if the latest game is being ported to OS X or not, I did miss some of the old games I used to play. There are so many free maps and add ons from the Doom community that just buying Doom, downloading a source port and getting some mods is enough to keep one entertained indefinitely. It will also only set you back about ten dollars to purchase Doom, making it extremely cheap gaming.

There are plenty of ports for Doom which release OS X binaries and these are all great ports, however ZDoom has such a large number of maps and features that you miss out on a lot of good mods if you aren't running it. I had never gotten around to running it on OS X before because they didn't have any binaries, but I finally decided to dive in and build it myself. Luckily, they support OS X by using CMake, but unluckily, nothing works perfectly and this is what had halted me from getting too deep before. As great as running CMake and then make would be, the build process doesn't work quite that easily. Before I continue however, I discovered that the DRD Team already hosted unofficial OS X builds of ZDoom so if you would like to spare yourself a headache and just download those, you can run ZDoom on OS X without building anything.

Why Xcode 4 and not a make

This tutorial creates an Xcode project which you build in Xcode 4 (or from the terminal using xcodebuild). This is for two reasons: I kept running into issues using make (which I will detail below) and because many may prefer to have an Xcode project available to them so that they can work directly with the code base in a modern IDE setting.

There is a tutorial on the ZDoom wiki on how to compile ZDoom on OS X and while it is a good jumping off point, it was not perfect and I needed to tweak a couple of things to get everything working.

Needed files

This tutorial focuses on building the latest stable release of ZDoom as of this writing, which is 2.5.0. Download the ZDoom 2.5.0 source code (in 7-Zip format).

You will also need FMOD Ex 4.26.36. This is not the latest release. ZDoom is not updated to work with newer versions of FMOD unless necessary due to the fact that downloading FMOD is annoyance and a hassle. ZDoom is also not bundled with FMOD, I believe due to the licensing reasons. FMOD is the biggest hassle in the entire build process. If you are curious, FMOD is the sound engine library. If you do not have this version of it (not a newer one, but this one specifically) you will not be able to build ZDoom.

You will also need CMake (make sure this is updated but no specific version except "latest" or 2.4+ is required). You can install this through MacPorts as well, if you prefer. Just type sudo port install cmake in the terminal.

Finally, make sure you have SDL installed (the latest, 1.2.14 is recommend on the ZDoom wiki). SDL is a library used for low level access across platforms.

How not to build

Skip ahead to learn how to properly build ZDoom in Xcode 4 and ignore my failed attempts

According to the ZDoom wiki, you will want to extract the source into a folder of your choosing such as /path/to/file/ZDoom/ and then work from the terminal in the ZDoom directory. Once you are in this directory, you are to run cmake such that the entire make is prepared for you. You are told to invoke the following. Do not invoke the following but read on in my blog.

cmake -DCMAKE_BUILD_TYPE=Release \
-DFMOD_LIBRARY="/Developer/FMOD Programmers API Mac/api/lib/libfmodex.dylib" \
-DFMOD_INCLUDE_DIR="/Developer/FMOD Programmers API Mac/api/inc/" \
-DNO_ASM=true

Now this isn't too far away from what needs to be done. Note that /Developer/FMOD Programmers API Mac/ is the default install location of FMOD, but make sure this is pointing to the correct directory, especially if you are maintaining various versions of FMOD in various directories (one for ZDoom at 4.26.36 and the latest stable one for other projects, for example). If you haven't changed anything and just installed FMOD as is, then the above should be fine.

When I ran this, CMake worked properly. I followed up by running make in the ZDoom directory and I even hit 100% in the building process. However, when it began to link, everything fell apart.

ld: warning: option -s is obsolete and being ignored
ld: warning: ignoring file /Developer/FMOD Programmers API Mac/api/lib/libfmodex.dylib, missing required architecture x86_64 in file
Undefined symbols for architecture x86_64:
...
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make[2]: *** [zdoom] Error 1
make[1]: *** [src/CMakeFiles/zdoom.dir/all] Error 2
make: *** [all] Error 2

The ... is just a ton of errors and warnings relating to FMOD from the code and has been omitted due to irrelevance.

What this error is stating is, simply put, that FMOD Ex's dynamic library, libfmodex.dylib was not found to be 64 bit compatible. The universal binary only has entries for i386 and ppc. It has no x86_64 architecture. This isn't a problem; this version of FMOD isn't supposed to have a 64 bit version for OS X. Even now, I believe the only OS X 64 bit support FMOD has is in development releases. However, non OS X releases have 64 bit modes and ZDoom can be built in 64 bit mode. Therefore, I realized that ZDoom must be attempting to build in 64 bit mode but cannot link to a 32 bit dynamic library that has no 64 bit architecture. The issue here was to get ZDoom to build in 32 bit mode.

To force 32 bit mode, I decided to start from scratch and redo my CMake command as such. Do not execute this either, this is still my list of failed attempts.

cmake -DCMAKE_BUILD_TYPE=Release \
-DFMOD_LIBRARY="/Developer/FMOD Programmers API Mac/api/lib/libfmodex.dylib" \
-DFMOD_INCLUDE_DIR="/Developer/FMOD Programmers API Mac/api/inc/" \
-DNO_ASM=true \
-DCMAKE_OSX_ARCHITECTURES=i386

As you can see, the only difference here is that I have added the line -DCMAKE_OSX_ARCHITECTURES=i386 which tells CMake I want to use a 32 bit Intel architecture. For PPC 32 bit, you would use ppc instead of i386. Now this seemed like a fine solution; since my original attempt had failed to link due to the entire codebase being built in 64 bit and attempting to link to a 32 bit library's nonexistent 64 bit architecture, I only needed to force a build in 32 bit mode and that line should do it.

Unfortunately, this did not work either. Although cmake was able to properly work, running a subsequent make did not even complete building.

[ 78%] Building CXX object src/CMakeFiles/zdoom.dir/g_shared/a_armor.o
/var/folders/0M/0Mqx0BzgE9SauLHWfk8q7k+++TI/-Tmp-//ccurbRiw.s:501:non-relocatable subtraction expression, "LC0" minus "L00000000009$pb"
/var/folders/0M/0Mqx0BzgE9SauLHWfk8q7k+++TI/-Tmp-//ccurbRiw.s:501:symbol: "L00000000009$pb" can't be undefined in a subtraction expression
/var/folders/0M/0Mqx0BzgE9SauLHWfk8q7k+++TI/-Tmp-//ccurbRiw.s:unknown:Undefined local symbol L00000000009$pb
make[2]: *** [src/CMakeFiles/zdoom.dir/g_shared/a_armor.o] Error 1
make[1]: *** [src/CMakeFiles/zdoom.dir/all] Error 2
make: *** [all] Error 2

For some reason, a_armor.o could not be built, due to an error that seemed to be related to bittiness (the code was not compiling now due to a forced 32 bit compile).

Instead of sorting out Makefiles and CMake files and all of that, I decided to use CMake to build an Xcode project and work from there, because command line cmake and make were not cutting it.

How to properly build and configure a ZDoom Xcode 4 project

We are in luck because CMake has built in support for Xcode. Of course, the project generated will need some tweaking (nothing is ever easy, is it) but this will finally yield a buildable project with the added bonus of being in the OS X development environment of Xcode (for ease of playing around).

First, cd to a fresh directory of the ZDoom source code in the terminal. Then we will run cmake again.
cmake -G Xcode \
-DCMAKE_BUILD_TYPE=Release \
-DFMOD_LIBRARY="/Developer/FMOD Programmers API Mac/api/lib/libfmodex.dylib" \
-DFMOD_INCLUDE_DIR="/Developer/FMOD Programmers API Mac/api/inc/" \
-DNO_ASM=true

You may notice that this is almost the same as above, except that the first line now includes -G Xcode. This is a command used by CMake to build an Xcode project file (.xcodeproj). Once again, make sure that the FMOD API is the correct version (4.26.36).

Upon running this cmake command, your directory should look something like this:

You should see a file, Project.xcodeproj. This is the project file. Open it up in Xcode.

You will see that the name of the project is "Project" which is a terrible name. Slowly double click on the project title in the upper left corner to edit the name.

Change it to "ZDoom" because that is what it is. Click through all the renaming confirmation boxes and your project file and project's internal name will be refactored to "ZDoom".

Note: Throughout this tutorial I am going to describe builds that I know will fail, to explain what you must fix in the project. Feel free to trust me and just skip the building, failing and cleaning and simply change what I tell you until we get to the final build which should work. Also, I am working in the ZDoom-Xcode directory.

I am going to build this now, despite not having made any significant changes. I am building the ALL_BUILD target in 32 bit mode (which is what we will be building every time).

Our build expectedly fails, due to some of the scripts attempting to access certain compiled targets such as arithchk and updaterevision. These are both executable files built during the ALL_BUILD build. However, the scripts that are looking for these executables are looking in the wrong place for them and failing. The executables are properly built but the scripts are looking for them in main directory of the .c files. The executables are actually getting built to a folder named after the current configuration. Since I am building in Debug mode in Xcode, the executables are in directories entitled Debug.

For example:

updaterevision is located at /ZDoom-Xcode/tools/updaterevision/Debug/updaterevision but is being looked for at /ZDoom-Xcode/tools/updaterevision/updaterevision where updaterevision.c is located. Likewise, arithchk is located at /ZDoom-Xcode/gdtoa/Debug/arithchk but being looked for at /ZDoom-Xcode/gdtoa/arithchk.

The work around for the problem that I have come up with involves symbolic links. Configuration directories such as Debug and Release are desirable and the configurations are actually the result of our CMake. For some reason, however, certain scripts don't know to use configuration directories. Instead of messing with generated scripts or searching for the problem on that level, we will simply create symbolic links to the executables after they have been built so that they exist in the configuration directory but can be accessed from the parent directory.

First, click on the ZDoom project so that you see this.

We are going to start with arithchk, but the principle remains the same throughout. First, choose arithchk from the sidebar. Then, click on "Build Phases".

You should see the following.

At the lower right corner, you will see and "Add Build Phase" button. Click on it and choose "Add Run Script".

What we are doing is adding an extra thing to do when building arithchk. We want to add a shell script that will create a symbolic link to the executable from the parent directory, after the build is complete since arithchk is one of the executables that is a being accessed incorrectly by various build scripts. In the "Run Script" text box for scripts, copy:

ln -sf /absolute/path/to/workspace/ZDoom-Xcode/gdtoa/$CONFIGURATION/arithchk /absolute/path/to/workspace/ZDoom-Xcode/gdtoa/arithchk
ln -sf "$SRCROOT/gdtoa/$CONFIGURATION/arithchk" "$SRCROOT/gdtoa/arithchk"

$CONFIGURATION is a helpful variable that will simply be "Debug" or "Release" or whatever other configuration name is being used. This will match the folder that the executable exists in. Make sure you use an absolute path to your ZDoom-Xcode directory. $SRCROOT represents /absolute/path/to/workspace/ZDoom-Xcode (see update note for 5/8/2011). Make sure to wrap this in quotes since the path may include spaces. We use -f in order to force overwriting of any links that may already exist (otherwise, rebuilds would fail).

Do the same for updaterevision...

ln -sf /absolute/path/to/workspace/ZDoom-Xcode/tools/updaterevision/$CONFIGURATION/updaterevision /absolute/path/to/workspace/ZDoom-Xcode/tools/updaterevision/updaterevision
ln -sf "$SRCROOT/tools/updaterevision/$CONFIGURATION/updaterevision" "$SRCROOT/tools/updaterevision/updaterevision"

And for zipdir...

ln -sf /absolute/path/to/workspace/ZDoom-Xcode/tools/zipdir/$CONFIGURATION/zipdir /absolute/path/to/workspace/ZDoom-Xcode/tools/zipdir/zipdir
ln -sf "$SRCROOT/tools/zipdir/$CONFIGURATION/zipdir" "$SRCROOT/tools/zipdir/zipdir"

And for qnan...

ln -sf /absolute/path/to/workspace/ZDoom-Xcode/gdtoa/$CONFIGURATION/qnan /absolute/path/to/workspace/ZDoom-Xcode/gdtoa/qnan
ln -sf "$SRCROOT/gdtoa/$CONFIGURATION/qnan" "$SRCROOT/gdtoa/qnan"

And for re2c...

ln -sf /absolute/path/to/workspace/ZDoom-Xcode/tools/re2c/$CONFIGURATION/re2c /absolute/path/to/workspace/ZDoom-Xcode/tools/re2c/re2c
ln -sf "$SRCROOT/tools/re2c/$CONFIGURATION/re2c" "$SRCROOT/tools/re2c/re2c"

And for lemon...

ln -sf /absolute/path/to/workspace/ZDoom-Xcode/tools/lemon/$CONFIGURATION/lemon /absolute/path/to/workspace/ZDoom-Xcode/tools/lemon/lemon
ln -sf "$SRCROOT/tools/lemon/$CONFIGURATION/lemon" "$SRCROOT/tools/lemon/lemon"

Now, the project should build without error!

To actually run zdoom, cd into the Debug folder (or whatever folder mirrors your configuration for building) in your main ZDoom-Xcode directory, and run ./zdoom. First, however, you must have copied a few files into this directory. You must have at least one IWAD file (a .wad file from either shareware Doom, Doom, Ultimate Doom, Doom II, or one of the Final Dooms or any of the IWADs listed on the ZDoom Wiki), the zdoom.pk3 file from the main ZDoom-Xcode directory, and a copy of libfmodex.dylib from your FMOD install (by default located at /Developer/FMOD Programmers API Mac/api/lib/libfmodex.dylib).

Sample folder for running ZDoom

Now you can build ZDoom from Xcode, and even work on it in the Xcode environment if you so choose. Enjoy!

4 comments:

  1. Vanilla Doom is my favorite flavor ;_; With chocolate sauce. Yum.

    ReplyDelete
  2. Thanks for this excellent post!

    I just wanted to let you know I was able to successfully follow your instructions using Xcode 3.2.4 instead of 4.

    One suggestion:

    For the symlinks you don't need to use an absolute path.
    Just use "$SRCROOT" instead of "/absolute/path/to/workspace/ZDoom-Xcode" and the reader will be able to copy the run script instructions verbatim. Also, don't forget to wrap with double quotes in case $SRCROOT gets resolved to a path with spaces. Your first example would then become:

    ln -sf "$SRCROOT/gdtoa/$CONFIGURATION/arithchk" "$SRCROOT/gdtoa/arithchk"

    Cheers,

    Andre

    ReplyDelete
  3. Thanks! I have updated the entry :)

    ReplyDelete