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