#!/bin/bash # -*-mode: sh; coding: latin-1-unix; fill-column: 79-*- # # maketool -- Run make on all available CPUs, tee'd # # "jobserver unavailable" warnings: # Most likely result from a nested call to make, when the parent make did # not realize that the child process it was invoking was actually a GNU # make program. In the parent makefile the sub-make must be started with a # "+" prefix. See the GNU make manual for more information. # # Installation: # This is a portable shell script that works on any UN*X and Windows # (Cygwin) system. Simply copy this script to your path, e.g. to # "$HOME/bin". # # Prerequisites: # sh, GNU make, egrep, wc, tee, sed # ######## # $Author: Andreas Spindler$ # $Maintained at: http://www.visualco.de$ script=`basename $0` ######################################################################## # Environment and options # MAKE=`which make`||Panic 'make: not found' # TODO: 1st lookup gmake SED=`which sed`||Panic 'sed: not found' TEE=`which tee` opts="-k" optlog=make.log optjobctl=1 function Usage { cat <&2 Usage: $script [regular-gnu-make-argument]... Synopsis: $ $script -k all Venue: Use "$script" instead of "make" to run GNU make. "$script" is a small shell-script that runs make with automatic job-control. All output will be tee'd to "$optlog". Automatic job-control: The "--jobs=N" parameter allows GNU make to run commands simultaneously. On a multiprocessor machine dependencies are then dissolved significantly faster, and targets are build parallely. "$script" will determine the number of available CPUs on Linux, MacOS, Solaris (SunOS) and BDS. Note that to run make efficiently (i.e. with the maximum number of jobs) the number of available CPUs must be determined. There's no portable way to get this important ratio, and GNU make also does not know the max. number of jobs. Multiple jobs: - In recursive make invocations the parent make and all sub-makes will communicate to ensure that there are only N jobs running at the same time between them all. The sub-make shall be started with a "+" prefix. - When commands are not serially executed messages from different commands may be interspersed. - When more than one process reads from standard input this can break pipes. - If make terminates for any reason (including a signal) with child processes running, it waits for them to finish before actually exiting. - Consider specifying --max-load=LIMIT. GNU make then checks the current system load average; make waits until it goes below the limit, or until all jobs finish. "$script" will not set this option by itself, but passes it to make like all arguments. EOF exit 0 } function Panic { cat <&2 Panic! in shell $$, pipe $?, terminal `tty`: $* $script exits with -1. EOF exit -1 } while [ $# -gt 0 ]; do case "$1" in -h|--help) Usage;; -j|--jobs) optjobctl=;; esac opts="$opts $1" shift done ######################################################################## # Main code # # Try to evaluate $ncpus # # Resources: # # ) # if [ -n "$optjobctl" ]; then case `uname -s` in Darwin) ncpus=`sysctl -n hw.activecpu`;; *bsd) ncpus=`sysctl -n hw.ncpu`;; CYGWIN*) [ -f /proc/cpuinfo ] && ncpus=`grep -i '^processor[[:space:]]*:' /proc/cpuinfo|wc -l`;; Linux) [ -f /proc/cpuinfo ] && ncpus=`grep -i '^processor[[:space:]]*:' /proc/cpuinfo|wc -l`;; SunOS) ncpus=`/usr/sbin/psrinfo|wc -l` ;; esac fi echo "$script: *** Found $ncpus CPUs" if [ -n "$ncpus" ]; then if [ $ncpus -gt 1 ]; then opts="$opts -j $ncpus" fi fi # Run make under tee. Reduce blank sequences in $opts into single blanks. Fail # for sub-makes, since $optlog then is already tee'd and the jobserver is busy. MK="$MAKE $opts" MK=`echo -n $MK|$SED -e 's/[ \t\r\n]+/ /g'` echo "$script: *** $MK [$optlog]" if [ -n "$MAKELEVEL" ]; then if [ $MAKELEVEL -gt 0 ]; then # "0" for top-level make Panic "cannot run as sub-make (MAKELEVEL=$MAKELEVEL)" fi fi if [ -n "$TEE" ]; then $MK $* 2>&1 | $TEE $optlog else $MK $* 2>&1 > $optlog fi # Local Variables: # coding: iso-8859-1-unix # fill-column: 79 # End: # maketool ends here