如何使用 make/gcc 静态 link 除 glibc 之外的所有库?

How to statically link all libraries except glibc using make/gcc?

我正在尝试编译一个程序,使所有库都静态地包含在最终的二进制文件中,但我仍然希望 glibc 是动态链接的。如果我使用“-static”,它会静态编译所有库,包括 glibc。基本上我需要一个 -static 参数以及类似 -exclude=glibc 的参数 使用 "make" 的示例以及使用纯 "gcc" 的示例都很棒。 运行 "ldd" 在最终的二进制文件上应该只显示动态链接的 glibc。

您可以 link 使用 -Bstatic and -Bdynamic 静态库的子集。在 GCC 命令行上,这看起来像这样(linking 静态针对 PCRE,仅作为示例):

-Wl,-Bstatic -lpcre -Wl,-Bdynamic

请注意 -lanl-ldl-lm-lmvec-lnsl-lpthread-lresolv-lrt-lutil 都是 glibc 的一部分,因此必须在 -Wl,-Bdynamic 之后(以便动态地 linked)。对于 -lcrypt,这取决于分布。

您所要求的可以在某些系统上大约完成,但不能使用 GCC 的 -static 选项。该选项对 linking:

具有全局影响

On systems that support dynamic linking, this overrides -pie and prevents linking with the shared libraries. On other systems, this option has no effect.

(GCC 9.2 manual)

要对 linking 进行所需级别的控制,您需要将标志传递给 linker。您可以使用 GCC 的 -Wl 选项来做到这一点。如果您正在使用 GCC,那么您可能也在使用 GNU linker,并且在支持静态和动态 linking 的构建目标上,它有多种混合它们的机制。特别是,GNU linker 的 -Bstatic 标志及其对应的 -Bdynamic 标志每个仅对命令行上以它们命名的库有效,直到下一个这样的标志。也就是说,它们允许您在为静态 linking 和动态 linking 指定库之间来回切换。

示例:

此 C 程序需要 linked 数学库,这不是 GCC 自动完成的:

link_test.c:

#include <stdio.h>
#include <math.h>

int main(void) {
    printf("The square root of 2 is approximately %f\n", sqrt(2.0));
}

gcc 命令将导致 -lm 静态 linked,但 libc 动态 linked:

gcc -o link_test link_test.c -Wl,-Bstatic -lm -Wl,-Bdynamic

任何数量的附加 -l 选项、库名称和目标文件名都可以与 -lm 一起放在 -Wl,-Bstatic-Wl,-Bdynamic 选项之间;所有这些对象都将被静态 linked。虽然 libc 没有明确地 linked(GCC 不需要),但在显式参数列表的末尾将 link 类型切换为 "dynamic" 对我来说确实如此, 导致 libc 被动态 linked:

$ ldd link_test
        linux-vdso.so.1 =>  (0x00007ffe185af000)
        libc.so.6 => /lib64/libc.so.6 (0x00002b775f059000)
        /lib64/ld-linux-x86-64.so.2 (0x00002b775ee35000)

(注意 libm 没有出现在动态库列表中,这与未使用 -Wl,-Bstatic 而 libc 不同。)

请注意,您的 objective 即 "Running 'ldd' on the final binary should show only glibc dynamically linked" 不一定可行,如上面的 ldd 输出所示。如果您的可执行文件完全是动态 linked,那么除了任何动态库之外,它还将包含动态加载器 linked,并且可能还有特定于平台的伪库,例如 linux-vdso.so.1.

您要求提供一个 makefile 示例,但这就像只要求 "write me a program"。这与 make 无关,并且有无数种方法可以将上述方法合并到 makefile 中。但既然你问了,这是最简单的变体之一:

生成文件

link_test: link_test.c
        gcc -o $@ $< -Wl,-Bstatic -lm -Wl,-Bdynamic