0%

静态编译使用 getaddrinfo 出现警告及动态静态混合使用

使用 -static 编译出现以下警告

libcurl.a(netrc.c.o): In function `Curl_parsenetrc':
netrc.c:(.text.Curl_parsenetrc+0x23e): warning: Using 'getpwuid' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
libplayer.a(stream_wfd.c.o): In function `wfd_stream_open':
stream_wfd.c:(.text.wfd_stream_open+0x5fe): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

glibc uses libnss to support a number of different providers for address resolution services. Unfortunately, you cannot statically link libnss, as exactly what providers it loads depends on the local system’s configuration.

相关功能不能正常工作,需要使用 动态编译 解决此问题或者更换编译工具链为 uclibc、 musl-gcc

动态

动态库后缀为 .so,是 Shared Object 的缩写,程序运行时的动态链接,多个进程可以链接同一个共享库。动态库在程序编译时并不会被连接到目标代码中,程序运行时被载入,因此在程序运行时还需要动态库存在。

编译生成动态库

gcc -fPIC -shared -o libmax.so max.c
  • -fPIC 为编译器选项,是 Position Independent Code 的缩写,表示要生成位置无关的代码,这是动态库需要的特性
  • -shared 为链接器选项,告诉 gcc 生成动态库而不是可执行文件

使用动态连接库

gcc test.c -L. -lmax
  • 生成可执行文件 a.out
  • -L. 表示搜索要链接的库文件时包含当前路径
  • -lmax 表示要链接 libmax.so,如果同一目录下同时存在同名的动态库和静态库,比如 libmax.so 和 libmax.a 都在当前路径下,则 gcc 会优先链接动态库

运行

$ ./a.out
./a.out: error while loading shared libraries: libmax.so: cannot open shared object file: No such file or directory

找不到 libmax.so,原来 Linux 是通过 /etc/ld.so.cache 文件搜寻要链接的动态库的。而 /etc/ld.so.cache 是 ldconfig 程序读取 /etc/ld.so.conf 文件生成的。( /etc/ld.so.conf 中并不必包含 /lib 和 /usr/lib, ldconfig 程序会自动搜索这两个目录)
如果我们把 libmax.so 所在的路径添加到 /etc/ld.so.conf 中,再以 root 权限运行 ldconfig 程序,更新 /etc/ld.so.cache, a.out 运行时,就可以找到 libmax.so。

还有另一种简单的方法,就是为 a.out 指定 LD_LIBRARY_PATH

LD_LIBRARY_PATH=. ./a.out

LD_LIBRARY_PATH 是寻找链接的动态库路径

对于 elf 格式的可执行程序,是由 ld-linux.so* 来完成的,它先后搜索 elf 文件 的 DT_RPATH 段,环境变量 LD_LIBRARY_PATH , /etc/ld.so.cache 文件列表, /lib/ , /usr/lib 目录,找到库文件后将其载入内存

静态

静态库后缀为 .a,静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。

LDFLAGS += -static

工具

ldd

使用 ldd 查看可执行程序依赖那些动态库或着动态库依赖于那些动态库

$ ldd /lib/libxtables.so.10
    linux-vdso.so.1 =>  (0x00007ffdf51f5000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fb9cda56000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb9cd676000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fb9cde67000)

nm

使用 nm 工具,查看静态库和动态库中有那些函数名

$ nm /lib/libxtables.so.10

nm 列出的符号有很多, 常见的有三种:

  • T 类:是在库中定义的函数,用 T 表示,这是最常见的
  • U 类:是在库中被调用,但并没有在库中定义(表明需要其他库支持),用 U 表示
  • W 类:是所谓的 弱态 符号,它们虽然在库中被定义,但是可能被其他库中的同名符号覆盖,用 W 表示

ar

使用 ar 工具,可以生成静态库,同时可以查看静态库中包含那些 .o 文件,即有那些源文件构成

$ ar -t libpng.a
pngerror.c.o
pngmem.c.o
pngrio.c.o
pngrutil.c.o
pngtrans.c.o
png.c.o
pngget.c.o
pngread.c.o
pngpread.c.o
pngrtran.c.o
pngset.c.o

如何查看动态库和静态库是 32 位,还是 64 位下的库

  • file .so
  • objdump -x .a

混合链接

当 ld 使用了选项 -static 时会导致所有的库使用静态链接,因此当使用混合链接是一定不能使用 -static,只能通过 -Wl,-Bstatic -llibname 或 -Wl,-Bdynamic -llibname 来指定链接方式

  • LIBRARY_PATH 环境变量:指定程序静态链接库文件搜索路径
  • LD_LIBRARY_PATH 环境变量:指定程序动态链接库文件搜索路径

Ref

  1. statically-linked binary that uses getaddrinfo?
  2. Glibc warning concerning use of getaddrinfo() in static library
  3. Static Linking Considered Harmful
  4. linux 库 动态 静态 编译 混合 使用
  5. 关于 GCC 中同时使用动态和静态库链接的操作参数和解释
  6. Linux static linking is dead?