375 lines
9.2 KiB
Bash
Executable File
375 lines
9.2 KiB
Bash
Executable File
#!/bin/sh
|
|
### quick-install-emacs --- do a halfway-decent job of installing emacs quickly
|
|
|
|
## Copyright (C) 2001-2024 Free Software Foundation, Inc.
|
|
|
|
## Author: Miles Bader <miles@gnu.org>
|
|
|
|
## This file is part of GNU Emacs.
|
|
|
|
## GNU Emacs 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.
|
|
|
|
## GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
### Commentary:
|
|
|
|
## This script is mainly intended for emacs maintainer or pretesters who
|
|
## install emacs very often. See the --help output for more details.
|
|
|
|
|
|
PUBLIC_LIBSRC_BINARIES='emacsclient etags ctags ebrowse'
|
|
|
|
AVOID="CVS -DIC README COPYING ChangeLog ~ [.]orig$ [.]rej$ Makefile$ Makefile.in$ makefile$ makefile.w32-in$ stamp-subdir [.]cvsignore [.]arch-ids [{]arch[}] [.][cho]$ make-docfile"
|
|
|
|
# Prune old binaries lying around in the source tree
|
|
PRUNE=no
|
|
# Re-install files even if they already exist
|
|
FORCE=no
|
|
# Command verbose flag
|
|
VERBOSE=''
|
|
|
|
me="`basename $0`"
|
|
|
|
# Install commands (if the user specifies the '--verbose' option, it is
|
|
# passed to these commands, so that feature only works if these commands
|
|
# implement it too)
|
|
LINK='cp -lf'
|
|
COPY='cp -f'
|
|
REMOVE='rm -r'
|
|
MKDIR='mkdir -p'
|
|
|
|
# Used to execute commands once we create them
|
|
EXEC='sh'
|
|
|
|
NAWK=/usr/bin/nawk
|
|
|
|
# avoid non-standard command output from non-C locales
|
|
unset LANG LC_ALL LC_MESSAGES
|
|
|
|
# Some messages
|
|
USAGE="Usage: $me [OPTION...] BUILD_TREE [PREFIX]"
|
|
TRY="Try '$me --help' for more information."
|
|
|
|
# Parse command-line options
|
|
while :; do
|
|
case "$1" in
|
|
-n|--dry-run)
|
|
EXEC=cat; shift;;
|
|
-p|--prune)
|
|
PRUNE=yes; shift;;
|
|
-P|--no-prune)
|
|
PRUNE=no; shift;;
|
|
--prune-only)
|
|
PRUNE=only; shift;;
|
|
-f|--force)
|
|
FORCE=yes; shift;;
|
|
-v|--verbose)
|
|
VERBOSE="-v"; shift;;
|
|
--help)
|
|
cat <<EOF
|
|
$USAGE
|
|
Install emacs quickly
|
|
|
|
-n, --dry-run print installation commands instead of
|
|
executing them
|
|
|
|
-f, --force install even files that haven't changed
|
|
-v, --verbose print messages describing what is done
|
|
|
|
-p, --prune prune old generated files
|
|
-P, --no-prune don't prune old generated files (default)
|
|
--prune-only prune old generated files, but don't install
|
|
|
|
--help display this help and exit
|
|
--version output version information and exit
|
|
|
|
$me install emacs "incrementally", that is, it will
|
|
install only those files that have changed since the last time it was
|
|
invoked, and remove any obsolete files from the installation
|
|
directories. It also uses hard-links into the source and build trees to
|
|
do the install, so it uses much less space than the default Makefile
|
|
install target; however, this also means that $me can
|
|
not install onto a disk partition other than the one on which the source
|
|
and build directories reside.
|
|
|
|
Optionally, $me can also remove old versions of
|
|
automatically generated files that are version-specific (such as the
|
|
versioned emacs executables in the 'src' directory).
|
|
The latter action is called "pruning", and
|
|
can be enabled using the '-p' or '--prune' options.
|
|
EOF
|
|
exit 0
|
|
;;
|
|
--version)
|
|
cat <<EOF
|
|
$me 1.6
|
|
|
|
Written by Miles Bader <miles@gnu.org>
|
|
EOF
|
|
exit 0
|
|
;;
|
|
-[!-]?*)
|
|
# split concatenated single-letter options apart
|
|
FIRST="$1"; shift
|
|
set -- `printf '%s\n' "$FIRST" | sed 's/-\(.\)\(.*\)/-\1 -\2/'` "$@"
|
|
;;
|
|
-*)
|
|
printf '%s\n' >&2 "$me: unrecognized option '$1'"
|
|
printf '%s\n' >&2 "$TRY"
|
|
exit 1
|
|
;;
|
|
*)
|
|
break;
|
|
esac
|
|
done
|
|
|
|
LINK_CMD="$LINK $VERBOSE"
|
|
REMOVE_CMD="$REMOVE $VERBOSE"
|
|
|
|
case $# in
|
|
1) BUILD="$1";;
|
|
2) BUILD="$1"; prefix="$2";;
|
|
*)
|
|
printf '%s\n' >&2 "$USAGE"
|
|
printf '%s\n' >&2 "$TRY"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
if test ! -d "$BUILD"; then
|
|
printf '%s\n' >&2 "$me: $BUILD: Build tree not found"
|
|
exit 2
|
|
elif test ! -r "$BUILD/config.status"; then
|
|
printf '%s\n' >&2 \
|
|
"$me: $BUILD: Not a proper build tree, config.status not found"
|
|
exit 2
|
|
fi
|
|
|
|
CONFIG_STATUS="$BUILD/config.status"
|
|
get_config_var ()
|
|
{
|
|
{ sed -n "s/^S[[]\"$1\"[]]=\"\([^\"]*\)\"/\1/p" $CONFIG_STATUS | sed q | grep ''; } ||
|
|
{ sed -n "s/^s\(.\)@$1@\1\(|#_!!_#|\)*\(.*\)\1.*$/\3/p" $CONFIG_STATUS | sed q | grep ''; } ||
|
|
{
|
|
printf '%s\n' >&2 \
|
|
"$me: $1: Configuration variable not found in $CONFIG_STATUS"
|
|
exit 4
|
|
}
|
|
}
|
|
|
|
test x"$SRC" = x && { SRC="`get_config_var srcdir`" || exit 4 ; }
|
|
test x"$prefix" = x && { prefix="`get_config_var prefix`" || exit 4 ; }
|
|
test x"$ARCH" = x && { ARCH="`get_config_var host`" || exit 4 ; }
|
|
|
|
VERSION=`
|
|
sed -n 's/^AC_INIT([ ]*\[*emacs]*[ ]*,[ ]*\[*\([^] ),]*\).*/\1/p' <$SRC/configure.ac
|
|
` || exit 4
|
|
test -n "$VERSION" || VERSION=`
|
|
sed -n 's/^AC_INIT([ ]*\[*GNU Emacs]*[ ]*,[ ]*\[*\([^] ),]*\).*/\1/p' <$SRC/configure.ac
|
|
` || exit 4
|
|
test -n "$VERSION" || { printf '%s\n' >&2 "$me: no version in configure.ac"; exit 4; }
|
|
|
|
DST_SHARE="$prefix/share/emacs/$VERSION"
|
|
DST_BIN="$prefix/bin"
|
|
DST_LIBEXEC="$prefix/libexec/emacs/$VERSION/$ARCH"
|
|
|
|
# There are various common places for the info dir to be, so try to
|
|
# use whatever's already there, defaulting to (and preferring)
|
|
# .../share/info.
|
|
#
|
|
DST_INFO=''
|
|
for D in "$prefix/share/info" "$prefix/info"; do
|
|
if test -d "$D"; then
|
|
DST_INFO="$D"
|
|
break
|
|
fi
|
|
done
|
|
DST_INFO=${DST_INFO:-"$prefix/share/info"}
|
|
|
|
maybe_mkdir ()
|
|
{
|
|
if ! test -d "$1"; then
|
|
$MKDIR $VERBOSE "$1" 2>&1 | sed "s/^mkdir:/$me:/" 1>&2
|
|
fi
|
|
}
|
|
|
|
maybe_mkdir "$DST_BIN"
|
|
maybe_mkdir "$DST_SHARE"
|
|
maybe_mkdir "$DST_SHARE/site-lisp"
|
|
maybe_mkdir "$DST_LIBEXEC"
|
|
maybe_mkdir "$DST_INFO"
|
|
|
|
( # start of command-generating sub-shell
|
|
|
|
PRUNED=""
|
|
if test x"$PRUNE" != xno; then
|
|
for D in `ls -1t $BUILD/src/emacs-$VERSION.* | sed 1d`; do
|
|
printf '%s\n' "$REMOVE_CMD $D"
|
|
PRUNED="$PRUNED $D"
|
|
done
|
|
fi
|
|
|
|
test x"$PRUNE" = xonly && exit 0
|
|
|
|
maybe_emit_copy ()
|
|
{
|
|
if test "$FORCE" = yes || ! cmp -s $1 $2; then
|
|
printf '%s\n' "$LINK_CMD $1 $2"
|
|
fi
|
|
}
|
|
|
|
maybe_emit_copy $BUILD/src/emacs $DST_BIN/emacs
|
|
maybe_emit_copy $BUILD/src/emacs $DST_BIN/emacs-$VERSION
|
|
|
|
for F in $PUBLIC_LIBSRC_BINARIES; do
|
|
maybe_emit_copy $BUILD/lib-src/$F $DST_BIN/$F
|
|
done
|
|
|
|
if test x"$SRC" = x"$BUILD"; then
|
|
PFXS="$BUILD"
|
|
else
|
|
PFXS="$SRC $BUILD"
|
|
fi
|
|
|
|
for SUBDIR in lisp leim etc lib-src info; do
|
|
# defaults
|
|
SHARED=no
|
|
FORCED=''
|
|
AVOID_PAT="`printf '%s\n' "($AVOID)" | tr ' ' '|'`"
|
|
|
|
# Set subdir-specific values
|
|
case $SUBDIR in
|
|
lisp|leim)
|
|
DST="$DST_SHARE/$SUBDIR"
|
|
;;
|
|
etc)
|
|
DST="$DST_SHARE/$SUBDIR"
|
|
# COPYING is in the avoid list, but there should be a copy of it in
|
|
# the install etc dir, so make that here.
|
|
FORCED="$DST/COPYING"
|
|
;;
|
|
lib-src)
|
|
DST="$DST_LIBEXEC"
|
|
AVOID_PAT="`printf '%s\n' "($AVOID ($PUBLIC_LIBSRC_BINARIES)\$)" | tr ' ' '|'`"
|
|
;;
|
|
info)
|
|
DST="$DST_INFO"
|
|
SHARED=yes
|
|
;;
|
|
esac
|
|
|
|
for PFX in $PFXS; do
|
|
if [ -d $PFX/$SUBDIR ]; then
|
|
for DIR in `(cd $PFX/$SUBDIR; find . -type d -print | sed 's@^./@@')`; do
|
|
if [ -d $DST/$DIR ]; then
|
|
printf '%s\n' "Directory $DST/$DIR exists"
|
|
else
|
|
printf '%s\n' "Directory $DST/$DIR non-existent"
|
|
if [ "`printf '%s\n' "$DIR" | grep -Ev "$AVOID_PAT"`" ]; then
|
|
maybe_mkdir $DST/$DIR
|
|
fi
|
|
fi
|
|
done
|
|
diff -sqr $PFX/$SUBDIR $DST
|
|
fi
|
|
done | $NAWK '
|
|
BEGIN {
|
|
src_pat = "^'"$SRC"'/'"$SUBDIR"'/"
|
|
build_pat = "^'"$BUILD"'/'"$SUBDIR"'/"
|
|
dst_pat = "^'"$DST"'/"
|
|
dst_pfx = "'"$DST"'/"
|
|
avoid_pat = "'"$AVOID_PAT"'"
|
|
force = ("'"$FORCE"'" == "yes")
|
|
shared = ("'"$SHARED"'" == "yes")
|
|
init_bool_array(pruned, "'"$PRUNED"'")
|
|
init_bool_array(forced, "'"$FORCED"'")
|
|
}
|
|
function init_bool_array(array, string, a,k)
|
|
{
|
|
split (string, a)
|
|
for (k in a)
|
|
array[a[k]] = 1
|
|
}
|
|
function install(src, dst)
|
|
{
|
|
if (! (src in pruned)) {
|
|
cp[src] = dst;
|
|
from[dst] = src;
|
|
delete rm[dst];
|
|
}
|
|
}
|
|
function update(src, dst, copy)
|
|
{
|
|
if (src in pruned) {
|
|
rm[dst] = 1;
|
|
delete from[dst]
|
|
} else {
|
|
if (copy)
|
|
cp[src] = dst;
|
|
from[dst] = src;
|
|
delete rm[dst];
|
|
}
|
|
}
|
|
function uninstall(dst)
|
|
{
|
|
if (!(dst in from))
|
|
rm[dst] = 1;
|
|
}
|
|
/^Directory / {
|
|
if ($2 ~ avoid_pat) {
|
|
if ($NF == "exists")
|
|
uninstall($2)
|
|
} else
|
|
update(0, $2, 0)
|
|
next
|
|
}
|
|
/^Files / {
|
|
if ($4 ~ avoid_pat && !($4 in forced))
|
|
uninstall($4)
|
|
else if ($NF == "identical")
|
|
update($2, $4, force)
|
|
else
|
|
update($2, $4, 1)
|
|
next
|
|
}
|
|
/^Only / {
|
|
pfx = $3
|
|
sub (/:$/, "/", pfx)
|
|
|
|
if (pfx ~ dst_pat) {
|
|
if (! shared)
|
|
uninstall(pfx $4)
|
|
} else {
|
|
subdir = pfx
|
|
if (subdir ~ src_pat)
|
|
sub (src_pat, "", subdir)
|
|
else
|
|
sub (build_pat, "", subdir)
|
|
|
|
dst = dst_pfx subdir $4
|
|
if (! (dst ~ avoid_pat))
|
|
install(pfx $4, dst)
|
|
}
|
|
next
|
|
}
|
|
END {
|
|
for (f in rm)
|
|
print "'"$REMOVE_CMD"' " f
|
|
for (f in cp)
|
|
print "'"$LINK_CMD"' " f " " cp[f]
|
|
}
|
|
'
|
|
done
|
|
|
|
) | eval $EXEC
|