1#!/bin/sh
2# install-reloc - install a program including a relocating wrapper
3# Copyright (C) 2003-2020 Free Software Foundation, Inc.
4# Written by Bruno Haible <bruno@clisp.org>, 2003.
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <https://www.gnu.org/licenses/>.
18
19# Usage 1:
20#   install-reloc -- library_path_var library_path_value prefix destdir \
21#                    compile_command srcdir builddir config_h_dir exeext \
22#                    strip_command \
23#                    install_command... destprog
24# where
25#   - library_path_var is the platform dependent runtime library path variable
26#   - library_path_value is a colon separated list of directories that contain
27#     the libraries at installation time (use this instead of -rpath)
28#   - prefix is the base directory at installation time
29#   - destdir is a string that is prepended to all file names at installation
30#     time; it is already prepended to destprog but not to library_path_value
31#     and prefix
32#   - compile_command is a C compiler compilation and linking command
33#   - srcdir is the directory where to find relocwrapper.c and its dependencies
34#   - builddir is the directory where to find built dependencies (namely,
35#     alloca.h and stdbool.h)
36#   - config_h_dir is the directory where to find config.h
37#   - exeext is platform dependent suffix of executables
38#   - strip_command is the command for stripping executables, or : if no
39#     stripping is desired
40#   - install_command is the install command line, excluding the final destprog
41#   - destprog is the destination program name
42# Usage 2:
43#   env RELOC_LIBRARY_PATH_VAR=library_path_var \
44#       RELOC_LIBRARY_PATH_VALUE=library_path_value \
45#       RELOC_PREFIX=prefix \
46#       RELOC_DESTDIR=destdir \
47#       RELOC_COMPILE_COMMAND=compile_command \
48#       RELOC_SRCDIR=srcdir \
49#       RELOC_BUILDDIR=builddir \
50#       RELOC_CONFIG_H_DIR=config_h_dir \
51#       RELOC_EXEEXT=exeext \
52#       RELOC_STRIP_PROG=strip_command \
53#       RELOC_INSTALL_PROG=install_command... \
54#   install-reloc prog1 ... destprog
55#   where destprog is either the destination program name (when only one program
56#   is specified) or the destination directory for all programs.
57# install-reloc renames destprog to destprog.bin and installs a relocating
58# wrapper in the place of destprog.
59
60progname=$0
61
62if test $# -ge 12 && test "x$1" = "x--"; then
63  # Get fixed position arguments.
64  shift
65  library_path_var=$1
66  library_path_value=$2
67  prefix=$3
68  destdir=$4
69  shift
70  shift
71  shift
72  shift
73  compile_command=$1
74  srcdir=$2
75  builddir=$3
76  config_h_dir=$4
77  exeext=$5
78  shift
79  shift
80  shift
81  shift
82  shift
83  strip_prog=$1
84  shift
85  install_prog=$1 # maybe not including the "-c" option
86  shift
87else
88  if test $# -ge 2; then
89    # Get arguments from environment variables.
90    library_path_var=$RELOC_LIBRARY_PATH_VAR
91    library_path_value=$RELOC_LIBRARY_PATH_VALUE
92    prefix=$RELOC_PREFIX
93    destdir=$RELOC_DESTDIR
94    compile_command=$RELOC_COMPILE_COMMAND
95    srcdir=$RELOC_SRCDIR
96    builddir=$RELOC_BUILDDIR
97    config_h_dir=$RELOC_CONFIG_H_DIR
98    exeext=$RELOC_EXEEXT
99    strip_prog=$RELOC_STRIP_PROG
100    install_prog=$RELOC_INSTALL_PROG # including the "-c" option
101  else
102    echo "Usage: $0 -- library_path_var library_path_value prefix destdir" \
103         "compile_command srcdir builddir config_h_dir exeext" \
104         "strip_command" \
105         "install_command... destprog" 1>&2
106    exit 1
107  fi
108fi
109
110# Get destprog, last argument.
111destprog=
112for arg
113do
114  destprog=$arg
115done
116# Determine whether destprog is a program name or a directory name.
117if test -d "$destprog"; then
118  sed_remove_trailing_slashes='s|//*$||'
119  destprog_directory=`echo "$destprog" | sed -e "$sed_remove_trailing_slashes"`
120  if test -z "$destprog_directory"; then
121    destprog_directory='/'
122  fi
123else
124  destprog_directory=
125fi
126# Prepare for remove trailing $exeext, if present.
127if test -n "$exeext"; then
128  sed_quote='s,\.,\\.,g'
129  sed_remove_exeext='s|'`echo "$exeext" | sed -e "$sed_quote"`'$||'
130fi
131if test -z "$destprog_directory"; then
132  # Remove trailing $exeext, if present.
133  if test -n "$exeext"; then
134    destprog=`echo "$destprog" | sed -e "$sed_remove_exeext"`
135  fi
136fi
137
138# Outputs a command and runs it.
139func_verbose ()
140{
141  # Make it easy to copy&paste the printed command into a shell in most cases,
142  # by escaping '\\', '"', and '$'. This is not perfect, just good enough.
143  echo "$@" | sed -e 's/\([\\"$]\)/\\\1/g'
144  "$@"
145}
146
147# Run install_command.
148func_verbose $install_prog "$@" || exit $?
149
150# Iterate over all destination program names.
151# func_iterate f
152# applies f to each destination program names, after setting destprog.
153sed_basename_of_file='s|^.*/||'
154func_iterate ()
155{
156  if test -n "$destprog_directory"; then
157    prev_arg=
158    for arg
159    do
160      if test -n "prev_arg"; then
161        destprog="$destprog_directory"/`echo "$prev_arg" | sed -e "$sed_basename_of_file"`
162        $1
163      fi
164      prev_arg="$arg"
165    done
166  else
167    $1
168  fi
169}
170
171# Run strip_command.
172func_strip ()
173{
174  # Remove trailing $exeext, if present.
175  if test -n "$exeext"; then
176    destprog=`echo "$destprog" | sed -e "$sed_remove_exeext"`
177  fi
178  func_verbose "$strip_prog" "$destprog$exeext" || exit $?
179}
180if test "$strip_prog" != ':'; then
181  func_iterate func_strip
182fi
183
184# If the platform doesn't support LD_LIBRARY_PATH or similar, we cannot build
185# a wrapper.
186test -n "$library_path_var" || exit 0
187
188libdirs=
189save_IFS="$IFS"; IFS=":"
190for dir in $library_path_value; do
191  IFS="$save_IFS"
192  if test -n "$dir"; then
193    case "$libdirs" in
194      *"\"$dir\""*) ;; # remove duplicate
195      *) libdirs="$libdirs\"$dir\"," ;;
196    esac
197  fi
198done
199IFS="$save_IFS"
200# If there are no library directories to add at runtime, we don't need a
201# wrapper.
202test -n "$libdirs" || exit 0
203
204# Determine installdir from destprog, removing a leading destdir if present.
205if test -n "$destprog_directory"; then
206  installdir="$destprog_directory"
207else
208  installdir=`echo "$destprog" | sed -e 's,/[^/]*$,,'`
209fi
210if test -n "$destdir"; then
211  sed_quote='s,\([|.\*^$[]\),\\\1,g'
212  sed_remove_destdir='s|^'`echo "$destdir" | sed -e "$sed_quote"`'||'
213  installdir=`echo "$installdir" | sed -e "$sed_remove_destdir"`
214fi
215
216# Compile and install wrapper.
217func_create_wrapper ()
218{
219  # Remove trailing $exeext, if present.
220  if test -n "$exeext"; then
221    destprog=`echo "$destprog" | sed -e "$sed_remove_exeext"`
222  fi
223
224  # Compile wrapper.
225  func_verbose $compile_command \
226               -I"$builddir" -I"$srcdir" -I"$config_h_dir" \
227               -DHAVE_CONFIG_H -DIN_RELOCWRAPPER -DNO_XMALLOC \
228               -D"INSTALLPREFIX=\"$prefix\"" -D"INSTALLDIR=\"$installdir\"" \
229               -D"LIBPATHVAR=\"$library_path_var\"" -D"LIBDIRS=$libdirs" \
230               -D"EXEEXT=\"$exeext\"" \
231               "$srcdir"/relocwrapper.c \
232               "$srcdir"/progname.c \
233               "$srcdir"/progreloc.c \
234               "$srcdir"/areadlink.c \
235               "$srcdir"/careadlinkat.c \
236               "$srcdir"/allocator.c \
237               "$srcdir"/readlink.c \
238               "$srcdir"/stat.c \
239               "$srcdir"/canonicalize-lgpl.c \
240               "$srcdir"/malloca.c \
241               "$srcdir"/lstat.c \
242               "$srcdir"/relocatable.c \
243               "$srcdir"/setenv.c \
244               "$srcdir"/c-ctype.c \
245               -o "$destprog.wrapper$exeext"
246  rc=$?
247  # Clean up object files left over in the current directory by the native C
248  # compilers on Solaris, HP-UX, OSF/1, IRIX.
249  rm -f relocwrapper.o \
250        progname.o \
251        progreloc.o \
252        areadlink.o \
253        careadlinkat.o \
254        allocator.o \
255        readlink.o \
256        stat.o \
257        canonicalize-lgpl.o \
258        malloca.o \
259        lstat.o \
260        relocatable.o \
261        setenv.o \
262        c-ctype.o
263  test $rc = 0 || exit $?
264  # Clean up debugging information left over by the native C compiler on MacOS X.
265  rm -rf "$destprog.wrapper$exeext.dSYM"
266  test $rc = 0 || exit $?
267
268  # Strip wrapper.
269  test "$strip_prog" = ':' || func_verbose "$strip_prog" "$destprog.wrapper$exeext" || exit $?
270
271  # Rename $destprog.wrapper -> $destprog -> $destprog.bin.
272  ln -f "$destprog$exeext" "$destprog.bin$exeext" \
273    || { rm -f "$destprog.bin$exeext" \
274         && cp -p "$destprog$exeext" "$destprog.bin$exeext"; } \
275    || exit 1
276  mv "$destprog.wrapper$exeext" "$destprog$exeext" || exit 1
277}
278func_iterate func_create_wrapper
279
280exit 0
281