Upcoming Events
Southwest Gaming Expo
11/20 - 11/22 @ Dallas, TX

Workshop on Network and Systems Support for Games (NetGames 2009)
11/23 - 11/25 @ Paris, France

ICIDS 2009 Interactive Storytelling
12/9 - 12/11 @ Guimarães, Portugal

Global Game Jam
1/29 - 1/31  

More events...


Quick Stats
7147 people currently visiting GDNet.
2341 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!



Link to us

Link to us

  Intel sponsors gamedev.net search:   

Linux Game Development Part 2
Distributable Binaries


The Solution: Steps 3-4

Step 3: Build custom libraries

Before you can build custom libraries, you need to download the source code. You probably know the web sites for SDL, OpenAL, Ogg/Vorbis, and any other libraries you use, so I won’t cover that here. If you don’t know, just plug it into Google and it will take you there.

The source code is usually packaged as a tarball, which is a compressed archive with a .tar.gz or .tgz extension. You’ll usually find it on the download page on a particular library’s web site. After you have downloaded the source tarball for each library, extract it into a temporary directory where you can build it.

Now we need to use the command line. Open an Xterm or Terminal window, and cd to the temporary directory that contains the source code. You need to be in the top-level directory of the source code tree you just extracted.

To build a custom version of each library, you should follow the directions that come with the library. Usually there is a README file that explains the steps you need to take. Basically, each library follows these three easy steps (you type these in on the command line):

  ./configure 
  make
  make install
Most open source libraries come with a utility called “configure” that allows it to figure out where the development tools and libraries are installed on your system. The configure tool also provides a plethora of options you can use to control how the library is built and tailor it to your needs. To find all the options, type:
  ./configure --help
There are too many options to cover for each library, so instead, I’ve decided to share with you the options I used and why I used them. Hopefully, that will provide some criteria that you can use to tailor your own libraries.

For SDL, these are the options I supplied to “configure”:

“--prefix=/home/troy/Projects/SDL” - specifies where my custom version of SDL will be installed at the end. All of my Makefiles (or my IDE project) will point here to pick up include files and libraries.

“--enable-X11-shared” - forces SDL to use the X11 libraries that are on the end user’s system. The low-level X11 libraries are pretty much guaranteed to be on the end user’s system and compatible, so you don’t need to worry about distributing them with your game.

“--disable-rpath” - basically, you want to avoid using RPATH. RPATH restricts libraries to only run in a specific location, so distributing RPATH-enabled libraries makes them pretty much useless. The SDL library is the only one I’m using that has RPATH enabled by default, but you’ll want to watch for this on other libraries you might be using.

“--disable-ipod” - this is obvious, since my game doesn’t need this.

“--disable-video-directfb” - disables the use of the DirectFB video driver, which as I understand it is built into the Linux kernel. It doesn’t support many video cards, and it is not optimized. This option removes support for DirectFB from my custom SDL library, thereby reducing the library size and ensuring that SDL uses the hardware-accelerated video driver for OpenGL (if present).

“--disable-audio” – when Dirk Dashing used OpenAL for its audio, I used this option. It removes the audio subsystem from my custom SDL library, which my game didn’t use, thereby reducing the library file size.

“--enable-sdl-dlopen” – enables dynamic runtime linking, so that SDL does not require all of the different low-level audio libraries for ALSA, arts, and ESD in order to run, but it will use them if they are present. I didn’t need to use this option when I disabled the audio subsystem, but I’m using SDL_mixer now, so I needed it. This option will reduce a significant number of dependencies on your custom version of SDL.

As of v1.04, Dirk Dashing uses SDL_mixer for its audio. For SDL_mixer, these are the options I supplied to “configure”:
“--disable-music-mod” – disables support for MOD, which my game doesn’t use, thereby reducing the library file size.

“--disable-music-midi” – disables support for MIDI, which my game doesn’t use, thereby reducing the library file size.

“--disable-music-mp3” – disables support for MP3, which my game doesn’t use, thereby reducing the library file size.

“--disable-music-ogg-shared” – disables dynamic linking of the Ogg/Vorbis libraries, so I can statically link them into my executable.

“--with-sdl-prefix=/home/troy/Projects/SDL” – tells SDL_mixer to use my custom version of SDL. This is important, because I don’t want SDL_mixer to compile or link against the prebuilt version that came with my Linux distribution.

For libogg, these are the options I supplied to “configure”:
“--prefix=/home/troy/Projects/ogg” - specifies where my custom version of the library will be installed at the end.
For libvorbis, these are the options I supplied to “configure”:
“--prefix=/home/troy/Projects/vorbis” - specifies where my custom version of the library will be installed at the end.

“--disable-oggtest” - speeds up the build time.

“--with-ogg=/home/troy/Projects/ogg” - tells libvorbis to use my custom version of libogg. This is important, because I don’t want libvorbis to compile or link against the prebuilt version that came with my Linux distribution.

Dirk Dashing v1.03 and earlier versions used OpenAL for the audio. For OpenAL, these are the options I specified to “configure”:
“--prefix=/home/troy/Projects/openal” - specifies where my custom version of the library will be installed at the end.

“--disable-sdl” - removes SDL support from OpenAL, since I don’t use it.

“--disable-vorbis” - removes the AL_EXT_vorbis extension, which Dirk Dashing doesn’t use.

“--disable-mp3” - removes the AL_EXT_mp3 extension, which Dirk Dashing doesn’t use.

For freealut, these are the options I specified to “configure”:
“--prefix=/home/troy/Projects/freealut” - specifies where my custom version of the library will be installed at the end.

“CPPFLAGS=-I/home/troy/Projects/openal/include” - tells freealut where to find the header files for my custom version of OpenAL

Building a custom library is a fairly easy process. The configure utility makes it very easy, once you identify the options you need to use.

Sometimes the configure script will fail because it cannot find a particular tool or library it needs. When that happens, use the package manager for your distribution to install the missing tool or library. Most good distributions provide a package manager that allows you to browse the set of available packages and search for a particular package you need. You just need to find the missing package, install it, and then run the configure tool again.

Just for fun, let’s run objdump on my custom OpenAL library and compare it to the dependency list we had before:

  NEEDED      libm.so.6
  NEEDED      libdl.so.2
  NEEDED      libpthread.so.0
  NEEDED      libc.so.6
Wow, we’ve gone from fourteen dependencies to only four! And they are all low-level libraries that I don’t need to worry about.

I found this to be true with all of the libraries that my Dirk Dashing executable directly depended on – when I built custom versions of those libraries to minimize the dependencies, I didn’t have to build anything that those libraries in turn depended on. I was able to minimize the dependencies of each custom library to the point that it only needed low-level libraries.

Step 4: Use Your Custom Libraries

Finally, edit the include and library paths in your Makefiles or your IDE projects to point to your custom libraries, and rebuild your application. Congratulations! You now have an application and a set of custom libraries that you can distribute that will run on almost any Linux distribution.

To run your program, it will need to be able to find your custom libraries. Shared objects are not like Windows DLLs - you can’t just co-locate your libraries in the same directory as your executable and expect the executable to find them. The runtime linker in Linux only looks for libraries based on directories specified in the LD_LIBRARY_PATH environment variable.

I recommend writing a short script to run your game. The script should set the LD_LIBRARY_PATH to point to your custom libraries and any system libraries you need, and then launch your executable. You can also have it cd to your installation directory first, so that the working directory is the directory where the executable resides - that way, your program can easily find all the game assets. Your desktop and menu shortcuts would then invoke your script rather than your executable.

Here is an example startup script that I used during development of Dirk Dashing:

  # Set the library path to point to my custom libs and my game libs
  # Separate multiple paths with a colon
  export LD_LIBRARY_PATH=/home/troy/Projects/DirkDashing/Lib:.

  # cd to the working directory, so it can find game assets
  cd /home/troy/Projects/DirkDashing

  # Start the game
  ./dirkdashing
The # sign at the start of a line indicates a comment. Notice that you can set multiple directories in LD_LIBRARY_PATH by separating them with a colon. I added the “.” at the end of the LD_LIBRARY_PATH to find game libraries that are located in the same directory as the executable.

Summary

This article was rather lengthy, but here’s the whole thing in a nutshell: to build a binary executable that will run on almost any Linux distribution, you need to statically link as many libraries as possible, and build custom versions of the rest. Then you provide your application and custom libraries together in your installer.

But we’ll talk about installers next time. Until then!


Contents
  Introduction
  The Problem
  The Solution: Steps 1-2
  The Solution: Steps 3-4

  Printable version
  Discuss this article

The Series
  Part 1: Introduction
  Part 2: Distributable Binaries
  Part 3: Installers
  Part 4: Testing
  Part 5: Marketing and Distribution