#!/bin/sh ### make-dist: create an Emacs distribution tar file from current srcdir ## Copyright (C) 1995, 1997-1998, 2000-2023 Free Software Foundation, ## Inc. ## 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 . ### Commentary: ## This basically creates a duplicate directory structure, and then ## hard links into it only those files that should be distributed. ## This means that if you add a file with an odd name, you should make ## sure that this script will include it. ### Code: progname="$0" ### Exit if a command fails. #set -e ### Print out each line we read, for debugging's sake. #set -v LANGUAGE=C LC_ALL=C LC_MESSAGES= LANG= export LANGUAGE LC_ALL LC_MESSAGES LANG ## Remove unnecessary restrictions on file access. umask 022 update=yes check=yes clean_up=no make_tar=no default_gzip=gzip newer="" with_info=yes changelog=yes verbose=no while [ $# -gt 0 ]; do case "$1" in ## This option tells make-dist to delete the staging directory ## when done. It is useless to use this unless you make a tar file. "--clean-up" ) clean_up=yes ;; ## This option tells make-dist to make a tar file. "--tar" ) make_tar=yes ;; ## This option tells make-dist not to recompile or do analogous things. "--no-update" ) update=no ;; ## This option says don't check for bad file names, etc. "--no-check" ) check=no ;; "--no-changelog" ) changelog=no ;; ## This options tells make-dist to skip the info files. This can ## be useful for creating a tarball purely for test purposes. "--no-info" ) with_info=no ;; ## This option tells make-dist to make the distribution normally, then ## remove all files older than the given timestamp file. This is useful ## for creating incremental or patch distributions. "--newer") newer="$2" new_extension=".new" shift ;; ## This option tells make-dist to use 'bzip2' instead of gzip. "--bzip2") default_gzip="bzip2" ;; ## Same with xz. "--xz") default_gzip="xz" ;; "--no-compress") default_gzip="cat" ;; "--snapshot") clean_up=yes make_tar=yes update=no ;; "--tests"|"--no-tests") echo "The option $1 no longer does anything" ;; "--verbose") verbose=yes ;; "--help") printf '%s\n' "Usage: ${progname} [options]" echo "" echo " --bzip2 use bzip2 instead of gzip" echo " --clean-up delete staging directories when done" echo " --xz use xz instead of gzip" echo " --no-compress don't compress" echo " --newer=TIME don't include files older than TIME" echo " --no-check don't check for bad file names etc." echo " --no-update don't recompile or do analogous things" echo " --no-changelog don't generate the top-level ChangeLog" echo " --no-info don't include info files" echo " --snapshot same as --clean-up --no-update --tar" echo " --tar make a tar file" echo " --verbose noisier output" echo "" exit 0 ;; * ) printf '%s\n' "${progname}: Unrecognized argument: $1" >&2 exit 1 ;; esac shift done ### Make sure we're running in the right place. if [ ! -d src -o ! -f src/lisp.h -o ! -d lisp -o ! -f lisp/subr.el ]; then printf '%s\n' "${progname}: Can't find 'src/lisp.h' and 'lisp/subr.el'." >&2 printf '%s\n' "${progname} must be run in the top directory of the Emacs" >&2 printf '%s\n' "distribution tree. cd to that directory and try again." >&2 exit 1 fi ### Find where to run Emacs. ### (Accept only absolute file names.) if [ $update = yes ]; then if [ -f src/emacs ]; then EMACS=`pwd`/src/emacs else case $EMACS in /*) ;; *) if [ ! -f "$EMACS" ]; then printf '%s\n' "$0: You must set the EMACS environment variable " \ "to an absolute file name." 2>&1 exit 1 fi;; esac fi fi ### Find out which version of Emacs this is. version=` sed -n 's/^AC_INIT(\[GNU Emacs],[ ]*\[\([^]]*\).*/\1/p' &2 exit 1 fi echo Version number is "$version" if [ $update = yes ]; then if ! grep -q "tree holds version *${version}" README; then echo "WARNING: README has the wrong version number" echo "Consider running M-x set-version from admin/admin.el" sleep 5 fi fi ### Make sure we don't already have a directory emacs-${version}. emacsname="emacs-${version}${new_extension}" if [ -d ${emacsname} ] then echo Directory "${emacsname}" already exists >&2 exit 1 fi ### Make sure the subdirectory is available. tempparent="make-dist.tmp.$$" if [ -d ${tempparent} ]; then printf '%s\n' "${progname}: staging directory '${tempparent}' already exists. Perhaps a previous invocation of '${progname}' failed to clean up after itself. Check that directories whose names are of the form 'make-dist.tmp.NNNNN' don't contain any important information, remove them, and try again." >&2 exit 1 fi if [ $check = yes ]; then echo "Sanity checking (use --no-check to disable this)..." error=no temp_el=/tmp/make-dist.tmp.$$ temp_elc=$temp_el.1 temp_elelc=$temp_el.2 temp_elcel=$temp_el.3 ls -1 lisp/[a-zA-Z]*.el lisp/[a-z]*/[a-zA-Z0-9]*.el \ lisp/[a-z]*/[a-z]*/[a-zA-Z0-9]*.el \ lisp/[a-z]*/[a-z]*/[a-z]*/[a-zA-Z0-9]*.el > $temp_el ls -1 lisp/[a-zA-Z]*.elc lisp/[a-z]*/[a-zA-Z0-9]*.elc \ lisp/[a-z]*/[a-z]*/[a-zA-Z0-9]*.elc \ lisp/[a-z]*/[a-z]*/[a-z]*/[a-zA-Z0-9]*.elc > $temp_elc ## Check for .elc files with no corresponding .el file. sed 's/\.el$/.elc/' $temp_el > $temp_elelc bogosities=`comm -13 $temp_elelc $temp_elc` if [ x"${bogosities}" != x"" ]; then error=yes echo "The following .elc files have no corresponding .el files:" echo "${bogosities}" fi ### Check for .el files with no corresponding .elc file. sed 's/\.elc$/.el/' $temp_elc > $temp_elcel losers=`comm -23 $temp_el $temp_elcel` bogosities= while read elc; do el=`echo $elc | sed 's/c$//'` [ -r "$el" ] || continue [ "$elc" -nt "$el" ] || bogosities="$bogosities $elc" done < $temp_elc if [ x"${bogosities}" != x"" ]; then error=yes echo "The following .elc files are older than their .el files:" echo "${bogosities}" fi rm -f $temp_el* bogosities= for file in $losers; do grep -q "^;.*no-byte-compile: t" "$file" && continue case $file in site-init.el | site-load.el | site-start.el | default.el) continue ;; esac bogosities="$file $bogosities" done if [ x"${bogosities}" != x"" ]; then error=yes echo "The following .el files have no corresponding .elc files:" echo "${bogosities}" fi ## This is only a crude check, eg it does not handle .info ## files with multiple .texi source files. find doc -name '*.texi' > $temp_el bogosities= while read texi; do info=`sed -n 's/^@setfilename //p' $texi | sed 's|.*info/||'` [ x"${info}" != x"" ] || continue info=info/$info [ -r "$info" ] || continue [ "$info" -nt "$texi" ] || bogosities="$bogosities $info" done < $temp_el rm -f $temp_el if [ x"${bogosities}" != x"" ]; then error=yes echo "The following .info files are older than their .texi files:" echo "${bogosities}" fi ## Is this a release? case $version in [1-9][0-9].[0-9]) if [ -r ChangeLog ]; then if ! grep -q "Version $version released" ChangeLog; then echo "No release notice in ChangeLog" error=yes fi else echo "A release must have a ChangeLog" error=yes fi ;; esac if [ $error = yes ]; then echo "Failed checks" >&2 exit 1 fi fi if [ $update = yes ]; then ## Make sure configure is newer than configure.ac, etc. ## It is better to let autoreconf do what is needed than ## for us to try and duplicate all its checks. echo "Running autoreconf" autoreconf -i -I m4 || { x=$?; echo Autoreconf FAILED! >&2; exit $x; } if [ "$make_info" = yes ] ; then echo "Updating Info files" make info fi echo "Updating finder, custom and autoload data" (cd lisp && make updates EMACS="$EMACS") echo "Updating leim-list.el" (cd leim && make leim-list.el EMACS="$EMACS") echo "Recompiling Lisp files" $EMACS -batch -f batch-byte-recompile-directory lisp fi # $update = yes if [ "$changelog" = yes ] && [ -r .git ]; then top_level_ChangeLog=ChangeLog else top_level_ChangeLog= fi # Files to distribute that might not be under version control. # Don't distribute site-init.el, site-load.el, or default.el. possibly_non_vc_files=" $top_level_ChangeLog MANIFEST aclocal.m4 configure admin/charsets/jisx2131-filter src/config.in exec/configure exec/config.h.in "$( find admin doc etc lisp \ \( -name '*.el' -o -name '*.elc' -o -name '*.map' -o -name '*.stamp' \ -o -name '*.texi' -o -name '*.tex' -o -name '*.txt' -o -name '*.pdf' \) \ ! -name 'site-init*' ! -name 'site-load*' ! -name 'default*' ) || exit if [ $with_info = yes ]; then info_files="info/dir $(echo info/*.info)" || exit else info_files= fi echo "Creating staging directory: '${tempparent}'" mkdir ${tempparent} || exit tempdir="${tempparent}/${emacsname}" manifest=MANIFEST [ -f $manifest ] || manifest=${tempparent}/MANIFEST # If Git is in use update the file MANIFEST, which can substitute for # 'git ls-files' later (e.g., after extraction from a tarball). # Otherwise, rely on the existing MANIFEST, which should be maintained some # other way when adding or deleting a distributed file while not using Git. # TODO: maybe this should ignore $update, and always update MANIFEST # if .git is present. # Filter out the files in msdos/autogen/, as they aren't useful in the # tarball, and get in the way during the build of the MSDOS port. if ( [ $update = yes ] || [ ! -f $manifest ] ) && [ -r .git ]; then echo "Updating $manifest" git ls-files | sed -e '/^msdos\/autogen\//d' > $manifest || exit printf '%s\n' $possibly_non_vc_files $info_files >>$manifest || exit sort -u -o $manifest $manifest || exit fi <$manifest || exit ### This trap ensures that the staging directory will be cleaned up even ### when the script is interrupted in mid-career. if [ "${clean_up}" = yes ]; then trap "echo 'Cleaning up the staging directory'; rm -rf ${tempparent}" EXIT fi echo "Creating top directory: '${tempdir}'" if [ $verbose = yes ] && (mkdir --verbose ${tempdir}) >/dev/null 2>&1; then mkdir_verbose='mkdir --verbose' else mkdir $tempdir || exit mkdir_verbose="mkdir" fi # file_to_skip is normally empty to link every file, # but it can be 'ChangeLog' if we do not want to link the # top-level ChangeLog. file_to_skip= if [ "$changelog" = yes ]; then if test -r .git; then ## When making a release or pretest the ChangeLog should already ## have been created and edited as needed. Don't ignore it. if [ -r ChangeLog ] && [ ! -L ChangeLog ]; then echo "Using existing top-level ChangeLog" else echo "Making top-level ChangeLog" make ChangeLog CHANGELOG=${tempdir}/ChangeLog || \ { x=$?; echo "make ChangeLog FAILED (try --no-changelog?)" >&2; exit $x; } file_to_skip=ChangeLog fi else echo "No repository, so omitting top-level ChangeLog" fi fi echo "Creating subdirectories" MANIFEST_subdir_sed=' $a\ '$tempdir'/info\ '$tempdir'/site-lisp s,[^/]*$,, s,/$,, /^$/d s,^,'$tempdir'/, ' tempsubdirs=$(sed "$MANIFEST_subdir_sed" $manifest | sort -u) $mkdir_verbose -p $tempsubdirs || exit echo "Making links to files" while read file; do case $file in MANIFEST) ln $manifest $tempdir/MANIFEST || exit ;; $file_to_skip) continue ;; *) ln "$file" $tempdir/"$file" || exit ;; esac done <$manifest if [ "${newer}" ]; then printf '%s\n' "Removing files older than $newer" ## We remove .elc files unconditionally, on the theory that anyone picking ## up an incremental distribution already has a running Emacs to byte-compile ## them with. find ${tempdir} \( -name '*.elc' -o ! -newer "${newer}" \) \ -exec rm -f {} \; || exit fi if [ "${make_tar}" = yes ]; then echo "Looking for $default_gzip" found=0 temppath=`printf '%s\n' "$PATH" | sed -e 's/^:/.:/' -e 's/::/:.:/g' -e 's/:$/:./' -e 's/:/ /g' ` for dir in ${temppath}; do [ -x "${dir}"/$default_gzip ] || continue found=1; break done if [ "$found" = "0" ]; then echo "WARNING: '$default_gzip' not found, will not compress" >&2 default_gzip="cat" fi case "${default_gzip}" in bzip2) gzip_extension=.bz2 ;; xz) gzip_extension=.xz ;; gzip) gzip_extension=.gz ; default_gzip="gzip --best --no-name";; *) gzip_extension= ;; esac echo "Creating tar file" taropt='--numeric-owner --owner=0 --group=0 --mode=go+u,go-w' tar -H ustar -cf /dev/null $tempdir/src/lisp.h 2>/dev/null && taropt="$taropt -H ustar" tar --sort=name -cf /dev/null $tempdir/src/lisp.h 2>/dev/null && taropt="$taropt --sort=name" [ "$verbose" = "yes" ] && taropt="$taropt --verbose" (cd $tempparent && case $default_gzip in cat) tar $taropt -cf - $emacsname;; *) if tar $taropt -cf /dev/null --use-compress-program="$default_gzip" \ $emacsname/src/lisp.h > /dev/null 2>&1 then tar $taropt -cf - --use-compress-program="$default_gzip" $emacsname else tar $taropt -cf $emacsname.tar $emacsname && $default_gzip <$emacsname.tar fi;; esac ) >$emacsname.tar"$gzip_extension" || exit fi ## Why are we deleting the staging directory if clean_up is no? if [ "${clean_up}" != yes ]; then (cd ${tempparent} && mv ${emacsname} ..) && rm -rf ${tempparent} fi # Local Variables: # sh-basic-offset: 2 # End: