【问题标题】:libtool changes the order of my linker flags in autotools?libtool 更改我的链接器标志在 autotools 中的顺序?
【发布时间】:2021-12-14 22:58:57
【问题描述】:

我正在尝试使用 musl(用于 x86)作为我的编译器和 lighttpd 的 autotools 构建系统来静态构建 Web 服务器 lighttpd(版本 1.4.49)。我的配置脚本如下:

CC=/home/musl-1.1.23/install/bin/musl-gcc CFLAGS="-g --static" LDFLAGS="-L/home/lighttpd -lwrappers -static-libgcc -Wl,--wrap=socket -Wl,--wrap=bind -Wl,--wrap=listen -Wl,--wrap=accept4 -Wl,--wrap=send -Wl,--wrap=recv -Wl,--wrap=shutdown LIGHTTPD_STATIC=yes ./configure --prefix=/home/lighttpd/install --enable-static --disable-shared --without-zlib --disable-ipv6 --without-bzip2 --without-pcre

我创建了自己的静态库“包装器”,其中包含我的 LDFLAGS 参数中为 configure 指定的函数的包装定义。一切设置的方式我需要我的包装库成为第一个链接的库(甚至在 musl 的标准 c 库之前),但是 libtool 正在将我的 LDFLAGS 参数的顺序从上面更改为以下:

libtool: link: /home/musl-1.1.23/install/bin/musl-gcc -g --static -Wall -W -Wshadow -pedantic -static-libgcc -Wl,--wrap=socket -Wl,--wrap=bind -Wl,--wrap=listen -Wl,--wrap=accept4 -Wl,--wrap=send -Wl,--wrap=recv -Wl,--wrap=shutdown -o proc_open proc_open-proc_open.o proc_open-buffer.o  -L/home/lighttpd-1.4.49 -lwrappers

代替:

libtool: link: /home/musl-1.1.23/install/bin/musl-gcc -g --static -Wall -W -Wshadow -pedantic -L/home/lighttpd-1.4.49 -lwrappers -static-libgcc -Wl,--wrap=socket -Wl,--wrap=bind -Wl,--wrap=listen -Wl,--wrap=accept4 -Wl,--wrap=send -Wl,--wrap=recv -Wl,--wrap=shutdown -o proc_open proc_open-proc_open.o proc_open-buffer.o

这会导致以下错误(我只包括了前几个,但其余的类似):

/usr/local/bin/ld: /home/musl-1.1.23/install/lib/libc.a(syslog.o): in function `__openlog':
/home/musl-1.1.23/src/misc/syslog.c:51: undefined reference to `__wrap_socket'
/usr/local/bin/ld: /home/musl-1.1.23/install/lib/libc.a(syslog.o): in function `_vsyslog':
/usr/local/bin/ld: /home/musl-1.1.23/src/misc/syslog.c:111: undefined reference to `__wrap_send'
/usr/local/bin/ld: /home/musl-1.1.23/src/misc/syslog.c:113: undefined reference to `__wrap_send'

我很奇怪为什么会发生这种情况,因为 LDFLAGS 以正确的顺序出现在其他任何地方:

/bin/bash ../libtool  --tag=CC   --mode=link /home/musl-1.1.23/install/bin/musl-gcc   -g --static -Wall -W -Wshadow -pedantic -module -export-dynamic -avoid-version -L/home/lighttpd -lwrappers -static-libgcc -Wl,--wrap=socket -Wl,--wrap=bind -Wl,--wrap=listen -Wl,--wrap=accept4 -Wl,--wrap=send -Wl,--wrap=recv -Wl,--wrap=shutdown -o mod_setenv.la -rpath /home/lighttpd/install/lib mod_setenv.lo  
libtool: link: ranlib .libs/mod_scgi.a

任何帮助将不胜感激!提前谢谢你。

【问题讨论】:

    标签: c linux gcc autotools libtool


    【解决方案1】:

    LDFLAGS 不适用于库添加到链接。尽管libtoolLDFLAGS 在链接命令中扩展得太早,这不是特定于自动工具的。

    在您的情况下,libtool 似乎正在识别该错误,并且在这很重要的情况下,将 -L-l 选项移动到它们需要的位置,之后正在链接的对象。 (或者至少需要有-l 选项,尤其是对于静态链接,如果libtool 将移动这些选项,那么移动-L 选项也是有实际原因的。)

    不幸的是,也没有其他面向用户的 Autotools 变量适合您声明的目的。将额外的库注入链接不是 Autotools 旨在支持的用例,如果不破解自动工具,将它们在链接的开头注入是不可能的。

    另一方面,您似乎误解了问题。你声称

    我需要我的包装库成为第一个链接的库(甚至在 musl 的标准 c 库之前)

    但这...

    /usr/local/bin/ld: /home/musl-1.1.23/install/lib/libc.a(syslog.o): in function `_vsyslog':
    /usr/local/bin/ld: /home/musl-1.1.23/src/misc/syslog.c:111: undefined reference to `__wrap_send'
    

    ... 告诉我恰恰相反:即使来自 libc 中标准库函数内部的调用也被包装,所以包装器需要出现在 last,甚至 after标准库(通常是最后一个,而不是第一个)。* 由于libwrap 可能会调用标准库函数本身,您可能需要链接 libc 两次。当然,这假设您真的想以这种方式弄乱标准库,这对我来说似乎不可取。

    如果您正在执行动态链接,那么这将不是问题:首先无法包装 C 库的内部调用。这向我表明,链接器的 --wrap 选项可能在设计时并未考虑到标准库的静态链接。

    我不倾向于建立一个测试平台来验证以下内容,但如果你真的想包装 libc 自己的内部函数调用,那么这可能会起作用:... LDFLAGS="-static-libgcc -Wl,--wrap=socket -Wl,--wrap=bind -Wl,--wrap=listen -Wl,--wrap=accept4 -Wl,--wrap=send -Wl,--wrap=recv -Wl,--wrap=shutdown" LIBS="-L/home/lighttpd -lc -lwrappers -lc" ./configure ...

    LIBS 并不是真正打算成为用户变量,这就是该计划的潜在弱点。但它是 Autoconf 的标准输出变量之一,它的内容应该出现在链接行的末尾。 configure 可以将其他库添加到LIBS,但不应添加任何库。风险在于configure 可能会清除任何初始内容。

    -lc 出现在-lwrappers 之前是秘诀。通常,您不需要显式指定 -lc,但在这种情况下您需要这样做,因为您需要针对 libwrappers 解析其中的一些符号,否则会过早链接。您还(可能)需要将 libwrappers 中的一些符号与 libc 链接起来。这可能是多余的,但在 libwrappers 之后再次显式链接 libc 可能是必要的,以克服链接器不必要的聪明。

    如果你想避免包装内部 libc 自调用,那么你可以试试... LDFLAGS="-static-libgcc -Wl,--wrap=socket -Wl,--wrap=bind -Wl,--wrap=listen -Wl,--wrap=accept4 -Wl,--wrap=send -Wl,--wrap=recv -Wl,--wrap=shutdown" LIBS="-L/home/lighttpd -lwrappers -Wl,--no-wrap=socket -Wl,--no-wrap=bind -Wl,--no-wrap=listen -Wl,--no-wrap=accept4 -Wl,--no-wrap=send -Wl,--no-wrap=recv -Wl,--no-wrap=shutdown" ./configure ...。这里的想法是(仅)关闭 libc 的包装,但它非常具有推测性,因为虽然用 no- 否定长选项是标准 GNU 形式,但特别是 --no-wrap 选项没有记录。


    *所以 libtool 的重新排序不会导致您出现的问题。事实上,如果 libtool 不执行该重新排序,那么您将遇到更多的链接错误。

    【讨论】:

    • 哇,非常感谢。这是一个很棒的解释。不幸的是 --no-wrap 不被 gcc 识别。另外,我并不真正关心包装 libc 的函数——但我想到了一个替代的想法。似乎很多这种并发症可以通过不使用包裹来缓解。因此,或者,我是否可以在静态库中定义自己的 socket()、bind()、listen()、...等函数,并将其链接到 musl 的 std-libc 之前,以便 musl 的 socket()、bind()、 ...等永远不会被lighttpd链接到?你对尝试这样做有什么想法?感谢您的回答,非常有帮助。
    • @ballsmahoney,标准库函数的标识符被保留用作具有外部链接的标识符。因此,未定义的行为源于提供替代实现,我确信这首先是--wrap 的重点。那,以及能够调用原始函数的包装器。您可以尝试一下,看看会发生什么,但即使它看起来有效,它也可能会在运行时创建隐藏的陷阱,让您大吃一惊。
    • 静态链接吗?
    • 不幸的是,我知道。也许我可以添加 FLAGS -nostdinc 和/或 -nostdlib 然后静态链接包含我想要的定义的库,然后链接 musl 的静态 C 库,以解决我自己的库不包含的所有标准 C 库功能。
    • 我看不出这如何与静态链接一起工作,@ballsmahoney。静态库不是预链接单元;相反,它们是可链接对象的简单捆绑。这与与 --wrap 链接导致 libc 函数也被包装在您的案例中这一事实密切相关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-08
    • 2014-03-17
    相关资源
    最近更新 更多