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