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.

相关功能不能正常工作,需要使用 动态编译 解决此问题或者更换编译工具链为 uclibcmusl-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.solibmax.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.cacheldconfig 程序读取 /etc/ld.so.conf 文件生成的。( /etc/ld.so.conf 中并不必包含 /lib/usr/libldconfig 程序会自动搜索这两个目录)
如果我们把 libmax.so 所在的路径添加到 /etc/ld.so.conf 中,再以 root 权限运行 ldconfig 程序,更新 /etc/ld.so.cachea.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?