Chr*_*nth 4 c linker docker alpine-linux
我正在尝试在从 Alpine 3.7 基础映像构建的 docker 容器中编译一个程序。该程序使用argp.h, 并将其包含为 #include <argp.h>. 我已经安装了 argp-standalone 并验证它是否已添加到映像中。该文件argp.h位于usr/include,但是当我使用以下命令编译程序时:
gcc -W -Wall -Wextra -I/usr/include -c -o progname.o progname.c
gcc -largp -o progname progname.o
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
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
Run Code Online (Sandbox Code Playgroud)
我有:
argp.h确实包含argp_failure、argp_parse和argp_error函数。argp.h到机器上的不同位置(例如,进入编译所在的同一目录,进入/usr/lib)-l和进行编译-L。映像中还安装的相关软件包有build-base、make和gcc。在 Ubuntu 映像上编译时,即使没有-largp和-I/usr/include标志,这些相同的命令也可以正常工作。Alpine 图像中可能发生什么不同的情况导致此功能不起作用?
编辑
根据 @Pablo 的评论,我现在将其编译如下:
gcc -W -Wall -Wextra -I/usr/include -L/usr/lib -c -o progname.o progname.c
gcc -largp -o progname progname.o
Run Code Online (Sandbox Code Playgroud)
验证静态库 后,libargp.a位于 中/usr/lib。然而,同样的问题仍然存在。
编辑2
编译如下(再次按照@Pablo的建议)解决了我遇到的错误:
gcc -W -Wall -Wextra -I/usr/include -L/usr/lib -c -o progname.o progname.c
gcc -o progname progname.o /usr/lib/libargp.a
Run Code Online (Sandbox Code Playgroud)
然而,我仍然很好奇为什么使用完全相同的库和指令,在 Alpine 映像中编译失败,而在 Ubuntu 映像中编译没有问题。
我仍然好奇为什么使用完全相同的库和指令,在 Alpine 映像中编译失败,而在 Ubuntu 映像中编译没有问题。
Alpine 上出现链接错误的原因可能有点令人惊讶,实际上并不是 Alpine 特有的。
虽然这无法链接:
gcc -largp -o progname progname.o
Run Code Online (Sandbox Code Playgroud)
这有效:
gcc -o progname progname.o -largp
Run Code Online (Sandbox Code Playgroud)
原因是传递给链接器的参数顺序,并且与链接算法有关。通常,在链接命令行中首先指定对象(可能还指定任何用户的静态库),然后使用-l. Eli Bendersky 的文章静态链接中的库顺序完美地解释了标准链接器算法:
目标文件和库在命令行上按一定顺序从左到右提供。这是链接顺序。这是链接器的作用:
- 链接器维护一个符号表。这个符号表做了很多事情,但其中保留了两个列表:
- 到目前为止遇到的所有对象和库导出的符号列表。
- 遇到的对象和库请求导入但尚未找到的未定义符号的列表。
- 当链接器遇到新的目标文件时,它会查看:
- 它导出的符号:这些符号被添加到上面提到的导出符号列表中。如果任何符号位于未定义列表中,则会将其从那里删除,因为现在已找到它。如果导出列表中已经存在任何符号,我们会收到“多重定义”错误:两个不同的对象导出相同的符号,并且链接器会感到困惑。
- 它导入的符号:这些符号将添加到未定义符号列表中,除非可以在导出符号列表中找到它们。
- 当链接器遇到新库时,事情会变得更有趣。链接器会遍历库中的所有对象。对于每个符号,它首先查看其导出的符号。
- 如果它导出的任何符号位于未定义列表中,则该对象将添加到链接并执行下一步。否则,将跳过下一步。
- 如果对象已添加到链接,则按上述方式处理 - 其未定义和导出的符号将添加到符号表中。
- 最后,如果库中的任何对象已包含在链接中,则会再次重新扫描库 - 可能会在同一库内的其他对象中找到包含的对象导入的符号。
当-largp首次出现时,链接器不会在链接过程中包含其任何对象,因为它还没有任何未定义的符号。如果静态库由路径提供,而不是通过 提供-l,则其所有对象都将添加到链接过程中。
| 归档时间: |
|
| 查看次数: |
1869 次 |
| 最近记录: |