在Alpine Docker中编译时可能导致链接错误的原因是什么?

我正在尝试根据Alpine 3.7基本映像构建的docker容器中编译程序。该程序使用class,并将其包括为argp.h。我已经安装了argp-standalone并验证了它正在将其安装到映像中。文件#include <argp.h>位于argp.h中,但是当我使用以下命令编译程序时:

usr/include

我收到以下错误:

gcc -W -Wall -Wextra -I/usr/include   -c -o progname.o progname.c
gcc -largp -o progname progname.o

我有:

  • 确保图像上的progname.o: In function `parse_opt': progname.c:(.text+0x4c9): undefined reference to `argp_failure' progname.c:(.text+0x50f): undefined reference to `argp_failure' progname.c:(.text+0x555): undefined reference to `argp_failure' progname.c:(.text+0x59b): undefined reference to `argp_failure' progname.c:(.text+0x5ce): undefined reference to `argp_error' progname.c:(.text+0x5f4): undefined reference to `argp_error' progname.o: In function `main': progname.c:(.text+0x1397): undefined reference to `argp_parse' collect2: error: ld returned 1 exit status make: *** [Makefile:9: progname] Error 1 版本实际上包括argp.hargp_failureargp_parse函数。
  • 试图将argp_error移至计算机上的不同位置(例如,移至正在进行编译的同一目录中,移至argp.h中)
  • 尝试使用/usr/lib-l进行编译。

映像中还安装了相关的软件包-Lbuild-basemake。 在Ubuntu映像上编译时,即使没有gcc-largp标志,这些相同的命令也可以正常工作。 Alpine图片中可能会发生什么不同的事情,从而导致此工作不起作用?

修改

根据@Pablo的评论,我现在将其编译如下:

-I/usr/include

在确认静态库gcc -W -Wall -Wextra -I/usr/include -L/usr/lib -c -o progname.o progname.c gcc -largp -o progname progname.o 位于libargp.a中之后。但是,相同的问题仍然存在。

编辑2

按以下方式编译(并再次按照@Pablo的建议)已解决我遇到的错误:

/usr/lib

但是,我仍然很好奇为什么使用完全相同的库和指令,当在Ubuntu映像中编译而没有问题时,却无法在Alpine映像中编译。

NICHNICHNICH 回答:在Alpine Docker中编译时可能导致链接错误的原因是什么?

我仍然很好奇,为什么使用完全相同的库和指令,这将无法在 Alpine 映像中编译,而在 Ubuntu 映像中编译没有问题。

Alpine 链接错误的原因可能有点令人惊讶,实际上并非 Alpine 特有。

虽然无法链接:

gcc -largp -o progname progname.o

这有效:

gcc -o progname progname.o -largp

原因是传递给链接器的参数的顺序,它与链接算法有关。通常,在链接命令行中首先指定对象(可能还有用户的静态库),然后使用 -l 指定库。 Eli Bendersky 的文章 Library order in static linking 中完美地解释了标准链接器算法:

对象文件和库在命令行中按特定顺序从左到右提供。这是链接顺序。以下是链接器的作用:

  • 链接器维护一个符号表。这个符号表做了很多事情,但其中有两个列表:
    • 迄今为止遇到的所有对象和库导出的符号列表。
    • 遇到的对象和库请求导入但尚未找到的未定义符号列表。
  • 当链接器遇到一个新的目标文件时,它会查看:
    • 它导出的符号:这些被添加到上面提到的导出符号列表中。如果任何符号在 undefined 列表中,它就会从那里删除,因为它现在已经找到了。如果导出列表中已经有任何符号,我们会收到“多重定义”错误:两个不同的对象导出相同的符号,链接器混淆。
    • 它导入的符号:这些符号被添加到未定义符号列表中,除非它们可以在导出符号列表中找到。
  • 当链接器遇到一个新库时,事情会变得更有趣一些。链接器遍历库中的所有对象。对于每一个,它首先查看它导出的符号。
    • 如果它导出的任何符号在未定义列表中,则将对象添加到链接并执行下一步。否则,将跳过下一步。
    • 如果对象已添加到链接中,则按上述方式处理 - 其未定义和导出的符号将添加到符号表中。
    • 最后,如果库中的任何对象已包含在链接中,则会再次重新扫描库 - 由包含的对象导入的符号可能会在同一库中的其他对象中找到。

-largp 首先出现时,链接器不会在链接过程中包含它的任何对象,因为它还没有任何未定义的符号。如果静态库是通过路径提供的,而不是通过 -l 提供的,那么它的所有对象都会被添加到链接过程中。

本文链接:https://www.f2er.com/3134358.html

大家都在问