在GCC中部分静态链接和部分动态链接的连接方式

5
我正在尝试使用GCC编译一个非常简单(像hello world一样简单)的C程序,同时使用动态和静态链接。 我想了解如何在一般情况下执行此操作,因此我的最小测试示例只是尝试将libc作为静态库链接并将libm作为动态库链接。
我至少遇到了以下关于同一主题的问题: GCC:仅静态链接某些库 gcc中共享库函数的静态链接 其中的一些答案建议使用-Wl,-Bstatic和-Wl,-Bdynamic来指定分别是静态和动态库。 还建议仅指定要链接的静态库的完整路径等其他内容。
我尝试了几个建议以及其变体。 我不明白它给我的错误消息。 我知道PIE是什么,但我不知道它与我正在尝试做的有什么关系。
这是一些失败的尝试:
$ gcc test.c /usr/lib64/libc.a
linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
urned 1 exit status
$ gcc test.c -Wl,-Bdynamic -lm -Wl,-Bstatic -lc
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bdynamic -lm -Wl,-Bstatic -lc test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
$ gcc -Wl,-Bstatic -lc -Wl,-Bdynamic -lm test.c
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../x86_64-pc-linux-gnu/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.3/../../../../lib64/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status

仅使用无参数编译,以及使用-static参数可以正常工作,但我需要部分静态编译:

$ gcc test.c -lm
$ gcc -static test.c -lm

然而,以下也失败了:
$ gcc test.c /usr/lib64/libc.a /usr/lib64/libm.a

我在这篇帖子中遇到了类似的错误:

C++静态链接共享库

然而,这些答案似乎并不适用于我的问题。

我试图编译的程序很简单(作为test.c):

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

int main(int argc, char **argv)
{
    int i = 0;

    for(i = 0; i < 65535; i++) {
            printf("%f\n", sinf(i));
            printf("%f\n", cosf(i));
            printf("%f\n", tanf(i));
            printf("%f\n", sqrtf(i));
    }


    return 0;
}

编辑:请注意,程序必须足够复杂才需要使用libm,否则如果实际上不需要libm,则链接尝试可能会产生误报。在我的原始test.c示例中,我仅使用sinf()到一个常量值,这使得编译器完全优化掉了sinf()调用。

我正在使用:

$ gcc --version
gcc (Gentoo 4.7.3-r1 p1.4, pie-0.5.5) 4.7.3

你尝试过按照GCC的建议去做(查看失败信息)吗? - Ashalynd
“-fPIE”和“-pie”对我来说毫无意义,无论如何我都不想编译成PIE。 - AttributedTensorField
1个回答

4
以下对我有效。
ln -s `gcc -print-file-name=libc.a`
gcc -static-libgcc -L. -lc test.c

然后ldd a.out会给出以下结果:
not a dynamic executable

翻译如下:

编辑:

原帖作者想要动态链接一个库,同时静态链接另一个库。他有一个例子,是静态链接 libc,动态链接 libm。我尝试了这个特殊情况,但没有成功。不过,反过来是可行的,即动态链接 libc,静态链接 libm

ln -s `gcc -print-file-name=libm.a`
gcc test.c -L. -lm

然后运行ldd a.out命令会得到:
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x41960000)
/lib/ld-linux.so.2 (0x4193d000)

请注意链接顺序的重要性。例如,gcc -L. -lm test.c 是不起作用的。
这也适用于其他库。例如 gomp
gcc -fopenmp test.c
ldd显示libgomp.so.1。我们可以像这样静态链接它。
ln -s `gcc -print-file-name=libgomp.a`
gcc -L. -fopenmp test.c

现在,ldd a.out 不会显示 libgomp.so.1。但在这种情况下,pthreads 仍然是动态链接的。要静态链接 pthreads,需要同时静态链接 libc

你好像已经编译了一个静态二进制文件。目的是将某些库静态链接到一个二进制文件中,同时将另一个库动态链接。例如,在原始问题中,将libc静态链接并将libm动态链接。在你的例子中,这个a.out文件只是静态的。 - AttributedTensorField
我的示例程序中包含的源代码存在问题。由于sinf()被调用时使用了常量参数,编译器会在编译之前计算结果并将其优化掉,因此不需要libm。当我更改源代码以实际需要libm时,在尝试编译您的示例时,会出现以下错误:test.c:(.text+0x28): undefined reference to `sinf'。我会更新问题并提供适当的代码示例。 - AttributedTensorField
您还可以看到,建议的命令无法生成包含任何libm的二进制文件,只需查看文件大小即可。使用gcc -L. -lm test.c得到的大小与仅使用gcc test.c而没有其他参数的大小相同。 - AttributedTensorField
@Z玻色子,更一般地说。我有一个库(libmpx),我只有.so(动态)版本,我必须动态链接它,但我希望其他所有内容(libc,libm等)都静态链接。 - AttributedTensorField
@isedev,除了静态库之外,我还可以使用第二个动态链接的libc,但是你如何做到这一点?你如何避免我收到的错误? - AttributedTensorField
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接