Complete last commit
[emacs.git] / admin / quick-install-emacs
blob4de7416e3d69aa79c48f65ec905b0a3fc8a7011c
1 #!/bin/sh
2 ### quick-install-emacs --- do a halfway-decent job of installing emacs quickly
4 ## Copyright (C) 2001-2015 Free Software Foundation, Inc.
6 ## Author: Miles Bader <miles@gnu.org>
8 ## This file is part of GNU Emacs.
10 ## GNU Emacs is free software: you can redistribute it and/or modify
11 ## it under the terms of the GNU General Public License as published by
12 ## the Free Software Foundation, either version 3 of the License, or
13 ## (at your option) any later version.
15 ## GNU Emacs is distributed in the hope that it will be useful,
16 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ## GNU General Public License for more details.
20 ## You should have received a copy of the GNU General Public License
21 ## along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24 ### Commentary:
26 ## This script is mainly intended for emacs maintainer or pretesters who
27 ## install emacs very often. See the --help output for more details.
30 PUBLIC_LIBSRC_BINARIES='emacsclient etags ctags ebrowse'
32 AVOID="CVS -DIC README COPYING ChangeLog ~ [.]orig$ [.]rej$ Makefile$ Makefile.in$ makefile$ makefile.w32-in$ stamp-subdir [.]cvsignore [.]arch-ids [{]arch[}] [.][cho]$ make-docfile"
34 # Prune old binaries lying around in the source tree
35 PRUNE=no
36 # Re-install files even if they already exist
37 FORCE=no
38 # Command verbose flag
39 VERBOSE=''
41 me="`basename $0`"
43 # Install commands (if the user specifies the '--verbose' option, it is
44 # passed to these commands, so that feature only works if these commands
45 # implement it too)
46 LINK='cp -lf'
47 COPY='cp -f'
48 REMOVE='rm -r'
49 MKDIR='mkdir -p'
51 # Used to execute commands once we create them
52 EXEC='sh'
54 NAWK=/usr/bin/nawk
56 # avoid non-standard command output from non-C locales
57 unset LANG LC_ALL LC_MESSAGES
59 # Some messages
60 USAGE="Usage: $me [OPTION...] BUILD_TREE [PREFIX]"
61 TRY="Try '$me --help' for more information."
63 # Parse command-line options
64 while :; do
65 case "$1" in
66 -n|--dry-run)
67 EXEC=cat; shift;;
68 -p|--prune)
69 PRUNE=yes; shift;;
70 -P|--no-prune)
71 PRUNE=no; shift;;
72 --prune-only)
73 PRUNE=only; shift;;
74 -f|--force)
75 FORCE=yes; shift;;
76 -v|--verbose)
77 VERBOSE="-v"; shift;;
78 --help)
79 cat <<EOF
80 $USAGE
81 Install emacs quickly
83 -n, --dry-run print installation commands instead of
84 executing them
86 -f, --force install even files that haven't changed
87 -v, --verbose print messages describing what is done
89 -p, --prune prune old generated files
90 -P, --no-prune don't prune old generated files (default)
91 --prune-only prune old generated files, but don't install
93 --help display this help and exit
94 --version output version information and exit
96 $me install emacs "incrementally", that is, it will
97 install only those files that have changed since the last time it was
98 invoked, and remove any obsolete files from the installation
99 directories. It also uses hard-links into the source and build trees to
100 do the install, so it uses much less space than the default Makefile
101 install target; however, this also means that $me can
102 not install onto a disk partition other than the one on which the source
103 and build directories reside.
105 Optionally, $me can also remove old versions of
106 automatically generated files that are version-specific (such as the
107 versioned emacs executables in the 'src' directory).
108 The latter action is called "pruning", and
109 can be enabled using the '-p' or '--prune' options.
111 exit 0
113 --version)
114 cat <<EOF
115 $me 1.6
117 Written by Miles Bader <miles@gnu.org>
119 exit 0
121 -[!-]?*)
122 # split concatenated single-letter options apart
123 FIRST="$1"; shift
124 set -- `printf '%s\n' "$FIRST" | sed 's/-\(.\)\(.*\)/-\1 -\2/'` "$@"
127 printf '%s\n' >&2 "$me: unrecognized option '$1'"
128 printf '%s\n' >&2 "$TRY"
129 exit 1
132 break;
133 esac
134 done
136 LINK_CMD="$LINK $VERBOSE"
137 REMOVE_CMD="$REMOVE $VERBOSE"
139 case $# in
140 1) BUILD="$1";;
141 2) BUILD="$1"; prefix="$2";;
143 printf '%s\n' >&2 "$USAGE"
144 printf '%s\n' >&2 "$TRY"
145 exit 1
147 esac
149 if test ! -d "$BUILD"; then
150 printf '%s\n' >&2 "$me: $BUILD: Build tree not found"
151 exit 2
152 elif test ! -r "$BUILD/config.status"; then
153 printf '%s\n' >&2 \
154 "$me: $BUILD: Not a proper build tree, config.status not found"
155 exit 2
158 CONFIG_STATUS="$BUILD/config.status"
159 get_config_var ()
161 { sed -n "s/^S[[]\"$1\"[]]=\"\([^\"]*\)\"/\1/p" $CONFIG_STATUS | sed q | grep ''; } ||
162 { sed -n "s/^s\(.\)@$1@\1\(|#_!!_#|\)*\(.*\)\1.*$/\3/p" $CONFIG_STATUS | sed q | grep ''; } ||
164 printf '%s\n' >&2 \
165 "$me: $1: Configuration variable not found in $CONFIG_STATUS"
166 exit 4
170 test x"$SRC" = x && { SRC="`get_config_var srcdir`" || exit 4 ; }
171 test x"$prefix" = x && { prefix="`get_config_var prefix`" || exit 4 ; }
172 test x"$ARCH" = x && { ARCH="`get_config_var host`" || exit 4 ; }
174 VERSION=`
175 sed -n 's/^AC_INIT(emacs,[ ]*\([^ )]*\).*/\1/p' <$SRC/configure.ac
176 ` || exit 4
177 test -n "$VERSION" || { printf '%s\n' >&2 "$me: no version in configure.ac"; exit 4; }
179 DST_SHARE="$prefix/share/emacs/$VERSION"
180 DST_BIN="$prefix/bin"
181 DST_LIBEXEC="$prefix/libexec/emacs/$VERSION/$ARCH"
183 # There are various common places for the info dir to be, so try to
184 # use whatever's already there, defaulting to (and preferring)
185 # .../share/info.
187 DST_INFO=''
188 for D in "$prefix/share/info" "$prefix/info"; do
189 if test -d "$D"; then
190 DST_INFO="$D"
191 break
193 done
194 DST_INFO=${DST_INFO:-"$prefix/share/info"}
196 maybe_mkdir ()
198 if ! test -d "$1"; then
199 $MKDIR $VERBOSE "$1" 2>&1 | sed "s/^mkdir:/$me:/" 1>&2
203 maybe_mkdir "$DST_BIN"
204 maybe_mkdir "$DST_SHARE"
205 maybe_mkdir "$DST_SHARE/site-lisp"
206 maybe_mkdir "$DST_LIBEXEC"
207 maybe_mkdir "$DST_INFO"
209 ( # start of command-generating sub-shell
211 PRUNED=""
212 if test x"$PRUNE" != xno; then
213 for D in `ls -1t $BUILD/src/emacs-$VERSION.* | sed 1d`; do
214 printf '%s\n' "$REMOVE_CMD $D"
215 PRUNED="$PRUNED $D"
216 done
219 test x"$PRUNE" = xonly && exit 0
221 maybe_emit_copy ()
223 if test "$FORCE" = yes || ! cmp -s $1 $2; then
224 printf '%s\n' "$LINK_CMD $1 $2"
228 maybe_emit_copy $BUILD/src/emacs $DST_BIN/emacs
229 maybe_emit_copy $BUILD/src/emacs $DST_BIN/emacs-$VERSION
231 for F in $PUBLIC_LIBSRC_BINARIES; do
232 maybe_emit_copy $BUILD/lib-src/$F $DST_BIN/$F
233 done
235 if test x"$SRC" = x"$BUILD"; then
236 PFXS="$BUILD"
237 else
238 PFXS="$SRC $BUILD"
241 for SUBDIR in lisp leim etc lib-src info; do
242 # defaults
243 SHARED=no
244 FORCED=''
245 AVOID_PAT="`printf '%s\n' "($AVOID)" | tr ' ' '|'`"
247 # Set subdir-specific values
248 case $SUBDIR in
249 lisp|leim)
250 DST="$DST_SHARE/$SUBDIR"
252 etc)
253 DST="$DST_SHARE/$SUBDIR"
254 # COPYING is in the avoid list, but there should be a copy of it in
255 # the install etc dir, so make that here.
256 FORCED="$DST/COPYING"
258 lib-src)
259 DST="$DST_LIBEXEC"
260 AVOID_PAT="`printf '%s\n' "($AVOID ($PUBLIC_LIBSRC_BINARIES)\$)" | tr ' ' '|'`"
262 info)
263 DST="$DST_INFO"
264 SHARED=yes
266 esac
268 for PFX in $PFXS; do
269 if [ -d $PFX/$SUBDIR ]; then
270 for DIR in `(cd $PFX/$SUBDIR; find . -type d -print | sed 's@^./@@')`; do
271 if [ -d $DST/$DIR ]; then
272 printf '%s\n' "Directory $DST/$DIR exists"
273 else
274 printf '%s\n' "Directory $DST/$DIR non-existent"
275 if [ "`printf '%s\n' "$DIR" | grep -Ev "$AVOID_PAT"`" ]; then
276 maybe_mkdir $DST/$DIR
279 done
280 diff -sqr $PFX/$SUBDIR $DST
282 done | $NAWK '
283 BEGIN {
284 src_pat = "^'"$SRC"'/'"$SUBDIR"'/"
285 build_pat = "^'"$BUILD"'/'"$SUBDIR"'/"
286 dst_pat = "^'"$DST"'/"
287 dst_pfx = "'"$DST"'/"
288 avoid_pat = "'"$AVOID_PAT"'"
289 force = ("'"$FORCE"'" == "yes")
290 shared = ("'"$SHARED"'" == "yes")
291 init_bool_array(pruned, "'"$PRUNED"'")
292 init_bool_array(forced, "'"$FORCED"'")
294 function init_bool_array(array, string, a,k)
296 split (string, a)
297 for (k in a)
298 array[a[k]] = 1
300 function install(src, dst)
302 if (! (src in pruned)) {
303 cp[src] = dst;
304 from[dst] = src;
305 delete rm[dst];
308 function update(src, dst, copy)
310 if (src in pruned) {
311 rm[dst] = 1;
312 delete from[dst]
313 } else {
314 if (copy)
315 cp[src] = dst;
316 from[dst] = src;
317 delete rm[dst];
320 function uninstall(dst)
322 if (!(dst in from))
323 rm[dst] = 1;
325 /^Directory / {
326 if ($2 ~ avoid_pat) {
327 if ($NF == "exists")
328 uninstall($2)
329 } else
330 update(0, $2, 0)
331 next
333 /^Files / {
334 if ($4 ~ avoid_pat && !($4 in forced))
335 uninstall($4)
336 else if ($NF == "identical")
337 update($2, $4, force)
338 else
339 update($2, $4, 1)
340 next
342 /^Only / {
343 pfx = $3
344 sub (/:$/, "/", pfx)
346 if (pfx ~ dst_pat) {
347 if (! shared)
348 uninstall(pfx $4)
349 } else {
350 subdir = pfx
351 if (subdir ~ src_pat)
352 sub (src_pat, "", subdir)
353 else
354 sub (build_pat, "", subdir)
356 dst = dst_pfx subdir $4
357 if (! (dst ~ avoid_pat))
358 install(pfx $4, dst)
360 next
362 END {
363 for (f in rm)
364 print "'"$REMOVE_CMD"' " f
365 for (f in cp)
366 print "'"$LINK_CMD"' " f " " cp[f]
369 done
371 ) | eval $EXEC