[PATCH] AIX: Optional filename-based shlib versioning

Michael Haubenwallner <[email protected]>
Newsgroups gmane.comp.gnu.libtool.patches
Message-ID <1416834550-3428-1-git-send-email-michael.haubenwallner@ssi-schaefer.com>
Support filename-based shared library versioning on AIX with the lib.so
library filename extension, which is used with runtime linking only.
Runtime linking is enabled by the -brtl linker flag for executables and
the -G linker flag for Shared Objects. The behaviour is similar to
Linux/SVR4 DT_SONAME, hence the name "aix-soname=svr4".

(--with-aix-soname=aix): Default, the current situation.
  (lib.a): When the -brtl linker flag is found in LDFLAGS, create from
    static objects only. Otherways, create as traditional shared library
    archive from the Shared Object built without runtime linking, with
    in-archive versioning.
  (lib.so): When the -brtl linker flag is found in LDFLAGS, create as
    the standalone Shared Object built with the -G linker flag, without
    any versioning support. Otherways, do not create it at all.
  (executables): When the -brtl linker flag is found in LDFLAGS, prefer
    to link against libraries with the .so filename extension.
    Otherways, link against libraries with the .a filename extension.
  (module): When the -brtl linker flag is found in LDFLAGS, same as for
    lib.so.  Otherways, same as for lib.a.

(--with-aix-soname=svr4): Filename-based shared library versioning.
  (lib.a): Create from static objects.
  (lib.so): Create as shared library archive from the Shared Object
    named shr.o or shr_64.o, built with the -G linker flag, and the
    F_LOADONLY flag set, plus an Import File named shr.imp or
    shr_64.imp, respectively, necessary to allow for filename-based
    versioning.
  (executables): Add the -brtl linker flag to LDFLAGS, to prefer linking
    against shared libraries with the .so filename extension.
  (module): Same as for lib.so.

(--with-aix-soname=both): One shared library is created with the
filename-based, another one with the in-archive versioning scheme for
backwards compatibility. The library_names value in the .la file
specifies either the one or the other, depending on whether the -brtl
linker flag is specified in LDFLAGS.
  (lib.a): Create as traditional shared library archive from the Shared
    Object built without runtime linking, with in-archive versioning.
  (lib.so): Create as shared library archive from the Shared Object
    named shr.o or shr_64.o, built with the -G linker flag, and the
    F_LOADONLY flag set, plus an Import File named shr.imp or
    shr_64.imp, respectively, necessary to allow for filename-based
    versioning.
  (executables): When the -brtl linker flag is found in LDFLAGS, prefer
    to link against libraries with the .so filename extension.
    Otherways, link against libraries with the .a filename extension.
  (module): Same as for both lib.a and lib.so.

* Makefile.am: (TESTS_ENVIRONMENT) Pass with_aix_soname value via
lt_cv_with_aix_soname into testsuite.

* configure.ac: AC_SUBST with_aix_soname.

* libltdl/loaders/dlopen.c: (vm_open) Use RTLD_MEMBER flag for dlopen
when the filename does specify an archive member between "()".
Otherways, retry with appending LT_SHARED_LIB_MEMBER when loading fails
without but archive file seems to exist.

* m4/libtool.m4: (dynamic_linker) Describe configured shared library
versioning variant according to with_aix_soname and runtime linking.
(soname_spec, library_names_spec, shlibpath_overrides_runpath,
postinstall_cmds, postuninstall_cmds, hardcode_direct,
hardcode_direct_absolute, no_undefined_flag, allow_undefined_flag) Set
according to with_aix_soname and runtime linking configuration.
(export_symbols_cmds) Decorate symbols with the weak keyword.
(archive_expsym_cmds) Create both shared libraries according to
with_aix_soname and runtime linking configuration. Filter -brtl linker
flag from compiler_flags for shared libraries due to its side effects.
(enable_static) Respect with_aix_soname for disabling as well.

* m4/ltdl.m4: (LT_SHARED_LIB_MEMBER) Define, set based on the value of
the shared_archive_member_spec libtool variable.

* m4/ltoptions.m4: (_LT_WITH_AIX_SONAME) New. Provides commandline
option --with-aix-soname=aix|svr4|both. Declares
(shared_archive_member_spec) as libtool variable.
(_LT_SET_OPTIONS) Define LT_INIT options "aix-soname=aix",
"aix-soname=svr4", "aix-soname=both". Default is "aix-soname=aix".

* tests/deplibs-ident.at: To define whether this test should XFAIL, use
hardcode_action, hardcode_direct, hardcode_direct_absolute configuration
settings instead of platforms aix, bitrig, hppa-hpux, interix or openbsd.

* tests/versioning.at: When shared_archive_member_spec is defined and
LDFLAGS contain -brtl, we can run the versioning check.
---
 Makefile.am              |   1 +
 configure.ac             |   1 +
 libltdl/loaders/dlopen.c |  40 +++++++++
 m4/libtool.m4            | 221 ++++++++++++++++++++++++++++++++++++++++-------
 m4/ltdl.m4               |   5 ++
 m4/ltoptions.m4          |  50 +++++++++++
 tests/deplibs-ident.at   |  11 ++-
 tests/versioning.at      |  14 ++-
 8 files changed, 306 insertions(+), 37 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 38f2dbd..60a067e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -740,6 +740,7 @@ TESTS_ENVIRONMENT = MAKE="$(MAKE)" CC="$(CC)" CFLAGS="$(CFLAGS)" \
 	F77="$(F77)" FFLAGS="$(FFLAGS)" \
 	FC="$(FC)" FCFLAGS="$(FCFLAGS)" \
 	GCJ="$(GCJ)" GCJFLAGS="$(GCJFLAGS)" \
+	lt_cv_with_aix_soname="$(with_aix_soname)" \
 	lt_cv_to_host_file_cmd="$(to_host_file_cmd)" \
 	lt_cv_to_tool_file_cmd="$(to_tool_file_cmd)"
 
diff --git a/configure.ac b/configure.ac
index c4dbe9f..dc777ca 100644
--- a/configure.ac
+++ b/configure.ac
@@ -156,6 +156,7 @@ LT_LANG(Windows Resource)
 
 # Ensure the correct file name (and path) conversion function
 # is available to the test suite.
+AC_SUBST([with_aix_soname])dnl
 AC_SUBST([to_host_file_cmd])dnl
 AC_SUBST([to_tool_file_cmd])dnl
 
diff --git a/libltdl/loaders/dlopen.c b/libltdl/loaders/dlopen.c
index 758d7f4..b79df3e 100644
--- a/libltdl/loaders/dlopen.c
+++ b/libltdl/loaders/dlopen.c
@@ -168,6 +168,9 @@ vm_open (lt_user_data LT__UNUSED loader_data, const char *filename,
 {
   int		module_flags = LT_LAZY_OR_NOW;
   lt_module	module;
+#ifdef RTLD_MEMBER
+  int		len = LT_STRLEN (filename);
+#endif
 
   if (advise)
     {
@@ -191,8 +194,45 @@ vm_open (lt_user_data LT__UNUSED loader_data, const char *filename,
 #endif
     }
 
+#ifdef RTLD_MEMBER /* AIX */
+  if (len >= 4) /* at least "l(m)" */
+    {
+      /* Advise loading an archive member only if the filename really
+	 contains both the opening and closing parent, and a member. */
+      if (filename[len-1] == ')')
+	{
+	  const char *opening = strrchr(filename, '(');
+	  if (opening && opening < (filename+len-2) && strchr(opening+1, '/') == NULL)
+	    module_flags |= RTLD_MEMBER;
+	}
+    }
+#endif
+
   module = dlopen (filename, module_flags);
 
+#if defined RTLD_MEMBER && defined LT_SHARED_LIB_MEMBER
+  if (!module && len && !(module_flags & RTLD_MEMBER) && errno == ENOEXEC)
+    {
+      /* Loading without a member specified failed with "Exec format error".
+	 So the file is there, but either has wrong bitwidth, or is an
+	 archive eventually containing the default shared archive member.
+	 Retry with default member, getting same error in worst case. */
+      const char *member = LT_SHARED_LIB_MEMBER;
+
+      char *attempt = MALLOC (char, len + strlen (member) + 1);
+      if (!attempt)
+	{
+	  LT__SETERROR (NO_MEMORY);
+	  return module;
+	}
+
+      sprintf (attempt, "%s%s", filename, member);
+      module = vm_open (loader_data, attempt, advise);
+      FREE (attempt);
+      return module;
+    }
+#endif
+
   if (!module)
     {
       DL__SETERROR (CANNOT_OPEN);
diff --git a/m4/libtool.m4 b/m4/libtool.m4
index 6143541..c50201c 100644
--- a/m4/libtool.m4
+++ b/m4/libtool.m4
@@ -2342,20 +2342,70 @@ aix[[4-9]]*)
       fi
       ;;
     esac
+    # Using Import Files as archive members, it is possible to support
+    # filename-based versioning of shared library archives on AIX. While
+    # this would work for both with and without runtime linking, it will
+    # prevent static linking of such archives. So we do filename-based
+    # shared library versioning with .so extension only, which is used
+    # when both runtime linking and shared linking is enabled.
+    # Unfortunately, runtime linking may impact performance, so we do
+    # not want this to be the default eventually. Also, we use the
+    # versioned .so libs for executables only if there is the -brtl
+    # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+    # To allow for filename-based versioning support, we need to create
+    # libNAME.so.V as an archive file, containing:
+    # *) an Import File, referring to the versioned filename of the
+    #    archive as well as the shared archive member, telling the
+    #    bitwidth (32 or 64) of that shared object, and providing the
+    #    list of exported symbols of that shared object, eventually
+    #    decorated with the 'weak' keyword
+    # *) the shared object with the F_LOADONLY flag set, to really avoid
+    #    it being seen by the linker.
+    # At run time we better use the real file rather than another symlink,
+    # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+    case $with_aix_soname:$aix_use_runtimelinking in
     # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
     # soname into executable. Probably we can add versioning support to
     # collect2, so additional links can be useful in future.
-    if test yes = "$aix_use_runtimelinking"; then
+    aix:yes) # traditional libtool
+      dynamic_linker='AIX unversionable lib.so'
       # If using run time linking (on AIX 4.2 or later) use lib<name>.so
       # instead of lib<name>.a to let people know that these are not
       # typical AIX shared libraries.
       library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-    else
+      ;;
+    aix:no) # traditional AIX only
+      dynamic_linker='AIX lib.a[(]lib.so.V[)]'
       # We preserve .a as extension for shared libraries through AIX4.2
       # and later when we are not doing run time linking.
       library_names_spec='$libname$release.a $libname.a'
       soname_spec='$libname$release$shared_ext$major'
-    fi
+      ;;
+    svr4:*) # full svr4 only
+      dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *:yes) # both, prefer svr4
+      dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # unpreferred sharedlib libNAME.a needs extra handling
+      postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+      postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *:no) # both, prefer aix
+      dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]"
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+      postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+      postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+      ;;
+    esac
     shlibpath_var=LIBPATH
   fi
   ;;
@@ -4764,13 +4814,17 @@ m4_if([$1], [CXX], [
   case $host_os in
   aix[[4-9]]*)
     # If we're using GNU nm, then we don't want the "-C" option.
-    # -C means demangle to AIX nm, but means don't demangle with GNU nm
-    # Also, AIX nm treats weak defined symbols like other global defined
-    # symbols, whereas GNU nm marks them as "W".
+    # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+    # Without the "-l" option, or with the "-B" option, AIX nm treats
+    # weak defined symbols like other global defined symbols, whereas
+    # GNU nm marks them as "W".
+    # While the 'weak' keyword is ignored in the Export File, we need
+    # it in the Import File for the 'aix-soname' feature, so we have
+    # to replace the "-B" option with "-P" for AIX nm.
     if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
     else
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+      _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
     fi
     ;;
   pw32*)
@@ -5214,19 +5268,35 @@ _LT_EOF
 	no_entry_flag=
       else
 	# If we're using GNU nm, then we don't want the "-C" option.
-	# -C means demangle to AIX nm, but means don't demangle with GNU nm
-	# Also, AIX nm treats weak defined symbols like other global
-	# defined symbols, whereas GNU nm marks them as "W".
+	# -C means demangle to GNU nm, but means don't demangle to AIX nm.
+	# Without the "-l" option, or with the "-B" option, AIX nm treats
+	# weak defined symbols like other global defined symbols, whereas
+	# GNU nm marks them as "W".
+	# While the 'weak' keyword is ignored in the Export File, we need
+	# it in the Import File for the 'aix-soname' feature, so we have
+	# to replace the "-B" option with "-P" for AIX nm.
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
 	else
-	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
 	# Test if we are trying to use run time linking or normal
 	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
-	# need to do runtime linking.
+	# have runtime linking enabled, and use it for executables.
+	# For shared libraries, we enable/disable runtime linking
+	# depending on the kind of the shared library created -
+	# when "with_aix_soname:aix_use_runtimelinking" is:
+	# "aix:no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "aix:yes"  lib.so          shared, rtl:yes, for executables
+	#            lib.a           static archive
+	# "both:no"  lib.so.V(shr.o) shared, rtl:yes
+	#            lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "both:yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a(lib.so.V) shared, rtl:no
+	# "svr4:*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a           static archive
 	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
 	  for ld_flag in $LDFLAGS; do
 	  if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
@@ -5234,6 +5304,13 @@ _LT_EOF
 	    break
 	  fi
 	  done
+	  if test svr4:no = "$with_aix_soname:$aix_use_runtimelinking"; then
+	    # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	    # so we don't have lib.a shared libs to link our executables.
+	    # We have to force runtime linking in this case.
+	    aix_use_runtimelinking=yes
+	    LDFLAGS="$LDFLAGS -Wl,-brtl"
+	  fi
 	  ;;
 	esac
 
@@ -5253,6 +5330,14 @@ _LT_EOF
       _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
       _LT_TAGVAR(link_all_deplibs, $1)=yes
       _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+      case $with_aix_soname:$aix_use_runtimelinking in
+      aix:*) ;; # traditional, no import file
+      svr4:* | *:yes) # use import file
+	# The Import File defines what to hardcode.
+	_LT_TAGVAR(hardcode_direct, $1)=no
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+	;;
+      esac
 
       if test yes = "$GCC"; then
 	case $host_os in aix4.[[012]]|aix4.[[012]].*)
@@ -5280,6 +5365,11 @@ _LT_EOF
 	if test yes = "$aix_use_runtimelinking"; then
 	  shared_flag="$shared_flag "'$wl-G'
 	fi
+	# Need to ensure runtime linking is disabled for the traditional
+	# shared library, or the linker may eventually find shared libraries
+	# /with/ Import File - we do not want to mix them.
+	shared_flag_aix='-shared'
+	shared_flag_svr4='-shared $wl-G'
       else
 	# not using gcc
 	if test ia64 = "$host_cpu"; then
@@ -5292,6 +5382,8 @@ _LT_EOF
 	  else
 	    shared_flag='$wl-bM:SRE'
 	  fi
+	  shared_flag_aix='$wl-bM:SRE'
+	  shared_flag_svr4='$wl-G'
 	fi
       fi
 
@@ -5299,7 +5391,7 @@ _LT_EOF
       # It seems that -bexpall does not export symbols beginning with
       # underscore (_), so it is better to generate a list of symbols to export.
       _LT_TAGVAR(always_export_symbols, $1)=yes
-      if test yes = "$aix_use_runtimelinking"; then
+      if test aix:yes = "$with_aix_soname:$aix_use_runtimelinking"; then
 	# Warning - without using the other runtime loading flags (-brtl),
 	# -berok will link without error, but may produce a broken library.
 	_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
@@ -5330,8 +5422,20 @@ _LT_EOF
 	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
 	  fi
 	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-	  # This is similar to how AIX traditionally builds its shared libraries.
-	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $wl-bnoentry $compiler_flags $wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	  # -brtl affects multiple linker settings, -berok does not and is overridden later
+	  compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+	  if test svr4 != "$with_aix_soname"; then
+	    # This is similar to how AIX traditionally builds its shared libraries.
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	  fi
+	  if test aix != "$with_aix_soname"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	  else
+	    # used by -dlpreopen to get the symbols
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	  fi
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
 	fi
       fi
       ;;
@@ -6056,8 +6160,12 @@ if test -n "$compiler"; then
     ;;
 
   aix[[4-9]]*)
-    if test ia64 != "$host_cpu" && test no = "$aix_use_runtimelinking"; then
-      test yes = "$enable_shared" && enable_static=no
+    if test ia64 != "$host_cpu"; then
+      case $enable_shared:$with_aix_soname:$aix_use_runtimelinking in
+      yes:aix:yes) ;; # shared object as lib.so file only
+      yes:svr4:*) ;; # shared object as lib.so archive member only
+      yes:*:*) enable_static=no ;; # shared object in lib.a archive as well
+      esac
     fi
     ;;
   esac
@@ -6245,7 +6353,19 @@ if test yes != "$_lt_caught_CXX_error"; then
 
           # Test if we are trying to use run time linking or normal
           # AIX style linking. If -brtl is somewhere in LDFLAGS, we
-          # need to do runtime linking.
+          # have runtime linking enabled, and use it for executables.
+          # For shared libraries, we enable/disable runtime linking
+          # depending on the kind of the shared library created -
+          # when "with_aix_soname:aix_use_runtimelinking" is:
+          # "aix:no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "aix:yes"  lib.so          shared, rtl:yes, for executables
+          #            lib.a           static archive
+          # "both:no"  lib.so.V(shr.o) shared, rtl:yes
+          #            lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "both:yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a(lib.so.V) shared, rtl:no
+          # "svr4:*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a           static archive
           case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
 	    for ld_flag in $LDFLAGS; do
 	      case $ld_flag in
@@ -6255,6 +6375,13 @@ if test yes != "$_lt_caught_CXX_error"; then
 	        ;;
 	      esac
 	    done
+	    if test svr4:no = "$with_aix_soname:$aix_use_runtimelinking"; then
+	      # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	      # so we don't have lib.a shared libs to link our executables.
+	      # We have to force runtime linking in this case.
+	      aix_use_runtimelinking=yes
+	      LDFLAGS="$LDFLAGS -Wl,-brtl"
+	    fi
 	    ;;
           esac
 
@@ -6274,6 +6401,14 @@ if test yes != "$_lt_caught_CXX_error"; then
         _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
         _LT_TAGVAR(link_all_deplibs, $1)=yes
         _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+        case $with_aix_soname:$aix_use_runtimelinking in
+        aix:*) ;; # no import file
+        svr4:* | *:yes) # use import file
+          # The Import File defines what to hardcode.
+          _LT_TAGVAR(hardcode_direct, $1)=no
+          _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+          ;;
+        esac
 
         if test yes = "$GXX"; then
           case $host_os in aix4.[[012]]|aix4.[[012]].*)
@@ -6300,6 +6435,11 @@ if test yes != "$_lt_caught_CXX_error"; then
 	  if test yes = "$aix_use_runtimelinking"; then
 	    shared_flag=$shared_flag' $wl-G'
 	  fi
+	  # Need to ensure runtime linking is disabled for the traditional
+	  # shared library, or the linker may eventually find shared libraries
+	  # /with/ Import File - we do not want to mix them.
+	  shared_flag_aix='-shared'
+	  shared_flag_svr4='-shared $wl-G'
         else
           # not using gcc
           if test ia64 = "$host_cpu"; then
@@ -6312,6 +6452,8 @@ if test yes != "$_lt_caught_CXX_error"; then
 	    else
 	      shared_flag='$wl-bM:SRE'
 	    fi
+	    shared_flag_aix='$wl-bM:SRE'
+	    shared_flag_svr4='$wl-G'
           fi
         fi
 
@@ -6320,10 +6462,11 @@ if test yes != "$_lt_caught_CXX_error"; then
         # underscore (_), so it is better to generate a list of symbols to
 	# export.
         _LT_TAGVAR(always_export_symbols, $1)=yes
-        if test yes = "$aix_use_runtimelinking"; then
+	if test aix:yes = "$with_aix_soname:$aix_use_runtimelinking"; then
           # Warning - without using the other runtime loading flags (-brtl),
           # -berok will link without error, but may produce a broken library.
-          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+          # The "-G" linker flag allows undefined symbols.
+          _LT_TAGVAR(no_undefined_flag, $1)='-bernotok'
           # Determine the default libpath from the value encoded in an empty
           # executable.
           _LT_SYS_MODULE_PATH_AIX([$1])
@@ -6352,9 +6495,21 @@ if test yes != "$_lt_caught_CXX_error"; then
 	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
 	    fi
 	    _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-	    # This is similar to how AIX traditionally builds its shared
-	    # libraries.
-	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $wl-bnoentry $compiler_flags $wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	    # -brtl affects multiple linker settings, -berok does not and is overridden later
+	    compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+	    if test svr4 != "$with_aix_soname"; then
+	      # This is similar to how AIX traditionally builds its shared
+	      # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
+	      _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	    fi
+	    if test aix != "$with_aix_soname"; then
+	      _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	    else
+	      # used by -dlpreopen to get the symbols
+	      _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	    fi
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
           fi
         fi
         ;;
@@ -7535,8 +7690,12 @@ if test yes != "$_lt_disable_F77"; then
         fi
         ;;
       aix[[4-9]]*)
-	if test ia64 != "$host_cpu" && test no = "$aix_use_runtimelinking"; then
-	  test yes = "$enable_shared" && enable_static=no
+	if test ia64 != "$host_cpu"; then
+	  case $enable_shared:$with_aix_soname:$aix_use_runtimelinking in
+	  yes:aix:yes) ;; # shared object as lib.so file only
+	  yes:svr4:*) ;; # shared object as lib.so archive member only
+	  yes:*:*) enable_static=no ;; # shared object in lib.a archive as well
+	  esac
 	fi
         ;;
     esac
@@ -7669,8 +7828,12 @@ if test yes != "$_lt_disable_FC"; then
         fi
         ;;
       aix[[4-9]]*)
-	if test ia64 != "$host_cpu" && test no = "$aix_use_runtimelinking"; then
-	  test yes = "$enable_shared" && enable_static=no
+	if test ia64 != "$host_cpu"; then
+	  case $enable_shared:$with_aix_soname:$aix_use_runtimelinking in
+	  yes:aix:yes) ;; # shared object as lib.so file only
+	  yes:svr4:*) ;; # shared object as lib.so archive member only
+	  yes:*:*) enable_static=no ;; # shared object in lib.a archive as well
+	  esac
 	fi
         ;;
     esac
diff --git a/m4/ltdl.m4 b/m4/ltdl.m4
index eeb37ac..59505fc 100644
--- a/m4/ltdl.m4
+++ b/m4/ltdl.m4
@@ -569,6 +569,11 @@ if test "$libltdl_cv_shrext" != "$libltdl_cv_shlibext"; then
   AC_DEFINE_UNQUOTED([LT_SHARED_EXT], ["$libltdl_cv_shrext"],
     [Define to the shared library suffix, say, ".dylib".])
 fi
+if test -n "$shared_archive_member_spec"; then
+  m4_pattern_allow([LT_SHARED_LIB_MEMBER])dnl
+  AC_DEFINE_UNQUOTED([LT_SHARED_LIB_MEMBER], ["($shared_archive_member_spec.o)"],
+    [Define to the shared archive member specification, say "(shr.o)".])
+fi
 ])# LT_SYS_MODULE_EXT
 
 # Old name:
diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4
index de6520e..061c1f6 100644
--- a/m4/ltoptions.m4
+++ b/m4/ltoptions.m4
@@ -82,6 +82,8 @@ m4_if([$1],[LT_INIT],[
   _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
   _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
 		   [_LT_ENABLE_FAST_INSTALL])
+  _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
+		   [_LT_WITH_AIX_SONAME([aix])])
   ])
 ])# _LT_SET_OPTIONS
 
@@ -319,6 +321,54 @@ dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
 dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
 
 
+# _LT_WITH_AIX_SONAME([DEFAULT])
+# ----------------------------------
+# implement the --with-aix-soname flag, and support the `aix-soname=aix'
+# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
+# is either `aix', `both' or `svr4'.  If omitted, it defaults to `aix'.
+m4_define([_LT_WITH_AIX_SONAME],
+[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
+shared_archive_member_spec=
+case $host:$enable_shared in
+(power*-*-aix[[5-9]]*:yes)
+  AC_MSG_CHECKING([which variant of shared library versioning to provide])
+  AC_ARG_WITH([aix-soname],
+    [AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
+      [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
+    [case $withval in
+     (aix|svr4|both) ;;
+     (*) AC_MSG_ERROR([Unknown argument to --with-aix-soname]);;
+     esac
+     lt_cv_with_aix_soname=$with_aix_soname],
+    [AC_CACHE_VAL([lt_cv_with_aix_soname],
+      [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
+     with_aix_soname=$lt_cv_with_aix_soname])
+  AC_MSG_RESULT([$with_aix_soname])
+  if test aix != "$with_aix_soname"; then
+    # For the AIX way of multilib, we name the shared archive member
+    # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+    # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+    # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+    # the AIX toolchain works better with OBJECT_MODE set (default 32).
+    if test 64 = "${OBJECT_MODE-32}"; then
+      shared_archive_member_spec=shr_64
+    else
+      shared_archive_member_spec=shr
+    fi
+  fi
+  ;;
+(*) with_aix_soname=aix ;;
+esac
+
+_LT_DECL([], [shared_archive_member_spec], [0],
+    [Shared archive member basename, for filename based shared library versioning on AIX])dnl
+])# _LT_WITH_AIX_SONAME
+
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
+
+
 # _LT_WITH_PIC([MODE])
 # --------------------
 # implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
diff --git a/tests/deplibs-ident.at b/tests/deplibs-ident.at
index 9c5e823..7b0f9bd 100644
--- a/tests/deplibs-ident.at
+++ b/tests/deplibs-ident.at
@@ -67,10 +67,13 @@ int main() { return a1() + a2() + a3() + c(); }
   AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS $LDFLAGS -o b$EXEEXT b.$OBJEXT ../liba1.la ../liba2.la ../liba3.la ../../c/libcee.la -rpath /nowhere],
 	   [0],[stdout],[ignore])
   AT_CHECK([$EGREP 'cee.*cee' stdout], 1, [ignore], [ignore])
-  AT_XFAIL_IF([case $host in
-                 *-*-aix*|*-*-bitrig*|hppa*-*-hpux*|*-*-interix*|*-*-openbsd*) false;;
-                 *):;;
-               esac])
+  AT_XFAIL_IF([dnl
+    eval `$LIBTOOL --config | $EGREP '^hardcode_(direct|direct_absolute|action)='`
+    case $hardcode_action:$hardcode_direct:$hardcode_direct_absolute in
+      relink:yes:no) :;;
+      *:no:*) :;;
+      *:*:*) false;;
+    esac])
   dnl This is currently broken in libtool
 )
 
diff --git a/tests/versioning.at b/tests/versioning.at
index dac032c..4b7eb7b 100644
--- a/tests/versioning.at
+++ b/tests/versioning.at
@@ -24,7 +24,7 @@
 AT_SETUP([versioning])
 AT_KEYWORDS([libtool])
 
-eval "`$LIBTOOL --config | $EGREP '^(objdir|host_os)='`"
+eval "`$LIBTOOL --config | $EGREP '^(objdir|host_os|shared_archive_member_spec)='`"
 
 # Setup some library and program sources:
 # a library (a1), a new revision (a2), a compatible update (a3),
@@ -228,9 +228,15 @@ AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS $LDFLAGS -o liba.la liba4.lo ]dnl
 AT_CHECK([$LIBTOOL --mode=install cp liba.la $libdir], [], [ignore], [ignore])
 AT_CHECK([$LIBTOOL --mode=clean rm -f liba.la], [], [ignore], [ignore])
 
-# This test does not work on AIX, not even with runtimelinking, because
-# the linker always records the unversioned name as dependency.
-AT_CHECK([:; case $host_os in aix*) exit 77;; esac])
+# This test does work on AIX when the 'aix-soname' feature is enabled and active
+# only, which is reflected in shared_archive_member_spec being set and LDFLAGS
+# containing -brtl. Otherways, even with runtimelinking, the linker always
+# records the unversioned name as dependency.
+AT_CHECK([:; case $host_os^$shared_archive_member_spec^$LDFLAGS in
+aix*^^*) exit 77;;
+aix*^*^*-brtl*) ;;
+aix*^*^*) exit 77 ;;
+esac])
 
 test_installed
 
-- 
1.8.5.5
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.