Skip to content

Commit 7f3ca80

Browse files
committed
bin/package: add support for DESTDIR (re: 9181553)
Packagers often need to install ksh in a separate tree that replicates the normal directory tree under a certain install root directory. This is possible by simply prepending that prefix to the install root directory prefix, e.g.: bin/package install /tmp/installroot/usr But, as of the referenced commit, this breaks on macOS because we need to configure the path in which to find dynamic libraries at install time. So we now need to make a distinction between the directory prefix used for execution and any additional prefix for (temporary) installation. That temporary prefix must be specified separately. As of this commit, packagers can do: DESTDIR=/tmp/installroot bin/package install /usr (passing it as an environment variable), or bin/package install /usr DESTDIR=/tmp/installroot (passing it as an extra assignment-like command argument). GNU-style Makefile systems generally support this feature using a variable called DESTDIR, which is why I chose that name here.
1 parent 9181553 commit 7f3ca80

File tree

2 files changed

+74
-55
lines changed

2 files changed

+74
-55
lines changed

README.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -230,17 +230,16 @@ bin/package use
230230

231231
### Install
232232

233-
Usage: `bin/package install` *destination_directory* [ *command* ... ]
233+
Usage: `bin/package install` *install_root_directory* [ *command* ... ]
234234

235235
Any command from the `arch` directory can be installed. If no *command* is
236236
specified, `ksh` and `shcomp` are assumed.
237237

238-
The *destination_directory* is created if it does not exist. Commands are
239-
installed in its `bin` subdirectory and each command's manual page, if
240-
available, is installed in `share/man`.
241-
242-
Destination directories with whitespace or shell pattern characters in their
243-
pathnames are not yet supported.
238+
The *install_root_directory* is the directory from which the command(s) will
239+
actually be run. It will be created if it does not exist. Commands are
240+
installed into its `bin` subdirectory, any shared libraries into `lib`, C
241+
development header files into `include/ast`, and each command's manual page,
242+
if available, is installed into `share/man`.
244243

245244
If a dynamically linked version of ksh and associated commands has been
246245
built, then the `install` subcommand will prefer that: commands, dynamic
@@ -249,6 +248,15 @@ statically linked version instead (and skip the header files), either delete
249248
the `dyn` subdirectory, or export `AST_NO_DYLIB=y` before building to prevent
250249
it from being created in the first place.
251250

251+
An additional install prefix directory path can be passed in `DESTDIR`, which
252+
can be either passed as an environment variable or specified on the comannd
253+
line as an extra assignment-like argument. The value of `DESTDIR` will be
254+
prefixed to the path of every destination file when installing it, but not
255+
when configuring the install root directory in the installed files (as may be
256+
required by individual systems, e.g., to find dynamic libraries). This feature
257+
is designed for packagers who need to install ksh into a directory other than
258+
the one from which it will be run in order to package it.
259+
252260
## What is ksh93?
253261

254262
The following is the official AT&T description from 1993 that came with the

bin/package

Lines changed: 59 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ command=${0##*/}
131131
case $(getopts '[-][123:xyz]' opt --xyz 2>/dev/null; echo 0$opt) in
132132
0123) USAGE=$'
133133
[-?
134-
@(#)$Id: '$command$' (ksh 93u+m) 2025-04-27 $
134+
@(#)$Id: '$command$' (ksh 93u+m) 2026-01-21 $
135135
]
136136
[-author?Glenn Fowler <gsf@research.att.com>]
137137
[-author?Contributors to https://github.com/ksh93/ksh]
@@ -212,20 +212,22 @@ case $(getopts '[-][123:xyz]' opt --xyz 2>/dev/null; echo 0$opt) in
212212
release incompatibilities has for the most part been
213213
futile.]
214214
}
215-
[+install\b [ \adest_dir\a ]] [ \acommand\a ... ]]?Install commands
215+
[+install\b [ \aroot_dir\a ]] [ \acommand\a ... ]]?Install commands
216216
from the \b$INSTALLROOT\b tree
217-
into appropriate subdirectories of \adest_dir\a.
218-
If \adest_dir\a does not exist,
217+
into appropriate subdirectories of \aroot_dir\a,
218+
typically an operating system directory such as \b/usr/local\b.
219+
If \aroot_dir\a does not exist,
219220
then it and any necessary subdirectories are created.
220-
\adest_dir\a can be a directory like \a/usr/local\a
221-
to install the \acommand\as directly,
222-
or a temporary directory like \a/tmp/pkgtree/usr\a
223-
to prepare for packaging with operating system-specific tools.
224221
Each \acommand\a is first searched in \b$INSTALLROOT/dyn/bin\b
225222
(dynamically linked version)
226223
and then in \b$INSTALLROOT/bin\b.
227224
If no \acommand\a is specified,
228-
then \aksh\a and \ashcomp\a are assumed.]
225+
then \bksh\b and \bshcomp\b are assumed.
226+
If you need to package the software using operating system-specific
227+
tools, then pass the path to a temporary install root directory
228+
in the \bDESTDIR\b variable; the software will be
229+
physically installed into \b$DESTDIR\b$\aroot_dir\a but configured
230+
(where applicable) to be executed from \aroot_dir\a.]
229231
[+make\b [ \apackage\a ]] [ \aoption\a ... ]] [ \atarget\a ... ]]?Build
230232
and install. The default \atarget\a is \binstall\b, which makes
231233
and installs \apackage\a. If the standard output is a terminal
@@ -454,8 +456,8 @@ DESCRIPTION
454456
export [ variable ...]
455457
List name=value for variable, one per line. If the only attribute is
456458
specified then only the variable values are listed. If no variables
457-
are specified then HOSTTYPE PACKAGEROOT INSTALLROOT PATH FPATH
458-
MANPATH are assumed.
459+
are specified then HOSTTYPE PACKAGEROOT INSTALLROOT PATH DEFPATH
460+
FPATH MANPATH are assumed.
459461
help [ action ]
460462
Display help text on the standard error (standard output for action).
461463
host [ attribute ... ]
@@ -473,16 +475,18 @@ DESCRIPTION
473475
similar, predictable style. OS point release information is
474476
avoided as much as possible, but vendor resistance to release
475477
incompatibilities has for the most part been futile.
476-
install [ dest_dir ] [ command ... ]
478+
install [ root_dir ] [ command ... ]
477479
Install commands from the $INSTALLROOT tree into appropriate
478-
subdirectories of dest_dir. If dest_dir does not exist, then it and
479-
any necessary subdirectories are created. dest_dir can be a directory
480-
like /usr/local to install the commands directly, or a temporary
481-
directory like /tmp/pkgtree/usr to prepare for packaging with
482-
operating system-specific tools. Each command is first searched in
483-
$INSTALLROOT/dyn/bin (dynamically linked version) and then in
484-
$INSTALLROOT/bin. If no command is specified, then ksh and shcomp
485-
are assumed.
480+
subdirectories of root_dir, typically an operating system directory
481+
such as /usr/local. If root_dir does not exist, then it and any
482+
necessary subdirectories are created. Each command is first searched
483+
in $INSTALLROOT/dyn/bin (dynamically linked version) and then in
484+
$INSTALLROOT/bin. If no command is specified, then ksh and shcomp are
485+
assumed. If you need to package the software using operating
486+
system-specific tools, then pass the path to a temporary install root
487+
directory in the DESTDIR variable; the software will be physically
488+
installed into $DESTDIR$root_dir but configured (where applicable) to
489+
be executed from root_dir.
486490
make [ package ] [ option ... ] [ target ... ]
487491
Build and install. The default target is install, which makes and
488492
installs package. If the standard output is a terminal then the
@@ -560,7 +564,7 @@ SEE ALSO
560564
pkgadd(1), pkgmk(1), rpm(1), sh(1), tar(1), optget(3)
561565

562566
IMPLEMENTATION
563-
version package (ksh 93u+m) 2025-04-27
567+
version package (ksh 93u+m) 2026-01-21
564568
author Glenn Fowler <gsf@research.att.com>
565569
author Contributors to https://github.com/ksh93/ksh
566570
copyright (c) 1994-2012 AT&T Intellectual Property
@@ -2581,56 +2585,63 @@ make_recurse() # dir
25812585

25822586
do_install() # dir [ command ... ]
25832587
{
2588+
case $DESTDIR in
2589+
?*) printf 'install: DESTDIR=%s\n' "$DESTDIR" ;;
2590+
esac
2591+
case $assign in
2592+
*=\'*) printf 'install:%s\n' "$assign"
2593+
eval "$assign" ;; # value(s) should be properly shellquoted
2594+
esac
25842595
cd "$INSTALLROOT"
2585-
printf 'install: installing from %s\n' "$PWD"
2586-
dd=$1
2596+
ird=$1
25872597
shift
2588-
case $dd in
2598+
case $ird in
25892599
'' | [!/]*)
2590-
err_out "ERROR: destination directory '$dd' must begin with a /" ;;
2600+
err_out "ERROR: install root directory '$ird' must begin with a /" ;;
25912601
/)
25922602
# avoid //foo
2593-
dd='' ;;
2603+
ird='' ;;
25942604
esac
25952605
# commands to install by default
25962606
test "$#" -eq 0 && set -- ksh shcomp
25972607
for f
25982608
do test -f "bin/$f" || err_out "Not found: $f" "Build first? Run $0 make"
25992609
done
2610+
printf 'install: installing from %s into %s\n' "$PWD" "$ird"
26002611
# set install directories
2601-
bindir=$dd/bin
2602-
fundir=${dd:-/usr}/share/fun
2603-
mandir=${dd:-/usr}/share/man
2612+
bindir=$ird/bin
2613+
fundir=${ird:-/usr}/share/fun
2614+
mandir=${ird:-/usr}/share/man
26042615
man1dir=$mandir/man1
26052616
man3dir=$mandir/man3
2606-
libdir=$dd/lib
2607-
includedir=$dd/include
2617+
libdir=$ird/lib
2618+
includedir=$ird/include
26082619
# and off we go
2609-
trace mkdir -p "$bindir" "$man1dir" || exit
2620+
trace mkdir -p "$DESTDIR$bindir" "$DESTDIR$man1dir" || exit
26102621
for f
26112622
do # macOS throws code signature error if in-use Mach-O binary is overwritten or deleted; must rename first
2612-
if test -e "$bindir/$f"
2613-
then trace mv "$bindir/$f" "$bindir/$f.old" || exit
2623+
if test -e "$DESTDIR$bindir/$f"
2624+
then trace mv "$DESTDIR$bindir/$f" "$DESTDIR$bindir/$f.old" || exit
26142625
fi
26152626
# install executable
26162627
if test -f "dyn/bin/$f"
2617-
then trace cp "dyn/bin/$f" "$bindir/" || exit
2628+
then trace cp "dyn/bin/$f" "$DESTDIR$bindir/" || exit
26182629
case $HOSTTYPE in
26192630
darwin.*)
2620-
trace install_name_tool -add_rpath "$libdir" "$bindir/$f" || exit
2631+
trace install_name_tool -add_rpath "$libdir" "$DESTDIR$bindir/$f" || exit
26212632
;;
26222633
esac
2623-
else trace cp "bin/$f" "$bindir/" || exit
2634+
else trace cp "bin/$f" "$DESTDIR$bindir/" || exit
26242635
fi
26252636
# install manual pages and autoloadable functions
26262637
case $f in
2627-
ksh) trace cp "$PACKAGEROOT/src/cmd/ksh93/sh.1" "$man1dir/ksh.1" || exit
2628-
trace mkdir -p "$fundir" || exit
2629-
(set +o noglob; trace cp "$PACKAGEROOT"/src/cmd/ksh93/fun/* "$fundir/") || exit
2638+
ksh) trace cp "$PACKAGEROOT/src/cmd/ksh93/sh.1" "$DESTDIR$man1dir/ksh.1" || exit
2639+
trace mkdir -p "$DESTDIR$fundir" || exit
2640+
(set +o noglob; trace cp "$PACKAGEROOT"/src/cmd/ksh93/fun/* "$DESTDIR$fundir/") || exit
26302641
;;
26312642
*) # AT&T --man, etc. is a glorified error message: writes to stderr and exits with status 2 :-/
26322643
# So we cannot reliably check for success; must check the result, too.
2633-
manfile=$man1dir/${f##*/}.1
2644+
manfile=$DESTDIR$man1dir/${f##*/}.1
26342645
bin/ksh -c '"$@" 2>&1' _ "bin/$f" --\?\?nroff >$manfile
26352646
if test "$?" -eq 2 &&
26362647
read -r magic < "$manfile" &&
@@ -2642,29 +2653,29 @@ do_install() # dir [ command ... ]
26422653
esac
26432654
done
26442655
if test -d "dyn/lib"
2645-
then trace mkdir -p "$libdir" "$man3dir" "$includedir"
2656+
then trace mkdir -p "$DESTDIR$libdir" "$DESTDIR$man3dir" "$DESTDIR$includedir"
26462657
# install libraries
26472658
set +o noglob
26482659
for f in dyn/lib/*
26492660
do set -o noglob
26502661
# macOS throws code signature error if in-use Mach-O binary is overwritten or deleted; must rename first
2651-
fi=$libdir/${f##*/}
2662+
fi=$DESTDIR$libdir/${f##*/}
26522663
if test -e "$fi" && ! test -L "$fi"
26532664
then trace mv "$fi" "$fi.old" || exit
26542665
fi
26552666
# the extra -R is needed as a workaround for /bin/cp to copy a symlink on (at least) macOS 12.7.5
2656-
trace cp -PR "$f" "$libdir"/ || exit
2667+
trace cp -PR "$f" "$DESTDIR$libdir"/ || exit
26572668
done
26582669
# install developer stuff
2659-
test -d "$includedir/ast" && trace rm -rf -- "$includedir/ast"
2660-
trace cp -R "include/ast" "$includedir"/ || exit
2661-
printf "install: writing into %s:" "$man3dir"
2670+
test -d "$DESTDIR$includedir/ast" && trace rm -rf -- "$DESTDIR$includedir/ast"
2671+
trace cp -R "include/ast" "$DESTDIR$includedir"/ || exit
2672+
printf "install: writing into %s:" "$DESTDIR$man3dir"
26622673
(
26632674
set +o noglob
26642675
for f in man/man3/*.3
26652676
do printf " %sast" "${f##*/}"
26662677
# give .3 pages an ast suffix to avoid conflicts
2667-
sed '/^\.TH .* 3/ s/ 3/ 3ast/' "$f" > "$man3dir/${f##*/}ast"
2678+
sed '/^\.TH .* 3/ s/ 3/ 3ast/' "$f" > "$DESTDIR$man3dir/${f##*/}ast"
26682679
done
26692680
)
26702681
printf '\n'

0 commit comments

Comments
 (0)