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