Compile with older libc (version `GLIBC_2.14' not found)

I have to compile a program on a current ubuntu (12.04). This program should then run on a cluster using CentOS with an older Kernel (2.6.18). I cannot compile on the cluster directly, unfortunately. If I just compile and copy the program without any changes I get the error message "kernel too old".

The way I understood it, the reason for this is not so much the Kernel version, but the version of libc that was used for compilation. So I tried to compile my program dynamically linking the libc from the cluster and statically linking everything else.

Research

There are already a lot of questions about this on SO but none of the answers really worked for me. So here is my research on that topic:

  • This question explains the reason for the Kernel too old message
  • This question is similar but more specialized and has no answers
  • Linking statically as proposed here didn't work because the libc is too old on the cluster. One answer also mentions to build using the old libc, but doesn't explain how to do this.
  • One way is to compile in a VM running an old OS. This worked but is complicated. I also read that you should not link libc statically
  • Apparently it is possible to compile for a different libc version with the option -rpath but this did not work for me (see below)

Current state

I copied the following files from the cluster into the directory /path/to/copied/libs

  • libc-2.5.so
  • libgcc_s.so.1
  • libstdc++.so.6

and am compiling with the options -nodefaultlibs -Xlinker -rpath=/path/to/copied/libs -Wl,-Bstatic,-lrt,-lboost_system,-lboost_filesystem -Wl,-Bdynamic,-lc,-lstdc++,-lgcc_s

The output of ldd on the compiled binary is

mybin: /path/to/copied/libs/libc.so.6: version `GLIBC_2.14' not found (required by mybin)
mybin: /path/to/copied/libs/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by mybin)
linux-vdso.so.1 =>  (0x00007ffff36bb000)
libc.so.6 => /path/to/copied/libs/libc.so.6 (0x00007fbe3789a000)
libstdc++.so.6 => /path/to/copied/libs/libstdc++.so.6 (0x00007fbe37599000)
libgcc_s.so.1 => /path/to/copied/libs/libgcc_s.so.1 (0x00007fbe3738b000)
/lib64/ld-linux-x86-64.so.2 (0x00007fbe37bf3000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fbe37071000)

I'm somewhat confused by the error, because it uses the correct path (i.e. the libc from the cluster) but still complains about a missing glibc version. When running ldd on the cluster it returns not a dynamic executable and running the binary results in the same two errors mentioned above. It also looks like there are other libraries included (linux-vdso.so.1, ld-linux-x86-64.so.2 and libm.so.6). Should I use the older versions for those as well?

So now I have two main questions:

  • Is this even the correct approach here?
  • If yes: how do I link the old libc correctly?

Solution 1:

See this answer.

Is this even the correct approach here

No: you can't use mismatched versions of glibc as your link command does. You used crt0.o and ld-linux.so from new (system-installed) libc, but libc.so.6 from an old (copied from cluster) libc. That is just not going to work.

Solution 2:

-rpath sets the DT_RPATH tag but doesn't tell the linker to look there for libs, you want -L for that.