bug#78072: Libtool incorrectly tries to use shared library when linking statically
Mike Krinkin <[email protected]> Fri, 25 Apr 2025 19:53:01 +0100
| Newsgroups | gmane.comp.gnu.libtool.bugs |
|---|---|
| Message-ID | <CACpa5=_fWppv7jG9d7zVh2M_pMCZOfZ=_shzibA-cTwCjkizsA@mail.gmail.com> |
--000000000000a04ff106339ed81d Content-Type: text/plain; charset="UTF-8" Hi There, I hit a weird behaviour when build colm as part of building Envoy proxy. Cutting through layers of the stack on top of the libtool things here is what things boil down to: 1. we have a project using autogen/configure/libtool that was configured with `--enable-static` and `--disable-shared` 2. when I run make on the project one of the linking steps failed with the following error: ``` ld.lld: error: attempted static link of dynamic object /usr/lib/libstdc++.so ``` Looking at the debug logs for the libtool invocations here is what I see: ``` /bin/sh ../libtool --tag=CXX --mode=link /usr/bin/clang-18 -Wall -DINCLUDEDIR='"/root/.cache/bazel/_bazel_root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3/execroot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir/colm/include"' -DLIBDIR='"/root/.cache/bazel/_bazel_root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3/execroot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir/colm/lib"' -DABS_TOP_BUILDDIR='"/root/.cache/bazel/_bazel_root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3/execroot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir"' -DABS_BUILDDIR='"/root/.cache/bazel/_bazel_root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3/execroot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir/src"' -DCONS_INIT -U_FORTIFY_SOURCE -fstack-protector -Wall -Wthread-safety -Wself-assign -Wunused-but-set-parameter -Wno-free-nonheap-object -fcolor-diagnostics -fno-omit-frame-pointer -g0 -O2 -D_FORTIFY_SOURCE=1 -DNDEBUG -ffunction-sections -fdata-sections -stdlib=libc++ -no-canonical-prefixes -Wno-builtin-macro-redefined -D__DATE__=redacted -D__TIMESTAMP__=redacted -D__TIME__=redacted -DABSL_MIN_LOG_LEVEL=4 -fdebug-types-section -fPIC -Wno-deprecated-declarations -std=c++20 -fsized-deallocation --static -lstdc++ -Wno-unused-command-line-argument -L. -Wl,--gdb-index -fuse-ld=/usr/bin/ld.lld -B/usr/bin -Wl,-no-as-needed -Wl,-z,relro,-z,now -lm -pthread -Wl,--gc-sections -l:libc++.a -l:libc++abi.a -fuse-ld=lld -o bootstrap0 bootstrap0-consinit.o bootstrap0-main.o libprog.a libcolm.la ``` NOTE: I split it in multiple lines to make it easier to read, originally it was a single line. There is a lot there, but two things that I believe are particularly relevant are: `--static` and `-lstdc++` flags. I believe that libtool next translated it into an actual command to link the binary and from the logs here is what I saw: ``` /usr/bin/clang-18 -Wall -DINCLUDEDIR=\"/root/.cache/bazel/_bazel_root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3/execroot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir/colm/include\" -DLIBDIR=\"/root/.cache/bazel/_bazel_root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3/execroot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir/colm/lib\" -DABS_TOP_BUILDDIR=\"/root/.cache/bazel/_bazel_root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3/execroot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir\" -DABS_BUILDDIR=\"/root/.cache/bazel/_bazel_root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3/execroot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir/src\" -DCONS_INIT -U_FORTIFY_SOURCE -fstack-protector -Wall -Wthread-safety -Wself-assign -Wunused-but-set-parameter -Wno-free-nonheap-object -fcolor-diagnostics -fno-omit-frame-pointer -g0 -O2 -D_FORTIFY_SOURCE=1 -DNDEBUG -ffunction-sections -fdata-sections -stdlib=libc++ -no-canonical-prefixes -Wno-builtin-macro-redefined -D__DATE__=redacted -D__TIMESTAMP__=redacted -D__TIME__=redacted -DABSL_MIN_LOG_LEVEL=4 -fdebug-types-section -fPIC -Wno-deprecated-declarations -std=c++20 -fsized-deallocation --static -Wno-unused-command-line-argument -Wl,--gdb-index -fuse-ld=/usr/bin/ld.lld -B/usr/bin -Wl,-no-as-needed -Wl,-z -Wl,relro -Wl,-z -Wl,now -Wl,--gc-sections -fuse-ld=lld -o bootstrap0 bootstrap0-consinit.o bootstrap0-main.o /usr/lib/libstdc++.so -L. libprog.a ./.libs/libcolm.a -lm -l:libc++.a -l:libc++abi.a -pthread ``` It's pretty close to what we asked libtool to do with a few differences: it does not have -lstdc++ flag and instead passes /usr/lib/libstdc++.so along with other object files as input to the linker which obviously does not work. My understanding is that libtool looked at -lstdc++ flag, found a corresponding libstdc++.la file and "resolved" it into a shared library. What I'm baffled by in this case is why did libtool resolve it to a shared library instead of a static one, even though it's clearly a static build? Moreover, even if we wanted to link against the dynamic library, it should be done via -l flag, so what libtool looks very weird - we can't just link shared library as if it was a object file or a static library. Am I missing something or libtool is completely off the mark here and trying to do something weird? Both shared and static libraries are present (and in the right directory) and la file looks reasonable otherwise: ``` # libstdc++.la - a libtool library file # Generated by libtool (GNU libtool 1.3134 2009-11-29) 2.2.7a # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='libstdc++.so.6' # Names of this library. library_names='libstdc++.so.6.0.32 libstdc++.so.6 libstdc++.so' # The name of the static archive. old_library='libstdc++.a' # Linker flags that can not go in dependency_libs. inherited_linker_flags='' # Libraries that this one depends upon. dependency_libs=' -lm' # Names of additional weak libraries provided by this library weak_library_names='' # Version information for libstdc++. current=6 age=0 revision=32 # Is this an already installed library? installed=yes # Should we warn about portability when linking against -modules? shouldnotlink=no # Files to dlopen/dlpreopen dlopen='' dlpreopen='' # Directory that this library needs to be installed in: libdir='/usr/lib' ``` If I just deleate the .la file all together, it skips the libtool siliness and things just work (that's how we are working around the issue now). Thank you. --000000000000a04ff106339ed81d Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">Hi There,<div><br></div><div>I hit a weird behaviour when = build colm as part of building Envoy proxy. Cutting through layers of the s= tack on top of the libtool things here is what things boil down to:</div><d= iv><br></div><div>1. we have a project using autogen/configure/libtool that= was configured with `--enable-static` and `--disable-shared`</div><div>2. = when I run make on the project one of the linking steps failed with the fol= lowing error:<br><br>```</div><div>ld.lld: error: attempted static link of = dynamic object /usr/lib/libstdc++.so<br>```</div><div><br></div><div>Lookin= g at the debug logs for the libtool invocations here is what I see:<br><br>= ```</div><div>/bin/sh ../libtool</div><div>=C2=A0 --tag=3DCXX</div><div>=C2= =A0 --mode=3Dlink</div><div>=C2=A0 /usr/bin/clang-18</div><div>=C2=A0 -Wall= </div><div>=C2=A0 -DINCLUDEDIR=3D'"/root/.cache/bazel/_bazel_root/= 37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3/execroot/= envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir/colm/include&= quot;'</div><div>=C2=A0 -DLIBDIR=3D'"/root/.cache/bazel/_bazel= _root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3/exe= croot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir/colm/li= b"'</div><div>=C2=A0 -DABS_TOP_BUILDDIR=3D'"/root/.cache/= bazel/_bazel_root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-s= andbox/3/execroot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tm= pdir"'</div><div>=C2=A0 -DABS_BUILDDIR=3D'"/root/.cache/b= azel/_bazel_root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sa= ndbox/3/execroot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmp= dir/src"'</div><div>=C2=A0 -DCONS_INIT</div><div>=C2=A0 -U_FORTIFY= _SOURCE</div><div>=C2=A0 -fstack-protector</div><div>=C2=A0 -Wall</div><div= >=C2=A0 -Wthread-safety</div><div>=C2=A0 -Wself-assign</div><div>=C2=A0 -Wu= nused-but-set-parameter</div><div>=C2=A0 -Wno-free-nonheap-object</div><div= >=C2=A0 -fcolor-diagnostics</div><div>=C2=A0 -fno-omit-frame-pointer</div><= div>=C2=A0 -g0</div><div>=C2=A0 -O2</div><div>=C2=A0 -D_FORTIFY_SOURCE=3D1<= /div><div>=C2=A0 -DNDEBUG</div><div>=C2=A0 -ffunction-sections</div><div>= =C2=A0 -fdata-sections</div><div>=C2=A0 -stdlib=3Dlibc++</div><div>=C2=A0 -= no-canonical-prefixes</div><div>=C2=A0 -Wno-builtin-macro-redefined</div><d= iv>=C2=A0 -D__DATE__=3Dredacted</div><div>=C2=A0 -D__TIMESTAMP__=3Dredacted= </div><div>=C2=A0 -D__TIME__=3Dredacted</div><div>=C2=A0 -DABSL_MIN_LOG_LEV= EL=3D4</div><div>=C2=A0 -fdebug-types-section</div><div>=C2=A0 -fPIC</div><= div>=C2=A0 -Wno-deprecated-declarations</div><div>=C2=A0 -std=3Dc++20 -fsiz= ed-deallocation</div><div>=C2=A0 --static</div><div>=C2=A0 -lstdc++</div><d= iv>=C2=A0 -Wno-unused-command-line-argument</div><div>=C2=A0 -L.</div><div>= =C2=A0 -Wl,--gdb-index</div><div>=C2=A0 -fuse-ld=3D/usr/bin/ld.lld</div><di= v>=C2=A0 -B/usr/bin</div><div>=C2=A0 -Wl,-no-as-needed</div><div>=C2=A0 -Wl= ,-z,relro,-z,now</div><div>=C2=A0 -lm</div><div>=C2=A0 -pthread</div><div>= =C2=A0 -Wl,--gc-sections</div><div>=C2=A0 -l:libc++.a</div><div>=C2=A0 -l:l= ibc++abi.a</div><div>=C2=A0 -fuse-ld=3Dlld</div><div>=C2=A0 -o bootstrap0 b= ootstrap0-consinit.o bootstrap0-main.o libprog.a <a href=3D"http://libcolm.= la">libcolm.la</a><br>```<br><br>NOTE: I split it in multiple lines to make= it easier to read, originally it was a single line.</div><div><br></div><d= iv>There is a lot there, but two things that I believe are particularly rel= evant are: `--static` and `-lstdc++` flags.</div><div>I believe that libtoo= l next translated it into an actual command to link the binary and from the= logs here is what I saw:<br><br>```</div><div>/usr/bin/clang-18</div><div>= =C2=A0 -Wall</div><div>=C2=A0 -DINCLUDEDIR=3D\"/root/.cache/bazel/_baz= el_root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3/e= xecroot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir/colm/= include\"</div><div>=C2=A0 -DLIBDIR=3D\"/root/.cache/bazel/_bazel= _root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3/exe= croot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir/colm/li= b\"</div><div>=C2=A0 -DABS_TOP_BUILDDIR=3D\"/root/.cache/bazel/_b= azel_root/37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3= /execroot/envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir\&qu= ot;</div><div>=C2=A0 -DABS_BUILDDIR=3D\"/root/.cache/bazel/_bazel_root= /37e3aec351bcd85a6ea8b58e3592ef6e/sandbox/processwrapper-sandbox/3/execroot= /envoy/bazel-out/k8-opt/bin/bazel/foreign_cc/colm.build_tmpdir/src\"</= div><div>=C2=A0 -DCONS_INIT</div><div>=C2=A0 -U_FORTIFY_SOURCE</div><div>= =C2=A0 -fstack-protector</div><div>=C2=A0 -Wall</div><div>=C2=A0 -Wthread-s= afety</div><div>=C2=A0 -Wself-assign</div><div>=C2=A0 -Wunused-but-set-para= meter</div><div>=C2=A0 -Wno-free-nonheap-object</div><div>=C2=A0 -fcolor-di= agnostics</div><div>=C2=A0 -fno-omit-frame-pointer</div><div>=C2=A0 -g0</di= v><div>=C2=A0 -O2</div><div>=C2=A0 -D_FORTIFY_SOURCE=3D1</div><div>=C2=A0 -= DNDEBUG</div><div>=C2=A0 -ffunction-sections</div><div>=C2=A0 -fdata-sectio= ns</div><div>=C2=A0 -stdlib=3Dlibc++</div><div>=C2=A0 -no-canonical-prefixe= s</div><div>=C2=A0 -Wno-builtin-macro-redefined</div><div>=C2=A0 -D__DATE__= =3Dredacted</div><div>=C2=A0 -D__TIMESTAMP__=3Dredacted</div><div>=C2=A0 -D= __TIME__=3Dredacted</div><div>=C2=A0 -DABSL_MIN_LOG_LEVEL=3D4</div><div>=C2= =A0 -fdebug-types-section</div><div>=C2=A0 -fPIC</div><div>=C2=A0 -Wno-depr= ecated-declarations</div><div>=C2=A0 -std=3Dc++20</div><div>=C2=A0 -fsized-= deallocation</div><div>=C2=A0 --static</div><div>=C2=A0 -Wno-unused-command= -line-argument</div><div>=C2=A0 -Wl,--gdb-index</div><div>=C2=A0 -fuse-ld= =3D/usr/bin/ld.lld</div><div>=C2=A0 -B/usr/bin</div><div>=C2=A0 -Wl,-no-as-= needed</div><div>=C2=A0 -Wl,-z</div><div>=C2=A0 -Wl,relro</div><div>=C2=A0 = -Wl,-z</div><div>=C2=A0 -Wl,now</div><div>=C2=A0 -Wl,--gc-sections</div><di= v>=C2=A0 -fuse-ld=3Dlld</div><div>=C2=A0 -o bootstrap0 bootstrap0-consinit.= o bootstrap0-main.o =C2=A0/usr/lib/libstdc++.so</div><div>=C2=A0 -L. libpro= g.a</div><div>=C2=A0 ./.libs/libcolm.a</div><div>=C2=A0 -lm</div><div>=C2= =A0 -l:libc++.a</div><div>=C2=A0 -l:libc++abi.a</div><div>=C2=A0 -pthread<b= r>```<br><br>It's pretty close to what we asked libtool to do with a fe= w differences: it does not have -lstdc++ flag and instead passes /usr/lib/l= ibstdc++.so along with other object files as input to the linker which obvi= ously does not work.<br><br>My understanding is that libtool looked at -lst= dc++ flag, found a corresponding libstdc++.la file and "resolved"= it into a shared library.</div><div><br></div><div>What I'm baffled by= in this case is why did libtool resolve it to a shared library instead of = a static one, even though it's clearly a static build?</div><div>Moreov= er, even if we wanted to link against the dynamic library, it should be don= e via -l flag, so what libtool looks very weird - we can't just link sh= ared library as if it was a object file or a static library.</div><div>Am I= missing something or libtool is completely off the mark here and trying to= do something weird?<br><br><br>Both shared and static libraries are presen= t (and in the right directory) and la file looks reasonable otherwise:<br><= br>```</div><div># libstdc++.la - a libtool library file<br># Generated by = libtool (GNU libtool 1.3134 2009-11-29) 2.2.7a<br>#<br># Please DO NOT dele= te this file!<br># It is necessary for linking the library.<br><br># The na= me that we can dlopen(3).<br>dlname=3D'libstdc++.so.6'<br><br># Nam= es of this library.<br>library_names=3D'libstdc++.so.6.0.32 libstdc++.s= o.6 libstdc++.so'<br><br># The name of the static archive.<br>old_libra= ry=3D'libstdc++.a'<br><br># Linker flags that can not go in depende= ncy_libs.<br>inherited_linker_flags=3D''<br><br># Libraries that th= is one depends upon.<br>dependency_libs=3D' -lm'<br><br># Names of = additional weak libraries provided by this library<br>weak_library_names=3D= ''<br><br># Version information for libstdc++.<br>current=3D6<br>ag= e=3D0<br>revision=3D32<br><br># Is this an already installed library?<br>in= stalled=3Dyes<br><br># Should we warn about portability when linking agains= t -modules?<br>shouldnotlink=3Dno<br><br># Files to dlopen/dlpreopen<br>dlo= pen=3D''<br>dlpreopen=3D''<br><br># Directory that this lib= rary needs to be installed in:<br>libdir=3D'/usr/lib'</div><div>```= </div><div><br></div><div>If I just deleate the .la file all together, it s= kips the libtool siliness and things just work (that's how we are worki= ng around the issue now).<br><br>Thank you.</div></div> --000000000000a04ff106339ed81d--