Search code examples
clinuxgccautotoolslibtool

libtool changes the order of my linker flags in autotools?


I am trying to statically build the web server lighttpd (version 1.4.49) using musl (for x86) as my compiler and lighttpd's autotools build system. My configuration script is as follows:

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

Where I have created my own static library "wrappers" that contains the wrapped definitions for the functions specified in my LDFLAGS argument for configure. The way everything is set up I need my wrapped library to be the first library linked (even before musl's standard c library), however libtool is changing the order of my LDFLAGS argument from above to the following:

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

instead of:

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

Which causes the following errors (I have only included the first few, but the rest are similar):

/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'

Its weird to me why this is happening, as everywhere else the LDFLAGS appear in the right order:

/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

Any help would be greatly appreciated! Thank you in advance.


Solution

  • LDFLAGS is not for libraries to add to the link. libtool notwithstanding, LDFLAGS is expanded too early in the link command, and this is not specific to the autotools.

    In your case, libtool appears to be recognizing that error, and in the case where that matters, moving the -L and -l options where they need to be, after the object(s) being linked. (Or at least the -l options need to be there, especially for a static link, and if libtool is going to move those, then there are practical reasons for moving the -L options, too.)

    Unfortunately, there is no other user-oriented Autotools variable appropriate to your stated purpose, either. Injecting extra libraries into the link is not a use case the Autotools are designed to support, and injecting them at the beginning of the link is unlikely to be feasible without hacking the autotooling.

    On the third hand, you appear to be misinterpreting the problem. You claim that

    I need my wrapped library to be the first library linked (even before musl's standard c library)

    But this ...

    /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'
    

    ... tells me exactly the opposite: even calls from inside standard library functions in libc are being wrapped, so the wrapper needs to appear last, even after the standard library (which ordinarily is last, not first).* And since libwrap probably calls standard library functions itself, you may need to link libc twice. Of course, that assumes that you really want to be messing with the standard library that way, which does not seem advisable to me.

    If you were performing a dynamic link then this would not be an issue: it would not be possible to wrap the internal calls of the C library in the first place. This suggests to me that the linker's --wrap option probably was not designed with static linking of the standard library in mind.

    I'm not inclined to set up a testbed to verify the following, but if you really do want to wrap libc's own internal function calls, then this may work: ... 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 is not really intended to be a user variable, and that's the potential weak point of this plan. But it is among Autoconf's standard output variables, and its contents should appear at the end of the link line. configure may prepend other libraries to LIBS, but it should not append any. The risk is that configure may clear any initial contents.

    The -lc appearing before -lwrappersis the secret sauce. Normally, you do not need to specify -lc explicitly, but in this case you do, because you need to resolve some symbols in it against libwrappers, which otherwise would be linked too early. You also (probably) need to link some symbols in libwrappers against libc. It may be redundant, but explicitly linking libc again, after libwrappers, may be necessary to overcome unwanted cleverness by the linker.

    If you want to avoid wrapping the internal libc self-calls, then you could try ... 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 .... The idea there is to turn off wrapping for libc (only), but it's pretty speculative, because although negating long options with no- is standard GNU form, the --no-wrap option in particular is not documented.


    *So libtool's reordering is not causing the issue you present. In fact, if libtool did not perform that reordering then you would have even more link errors.