bug#80153: libtool: 2.5.4 - gcc 16 --push-state --as-needed -latomic --pop-state vs. libtool

Jakub Jelinek via bug-libtool via Bug reports for the GNU libtool shared library maintenance tool <[email protected]> Fri, 9 Jan 2026 16:57:53 +0100
Newsgroups gmane.comp.gnu.libtool.bugs
Message-ID <aWElgbLBxsMI4eOc@tucnak>
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