openSUSE:Packaging Games
Build Service Tutorial · Tips & Tricks · Cross Distribution Howto · Packaging checks
Desktop menu categories · RPM Macros · Scriptlets · Init scripts · How to write good changes
In addition to the standard packaging guidelines, there are a few other strong recommendations when packaging games.
Package separation
- Package game files and data files separately, if possible, to reduce size of bugfix updates. This must be done if upstream packages game data in separate tarballs.
- In most cases, game data packages (levels, artwork, sounds and music) should be
BuildArch: noarch
- Data files (maps, pixmaps, sounds) go in
%{_datadir}/%{name}
, not%{_datadir}/games/%{name}
. Binaries go in%{_bindir}
and not/usr/games
. According to the FHS, the use of/usr/share/games
and/usr/games
is optional, and we recommend not using either for consistency, so that games are packaged like all other applications. - If you know that game with version 1.3.3 works with data of a version 1.2 or later, you could use the following scheme:
game.spec
Version: 1.3.3 Requires: game-data >= 1.2
game-data.spec
Version: 1.2 Requires: game >= 1.2
Commonly used libraries
- For games that require SDL use
SDL-devel
(and possibly others likeSDL_image-devel
,SDL_mixer-devel
,SDL_net-devel
, etc.) in BuildRequires. Our SDL libraries provide these symbols and usinglibSDL-devel
directly will not work on Fedora, Mandriva and older openSUSE releases.
Files and permissions
- high score and runtime configuration files should go in
/var/games/%{name}
according to the FHS. If the package only puts a single file in this location, then it's acceptable to drop the %{name} subdirectory and place the file directly into /var/games. - man pages for games go in section 6:
%{_mandir}/man6/
according to the FHS. - spec file group:
Group: Amusements/Games
- Desktop file category:
Categories=Game;
and any from this list as appropriate. See this mail for info on how todo this properly. - License file must be included to clarify legal status, even if upstream doesn't provide it in the source tarball.
- Game service daemons, such as those provided by xpilot-ng-server and wesnoth, must run under their own userid, not 'root', 'games', or any other system user.
- All
%files
must be owned by root,root, with the exception of certain shared files such as a scoreboard. - If necessary, a game can be made setgid 'games' in order to allow a shared scoreboard file. But only if necessary, and care should be taken to drop setgid privileges when not needed. The following example shows how to properly drop setuid/setgid privileges. A setgid bit requires prior approval by the SUSE security team though.
/* Keep a global pointer to the scoreboard file. I know, global vars are * ugly and should be avoided. Your application might do this differently. * This is just an example. */ extern FILE *scoreboard_filehandle; /* * Notice that we deal with dropping setgid immediately in main() after opening * the scoreboard file, and before doing _anything_ else. This minimizes the amount * of code that is run setuid/setgid. */ int main(int argc, char **argv) { gid_t realgid; uid_t realuid; /* Open the scoreboard file. This could be NULL! Users of this * variable must check before using and not bother writing a * scoreboard if it is null. * * The file is opened with mode "r+" to preserve the existing contents. * This allows the program to first read the scoreboard and then write * it out again with new values. Just make sure you don't close() the file * after reading it or you won't be able to write to it again. */ scoreboard_filehandle=fopen(SCOREBOARDFILE, "r+"); /* Figure out who we really are. */ realgid = getgid(); realuid = getuid(); /* This is where we drop our setuid/setgid privileges. */ if (setresgid(-1, realgid, realgid) != 0) { perror("Could not drop setgid privileges. Aborting."); exit(1); } if (setresuid(-1, realuid, realuid) != 0) { perror("Could not drop setuid privileges. Aborting."); exit(1); } /* ...Continue setting up the game... */
Games not designed for Linux/Unix
Some games are not designed for Linux/Unix : they run from a single directory, and try to write in it. A good solution for this is to create a bash wrapper which:
- creates a directory for the game in the user's home
- populates it with symlinks to the files in the game dir under /usr/share/%{name}
- cd into that dir and run the real binary
Such a script could look like this :
#!/bin/sh GAME_LOCAL_DIR=$HOME/.mygame GAME_DATA_DIR=/usr/share/mygame GAME_EXECUTABLE=/usr/libexec/mygame/mygame mkdir -p $GAME_LOCAL_DIR cd $GAME_LOCAL_DIR for dir in techs data maps tilesets; do ln -snf $GAME_DATA_DIR/$dir $dir done test -d savegames || mkdir savegames test -e mygame.ini || cp $GAME_DATA_DIR/mygame.ini mygame.ini exec $GAME_EXECUTABLE "$@"
OpenGL Wrapper
If a game requires 3D accelerated graphic card you have to use DRI checking wrapper which will show an error dialog if DRI is not available explaining about Free Software and 3D drivers and then exit. What you must do is:
- Add:
Requires: opengl-games-utils
- Add to
%install
:ln -s opengl-game-wrapper.sh $RPM_BUILD_ROOT%{_bindir}/%{name}-wrapper
- Add
%{_bindir}/%{name}-wrapper
to%files
- Change the .desktop file Exec entry from
%{name
} to%{name}-wrapper
This all assumes your main binary name == %{name}, otherwise adapt as necessary.
If you already have a wrapper script for one reason or the other, you can incorperate the checkDriOk function directly into your wrapper, no need todo a wrapper wrapper, see vegastrike's vegastrike-wrapper.sh file as example.