build.sh revision 1.171.4.2
1#! /usr/bin/env sh
2#	$NetBSD: build.sh,v 1.171.4.2 2008/01/09 01:19:18 matt Exp $
3#
4# Copyright (c) 2001-2005 The NetBSD Foundation, Inc.
5# All rights reserved.
6#
7# This code is derived from software contributed to The NetBSD Foundation
8# by Todd Vierling and Luke Mewburn.
9#
10# Redistribution and use in source and binary forms, with or without
11# modification, are permitted provided that the following conditions
12# are met:
13# 1. Redistributions of source code must retain the above copyright
14#    notice, this list of conditions and the following disclaimer.
15# 2. Redistributions in binary form must reproduce the above copyright
16#    notice, this list of conditions and the following disclaimer in the
17#    documentation and/or other materials provided with the distribution.
18# 3. All advertising materials mentioning features or use of this software
19#    must display the following acknowledgement:
20#        This product includes software developed by the NetBSD
21#        Foundation, Inc. and its contributors.
22# 4. Neither the name of The NetBSD Foundation nor the names of its
23#    contributors may be used to endorse or promote products derived
24#    from this software without specific prior written permission.
25#
26# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36# POSSIBILITY OF SUCH DAMAGE.
37#
38#
39# Top level build wrapper, for a system containing no tools.
40#
41# This script should run on any POSIX-compliant shell.  If the
42# first "sh" found in the PATH is a POSIX-compliant shell, then
43# you should not need to take any special action.  Otherwise, you
44# should set the environment variable HOST_SH to a POSIX-compliant
45# shell, and invoke build.sh with that shell.  (Depending on your
46# system, one of /bin/ksh, /usr/local/bin/bash, or /usr/xpg4/bin/sh
47# might be a suitable shell.)
48#
49
50progname=${0##*/}
51toppid=$$
52results=/dev/null
53trap "exit 1" 1 2 3 15
54
55bomb()
56{
57	cat >&2 <<ERRORMESSAGE
58
59ERROR: $@
60*** BUILD ABORTED ***
61ERRORMESSAGE
62	kill ${toppid}		# in case we were invoked from a subshell
63	exit 1
64}
65
66
67statusmsg()
68{
69	${runcmd} echo "===> $@" | tee -a "${results}"
70}
71
72warning()
73{
74	statusmsg "Warning: $@"
75}
76
77# Find a program in the PATH, and print the result.  If not found,
78# print a default.  If $2 is defined (even if it is an empty string),
79# then that is the default; otherwise, $1 is used as the default.
80find_in_PATH()
81{
82	local prog="$1"
83	local result="${2-"$1"}"
84	local oldIFS="${IFS}"
85	local dir
86	IFS=":"
87	for dir in ${PATH}; do
88		if [ -x "${dir}/${prog}" ]; then
89			result="${dir}/${prog}"
90			break
91		fi
92	done
93	IFS="${oldIFS}"
94	echo "${result}"
95}
96
97# Try to find a working POSIX shell, and set HOST_SH to refer to it.
98# Assumes that uname_s, uname_m, and PWD have been set.
99set_HOST_SH()
100{
101	# Even if ${HOST_SH} is already defined, we still do the
102	# sanity checks at the end.
103
104	# Solaris has /usr/xpg4/bin/sh.
105	#
106	[ -z "${HOST_SH}" ] && [ x"${uname_s}" = x"SunOS" ] && \
107		[ -x /usr/xpg4/bin/sh ] && HOST_SH="/usr/xpg4/bin/sh"
108
109	# Try to get the name of the shell that's running this script,
110	# by parsing the output from "ps".  We assume that, if the host
111	# system's ps command supports -o comm at all, it will do so
112	# in the usual way: a one-line header followed by a one-line
113	# result, possibly including trailing white space.  And if the
114	# host system's ps command doesn't support -o comm, we assume
115	# that we'll get an error message on stderr and nothing on
116	# stdout.  (We don't try to use ps -o 'comm=' to suppress the
117	# header line, because that is less widely supported.)
118	#
119	# If we get the wrong result here, the user can override it by
120	# specifying HOST_SH in the environment.
121	#
122	[ -z "${HOST_SH}" ] && HOST_SH="$(
123		(ps -p $$ -o comm | sed -ne '2s/[ \t]*$//p') 2>/dev/null )"
124
125	# If nothing above worked, use "sh".  We will later find the
126	# first directory in the PATH that has a "sh" program.
127	#
128	[ -z "${HOST_SH}" ] && HOST_SH="sh"
129
130	# If the result so far is not an absolute path, try to prepend
131	# PWD or search the PATH.
132	#
133	case "${HOST_SH}" in
134	/*)	:
135		;;
136	*/*)	HOST_SH="${PWD}/${HOST_SH}"
137		;;
138	*)	HOST_SH="$(find_in_PATH "${HOST_SH}")"
139		;;
140	esac
141
142	# If we don't have an absolute path by now, bomb.
143	#
144	case "${HOST_SH}" in
145	/*)	:
146		;;
147	*)	bomb "HOST_SH=\"${HOST_SH}\" is not an absolute path."
148		;;
149	esac
150
151	# If HOST_SH is not executable, bomb.
152	#
153	[ -x "${HOST_SH}" ] ||
154	    bomb "HOST_SH=\"${HOST_SH}\" is not executable."
155}
156
157initdefaults()
158{
159	makeenv=
160	makewrapper=
161	makewrappermachine=
162	runcmd=
163	operations=
164	removedirs=
165
166	[ -d usr.bin/make ] || cd "$(dirname $0)"
167	[ -d usr.bin/make ] ||
168	    bomb "build.sh must be run from the top source level"
169	[ -f share/mk/bsd.own.mk ] ||
170	    bomb "src/share/mk is missing; please re-fetch the source tree"
171
172	# Find information about the build platform.  Note that "uname -p"
173	# is not part of POSIX, but NetBSD's uname -p prints MACHINE_ARCH,
174	# while uname -m prints MACHINE.
175	#
176	uname_s=$(uname -s 2>/dev/null)
177	uname_r=$(uname -r 2>/dev/null)
178	uname_m=$(uname -m 2>/dev/null)
179	uname_p=$(uname -p 2>/dev/null || uname -m 2>/dev/null)
180
181	# If $PWD is a valid name of the current directory, POSIX mandates
182	# that pwd return it by default which causes problems in the
183	# presence of symlinks.  Unsetting PWD is simpler than changing
184	# every occurrence of pwd to use -P.
185	#
186	# XXX Except that doesn't work on Solaris. Or many Linuces.
187	#
188	unset PWD
189	TOP=$(/bin/pwd -P 2>/dev/null || /bin/pwd 2>/dev/null)
190
191	# The user can set HOST_SH in the environment, or we try to
192	# guess an appropriate value.  Then we set several other
193	# variables from HOST_SH.
194	#
195	set_HOST_SH
196	setmakeenv HOST_SH "${HOST_SH}"
197	setmakeenv BSHELL "${HOST_SH}"
198	setmakeenv CONFIG_SHELL "${HOST_SH}"
199
200	# Set defaults.
201	#
202	toolprefix=nb
203
204	# Some systems have a small ARG_MAX.  -X prevents make(1) from
205	# exporting variables in the environment redundantly.
206	#
207	case "${uname_s}" in
208	Darwin | FreeBSD | CYGWIN*)
209		MAKEFLAGS=-X
210		;;
211	*)
212		MAKEFLAGS=
213		;;
214	esac
215
216	# do_{operation}=true if given operation is requested.
217	#
218	do_expertmode=false
219	do_rebuildmake=false
220	do_removedirs=false
221	do_tools=false
222	do_obj=false
223	do_build=false
224	do_distribution=false
225	do_release=false
226	do_kernel=false
227	do_releasekernel=false
228	do_install=false
229	do_sets=false
230	do_sourcesets=false
231	do_syspkgs=false
232	do_iso_image=false
233	do_iso_image_source=false
234	do_params=false
235
236	# Create scratch directory
237	#
238	tmpdir="${TMPDIR-/tmp}/nbbuild$$"
239	mkdir "${tmpdir}" || bomb "Cannot mkdir: ${tmpdir}"
240	trap "cd /; rm -r -f \"${tmpdir}\"" 0
241	results="${tmpdir}/build.sh.results"
242
243	# Set source directories
244	#
245	setmakeenv NETBSDSRCDIR "${TOP}"
246
247	# Find the version of NetBSD
248	#
249	DISTRIBVER="$(${HOST_SH} ${TOP}/sys/conf/osrelease.sh)"
250
251	# Set various environment variables to known defaults,
252	# to minimize (cross-)build problems observed "in the field".
253	#
254	unsetmakeenv INFODIR
255	unsetmakeenv LESSCHARSET
256	setmakeenv LC_ALL C
257}
258
259getarch()
260{
261	# Translate some MACHINE name aliases (known only to build.sh)
262	# into proper MACHINE and MACHINE_ARCH names.  Save the alias
263	# name in makewrappermachine.
264	#
265	case "${MACHINE}" in
266
267	evbarm-e[bl])
268		makewrappermachine=${MACHINE}
269		# MACHINE_ARCH is "arm" or "armeb", not "armel"
270		MACHINE_ARCH=arm${MACHINE##*-}
271		MACHINE_ARCH=${MACHINE_ARCH%el}
272		MACHINE=${MACHINE%-e[bl]}
273		;;
274
275	evbmips-e[bl]|sbmips-e[bl])
276		makewrappermachine=${MACHINE}
277		MACHINE_ARCH=mips${MACHINE##*-}
278		MACHINE=${MACHINE%-e[bl]}
279		;;
280
281	evbmips64-e[bl]|sbmips64-e[bl])
282		makewrappermachine=${MACHINE}
283		MACHINE_ARCH=mips64${MACHINE##*-}
284		MACHINE=${MACHINE%64-e[bl]}
285		;;
286
287	evbsh3-e[bl])
288		makewrappermachine=${MACHINE}
289		MACHINE_ARCH=sh3${MACHINE##*-}
290		MACHINE=${MACHINE%-e[bl]}
291		;;
292
293	esac
294
295	# Translate a MACHINE into a default MACHINE_ARCH.
296	#
297	case "${MACHINE}" in
298
299	acorn26|acorn32|cats|hpcarm|iyonix|netwinder|shark|zaurus)
300		MACHINE_ARCH=arm
301		;;
302
303	evbarm)		# unspecified MACHINE_ARCH gets LE
304		MACHINE_ARCH=${MACHINE_ARCH:=arm}
305		;;
306
307	hp700)
308		MACHINE_ARCH=hppa
309		;;
310
311	sun2)
312		MACHINE_ARCH=m68000
313		;;
314
315	amiga|atari|cesfic|hp300|luna68k|mac68k|mvme68k|news68k|next68k|sun3|x68k)
316		MACHINE_ARCH=m68k
317		;;
318
319	evbmips|sbmips)		# no default MACHINE_ARCH
320		;;
321
322	ews4800mips|mipsco|newsmips|sgimips)
323		MACHINE_ARCH=mipseb
324		;;
325
326	algor|arc|cobalt|hpcmips|playstation2|pmax)
327		MACHINE_ARCH=mipsel
328		;;
329
330	pc532)
331		MACHINE_ARCH=ns32k
332		;;
333
334	evbppc64|macppc64)
335		makewrappermachine=${MACHINE}
336		MACHINE=${MACHINE%64}
337		MACHINE_ARCH=powerpc64
338		;;
339
340	amigappc|bebox|evbppc|ibmnws|macppc|mvmeppc|ofppc|prep|rs6000|sandpoint)
341		MACHINE_ARCH=powerpc
342		;;
343
344	evbsh3)			# no default MACHINE_ARCH
345		;;
346
347	mmeye)
348		MACHINE_ARCH=sh3eb
349		;;
350
351	dreamcast|hpcsh|landisk)
352		MACHINE_ARCH=sh3el
353		;;
354
355	amd64)
356		MACHINE_ARCH=x86_64
357		;;
358
359	alpha|i386|sparc|sparc64|vax|ia64)
360		MACHINE_ARCH=${MACHINE}
361		;;
362
363	*)
364		bomb "Unknown target MACHINE: ${MACHINE}"
365		;;
366
367	esac
368}
369
370validatearch()
371{
372	# Ensure that the MACHINE_ARCH exists (and is supported by build.sh).
373	#
374	case "${MACHINE_ARCH}" in
375
376	alpha|arm|armeb|hppa|i386|m68000|m68k|mipse[bl]|mips64e[bl]|ns32k|powerpc|powerpc64|sh[35]e[bl]|sparc|sparc64|vax|x86_64|ia64)
377		;;
378
379	"")
380		bomb "No MACHINE_ARCH provided"
381		;;
382
383	*)
384		bomb "Unknown target MACHINE_ARCH: ${MACHINE_ARCH}"
385		;;
386
387	esac
388
389	# Determine valid MACHINE_ARCHs for MACHINE
390	#
391	case "${MACHINE}" in
392
393	evbarm)
394		arches="arm armeb"
395		;;
396
397	evbmips|sbmips)
398		arches="mipseb mipsel mips64eb mips64el"
399		;;
400
401	sgimips)
402		arches="mipseb mips64eb"
403		;;
404
405	evbsh3)
406		arches="sh3eb sh3el"
407		;;
408
409	macppc|evbppc)
410		arches="powerpc powerpc64"
411		;;
412	*)
413		oma="${MACHINE_ARCH}"
414		getarch
415		arches="${MACHINE_ARCH}"
416		MACHINE_ARCH="${oma}"
417		;;
418
419	esac
420
421	# Ensure that MACHINE_ARCH supports MACHINE
422	#
423	archok=false
424	for a in ${arches}; do
425		if [ "${a}" = "${MACHINE_ARCH}" ]; then
426			archok=true
427			break
428		fi
429	done
430	${archok} ||
431	    bomb "MACHINE_ARCH '${MACHINE_ARCH}' does not support MACHINE '${MACHINE}'"
432}
433
434nobomb_getmakevar()
435{
436	[ -x "${make}" ] || return 1
437	"${make}" -m ${TOP}/share/mk -s -B -f- _x_ <<EOF || return 1
438_x_:
439	echo \${$1}
440.include <bsd.prog.mk>
441.include <bsd.kernobj.mk>
442EOF
443}
444
445raw_getmakevar()
446{
447	[ -x "${make}" ] || bomb "raw_getmakevar $1: ${make} is not executable"
448	nobomb_getmakevar "$1" || bomb "raw_getmakevar $1: ${make} failed"
449}
450
451getmakevar()
452{
453	# raw_getmakevar() doesn't work properly if $make hasn't yet been
454	# built, which can happen when running with the "-n" option.
455	# getmakevar() deals with this by emitting a literal '$'
456	# followed by the variable name, instead of trying to find the
457	# variable's value.
458	#
459	if [ -x "${make}" ]; then
460		raw_getmakevar "$1"
461	else
462		echo "\$$1"
463	fi
464}
465
466setmakeenv()
467{
468	eval "$1='$2'; export $1"
469	makeenv="${makeenv} $1"
470}
471
472unsetmakeenv()
473{
474	eval "unset $1"
475	makeenv="${makeenv} $1"
476}
477
478# Convert possibly-relative path to absolute path by prepending
479# ${TOP} if necessary.  Also delete trailing "/", if any.
480resolvepath()
481{
482	case "${OPTARG}" in
483	/)
484		;;
485	/*)
486		OPTARG="${OPTARG%/}"
487		;;
488	*)
489		OPTARG="${TOP}/${OPTARG%/}"
490		;;
491	esac
492}
493
494usage()
495{
496	if [ -n "$*" ]; then
497		echo ""
498		echo "${progname}: $*"
499	fi
500	cat <<_usage_
501
502Usage: ${progname} [-EnorUux] [-a arch] [-B buildid] [-C cdextras] [-D dest]
503		[-j njob] [-M obj] [-m mach] [-N noisy] [-O obj] [-R release]
504		[-T tools] [-V var=[value]] [-w wrapper] [-X x11src] [-Z var]
505		operation [...]
506
507 Build operations (all imply "obj" and "tools"):
508    build               Run "make build".
509    distribution        Run "make distribution" (includes DESTDIR/etc/ files).
510    release             Run "make release" (includes kernels & distrib media).
511
512 Other operations:
513    help                Show this message and exit.
514    makewrapper         Create ${toolprefix}make-\${MACHINE} wrapper and ${toolprefix}make.
515                        Always performed.
516    obj                 Run "make obj".  [Default unless -o is used]
517    tools               Build and install tools.
518    install=idir        Run "make installworld" to \`idir' to install all sets
519			except \`etc'.  Useful after "distribution" or "release"
520    kernel=conf         Build kernel with config file \`conf'
521    releasekernel=conf  Install kernel built by kernel=conf to RELEASEDIR.
522    sets                Create binary sets in RELEASEDIR/MACHINE/binary/sets.
523			DESTDIR should be populated beforehand.
524    sourcesets          Create source sets in RELEASEDIR/source/sets.
525    syspkgs             Create syspkgs in RELEASEDIR/MACHINE/binary/syspkgs.
526    iso-image           Create CD-ROM image in RELEASEDIR/iso.
527    iso-image-source    Create CD-ROM image with source in RELEASEDIR/iso.
528    params              Display various make(1) parameters.
529
530 Options:
531    -a arch     Set MACHINE_ARCH to arch.  [Default: deduced from MACHINE]
532    -B buildId  Set BUILDID to buildId.
533    -C cdextras Set CDEXTRA to cdextras
534    -D dest     Set DESTDIR to dest.  [Default: destdir.MACHINE]
535    -E          Set "expert" mode; disables various safety checks.
536                Should not be used without expert knowledge of the build system.
537    -h          Print this help message.
538    -j njob     Run up to njob jobs in parallel; see make(1) -j.
539    -M obj      Set obj root directory to obj; sets MAKEOBJDIRPREFIX.
540                Unsets MAKEOBJDIR.
541    -m mach     Set MACHINE to mach; not required if NetBSD native.
542    -N noisy	Set the noisyness (MAKEVERBOSE) level of the build:
543		    0	Quiet
544		    1	Operations are described, commands are suppressed
545		    2	Full output
546		[Default: 2]
547    -n          Show commands that would be executed, but do not execute them.
548    -O obj      Set obj root directory to obj; sets a MAKEOBJDIR pattern.
549                Unsets MAKEOBJDIRPREFIX.
550    -o          Set MKOBJDIRS=no; do not create objdirs at start of build.
551    -R release  Set RELEASEDIR to release.  [Default: releasedir]
552    -r          Remove contents of TOOLDIR and DESTDIR before building.
553    -T tools    Set TOOLDIR to tools.  If unset, and TOOLDIR is not set in
554                the environment, ${toolprefix}make will be (re)built unconditionally.
555    -U          Set MKUNPRIVED=yes; build without requiring root privileges,
556    		install from an UNPRIVED build with proper file permissions.
557    -u          Set MKUPDATE=yes; do not run "make clean" first.
558		Without this, everything is rebuilt, including the tools.
559    -V v=[val]  Set variable \`v' to \`val'.
560    -w wrapper  Create ${toolprefix}make script as wrapper.
561                [Default: \${TOOLDIR}/bin/${toolprefix}make-\${MACHINE}]
562    -X x11src   Set X11SRCDIR to x11src.  [Default: /usr/xsrc]
563    -x          Set MKX11=yes; build X11R6 from X11SRCDIR
564    -Z v        Unset ("zap") variable \`v'.
565
566_usage_
567	exit 1
568}
569
570parseoptions()
571{
572	opts='a:B:bC:D:dEhi:j:k:M:m:N:nO:oR:rT:tUuV:w:xX:Z:'
573	opt_a=no
574
575	if type getopts >/dev/null 2>&1; then
576		# Use POSIX getopts.
577		#
578		getoptcmd='getopts ${opts} opt && opt=-${opt}'
579		optargcmd=':'
580		optremcmd='shift $((${OPTIND} -1))'
581	else
582		type getopt >/dev/null 2>&1 ||
583		    bomb "/bin/sh shell is too old; try ksh or bash"
584
585		# Use old-style getopt(1) (doesn't handle whitespace in args).
586		#
587		args="$(getopt ${opts} $*)"
588		[ $? = 0 ] || usage
589		set -- ${args}
590
591		getoptcmd='[ $# -gt 0 ] && opt="$1" && shift'
592		optargcmd='OPTARG="$1"; shift'
593		optremcmd=':'
594	fi
595
596	# Parse command line options.
597	#
598	while eval ${getoptcmd}; do
599		case ${opt} in
600
601		-a)
602			eval ${optargcmd}
603			MACHINE_ARCH=${OPTARG}
604			opt_a=yes
605			;;
606
607		-B)
608			eval ${optargcmd}
609			BUILDID=${OPTARG}
610			;;
611
612		-b)
613			usage "'-b' has been replaced by 'makewrapper'"
614			;;
615
616		-C)
617			eval ${optargcmd}; resolvepath
618			iso_dir=${OPTARG}
619			;;
620
621		-D)
622			eval ${optargcmd}; resolvepath
623			setmakeenv DESTDIR "${OPTARG}"
624			;;
625
626		-d)
627			usage "'-d' has been replaced by 'distribution'"
628			;;
629
630		-E)
631			do_expertmode=true
632			;;
633
634		-i)
635			usage "'-i idir' has been replaced by 'install=idir'"
636			;;
637
638		-j)
639			eval ${optargcmd}
640			parallel="-j ${OPTARG}"
641			;;
642
643		-k)
644			usage "'-k conf' has been replaced by 'kernel=conf'"
645			;;
646
647		-M)
648			eval ${optargcmd}; resolvepath
649			makeobjdir="${OPTARG}"
650			unsetmakeenv MAKEOBJDIR
651			setmakeenv MAKEOBJDIRPREFIX "${OPTARG}"
652			;;
653
654			# -m overrides MACHINE_ARCH unless "-a" is specified
655		-m)
656			eval ${optargcmd}
657			MACHINE="${OPTARG}"
658			[ "${opt_a}" != "yes" ] && getarch
659			;;
660
661		-N)
662			eval ${optargcmd}
663			case "${OPTARG}" in
664			0|1|2)
665				setmakeenv MAKEVERBOSE "${OPTARG}"
666				;;
667			*)
668				usage "'${OPTARG}' is not a valid value for -N"
669				;;
670			esac
671			;;
672
673		-n)
674			runcmd=echo
675			;;
676
677		-O)
678			eval ${optargcmd}; resolvepath
679			makeobjdir="${OPTARG}"
680			unsetmakeenv MAKEOBJDIRPREFIX
681			setmakeenv MAKEOBJDIR "\${.CURDIR:C,^$TOP,$OPTARG,}"
682			;;
683
684		-o)
685			MKOBJDIRS=no
686			;;
687
688		-R)
689			eval ${optargcmd}; resolvepath
690			setmakeenv RELEASEDIR "${OPTARG}"
691			;;
692
693		-r)
694			do_removedirs=true
695			do_rebuildmake=true
696			;;
697
698		-T)
699			eval ${optargcmd}; resolvepath
700			TOOLDIR="${OPTARG}"
701			export TOOLDIR
702			;;
703
704		-t)
705			usage "'-t' has been replaced by 'tools'"
706			;;
707
708		-U)
709			setmakeenv MKUNPRIVED yes
710			;;
711
712		-u)
713			setmakeenv MKUPDATE yes
714			;;
715
716		-V)
717			eval ${optargcmd}
718			case "${OPTARG}" in
719		    # XXX: consider restricting which variables can be changed?
720			[a-zA-Z_][a-zA-Z_0-9]*=*)
721				setmakeenv "${OPTARG%%=*}" "${OPTARG#*=}"
722				;;
723			*)
724				usage "-V argument must be of the form 'var=[value]'"
725				;;
726			esac
727			;;
728
729		-w)
730			eval ${optargcmd}; resolvepath
731			makewrapper="${OPTARG}"
732			;;
733
734		-X)
735			eval ${optargcmd}; resolvepath
736			setmakeenv X11SRCDIR "${OPTARG}"
737			;;
738
739		-x)
740			setmakeenv MKX11 yes
741			;;
742
743		-Z)
744			eval ${optargcmd}
745		    # XXX: consider restricting which variables can be unset?
746			unsetmakeenv "${OPTARG}"
747			;;
748
749		--)
750			break
751			;;
752
753		-'?'|-h)
754			usage
755			;;
756
757		esac
758	done
759
760	# Validate operations.
761	#
762	eval ${optremcmd}
763	while [ $# -gt 0 ]; do
764		op=$1; shift
765		operations="${operations} ${op}"
766
767		case "${op}" in
768
769		help)
770			usage
771			;;
772
773		makewrapper|obj|tools|build|distribution|release|sets|sourcesets|syspkgs|params)
774			;;
775
776		iso-image)
777			op=iso_image	# used as part of a variable name
778			;;
779
780		iso-image-source)
781			op=iso_image_source   # used as part of a variable name
782			;;
783
784		kernel=*|releasekernel=*)
785			arg=${op#*=}
786			op=${op%%=*}
787			[ -n "${arg}" ] ||
788			    bomb "Must supply a kernel name with \`${op}=...'"
789			;;
790
791		install=*)
792			arg=${op#*=}
793			op=${op%%=*}
794			[ -n "${arg}" ] ||
795			    bomb "Must supply a directory with \`install=...'"
796			;;
797
798		*)
799			usage "Unknown operation \`${op}'"
800			;;
801
802		esac
803		eval do_${op}=true
804	done
805	[ -n "${operations}" ] || usage "Missing operation to perform."
806
807	# Set up MACHINE*.  On a NetBSD host, these are allowed to be unset.
808	#
809	if [ -z "${MACHINE}" ]; then
810		[ "${uname_s}" = "NetBSD" ] ||
811		    bomb "MACHINE must be set, or -m must be used, for cross builds."
812		MACHINE=${uname_m}
813	fi
814	[ -n "${MACHINE_ARCH}" ] || getarch
815	validatearch
816
817	# Set up default make(1) environment.
818	#
819	makeenv="${makeenv} TOOLDIR MACHINE MACHINE_ARCH MAKEFLAGS"
820	[ -z "${BUILDID}" ] || makeenv="${makeenv} BUILDID"
821	MAKEFLAGS="-de -m ${TOP}/share/mk ${MAKEFLAGS} MKOBJDIRS=${MKOBJDIRS-yes}"
822	export MAKEFLAGS MACHINE MACHINE_ARCH
823}
824
825sanitycheck()
826{
827	# If the PATH contains any non-absolute components (including,
828	# but not limited to, "." or ""), then complain.  As an exception,
829	# allow "" or "." as the last component of the PATH.  This is fatal
830	# if expert mode is not in effect.
831	#
832	local path="${PATH}"
833	path="${path%:}"	# delete trailing ":"
834	path="${path%:.}"	# delete trailing ":."
835	case ":${path}:/" in
836	*:[!/]*)
837		if ${do_expertmode}; then
838			warning "PATH contains non-absolute components"
839		else
840			bomb "PATH environment variable must not" \
841			     "contain non-absolute components"
842		fi
843		;;
844	esac
845}
846
847# Try to set a value for TOOLDIR.  This is difficult because of a cyclic
848# dependency: TOOLDIR may be affected by settings in /etc/mk.conf, so
849# we would like to use getmakevar to get the value of TOOLDIR, but we
850# can't use getmakevar before we have an up to date version of nbmake;
851# we might already have an up to date version of nbmake in TOOLDIR, but
852# we don't yet know where TOOLDIR is.
853#
854# In principle, we could break the cycle by building a copy of nbmake
855# in a temporary directory.  However, people who use the default value
856# of TOOLDIR do not like to have nbmake rebuilt every time they run
857# build.sh.
858#
859# We try to please everybody as follows:
860#
861# * If TOOLDIR was set in the environment or on the command line, use
862#   that value.
863# * Otherwise try to guess what TOOLDIR would be if not overridden by
864#   /etc/mk.conf, and check whether the resulting directory contains
865#   a copy of ${toolprefix}make (this should work for everybody who
866#   doesn't override TOOLDIR via /etc/mk.conf);
867# * Failing that, search for ${toolprefix}make, nbmake, bmake, or make,
868#   in the PATH (this might accidentally find a non-NetBSD version of
869#   make, which will lead to failure in the next step);
870# * If a copy of make was found above, try to use it with
871#   nobomb_getmakevar to find the correct value for TOOLDIR;
872# * If all else fails, leave TOOLDIR unset.  Our caller is expected to
873#   be able to cope with this.
874#
875try_set_TOOLDIR()
876{
877	[ -n "${TOOLDIR}" ] && return
878
879	# Set guess_TOOLDIR, in the same way that <bsd.own.mk> would set
880	# TOOLDIR if /etc/mk.conf sisn't interfere.
881	local topobjdir="${TOP}"
882	[ -n "${makeobjdir}" ] && topobjdir="${topobjdir}/${makeobjdir}"
883	local host_ostype="${uname_s}-$(
884		echo "${uname_r}" | sed -e 's/([^)]*)//g' -e 's/ /_/g'
885		)$(
886		echo "${uname_p}" | sed -e 's/([^)]*)//g' -e 's/ /_/g'
887		)"
888	local guess_TOOLDIR="${topobjdir}/tooldir.${host_ostype}"
889
890	# Look for a suitable ${toolprefix}make, nbmake, bmake, or make.
891	guess_make="${guess_TOOLDIR}/bin/${toolprefix}make"
892	[ -x "${guess_make}" ] || guess_make=""
893	: ${guess_make:=$(find_in_PATH ${toolprefix}make '')}
894	: ${guess_make:=$(find_in_PATH nbmake '')}
895	: ${guess_make:=$(find_in_PATH bmake '')}
896	: ${guess_make:=$(find_in_PATH make '')}
897
898	# Use ${guess_make} with nobomb_getmakevar
899	if [ -x "${guess_make}" ]; then
900		TOOLDIR=$(make="${guess_make}" nobomb_getmakevar TOOLDIR)
901		[ -n "${TOOLDIR}" ] || unset TOOLDIR
902	fi
903}
904
905rebuildmake()
906{
907	# Test make source file timestamps against installed ${toolprefix}make
908	# binary, if TOOLDIR is pre-set or if try_set_TOOLDIR can set it.
909	#
910	try_set_TOOLDIR
911	make="${TOOLDIR-nonexistent}/bin/${toolprefix}make"
912	if [ -x "${make}" ]; then
913		for f in usr.bin/make/*.[ch] usr.bin/make/lst.lib/*.[ch]; do
914			if [ "${f}" -nt "${make}" ]; then
915				statusmsg "${make} outdated (older than ${f}), needs building."
916				do_rebuildmake=true
917				break
918			fi
919		done
920	else
921		statusmsg "No ${make}, needs building."
922		do_rebuildmake=true
923	fi
924
925	# Build bootstrap ${toolprefix}make if needed.
926	if ${do_rebuildmake}; then
927		statusmsg "Bootstrapping ${toolprefix}make"
928		${runcmd} cd "${tmpdir}"
929		${runcmd} env CC="${HOST_CC-cc}" CPPFLAGS="${HOST_CPPFLAGS}" \
930			CFLAGS="${HOST_CFLAGS--O}" LDFLAGS="${HOST_LDFLAGS}" \
931			${HOST_SH} "${TOP}/tools/make/configure" ||
932		    bomb "Configure of ${toolprefix}make failed"
933		${runcmd} ${HOST_SH} buildmake.sh ||
934		    bomb "Build of ${toolprefix}make failed"
935		make="${tmpdir}/${toolprefix}make"
936		${runcmd} cd "${TOP}"
937		${runcmd} rm -f usr.bin/make/*.o usr.bin/make/lst.lib/*.o
938	fi
939}
940
941validatemakeparams()
942{
943	if [ "${runcmd}" = "echo" ]; then
944		TOOLCHAIN_MISSING=no
945		EXTERNAL_TOOLCHAIN=""
946	else
947		TOOLCHAIN_MISSING=$(raw_getmakevar TOOLCHAIN_MISSING)
948		EXTERNAL_TOOLCHAIN=$(raw_getmakevar EXTERNAL_TOOLCHAIN)
949	fi
950	if [ "${TOOLCHAIN_MISSING}" = "yes" ] && \
951	   [ -z "${EXTERNAL_TOOLCHAIN}" ]; then
952		${runcmd} echo "ERROR: build.sh (in-tree cross-toolchain) is not yet available for"
953		${runcmd} echo "	MACHINE:      ${MACHINE}"
954		${runcmd} echo "	MACHINE_ARCH: ${MACHINE_ARCH}"
955		${runcmd} echo ""
956		${runcmd} echo "All builds for this platform should be done via a traditional make"
957		${runcmd} echo "If you wish to use an external cross-toolchain, set"
958		${runcmd} echo "	EXTERNAL_TOOLCHAIN=<path to toolchain root>"
959		${runcmd} echo "in either the environment or mk.conf and rerun"
960		${runcmd} echo "	${progname} $*"
961		exit 1
962	fi
963
964	# Normalise MKOBJDIRS, MKUNPRIVED, and MKUPDATE
965	# These may be set as build.sh options or in "mk.conf".
966	# Don't export them as they're only used for tests in build.sh.
967	#
968	MKOBJDIRS=$(getmakevar MKOBJDIRS)
969	MKUNPRIVED=$(getmakevar MKUNPRIVED)
970	MKUPDATE=$(getmakevar MKUPDATE)
971
972	if [ "${MKOBJDIRS}" != "no" ]; then
973		# If setting -M or -O to the root of an obj dir, make sure
974		# the base directory is made before continuing as <bsd.own.mk>
975		# will need this to pick up _SRC_TOP_OBJ_
976		#
977		if [ ! -z "${makeobjdir}" ]; then
978			${runcmd} mkdir -p "${makeobjdir}"
979		fi
980
981		# make obj in tools to ensure that the objdir for the top-level
982		# of the source tree and for "tools" is available, in case the
983		# default TOOLDIR setting from <bsd.own.mk> is used, or the
984		# build.sh default DESTDIR and RELEASEDIR is to be used.
985		#
986		${runcmd} cd tools
987		${runcmd} "${make}" -m ${TOP}/share/mk obj NOSUBDIR= ||
988		    bomb "Failed to make obj in tools"
989		${runcmd} cd "${TOP}"
990	fi
991
992	# Find TOOLDIR, DESTDIR, and RELEASEDIR.
993	#
994	TOOLDIR=$(getmakevar TOOLDIR)
995	statusmsg "TOOLDIR path:     ${TOOLDIR}"
996	DESTDIR=$(getmakevar DESTDIR)
997	RELEASEDIR=$(getmakevar RELEASEDIR)
998	if ! $do_expertmode; then
999		_SRC_TOP_OBJ_=$(getmakevar _SRC_TOP_OBJ_)
1000		: ${DESTDIR:=${_SRC_TOP_OBJ_}/destdir.${MACHINE}}
1001		: ${RELEASEDIR:=${_SRC_TOP_OBJ_}/releasedir}
1002		makeenv="${makeenv} DESTDIR RELEASEDIR"
1003	fi
1004	export TOOLDIR DESTDIR RELEASEDIR
1005	statusmsg "DESTDIR path:     ${DESTDIR}"
1006	statusmsg "RELEASEDIR path:  ${RELEASEDIR}"
1007
1008	# Check validity of TOOLDIR and DESTDIR.
1009	#
1010	if [ -z "${TOOLDIR}" ] || [ "${TOOLDIR}" = "/" ]; then
1011		bomb "TOOLDIR '${TOOLDIR}' invalid"
1012	fi
1013	removedirs="${TOOLDIR}"
1014
1015	if [ -z "${DESTDIR}" ] || [ "${DESTDIR}" = "/" ]; then
1016		if ${do_build} || ${do_distribution} || ${do_release}; then
1017			if ! ${do_build} || \
1018			   [ "${uname_s}" != "NetBSD" ] || \
1019			   [ "${uname_m}" != "${MACHINE}" ]; then
1020				bomb "DESTDIR must != / for cross builds, or ${progname} 'distribution' or 'release'."
1021			fi
1022			if ! ${do_expertmode}; then
1023				bomb "DESTDIR must != / for non -E (expert) builds"
1024			fi
1025			statusmsg "WARNING: Building to /, in expert mode."
1026			statusmsg "         This may cause your system to break!  Reasons include:"
1027			statusmsg "            - your kernel is not up to date"
1028			statusmsg "            - the libraries or toolchain have changed"
1029			statusmsg "         YOU HAVE BEEN WARNED!"
1030		fi
1031	else
1032		removedirs="${removedirs} ${DESTDIR}"
1033	fi
1034	if ${do_build} || ${do_distribution} || ${do_release}; then
1035		if ! ${do_expertmode} && \
1036		    [ "$(id -u 2>/dev/null)" -ne 0 ] && \
1037		    [ "${MKUNPRIVED}" = "no" ] ; then
1038			bomb "-U or -E must be set for build as an unprivileged user."
1039		fi
1040        fi
1041	if ${do_releasekernel} && [ -z "${RELEASEDIR}" ]; then
1042		bomb "Must set RELEASEDIR with \`releasekernel=...'"
1043	fi
1044}
1045
1046
1047createmakewrapper()
1048{
1049	# Remove the target directories.
1050	#
1051	if ${do_removedirs}; then
1052		for f in ${removedirs}; do
1053			statusmsg "Removing ${f}"
1054			${runcmd} rm -r -f "${f}"
1055		done
1056	fi
1057
1058	# Recreate $TOOLDIR.
1059	#
1060	${runcmd} mkdir -p "${TOOLDIR}/bin" ||
1061	    bomb "mkdir of '${TOOLDIR}/bin' failed"
1062
1063	# Install ${toolprefix}make if it was built.
1064	#
1065	if ${do_rebuildmake}; then
1066		${runcmd} rm -f "${TOOLDIR}/bin/${toolprefix}make"
1067		${runcmd} cp "${make}" "${TOOLDIR}/bin/${toolprefix}make" ||
1068		    bomb "Failed to install \$TOOLDIR/bin/${toolprefix}make"
1069		make="${TOOLDIR}/bin/${toolprefix}make"
1070		statusmsg "Created ${make}"
1071	fi
1072
1073	# Build a ${toolprefix}make wrapper script, usable by hand as
1074	# well as by build.sh.
1075	#
1076	if [ -z "${makewrapper}" ]; then
1077		makewrapper="${TOOLDIR}/bin/${toolprefix}make-${makewrappermachine:-${MACHINE}}"
1078		[ -z "${BUILDID}" ] || makewrapper="${makewrapper}-${BUILDID}"
1079	fi
1080
1081	${runcmd} rm -f "${makewrapper}"
1082	if [ "${runcmd}" = "echo" ]; then
1083		echo 'cat <<EOF >'${makewrapper}
1084		makewrapout=
1085	else
1086		makewrapout=">>\${makewrapper}"
1087	fi
1088
1089	case "${KSH_VERSION:-${SH_VERSION}}" in
1090	*PD\ KSH*|*MIRBSD\ KSH*)
1091		set +o braceexpand
1092		;;
1093	esac
1094
1095	eval cat <<EOF ${makewrapout}
1096#! ${HOST_SH}
1097# Set proper variables to allow easy "make" building of a NetBSD subtree.
1098# Generated from:  \$NetBSD: build.sh,v 1.171.4.2 2008/01/09 01:19:18 matt Exp $
1099# with these arguments: ${_args}
1100#
1101
1102EOF
1103	{
1104		for f in ${makeenv}; do
1105			if eval "[ -z \"\${$f}\" -a \"\${${f}-X}\" = \"X\" ]"; then
1106				eval echo "unset ${f}"
1107			else
1108				eval echo "${f}=\'\$$(echo ${f})\'\;\ export\ ${f}"
1109			fi
1110		done
1111
1112		eval cat <<EOF
1113MAKEWRAPPERMACHINE=${makewrappermachine:-${MACHINE}}; export MAKEWRAPPERMACHINE
1114USETOOLS=yes; export USETOOLS
1115EOF
1116	} | eval sort -u "${makewrapout}"
1117	eval cat <<EOF "${makewrapout}"
1118
1119exec "\${TOOLDIR}/bin/${toolprefix}make" \${1+"\$@"}
1120EOF
1121	[ "${runcmd}" = "echo" ] && echo EOF
1122	${runcmd} chmod +x "${makewrapper}"
1123	statusmsg "makewrapper:      ${makewrapper}"
1124	statusmsg "Updated ${makewrapper}"
1125}
1126
1127buildtools()
1128{
1129	if [ "${MKOBJDIRS}" != "no" ]; then
1130		${runcmd} "${makewrapper}" ${parallel} obj-tools ||
1131		    bomb "Failed to make obj-tools"
1132	fi
1133	${runcmd} cd tools
1134	if [ "${MKUPDATE}" = "no" ]; then
1135		${runcmd} "${makewrapper}" ${parallel} cleandir ||
1136		    bomb "Failed to make cleandir tools"
1137	fi
1138	${runcmd} "${makewrapper}" ${parallel} dependall ||
1139	    bomb "Failed to make dependall tools"
1140	${runcmd} "${makewrapper}" ${parallel} install ||
1141	    bomb "Failed to make install tools"
1142	statusmsg "Tools built to ${TOOLDIR}"
1143	${runcmd} cd "${TOP}"
1144}
1145
1146getkernelconf()
1147{
1148	kernelconf="$1"
1149	if [ "${MKOBJDIRS}" != "no" ]; then
1150		# The correct value of KERNOBJDIR might
1151		# depend on a prior "make obj" in
1152		# ${KERNSRCDIR}/${KERNARCHDIR}/compile.
1153		#
1154		KERNSRCDIR="$(getmakevar KERNSRCDIR)"
1155		KERNARCHDIR="$(getmakevar KERNARCHDIR)"
1156		${runcmd} cd "${KERNSRCDIR}/${KERNARCHDIR}/compile"
1157		${runcmd} "${makewrapper}" ${parallel} obj ||
1158		    bomb "Failed to make obj in ${KERNSRCDIR}/${KERNARCHDIR}/compile"
1159		${runcmd} cd "${TOP}"
1160	fi
1161	KERNCONFDIR="$(getmakevar KERNCONFDIR)"
1162	KERNOBJDIR="$(getmakevar KERNOBJDIR)"
1163	case "${kernelconf}" in
1164	*/*)
1165		kernelconfpath="${kernelconf}"
1166		kernelconfname="${kernelconf##*/}"
1167		;;
1168	*)
1169		kernelconfpath="${KERNCONFDIR}/${kernelconf}"
1170		kernelconfname="${kernelconf}"
1171		;;
1172	esac
1173	kernelbuildpath="${KERNOBJDIR}/${kernelconfname}"
1174}
1175
1176buildkernel()
1177{
1178	if ! ${do_tools} && ! ${buildkernelwarned:-false}; then
1179		# Building tools every time we build a kernel is clearly
1180		# unnecessary.  We could try to figure out whether rebuilding
1181		# the tools is necessary this time, but it doesn't seem worth
1182		# the trouble.  Instead, we say it's the user's responsibility
1183		# to rebuild the tools if necessary.
1184		#
1185		statusmsg "Building kernel without building new tools"
1186		buildkernelwarned=true
1187	fi
1188	getkernelconf $1
1189	statusmsg "Building kernel:  ${kernelconf}"
1190	statusmsg "Build directory:  ${kernelbuildpath}"
1191	${runcmd} mkdir -p "${kernelbuildpath}" ||
1192	    bomb "Cannot mkdir: ${kernelbuildpath}"
1193	if [ "${MKUPDATE}" = "no" ]; then
1194		${runcmd} cd "${kernelbuildpath}"
1195		${runcmd} "${makewrapper}" ${parallel} cleandir ||
1196		    bomb "Failed to make cleandir in ${kernelbuildpath}"
1197		${runcmd} cd "${TOP}"
1198	fi
1199	[ -x "${TOOLDIR}/bin/${toolprefix}config" ] \
1200	|| bomb "${TOOLDIR}/bin/${toolprefix}config does not exist. You need to \"$0 tools\" first."
1201	${runcmd} "${TOOLDIR}/bin/${toolprefix}config" -b "${kernelbuildpath}" \
1202		-s "${TOP}/sys" "${kernelconfpath}" ||
1203	    bomb "${toolprefix}config failed for ${kernelconf}"
1204	${runcmd} cd "${kernelbuildpath}"
1205	${runcmd} "${makewrapper}" ${parallel} depend ||
1206	    bomb "Failed to make depend in ${kernelbuildpath}"
1207	${runcmd} "${makewrapper}" ${parallel} all ||
1208	    bomb "Failed to make all in ${kernelbuildpath}"
1209	${runcmd} cd "${TOP}"
1210
1211	if [ "${runcmd}" != "echo" ]; then
1212		statusmsg "Kernels built from ${kernelconf}:"
1213		kernlist=$(awk '$1 == "config" { print $2 }' ${kernelconfpath})
1214		for kern in ${kernlist:-netbsd}; do
1215			[ -f "${kernelbuildpath}/${kern}" ] && \
1216			    echo "  ${kernelbuildpath}/${kern}"
1217		done | tee -a "${results}"
1218	fi
1219}
1220
1221releasekernel()
1222{
1223	getkernelconf $1
1224	kernelreldir="${RELEASEDIR}/${MACHINE}/binary/kernel"
1225	${runcmd} mkdir -p "${kernelreldir}"
1226	kernlist=$(awk '$1 == "config" { print $2 }' ${kernelconfpath})
1227	for kern in ${kernlist:-netbsd}; do
1228		builtkern="${kernelbuildpath}/${kern}"
1229		[ -f "${builtkern}" ] || continue
1230		releasekern="${kernelreldir}/${kern}-${kernelconfname}.gz"
1231		statusmsg "Kernel copy:      ${releasekern}"
1232		${runcmd} gzip -c -9 < "${builtkern}" > "${releasekern}"
1233	done
1234}
1235
1236installworld()
1237{
1238	dir="$1"
1239	${runcmd} "${makewrapper}" INSTALLWORLDDIR="${dir}" installworld ||
1240	    bomb "Failed to make installworld to ${dir}"
1241	statusmsg "Successful installworld to ${dir}"
1242}
1243
1244
1245main()
1246{
1247	initdefaults
1248	_args=$@
1249	parseoptions "$@"
1250
1251	sanitycheck
1252
1253	build_start=$(date)
1254	statusmsg "${progname} command: $0 $@"
1255	statusmsg "${progname} started: ${build_start}"
1256	statusmsg "NetBSD version:   ${DISTRIBVER}"
1257	statusmsg "MACHINE:          ${MACHINE}"
1258	statusmsg "MACHINE_ARCH:     ${MACHINE_ARCH}"
1259	statusmsg "Build platform:   ${uname_s} ${uname_r} ${uname_m}"
1260	statusmsg "HOST_SH:          ${HOST_SH}"
1261
1262	rebuildmake
1263	validatemakeparams
1264	createmakewrapper
1265
1266	# Perform the operations.
1267	#
1268	for op in ${operations}; do
1269		case "${op}" in
1270
1271		makewrapper)
1272			# no-op
1273			;;
1274
1275		tools)
1276			buildtools
1277			;;
1278
1279		sets)
1280			statusmsg "Building sets from pre-populated ${DESTDIR}"
1281			${runcmd} "${makewrapper}" ${parallel} ${op} ||
1282			    bomb "Failed to make ${op}"
1283			statusmsg "Successful make ${op}"
1284			;;
1285
1286		obj|build|distribution|release|sourcesets|syspkgs|params)
1287			${runcmd} "${makewrapper}" ${parallel} ${op} ||
1288			    bomb "Failed to make ${op}"
1289			statusmsg "Successful make ${op}"
1290			;;
1291
1292		iso-image|iso-image-source)
1293			${runcmd} "${makewrapper}" ${parallel} \
1294			    CDEXTRA=$iso_dir ${op} ||
1295			    bomb "Failed to make ${op}"
1296			statusmsg "Successful make ${op}"
1297			;;
1298
1299		kernel=*)
1300			arg=${op#*=}
1301			buildkernel "${arg}"
1302			;;
1303
1304		releasekernel=*)
1305			arg=${op#*=}
1306			releasekernel "${arg}"
1307			;;
1308
1309		install=*)
1310			arg=${op#*=}
1311			if [ "${arg}" = "/" ] && \
1312			    (	[ "${uname_s}" != "NetBSD" ] || \
1313				[ "${uname_m}" != "${MACHINE}" ] ); then
1314				bomb "'${op}' must != / for cross builds."
1315			fi
1316			installworld "${arg}"
1317			;;
1318
1319		*)
1320			bomb "Unknown operation \`${op}'"
1321			;;
1322
1323		esac
1324	done
1325
1326	statusmsg "${progname} ended:   $(date)"
1327	if [ -s "${results}" ]; then
1328		echo "===> Summary of results:"
1329		sed -e 's/^===>//;s/^/	/' "${results}"
1330		echo "===> ."
1331	fi
1332}
1333
1334main "$@"
1335