Linux的动态加载,支持向下兼容(backward compatibility),也就是说保证在老的系统上生成的可执行程序可以继续在新的系统上运行,但是反过来,Linux并不支持向上兼容(forward compatibility),不保证新的系统上面生成的可执行程序在老的系统上运行。
另外,C/C++依赖的glibc/libstdc++/gcc的版本,各个发行版经常会不一样。
规范化操作:
一般来说,跨所有主流的Linux发行版发布Binary没什么好的办法。
方案一、以几个distro作为基准提供,如Ubuntu、SUSE、RHEL、Debian、CentOS为基础,这样就能覆盖90%以上的商业用户了,其他平台,以tar包的形式提供源码构建。
方案二、按照源码包的逻辑,使用autotools、cmake等构建工具进行开发库搜索,并限制依赖库的版本,如果不满足就不生成,这样发布的时候就直接发布源码;
方案三、使用ermine或者statifier,将可执行文件和它所依赖的动态库打包到一个可执行文件中。ermine是收费的,statifier是开源的。
http://magicermine.com/
http://statifier.sourceforge.net/
非规范化操作(偶尔做一次):
方法一、找一台跟目标机器glibc版本一致的机器重新编译;
方法二、在目标机器上面升级GLIBC至开发机版本,但这是不推荐的,升级过程中很容易造成目标机器崩掉,要是生产机器就完蛋了;
方法三、动态链接改为静态链接方法, 将所有可执行文件文件依赖的静态库, 系统库,全部静态链接到可执行文件中(参考 https://blog.csdn.net/lhqsine/article/details/7547559)。但是静态链接也不是万能的,经常会出各种问题;
方法四、运行时替换ld.so和libc.so, 其中libc.so直接拷贝到目标机器上放到自己指定的一个目录下,ld.so在运行时命令行指定;(参考 https://blog.51cto.com/mickelfeng/938881)
libc.so.6: 是glibc的动态库,glibc是GNU发布的libc库,即c运行库。glibc是Linux系统中最底层的API,几乎其它任何运行库都会依赖于glibc。glibc除了封装Linux操作系统所提供的系统服务外,它本身也提供了许多其它一些必要功能服务的实现。查看系统glibc库版本可使用如下命令。 如果程序开发环境是比价新的glibc库,编译出来之后放到比较老的glibc库的系统上去运行,就经常会出现类似“/lib64/libc.so.6: version `GLIBC_2.14' not found”的错误。
bash-4.1$ strings /lib64/libc.so.6 |grep GLIBC_
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11
GLIBC_2.12
GLIBC_PRIVATE
ld-linux.so.X,其中X为一个数字,在不同的平台上名字也会不同。它是链接器(ld)的运行时组件,它定位应用程序使用的动态库并将其加载到内存中。 通常,在链接期间隐式指定动态链接器。 ELF规范说GCC包含一个名为INTERP的特殊ELF程序头,它的p_type为PT_INTERP。 此程序头指定解释器(interpreter)的路径。 可以使用readelf命令检查给定程序的程序头如下。
bash-4.1$ ls -l /lib64/ld*
-rwxr-xr-x. 1 root root 157072 May 21 2015 /lib64/ld-2.12.so
lrwxrwxrwx. 1 root root 10 Nov 26 2016 /lib64/ld-linux-x86-64.so.2 -> ld-2.12.so
lrwxrwxrwx. 1 root root 20 Nov 26 2016 /lib64/ld-lsb-x86-64.so.3 -> ld-linux-x86-64.so.2
bash-4.1$ readelf -l /bin/ls
Elf file type is EXEC (Executable file)
Entry point 0x4027e0
There are 8 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001c0 0x00000000000001c0 R E 8
INTERP 0x0000000000000200 0x0000000000400200 0x0000000000400200
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000189e4 0x00000000000189e4 R E 200000
LOAD 0x0000000000019000 0x0000000000619000 0x0000000000619000
0x00000000000026e0 0x00000000000026e0 RW 200000
DYNAMIC 0x0000000000019a88 0x0000000000619a88 0x0000000000619a88
0x00000000000001d0 0x00000000000001d0 RW 8
NOTE 0x000000000000021c 0x000000000040021c 0x000000000040021c
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x0000000000015d48 0x0000000000415d48 0x0000000000415d48
0x00000000000006b4 0x00000000000006b4 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 8
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .gnu.liblist .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame .dynstr
03 .ctors .dtors .jcr .data.rel.ro .dynamic .got .got.plt .data .bss .gnu.conflict
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
下面是一个摘自stackoverflow的回答:
https://stackoverflow.com/questions/8657908/deploying-yesod-to-heroku-cant-build-statically/8658468#
For dynamic linking, Linux (and most other UNIXes) support backward compatibility: an old binary continues to work on newer systems. But they don't support forward compatibility (a binary built on a newer system will generally not run on an older one).
But that's what you are trying to do: you built on a system with glibc-2.14 (or newer), and you are running on a system with glibc-2.13 (or older).
The other thing you need to know is that glibc is composed of some 200+ binaries that must all match exactly. Two key binaries are /lib/ld-linux.so
and /lib/libc.so.6
(but there are many more: libpthread.so.0
, libnsl.so.1
, etc. etc). If some of these binaries came from different versions of glibc, you usually get a crash. And that is exactly what you got, when you tried to place your glibc-2.14 libc.so.6
on the LD_LIBRARY_PATH
-- it no longer matches the system /lib/ld-linux
.
So what are the solutions? There are several possibilities (in increasing difficulty):
You could copy ld-2.14.so
(the target of /lib/ld-linux
symlink) to the target system, and invoke it explicitly:
/path/to/ld-2.14.so --library-path /path/to/your/executable
This generally works, but can confuse an application that looks at argv[0]
, and breaks for applications that re-exec themselves.
You could build on an older system.
You could use appgcc
(this option has disappeared, see this for description of what it used to be).
You could set up a chroot environment matching the target system, and build inside that chroot.
You could build yourself a Linux-to-olderLinux crosscompiler.