> 2019-02-23  Bruno Haible  <br...@clisp.org>
> 
>       relocatable-prog: Use wrapper-free installation also on Mac OS X.
>       Reported by Paul Smith <psm...@gnu.org>.
>       * build-aux/install-reloc: Accept a 'mode' argument as first argument.
>       (func_relativize): New function, from gnulib-tool.
>       Handle mode 'macosx' through invocations of 'otool' and
>       'install_name_tool'.
>       * m4/relocatable.m4 (gl_RELOCATABLE_BODY): Determine use_macos_tools.
>       If use_macos_tools is true, set INSTALL_PROGRAM_ENV to an
>       'install-reloc' invocation with mode 'macosx'.

This patch works for executables that reference shared libraries
in the same package. But it does not work for shared libraries that
reference other shared libraries in the same package. I'm therefore
reverting this patch and adding this one instead.


2019-03-04  Bruno Haible  <br...@clisp.org>

        relocatable-prog: Use wrapper-free installation on Mac OS X, take 2.
        This approach supports relocatable installation of shared libraries
        which depend on other shared libraries from the same package.
        * m4/relocatable.m4 (gl_RELOCATABLE_BODY): Determine use_macos_tools.
        If use_macos_tools is true, use reloc-ldflags and set LIBTOOL to be a
        wrapper around the original LIBTOOL.
        * build-aux/reloc-ldflags: Add support for Mac OS X, which uses the
        token '@loader_path' instead of '$ORIGIN'.
        * build-aux/libtool-reloc: New file.
        * modules/relocatable-prog (Files): Add it.
        * doc/relocatable-maint.texi (Supporting Relocation): Update to match
        the recent changes. Document the need to set the *_LDFLAGS of libraries.
        RELOCATABLE_LIBRARY_PATH and RELOCATABLE_CONFIG_H_DIR should be set in
        Makefile.am, not in configure.ac.

diff --git a/build-aux/libtool-reloc b/build-aux/libtool-reloc
new file mode 100755
index 0000000..9d899ab
--- /dev/null
+++ b/build-aux/libtool-reloc
@@ -0,0 +1,89 @@
+#!/bin/sh
+# libtool-reloc - libtool wrapper with support for relocatable programs
+# Copyright (C) 2019 Free Software Foundation, Inc.
+# Written by Bruno Haible <br...@clisp.org>, 2019.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+# Usage: libtool-reloc libtool LIBTOOL_ARGUMENTS
+
+# Outputs a command and runs it.
+func_verbose ()
+{
+  # Make it easy to copy&paste the printed command into a shell in most cases,
+  # by escaping '\\', '"', and '$'. This is not perfect, just good enough.
+  echo "$@" | sed -e 's/\([\\"$]\)/\\\1/g'
+  "$@"
+}
+
+# Determine the mode from the arguments.
+mode=
+for arg
+do
+  case "$arg" in
+    --mode=link) mode=link ;;
+  esac
+done
+
+if test "$mode" = link; then
+  # Determine the target from the arguments.
+  target=
+  next_is_target=false
+  for arg
+  do
+    if $next_is_target; then
+      target="$arg"
+      next_is_target=false
+    else
+      case "$arg" in
+        -o) next_is_target=true ;;
+        *) next_is_target=false ;;
+      esac
+    fi
+  done
+  case "$target" in
+    *.la)
+      # When creating a library:
+      # 1. Add a '-Wl,-rpath,@loader_path' option.
+      #    (A '-R @loader_path' option does not work: libtool produces
+      #    an error "error: only absolute run-paths are allowed".)
+      #    (Also note that 'install_name_tool -add_rpath @loader_path ...'
+      #    does not work on Mac OS X 10.5.)
+      #    This is done through the RELOCATABLE_LDFLAGS macro.
+      # 2. After creating the library, run
+      #    install_name_tool -id @rpath/$dlname $target_dir/.libs/$dlname
+      #    (This is easier than to modify the libtool script to emit a 
different
+      #    install_name. Also, an option '-Wl,-install_name,@rpath/$dlname' 
does
+      #    not work since libtool emits another option '-Wl,-install_name,...'
+      #    after it.
+      "$@" && {
+        dlname_assignment=`grep '^dlname=' "$target"`
+        dlname=
+        eval "$dlname_assignment"
+        # Nothing to do when --disable-shared was specified.
+        if test -n "$dlname"; then
+          target_dir=`dirname "$target"`
+          if test -f "$target_dir/.libs/$dlname"; then
+            func_verbose install_name_tool -id "@rpath/$dlname" 
"$target_dir/.libs/$dlname"
+          fi
+        fi
+      }
+      ;;
+    *)
+      "$@"
+      ;;
+  esac
+else
+  "$@"
+fi
diff --git a/build-aux/reloc-ldflags b/build-aux/reloc-ldflags
index 3aed330..625fef2 100755
--- a/build-aux/reloc-ldflags
+++ b/build-aux/reloc-ldflags
@@ -53,6 +53,7 @@ case "$installdir" in
     ;;
 esac
 
+origin_token=
 case "$host_os" in
   linux* | gnu* | kfreebsd* | \
   freebsd* | dragonfly* | \
@@ -60,54 +61,59 @@ case "$host_os" in
   openbsd* | \
   solaris* | \
   haiku*)
-    rpath=
-    save_IFS="$IFS"; IFS=":"
-    for dir in $library_path_value; do
-      IFS="$save_IFS"
-      case "$dir" in
-        /*)
-          # Make dir relative to installdir. (Works only if dir is absolute.)
-          idir="$installdir"
-          while true; do
-            dfirst=`echo "$dir" | sed -n -e 's,^//*\([^/]*\).*$,/\1,p'`
-            ifirst=`echo "$idir" | sed -n -e 's,^//*\([^/]*\).*$,/\1,p'`
-            if test -z "$dfirst" || test -z "$ifirst"; then
-              break
-            fi
-            if test "$dfirst" != "$ifirst"; then
-              break
-            fi
-            dir=`echo "$dir" | sed -e 's,^//*[^/]*,,'`
-            idir=`echo "$idir" | sed -e 's,^//*[^/]*,,'`
-          done
-          dir="\$ORIGIN"`echo "$idir" | sed -e 's,//*[^/]*,/..,g'`"$dir"
-          # Add dir to rpath.
-          rpath="${rpath}${rpath:+ }$dir"
-          ;;
-        *)
-          if test -n "$dir"; then
-            echo "libdir is not absolute: $dir" 1>&2
-          fi
-          ;;
-      esac
-    done
-    IFS="$save_IFS"
-    # Output it.
-    if test -n "$rpath"; then
-      case "$host_os" in
-        # At least some versions of FreeBSD, DragonFly, and OpenBSD need the
-        # linker option "-z origin". See <https://lekensteyn.nl/rpath.html>.
-        freebsd* | dragonfly* | openbsd*)
-          echo "-Wl,-z,origin -Wl,-rpath,$rpath" ;;
-        *)
-          echo "-Wl,-rpath,$rpath" ;;
-      esac
-    fi
+    origin_token='$ORIGIN'
     ;;
-  *)
-    echo "relocation via rpath not supported on this system: $host" 1>&2
-    exit 1
+  darwin*)
+    origin_token='@loader_path'
     ;;
 esac
+if test -n "$origin_token"; then
+  rpath=
+  save_IFS="$IFS"; IFS=":"
+  for dir in $library_path_value; do
+    IFS="$save_IFS"
+    case "$dir" in
+      /*)
+        # Make dir relative to installdir. (Works only if dir is absolute.)
+        idir="$installdir"
+        while true; do
+          dfirst=`echo "$dir" | sed -n -e 's,^//*\([^/]*\).*$,/\1,p'`
+          ifirst=`echo "$idir" | sed -n -e 's,^//*\([^/]*\).*$,/\1,p'`
+          if test -z "$dfirst" || test -z "$ifirst"; then
+            break
+          fi
+          if test "$dfirst" != "$ifirst"; then
+            break
+          fi
+          dir=`echo "$dir" | sed -e 's,^//*[^/]*,,'`
+          idir=`echo "$idir" | sed -e 's,^//*[^/]*,,'`
+        done
+        dir="$origin_token"`echo "$idir" | sed -e 's,//*[^/]*,/..,g'`"$dir"
+        # Add dir to rpath.
+        rpath="${rpath}${rpath:+ }$dir"
+        ;;
+      *)
+        if test -n "$dir"; then
+          echo "libdir is not absolute: $dir" 1>&2
+        fi
+        ;;
+    esac
+  done
+  IFS="$save_IFS"
+  # Output it.
+  if test -n "$rpath"; then
+    case "$host_os" in
+      # At least some versions of FreeBSD, DragonFly, and OpenBSD need the
+      # linker option "-z origin". See <https://lekensteyn.nl/rpath.html>.
+      freebsd* | dragonfly* | openbsd*)
+        echo "-Wl,-z,origin -Wl,-rpath,$rpath" ;;
+      *)
+        echo "-Wl,-rpath,$rpath" ;;
+    esac
+  fi
+else
+  echo "relocation via rpath not supported on this system: $host" 1>&2
+  exit 1
+fi
 
 exit 0
diff --git a/doc/relocatable-maint.texi b/doc/relocatable-maint.texi
index 200fcab..d391598 100644
--- a/doc/relocatable-maint.texi
+++ b/doc/relocatable-maint.texi
@@ -38,13 +38,8 @@ here in a platform-specific way:
 On most operating systems, it adds a linker option (@option{-rpath}) that
 causes the dynamic linker to search for libraries in a directory relative
 to the location of the invoked executable.  This works on GNU/Linux and
-modern versions of GNU/Hurd, GNU/kFreeBSD, FreeBSD, NetBSD, OpenBSD, Solaris,
-Haiku.
-
-@item
-On macOS, it modifies the installed executables after installation in a way
-that causes the dynamic linker to search for libraries in a directory relative
-to the location of the invoked executable.
+modern versions of GNU/Hurd, GNU/kFreeBSD, macOS, FreeBSD, NetBSD, OpenBSD,
+Solaris, Haiku.
 
 @item
 On other Unix systems, it installs a trampoline executable.  The trampoline
@@ -63,7 +58,10 @@ You can make your program relocatable by following these 
steps:
 @enumerate
 @item
 Import the @code{relocatable-prog} module.  For libraries, use the
-@code{relocatable-lib} or @code{relocatable-lib-lgpl} module.
+@code{relocatable-lib} or @code{relocatable-lib-lgpl} module, if
+the libraries are independent.  For installing multiple libraries,
+at least one of which depends on another one, use the @code{relocatable-prog}
+module.
 If you need more than one module, or you need to use them with different
 settings, you will need multiple copies of gnulib (@pxref{Multiple instances}).
 
@@ -233,20 +231,29 @@ AM_CONDITIONAL([SHLIBS_IN_BINDIR],
 @end smallexample
 
 @item
-You may also need to add a couple of variable assignments to your
-@file{configure.ac}.
+In your @file{Makefile.am}, for every library @command{libfoo} that gets
+installed in, say, @file{$(libdir)}, you add:
+
+@example
+if RELOCATABLE_VIA_LD
+libfoo_la_LDFLAGS = `$(RELOCATABLE_LDFLAGS) $(libdir)`
+endif
+@end example
+
+@item
+Add a couple of variable assignments to your @file{Makefile.am}.
 
 If your package (or any package you rely on, e.g.@: gettext-runtime)
 will be relocated together with a set of installed shared libraries,
-then set @var{RELOCATABLE_LIBRARY_PATH} to a colon-separated list
+then set @code{RELOCATABLE_LIBRARY_PATH} to a colon-separated list
 of those libraries' directories, e.g.
 @example
-RELOCATABLE_LIBRARY_PATH='$(libdir)'
+RELOCATABLE_LIBRARY_PATH = $(libdir)
 @end example
 
 If your @file{config.h} is not in @file{$(top_builddir)}, then set
-@var{RELOCATABLE_CONFIG_H_DIR} to its directory, e.g.
+@code{RELOCATABLE_CONFIG_H_DIR} to its directory, e.g.
 @example
-RELOCATABLE_CONFIG_H_DIR='$(top_builddir)/src'
+RELOCATABLE_CONFIG_H_DIR = $(top_builddir)/src
 @end example
 @end enumerate
diff --git a/m4/relocatable.m4 b/m4/relocatable.m4
index faa23f2..bbfb44c 100644
--- a/m4/relocatable.m4
+++ b/m4/relocatable.m4
@@ -1,4 +1,4 @@
-# relocatable.m4 serial 21
+# relocatable.m4 serial 23
 dnl Copyright (C) 2003, 2005-2007, 2009-2019 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -22,18 +22,28 @@ dnl The guts of gl_RELOCATABLE. Needs to be expanded only 
once.
 AC_DEFUN([gl_RELOCATABLE_BODY],
 [
   AC_REQUIRE([AC_PROG_INSTALL])
+
   dnl This AC_BEFORE invocation leads to unjustified autoconf warnings
   dnl when gl_RELOCATABLE_BODY is invoked more than once.
+  dnl
   dnl We need this AC_BEFORE because AC_PROG_INSTALL is documented to
   dnl overwrite earlier settings of INSTALL and INSTALL_PROGRAM (even
   dnl though in autoconf-2.52..2.60 it doesn't do so), but we want this
   dnl macro's setting of INSTALL_PROGRAM to persist.
-  AC_BEFORE([AC_PROG_INSTALL],[gl_RELOCATABLE_BODY])
+  dnl Arghh: AC_BEFORE does not work in this setting :-(
+  dnl AC_BEFORE([AC_PROG_INSTALL],[gl_RELOCATABLE_BODY])
+  dnl
+  dnl LT_INIT sets LIBTOOL, but we want this macro's setting of LIBTOOL to
+  dnl persist.
+  dnl Arghh: AC_BEFORE does not work in this setting :-(
+  dnl AC_BEFORE([LT_INIT],[gl_RELOCATABLE_BODY])
+
   AC_REQUIRE([AC_LIB_LIBPATH])
   AC_REQUIRE([gl_RELOCATABLE_LIBRARY_BODY])
   AC_REQUIRE([AC_CANONICAL_HOST])
   is_noop=no
   use_elf_origin_trick=no
+  use_macos_tools=no
   use_wrapper=no
   if test $RELOCATABLE = yes; then
     # --enable-relocatable implies --disable-rpath
@@ -74,13 +84,17 @@ changequote(,)dnl
       solaris*) use_elf_origin_trick=yes ;;
       # Haiku: yes.
       haiku*) use_elf_origin_trick=yes ;;
+      # On Mac OS X 10.4 or newer, use Mac OS X tools. See
+      # <https://wincent.com/wiki/@executable_path,_@load_path_and_@rpath>.
+      darwin | darwin[1-7].*) ;;
+      darwin*) use_macos_tools=yes ;;
 changequote([,])dnl
     esac
     if test $is_noop = yes; then
       RELOCATABLE_LDFLAGS=:
       AC_SUBST([RELOCATABLE_LDFLAGS])
     else
-      if test $use_elf_origin_trick = yes; then
+      if test $use_elf_origin_trick = yes || test $use_macos_tools = yes; then
         dnl Use the dynamic linker's support for relocatable programs.
         case "$ac_aux_dir" in
           /*) reloc_ldflags="$ac_aux_dir/reloc-ldflags" ;;
@@ -88,6 +102,13 @@ changequote([,])dnl
         esac
         RELOCATABLE_LDFLAGS="\"$reloc_ldflags\" \"\$(host)\" 
\"\$(RELOCATABLE_LIBRARY_PATH)\""
         AC_SUBST([RELOCATABLE_LDFLAGS])
+        if test $use_macos_tools = yes; then
+          dnl Use a libtool wrapper that uses Mac OS X tools.
+          case "$ac_aux_dir" in
+            /*) LIBTOOL="${CONFIG_SHELL-$SHELL} $ac_aux_dir/libtool-reloc 
$LIBTOOL" ;;
+            *) LIBTOOL="${CONFIG_SHELL-$SHELL} 
\$(top_builddir)/$ac_aux_dir/libtool-reloc $LIBTOOL" ;;
+          esac
+        fi
       else
         use_wrapper=yes
         dnl Unfortunately we cannot define INSTALL_PROGRAM to a command
@@ -104,7 +125,7 @@ changequote([,])dnl
     fi
   fi
   AM_CONDITIONAL([RELOCATABLE_VIA_LD],
-    [test $is_noop = yes || test $use_elf_origin_trick = yes])
+    [test $is_noop = yes || test $use_elf_origin_trick = yes || test 
$use_macos_tools = yes])
   AM_CONDITIONAL([RELOCATABLE_VIA_WRAPPER], [test $use_wrapper = yes])
 
   dnl RELOCATABLE_LIBRARY_PATH can be set in configure.ac. Default is empty.
diff --git a/modules/relocatable-prog b/modules/relocatable-prog
index d984314..4111665 100644
--- a/modules/relocatable-prog
+++ b/modules/relocatable-prog
@@ -5,6 +5,7 @@ properly when copied to an arbitrary directory.
 Files:
 build-aux/config.libpath
 build-aux/reloc-ldflags
+build-aux/libtool-reloc
 doc/relocatable.texi
 lib/relocatable.h
 lib/relocatable.c


Reply via email to