The following describes a GNU/Linux game development problem I am still tackling have solved, although I’ve made progress and learned a lot. Hopefully the following information can be useful to you.
The Problem
A few weeks ago, one person informed me that Killer Kittens blew up on his Debian Stable machine:
./killerkittens.bin: /lib/tls/i686/cmov/libc.so.6: version `GLIBC_2.4' not found (required by ./killerkittens.bin)
Most of the dependency issues I’ve encountered involved changing flags used in my libraries, such as libSDL. Unfortunately, this issue was different. It was strange because I wasn’t sure why my game was depending on GLIBC_2.4 since I wasn’t explicitly linking to it.
Why This Problem Exists
Since then, I have learned that this is a common problem for GNU/Linux developers, especially when using C++. By default, the linker will use the latest versions of functions you are using. Let’s say that you used gcc v2.94 on your Red Hat 6.1 machine to create your binary years ago. It will link against version 1 of a function. Well, that binary will continue to run on newer systems since version 1 is kept around for backwards-compatibilty, which explains why older games such as Quake 3 Arena will still run just fine.
Now if you use your cutting-edge Ubuntu (8.04) Hardy Heron system to compile (I’m actually on 7.04), you’ll likely have gcc v4.1 or higher, along with its associated libraries. The linker will find version 2 of a function. That binary will work just fine on your system, and it will work just fine on systems that have been upgraded to use the latest libc libraries. The binary will NOT work on an older system, such as Debian Stable, which is still using version 1 functions. The binary will complain that it can’t find GLIBC_2.4 because Debian Stable may have only GLIBC_2.3.
Possible Solutions
To solve this problem, you could make GLIBC_2.4 a requirement to play your game, but frankly, it isn’t truly a requirement, and there is no reason why you should force your users to upgrade if they don’t have to. More likely, you will just cut off your potential audience. Even if you are releasing the source to your game so that your players can always recompile to get it to run on their system, people generally like games that work out of the box. It’s less effort, which means more of a chance for your game to stay on someone’s hard drive.
You could find an older distro and build your binaries on it, but you may not have a spare machine and may not want to go through the hassle. Also, even if you installed it on your current machine, why give up the power of your current updated system? Michael from Linux Game Publishing offered the following advice:
one extra thing I do – I build against a VERY old set of libraries. As in Red Hat 6.1. That is a ‘magic environment’ that ‘just works’ everywhere.
I would like to try setting up a sandbox environment on my system. I know you can setup a new filesystem and chroot to it, but I had trouble finding information on how to put one together. Since I wanted to release this game weeks ago, I decided against spending a lot of time learning how to do yet another thing to get something working just so I can do the thing I initially wanted to do. Look up Yak Shaving if you hadn’t heard of it before.
Hope!
One thing people told me to try was autopackage’s build tools apgcc and apg++. These are wrapper scripts around gcc/g++ that are used to get your binary to build using the older library symbols.
Hopes dashed!
I think they would have worked fine, but there was a problem with building the Kyra Sprite Engine. Building Kyra is supposed to produce two libraries, libengine and libkyra. For some reason, when I used apg++, it forgot to use files found in a util directory, and so it wouldn’t build the libraries. g++ worked just fine, but then I had a dependency on newer symbols. I spent a bit of time trying to figure out if it was a problem with apgcc/apg++ or a problem with Kyra. In either case, I didn’t want to deal with it longer than I had to, and I was getting a bit demoralized. I can’t use my regular compiler, and I can’t use the one tool that people have suggested to help solve this problem. Honestly, if it wasn’t for Kyra, which has been giving me headaches for the past few months, I bet everything would have been solved long ago, but to gut my project of this library would be a bit more work than I would like. There had to be a way to solve this issue.
When I read more about the C++ ABI Problem, I saw the following quote which gave me hope again:
GCC 3.4 is able to generate binaries with the GCC 3.2 ABI using a compiler switch.
A compiler switch? Seriously? After searching a bit and asking questions on IRC, I learned about the compiler flag -fabi-version. According to C++ Standard Library ABI:
Changes to the default compiler option for -fabi-version.
It is versioned as follows:
* gcc-3.0.x: (Error, not versioned)
* gcc-3.1.x: (Error, not versioned)
* gcc-3.2.x: -fabi-version=1
* gcc-3.3.x: -fabi-version=1
* gcc-3.4.x: -fabi-version=2
My installed compiler was gcc v4.1, and I found that passing in -fabi-version=1 by itself didn’t do anything that I could see. I did, however, install gcc-3.3 and g++-3.3, which also pulled down the appropriate stdc++ library. From my own tests, I learned that the compiler switch did nothing useful. So much for that research. Still, with the older compiler, I was able to get a working binary that should run on older systems.
Some Success!
Before switching to gcc-3.3/g++-3.3, I would get the following output from objdump -x libengine.so:
Version References:
required from libm.so.6:
0x0d696910 0x00 06 GLIBC_2.0
required from libgcc_s.so.1:
0x0b792650 0x00 10 GCC_3.0
0x0d696910 0x00 05 GLIBC_2.0
required from libstdc++.so.6:
0x056bafd3 0x00 07 CXXABI_1.3
0x08922974 0x00 03 GLIBCXX_3.4
required from libc.so.6:
0x0d696914 0x00 09 GLIBC_2.4
0x0d696911 0x00 08 GLIBC_2.1
0x09691f73 0x00 04 GLIBC_2.1.3
0x0d696910 0x00 02 GLIBC_2.0
After using the older compiler version:
Version References:
required from libm.so.6:
0x0d696910 0x00 06 GLIBC_2.0
required from libgcc_s.so.1:
0x0b792650 0x00 09 GCC_3.0
0x0d696910 0x00 05 GLIBC_2.0
required from libstdc++.so.5:
0x081a2972 0x00 07 GLIBCPP_3.2
0x056bafd2 0x00 04 CXXABI_1.2
required from libc.so.6:
0x0d696911 0x00 08 GLIBC_2.1
0x09691f73 0x00 03 GLIBC_2.1.3
0x0d696910 0x00 02 GLIBC_2.0
Now I can package up my game and expect that it should run on older systems without a problem. You should expect that most of your players will be running a system with GLIBC_2.3 or GLIBC_2.4, so targeting the former should still allow your project to run on the latter.
Your distribution should also allow you to install multiple versions of gcc and g++. To implement these changes, I simply made sure that I changed my build scripts to use CC=gcc-3.3 and CXX=g++-3.3. My game’s binary and each of the custom-built libraries, including Kyra, no longer depend on the newer symbols.
Not a Full Solution…
Unfortunately, now my custom libSDL has a dependency on libX11 and libXext, even though I am still passing in –enable-X11-shared, which is what I used when I was using gcc-4.1. I learned why when I read the changelog:
– Dynamic X11 loading is only enabled with gcc 4 supporting -fvisibility=hidden. This fixes crashes related to symbol collisions, and allows building on Solaris and IRIX.
Unfortunately, SDL 1.2.11 was also the release that builds the way you would expect. That is, 1.2.10 does not provide a configure script, and so downgrading to it isn’t going to be a simple matter. If I keep 1.2.11 or even use the latest stable version, 1.2.13, I still have to deal with dependencies if I use gcc-3.3 to get rid of GLIBC_2.4. If I use apgcc, I have to deal with Kyra not building, which requires working on Kyra to fix it or working on my game to get rid of Kyra. Someone on IRC did suggest that Kyra’s build scripts or the code itself might conditionally rely on “gcc” being used, so that’s where I will investigate next.
If you are not using Kyra, however, I imagine the above information should solve any GLIBC_2.4 dependency issues you may have, but you now have to deal with libX11 issues. In fact, if you’re not using Kyra, then the apgcc/apg++ solution should work for you. Once I solve this problem, I will write a follow-up article explaining how I did so.
In the meantime, I did find this post by Gerry JJ about a script he wrote based on apgcc. I’ll have to check out his apgcc-derived script later.
For more info on this issue:
- My Linux Game Tome forum post about this issue
- Autopackage page on Linux Binary Compatibility Problems
- Troy Hepfner’s excellent Linux Game Development series
[tags]linux, game development, business, programming [/tags]
One reply on “Linux Game Development: GLIBC_2.4 not found”
[…] week, I wrote about the `GLIBC_2.4′ not found errors your game might get when an application built on a new distribution is run on an older […]