Package: libtool;
Reported by: Jakub Jelinek <jakub <at> redhat.com>
Date: Thu, 8 Jan 2026 15:14:01 UTC
Severity: normal
To reply to this bug, email your comments to 80153 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
View this report as an mbox folder, status mbox, maintainer mbox
bug-libtool <at> gnu.org:bug#80153; Package libtool.
(Thu, 08 Jan 2026 15:14:01 GMT) Full text and rfc822 format available.Jakub Jelinek <jakub <at> redhat.com>:bug-libtool <at> gnu.org.
(Thu, 08 Jan 2026 15:14:02 GMT) Full text and rfc822 format available.Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Jakub Jelinek <jakub <at> redhat.com> To: bug-libtool <at> gnu.org Subject: libtool: 2.5.4 - gcc 16 --push-state --as-needed -latomic --pop-state vs. libtool Date: Thu, 8 Jan 2026 12:25:41 +0100
Hi! gcc 16 in https://gcc.gnu.org/r16-4315 https://gcc.gnu.org/PR81358 change added --push-state --as-needed -latomic --pop-state to the collect2/ld invocation from the gcc/g++ etc. drivers. Unfortunately libtool.m4 in the loop starting with # Parse the compiler output and extract the necessary # objects, libraries and library flags. grabs object files and libraries and -L/-R options from the compiler driver invocation of the linker and grabs them without these --push-state --as-needed / --pop-state wrapping options, which are needed to only link the library in if it is actually needed. I think on Solaris the pair is -z ignore / -z record instead, but unfortunately in that case it is less clear if those options are meant to affect just the single library and so are a property of that library, or if they have been randomly added e.g. by the user or whatever and affect instead what comes after it or multiple libraries etc. Anyway, what we see in gcc, as mentioned in https://gcc.gnu.org/PR123396 is that several shared libraries linked with libtool are then uselessly linked to libatomic.so: for i in libstdc++-v3/src/.libs/libstdc++.so.6.*.* libsanitizer/*/.libs/lib*.so.*.* libgcobol/.libs/lib*.so.*.*; do echo $i; ldd -u $i; done libstdc++-v3/src/.libs/libstdc++.so.6.0.35 Unused direct dependencies: /lib64/libatomic.so.1 libsanitizer/asan/.libs/libasan.so.8.0.0 Unused direct dependencies: /lib64/libatomic.so.1 libsanitizer/hwasan/.libs/libhwasan.so.0.0.0 Unused direct dependencies: /lib64/libm.so.6 /lib64/libatomic.so.1 libsanitizer/lsan/.libs/liblsan.so.0.0.0 Unused direct dependencies: /lib64/libm.so.6 /lib64/libatomic.so.1 libsanitizer/tsan/.libs/libtsan.so.2.0.0 Unused direct dependencies: /lib64/libatomic.so.1 libsanitizer/ubsan/.libs/libubsan.so.1.0.0 Unused direct dependencies: /lib64/libm.so.6 /lib64/libatomic.so.1 libgcobol/.libs/libgcobol.so.2.0.0 Unused direct dependencies: /lib64/libatomic.so.1 E.g. for libstdc++-v3, libtool created by configure has postdep_objects="/home/jakub/src/gcc/obj38/./gcc/crtendS.o /lib/../lib64/crtn.o" postdeps=" -lgcc_s -latomic -lc -lgcc_s " I see -latomic in postdeps or postdeps_CXX in other packags, e.g. when gettext is built with gcc 16, but in that case I actually don't see any shared library or binary linked uselessly against libatomic.so.1; not really sure why though. In https://gcc.gnu.org/pipermail/gcc-patches/2025-December/704644.html the PR81358 patch author suggested to work around this by filtering out -latomic from postdeps_CXX, though I think that just means the libraries will never be linked against libatomic.so.1 rather than only linking against it on architectures where e.g. some atomics aren't provided by inlined code and need to fallback to libatomic.so.1. So, I've been wondering if the libtool.m4 # Parse the compiler output and extract the necessary # objects, libraries and library flags. couldn't special case at least the --push-state --as-needed options before -lXXX option and --pop-state after it and in that case put into postdeps_* var instead of just -lXXX $_LT_TAGVAR(lt_prog_compiler_wl, $1)--push-state $_LT_TAGVAR(lt_prog_compiler_wl, $1)--as-needed -lXXX $_LT_TAGVAR(lt_prog_compiler_wl, $1) But I admit I haven't studied in detail in what exactly the postdeps var is used. Jakub
bug-libtool <at> gnu.org:bug#80153; Package libtool.
(Thu, 08 Jan 2026 17:12:02 GMT) Full text and rfc822 format available.Message #8 received at 80153 <at> debbugs.gnu.org (full text, mbox):
From: Frederic Berat <fberat <at> redhat.com> To: Jakub Jelinek <jakub <at> redhat.com> Cc: 80153 <at> debbugs.gnu.org Subject: Re: bug#80153: libtool: 2.5.4 - gcc 16 --push-state --as-needed -latomic --pop-state vs. libtool Date: Thu, 8 Jan 2026 18:10:59 +0100
[Message part 1 (text/plain, inline)]
On Thu, Jan 8, 2026 at 4:14 PM Jakub Jelinek via bug-libtool via Bug reports for the GNU libtool shared library maintenance tool < bug-libtool <at> gnu.org> wrote: > Hi! > > gcc 16 in https://gcc.gnu.org/r16-4315 https://gcc.gnu.org/PR81358 change > added --push-state --as-needed -latomic --pop-state to the collect2/ld > invocation from the gcc/g++ etc. drivers. > > Unfortunately libtool.m4 in the loop starting with > # Parse the compiler output and extract the necessary > # objects, libraries and library flags. > grabs object files and libraries and -L/-R options from the compiler > driver invocation of the linker and grabs them without these > --push-state --as-needed / --pop-state wrapping options, which are needed > to only link the library in if it is actually needed. > I think on Solaris the pair is -z ignore / -z record instead, but > unfortunately in that case it is less clear if those options are meant to > affect just the single library and so are a property of that library, or > if they have been randomly added e.g. by the user or whatever and affect > instead what comes after it or multiple libraries etc. > > Anyway, what we see in gcc, as mentioned in https://gcc.gnu.org/PR123396 > is that several shared libraries linked with libtool are then uselessly > linked to libatomic.so: > for i in libstdc++-v3/src/.libs/libstdc++.so.6.*.* > libsanitizer/*/.libs/lib*.so.*.* libgcobol/.libs/lib*.so.*.*; do echo $i; > ldd -u $i; done > libstdc++-v3/src/.libs/libstdc++.so.6.0.35 > Unused direct dependencies: > /lib64/libatomic.so.1 > libsanitizer/asan/.libs/libasan.so.8.0.0 > Unused direct dependencies: > /lib64/libatomic.so.1 > libsanitizer/hwasan/.libs/libhwasan.so.0.0.0 > Unused direct dependencies: > /lib64/libm.so.6 > /lib64/libatomic.so.1 > libsanitizer/lsan/.libs/liblsan.so.0.0.0 > Unused direct dependencies: > /lib64/libm.so.6 > /lib64/libatomic.so.1 > libsanitizer/tsan/.libs/libtsan.so.2.0.0 > Unused direct dependencies: > /lib64/libatomic.so.1 > libsanitizer/ubsan/.libs/libubsan.so.1.0.0 > Unused direct dependencies: > /lib64/libm.so.6 > /lib64/libatomic.so.1 > libgcobol/.libs/libgcobol.so.2.0.0 > Unused direct dependencies: > /lib64/libatomic.so.1 > E.g. for libstdc++-v3, libtool created by configure has > postdep_objects="/home/jakub/src/gcc/obj38/./gcc/crtendS.o > /lib/../lib64/crtn.o" > postdeps=" -lgcc_s -latomic -lc -lgcc_s " > > I see -latomic in postdeps or postdeps_CXX in other packags, e.g. when > gettext is built with gcc 16, but in that case I actually don't see any > shared library or binary linked uselessly against libatomic.so.1; not > really > sure why though. > > In https://gcc.gnu.org/pipermail/gcc-patches/2025-December/704644.html > the PR81358 patch author suggested to work around this by filtering > out -latomic from postdeps_CXX, though I think that just means the > libraries > will never be linked against libatomic.so.1 rather than only linking > against > it on architectures where e.g. some atomics aren't provided by inlined code > and need to fallback to libatomic.so.1. > > So, I've been wondering if the libtool.m4 > # Parse the compiler output and extract the necessary > # objects, libraries and library flags. > couldn't special case at least the --push-state --as-needed options before > -lXXX option and --pop-state after it and in that case put into postdeps_* > var instead of just -lXXX > $_LT_TAGVAR(lt_prog_compiler_wl, $1)--push-state > $_LT_TAGVAR(lt_prog_compiler_wl, $1)--as-needed -lXXX > $_LT_TAGVAR(lt_prog_compiler_wl, $1) > But I admit I haven't studied in detail in what exactly the postdeps var is > used. > > I've attached a standalone reproduction script that I tested in a fedora-rawhide environment with GCC16. And a patch that I'm planning to apply on fedora's libtool 2.5.4 (I don't have the master equivalent yet), although I'm not sure that I do what I should there, so I'd be pleased to get feedback. Without the patch, libtool generates the following command: libtool: link: g++ -std=gnu++11 -fPIC -DPIC -shared -nostdlib /usr/lib/gcc/x86_64-redhat-linux/16/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/16/crtbeginS.o .libs/repro.o -L/usr/lib/gcc/x86_64-redhat-linux/16 -L/usr/lib/gcc/x86_64-redhat-linux/16/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/16/../../.. -L/lib -L/usr/lib -lstdc++ -lm -lgcc_s -latomic -lc -lgcc_s /usr/lib/gcc/x86_64-redhat-linux/16/crtendS.o /usr/lib/gcc/x86_64-redhat-linux/16/../../../../lib64/crtn.o -Wl,-soname -Wl,librepro.so.0 -o .libs/librepro.so.0.0.0 The push-state/as-needed/pop-state gets stripped. With the patch we get that one: libtool: link: g++ -std=gnu++11 -fPIC -DPIC -shared -nostdlib /usr/lib/gcc/x86_64-redhat-linux/16/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/16/crtbeginS.o .libs/repro.o -L/usr/lib/gcc/x86_64-redhat-linux/16 -L/usr/lib/gcc/x86_64-redhat-linux/16/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/16/../../.. -L/lib -L/usr/lib -lstdc++ -lm -lgcc_s -Wl,--push-state -Wl,--as-needed -latomic -Wl,--pop-state -lc -lgcc_s /usr/lib/gcc/x86_64-redhat-linux/16/crtendS.o /usr/lib/gcc/x86_64-redhat-linux/16/../../../../lib64/crtn.o -Wl,-soname -Wl,librepro.so.0 -o .libs/librepro.so.0.0.0 Fred. > Jakub > > > > >
[Message part 2 (text/html, inline)]
[0001-Preserve-positional-linker-state-flags.patch (text/x-patch, attachment)]
[repro.sh (application/x-shellscript, attachment)]
bug-libtool <at> gnu.org:bug#80153; Package libtool.
(Fri, 09 Jan 2026 15:59:02 GMT) Full text and rfc822 format available.Message #11 received at 80153 <at> debbugs.gnu.org (full text, mbox):
From: Jakub Jelinek <jakub <at> redhat.com> To: Frederic Berat <fberat <at> redhat.com> Cc: 80153 <at> debbugs.gnu.org Subject: Re: bug#80153: libtool: 2.5.4 - gcc 16 --push-state --as-needed -latomic --pop-state vs. libtool Date: Fri, 9 Jan 2026 16:57:53 +0100
On Thu, Jan 08, 2026 at 06:10:59PM +0100, Frederic Berat wrote:
> I've attached a standalone reproduction script that I tested in a
> fedora-rawhide environment with GCC16.
> And a patch that I'm planning to apply on fedora's libtool 2.5.4 (I don't
> have the master equivalent yet), although I'm not sure that I do what I
> should there, so I'd be pleased to get feedback.
Thanks.
> Without the patch, libtool generates the following command:
For libtool.m4, I've been thinking more about something like below
(though this patch is for the much older libtool.m4 copy in gcc
instead of 2.5.4).
So that it doesn't copy random --push-state or --as-needed etc.
option, only the cases where it is exactly
--push-state --{,no-}as-needed -l* --pop-state
where there is a single -l* will have the wrappers and other cases
will not. As those are the cases where we know for sure the
corresponding option is meant to override just that single library and
nothing else.
E.g.
--as-needed or --no-as-needed could come up on random other places of
the command line based on distro defaults or $CC used etc.
--- libtool.m4 2025-12-30 22:20:58.573130385 +0100
+++ libtool.m4 2026-01-09 16:51:35.393699435 +0100
@@ -6634,8 +6634,70 @@ if AC_TRY_EVAL(ac_compile); then
# Sentinel used to keep track of whether or not we are before
# the conftest object file.
pre_test_object_deps_done=no
+ state_pre=
+ state_post=
+
+ for pp in `eval "$output_verbose_link_cmd"`; do
+ p=$pp
+ case $p in
+
+ --push-state)
+ # Handle --push-state --as-needed -lfoo --pop-state
+ state_pre=$p
+ continue
+ ;;
+
+ --as-needed|--no-as-needed)
+ if test x$state_pre == x--push-state; then
+ state_pre="$state_pre $p "
+ else
+ state_pre=
+ fi
+ continue
+ ;;
+
+ --pop-state)
+ case "$state_pre" in
+ "--push-state --"*)
+ case "$prev" in
+ -l*)
+ state_post=" $p"
+ p=$prev
+ prev=
+ ;;
+ *)
+ state_pre=
+ ;;
+ esac
+ ;;
+ *)
+ state_pre=
+ ;;
+ esac
+ ;;
+
+ -l*)
+ case "$state_pre" in
+ "--push-state --"*)
+ if test -z "$prev"; then
+ prev=$p
+ continue
+ fi
+ p="${prev} ${p}"
+ state_pre=
+ ;;
+ *)
+ state_pre=
+ ;;
+ esac
+ ;;
+
+ *)
+ state_pre=
+ ;;
+
+ esac
- for p in `eval "$output_verbose_link_cmd"`; do
case $p in
-L* | -R* | -l*)
@@ -6666,11 +6728,13 @@ if AC_TRY_EVAL(ac_compile); then
esac
else
if test -z "$_LT_TAGVAR(postdeps, $1)"; then
- _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+ _LT_TAGVAR(postdeps, $1)="${state_pre}${prev}${p}${state_post}"
else
- _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${state_pre}${prev}${p}${state_post}"
fi
fi
+ state_pre=
+ state_post=
;;
*.$objext)
Jakub
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.