build.sh revision 1.242
1#! /usr/bin/env sh
2#	$NetBSD: build.sh,v 1.242 2010/12/06 09:08:39 pooka Exp $
3#
4# Copyright (c) 2001-2009 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
46tab='	'
47trap "exit 1" 1 2 3 15
48
49bomb()
50{
51	cat >&2 <<ERRORMESSAGE
52
53ERROR: $@
54*** BUILD ABORTED ***
55ERRORMESSAGE
56	kill ${toppid}		# in case we were invoked from a subshell
57	exit 1
58}
59
60
61statusmsg()
62{
63	${runcmd} echo "===> $@" | tee -a "${results}"
64}
65
66statusmsg2()
67{
68	local msg
69
70	msg="${1}"
71	shift
72	case "${msg}" in
73	????????????????*)	;;
74	??????????*)		msg="${msg}      ";;
75	?????*)			msg="${msg}           ";;
76	*)			msg="${msg}                ";;
77	esac
78	case "${msg}" in
79	?????????????????????*)	;;
80	????????????????????)	msg="${msg} ";;
81	???????????????????)	msg="${msg}  ";;
82	??????????????????)	msg="${msg}   ";;
83	?????????????????)	msg="${msg}    ";;
84	????????????????)	msg="${msg}     ";;
85	esac
86	statusmsg "${msg}$*"
87}
88
89warning()
90{
91	statusmsg "Warning: $@"
92}
93
94# Find a program in the PATH, and print the result.  If not found,
95# print a default.  If $2 is defined (even if it is an empty string),
96# then that is the default; otherwise, $1 is used as the default.
97find_in_PATH()
98{
99	local prog="$1"
100	local result="${2-"$1"}"
101	local oldIFS="${IFS}"
102	local dir
103	IFS=":"
104	for dir in ${PATH}; do
105		if [ -x "${dir}/${prog}" ]; then
106			result="${dir}/${prog}"
107			break
108		fi
109	done
110	IFS="${oldIFS}"
111	echo "${result}"
112}
113
114# Try to find a working POSIX shell, and set HOST_SH to refer to it.
115# Assumes that uname_s, uname_m, and PWD have been set.
116set_HOST_SH()
117{
118	# Even if ${HOST_SH} is already defined, we still do the
119	# sanity checks at the end.
120
121	# Solaris has /usr/xpg4/bin/sh.
122	#
123	[ -z "${HOST_SH}" ] && [ x"${uname_s}" = x"SunOS" ] && \
124		[ -x /usr/xpg4/bin/sh ] && HOST_SH="/usr/xpg4/bin/sh"
125
126	# Try to get the name of the shell that's running this script,
127	# by parsing the output from "ps".  We assume that, if the host
128	# system's ps command supports -o comm at all, it will do so
129	# in the usual way: a one-line header followed by a one-line
130	# result, possibly including trailing white space.  And if the
131	# host system's ps command doesn't support -o comm, we assume
132	# that we'll get an error message on stderr and nothing on
133	# stdout.  (We don't try to use ps -o 'comm=' to suppress the
134	# header line, because that is less widely supported.)
135	#
136	# If we get the wrong result here, the user can override it by
137	# specifying HOST_SH in the environment.
138	#
139	[ -z "${HOST_SH}" ] && HOST_SH="$(
140		(ps -p $$ -o comm | sed -ne "2s/[ ${tab}]*\$//p") 2>/dev/null )"
141
142	# If nothing above worked, use "sh".  We will later find the
143	# first directory in the PATH that has a "sh" program.
144	#
145	[ -z "${HOST_SH}" ] && HOST_SH="sh"
146
147	# If the result so far is not an absolute path, try to prepend
148	# PWD or search the PATH.
149	#
150	case "${HOST_SH}" in
151	/*)	:
152		;;
153	*/*)	HOST_SH="${PWD}/${HOST_SH}"
154		;;
155	*)	HOST_SH="$(find_in_PATH "${HOST_SH}")"
156		;;
157	esac
158
159	# If we don't have an absolute path by now, bomb.
160	#
161	case "${HOST_SH}" in
162	/*)	:
163		;;
164	*)	bomb "HOST_SH=\"${HOST_SH}\" is not an absolute path."
165		;;
166	esac
167
168	# If HOST_SH is not executable, bomb.
169	#
170	[ -x "${HOST_SH}" ] ||
171	    bomb "HOST_SH=\"${HOST_SH}\" is not executable."
172}
173
174initdefaults()
175{
176	makeenv=
177	makewrapper=
178	makewrappermachine=
179	runcmd=
180	operations=
181	removedirs=
182
183	[ -d usr.bin/make ] || cd "$(dirname $0)"
184	[ -d usr.bin/make ] ||
185	    bomb "build.sh must be run from the top source level"
186	[ -f share/mk/bsd.own.mk ] ||
187	    bomb "src/share/mk is missing; please re-fetch the source tree"
188
189	# Set LC_ALL=C before we try to parse the output from any command
190	setmakeenv LC_ALL C
191
192	# Find information about the build platform.  This should be
193	# kept in sync with _HOST_OSNAME, _HOST_OSREL, and _HOST_ARCH
194	# variables in share/mk/bsd.sys.mk.
195	#
196	# Note that "uname -p" is not part of POSIX, but we want uname_p
197	# to be set to the host MACHINE_ARCH, if possible.  On systems
198	# where "uname -p" fails, prints "unknown", or prints a string
199	# that does not look like an identifier, fall back to using the
200	# output from "uname -m" instead.
201	#
202	uname_s=$(uname -s 2>/dev/null)
203	uname_r=$(uname -r 2>/dev/null)
204	uname_m=$(uname -m 2>/dev/null)
205	uname_p=$(uname -p 2>/dev/null || echo "unknown")
206	case "${uname_p}" in
207	''|unknown|*[^-_A-Za-z0-9]*) uname_p="${uname_m}" ;;
208	esac
209
210	id_u=$(id -u 2>/dev/null || /usr/xpg4/bin/id -u 2>/dev/null)
211
212	# If $PWD is a valid name of the current directory, POSIX mandates
213	# that pwd return it by default which causes problems in the
214	# presence of symlinks.  Unsetting PWD is simpler than changing
215	# every occurrence of pwd to use -P.
216	#
217	# XXX Except that doesn't work on Solaris. Or many Linuces.
218	#
219	unset PWD
220	TOP=$(/bin/pwd -P 2>/dev/null || /bin/pwd 2>/dev/null)
221
222	# The user can set HOST_SH in the environment, or we try to
223	# guess an appropriate value.  Then we set several other
224	# variables from HOST_SH.
225	#
226	set_HOST_SH
227	setmakeenv HOST_SH "${HOST_SH}"
228	setmakeenv BSHELL "${HOST_SH}"
229	setmakeenv CONFIG_SHELL "${HOST_SH}"
230
231	# Set defaults.
232	#
233	toolprefix=nb
234
235	# Some systems have a small ARG_MAX.  -X prevents make(1) from
236	# exporting variables in the environment redundantly.
237	#
238	case "${uname_s}" in
239	Darwin | FreeBSD | CYGWIN*)
240		MAKEFLAGS=-X
241		;;
242	*)
243		MAKEFLAGS=
244		;;
245	esac
246
247	# do_{operation}=true if given operation is requested.
248	#
249	do_expertmode=false
250	do_rebuildmake=false
251	do_removedirs=false
252	do_tools=false
253	do_cleandir=false
254	do_obj=false
255	do_build=false
256	do_distribution=false
257	do_release=false
258	do_kernel=false
259	do_releasekernel=false
260	do_modules=false
261	do_install=false
262	do_sets=false
263	do_sourcesets=false
264	do_syspkgs=false
265	do_iso_image=false
266	do_iso_image_source=false
267	do_params=false
268	do_rump=false
269
270	# done_{operation}=true if given operation has been done.
271	#
272	done_rebuildmake=false
273
274	# Create scratch directory
275	#
276	tmpdir="${TMPDIR-/tmp}/nbbuild$$"
277	mkdir "${tmpdir}" || bomb "Cannot mkdir: ${tmpdir}"
278	trap "cd /; rm -r -f \"${tmpdir}\"" 0
279	results="${tmpdir}/build.sh.results"
280
281	# Set source directories
282	#
283	setmakeenv NETBSDSRCDIR "${TOP}"
284
285	# Make sure KERNOBJDIR is an absolute path if defined
286	#
287	case "${KERNOBJDIR}" in
288	''|/*)	;;
289	*)	KERNOBJDIR="${TOP}/${KERNOBJDIR}"
290		setmakeenv KERNOBJDIR "${KERNOBJDIR}"
291		;;
292	esac
293
294	# Find the version of NetBSD
295	#
296	DISTRIBVER="$(${HOST_SH} ${TOP}/sys/conf/osrelease.sh)"
297
298	# Set the BUILDSEED to NetBSD-"N"
299	#
300	setmakeenv BUILDSEED "NetBSD-$(${HOST_SH} ${TOP}/sys/conf/osrelease.sh -m)"
301
302	# Set MKARZERO to "yes"
303	#
304	setmakeenv MKARZERO "yes"
305
306	# Set various environment variables to known defaults,
307	# to minimize (cross-)build problems observed "in the field".
308	#
309	unsetmakeenv INFODIR
310	unsetmakeenv LESSCHARSET
311}
312
313getarch()
314{
315	# Translate some MACHINE name aliases (known only to build.sh)
316	# into proper MACHINE and MACHINE_ARCH names.  Save the alias
317	# name in makewrappermachine.
318	#
319	case "${MACHINE}" in
320
321	evbarm-e[bl])
322		makewrappermachine=${MACHINE}
323		# MACHINE_ARCH is "arm" or "armeb", not "armel"
324		MACHINE_ARCH=arm${MACHINE##*-}
325		MACHINE_ARCH=${MACHINE_ARCH%el}
326		MACHINE=${MACHINE%-e[bl]}
327		;;
328
329	evbmips-e[bl]|sbmips-e[bl])
330		makewrappermachine=${MACHINE}
331		MACHINE_ARCH=mips${MACHINE##*-}
332		MACHINE=${MACHINE%-e[bl]}
333		;;
334
335	evbmips64-e[bl]|sbmips64-e[bl])
336		makewrappermachine=${MACHINE}
337		MACHINE_ARCH=mips64${MACHINE##*-}
338		MACHINE=${MACHINE%64-e[bl]}
339		;;
340
341	evbsh3-e[bl])
342		makewrappermachine=${MACHINE}
343		MACHINE_ARCH=sh3${MACHINE##*-}
344		MACHINE=${MACHINE%-e[bl]}
345		;;
346
347	esac
348
349	# Translate a MACHINE into a default MACHINE_ARCH.
350	#
351	case "${MACHINE}" in
352
353	acorn26|acorn32|cats|hpcarm|iyonix|netwinder|shark|zaurus)
354		MACHINE_ARCH=arm
355		;;
356
357	evbarm)		# unspecified MACHINE_ARCH gets LE
358		MACHINE_ARCH=${MACHINE_ARCH:=arm}
359		;;
360
361	hp700)
362		MACHINE_ARCH=hppa
363		;;
364
365	sun2)
366		MACHINE_ARCH=m68000
367		;;
368
369	amiga|atari|cesfic|hp300|luna68k|mac68k|mvme68k|news68k|next68k|sun3|x68k)
370		MACHINE_ARCH=m68k
371		;;
372
373	evbmips|sbmips)		# no default MACHINE_ARCH
374		;;
375
376	sgimips64)
377		makewrappermachine=${MACHINE}
378		MACHINE=${MACHINE%64}
379		MACHINE_ARCH=mips64eb
380		;;
381
382	ews4800mips|mipsco|newsmips|sgimips)
383		MACHINE_ARCH=mipseb
384		;;
385
386	algor64|cobalt64|pmax64)
387		makewrappermachine=${MACHINE}
388		MACHINE=${MACHINE%64}
389		MACHINE_ARCH=mips64el
390		;;
391
392	algor|arc|cobalt|hpcmips|pmax)
393		MACHINE_ARCH=mipsel
394		;;
395
396	evbppc64|macppc64|ofppc64)
397		makewrappermachine=${MACHINE}
398		MACHINE=${MACHINE%64}
399		MACHINE_ARCH=powerpc64
400		;;
401
402	amigappc|bebox|evbppc|ibmnws|macppc|mvmeppc|ofppc|prep|rs6000|sandpoint)
403		MACHINE_ARCH=powerpc
404		;;
405
406	evbsh3)			# no default MACHINE_ARCH
407		;;
408
409	mmeye)
410		MACHINE_ARCH=sh3eb
411		;;
412
413	dreamcast|hpcsh|landisk)
414		MACHINE_ARCH=sh3el
415		;;
416
417	amd64)
418		MACHINE_ARCH=x86_64
419		;;
420
421	alpha|i386|sparc|sparc64|vax|ia64)
422		MACHINE_ARCH=${MACHINE}
423		;;
424
425	*)
426		bomb "Unknown target MACHINE: ${MACHINE}"
427		;;
428
429	esac
430}
431
432validatearch()
433{
434	# Ensure that the MACHINE_ARCH exists (and is supported by build.sh).
435	#
436	case "${MACHINE_ARCH}" in
437
438	alpha|arm|armeb|hppa|i386|m68000|m68k|mipse[bl]|mips64e[bl]|powerpc|powerpc64|sh3e[bl]|sparc|sparc64|vax|x86_64|ia64)
439		;;
440
441	"")
442		bomb "No MACHINE_ARCH provided"
443		;;
444
445	*)
446		bomb "Unknown target MACHINE_ARCH: ${MACHINE_ARCH}"
447		;;
448
449	esac
450
451	# Determine valid MACHINE_ARCHs for MACHINE
452	#
453	case "${MACHINE}" in
454
455	evbarm)
456		arches="arm armeb"
457		;;
458
459	algor|cobalt|pmax)
460		arches="mipsel mips64el"
461		;;
462
463	evbmips|sbmips)
464		arches="mipseb mipsel mips64eb mips64el"
465		;;
466
467	sgimips)
468		arches="mipseb mips64eb"
469		;;
470
471	evbsh3)
472		arches="sh3eb sh3el"
473		;;
474
475	macppc|evbppc|ofppc)
476		arches="powerpc powerpc64"
477		;;
478	*)
479		oma="${MACHINE_ARCH}"
480		getarch
481		arches="${MACHINE_ARCH}"
482		MACHINE_ARCH="${oma}"
483		;;
484
485	esac
486
487	# Ensure that MACHINE_ARCH supports MACHINE
488	#
489	archok=false
490	for a in ${arches}; do
491		if [ "${a}" = "${MACHINE_ARCH}" ]; then
492			archok=true
493			break
494		fi
495	done
496	${archok} ||
497	    bomb "MACHINE_ARCH '${MACHINE_ARCH}' does not support MACHINE '${MACHINE}'"
498}
499
500# nobomb_getmakevar --
501# Given the name of a make variable in $1, print make's idea of the
502# value of that variable, or return 1 if there's an error.
503#
504nobomb_getmakevar()
505{
506	[ -x "${make}" ] || return 1
507	"${make}" -m ${TOP}/share/mk -s -B -f- _x_ <<EOF || return 1
508_x_:
509	echo \${$1}
510.include <bsd.prog.mk>
511.include <bsd.kernobj.mk>
512EOF
513}
514
515# nobomb_getmakevar --
516# Given the name of a make variable in $1, print make's idea of the
517# value of that variable, or bomb if there's an error.
518#
519bomb_getmakevar()
520{
521	[ -x "${make}" ] || bomb "bomb_getmakevar $1: ${make} is not executable"
522	nobomb_getmakevar "$1" || bomb "bomb_getmakevar $1: ${make} failed"
523}
524
525# nobomb_getmakevar --
526# Given the name of a make variable in $1, print make's idea of the
527# value of that variable, or print a literal '$' followed by the
528# variable name if ${make} is not executable.  This is intended for use in
529# messages that need to be readable even if $make hasn't been built,
530# such as when build.sh is run with the "-n" option.
531#
532getmakevar()
533{
534	if [ -x "${make}" ]; then
535		bomb_getmakevar "$1"
536	else
537		echo "\$$1"
538	fi
539}
540
541setmakeenv()
542{
543	eval "$1='$2'; export $1"
544	makeenv="${makeenv} $1"
545}
546
547unsetmakeenv()
548{
549	eval "unset $1"
550	makeenv="${makeenv} $1"
551}
552
553# Given a variable name in $1, modify the variable in place as follows:
554# For each space-separated word in the variable, call resolvepath.
555resolvepaths()
556{
557	local var="$1"
558	local val
559	eval val=\"\${${var}}\"
560	local newval=''
561	local word
562	for word in ${val}; do
563		resolvepath word
564		newval="${newval}${newval:+ }${word}"
565	done
566	eval ${var}=\"\${newval}\"
567}
568
569# Given a variable name in $1, modify the variable in place as follows:
570# Convert possibly-relative path to absolute path by prepending
571# ${TOP} if necessary.  Also delete trailing "/", if any.
572resolvepath()
573{
574	local var="$1"
575	local val
576	eval val=\"\${${var}}\"
577	case "${val}" in
578	/)
579		;;
580	/*)
581		val="${val%/}"
582		;;
583	*)
584		val="${TOP}/${val%/}"
585		;;
586	esac
587	eval ${var}=\"\${val}\"
588}
589
590usage()
591{
592	if [ -n "$*" ]; then
593		echo ""
594		echo "${progname}: $*"
595	fi
596	cat <<_usage_
597
598Usage: ${progname} [-EnorUux] [-a arch] [-B buildid] [-C cdextras]
599                [-D dest] [-j njob] [-M obj] [-m mach] [-N noisy]
600                [-O obj] [-R release] [-S seed] [-T tools]
601                [-V var=[value]] [-w wrapper] [-X x11src] [-Y extsrcsrc]
602                [-Z var]
603                operation [...]
604
605 Build operations (all imply "obj" and "tools"):
606    build               Run "make build".
607    distribution        Run "make distribution" (includes DESTDIR/etc/ files).
608    release             Run "make release" (includes kernels & distrib media).
609
610 Other operations:
611    help                Show this message and exit.
612    makewrapper         Create ${toolprefix}make-\${MACHINE} wrapper and ${toolprefix}make.
613                        Always performed.
614    cleandir            Run "make cleandir".  [Default unless -u is used]
615    obj                 Run "make obj".  [Default unless -o is used]
616    tools               Build and install tools.
617    install=idir        Run "make installworld" to \`idir' to install all sets
618                        except \`etc'.  Useful after "distribution" or "release"
619    kernel=conf         Build kernel with config file \`conf'
620    releasekernel=conf  Install kernel built by kernel=conf to RELEASEDIR.
621    modules             Build kernel modules.
622    rumptest            Do a linktest for rump (for developers).
623    sets                Create binary sets in
624                        RELEASEDIR/RELEASEMACHINEDIR/binary/sets.
625                        DESTDIR should be populated beforehand.
626    sourcesets          Create source sets in RELEASEDIR/source/sets.
627    syspkgs             Create syspkgs in
628                        RELEASEDIR/RELEASEMACHINEDIR/binary/syspkgs.
629    iso-image           Create CD-ROM image in RELEASEDIR/iso.
630    iso-image-source    Create CD-ROM image with source in RELEASEDIR/iso.
631    params              Display various make(1) parameters.
632
633 Options:
634    -a arch     Set MACHINE_ARCH to arch.  [Default: deduced from MACHINE]
635    -B buildId  Set BUILDID to buildId.
636    -C cdextras Append cdextras to CDEXTRA variable for inclusion on CD-ROM.
637    -D dest     Set DESTDIR to dest.  [Default: destdir.MACHINE]
638    -E          Set "expert" mode; disables various safety checks.
639                Should not be used without expert knowledge of the build system.
640    -h          Print this help message.
641    -j njob     Run up to njob jobs in parallel; see make(1) -j.
642    -M obj      Set obj root directory to obj; sets MAKEOBJDIRPREFIX.
643                Unsets MAKEOBJDIR.
644    -m mach     Set MACHINE to mach; not required if NetBSD native.
645    -N noisy    Set the noisyness (MAKEVERBOSE) level of the build:
646                    0   Minimal output ("quiet")
647                    1   Describe what is occurring
648                    2   Describe what is occurring and echo the actual command
649                    3   Ignore the effect of the "@" prefix in make commands
650                    4   Trace shell commands using the shell's -x flag
651                [Default: 2]
652    -n          Show commands that would be executed, but do not execute them.
653    -O obj      Set obj root directory to obj; sets a MAKEOBJDIR pattern.
654                Unsets MAKEOBJDIRPREFIX.
655    -o          Set MKOBJDIRS=no; do not create objdirs at start of build.
656    -R release  Set RELEASEDIR to release.  [Default: releasedir]
657    -r          Remove contents of TOOLDIR and DESTDIR before building.
658    -S seed     Set BUILDSEED to seed.  [Default: NetBSD-majorversion]
659    -T tools    Set TOOLDIR to tools.  If unset, and TOOLDIR is not set in
660                the environment, ${toolprefix}make will be (re)built unconditionally.
661    -U          Set MKUNPRIVED=yes; build without requiring root privileges,
662                install from an UNPRIVED build with proper file permissions.
663    -u          Set MKUPDATE=yes; do not run "make cleandir" first.
664                Without this, everything is rebuilt, including the tools.
665    -V v=[val]  Set variable \`v' to \`val'.
666    -w wrapper  Create ${toolprefix}make script as wrapper.
667                [Default: \${TOOLDIR}/bin/${toolprefix}make-\${MACHINE}]
668    -X x11src   Set X11SRCDIR to x11src.  [Default: /usr/xsrc]
669    -x          Set MKX11=yes; build X11 from X11SRCDIR
670    -Y extsrcsrc
671                Set EXTSRCSRCDIR to extsrcsrc.  [Default: /usr/extsrc]
672    -y          Set MKEXTSRC=yes; build extsrc from EXTSRCSRCDIR
673    -Z v        Unset ("zap") variable \`v'.
674
675_usage_
676	exit 1
677}
678
679parseoptions()
680{
681	opts='a:B:C:D:Ehj:M:m:N:nO:oR:rS:T:UuV:w:xX:yY:Z:'
682	opt_a=no
683
684	if type getopts >/dev/null 2>&1; then
685		# Use POSIX getopts.
686		#
687		getoptcmd='getopts ${opts} opt && opt=-${opt}'
688		optargcmd=':'
689		optremcmd='shift $((${OPTIND} -1))'
690	else
691		type getopt >/dev/null 2>&1 ||
692		    bomb "/bin/sh shell is too old; try ksh or bash"
693
694		# Use old-style getopt(1) (doesn't handle whitespace in args).
695		#
696		args="$(getopt ${opts} $*)"
697		[ $? = 0 ] || usage
698		set -- ${args}
699
700		getoptcmd='[ $# -gt 0 ] && opt="$1" && shift'
701		optargcmd='OPTARG="$1"; shift'
702		optremcmd=':'
703	fi
704
705	# Parse command line options.
706	#
707	while eval ${getoptcmd}; do
708		case ${opt} in
709
710		-a)
711			eval ${optargcmd}
712			MACHINE_ARCH=${OPTARG}
713			opt_a=yes
714			;;
715
716		-B)
717			eval ${optargcmd}
718			BUILDID=${OPTARG}
719			;;
720
721		-C)
722			eval ${optargcmd}; resolvepaths OPTARG
723			CDEXTRA="${CDEXTRA}${CDEXTRA:+ }${OPTARG}"
724			;;
725
726		-D)
727			eval ${optargcmd}; resolvepath OPTARG
728			setmakeenv DESTDIR "${OPTARG}"
729			;;
730
731		-E)
732			do_expertmode=true
733			;;
734
735		-j)
736			eval ${optargcmd}
737			parallel="-j ${OPTARG}"
738			;;
739
740		-M)
741			eval ${optargcmd}; resolvepath OPTARG
742			case "${OPTARG}" in
743			\$*)	usage "-M argument must not begin with '$'"
744				;;
745			*\$*)	# can use resolvepath, but can't set TOP_objdir
746				resolvepath OPTARG
747				;;
748			*)	resolvepath OPTARG
749				TOP_objdir="${OPTARG}${TOP}"
750				;;
751			esac
752			unsetmakeenv MAKEOBJDIR
753			setmakeenv MAKEOBJDIRPREFIX "${OPTARG}"
754			;;
755
756			# -m overrides MACHINE_ARCH unless "-a" is specified
757		-m)
758			eval ${optargcmd}
759			MACHINE="${OPTARG}"
760			[ "${opt_a}" != "yes" ] && getarch
761			;;
762
763		-N)
764			eval ${optargcmd}
765			case "${OPTARG}" in
766			0|1|2|3|4)
767				setmakeenv MAKEVERBOSE "${OPTARG}"
768				;;
769			*)
770				usage "'${OPTARG}' is not a valid value for -N"
771				;;
772			esac
773			;;
774
775		-n)
776			runcmd=echo
777			;;
778
779		-O)
780			eval ${optargcmd}
781			case "${OPTARG}" in
782			*\$*)	usage "-O argument must not contain '$'"
783				;;
784			*)	resolvepath OPTARG
785				TOP_objdir="${OPTARG}"
786				;;
787			esac
788			unsetmakeenv MAKEOBJDIRPREFIX
789			setmakeenv MAKEOBJDIR "\${.CURDIR:C,^$TOP,$OPTARG,}"
790			;;
791
792		-o)
793			MKOBJDIRS=no
794			;;
795
796		-R)
797			eval ${optargcmd}; resolvepath OPTARG
798			setmakeenv RELEASEDIR "${OPTARG}"
799			;;
800
801		-r)
802			do_removedirs=true
803			do_rebuildmake=true
804			;;
805
806		-S)
807			eval ${optargcmd}
808			setmakeenv BUILDSEED "${OPTARG}"
809			;;
810
811		-T)
812			eval ${optargcmd}; resolvepath OPTARG
813			TOOLDIR="${OPTARG}"
814			export TOOLDIR
815			;;
816
817		-U)
818			setmakeenv MKUNPRIVED yes
819			;;
820
821		-u)
822			setmakeenv MKUPDATE yes
823			;;
824
825		-V)
826			eval ${optargcmd}
827			case "${OPTARG}" in
828		    # XXX: consider restricting which variables can be changed?
829			[a-zA-Z_][a-zA-Z_0-9]*=*)
830				setmakeenv "${OPTARG%%=*}" "${OPTARG#*=}"
831				;;
832			*)
833				usage "-V argument must be of the form 'var=[value]'"
834				;;
835			esac
836			;;
837
838		-w)
839			eval ${optargcmd}; resolvepath OPTARG
840			makewrapper="${OPTARG}"
841			;;
842
843		-X)
844			eval ${optargcmd}; resolvepath OPTARG
845			setmakeenv X11SRCDIR "${OPTARG}"
846			;;
847
848		-x)
849			setmakeenv MKX11 yes
850			;;
851
852		-Y)
853			eval ${optargcmd}; resolvepath OPTARG
854			setmakeenv EXTSRCSRCDIR "${OPTARG}"
855			;;
856
857		-y)
858			setmakeenv MKEXTSRC yes
859			;;
860
861		-Z)
862			eval ${optargcmd}
863		    # XXX: consider restricting which variables can be unset?
864			unsetmakeenv "${OPTARG}"
865			;;
866
867		--)
868			break
869			;;
870
871		-'?'|-h)
872			usage
873			;;
874
875		esac
876	done
877
878	# Validate operations.
879	#
880	eval ${optremcmd}
881	while [ $# -gt 0 ]; do
882		op=$1; shift
883		operations="${operations} ${op}"
884
885		case "${op}" in
886
887		help)
888			usage
889			;;
890
891		makewrapper|cleandir|obj|tools|build|distribution|release|sets|sourcesets|syspkgs|params)
892			;;
893
894		iso-image)
895			op=iso_image	# used as part of a variable name
896			;;
897
898		iso-image-source)
899			op=iso_image_source   # used as part of a variable name
900			;;
901
902		kernel=*|releasekernel=*)
903			arg=${op#*=}
904			op=${op%%=*}
905			[ -n "${arg}" ] ||
906			    bomb "Must supply a kernel name with \`${op}=...'"
907			;;
908
909		modules)
910			op=modules
911			;;
912
913		install=*)
914			arg=${op#*=}
915			op=${op%%=*}
916			[ -n "${arg}" ] ||
917			    bomb "Must supply a directory with \`install=...'"
918			;;
919
920		rump|rumptest)
921			op=${op}
922			;;
923
924		*)
925			usage "Unknown operation \`${op}'"
926			;;
927
928		esac
929		eval do_${op}=true
930	done
931	[ -n "${operations}" ] || usage "Missing operation to perform."
932
933	# Set up MACHINE*.  On a NetBSD host, these are allowed to be unset.
934	#
935	if [ -z "${MACHINE}" ]; then
936		[ "${uname_s}" = "NetBSD" ] ||
937		    bomb "MACHINE must be set, or -m must be used, for cross builds."
938		MACHINE=${uname_m}
939	fi
940	[ -n "${MACHINE_ARCH}" ] || getarch
941	validatearch
942
943	# Set up default make(1) environment.
944	#
945	makeenv="${makeenv} TOOLDIR MACHINE MACHINE_ARCH MAKEFLAGS"
946	[ -z "${BUILDID}" ] || makeenv="${makeenv} BUILDID"
947	MAKEFLAGS="-de -m ${TOP}/share/mk ${MAKEFLAGS} MKOBJDIRS=${MKOBJDIRS-yes}"
948	export MAKEFLAGS MACHINE MACHINE_ARCH
949}
950
951sanitycheck()
952{
953	# If the PATH contains any non-absolute components (including,
954	# but not limited to, "." or ""), then complain.  As an exception,
955	# allow "" or "." as the last component of the PATH.  This is fatal
956	# if expert mode is not in effect.
957	#
958	local path="${PATH}"
959	path="${path%:}"	# delete trailing ":"
960	path="${path%:.}"	# delete trailing ":."
961	case ":${path}:/" in
962	*:[!/]*)
963		if ${do_expertmode}; then
964			warning "PATH contains non-absolute components"
965		else
966			bomb "PATH environment variable must not" \
967			     "contain non-absolute components"
968		fi
969		;;
970	esac
971}
972
973# print_tooldir_make --
974# Try to find and print a path to an existing
975# ${TOOLDIR}/bin/${toolprefix}make, for use by rebuildmake() before a
976# new version of ${toolprefix}make has been built.
977#
978# * If TOOLDIR was set in the environment or on the command line, use
979#   that value.
980# * Otherwise try to guess what TOOLDIR would be if not overridden by
981#   /etc/mk.conf, and check whether the resulting directory contains
982#   a copy of ${toolprefix}make (this should work for everybody who
983#   doesn't override TOOLDIR via /etc/mk.conf);
984# * Failing that, search for ${toolprefix}make, nbmake, bmake, or make,
985#   in the PATH (this might accidentally find a non-NetBSD version of
986#   make, which will lead to failure in the next step);
987# * If a copy of make was found above, try to use it with
988#   nobomb_getmakevar to find the correct value for TOOLDIR, and believe the
989#   result only if it's a directory that already exists;
990# * If a value of TOOLDIR was found above, and if
991#   ${TOOLDIR}/bin/${toolprefix}make exists, print that value.
992#
993print_tooldir_make()
994{
995	local possible_TOP_OBJ
996	local possible_TOOLDIR
997	local possible_make
998	local tooldir_make
999
1000	if [ -n "${TOOLDIR}" ]; then
1001		echo "${TOOLDIR}/bin/${toolprefix}make"
1002		return 0
1003	fi
1004
1005	# Set host_ostype to something like "NetBSD-4.5.6-i386".  This
1006	# is intended to match the HOST_OSTYPE variable in <bsd.own.mk>.
1007	#
1008	local host_ostype="${uname_s}-$(
1009		echo "${uname_r}" | sed -e 's/([^)]*)//g' -e 's/ /_/g'
1010		)-$(
1011		echo "${uname_p}" | sed -e 's/([^)]*)//g' -e 's/ /_/g'
1012		)"
1013
1014	# Look in a few potential locations for
1015	# ${possible_TOOLDIR}/bin/${toolprefix}make.
1016	# If we find it, then set possible_make.
1017	#
1018	# In the usual case (without interference from environment
1019	# variables or /etc/mk.conf), <bsd.own.mk> should set TOOLDIR to
1020	# "${_SRC_TOP_OBJ_}/tooldir.${host_ostype}".
1021	#
1022	# In practice it's difficult to figure out the correct value
1023	# for _SRC_TOP_OBJ_.  In the easiest case, when the -M or -O
1024	# options were passed to build.sh, then ${TOP_objdir} will be
1025	# the correct value.  We also try a few other possibilities, but
1026	# we do not replicate all the logic of <bsd.obj.mk>.
1027	#
1028	for possible_TOP_OBJ in \
1029		"${TOP_objdir}" \
1030		"${MAKEOBJDIRPREFIX:+${MAKEOBJDIRPREFIX}${TOP}}" \
1031		"${TOP}" \
1032		"${TOP}/obj" \
1033		"${TOP}/obj.${MACHINE}"
1034	do
1035		[ -n "${possible_TOP_OBJ}" ] || continue
1036		possible_TOOLDIR="${possible_TOP_OBJ}/tooldir.${host_ostype}"
1037		possible_make="${possible_TOOLDIR}/bin/${toolprefix}make"
1038		if [ -x "${possible_make}" ]; then
1039			break
1040		else
1041			unset possible_make
1042		fi
1043	done
1044
1045	# If the above didn't work, search the PATH for a suitable
1046	# ${toolprefix}make, nbmake, bmake, or make.
1047	#
1048	: ${possible_make:=$(find_in_PATH ${toolprefix}make '')}
1049	: ${possible_make:=$(find_in_PATH nbmake '')}
1050	: ${possible_make:=$(find_in_PATH bmake '')}
1051	: ${possible_make:=$(find_in_PATH make '')}
1052
1053	# At this point, we don't care whether possible_make is in the
1054	# correct TOOLDIR or not; we simply want it to be usable by
1055	# getmakevar to help us find the correct TOOLDIR.
1056	#
1057	# Use ${possible_make} with nobomb_getmakevar to try to find
1058	# the value of TOOLDIR.  Believe the result only if it's
1059	# a directory that already exists and contains bin/${toolprefix}make.
1060	#
1061	if [ -x "${possible_make}" ]; then
1062		possible_TOOLDIR="$(
1063			make="${possible_make}" nobomb_getmakevar TOOLDIR
1064			)"
1065		if [ $? = 0 ] && [ -n "${possible_TOOLDIR}" ] \
1066		    && [ -d "${possible_TOOLDIR}" ];
1067		then
1068			tooldir_make="${possible_TOOLDIR}/bin/${toolprefix}make"
1069			if [ -x "${tooldir_make}" ]; then
1070				echo "${tooldir_make}"
1071				return 0
1072			fi
1073		fi
1074	fi
1075	return 1
1076}
1077
1078# rebuildmake --
1079# Rebuild nbmake in a temporary directory if necessary.  Sets $make
1080# to a path to the nbmake executable.  Sets done_rebuildmake=true
1081# if nbmake was rebuilt.
1082#
1083# There is a cyclic dependency between building nbmake and choosing
1084# TOOLDIR: TOOLDIR may be affected by settings in /etc/mk.conf, so we
1085# would like to use getmakevar to get the value of TOOLDIR; but we can't
1086# use getmakevar before we have an up to date version of nbmake; we
1087# might already have an up to date version of nbmake in TOOLDIR, but we
1088# don't yet know where TOOLDIR is.
1089#
1090# The default value of TOOLDIR also depends on the location of the top
1091# level object directory, so $(getmakevar TOOLDIR) invoked before or
1092# after making the top level object directory may produce different
1093# results.
1094#
1095# Strictly speaking, we should do the following:
1096#
1097#    1. build a new version of nbmake in a temporary directory;
1098#    2. use the temporary nbmake to create the top level obj directory;
1099#    3. use $(getmakevar TOOLDIR) with the temporary nbmake to
1100#       get the corect value of TOOLDIR;
1101#    4. move the temporary nbmake to ${TOOLDIR}/bin/nbmake.
1102#
1103# However, people don't like building nbmake unnecessarily if their
1104# TOOLDIR has not changed since an earlier build.  We try to avoid
1105# rebuilding a temporary version of nbmake by taking some shortcuts to
1106# guess a value for TOOLDIR, looking for an existing version of nbmake
1107# in that TOOLDIR, and checking whether that nbmake is newer than the
1108# sources used to build it.
1109#
1110rebuildmake()
1111{
1112	make="$(print_tooldir_make)"
1113	if [ -n "${make}" ] && [ -x "${make}" ]; then
1114		for f in usr.bin/make/*.[ch] usr.bin/make/lst.lib/*.[ch]; do
1115			if [ "${f}" -nt "${make}" ]; then
1116				statusmsg "${make} outdated" \
1117					"(older than ${f}), needs building."
1118				do_rebuildmake=true
1119				break
1120			fi
1121		done
1122	else
1123		statusmsg "No \$TOOLDIR/bin/${toolprefix}make, needs building."
1124		do_rebuildmake=true
1125	fi
1126
1127	# Build bootstrap ${toolprefix}make if needed.
1128	if ${do_rebuildmake}; then
1129		statusmsg "Bootstrapping ${toolprefix}make"
1130		${runcmd} cd "${tmpdir}"
1131		${runcmd} env CC="${HOST_CC-cc}" CPPFLAGS="${HOST_CPPFLAGS}" \
1132			CFLAGS="${HOST_CFLAGS--O}" LDFLAGS="${HOST_LDFLAGS}" \
1133			${HOST_SH} "${TOP}/tools/make/configure" ||
1134		    bomb "Configure of ${toolprefix}make failed"
1135		${runcmd} ${HOST_SH} buildmake.sh ||
1136		    bomb "Build of ${toolprefix}make failed"
1137		make="${tmpdir}/${toolprefix}make"
1138		${runcmd} cd "${TOP}"
1139		${runcmd} rm -f usr.bin/make/*.o usr.bin/make/lst.lib/*.o
1140		done_rebuildmake=true
1141	fi
1142}
1143
1144validatemakeparams()
1145{
1146	if [ "${runcmd}" = "echo" ]; then
1147		TOOLCHAIN_MISSING=no
1148		EXTERNAL_TOOLCHAIN=""
1149	else
1150		TOOLCHAIN_MISSING=$(bomb_getmakevar TOOLCHAIN_MISSING)
1151		EXTERNAL_TOOLCHAIN=$(bomb_getmakevar EXTERNAL_TOOLCHAIN)
1152	fi
1153	if [ "${TOOLCHAIN_MISSING}" = "yes" ] && \
1154	   [ -z "${EXTERNAL_TOOLCHAIN}" ]; then
1155		${runcmd} echo "ERROR: build.sh (in-tree cross-toolchain) is not yet available for"
1156		${runcmd} echo "	MACHINE:      ${MACHINE}"
1157		${runcmd} echo "	MACHINE_ARCH: ${MACHINE_ARCH}"
1158		${runcmd} echo ""
1159		${runcmd} echo "All builds for this platform should be done via a traditional make"
1160		${runcmd} echo "If you wish to use an external cross-toolchain, set"
1161		${runcmd} echo "	EXTERNAL_TOOLCHAIN=<path to toolchain root>"
1162		${runcmd} echo "in either the environment or mk.conf and rerun"
1163		${runcmd} echo "	${progname} $*"
1164		exit 1
1165	fi
1166
1167	# Normalise MKOBJDIRS, MKUNPRIVED, and MKUPDATE
1168	# These may be set as build.sh options or in "mk.conf".
1169	# Don't export them as they're only used for tests in build.sh.
1170	#
1171	MKOBJDIRS=$(getmakevar MKOBJDIRS)
1172	MKUNPRIVED=$(getmakevar MKUNPRIVED)
1173	MKUPDATE=$(getmakevar MKUPDATE)
1174
1175	if [ "${MKOBJDIRS}" != "no" ]; then
1176		# Create the top-level object directory.
1177		#
1178		# "make obj NOSUBDIR=" can handle most cases, but it
1179		# can't handle the case where MAKEOBJDIRPREFIX is set
1180		# while the corresponding directory does not exist
1181		# (rules in <bsd.obj.mk> would abort the build).  We
1182		# therefore have to handle the MAKEOBJDIRPREFIX case
1183		# without invoking "make obj".  The MAKEOBJDIR case
1184		# could be handled either way, but we choose to handle
1185		# it similarly to MAKEOBJDIRPREFIX.
1186		#
1187		if [ -n "${TOP_obj}" ]; then
1188			# It must have been set by the "-M" or "-O"
1189			# command line options, so there's no need to
1190			# use getmakevar
1191			:
1192		elif [ -n "$MAKEOBJDIRPREFIX" ]; then
1193			TOP_obj="$(getmakevar MAKEOBJDIRPREFIX)${TOP}"
1194		elif [ -n "$MAKEOBJDIR" ]; then
1195			TOP_obj="$(getmakevar MAKEOBJDIR)"
1196		fi
1197		if [ -n "$TOP_obj" ]; then
1198			${runcmd} mkdir -p "${TOP_obj}" ||
1199			    bomb "Can't create top level object directory" \
1200					"${TOP_obj}"
1201		else
1202			${runcmd} "${make}" -m ${TOP}/share/mk obj NOSUBDIR= ||
1203			    bomb "Can't create top level object directory" \
1204					"using make obj"
1205		fi
1206
1207		# make obj in tools to ensure that the objdir for "tools"
1208		# is available.
1209		#
1210		${runcmd} cd tools
1211		${runcmd} "${make}" -m ${TOP}/share/mk obj NOSUBDIR= ||
1212		    bomb "Failed to make obj in tools"
1213		${runcmd} cd "${TOP}"
1214	fi
1215
1216	# Find TOOLDIR, DESTDIR, and RELEASEDIR, according to getmakevar,
1217	# and bomb if they have changed from the values we had from the
1218	# command line or environment.
1219	#
1220	# This must be done after creating the top-level object directory.
1221	#
1222	for var in TOOLDIR DESTDIR RELEASEDIR
1223	do
1224		eval oldval=\"\$${var}\"
1225		newval="$(getmakevar $var)"
1226		if ! $do_expertmode; then
1227			: ${_SRC_TOP_OBJ_:=$(getmakevar _SRC_TOP_OBJ_)}
1228			case "$var" in
1229			DESTDIR)
1230				: ${newval:=${_SRC_TOP_OBJ_}/destdir.${MACHINE}}
1231				makeenv="${makeenv} DESTDIR"
1232				;;
1233			RELEASEDIR)
1234				: ${newval:=${_SRC_TOP_OBJ_}/releasedir}
1235				makeenv="${makeenv} RELEASEDIR"
1236				;;
1237			esac
1238		fi
1239		if [ -n "$oldval" ] && [ "$oldval" != "$newval" ]; then
1240			bomb "Value of ${var} has changed" \
1241				"(was \"${oldval}\", now \"${newval}\")"
1242		fi
1243		eval ${var}=\"\${newval}\"
1244		eval export ${var}
1245		statusmsg2 "${var} path:" "${newval}"
1246	done
1247
1248	# RELEASEMACHINEDIR is just a subdir name, e.g. "i386".
1249	RELEASEMACHINEDIR=$(getmakevar RELEASEMACHINEDIR)
1250
1251	# Check validity of TOOLDIR and DESTDIR.
1252	#
1253	if [ -z "${TOOLDIR}" ] || [ "${TOOLDIR}" = "/" ]; then
1254		bomb "TOOLDIR '${TOOLDIR}' invalid"
1255	fi
1256	removedirs="${TOOLDIR}"
1257
1258	if [ -z "${DESTDIR}" ] || [ "${DESTDIR}" = "/" ]; then
1259		if ${do_build} || ${do_distribution} || ${do_release}; then
1260			if ! ${do_build} || \
1261			   [ "${uname_s}" != "NetBSD" ] || \
1262			   [ "${uname_m}" != "${MACHINE}" ]; then
1263				bomb "DESTDIR must != / for cross builds, or ${progname} 'distribution' or 'release'."
1264			fi
1265			if ! ${do_expertmode}; then
1266				bomb "DESTDIR must != / for non -E (expert) builds"
1267			fi
1268			statusmsg "WARNING: Building to /, in expert mode."
1269			statusmsg "         This may cause your system to break!  Reasons include:"
1270			statusmsg "            - your kernel is not up to date"
1271			statusmsg "            - the libraries or toolchain have changed"
1272			statusmsg "         YOU HAVE BEEN WARNED!"
1273		fi
1274	else
1275		removedirs="${removedirs} ${DESTDIR}"
1276	fi
1277	if ${do_build} || ${do_distribution} || ${do_release}; then
1278		if ! ${do_expertmode} && \
1279		    [ "$id_u" -ne 0 ] && \
1280		    [ "${MKUNPRIVED}" = "no" ] ; then
1281			bomb "-U or -E must be set for build as an unprivileged user."
1282		fi
1283	fi
1284	if ${do_releasekernel} && [ -z "${RELEASEDIR}" ]; then
1285		bomb "Must set RELEASEDIR with \`releasekernel=...'"
1286	fi
1287
1288	# Install as non-root is a bad idea.
1289	#
1290	if ${do_install} && [ "$id_u" -ne 0 ] ; then
1291		if ${do_expertmode}; then
1292			warning "Will install as an unprivileged user."
1293		else
1294			bomb "-E must be set for install as an unprivileged user."
1295		fi
1296	fi
1297
1298	# If a previous build.sh run used -U (and therefore created a
1299	# METALOG file), then most subsequent build.sh runs must also
1300	# use -U.  If DESTDIR is about to be removed, then don't perform
1301	# this check.
1302	#
1303	case "${do_removedirs} ${removedirs} " in
1304	true*" ${DESTDIR} "*)
1305		# DESTDIR is about to be removed
1306		;;
1307	*)
1308		if ( ${do_build} || ${do_distribution} || ${do_release} || \
1309		    ${do_install} ) && \
1310		    [ -e "${DESTDIR}/METALOG" ] && \
1311		    [ "${MKUNPRIVED}" = "no" ] ; then
1312			if $do_expertmode; then
1313				warning "A previous build.sh run specified -U."
1314			else
1315				bomb "A previous build.sh run specified -U; you must specify it again now."
1316			fi
1317		fi
1318		;;
1319	esac
1320}
1321
1322
1323createmakewrapper()
1324{
1325	# Remove the target directories.
1326	#
1327	if ${do_removedirs}; then
1328		for f in ${removedirs}; do
1329			statusmsg "Removing ${f}"
1330			${runcmd} rm -r -f "${f}"
1331		done
1332	fi
1333
1334	# Recreate $TOOLDIR.
1335	#
1336	${runcmd} mkdir -p "${TOOLDIR}/bin" ||
1337	    bomb "mkdir of '${TOOLDIR}/bin' failed"
1338
1339	# If we did not previously rebuild ${toolprefix}make, then
1340	# check whether $make is still valid and the same as the output
1341	# from print_tooldir_make.  If not, then rebuild make now.  A
1342	# possible reason for this being necessary is that the actual
1343	# value of TOOLDIR might be different from the value guessed
1344	# before the top level obj dir was created.
1345	#
1346	if ! ${done_rebuildmake} && \
1347	    ( [ ! -x "$make" ] || [ "$make" != "$(print_tooldir_make)" ] )
1348	then
1349		rebuildmake
1350	fi
1351
1352	# Install ${toolprefix}make if it was built.
1353	#
1354	if ${done_rebuildmake}; then
1355		${runcmd} rm -f "${TOOLDIR}/bin/${toolprefix}make"
1356		${runcmd} cp "${make}" "${TOOLDIR}/bin/${toolprefix}make" ||
1357		    bomb "Failed to install \$TOOLDIR/bin/${toolprefix}make"
1358		make="${TOOLDIR}/bin/${toolprefix}make"
1359		statusmsg "Created ${make}"
1360	fi
1361
1362	# Build a ${toolprefix}make wrapper script, usable by hand as
1363	# well as by build.sh.
1364	#
1365	if [ -z "${makewrapper}" ]; then
1366		makewrapper="${TOOLDIR}/bin/${toolprefix}make-${makewrappermachine:-${MACHINE}}"
1367		[ -z "${BUILDID}" ] || makewrapper="${makewrapper}-${BUILDID}"
1368	fi
1369
1370	${runcmd} rm -f "${makewrapper}"
1371	if [ "${runcmd}" = "echo" ]; then
1372		echo 'cat <<EOF >'${makewrapper}
1373		makewrapout=
1374	else
1375		makewrapout=">>\${makewrapper}"
1376	fi
1377
1378	case "${KSH_VERSION:-${SH_VERSION}}" in
1379	*PD\ KSH*|*MIRBSD\ KSH*)
1380		set +o braceexpand
1381		;;
1382	esac
1383
1384	eval cat <<EOF ${makewrapout}
1385#! ${HOST_SH}
1386# Set proper variables to allow easy "make" building of a NetBSD subtree.
1387# Generated from:  \$NetBSD: build.sh,v 1.242 2010/12/06 09:08:39 pooka Exp $
1388# with these arguments: ${_args}
1389#
1390
1391EOF
1392	{
1393		for f in ${makeenv}; do
1394			if eval "[ -z \"\${$f}\" -a \"\${${f}-X}\" = \"X\" ]"; then
1395				eval echo "unset ${f}"
1396			else
1397				eval echo "${f}=\'\$$(echo ${f})\'\;\ export\ ${f}"
1398			fi
1399		done
1400
1401		eval cat <<EOF
1402MAKEWRAPPERMACHINE=${makewrappermachine:-${MACHINE}}; export MAKEWRAPPERMACHINE
1403USETOOLS=yes; export USETOOLS
1404EOF
1405	} | eval sort -u "${makewrapout}"
1406	eval cat <<EOF "${makewrapout}"
1407
1408exec "\${TOOLDIR}/bin/${toolprefix}make" \${1+"\$@"}
1409EOF
1410	[ "${runcmd}" = "echo" ] && echo EOF
1411	${runcmd} chmod +x "${makewrapper}"
1412	statusmsg2 "Updated makewrapper:" "${makewrapper}"
1413}
1414
1415make_in_dir()
1416{
1417	dir="$1"
1418	op="$2"
1419	${runcmd} cd "${dir}" ||
1420	    bomb "Failed to cd to \"${dir}\""
1421	${runcmd} "${makewrapper}" ${parallel} ${op} ||
1422	    bomb "Failed to make ${op} in \"${dir}\""
1423	${runcmd} cd "${TOP}" ||
1424	    bomb "Failed to cd back to \"${TOP}\""
1425}
1426
1427buildtools()
1428{
1429	if [ "${MKOBJDIRS}" != "no" ]; then
1430		${runcmd} "${makewrapper}" ${parallel} obj-tools ||
1431		    bomb "Failed to make obj-tools"
1432	fi
1433	if [ "${MKUPDATE}" = "no" ]; then
1434		make_in_dir tools cleandir
1435	fi
1436	make_in_dir tools dependall
1437	make_in_dir tools install
1438	statusmsg "Tools built to ${TOOLDIR}"
1439}
1440
1441getkernelconf()
1442{
1443	kernelconf="$1"
1444	if [ "${MKOBJDIRS}" != "no" ]; then
1445		# The correct value of KERNOBJDIR might
1446		# depend on a prior "make obj" in
1447		# ${KERNSRCDIR}/${KERNARCHDIR}/compile.
1448		#
1449		KERNSRCDIR="$(getmakevar KERNSRCDIR)"
1450		KERNARCHDIR="$(getmakevar KERNARCHDIR)"
1451		make_in_dir "${KERNSRCDIR}/${KERNARCHDIR}/compile" obj
1452	fi
1453	KERNCONFDIR="$(getmakevar KERNCONFDIR)"
1454	KERNOBJDIR="$(getmakevar KERNOBJDIR)"
1455	case "${kernelconf}" in
1456	*/*)
1457		kernelconfpath="${kernelconf}"
1458		kernelconfname="${kernelconf##*/}"
1459		;;
1460	*)
1461		kernelconfpath="${KERNCONFDIR}/${kernelconf}"
1462		kernelconfname="${kernelconf}"
1463		;;
1464	esac
1465	kernelbuildpath="${KERNOBJDIR}/${kernelconfname}"
1466}
1467
1468buildkernel()
1469{
1470	if ! ${do_tools} && ! ${buildkernelwarned:-false}; then
1471		# Building tools every time we build a kernel is clearly
1472		# unnecessary.  We could try to figure out whether rebuilding
1473		# the tools is necessary this time, but it doesn't seem worth
1474		# the trouble.  Instead, we say it's the user's responsibility
1475		# to rebuild the tools if necessary.
1476		#
1477		statusmsg "Building kernel without building new tools"
1478		buildkernelwarned=true
1479	fi
1480	getkernelconf $1
1481	statusmsg2 "Building kernel:" "${kernelconf}"
1482	statusmsg2 "Build directory:" "${kernelbuildpath}"
1483	${runcmd} mkdir -p "${kernelbuildpath}" ||
1484	    bomb "Cannot mkdir: ${kernelbuildpath}"
1485	if [ "${MKUPDATE}" = "no" ]; then
1486		make_in_dir "${kernelbuildpath}" cleandir
1487	fi
1488	[ -x "${TOOLDIR}/bin/${toolprefix}config" ] \
1489	|| bomb "${TOOLDIR}/bin/${toolprefix}config does not exist. You need to \"$0 tools\" first."
1490	${runcmd} "${TOOLDIR}/bin/${toolprefix}config" -b "${kernelbuildpath}" \
1491		-s "${TOP}/sys" "${kernelconfpath}" ||
1492	    bomb "${toolprefix}config failed for ${kernelconf}"
1493	make_in_dir "${kernelbuildpath}" depend
1494	make_in_dir "${kernelbuildpath}" all
1495
1496	if [ "${runcmd}" != "echo" ]; then
1497		statusmsg "Kernels built from ${kernelconf}:"
1498		kernlist=$(awk '$1 == "config" { print $2 }' ${kernelconfpath})
1499		for kern in ${kernlist:-netbsd}; do
1500			[ -f "${kernelbuildpath}/${kern}" ] && \
1501			    echo "  ${kernelbuildpath}/${kern}"
1502		done | tee -a "${results}"
1503	fi
1504}
1505
1506releasekernel()
1507{
1508	getkernelconf $1
1509	kernelreldir="${RELEASEDIR}/${RELEASEMACHINEDIR}/binary/kernel"
1510	${runcmd} mkdir -p "${kernelreldir}"
1511	kernlist=$(awk '$1 == "config" { print $2 }' ${kernelconfpath})
1512	for kern in ${kernlist:-netbsd}; do
1513		builtkern="${kernelbuildpath}/${kern}"
1514		[ -f "${builtkern}" ] || continue
1515		releasekern="${kernelreldir}/${kern}-${kernelconfname}.gz"
1516		statusmsg2 "Kernel copy:" "${releasekern}"
1517		if [ "${runcmd}" = "echo" ]; then
1518			echo "gzip -c -9 < ${builtkern} > ${releasekern}"
1519		else
1520			gzip -c -9 < "${builtkern}" > "${releasekern}"
1521		fi
1522	done
1523}
1524
1525buildmodules()
1526{
1527	setmakeenv MKBINUTILS no
1528	if ! ${do_tools} && ! ${buildmoduleswarned:-false}; then
1529		# Building tools every time we build modules is clearly
1530		# unnecessary as well as a kernel.
1531		#
1532		statusmsg "Building modules without building new tools"
1533		buildmoduleswarned=true
1534	fi
1535
1536	statusmsg "Building kernel modules for NetBSD/${MACHINE} ${DISTRIBVER}"
1537	if [ "${MKOBJDIRS}" != "no" ]; then
1538		make_in_dir sys/modules obj ||
1539		    bomb "Failed to make obj in sys/modules"
1540	fi
1541	if [ "${MKUPDATE}" = "no" ]; then
1542		make_in_dir sys/modules cleandir
1543	fi
1544	${runcmd} "${makewrapper}" ${parallel} do-sys-modules ||
1545	    bomb "Failed to make do-sys-modules"
1546
1547	statusmsg "Successful build of kernel modules for NetBSD/${MACHINE} ${DISTRIBVER}"
1548}
1549
1550installworld()
1551{
1552	dir="$1"
1553	${runcmd} "${makewrapper}" INSTALLWORLDDIR="${dir}" installworld ||
1554	    bomb "Failed to make installworld to ${dir}"
1555	statusmsg "Successful installworld to ${dir}"
1556}
1557
1558# Run rump build&link tests.
1559#
1560# To make this feasible for running without having to install includes and
1561# libraries into destdir (i.e. quick), we only run ld.  This is possible
1562# since the rump kernel is a closed namespace apart from calls to rumpuser.
1563# Therefore, if ld complains only about rumpuser symbols, rump kernel
1564# linking was successful.
1565# 
1566# We test that rump links with a number of component configurations.
1567# These attempt to mimic what is encountered in the full build.
1568# See list below.  The list should probably be either autogenerated
1569# or managed elsewhere.  But keep it here until a better idea arises.
1570#
1571# Above all, note that THIS IS NOT A SUBSTITUTE FOR A FULL BUILD.
1572#
1573
1574RUMP_LIBSETS='
1575	-lrump,
1576	-lrumpvfs -lrump,
1577	-lrumpdev -lrump,
1578	-lrumpnet -lrump,
1579	-lrumpkern_tty -lrumpvfs -lrump,
1580	-lrumpfs_tmpfs -lrumpvfs -lrump,
1581	-lrumpfs_ffs -lrumpfs_msdos -lrumpvfs -lrumpdev_disk -lrumpdev -lrump,
1582	-lrumpnet_virtif -lrumpnet_netinet -lrumpnet_net -lrumpnet -lrump,
1583	-lrumpnet_sockin -lrumpfs_smbfs -lrumpdev_netsmb
1584	    -lrumpkern_crypto -lrumpdev -lrumpnet -lrumpvfs -lrump,
1585	-lrumpnet_sockin -lrumpfs_nfs -lrumpnet -lrumpvfs -lrump,
1586	-lrumpdev_cgd -lrumpdev_raidframe -lrumpdev_disk -lrumpdev_rnd
1587	    -lrumpdev_dm -lrumpdev -lrumpvfs -lrumpkern_crypto -lrump'
1588dorump()
1589{
1590	local doclean=""
1591	local doobjs=""
1592
1593	# we cannot link libs without building csu, and that leads to lossage
1594	[ "${1}" != "rumptest" ] && bomb 'build.sh rump not yet functional. ' \
1595	    'did you mean "rumptest"?'
1596
1597	# create obj and distrib dirs
1598	if [ "${MKOBJDIRS}" != "no" ]; then
1599		make_in_dir "${NETBSDSRCDIR}/etc/mtree" obj
1600		make_in_dir "${NETBSDSRCDIR}/sys/rump" obj
1601	fi
1602	${runcmd} "${makewrapper}" ${parallel} do-distrib-dirs \
1603	    || bomb 'could not create distrib-dirs'
1604
1605	[ "${MKUPDATE}" = "no" ] && doclean="cleandir"
1606	targlist="${doclean} ${doobjs} dependall install"
1607	# optimize: for test we build only static libs (3x test speedup)
1608	if [ "${1}" = "rumptest" ] ; then
1609		setmakeenv NOPIC 1
1610		setmakeenv NOPROFILE 1
1611	fi
1612	for cmd in ${targlist} ; do
1613		make_in_dir "${NETBSDSRCDIR}/sys/rump" ${cmd}
1614	done
1615
1616	# if we just wanted to build & install rump, we're done
1617	[ "${1}" != "rumptest" ] && return
1618
1619	${runcmd} cd "${NETBSDSRCDIR}/sys/rump/librump/rumpkern" \
1620	    || bomb "cd to rumpkern failed"
1621	md_quirks=`${runcmd} "${makewrapper}" -V '${_SYMQUIRK}'`
1622	# one little, two little, three little backslashes ...
1623	md_quirks="$(echo ${md_quirks} | sed 's,\\,\\\\,g'";s/'//g" )"
1624	${runcmd} cd "${TOP}" || bomb "cd to ${TOP} failed"
1625	tool_ld=`${runcmd} "${makewrapper}" -V '${LD}'`
1626
1627	local oIFS="${IFS}"
1628	IFS=","
1629	for set in ${RUMP_LIBSETS} ; do
1630		IFS="${oIFS}"
1631		${runcmd} ${tool_ld} -nostdlib -L${DESTDIR}/usr/lib	\
1632		    -static --whole-archive ${set} 2>&1 -o /tmp/rumptest.$$ | \
1633		      awk -v quirks="${md_quirks}" '
1634			/undefined reference/ &&
1635			    !/more undefined references.*follow/{
1636				if (match($NF,
1637				    "`(rumpuser_|__" quirks ")") == 0)
1638					fails[NR] = $0
1639			}
1640			/cannot find -l/{fails[NR] = $0}
1641			/cannot open output file/{fails[NR] = $0}
1642			END{
1643				for (x in fails)
1644					print fails[x]
1645				exit x!=0
1646			}'
1647		[ $? -ne 0 ] && bomb "Testlink of rump failed: ${set}"
1648	done
1649	statusmsg "Rump build&link tests successful"
1650}
1651
1652main()
1653{
1654	initdefaults
1655	_args=$@
1656	parseoptions "$@"
1657
1658	sanitycheck
1659
1660	build_start=$(date)
1661	statusmsg2 "${progname} command:" "$0 $*"
1662	statusmsg2 "${progname} started:" "${build_start}"
1663	statusmsg2 "NetBSD version:"   "${DISTRIBVER}"
1664	statusmsg2 "MACHINE:"          "${MACHINE}"
1665	statusmsg2 "MACHINE_ARCH:"     "${MACHINE_ARCH}"
1666	statusmsg2 "Build platform:"   "${uname_s} ${uname_r} ${uname_m}"
1667	statusmsg2 "HOST_SH:"          "${HOST_SH}"
1668
1669	rebuildmake
1670	validatemakeparams
1671	createmakewrapper
1672
1673	# Perform the operations.
1674	#
1675	for op in ${operations}; do
1676		case "${op}" in
1677
1678		makewrapper)
1679			# no-op
1680			;;
1681
1682		tools)
1683			buildtools
1684			;;
1685
1686		sets)
1687			statusmsg "Building sets from pre-populated ${DESTDIR}"
1688			${runcmd} "${makewrapper}" ${parallel} ${op} ||
1689			    bomb "Failed to make ${op}"
1690			setdir=${RELEASEDIR}/${RELEASEMACHINEDIR}/binary/sets
1691			statusmsg "Built sets to ${setdir}"
1692			;;
1693
1694		cleandir|obj|build|distribution|release|sourcesets|syspkgs|params)
1695			${runcmd} "${makewrapper}" ${parallel} ${op} ||
1696			    bomb "Failed to make ${op}"
1697			statusmsg "Successful make ${op}"
1698			;;
1699
1700		iso-image|iso-image-source)
1701			${runcmd} "${makewrapper}" ${parallel} \
1702			    CDEXTRA="$CDEXTRA" ${op} ||
1703			    bomb "Failed to make ${op}"
1704			statusmsg "Successful make ${op}"
1705			;;
1706
1707		kernel=*)
1708			arg=${op#*=}
1709			buildkernel "${arg}"
1710			;;
1711
1712		releasekernel=*)
1713			arg=${op#*=}
1714			releasekernel "${arg}"
1715			;;
1716
1717		modules)
1718			buildmodules
1719			;;
1720
1721		install=*)
1722			arg=${op#*=}
1723			if [ "${arg}" = "/" ] && \
1724			    (	[ "${uname_s}" != "NetBSD" ] || \
1725				[ "${uname_m}" != "${MACHINE}" ] ); then
1726				bomb "'${op}' must != / for cross builds."
1727			fi
1728			installworld "${arg}"
1729			;;
1730
1731		rump|rumptest)
1732			dorump "${op}"
1733			;;
1734
1735		*)
1736			bomb "Unknown operation \`${op}'"
1737			;;
1738
1739		esac
1740	done
1741
1742	statusmsg2 "${progname} ended:" "$(date)"
1743	if [ -s "${results}" ]; then
1744		echo "===> Summary of results:"
1745		sed -e 's/^===>//;s/^/	/' "${results}"
1746		echo "===> ."
1747	fi
1748}
1749
1750main "$@"
1751