]> git.ipfire.org Git - thirdparty/libtool.git/commitdiff
ltmain.in: ensure old libraries are not archived
authorAlexandre Janniaux <ajanni@videolabs.io>
Tue, 6 Apr 2021 08:22:14 +0000 (10:22 +0200)
committerIleana Dumitrescu <ileanadumitrescu95@gmail.com>
Thu, 21 May 2026 18:07:24 +0000 (21:07 +0300)
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.

Reported: https://savannah.gnu.org/patch/?10569

build-aux/ltmain.in
tests/archive-in-archive.at

index 45e0668f3fd99e09c3869baec3feba9d17caa8ec..7947a3bf601a9314199d010030cba94967555666 100644 (file)
@@ -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)
@@ -8958,7 +8958,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
@@ -9219,6 +9223,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
index d081f57da6b35ca641a26853630621ae975080f6..b48579ae5b7463cf27b4c855b5aea0b8727236d1 100644 (file)
@@ -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