1#!/usr/local/bin/bash
2
3# This script attempts to build all GAP packages contained in the current
4# directory. Normally, you should run this script from the 'pkg'
5# subdirectory of your GAP installation.
6
7# You can also run it from other locations, but then you need to tell the
8# script where your GAP root directory is, by passing it as an argument
9# to the script with '--with-gaproot='. By default, the script assumes that
10# the parent of the current working directory is the GAP root directory.
11
12# If arguments are added, then they are considered packages. In that case
13# only these packages will be built, and all others are ignored.
14
15# You need at least 'gzip', GNU 'tar', a C compiler, sed, pdftex to run this.
16# Some packages also need a C++ compiler.
17
18# Contact support@gap-system.org for questions and complaints.
19
20# Note, that this isn't and is not intended to be a sophisticated script.
21# Even if it doesn't work completely automatically for you, you may get
22# an idea what to do for a complete installation of GAP.
23
24set -e
25
26# Is someone trying to run us from inside the 'bin' directory?
27if [[ -f gapicon.bmp ]]
28then
29  error "This script must be run from inside the pkg directory" \
30        "Type: cd ../pkg; ../bin/BuildPackages.sh"
31fi
32
33CURDIR="$(pwd)"
34GAPROOT="$(cd .. && pwd)"
35COLORS=yes
36STRICT=no       # exit with non-zero exit code when encountering any failures
37PACKAGES=()
38
39# If output does not go into a terminal (but rather into a log file),
40# turn off colors.
41[[ -t 1 ]] || COLORS=no
42
43while [[ "$#" -ge 1 ]]; do
44  option="$1" ; shift
45  case "$option" in
46    --with-gaproot)   GAPROOT="$1"; shift ;;
47    --with-gaproot=*) GAPROOT=${option#--with-gaproot=}; ;;
48
49    --no-color)       COLORS=no ;;
50    --color)          COLORS=yes ;;
51
52    --no-strict)      STRICT=no ;;
53    --strict)         STRICT=yes ;;
54    --add-package-config-*)   typeset PACKAGE_CONFIG_ARGS_${option:21}="$1"; shift ;;
55
56    -*)               echo "ERROR: unsupported argument $option" ; exit 1;;
57    *)                PACKAGES+=("$option") ;;
58  esac
59done
60
61# If user specified no packages to build, build all packages in subdirectories.
62if [[ ${#PACKAGES[@]} == 0 ]]
63then
64  # Put package directory names into a bash array to avoid issues with
65  # spaces in filenames. This code will still break if there are newlines
66  # in the name.
67  old_IFS=$IFS
68  IFS=$'\n' PACKAGES=($(find . -maxdepth 2 -type f -name PackageInfo.g))
69  IFS=$old_IFS
70  PACKAGES=( "${PACKAGES[@]%/PackageInfo.g}" )
71fi
72
73# Some helper functions for printing user messages
74if [[ "x$COLORS" = xyes ]]
75then
76  # print notices in green, warnings in yellow, errors in read
77  notice()    { printf "\033[32m%s\033[0m\n" "$@" ; }
78  warning()   { printf "\033[33mWARNING: %s\033[0m\n" "$@" ; }
79  error()     { printf "\033[31mERROR: %s\033[0m\n" "$@" ; exit 1 ; }
80  std_error() { printf "\033[31m%s\033[0m\n" "$@" ; }
81else
82  notice()    { printf "%s\n" "$@" ; }
83  warning()   { printf "WARNING: %s\n" "$@" ; }
84  error()     { printf "ERROR: %s\n" "$@" ; exit 1 ; }
85  std_error() { printf "%s\n" "$@" ; }
86fi
87
88
89notice "Using GAP root $GAPROOT"
90
91# Check whether $GAPROOT is valid
92if [[ ! -f "$GAPROOT/sysinfo.gap" ]]
93then
94  error "$GAPROOT is not the root of a gap installation (no sysinfo.gap)" \
95        "Please provide the absolute path of your GAP root directory as" \
96        "first argument with '--with-gaproot=' to this script."
97fi
98
99# read in sysinfo
100source "$GAPROOT/sysinfo.gap"
101
102# detect whether GAP was built in 32bit mode
103# TODO: once all packages have adapted to the new build system,
104# this should no longer be necessary, as package build systems should
105# automatically adjust to 32bit mode.
106case "$GAP_ABI" in
107  32)
108    notice "Building with 32-bit ABI"
109    CONFIGFLAGS="CFLAGS=-m32 LDFLAGS=-m32 LOPTS=-m32 CXXFLAGS=-m32"
110    ;;
111  64)
112    notice "Building with 64-bit ABI"
113    CONFIGFLAGS=""
114    ;;
115  *)
116    error "Unsupported GAP ABI '$GAParch_abi'."
117    ;;
118esac
119
120
121LOGDIR=log
122mkdir -p "$LOGDIR"
123
124
125# Many package require GNU make. So use gmake if available,
126# for improved compatibility with *BSD systems where "make"
127# is BSD make, not GNU make.
128if hash gmake 2> /dev/null
129then
130  MAKE=gmake
131else
132  MAKE=make
133fi
134
135notice \
136"Attempting to build GAP packages." \
137"Note that many GAP packages require extra programs to be installed," \
138"and some are quite difficult to build. Please read the documentation for" \
139"packages which fail to build correctly, and only worry about packages" \
140"you require!"
141
142# print the given command plus arguments, single quoted, then run it
143echo_run() {
144  # when printf is given a format string with only one format specification,
145  # it applies that format string to each argument in sequence
146  notice "Running $(printf "'%s' " "$@")"
147  "$@"
148}
149
150build_fail() {
151  echo ""
152  warning "Failed to build $PKG"
153  echo "$PKG" >> "$LOGDIR/fail.log"
154  if [[ $STRICT = yes ]]
155  then
156    exit 1
157  fi
158}
159
160run_configure_and_make() {
161  # We want to know if this is an autoconf configure script
162  # or not, without actually executing it!
163  if [[ -f autogen.sh && ! -f configure ]]
164  then
165    ./autogen.sh
166  fi
167  if [[ -f "configure" ]]
168  then
169    if grep Autoconf ./configure > /dev/null
170    then
171      local PKG_NAME=$($GAPROOT/gap -q -T -A <<GAPInput
172Read("PackageInfo.g");
173Print(GAPInfo.PackageInfoCurrent.PackageName);
174GAPInput
175)
176      local CONFIG_ARGS_FLAG_NAME="PACKAGE_CONFIG_ARGS_${PKG_NAME}"
177      echo_run ./configure --with-gaproot="$GAPROOT" $CONFIGFLAGS ${!CONFIG_ARGS_FLAG_NAME}
178      echo_run "$MAKE" clean
179    else
180      echo_run ./configure "$GAPROOT"
181      echo_run "$MAKE" clean
182      echo_run ./configure "$GAPROOT"
183    fi
184    echo_run "$MAKE"
185  else
186    notice "No building required for $PKG"
187  fi
188}
189
190build_one_package() {
191  # requires one argument which is the package directory
192  PKG="$1"
193  echo ""
194  date
195  echo ""
196  notice "==== Checking $PKG"
197  (  # start subshell
198  set -e
199  cd "$CURDIR/$PKG"
200  case "$PKG" in
201    # All but the last lines should end by '&&', otherwise (for some reason)
202    # some packages that fail to build will not get reported in the logs.
203    atlasrep*)
204      chmod 1777 datagens dataword
205    ;;
206
207    NormalizInterface*)
208      ./build-normaliz.sh "$GAPROOT" && \
209      run_configure_and_make
210    ;;
211
212    pargap*)
213      echo_run ./configure --with-gap="$GAPROOT" && \
214      echo_run "$MAKE" && \
215      cp bin/pargap.sh "$GAPROOT/bin" && \
216      rm -f ALLPKG
217    ;;
218
219    xgap*)
220      echo_run ./configure --with-gaproot="$GAPROOT" && \
221      echo_run "$MAKE" && \
222      rm -f "$GAPROOT/bin/xgap.sh" && \
223      cp bin/xgap.sh "$GAPROOT/bin"
224    ;;
225
226    simpcomp*)
227      # Old versions of simpcomp were not setting the executable
228      # bit for some files; they also were not copying the bistellar
229      # executable to the right place
230      (chmod a+x configure depcomp install-sh missing || :) && \
231      run_configure_and_make && \
232      mkdir -p bin && test -x bin/bistellar || mv bistellar bin
233    ;;
234
235    *)
236      run_configure_and_make
237    ;;
238  esac
239  ) || build_fail
240}
241
242date >> "$LOGDIR/fail.log"
243for PKG in "${PACKAGES[@]}"
244do
245  # cut off the ending slash (if exists)
246  PKG="${PKG%/}"
247  # cut off everything before the first slash to only keep the package name
248  # (these two commands are mainly to accomodate the logs better,
249  # as they make no difference with changing directories)
250  PKG="${PKG##*/}"
251  if [[ -e "$CURDIR/$PKG/PackageInfo.g" ]]
252  then
253    (build_one_package "$PKG" \
254     > >(tee "$LOGDIR/$PKG.out") \
255    2> >(while read line
256         do \
257           std_error "$line"
258         done \
259         > >(tee "$LOGDIR/$PKG.err" >&2) \
260         ) \
261    )> >(tee "$LOGDIR/$PKG.log" ) 2>&1
262
263    # remove superfluous log files if there was no error message
264    if [[ ! -s "$LOGDIR/$PKG.err" ]]
265    then
266      rm -f "$LOGDIR/$PKG.err"
267      rm -f "$LOGDIR/$PKG.out"
268    fi
269
270    # remove log files if package needed no compilation
271    if [[ "$(grep -c 'No building required for' $LOGDIR/$PKG.log)" -ge 1 ]]
272    then
273      rm -f "$LOGDIR/$PKG.err"
274      rm -f "$LOGDIR/$PKG.out"
275      rm -f "$LOGDIR/$PKG.log"
276    fi
277  else
278    echo
279    warning "$PKG does not seem to be a package directory, skipping"
280  fi
281done
282
283echo "" >> "$LOGDIR/fail.log"
284echo ""
285notice "Packages which failed to build are in ./$LOGDIR/fail.log"
286