"as-needed" breaks our build with undefined symbols

Consider editing the original post to replace Unicode Character with " and utilize fenced code blocks so that people can play with the example with ease.

clang -shared -fpic -o libfoo.so foo.cc  # libfoo.so does not need libstdc++.so.6
clang -fuse-ld=bfd test.c -L./ -lfoo -Wl,--as-needed -lstdc++ -Wl,--no-as-needed  # a.out needs libstdc++.so.6
% readelf -W --dyn-syms tmp/c/libfoo.so | grep _ZSt21ios_base_library_initv
     5: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZSt21ios_base_library_initv

I have debugged ld. In binutils-gdb/bfd/elflink.c, libstdc++.so.6 is considered needed becuase it defines _ZSt21ios_base_library_initv@@GLIBCXX_3.4.32, which can satisfy libfoo.so’s unversioned reference.

/* Add symbols from an ELF object file to the linker hash table.  */

static bool
elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
{
...
              elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class)
                (elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED);

If libfoo.so needs libstdc++.so.6 (clang++ -shared -fpic -o libfoo.so foo.cc, clang++ instead of clang to link against libstdc++), a.out will not need libstdc++.so.6.

Why does GNU ld care about libfoo.so’s dependency on libstdc++.so.6?
I guess this is used as a linker workaround for underlinking problems.
When the missing dependency (libstdc++.so.6) by a DSO is seen by the executable link, the executable will get the DT_NEEDED to satisfy the DSO’s requirement, even if itself doesn’t need the dependency.

I think the justification for this special case is low and other linkers should not port this behavior.

I have updated my Explain GNU style linker options | MaskRay to mention GNU ld’s behavior