Bug 31774 - inconsitency between gcc and g++ when linking with --as-needed
Summary: inconsitency between gcc and g++ when linking with --as-needed
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: driver (show other bugs)
Version: unknown
: P3 normal
Target Milestone: 9.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-05-01 19:41 UTC by Peter
Modified: 2021-08-26 04:11 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Peter 2007-05-01 19:41:50 UTC
I have problems linking executable with C++ library with --as-needed ld flag while linking with gcc succeeds. During investigation I found inconsistency in gcc and g++ calls concerning --as-needed. First I will show you what I do next I'll summarize what is this bug about:

* What I do:
First I compile/link objects which will be included in library:

libtool --mode=compile i686-pc-linux-gnu-g++ -c -g -O2 -pthread sync.cpp 
 i686-pc-linux-gnu-g++ -c -g -O2 -pthread sync.cpp  -fPIC -DPIC -o .libs/sync.o 
 i686-pc-linux-gnu-g++ -c -g -O2 -pthread sync.cpp -o sync.o >/dev/null 2>&1 

All objects I linked in the same way. Next library is linked itself
(I've edited output to simplify reading so there could be some typos):

libtool --mode=link i686-pc-linux-gnu-g++ -o libgigabase_r.la class.lo
  compiler.lo database.lo replicator.lo hashtab.lo file.lo symtab.lo 
  btree.lo rtree.lo cursor.lo query.lo pagepool.lo wwwapi.lo unisock.lo 
  blob.lo container.lo exception.lo localcli.lo sync.lo -pthread
  -rpath /usr/lib -version-info 2
i686-pc-linux-gnu-g++ -shared 
  -nostdlib /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../crti.o
  /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/crtbeginS.o
  .libs/class.o .libs/compiler.o .libs/database.o .libs/replicator.o
  .libs/hashtab.o .libs/file.o .libs/symtab.o .libs/btree.o
  .libs/rtree.o .libs/cursor.o .libs/query.o .libs/pagepool.o
  .libs/wwwapi.o .libs/unisock.o .libs/blob.o .libs/container.o
  .libs/exception.o .libs/localcli.o .libs/sync.o 
  -L/usr/lib/gcc/i686-pc-linux-gnu/4.1.2
  -L/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../../i686-pc-linux-gnu/lib
  -L/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../.. -lstdc++ -lm -lc
  -lgcc_s /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/crtendS.o
  /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../crtn.o  -pthread
  -Wl,-soname -Wl,libgigabase_r.so.2 -o .libs/libgigabase_r.so.2.0.0 
(cd .libs && rm -f libgigabase_r.so.2 && ln -s libgigabase_r.so.2.0.0 
  libgigabase_r.so.2) 
(cd .libs && rm -f libgigabase_r.so && ln -s libgigabase_r.so.2.0.0 
  libgigabase_r.so) 
i686-pc-linux-gnu-ar cru .libs/libgigabase_r.a  class.o compiler.o
  database.o replicator.o hashtab.o file.o symtab.o btree.o rtree.o
  cursor.o query.o pagepool.o wwwapi.o unisock.o blob.o container.o
  exception.o localcli.o sync.o 
i686-pc-linux-gnu-ranlib .libs/libgigabase_r.a 
creating libgigabase_r.la 
(cd .libs && rm -f libgigabase_r.la && ln -s ../libgigabase_r.la 
libgigabase_r.la) 

Now I link two programs (subsql and guess) against libgigabase_r.so.
While subsql builds successfully: 

i686-pc-linux-gnu-g++ -c -g -O2 -pthread  subsql.cpp 
i686-pc-linux-gnu-g++ -c -g -O2 -pthread  server.cpp 
libtool --mode=link i686-pc-linux-gnu-g++ -Wl,--as-needed -pthread  -o 
subsql subsql.o server.o libgigabase_r.la 
i686-pc-linux-gnu-g++ -Wl,--as-needed -pthread -o .libs/subsql 
subsql.o server.o  ./.libs/libgigabase_r.so 
creating subsql 

guess programm do not:

i686-pc-linux-gnu-g++ -c -g -O2 -pthread  guess.cpp 
libtool --mode=link i686-pc-linux-gnu-g++ -Wl,--as-needed -pthread  -o 
guess guess.o libgigabase_r.la 
i686-pc-linux-gnu-g++ -Wl,--as-needed -pthread -o .libs/guess 
guess.o  ./.libs/libgigabase_r.so 
./.libs/libgigabase_r.so: undefined reference to `pthread_key_create' 
./.libs/libgigabase_r.so: undefined reference to `pthread_getspecific' 
./.libs/libgigabase_r.so: undefined reference to `pthread_create' 
./.libs/libgigabase_r.so: undefined reference to `pthread_key_delete' 
./.libs/libgigabase_r.so: undefined reference to `pthread_detach' 
./.libs/libgigabase_r.so: undefined reference to `pthread_setspecific' 
./.libs/libgigabase_r.so: undefined reference to `pthread_join' 
collect2: ld returned 1 exit status 
make: *** [guess] Error 1

* What is this bug about:

As you noticed libtool links library with -nostdlib and this dependency on libpthread is missed in .libs/libgigabase_r.so. On pthreads mailing list I was assured that it's Ok to avoid this dependency and even sometimes this is useful.

Why the first linkage succeeds while second not.  I've looked at object files which are used to build final executables and found the differences between them. The object sever.o (which is used to build subsql) has pthread_* functions in elf Symbol table (part of output of readelf -W -a):

00002899  00006602 R_386_PC32             00000000   pthread_create 

and in .symtab: 

   102: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND pthread_create 

while the only object file guess.o (which is used to build guess) do not have any references to pthread_*().

Why I think this bug is in g++. I found that substitution of g++ to gcc during last linkage fixes compilation problem. While it seems to be wrong to link C++ program with gcc I've compared verbose output of gcc calls and found that difference in the output. g++ as well as gcc call collect2 but with a bit different options. g++ call of collect2 misses this part completely (which follows after other objects):

--no-as-needed -lpthread -lc -lgcc --as-needed

Just for record both calls here:
============================================================
[pva in ~/gigabase/gigabase]
 $=> i686-pc-linux-gnu-g++ -Wl,--as-needed -pthread -o .libs/guess guess.o  ./.libs/libgigabase_r.so -v
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: /var/tmp/portage/sys-devel/gcc-4.1.2/work/gcc-4.1.2/configure --prefix=/usr --bindir=/usr/i686-pc-linux-gnu/gcc-bin/4.1.2 --includedir=/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include --datadir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.2 --mandir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.2/man --infodir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.2/info --with-gxx-include-dir=/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4 --host=i686-pc-linux-gnu --build=i686-pc-linux-gnu --disable-altivec --enable-nls --without-included-gettext --with-system-zlib --disable-checking --disable-werror --enable-secureplt --disable-libunwind-exceptions --disable-multilib --disable-libmudflap --disable-libssp --disable-libgcj --enable-languages=c,c++ --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu
Thread model: posix
gcc version 4.1.2 (Gentoo 4.1.2)
 /usr/libexec/gcc/i686-pc-linux-gnu/4.1.2/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o .libs/guess /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../crt1.o /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../crti.o /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/crtbegin.o -L/usr/lib/gcc/i686-pc-linux-gnu/4.1.2 -L/usr/lib/gcc/i686-pc-linux-gnu/4.1.2 -L/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../../i686-pc-linux-gnu/lib -L/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../.. --as-needed guess.o ./.libs/libgigabase_r.so -lstdc++ -lm -lgcc_s -lgcc -lpthread -lc -lgcc_s -lgcc /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/crtend.o /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../crtn.o
./.libs/libgigabase_r.so: undefined reference to `pthread_key_create'
./.libs/libgigabase_r.so: undefined reference to `pthread_getspecific'
./.libs/libgigabase_r.so: undefined reference to `pthread_create'
./.libs/libgigabase_r.so: undefined reference to `pthread_key_delete'
./.libs/libgigabase_r.so: undefined reference to `pthread_detach'
./.libs/libgigabase_r.so: undefined reference to `pthread_setspecific'
./.libs/libgigabase_r.so: undefined reference to `pthread_join'
collect2: ld returned 1 exit status
[pva in ~/gigabase/gigabase]
 $=> i686-pc-linux-gnu-gcc -Wl,--as-needed -pthread -o .libs/guess guess.o  ./.libs/libgigabase_r.so -v
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: /var/tmp/portage/sys-devel/gcc-4.1.2/work/gcc-4.1.2/configure --prefix=/usr --bindir=/usr/i686-pc-linux-gnu/gcc-bin/4.1.2 --includedir=/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include --datadir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.2 --mandir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.2/man --infodir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.2/info --with-gxx-include-dir=/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4 --host=i686-pc-linux-gnu --build=i686-pc-linux-gnu --disable-altivec --enable-nls --without-included-gettext --with-system-zlib --disable-checking --disable-werror --enable-secureplt --disable-libunwind-exceptions --disable-multilib --disable-libmudflap --disable-libssp --disable-libgcj --enable-languages=c,c++ --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu
Thread model: posix
gcc version 4.1.2 (Gentoo 4.1.2)
 /usr/libexec/gcc/i686-pc-linux-gnu/4.1.2/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o .libs/guess /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../crt1.o /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../crti.o /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/crtbegin.o -L/usr/lib/gcc/i686-pc-linux-gnu/4.1.2 -L/usr/lib/gcc/i686-pc-linux-gnu/4.1.2 -L/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../../i686-pc-linux-gnu/lib -L/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../.. --as-needed guess.o ./.libs/libgigabase_r.so -lgcc --as-needed -lgcc_s --no-as-needed -lpthread -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/crtend.o /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../crtn.o
[pva in ~/gigabase/gigabase]
 $=>
============================================================

That is the inconsistency between gcc and g++.

[1] http://groups.google.com/group/comp.programming.threads/browse_thread/thread/5243754283a02465/5d73e8a1425663fe#5d73e8a1425663fe

Thank you very much for your time,
Peter.
Comment 1 Andrew Pinski 2007-05-01 21:03:02 UTC
I think this is really a libtool bug passing -nostdlib to g++, there is no reason why it should be doing that anyways.

Also --as-needed is a binutils option, since the pthreads library is not needed by the main program, it is needed by the shared library libgigabase_r.so, ld is not adding it to the link line which is the correct thing so libgigabase_r.so needs to link against libpthreads.so to be correctly done. 
Comment 2 Peter 2007-05-02 06:56:45 UTC
libtool bug was discussed earlier:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460

But this bug is not about libtool. Libtool just expose problem, although it should hide but that is another bug.

I may wish to have library not dependent on -pthread not linking with libpthread. Then further linking with this library for gcc succeeds, while for g++ not and this is what this bug is about. May be this should be fixed in gcc, but as gcc works and even it does some specific actions it seems to me that more natural fix will be to add same magic to g++. But proper solution is up to gcc maintainers.
Comment 3 Andrew Pinski 2021-08-26 04:11:31 UTC
Fixed for GCC 9 by r9-97.  G++ no longer does --no-as-needed instead it uses --push-state --as-needed .... --pop-state