ubuntushared-librariesld

Why does Ubuntu's linker use --as-needed by default?


On Linux with gcc, when using the -l option to specify a library and that library is not needed (no reference to any symbol in that library), sometimes the linker stores a reference to that library (option --no-as-needed), sometimes it does not (option --as-needed). The documented (man ld) behaviour is to include the library. Therefore, the default option is --no-as-needed.

However, on Ubuntu, it seems that the default is --as-needed, even though man ld on the same system says the opposite.

Do you know why?

Let's take an example. Consider the empty program test1.c which references nothing but the standard C library:

int main(int argc, char* argv[])
{
}

Now, let's build it and specify an unneeded library, here -lsrt:

gcc -c test1.c
echo "=== default"
gcc test1.o -lsrt -o test1
ldd test1
echo "=== --as-needed"
gcc test1.o -Wl,--as-needed -lsrt -o test1
ldd test1
echo "=== --no-as-needed"
gcc test1.o -Wl,--no-as-needed -lsrt -o test1
ldd test1

On Ubuntu 24.10 with GCC 14.2.0, we get this:

=== default
    linux-vdso.so.1 (0x0000f2c7dae1c000)
    libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000f2c7dabe0000)
    /lib/ld-linux-aarch64.so.1 (0x0000f2c7dadd0000)
=== --as-needed
    linux-vdso.so.1 (0x0000ff893479c000)
    libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000ff8934560000)
    /lib/ld-linux-aarch64.so.1 (0x0000ff8934750000)
=== --no-as-needed
    linux-vdso.so.1 (0x0000e80830bea000)
    libsrt.so.1.5 => /lib/aarch64-linux-gnu/libsrt.so.1.5 (0x0000e80830a90000)
    libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000e808308d0000)
    libcrypto.so.3 => /lib/aarch64-linux-gnu/libcrypto.so.3 (0x0000e80830200000)
    libstdc++.so.6 => /lib/aarch64-linux-gnu/libstdc++.so.6 (0x0000e8082fe00000)
    libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x0000e80830820000)
    libgcc_s.so.1 => /lib/aarch64-linux-gnu/libgcc_s.so.1 (0x0000e808307e0000)
    /lib/ld-linux-aarch64.so.1 (0x0000e80830ba0000)
    libz.so.1 => /lib/aarch64-linux-gnu/libz.so.1 (0x0000e808307a0000)
    libzstd.so.1 => /lib/aarch64-linux-gnu/libzstd.so.1 (0x0000e80830140000)

On the other hand, on Fedora 41 with GCC 14.2.1, the default is the same as --no-as-needed.

The question has already been asked here in 2018 but got no answer.


Solution

  • The --as-needed/--no-as-needed distro-schism occurred in 2013 with Debian Wheezy, which broke with tradition by building GCC to pass --as-needed to the linker by default. Subsequently the Debian-derived distros (including Ubuntu) followed suit while Fedora and its derivatives stayed old-school.

    The linker (ld) is not changed. The difference is whether the distro's GCC build by default passes --as-needed to the linker at a position before the explicit and implicit libraries (thus overriding the linker's default), or does not pass it (accepting the linker's default).

    Why did Debian go this way? Here is the rationale. As your own example shows, you can load a lot of superfluous DSOs with --no-as-needed.

    Why didn't Fedora? Since they didn't change, they didn't publish an explanation of not changing (AFAIK). I'd assume the old-school thinking was that's it's best for GCC by default to follow the linker on this point, since --as-needed linking is considerably more work than --no-as-needed. So there's a tradeoff on which judgements might differ.