# HG changeset patch # User Bruno Haible # Date 1550958174 -3600 # Node ID 5fd32d1281294c6c2ca456431e7969e7aab3e239 # Parent cd38408f509acaba7fc7358fa8d4b034fa1e47a2 relocatable-prog: Use wrapper-free installation also on Mac OS X. Reported by Paul Smith . * 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'. diff -r cd38408f509a -r 5fd32d128129 ChangeLog --- a/ChangeLog Sat Feb 23 21:24:14 2019 +0100 +++ b/ChangeLog Sat Feb 23 22:42:54 2019 +0100 @@ -1,3 +1,15 @@ +2019-02-23 Bruno Haible + + relocatable-prog: Use wrapper-free installation also on Mac OS X. + Reported by Paul Smith . + * 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'. + 2019-02-23 Bruno Haible relocatable-prog: Use $ORIGIN trick also on GNU/Hurd. diff -r cd38408f509a -r 5fd32d128129 build-aux/install-reloc --- a/build-aux/install-reloc Sat Feb 23 21:24:14 2019 +0100 +++ b/build-aux/install-reloc Sat Feb 23 22:42:54 2019 +0100 @@ -1,5 +1,8 @@ #!/bin/sh -# install-reloc - install a program including a relocating wrapper +# install-reloc - install a program in a way that it will find its shared +# libraries even when relocated, +# - either including a relocating wrapper, +# - or using Mac OS X specific tools. # Copyright (C) 2003-2019 Free Software Foundation, Inc. # Written by Bruno Haible , 2003. # @@ -17,10 +20,15 @@ # along with this program. If not, see . # Usage 1: -# install-reloc -- library_path_var library_path_value prefix destdir \ +# install-reloc -- 'wrapper' \ +# library_path_var library_path_value prefix destdir \ # compile_command srcdir builddir config_h_dir exeext \ # strip_command \ # install_command... destprog +# install-reloc -- 'macosx' \ +# prefix destdir \ +# strip_command \ +# install_command... destprog # where # - library_path_var is the platform dependent runtime library path variable # - library_path_value is a colon separated list of directories that contain @@ -40,7 +48,8 @@ # - install_command is the install command line, excluding the final destprog # - destprog is the destination program name # Usage 2: -# env RELOC_LIBRARY_PATH_VAR=library_path_var \ +# env RELOC_MODE='wrapper' \ +# RELOC_LIBRARY_PATH_VAR=library_path_var \ # RELOC_LIBRARY_PATH_VALUE=library_path_value \ # RELOC_PREFIX=prefix \ # RELOC_DESTDIR=destdir \ @@ -51,59 +60,120 @@ # RELOC_EXEEXT=exeext \ # RELOC_STRIP_PROG=strip_command \ # RELOC_INSTALL_PROG=install_command... \ -# install-reloc prog1 ... destprog +# install-reloc prog1 ... destprog +# env RELOC_MODE='macosx' \ +# RELOC_PREFIX=prefix \ +# RELOC_DESTDIR=destdir \ +# RELOC_STRIP_PROG=strip_command \ +# RELOC_INSTALL_PROG=install_command... \ +# install-reloc prog1 ... destprog # where destprog is either the destination program name (when only one program # is specified) or the destination directory for all programs. -# install-reloc renames destprog to destprog.bin and installs a relocating -# wrapper in the place of destprog. +# In the 'wrapper' mode, install-reloc renames destprog to destprog.bin and +# installs a relocating wrapper in the place of destprog. progname=$0 -if test $# -ge 12 && test "x$1" = "x--"; then +func_usage () +{ + echo "Usage: $0 -- 'wrapper'" \ + "library_path_var library_path_value prefix destdir" \ + "compile_command srcdir builddir config_h_dir exeext" \ + "strip_command" \ + "install_command... destprog" + echo "Usage: $0 -- 'macosx'" \ + "prefix destdir" \ + "strip_command" \ + "install_command... destprog" +} + +if test "x$1" = "x--"; then # Get fixed position arguments. - shift - library_path_var=$1 - library_path_value=$2 - prefix=$3 - destdir=$4 - shift - shift - shift - shift - compile_command=$1 - srcdir=$2 - builddir=$3 - config_h_dir=$4 - exeext=$5 - shift - shift - shift - shift - shift - strip_prog=$1 - shift - install_prog=$1 # maybe not including the "-c" option - shift + case "$2" in + wrapper) + if test $# -ge 13; then + mode=$2 + shift + shift + library_path_var=$1 + library_path_value=$2 + prefix=$3 + destdir=$4 + shift + shift + shift + shift + compile_command=$1 + srcdir=$2 + builddir=$3 + config_h_dir=$4 + exeext=$5 + shift + shift + shift + shift + shift + strip_prog=$1 + shift + install_prog=$1 # maybe not including the "-c" option + shift + else + func_usage 1>&2; exit 1 + fi + ;; + macosx) + if test $# -ge 6; then + mode=$2 + shift + shift + prefix=$1 + destdir=$2 + shift + shift + exeext= + strip_prog=$1 + shift + install_prog=$1 # maybe not including the "-c" option + shift + else + func_usage 1>&2; exit 1 + fi + ;; + *) + func_usage 1>&2; exit 1 + ;; + esac else if test $# -ge 2; then # Get arguments from environment variables. - library_path_var=$RELOC_LIBRARY_PATH_VAR - library_path_value=$RELOC_LIBRARY_PATH_VALUE - prefix=$RELOC_PREFIX - destdir=$RELOC_DESTDIR - compile_command=$RELOC_COMPILE_COMMAND - srcdir=$RELOC_SRCDIR - builddir=$RELOC_BUILDDIR - config_h_dir=$RELOC_CONFIG_H_DIR - exeext=$RELOC_EXEEXT - strip_prog=$RELOC_STRIP_PROG - install_prog=$RELOC_INSTALL_PROG # including the "-c" option + mode=$RELOC_MODE + case "$mode" in + wrapper) + library_path_var=$RELOC_LIBRARY_PATH_VAR + library_path_value=$RELOC_LIBRARY_PATH_VALUE + prefix=$RELOC_PREFIX + destdir=$RELOC_DESTDIR + compile_command=$RELOC_COMPILE_COMMAND + srcdir=$RELOC_SRCDIR + builddir=$RELOC_BUILDDIR + config_h_dir=$RELOC_CONFIG_H_DIR + exeext=$RELOC_EXEEXT + strip_prog=$RELOC_STRIP_PROG + install_prog=$RELOC_INSTALL_PROG # including the "-c" option + ;; + macosx) + prefix=$RELOC_PREFIX + destdir=$RELOC_DESTDIR + exeext= + strip_prog=$RELOC_STRIP_PROG + install_prog=$RELOC_INSTALL_PROG # including the "-c" option + ;; + *) + func_usage 1>&2; exit 1 + ;; + esac else - echo "Usage: $0 -- library_path_var library_path_value prefix destdir" \ - "compile_command srcdir builddir config_h_dir exeext" \ - "strip_command" \ - "install_command... destprog" 1>&2 - exit 1 + func_usage 1>&2; exit 1 fi fi @@ -179,30 +249,13 @@ func_iterate func_strip fi -# If the platform doesn't support LD_LIBRARY_PATH or similar, we cannot build -# a wrapper. -test -n "$library_path_var" || exit 0 - -libdirs= -save_IFS="$IFS"; IFS=":" -for dir in $library_path_value; do - IFS="$save_IFS" - if test -n "$dir"; then - case "$libdirs" in - *"\"$dir\""*) ;; # remove duplicate - *) libdirs="$libdirs\"$dir\"," ;; - esac - fi -done -IFS="$save_IFS" -# If there are no library directories to add at runtime, we don't need a -# wrapper. -test -n "$libdirs" || exit 0 - # Determine installdir from destprog, removing a leading destdir if present. if test -n "$destprog_directory"; then + # There's possibly multiple programs to install, but all go into the same + # directory. installdir="$destprog_directory" else + # There's only one program to install. installdir=`echo "$destprog" | sed -e 's,/[^/]*$,,'` fi if test -n "$destdir"; then @@ -211,68 +264,160 @@ installdir=`echo "$installdir" | sed -e "$sed_remove_destdir"` fi -# Compile and install wrapper. -func_create_wrapper () +# func_relativize DIR1 DIR2 +# computes a relative pathname RELDIR such that DIR1/RELDIR = DIR2. +# Input: +# - DIR1 relative pathname, relative to the current directory +# - DIR2 relative pathname, relative to the current directory +# Output: +# - reldir relative pathname of DIR2, relative to DIR1 +func_relativize () { - # Remove trailing $exeext, if present. - if test -n "$exeext"; then - destprog=`echo "$destprog" | sed -e "$sed_remove_exeext"` - fi + dir0=`pwd` + dir1="$1" + dir2="$2" + sed_first='s,^\([^/]*\)/.*$,\1,' + sed_rest='s,^[^/]*/*,,' + sed_last='s,^.*/\([^/]*\)$,\1,' + sed_butlast='s,/*[^/]*$,,' + while test -n "$dir1"; do + first=`echo "$dir1" | sed -e "$sed_first"` + if test "$first" != "."; then + if test "$first" = ".."; then + dir2=`echo "$dir0" | sed -e "$sed_last"`/"$dir2" + dir0=`echo "$dir0" | sed -e "$sed_butlast"` + else + first2=`echo "$dir2" | sed -e "$sed_first"` + if test "$first2" = "$first"; then + dir2=`echo "$dir2" | sed -e "$sed_rest"` + else + dir2="../$dir2" + fi + dir0="$dir0"/"$first" + fi + fi + dir1=`echo "$dir1" | sed -e "$sed_rest"` + done + reldir="$dir2" +} + +case "$mode" in + + wrapper) + # If the platform doesn't support LD_LIBRARY_PATH or similar, we cannot + # build a wrapper. + test -n "$library_path_var" || exit 0 + + libdirs= + save_IFS="$IFS"; IFS=":" + for dir in $library_path_value; do + IFS="$save_IFS" + if test -n "$dir"; then + case "$libdirs" in + *"\"$dir\""*) ;; # remove duplicate + *) libdirs="$libdirs\"$dir\"," ;; + esac + fi + done + IFS="$save_IFS" + # If there are no library directories to add at runtime, we don't need a + # wrapper. + test -n "$libdirs" || exit 0 + + # Compile and install wrapper. + func_create_wrapper () + { + # Remove trailing $exeext, if present. + if test -n "$exeext"; then + destprog=`echo "$destprog" | sed -e "$sed_remove_exeext"` + fi - # Compile wrapper. - func_verbose $compile_command \ - -I"$builddir" -I"$srcdir" -I"$config_h_dir" \ - -DHAVE_CONFIG_H -DIN_RELOCWRAPPER -DNO_XMALLOC \ - -D"INSTALLPREFIX=\"$prefix\"" -D"INSTALLDIR=\"$installdir\"" \ - -D"LIBPATHVAR=\"$library_path_var\"" -D"LIBDIRS=$libdirs" \ - -D"EXEEXT=\"$exeext\"" \ - "$srcdir"/relocwrapper.c \ - "$srcdir"/progname.c \ - "$srcdir"/progreloc.c \ - "$srcdir"/areadlink.c \ - "$srcdir"/careadlinkat.c \ - "$srcdir"/allocator.c \ - "$srcdir"/readlink.c \ - "$srcdir"/stat.c \ - "$srcdir"/canonicalize-lgpl.c \ - "$srcdir"/malloca.c \ - "$srcdir"/lstat.c \ - "$srcdir"/relocatable.c \ - "$srcdir"/setenv.c \ - "$srcdir"/c-ctype.c \ - -o "$destprog.wrapper$exeext" - rc=$? - # Clean up object files left over in the current directory by the native C - # compilers on Solaris, HP-UX, OSF/1, IRIX. - rm -f relocwrapper.o \ - progname.o \ - progreloc.o \ - areadlink.o \ - careadlinkat.o \ - allocator.o \ - readlink.o \ - stat.o \ - canonicalize-lgpl.o \ - malloca.o \ - lstat.o \ - relocatable.o \ - setenv.o \ - c-ctype.o - test $rc = 0 || exit $? - # Clean up debugging information left over by the native C compiler on MacOS X. - rm -rf "$destprog.wrapper$exeext.dSYM" - test $rc = 0 || exit $? + # Compile wrapper. + func_verbose $compile_command \ + -I"$builddir" -I"$srcdir" -I"$config_h_dir" \ + -DHAVE_CONFIG_H -DIN_RELOCWRAPPER -DNO_XMALLOC \ + -D"INSTALLPREFIX=\"$prefix\"" -D"INSTALLDIR=\"$installdir\"" \ + -D"LIBPATHVAR=\"$library_path_var\"" -D"LIBDIRS=$libdirs" \ + -D"EXEEXT=\"$exeext\"" \ + "$srcdir"/relocwrapper.c \ + "$srcdir"/progname.c \ + "$srcdir"/progreloc.c \ + "$srcdir"/areadlink.c \ + "$srcdir"/careadlinkat.c \ + "$srcdir"/allocator.c \ + "$srcdir"/readlink.c \ + "$srcdir"/stat.c \ + "$srcdir"/canonicalize-lgpl.c \ + "$srcdir"/malloca.c \ + "$srcdir"/lstat.c \ + "$srcdir"/relocatable.c \ + "$srcdir"/setenv.c \ + "$srcdir"/c-ctype.c \ + -o "$destprog.wrapper$exeext" + rc=$? + # Clean up object files left over in the current directory by the native C + # compilers on Solaris, HP-UX, OSF/1, IRIX. + rm -f relocwrapper.o \ + progname.o \ + progreloc.o \ + areadlink.o \ + careadlinkat.o \ + allocator.o \ + readlink.o \ + stat.o \ + canonicalize-lgpl.o \ + malloca.o \ + lstat.o \ + relocatable.o \ + setenv.o \ + c-ctype.o + test $rc = 0 || exit $? + # Clean up debugging information left over by the native C compiler on + # Mac OS X. + rm -rf "$destprog.wrapper$exeext.dSYM" + test $rc = 0 || exit $? - # Strip wrapper. - test "$strip_prog" = ':' || func_verbose "$strip_prog" "$destprog.wrapper$exeext" || exit $? + # Strip wrapper. + test "$strip_prog" = ':' || func_verbose "$strip_prog" "$destprog.wrapper$exeext" || exit $? + + # Rename $destprog.wrapper -> $destprog -> $destprog.bin. + ln -f "$destprog$exeext" "$destprog.bin$exeext" \ + || { rm -f "$destprog.bin$exeext" \ + && cp -p "$destprog$exeext" "$destprog.bin$exeext"; } \ + || exit 1 + mv "$destprog.wrapper$exeext" "$destprog$exeext" || exit 1 + } + func_iterate func_create_wrapper + ;; - # Rename $destprog.wrapper -> $destprog -> $destprog.bin. - ln -f "$destprog$exeext" "$destprog.bin$exeext" \ - || { rm -f "$destprog.bin$exeext" \ - && cp -p "$destprog$exeext" "$destprog.bin$exeext"; } \ - || exit 1 - mv "$destprog.wrapper$exeext" "$destprog$exeext" || exit 1 -} -func_iterate func_create_wrapper + macosx) + # Insert a reference to @loader_path in selected shared library references. + # For executables, @executable_path is equivalent to @loader_path. + func_reference_loader_path () + { + # For using 'install_name_tool -change ...' we need to know the precise + # library version of each reference. The linker command line does not give + # us the information; only 'otool' provides it. + # Documentation: + # + # + # The install_name_tool exists in versions without and with rpath support: + # + # + otool -L "$destprog" | sed -e '/:$/d' -e 's/^[ ]*//' -e 's/ (.*$//' | \ + while read libfilename; do + case "$libfilename" in + "$prefix"/* ) + func_relativize "$installdir" "$libfilename" + new_libfilename="@loader_path/$reldir" + func_verbose install_name_tool -change "$libfilename" "$new_libfilename" "$destprog" + ;; + esac + done + } + func_iterate func_reference_loader_path + ;; + +esac exit 0 diff -r cd38408f509a -r 5fd32d128129 m4/relocatable.m4 --- a/m4/relocatable.m4 Sat Feb 23 21:24:14 2019 +0100 +++ b/m4/relocatable.m4 Sat Feb 23 22:42:54 2019 +0100 @@ -1,4 +1,4 @@ -# relocatable.m4 serial 21 +# relocatable.m4 serial 22 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, @@ -34,6 +34,7 @@ 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,6 +75,10 @@ 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 + # . + darwin | darwin[1-8].*) ;; + darwin*) use_macos_tools=yes ;; changequote([,])dnl esac if test $is_noop = yes; then @@ -89,12 +94,16 @@ RELOCATABLE_LDFLAGS="\"$reloc_ldflags\" \"\$(host)\" \"\$(RELOCATABLE_LIBRARY_PATH)\"" AC_SUBST([RELOCATABLE_LDFLAGS]) else - use_wrapper=yes dnl Unfortunately we cannot define INSTALL_PROGRAM to a command dnl consisting of more than one word - libtool doesn't support this. dnl So we abuse the INSTALL_PROGRAM_ENV hook, originally meant for the dnl 'install-strip' target. - INSTALL_PROGRAM_ENV="RELOC_LIBRARY_PATH_VAR=\"$shlibpath_var\" RELOC_LIBRARY_PATH_VALUE=\"\$(RELOCATABLE_LIBRARY_PATH)\" RELOC_PREFIX=\"\$(prefix)\" RELOC_DESTDIR=\"\$(DESTDIR)\" RELOC_COMPILE_COMMAND=\"\$(CC) \$(CPPFLAGS) \$(CFLAGS) \$(LDFLAGS)\" RELOC_SRCDIR=\"\$(RELOCATABLE_SRC_DIR)\" RELOC_BUILDDIR=\"\$(RELOCATABLE_BUILD_DIR)\" RELOC_CONFIG_H_DIR=\"\$(RELOCATABLE_CONFIG_H_DIR)\" RELOC_EXEEXT=\"\$(EXEEXT)\" RELOC_STRIP_PROG=\"\$(RELOCATABLE_STRIP)\" RELOC_INSTALL_PROG=\"$INSTALL_PROGRAM\"" + if test $use_macos_tools = yes; then + INSTALL_PROGRAM_ENV="RELOC_MODE=macosx RELOC_PREFIX=\"\$(prefix)\" RELOC_DESTDIR=\"\$(DESTDIR)\" RELOC_STRIP_PROG=\"\$(RELOCATABLE_STRIP)\" RELOC_INSTALL_PROG=\"$INSTALL_PROGRAM\"" + else + use_wrapper=yes + INSTALL_PROGRAM_ENV="RELOC_MODE=wrapper RELOC_LIBRARY_PATH_VAR=\"$shlibpath_var\" RELOC_LIBRARY_PATH_VALUE=\"\$(RELOCATABLE_LIBRARY_PATH)\" RELOC_PREFIX=\"\$(prefix)\" RELOC_DESTDIR=\"\$(DESTDIR)\" RELOC_COMPILE_COMMAND=\"\$(CC) \$(CPPFLAGS) \$(CFLAGS) \$(LDFLAGS)\" RELOC_SRCDIR=\"\$(RELOCATABLE_SRC_DIR)\" RELOC_BUILDDIR=\"\$(RELOCATABLE_BUILD_DIR)\" RELOC_CONFIG_H_DIR=\"\$(RELOCATABLE_CONFIG_H_DIR)\" RELOC_EXEEXT=\"\$(EXEEXT)\" RELOC_STRIP_PROG=\"\$(RELOCATABLE_STRIP)\" RELOC_INSTALL_PROG=\"$INSTALL_PROGRAM\"" + fi AC_SUBST([INSTALL_PROGRAM_ENV]) case "$ac_aux_dir" in /*) INSTALL_PROGRAM="$ac_aux_dir/install-reloc" ;;