Hi,

I've investigated the testsuite with your feedback and it seems all problems
I missed are coming from the line merging old_deplibs into dependency_libs.

It seems using the same loop as the snippet above, ie. checking for
absolute path and adding pwd if needed, is enough to fix the absolute
path requirement. The test was failing because, fortunately in the test,
the referenced static archive was used from a different working directory.

Then it was also failing on the test producing libltdl.so. It seems that
I misunderstand this part of the code back then and though it would only
affect old libraries because the linker would use $deplibs when building
the shared library. However, the static archives would still be forwarded
to dependency_libs in the final libtool archive because of that, which the
testsuite fortunately catched too. By gating the code with a check on
library_names (so assuming static archives are squashed into the shared
libraries), I can finally pass this last remaining test.

Here is a new revision. with this change. The main changes are commit
message to reference this issue and this line:

+           func_append dependency_libs " $old_deplibs"

Transformed into:

+         # Forward old library dependencies only when no shared
+         # library is being built. When building the shared library,
+         # the linker uses $deplibs to link the archives into it, but
+         # then we don't want to add it as transitive dependency.
+         if test -z "$library_names"; then
+           for lib in $old_deplibs; do
+             case $lib in
+               [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+               *) abs=`pwd`"/$lib" ;;
+             esac
+             func_append dependency_libs " $abs"
+           done
+         fi

I've copied the code above for path handling without accounting whether
refactoring could be interesting or not.

Regards,
--
Alexandre Janniaux
Videolabs



Le sam. 16 mai 2026 à 11:49, Alexandre Janniaux <[email protected]> a
écrit :

> Hi,
>
> Thanks for the review, sorry for the test failure. I'll provide a new
> revision of the patches.
>
> Regards,
> --
> Alexandre Janniaux
> Videolabs
>
> Le ven. 15 mai 2026 à 19:59, Ileana Dumitrescu <[email protected]>
> a écrit :
>
>> Follow-up Comment #1, patch #10569 (group libtool):
>>
>> Thank you for the patches!
>>
>> Unfortunately, these changes cause several libtool tests to fail on
>> GNU/Linux
>> due to a relative path of dlopen.a being added to the linking command. I
>> converted the dependency_libs path into an absolute path, which fixed
>> most of
>> the tests, but a different failure was caused in configure-iface.at. I
>> will
>> try debugging this some more, but I may not be able to fix it before the
>> next
>> beta/stable releases. If you submit new patch files with a fix before me,
>> I
>> would be happy to test and hopefully apply them.
>>
>>
>>
>>
>>     _______________________________________________________
>>
>> Reply to this item at:
>>
>>   <https://savannah.gnu.org/patch/?10569>
>>
>> _______________________________________________
>> Message sent via Savannah
>> https://savannah.gnu.org/
>>
>
From e12afb3e216a015db5d5e7d567ee1fb18f559564 Mon Sep 17 00:00:00 2001
From: Alexandre Janniaux <[email protected]>
Date: Tue, 6 Apr 2021 10:22:14 +0200
Subject: [PATCH 1/3] ltmain.in: ensure old libraries are not archived
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Previously, adding a static archive library, aka. old library, as a
dependency of a new libtool library compiled as a static archive (be it
a convenience library or an installed static library) resulted in the
dependency archive being added into the target archive as-is.

However, linkers are usually not able to use nested archive as-is. It
results in errors like these on Linux and Darwin at least:

    /usr/bin/ld: ./.libs/libfoo.a: member ./.libs/libfoo.a(libbar.a) in
    archive is not an object

or

    /usr/bin/nm: libbar.a: file format not recognized

With libfoo.a being the static libtool target and libbar.a being the
nested/linked static library.

Libtool has a quite close behaviour with convenience libraries, where
the content (objects) of the convenience library are extracted and added
back into the new target, but that´s mostly a libtool creation.

The static dependencies should not be "linked" into other static
libraries as there should not be linking involved, and we don´t want to
potentially duplicate symbols like done for the convenience libraries.

Instead, keep them in the dependency_libs of the new libtool archive
created and forward them until we link a shared library or an
executable. We do need to ensure they are referenced with absolute path
since we can link from a different folder than the one it was referenced
from.

We also need to filter out the shared library case since we don't want
to include the static archives in dependencies again.

The test was marked XFAIL since 2010 because the fix for the
nested-archive bug was incomplete. Now that ltmain.in properly
forwards old library dependencies instead of archiving them,
the test passes: remove the AT_XFAIL_IF and correct the
foo.$OBJEXT assertion (objects from the dependency must NOT
appear in the target archive).

Absolute paths are forwarded as-is like above.
Relative paths are transformed into absolute using pwd.

The old deplibs are not appended if they have been linked
into a shared library output already.
---
 build-aux/ltmain.in         | 24 +++++++++++++++++++++---
 tests/archive-in-archive.at |  8 ++++----
 2 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/build-aux/ltmain.in b/build-aux/ltmain.in
index 70d0e111..a1d24dd2 100644
--- a/build-aux/ltmain.in
+++ b/build-aux/ltmain.in
@@ -5816,7 +5816,6 @@ func_mode_link ()
       *.$libext|*.so)
 	# An archive or an explicit shared library.
 	func_append deplibs " $arg"
-	func_append old_deplibs " $arg"
 	continue
 	;;
 
@@ -6215,6 +6214,8 @@ func_mode_link ()
 	  if test conv = "$pass"; then
 	    deplibs="$deplib $deplibs"
 	    continue
+	  else
+	    func_append old_deplibs " $deplib"
 	  fi
 	  case $linkmode in
 	  lib)
@@ -7184,7 +7185,6 @@ func_mode_link ()
       # Now set the variables for building old libraries.
       build_libtool_libs=no
       oldlibs=$output
-      func_append objs "$old_deplibs"
       ;;
 
     lib)
@@ -8952,7 +8952,11 @@ func_mode_link ()
 	  build_libtool_libs=no
           ;;
 	*)
-	  oldobjs="$old_deplibs $non_pic_objects"
+	  oldobjs="$non_pic_objects"
+	  # This is not correct to add old_deplibs creating an archive
+	  # so append them only when creating an executable or a shared
+	  # library.
+	  test yes != "$build_old_libs" && oldobjs="$oldobjs $old_deplibs"
 	  $preload && test -f "$symfileobj" \
 	    && func_append oldobjs " $symfileobj"
 	  addlibs=$old_convenience
@@ -9213,6 +9217,20 @@ func_mode_link ()
 	    done
 	    dlprefiles=$newdlprefiles
 	  fi
+
+	  # Forward old library dependencies only when no shared
+	  # library is being built. When building the shared library,
+	  # the linker uses $deplibs to link the archives into it, but
+	  # then we don't want to add it as transitive dependency.
+	  if test -z "$library_names"; then
+	    for lib in $old_deplibs; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append dependency_libs " $abs"
+	    done
+	  fi
 	  $RM $output
 	  # place dlname in correct position for cygwin
 	  # In fact, it would be nice if we could use this code for all target
diff --git a/tests/archive-in-archive.at b/tests/archive-in-archive.at
index d081f57d..b48579ae 100644
--- a/tests/archive-in-archive.at
+++ b/tests/archive-in-archive.at
@@ -24,9 +24,6 @@
 AT_SETUP([static library contains static library])
 AT_KEYWORDS([libtool])
 
-# This test passes with MS lib.
-AT_XFAIL_IF([case $AR in ar-lib\ * | *[[/\\]]ar-lib\ *) false;; *) :;; esac])
-
 AT_DATA([foo.c],
 [
 int foo() { return 1;}
@@ -51,7 +48,10 @@ AT_CHECK([$LIBTOOL --mode=link --tag=CC --tag=disable-shared $CC $CFLAGS $LDFLAG
 AT_CHECK([$LIBTOOL --mode=install cp libbar.la $thisdir], [], [ignore], [ignore])
 eval `$EGREP '^(old_library)=' < libbar.la`
 libbar=$old_library
+# The old library (libfoo.a) must NOT be nested inside libbar.a.
 AT_CHECK([$AR -t $libbar | $GREP $libfoo],[1],[ignore],[ignore])
-AT_CHECK([$AR -t $libbar | $GREP foo.$OBJEXT],[],[ignore],[ignore])
+# Objects from libfoo must NOT be extracted into libbar.a either.
+AT_CHECK([$AR -t $libbar | $GREP foo.$OBJEXT],[1],[ignore],[ignore])
+# bar's own object must still be present.
 AT_CHECK([$AR -t $libbar | $GREP bar.$OBJEXT],[],[ignore],[ignore])
 AT_CLEANUP
-- 
2.53.0

From 87159d043e4f74ab3c24de630682e17c03b1a91f Mon Sep 17 00:00:00 2001
From: Alexandre Janniaux <[email protected]>
Date: Tue, 28 Apr 2026 16:11:01 +0200
Subject: [PATCH 2/3] tests: extend archive-in-archive with dependency
 forwarding check

Verify that the old library dependency is recorded in
dependency_libs of the target .la file, and that an executable
linked against the target can resolve symbols from the forwarded
dependency.
---
 tests/archive-in-archive.at | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/tests/archive-in-archive.at b/tests/archive-in-archive.at
index b48579ae..f0e6ff1f 100644
--- a/tests/archive-in-archive.at
+++ b/tests/archive-in-archive.at
@@ -31,7 +31,14 @@ int foo() { return 1;}
 
 AT_DATA([bar.c],
 [
-int bar() { return 1;}
+extern int foo();
+int bar() { return foo();}
+])
+
+AT_DATA([main.c],
+[
+extern int bar();
+int main() { return !bar();}
 ])
 
 thisdir=`cd . && pwd`
@@ -54,4 +61,13 @@ AT_CHECK([$AR -t $libbar | $GREP $libfoo],[1],[ignore],[ignore])
 AT_CHECK([$AR -t $libbar | $GREP foo.$OBJEXT],[1],[ignore],[ignore])
 # bar's own object must still be present.
 AT_CHECK([$AR -t $libbar | $GREP bar.$OBJEXT],[],[ignore],[ignore])
+# libfoo must be forwarded in dependency_libs of libbar.la.
+AT_CHECK([$GREP 'dependency_libs=.*libfoo' libbar.la],[],[ignore],[ignore])
+# Link an executable against libbar.la; the forwarded dependency must
+# allow the linker to resolve foo().
+$CC $CPPFLAGS $CFLAGS -c -o main.$OBJEXT main.c
+AT_CHECK([$LIBTOOL --mode=link --tag=CC $CC $CFLAGS $LDFLAGS \
+	 -o main$EXEEXT main.$OBJEXT libbar.la],
+	 [], [ignore], [ignore])
+LT_AT_EXEC_CHECK([./main])
 AT_CLEANUP
-- 
2.53.0

From 7cb02827c73464916a3e60f8561dfb27457d7394 Mon Sep 17 00:00:00 2001
From: Alexandre Janniaux <[email protected]>
Date: Fri, 2 Apr 2021 13:14:41 +0200
Subject: [PATCH 3/3] ltmain.in: defer warn dependency to static library

When linking old library to any libtool target that is not an
executable, libtool warns that it might not be portable, in particular
because shared libraries need PIC from the static library to be working.

However, when adding an old library as dependency to a static libtool
library, there is no linkage, and thus no portability issue, so there's
no reason to warn. If the static libtool library is then linked to a
shared library, the dependency will be forwarded and the warning will
happen at this time.
---
 build-aux/ltmain.in | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/build-aux/ltmain.in b/build-aux/ltmain.in
index a1d24dd2..f64c0222 100644
--- a/build-aux/ltmain.in
+++ b/build-aux/ltmain.in
@@ -6246,7 +6246,9 @@ func_mode_link ()
 		;;
 	      esac
 	      if $valid_a_lib; then
-		func_warning "Linking the shared library $output against the static library $deplib is not portable!"
+		if test yes != "$build_old_libs"; then
+		  func_warning "Linking the shared library $output against the static library $deplib is not portable!"
+		fi
 		deplibs="$deplib $deplibs"
 	      else
 		func_warning "Trying to link with static lib archive $deplib."
-- 
2.53.0

Reply via email to