Compiling GLIBC on Linux. Oh golly gosh!

Started by
15 comments, last by klems 13 years, 2 months ago
I'm trying to compile my game on Linux. It works find on my Ubuntu system, but when I send the compiled binary off to my buddy with Centos it won't run. It complains saying:


/lib64/libc.so.6: version `GLIBC_2.7' not found
/lib64/libc.so.6: version `GLIBC_2.11' not found
/usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.9' not found
/usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.11' not found

I've googled around the place and it seems that because I compiled on my new computer it's not going to work on his old computer. Whereas if I'd compiled on an old computer it would've worked fine on both. Crazy old Linux! He only has GLIBC_2.5 on his Centos machine, whereas I have 2.11. What I'd like though is for my binary to run on as many installations as possible. I really don't want to have to set up a whole new installation with an old version of GLIBC just to recompile it again. So first of all, can I force my project to compile at the lowest level of GLIBC possible? Or at the very least, how do I remove these symbols (from running: objdump -T MYGAME):

GLIBC_2.4 __stack_chk_fail
GLIBC_2.7 __isoc99_sscanf
GLIBC_2.11 __longjmp_chk
GLIBCXX_3.4.11 _ZNKSt5ctypeIcE13_M_widen_initEv
GLIBCXX_3.4.9 _ZNSo9_M_insertIbEERSoT_
GLIBCXX_3.4.9 _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
GLIBCXX_3.4.9 _ZNSo9_M_insertImEERSoT_
GLIBCXX_3.4.9 _ZNSo9_M_insertIdEERSoT_
GLIBCXX_3.4.9 _ZNSi10_M_extractIfEERSiRT_


My understanding is that if I remove these symbols from my code/project then it'll run fine on my buddies computer. Of course ideally, if there's a way to support even lower than that this would be awesome. So what's the best course of action here? Is there some compiler option to automatically support the oldest versions of GLIBC and GLIBCXX? Or maybe I have to manually go through and weed all these symbols out (also probably through some compiler options).. or maybe I need to statically link against libc.so.6 and libstdc++.so.6?

Anyway, any help would be greatly appreciated :D
Cheers,
Ben.
--------------------------Check out my free, top-down multiplayer shooter: Subvein
Advertisement
Not every Linux distro is the same. Hence the reason why every distro has their own package manager and it's own set up packaged versions.
On Linux it's often much easier to just give the source code to the user so he can compile it himself.
"I really don't want to have to set up a whole new installation with an old version of GLIBC just to recompile it again"

That's not how you do this. You do this with what is called a "chroot".

A chroot (pronounced "chuh-root") is a unix environment INSIDE another unix environment. It's not virtualisation or emulation, it's much more lightweight than that. You simply build a file tree containing a build environment -- typically it will be just the basic minimum packages to do the build, and including *specific* versions of libraries to link against. You then copy your source (or partially built system) into it, and perform the final link.

Here's a document which talks about setting up a chroot;

http://wiki.blender.org/index.php/Dev:Doc/Setting_Up_a_Chroot_Build_Environment_under_Linux

It's actually about how to build blender, but it's got the general stuff in it. Basically chroot starts a new shell and will execute commands, but after setting an environment where / is actually somewhere else. The shell (and its children processes) aren't allowed to peek outside their particular part of the file system.

So you set up a new directory somewhere, and it'll have its OWN /etc, /bin and so on. Of course, it's not a full operating system, so you don't actually get an /etc/passwd in there. What you do then is copy packages somewhere in that tree and then have chroot execute a shell script which installs them. It'll install them into its /bin directory. Then you chroot a script which does your build inside it, then you copy out the completed build.

Building the chroot for the first time can be a little expensive, but you can keep it lying around for when you need it. Many software development teams check the completed chroots themselves into their revision management systems, or keep pristine copies of them on fileservers so they can be just cloned onto build servers when needed. Another reason for doing this is that it makes your build independent of your development environment. You don't need to worry about installing games or whatever on your machine, because even if they upgrade (say) your opengl libraries, you KNOW the version in the chroot is the one you actually want to build against. You don't have to stop doing local builds either -- you can still do that which means all the symbols and source are easy to get at and so on.

Also, you can then (reasonably trivially) build cross-distribution software. For example, I routinely build red-hat RPMs for various version of redhat on my Ubuntu desktop. Why? Well the chroots are fresh -- so I can install anything I want in them, it doesn't have to be the distro on my desktop. So I've got a RedHat 5.6 chroot, and a RedHat 6.0 chroot and also a Suse Enterprise chroot and I can build things in there that will run on those different distros.


There are two things you'll encounter. One is you'll need to find a sufficiently low version of glibc in order to install it in the chroot. Good news is you often get away with just nicking the file itself from somewhere and overlaying that onto a package install.

The next thing is what'll probably get you. The reason that your program is demanding those symbols to dynamically link at runtime is that they're part of a feature in glibc that you're using in your app which only appears in later versions of the library. That's why they're there. It's not Linux being crazy, it's a safety precaution to stop you running apps which need features which aren't present in the local version of glibc. In other words, even if you forced this to work, your app is going to crash. Eventually it'll call an ioctl not supported by the kernel or look-up a glibc entrypoint which doesn't exist or something.

This is how, for example, you get new API calls safely added to glibc. They have an internal versioning system which says "this'll only work on THIS version or higher". Windows, by the way, does exactly the same thing only instead of complaining about missing symbols like that it pops up a message box saying something like "This program cannot be run because there are parts of its environment missing" but crucially doesn't tell you which version of the c runtime will be sufficient to run it...

You *can* solve this by finding out what's dragging those symbols in and programming around that. The STL is particularly fond of this, but other things will do it as well. If you can locate them and it's something you have an alternative for then you can simply use the alternative. I've fixed compilation errors in this way before -- ISTR one was something like an STL linked list operation needed the feature but the equivalent for vectors didn't so I rewrote the one container which was causing the problem to used a vector, took the performance hit for vector resizing (which was small enough not to worry) and now my app "just worked" on the target systems.

every distro has their own package manager


Uhm ...

There are only two "mainstream" packaging systems, debs and rpms. And in many cases, carefully stuffed packages install on many distros that understand the package in question. The last deb I've personally distributed e.g. would install on at least Ubuntus 10.x, Debians 5.x, Mint and gNewSense (others not tested).



O.P.: Maybe ELF Statifier could be of interest to you, though it completely circumvents the whole idea behind package managers. An extravagant idea could also be to setup a virtualbox-image :D
Here you go:
http://ldn.linuxfoundation.org/lsb/build-lsb-compliant-application

If you intend to do cross distribution binary only applications the LSB is your best friend.
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!
Here you go:
http://ldn.linuxfoundation.org/lsb/build-lsb-compliant-application

If you intend to do cross distribution binary only applications the LSB is your best friend.
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!
A third alternative you could consider is to build your game statically.

You get this exact same problem on Microsoft Windows. Often times application vendors work around simply by shipping all the runtimes with their app (eg. MSVCRT.DLL and friends).

Stephen M. Webb
Professional Free Software Developer

Thanks for all the suggestions guys :D

Katie, thx for that massive reply. I think I might set up a chroot environment. Can you reccomend a good distrbution to target the lowest level possible (for maximum compatibility)?
--------------------------Check out my free, top-down multiplayer shooter: Subvein
Centos, RHEL, SLES and some other distros intended for 'enterprise' type machines have relatively old (aka 'stable') versions of most software compared to something like Ubuntu so you have to be aware of that if you intend to distribute binaries.

This topic is closed to new replies.

Advertisement