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