Linux Games Install And Directory Guide <author>Ingo Ruhnke, <tt/grumbel@gmx.de/ <date>v0.3, Begin: Tue Aug 17 23:11:43 1999, Last update: Wed Aug 25 23:59:18 1999 <abstract> This document gives an overview how to install games under Linux and how to put the files in the correct directories according to the FHS. </abstract> <!-- Structure: * which files are there? * where to put them? * how to allow user build files * How to handle packages * how to get this to work with automake? * how to make think relocatable * how to install a game from a cd --> <toc> <sect>What is different between DOS/Windows and Linux? <p> DOS and Windows use a very simple way of handling the directories. If you install a program, all data goes to a single directory. The program don't has to worry about were to place the files, it can handle that as it likes to do. <p> Under Linux the thing looks a bit different, the complete file system is only one big tree, there is no separation into different drives and the data of a program is spread over this filesystem tree. There is a standard document, the Filesystem Hierarchy Standard, which describes where the files belong, most games which I know do not follow this standard or following only some of its rules. </p> <p> For standard software documentation goes to <tt>/usr/doc/</tt>, binaries go to <tt>/usr/bin/</tt>, data files to <tt>/usr/share</tt> and so on. This has different reasons, one of them is that you should be able to mount the <tt>share/</tt> directory remote over a network, since it should only contain system independent files, while <tt>bin/</tt> for example contains system depended binaries which can't be shared over different machine types. For games there are some special directories reserved, they differ a bit from the standard directories, but not much. A lot of games at the moment don't use that directories, this document should give a introduction on how to handle all that directories and how to avoid trouble. <sect>The directories and how to handle them <sect1>The different between <tt>/usr/</tt> and <tt>/usr/local</tt>. <p>Before I start with some more detailed description, there is one thing you should know. There is a directory tree <tt>/usr</tt> and there is a directory tree <tt>/usr/local</tt>, they contain both the same subdirectories, but the different is that <em>all</em> stuff under <tt>/usr</tt> is handled by the distributions package system, while all stuff under <tt>/usr/local</tt> is maintained by the system administrator. So if you are providing a game as source or as a precompiled tarball it has to go to <tt>/usr/local</tt>, if you provide instead or in addition <bf>RPM</bf> or <bf>debian packages</bf> they should install them self into <tt>/usr</tt>. In the following text I will refer only to <tt>/usr</tt>, because things under <tt>/usr/local</tt> are the same just in another prefix directory. </p> <!--p> There is also an directory called <tt>/opt</tt> in the Filesystem Hierarchy </p--> <sect1>Which files are needed by a game? <p> So before we a going to install a game we first have to think which files we have in a game and what types of files are they. Most games will have some or most of the following file types: <itemize> <item>binaries (executables) <item>graphics (*.pcx, *.tif, *.jpg, etc.) <item>musics (*.mp3, *.wav, *.mod, *.midi, etc.) <item>sounds (*.wav, *.voc, etc.) <item>packed datafiles (*.wad, *.dat, etc.) <item>levelfiles <item>shared libraries (*.so) <item>script files <item>save games <item>hiscore files <item>config files <item>etc. </itemize> <sect1>Where to put the files? <sect2>Binaries - /usr/games/ <p>This is the easiest thing to do correct. Normal programs are placed under <tt>/usr/bin</tt>, while games get their own directory under <tt>/usr/games/</tt>. So all user visible binaries should go directly into that directory, this will be mostly just a single executable binary. <sect2>Static Datafiles - /usr/share/games/ <p> A lot of games at the moment put there data files in a place like <tt>/usr/lib/$GAME</tt>, but games will now get there own directory so placing them into <tt>/usr/lib/</tt> wouldn't be the correct way. The new place for static game data is <tt>/usr/share/games/$GAME</tt>. All <em>static</em> and <em>architecture independent</em> goes to that directory, like images, music files or packed datafiles. It is not required to separate the directory any further, but I recommend it, since it will ensure that you will not end up in chaos, if the project groves. <sect2>Shared library's - /usr/lib/games/ <p> Some games use shared libraries which are linked at run time, this allows the game much more flexibility, because levels and enemy's can be created in C or whatever language they might choose, so there is no need for scripting languages or other stuff to make the game more flexible. You might guess that libraries should also placed under <tt>/usr/share/</tt>, but that is not correct. Since <tt>/usr/share/</tt> is only for architecture independent files and shared libraries are not architecture independent, they depend on a specific type of machine architecture. So they should be placed under <tt>/usr/lib/games/$GAME/</tt>. <sect2>Save games - $HOME <p> A lot of games offer the possibility to save the game status and restore the state where you left the game. This data is variable and should therefore not saved under <tt>/usr/*</tt>. So were to put the savegames? Because savegames are personal data, there are best placed into the users home directory. The savegames should be placed in an extra directory for each game, like <tt>$HOME/.$GAME/</tt>. This will ensure that the directory is normally hidden and won't annoy the user. If there is more variable user specific data (like demo files, etc.) it should also be placed in that directory. Then the directory should be separated into some subdirs like <tt>save/</tt> and <tt>demo/</tt>. <sect2>Hiscores - /var/games/ <p> Hiscores are similar to save games, but they are not equal. The different is that save games or mostly interesting for personal use, while hiscores are interesting for other. On a multiuser system it would be interesting to fight against other peoples hiscores. So hiscore files and other dynamic data which is not meant for personal use only should be placed under <tt>/var/games/</tt>. If the game needs more then one file to hold the data it should get its own subdirectory, like <tt>/var/games/$GAME</tt> <sect2>Config files - /etc & $HOME <p> As for all other programms, there are two places for config files, one is <tt>/etc/</tt> and the other is the users home directory. I'd recomment to use an extra directory for games under <tt>/etc/</tt>, but the FHS does not require this. So <tt>/etc/games/</tt> should be the places where the global config files where placed. Local user config files should be placed under <tt>$HOME/.$GAME/</tt>, just like save games. <sect1>How to find the files and how to make the game relocatable? <p> Now you know where to put all files, but how to find them after installaton? If the game is compiled from source it is easy, the install prefix, which should be <tt>/usr/local</tt> by default, should be compiled into the binary. How to do this using autoconf/automake is discribed below, if you are using a non standard way, you have to do that yourself or switch to autoconf/automake, which is really recommend. This way the game will allways know where it was installed. </p> <p> The problems come when you are trying distribute a binary version. If the game is packed in a debian or RPM package, then the package maintainer should set the prefix right so that the game will run fine after installaton. But what if the user wants to install the game somewhere else, for example under <tt>/opt</tt>? Then the game has to be relocatable. But what does relocatable mean? Its means that you can install a programm where ever you want it to be, you are not forced to use the standard directories. There should be allways a way to override the default path in a game. A good possibility to do that is to set the prefix directory throu a configuration file, an enviroment variable ($GAME_DATADIR or $GAME_PREFIX) or an command line option, for example <tt>--data-dir</tt>. <sect1>How to allow extra levels or similar stuff? <p> The problem that arrived with extra levels and similar stuff is that not all users have root access to there macines, so it is not possible or to difficult to place the files under <tt>/usr</tt> or it would be more comfortable to have them in the home directory when you are developing a level. Therefore the game should offer the possibility to read the files from <tt>$HOME/.$GAME/</tt>. The subdirectory structure in that directory should be equal to that in <tt>/usr/share/games/$GAME</tt>, so it will be possible to extract the extra level in <tt>/usr/share</tt> or in <tt>$HOME/.$GAME</tt>, without tweaking the path. <p> [FIXME:] At the moment I am not having much experience with shared libaries, so I can not say if it will cause throuble to placing them under <tt>$HOME/.$GAME/</tt>. I think the LD_LIBRARY_PATH has to be adjusted, but I am not sure. <sect1>How to handle data from a cd-rom? <p> [FIXME:] This section is only theoretical, I never tested anything from below, so be warned! <p> Under DOS and Windows handling the cdrom wasn't very difficult the game only needs to now the drive letter. Under Linux the situation is not much different, but instead of a drive letter we have a device name where the cd-rom is and a directory name where the cd-rom is mounted. The standard places are on the most machines <tt>/dev/cdrom</tt>, which is a link to the correct device (you normaly will newer want to touch this directly) and the directory <tt>/cdrom</tt>. But the correct location should be always be detected at installation time and stored in a human readable configuration file. <p> Some games allow it to install only some files to the harddrive and let all other data resist on the CD or to install all data to the harddisk. This shouldn't be to hard to include into a game, it only has to keep track of were it installed it files and then load them were there were installed. I recomment it to have a similar directory structure on the cdrom as on the harddisk, since that makes thing easier, so the programm can acces its data with: <tscreen> <verb> f = fopen(make_full_path("levels/level1.dat"), "rb"); ... </verb> </tscreen> Where <tt>make_full_path()</tt> is a function translating the relative path (here: <tt>levels/level1.dat</tt>) into a full path, which could be <tt>/cdrom/levels/level1.dat</tt> or <tt>/usr/share/games/GAME/levels/level1.dat</tt>, depending on which data was installed. Another more tricky possibility would be to use symlink. The install scripts would create symlinks for all files which aren't installed and let this symlinks point to the cdrom directory, that would be possible, but cause some trouble when the cdrom is mounted to another directory or the computer as multiple cdrom drives. <sect>How to install the game? <p> Now as we made clear where all the files should go. The question is how to install the game? The game can come into source or binary form, can use just a few MB's or thousand of them. If the game is small it is the best to just use the standard ways of installing software under Linux, which are tar.gz files containing the source, or for binary distributions use packages files like RPM or debian packages, you can also use tar.gz binary distribution, but then they would not check if the correct libraries are installed, that causes lots of trouble for example with mixed libc5, glibc2.0 and glibc2.1 installation. So if you are not having much time while developing its better to not start creating tar.gz binaries and instead make the source as easy compile able as possible. <sect1>How to install the source? <p> The source package should <em>always</em> be a tar.gz file which installs in a single directory tree and is after unpacking installable with a: <tscreen><verb> $ ./configure $ make $ make install </verb></tscreen> This way of installation is the standard way for most software and is very common for the most users, so it will cause the lessest trouble. This way can be easily obtained with autoconf and automake. If you are using a non standard way of doing installations, you should change it to the lock and feel of the above or even better switch over to automake and autoconf, since it will give you all that and also stuff like automatic distribution packaging and library checking, etc. <sect1>How create packages? <p> The task of package creation is more or less complex. You can probably get some simple packages to work for your distribution, but maintaining different packages for different distribution, which you don't have, is probably a bit hard, since you can't test them easily. It is a very good idea to find somebody who will packaging the stuff for you and test it, this will save you a lot of work and ensure that the package will work. <sect1>How to handle CD-Rom installation? <p> If your game is very big, so that it is distributed on CD, there could be some trouble. Packages of your program will be impossible, since you would have to distribute three or more different packages (.rpm, .deb, tar.gz), that will probably blowup the CD space. So the easiest solution is to just distribute a tar.gz file with a installation script and documentation on how to do the installation manually. The install script should ask what the user wants to install and where to install it, it should also create a install log, so that the game find its datafiles after installation without user interactions. The script should probably perform the following task: <itemize> <item>Ask what to install (videos, level data, etc.) <item>Ask where to install (<tt>/opt</tt>, <tt>/usr</tt>, <tt>/usr/local</tt>, etc.) <item>Install the data <item>Make sure that the game will find its data (create a config script or tell the user which enviroment variables he has to set) </itemize> <sect1>How to create update or patch distribution? <p> If you release a new version of your package it is a good idea to also make a patch or update available, so that the user is not forced to download the complete game again. <sect2>Using diff/patch <p> If you changed only the source, you can create a patch file, with diff. The patch file can be applied using patch. For more informations see <tt>info patch</tt> and <tt>info diff</tt>. The problem is that diff/patch can't handle binary files, so it is impossible to use them with alone if you changed some datafiles or changed the directory layout. <sect2>Using hand build update scripts <p> If you changed the directory layout or added some new files you will have to use a hand build update script. The script should first check for the games install directory and than start patching and updating. </p> <sect2>Patching a RPM <p> If you distributed your game as RPM you might ask, but how to patch that? A way to do that was mentioned by Pierre Phaneuf <pp@ludusdesign.com>. You could create an update script and a Source RPM, the script will than catch all the installed datafiles from their directories, build a new RPM from the Source RPM using the datafiles and then install the new RPM. But aware that this is only theoretical and was never been tested in practice. </p> <sect>Some tips about of to make that with automake/autoconf? <sect1>Tweaking the path <p> The problem with automake, which I really recommend to use, is that it installed the files at default in the normal places, thats perfectly OK, but since games are a bit different there is the need to tweak the pathnames a bit. That can be done by placing the following in the <tt>Makefile.am</tt>'s <p> <tscreen><verb> # Tweaking the `datadir' to install the files in the correct location pkgdatadir = $(datadir)/games/@PACKAGE@ </verb></tscreen> <sect1>How to find out where the package is installed? <p> If you are using automake/autoconf the user has the choice to override the default prefix, which is <tt>/usr/local</tt>. So the question is how to I get the install directory? Therefore we have to hardcode the path into the binary, but how to accomplish that? The problem is that we need to expand the variable <tt/$prefix/ to the full pathname, else we would end up with a useless string like <tt>"$prefix/"</tt>. Place the following in the file <tt/acinclude.m4/: <tscreen><verb> AC_DEFUN(MY_EXPAND_DIR, [ $1=$2 $1=`( test "x$prefix" = xNONE && prefix="$ac_default_prefix" test "x$exec_prefix" = xNONE && exec_prefix="${prefix}" eval echo \""[$]$1"\" )` ]) </verb></tscreen> And the following into <tt/configure.in/: <tscreen><verb> MY_EXPAND_DIR(game_datadir, "$datadir/games/$PACKAGE") AC_DEFINE_UNQUOTED( GAME_DATADIR, "$game_datadir") </verb></tscreen> This will create a macro called GAME_DATADIR, which will expand into the path where your game data resist. For example if the game is installed into <tt>/usr/local</tt> GAME_DATADIR will expand to <tt>/usr/local/share/GAME/</tt>, when you need other data then the one that resist in <tt>share/$GAME</tt> you can also use <tt>"$prefix"</tt> in the example. </p> </article>