xref: /netbsd/build.sh (revision 4e9d3760)
1#! /usr/bin/env sh
2#	$NetBSD: build.sh,v 1.160 2007/01/29 00:08:13 matt 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|evbarm|hpcarm|iyonix|netwinder|shark|zaurus)
281		MACHINE_ARCH=arm
282		;;
283
284	hp700)
285		MACHINE_ARCH=hppa
286		;;
287
288	sun2)
289		MACHINE_ARCH=m68000
290		;;
291
292	amiga|atari|cesfic|hp300|luna68k|mac68k|mvme68k|news68k|next68k|sun3|x68k)
293		MACHINE_ARCH=m68k
294		;;
295
296	evbmips|sbmips)		# no default MACHINE_ARCH
297		;;
298
299	ews4800mips|mipsco|newsmips|sgimips)
300		MACHINE_ARCH=mipseb
301		;;
302
303	algor|arc|cobalt|hpcmips|playstation2|pmax)
304		MACHINE_ARCH=mipsel
305		;;
306
307	pc532)
308		MACHINE_ARCH=ns32k
309		;;
310
311	evbppc64|macppc64)
312		makewrappermachine=${MACHINE}
313		MACHINE=${MACHINE%64}
314		MACHINE_ARCH=powerpc64
315		;;
316
317	amigappc|bebox|evbppc|ibmnws|macppc|mvmeppc|ofppc|pmppc|prep|sandpoint)
318		MACHINE_ARCH=powerpc
319		;;
320
321	evbsh3)			# no default MACHINE_ARCH
322		;;
323
324	mmeye)
325		MACHINE_ARCH=sh3eb
326		;;
327
328	dreamcast|hpcsh|landisk)
329		MACHINE_ARCH=sh3el
330		;;
331
332	evbsh5)
333		MACHINE_ARCH=sh5el
334		;;
335	amd64)
336		MACHINE_ARCH=x86_64
337		;;
338
339	alpha|i386|sparc|sparc64|vax|ia64)
340		MACHINE_ARCH=${MACHINE}
341		;;
342
343	*)
344		bomb "Unknown target MACHINE: ${MACHINE}"
345		;;
346
347	esac
348}
349
350validatearch()
351{
352	# Ensure that the MACHINE_ARCH exists (and is supported by build.sh).
353	#
354	case "${MACHINE_ARCH}" in
355
356	alpha|arm|armeb|hppa|i386|m68000|m68k|mipse[bl]|mips64e[bl]|ns32k|powerpc|powerpc64|sh[35]e[bl]|sparc|sparc64|vax|x86_64|ia64)
357		;;
358
359	"")
360		bomb "No MACHINE_ARCH provided"
361		;;
362
363	*)
364		bomb "Unknown target MACHINE_ARCH: ${MACHINE_ARCH}"
365		;;
366
367	esac
368
369	# Determine valid MACHINE_ARCHs for MACHINE
370	#
371	case "${MACHINE}" in
372
373	evbarm)
374		arches="arm armeb"
375		;;
376
377	evbmips|sbmips)
378		arches="mipseb mipsel mips64eb mips64el"
379		;;
380
381	sgimips)
382		arches="mipseb mips64eb"
383		;;
384
385	evbsh3)
386		arches="sh3eb sh3el"
387		;;
388
389	evbsh5)
390		arches="sh5eb sh5el"
391		;;
392
393	macppc|evbppc)
394		arches="powerpc powerpc64"
395		;;
396	*)
397		oma="${MACHINE_ARCH}"
398		getarch
399		arches="${MACHINE_ARCH}"
400		MACHINE_ARCH="${oma}"
401		;;
402
403	esac
404
405	# Ensure that MACHINE_ARCH supports MACHINE
406	#
407	archok=false
408	for a in ${arches}; do
409		if [ "${a}" = "${MACHINE_ARCH}" ]; then
410			archok=true
411			break
412		fi
413	done
414	${archok} ||
415	    bomb "MACHINE_ARCH '${MACHINE_ARCH}' does not support MACHINE '${MACHINE}'"
416}
417
418raw_getmakevar()
419{
420	[ -x "${make}" ] || bomb "raw_getmakevar $1: ${make} is not executable"
421	"${make}" -m ${TOP}/share/mk -s -f- _x_ <<EOF || bomb "raw_getmakevar $1: ${make} failed"
422_x_:
423	echo \${$1}
424.include <bsd.prog.mk>
425.include <bsd.kernobj.mk>
426EOF
427}
428
429getmakevar()
430{
431	# raw_getmakevar() doesn't work properly if $make hasn't yet been
432	# built, which can happen when running with the "-n" option.
433	# getmakevar() deals with this by emitting a literal '$'
434	# followed by the variable name, instead of trying to find the
435	# variable's value.
436	#
437	if [ -x "${make}" ]; then
438		raw_getmakevar "$1"
439	else
440		echo "\$$1"
441	fi
442}
443
444setmakeenv()
445{
446	eval "$1='$2'; export $1"
447	makeenv="${makeenv} $1"
448}
449
450unsetmakeenv()
451{
452	eval "unset $1"
453	makeenv="${makeenv} $1"
454}
455
456# Convert possibly-relative path to absolute path by prepending
457# ${TOP} if necessary.  Also delete trailing "/", if any.
458resolvepath()
459{
460	case "${OPTARG}" in
461	/)
462		;;
463	/*)
464		OPTARG="${OPTARG%/}"
465		;;
466	*)
467		OPTARG="${TOP}/${OPTARG%/}"
468		;;
469	esac
470}
471
472usage()
473{
474	if [ -n "$*" ]; then
475		echo ""
476		echo "${progname}: $*"
477	fi
478	cat <<_usage_
479
480Usage: ${progname} [-EnorUux] [-a arch] [-B buildid] [-D dest] [-j njob]
481		[-M obj] [-m mach] [-N noisy] [-O obj] [-R release] [-T tools]
482		[-V var=[value]] [-w wrapper] [-X x11src] [-Z var]
483		operation [...]
484
485 Build operations (all imply "obj" and "tools"):
486    build               Run "make build".
487    distribution        Run "make distribution" (includes DESTDIR/etc/ files).
488    release             Run "make release" (includes kernels & distrib media).
489
490 Other operations:
491    help                Show this message and exit.
492    makewrapper         Create ${toolprefix}make-\${MACHINE} wrapper and ${toolprefix}make.
493                        Always performed.
494    obj                 Run "make obj".  [Default unless -o is used]
495    tools               Build and install tools.
496    install=idir        Run "make installworld" to \`idir' to install all sets
497			except \`etc'.  Useful after "distribution" or "release"
498    kernel=conf         Build kernel with config file \`conf'
499    releasekernel=conf  Install kernel built by kernel=conf to RELEASEDIR.
500    sets                Create binary sets in RELEASEDIR/MACHINE/binary/sets.
501			DESTDIR should be populated beforehand.
502    sourcesets          Create source sets in RELEASEDIR/source/sets.
503    syspkgs             Create syspkgs in RELEASEDIR/MACHINE/binary/syspkgs.
504    iso-image           Create CD-ROM image in RELEASEDIR/MACHINE/installation.
505    params              Display various make(1) parameters.
506
507 Options:
508    -a arch     Set MACHINE_ARCH to arch.  [Default: deduced from MACHINE]
509    -B buildId  Set BUILDID to buildId.
510    -D dest     Set DESTDIR to dest.  [Default: destdir.MACHINE]
511    -E          Set "expert" mode; disables various safety checks.
512                Should not be used without expert knowledge of the build system.
513    -h          Print this help message.
514    -j njob     Run up to njob jobs in parallel; see make(1) -j.
515    -M obj      Set obj root directory to obj; sets MAKEOBJDIRPREFIX.
516                Unsets MAKEOBJDIR.
517    -m mach     Set MACHINE to mach; not required if NetBSD native.
518    -N noisy	Set the noisyness (MAKEVERBOSE) level of the build:
519		    0	Quiet
520		    1	Operations are described, commands are suppressed
521		    2	Full output
522		[Default: 2]
523    -n          Show commands that would be executed, but do not execute them.
524    -O obj      Set obj root directory to obj; sets a MAKEOBJDIR pattern.
525                Unsets MAKEOBJDIRPREFIX.
526    -o          Set MKOBJDIRS=no; do not create objdirs at start of build.
527    -R release  Set RELEASEDIR to release.  [Default: releasedir]
528    -r          Remove contents of TOOLDIR and DESTDIR before building.
529    -T tools    Set TOOLDIR to tools.  If unset, and TOOLDIR is not set in
530                the environment, ${toolprefix}make will be (re)built unconditionally.
531    -U          Set MKUNPRIVED=yes; build without requiring root privileges,
532    		install from an UNPRIVED build with proper file permissions.
533    -u          Set MKUPDATE=yes; do not run "make clean" first.
534		Without this, everything is rebuilt, including the tools.
535    -V v=[val]  Set variable \`v' to \`val'.
536    -w wrapper  Create ${toolprefix}make script as wrapper.
537                [Default: \${TOOLDIR}/bin/${toolprefix}make-\${MACHINE}]
538    -X x11src   Set X11SRCDIR to x11src.  [Default: /usr/xsrc]
539    -x          Set MKX11=yes; build X11R6 from X11SRCDIR
540    -Z v        Unset ("zap") variable \`v'.
541
542_usage_
543	exit 1
544}
545
546parseoptions()
547{
548	opts='a:B:bD:dEhi:j:k:M:m:N:nO:oR:rT:tUuV:w:xX:Z:'
549	opt_a=no
550
551	if type getopts >/dev/null 2>&1; then
552		# Use POSIX getopts.
553		#
554		getoptcmd='getopts ${opts} opt && opt=-${opt}'
555		optargcmd=':'
556		optremcmd='shift $((${OPTIND} -1))'
557	else
558		type getopt >/dev/null 2>&1 ||
559		    bomb "/bin/sh shell is too old; try ksh or bash"
560
561		# Use old-style getopt(1) (doesn't handle whitespace in args).
562		#
563		args="$(getopt ${opts} $*)"
564		[ $? = 0 ] || usage
565		set -- ${args}
566
567		getoptcmd='[ $# -gt 0 ] && opt="$1" && shift'
568		optargcmd='OPTARG="$1"; shift'
569		optremcmd=':'
570	fi
571
572	# Parse command line options.
573	#
574	while eval ${getoptcmd}; do
575		case ${opt} in
576
577		-a)
578			eval ${optargcmd}
579			MACHINE_ARCH=${OPTARG}
580			opt_a=yes
581			;;
582
583		-B)
584			eval ${optargcmd}
585			BUILDID=${OPTARG}
586			;;
587
588		-b)
589			usage "'-b' has been replaced by 'makewrapper'"
590			;;
591
592		-D)
593			eval ${optargcmd}; resolvepath
594			setmakeenv DESTDIR "${OPTARG}"
595			;;
596
597		-d)
598			usage "'-d' has been replaced by 'distribution'"
599			;;
600
601		-E)
602			do_expertmode=true
603			;;
604
605		-i)
606			usage "'-i idir' has been replaced by 'install=idir'"
607			;;
608
609		-j)
610			eval ${optargcmd}
611			parallel="-j ${OPTARG}"
612			;;
613
614		-k)
615			usage "'-k conf' has been replaced by 'kernel=conf'"
616			;;
617
618		-M)
619			eval ${optargcmd}; resolvepath
620			makeobjdir="${OPTARG}"
621			unsetmakeenv MAKEOBJDIR
622			setmakeenv MAKEOBJDIRPREFIX "${OPTARG}"
623			;;
624
625			# -m overrides MACHINE_ARCH unless "-a" is specified
626		-m)
627			eval ${optargcmd}
628			MACHINE="${OPTARG}"
629			[ "${opt_a}" != "yes" ] && getarch
630			;;
631
632		-N)
633			eval ${optargcmd}
634			case "${OPTARG}" in
635			0|1|2)
636				setmakeenv MAKEVERBOSE "${OPTARG}"
637				;;
638			*)
639				usage "'${OPTARG}' is not a valid value for -N"
640				;;
641			esac
642			;;
643
644		-n)
645			runcmd=echo
646			;;
647
648		-O)
649			eval ${optargcmd}; resolvepath
650			makeobjdir="${OPTARG}"
651			unsetmakeenv MAKEOBJDIRPREFIX
652			setmakeenv MAKEOBJDIR "\${.CURDIR:C,^$TOP,$OPTARG,}"
653			;;
654
655		-o)
656			MKOBJDIRS=no
657			;;
658
659		-R)
660			eval ${optargcmd}; resolvepath
661			setmakeenv RELEASEDIR "${OPTARG}"
662			;;
663
664		-r)
665			do_removedirs=true
666			do_rebuildmake=true
667			;;
668
669		-T)
670			eval ${optargcmd}; resolvepath
671			TOOLDIR="${OPTARG}"
672			export TOOLDIR
673			;;
674
675		-t)
676			usage "'-t' has been replaced by 'tools'"
677			;;
678
679		-U)
680			setmakeenv MKUNPRIVED yes
681			;;
682
683		-u)
684			setmakeenv MKUPDATE yes
685			;;
686
687		-V)
688			eval ${optargcmd}
689			case "${OPTARG}" in
690		    # XXX: consider restricting which variables can be changed?
691			[a-zA-Z_][a-zA-Z_0-9]*=*)
692				setmakeenv "${OPTARG%%=*}" "${OPTARG#*=}"
693				;;
694			*)
695				usage "-V argument must be of the form 'var=[value]'"
696				;;
697			esac
698			;;
699
700		-w)
701			eval ${optargcmd}; resolvepath
702			makewrapper="${OPTARG}"
703			;;
704
705		-X)
706			eval ${optargcmd}; resolvepath
707			setmakeenv X11SRCDIR "${OPTARG}"
708			;;
709
710		-x)
711			setmakeenv MKX11 yes
712			;;
713
714		-Z)
715			eval ${optargcmd}
716		    # XXX: consider restricting which variables can be unset?
717			unsetmakeenv "${OPTARG}"
718			;;
719
720		--)
721			break
722			;;
723
724		-'?'|-h)
725			usage
726			;;
727
728		esac
729	done
730
731	# Validate operations.
732	#
733	eval ${optremcmd}
734	while [ $# -gt 0 ]; do
735		op=$1; shift
736		operations="${operations} ${op}"
737
738		case "${op}" in
739
740		help)
741			usage
742			;;
743
744		makewrapper|obj|tools|build|distribution|release|sets|sourcesets|syspkgs|params)
745			;;
746
747		iso-image)
748			op=iso_image	# used as part of a variable name
749			;;
750
751		kernel=*|releasekernel=*)
752			arg=${op#*=}
753			op=${op%%=*}
754			[ -n "${arg}" ] ||
755			    bomb "Must supply a kernel name with \`${op}=...'"
756			;;
757
758		install=*)
759			arg=${op#*=}
760			op=${op%%=*}
761			[ -n "${arg}" ] ||
762			    bomb "Must supply a directory with \`install=...'"
763			;;
764
765		*)
766			usage "Unknown operation \`${op}'"
767			;;
768
769		esac
770		eval do_${op}=true
771	done
772	[ -n "${operations}" ] || usage "Missing operation to perform."
773
774	# Set up MACHINE*.  On a NetBSD host, these are allowed to be unset.
775	#
776	if [ -z "${MACHINE}" ]; then
777		[ "${uname_s}" = "NetBSD" ] ||
778		    bomb "MACHINE must be set, or -m must be used, for cross builds."
779		MACHINE=${uname_m}
780	fi
781	[ -n "${MACHINE_ARCH}" ] || getarch
782	validatearch
783
784	# Set up default make(1) environment.
785	#
786	makeenv="${makeenv} TOOLDIR MACHINE MACHINE_ARCH MAKEFLAGS"
787	[ -z "${BUILDID}" ] || makeenv="${makeenv} BUILDID"
788	MAKEFLAGS="-de -m ${TOP}/share/mk ${MAKEFLAGS} MKOBJDIRS=${MKOBJDIRS-yes}"
789	export MAKEFLAGS MACHINE MACHINE_ARCH
790}
791
792rebuildmake()
793{
794	# Test make source file timestamps against installed ${toolprefix}make
795	# binary, if TOOLDIR is pre-set.
796	#
797	# Note that we do NOT try to grovel "mk.conf" here to find out if
798	# TOOLDIR is set there, because it can contain make variable
799	# expansions and other stuff only parseable *after* we have a working
800	# ${toolprefix}make.  So this logic can only work if the user has
801	# pre-set TOOLDIR in the environment or used the -T option to build.sh.
802	#
803	make="${TOOLDIR-nonexistent}/bin/${toolprefix}make"
804	if [ -x "${make}" ]; then
805		for f in usr.bin/make/*.[ch] usr.bin/make/lst.lib/*.[ch]; do
806			if [ "${f}" -nt "${make}" ]; then
807				statusmsg "${make} outdated (older than ${f}), needs building."
808				do_rebuildmake=true
809				break
810			fi
811		done
812	else
813		statusmsg "No ${make}, needs building."
814		do_rebuildmake=true
815	fi
816
817	# Build bootstrap ${toolprefix}make if needed.
818	if ${do_rebuildmake}; then
819		statusmsg "Bootstrapping ${toolprefix}make"
820		${runcmd} cd "${tmpdir}"
821		${runcmd} env CC="${HOST_CC-cc}" CPPFLAGS="${HOST_CPPFLAGS}" \
822			CFLAGS="${HOST_CFLAGS--O}" LDFLAGS="${HOST_LDFLAGS}" \
823			${HOST_SH} "${TOP}/tools/make/configure" ||
824		    bomb "Configure of ${toolprefix}make failed"
825		${runcmd} ${HOST_SH} buildmake.sh ||
826		    bomb "Build of ${toolprefix}make failed"
827		make="${tmpdir}/${toolprefix}make"
828		${runcmd} cd "${TOP}"
829		${runcmd} rm -f usr.bin/make/*.o usr.bin/make/lst.lib/*.o
830	fi
831}
832
833validatemakeparams()
834{
835	if [ "${runcmd}" = "echo" ]; then
836		TOOLCHAIN_MISSING=no
837		EXTERNAL_TOOLCHAIN=""
838	else
839		TOOLCHAIN_MISSING=$(raw_getmakevar TOOLCHAIN_MISSING)
840		EXTERNAL_TOOLCHAIN=$(raw_getmakevar EXTERNAL_TOOLCHAIN)
841	fi
842	if [ "${TOOLCHAIN_MISSING}" = "yes" ] && \
843	   [ -z "${EXTERNAL_TOOLCHAIN}" ]; then
844		${runcmd} echo "ERROR: build.sh (in-tree cross-toolchain) is not yet available for"
845		${runcmd} echo "	MACHINE:      ${MACHINE}"
846		${runcmd} echo "	MACHINE_ARCH: ${MACHINE_ARCH}"
847		${runcmd} echo ""
848		${runcmd} echo "All builds for this platform should be done via a traditional make"
849		${runcmd} echo "If you wish to use an external cross-toolchain, set"
850		${runcmd} echo "	EXTERNAL_TOOLCHAIN=<path to toolchain root>"
851		${runcmd} echo "in either the environment or mk.conf and rerun"
852		${runcmd} echo "	${progname} $*"
853		exit 1
854	fi
855
856	# Normalise MKOBJDIRS, MKUNPRIVED, and MKUPDATE
857	# These may be set as build.sh options or in "mk.conf".
858	# Don't export them as they're only used for tests in build.sh.
859	#
860	MKOBJDIRS=$(getmakevar MKOBJDIRS)
861	MKUNPRIVED=$(getmakevar MKUNPRIVED)
862	MKUPDATE=$(getmakevar MKUPDATE)
863
864	if [ "${MKOBJDIRS}" != "no" ]; then
865		# If setting -M or -O to the root of an obj dir, make sure
866		# the base directory is made before continuing as <bsd.own.mk>
867		# will need this to pick up _SRC_TOP_OBJ_
868		#
869		if [ ! -z "${makeobjdir}" ]; then
870			${runcmd} mkdir -p "${makeobjdir}"
871		fi
872
873		# make obj in tools to ensure that the objdir for the top-level
874		# of the source tree and for "tools" is available, in case the
875		# default TOOLDIR setting from <bsd.own.mk> is used, or the
876		# build.sh default DESTDIR and RELEASEDIR is to be used.
877		#
878		${runcmd} cd tools
879		${runcmd} "${make}" -m ${TOP}/share/mk obj NOSUBDIR= ||
880		    bomb "Failed to make obj in tools"
881		${runcmd} cd "${TOP}"
882	fi
883
884	statusmsg "MACHINE:          ${MACHINE}"
885	statusmsg "MACHINE_ARCH:     ${MACHINE_ARCH}"
886
887	# Find TOOLDIR, DESTDIR, and RELEASEDIR.
888	#
889	TOOLDIR=$(getmakevar TOOLDIR)
890	statusmsg "TOOLDIR path:     ${TOOLDIR}"
891	DESTDIR=$(getmakevar DESTDIR)
892	RELEASEDIR=$(getmakevar RELEASEDIR)
893	if ! $do_expertmode; then
894		_SRC_TOP_OBJ_=$(getmakevar _SRC_TOP_OBJ_)
895		: ${DESTDIR:=${_SRC_TOP_OBJ_}/destdir.${MACHINE}}
896		: ${RELEASEDIR:=${_SRC_TOP_OBJ_}/releasedir}
897		makeenv="${makeenv} DESTDIR RELEASEDIR"
898	fi
899	export TOOLDIR DESTDIR RELEASEDIR
900	statusmsg "DESTDIR path:     ${DESTDIR}"
901	statusmsg "RELEASEDIR path:  ${RELEASEDIR}"
902
903	# Check validity of TOOLDIR and DESTDIR.
904	#
905	if [ -z "${TOOLDIR}" ] || [ "${TOOLDIR}" = "/" ]; then
906		bomb "TOOLDIR '${TOOLDIR}' invalid"
907	fi
908	removedirs="${TOOLDIR}"
909
910	if [ -z "${DESTDIR}" ] || [ "${DESTDIR}" = "/" ]; then
911		if ${do_build} || ${do_distribution} || ${do_release}; then
912			if ! ${do_build} || \
913			   [ "${uname_s}" != "NetBSD" ] || \
914			   [ "${uname_m}" != "${MACHINE}" ]; then
915				bomb "DESTDIR must != / for cross builds, or ${progname} 'distribution' or 'release'."
916			fi
917			if ! ${do_expertmode}; then
918				bomb "DESTDIR must != / for non -E (expert) builds"
919			fi
920			statusmsg "WARNING: Building to /, in expert mode."
921			statusmsg "         This may cause your system to break!  Reasons include:"
922			statusmsg "            - your kernel is not up to date"
923			statusmsg "            - the libraries or toolchain have changed"
924			statusmsg "         YOU HAVE BEEN WARNED!"
925		fi
926	else
927		removedirs="${removedirs} ${DESTDIR}"
928	fi
929	if ${do_build} || ${do_distribution} || ${do_release}; then
930		if ! ${do_expertmode} && \
931		    [ "$(id -u 2>/dev/null)" -ne 0 ] && \
932		    [ "${MKUNPRIVED}" = "no" ] ; then
933			bomb "-U or -E must be set for build as an unprivileged user."
934		fi
935        fi
936	if ${do_releasekernel} && [ -z "${RELEASEDIR}" ]; then
937		bomb "Must set RELEASEDIR with \`releasekernel=...'"
938	fi
939}
940
941
942createmakewrapper()
943{
944	# Remove the target directories.
945	#
946	if ${do_removedirs}; then
947		for f in ${removedirs}; do
948			statusmsg "Removing ${f}"
949			${runcmd} rm -r -f "${f}"
950		done
951	fi
952
953	# Recreate $TOOLDIR.
954	#
955	${runcmd} mkdir -p "${TOOLDIR}/bin" ||
956	    bomb "mkdir of '${TOOLDIR}/bin' failed"
957
958	# Install ${toolprefix}make if it was built.
959	#
960	if ${do_rebuildmake}; then
961		${runcmd} rm -f "${TOOLDIR}/bin/${toolprefix}make"
962		${runcmd} cp "${make}" "${TOOLDIR}/bin/${toolprefix}make" ||
963		    bomb "Failed to install \$TOOLDIR/bin/${toolprefix}make"
964		make="${TOOLDIR}/bin/${toolprefix}make"
965		statusmsg "Created ${make}"
966	fi
967
968	# Build a ${toolprefix}make wrapper script, usable by hand as
969	# well as by build.sh.
970	#
971	if [ -z "${makewrapper}" ]; then
972		makewrapper="${TOOLDIR}/bin/${toolprefix}make-${makewrappermachine:-${MACHINE}}"
973		[ -z "${BUILDID}" ] || makewrapper="${makewrapper}-${BUILDID}"
974	fi
975
976	${runcmd} rm -f "${makewrapper}"
977	if [ "${runcmd}" = "echo" ]; then
978		echo 'cat <<EOF >'${makewrapper}
979		makewrapout=
980	else
981		makewrapout=">>\${makewrapper}"
982	fi
983
984	case "${KSH_VERSION:-${SH_VERSION}}" in
985	*PD\ KSH*|*MIRBSD\ KSH*)
986		set +o braceexpand
987		;;
988	esac
989
990	eval cat <<EOF ${makewrapout}
991#! ${HOST_SH}
992# Set proper variables to allow easy "make" building of a NetBSD subtree.
993# Generated from:  \$NetBSD: build.sh,v 1.160 2007/01/29 00:08:13 matt Exp $
994# with these arguments: ${_args}
995#
996EOF
997	for f in ${makeenv}; do
998		if eval "[ -z \"\${$f}\" -a \"\${${f}-X}\" = \"X\" ]"; then
999			eval echo "unset ${f}" ${makewrapout}
1000		else
1001			eval echo "${f}=\'\$$(echo ${f})\'\;\ export\ ${f}" ${makewrapout}
1002		fi
1003	done
1004
1005	eval cat <<EOF ${makewrapout}
1006MAKEWRAPPERMACHINE=${makewrappermachine:-${MACHINE}}; export MAKEWRAPPERMACHINE
1007USETOOLS=yes; export USETOOLS
1008
1009exec "\${TOOLDIR}/bin/${toolprefix}make" \${1+"\$@"}
1010EOF
1011	[ "${runcmd}" = "echo" ] && echo EOF
1012	${runcmd} chmod +x "${makewrapper}"
1013	statusmsg "makewrapper:      ${makewrapper}"
1014	statusmsg "Updated ${makewrapper}"
1015}
1016
1017buildtools()
1018{
1019	if [ "${MKOBJDIRS}" != "no" ]; then
1020		${runcmd} "${makewrapper}" ${parallel} obj-tools ||
1021		    bomb "Failed to make obj-tools"
1022	fi
1023	${runcmd} cd tools
1024	if [ "${MKUPDATE}" = "no" ]; then
1025		${runcmd} "${makewrapper}" ${parallel} cleandir ||
1026		    bomb "Failed to make cleandir tools"
1027	fi
1028	${runcmd} "${makewrapper}" ${parallel} dependall ||
1029	    bomb "Failed to make dependall tools"
1030	${runcmd} "${makewrapper}" ${parallel} install ||
1031	    bomb "Failed to make install tools"
1032	statusmsg "Tools built to ${TOOLDIR}"
1033	${runcmd} cd "${TOP}"
1034}
1035
1036getkernelconf()
1037{
1038	kernelconf="$1"
1039	if [ "${MKOBJDIRS}" != "no" ]; then
1040		# The correct value of KERNOBJDIR might
1041		# depend on a prior "make obj" in
1042		# ${KERNSRCDIR}/${KERNARCHDIR}/compile.
1043		#
1044		KERNSRCDIR="$(getmakevar KERNSRCDIR)"
1045		KERNARCHDIR="$(getmakevar KERNARCHDIR)"
1046		${runcmd} cd "${KERNSRCDIR}/${KERNARCHDIR}/compile"
1047		${runcmd} "${makewrapper}" ${parallel} obj ||
1048		    bomb "Failed to make obj in ${KERNSRCDIR}/${KERNARCHDIR}/compile"
1049		${runcmd} cd "${TOP}"
1050	fi
1051	KERNCONFDIR="$(getmakevar KERNCONFDIR)"
1052	KERNOBJDIR="$(getmakevar KERNOBJDIR)"
1053	case "${kernelconf}" in
1054	*/*)
1055		kernelconfpath="${kernelconf}"
1056		kernelconfname="${kernelconf##*/}"
1057		;;
1058	*)
1059		kernelconfpath="${KERNCONFDIR}/${kernelconf}"
1060		kernelconfname="${kernelconf}"
1061		;;
1062	esac
1063	kernelbuildpath="${KERNOBJDIR}/${kernelconfname}"
1064}
1065
1066buildkernel()
1067{
1068	if ! ${do_tools} && ! ${buildkernelwarned:-false}; then
1069		# Building tools every time we build a kernel is clearly
1070		# unnecessary.  We could try to figure out whether rebuilding
1071		# the tools is necessary this time, but it doesn't seem worth
1072		# the trouble.  Instead, we say it's the user's responsibility
1073		# to rebuild the tools if necessary.
1074		#
1075		statusmsg "Building kernel without building new tools"
1076		buildkernelwarned=true
1077	fi
1078	getkernelconf $1
1079	statusmsg "Building kernel:  ${kernelconf}"
1080	statusmsg "Build directory:  ${kernelbuildpath}"
1081	${runcmd} mkdir -p "${kernelbuildpath}" ||
1082	    bomb "Cannot mkdir: ${kernelbuildpath}"
1083	if [ "${MKUPDATE}" = "no" ]; then
1084		${runcmd} cd "${kernelbuildpath}"
1085		${runcmd} "${makewrapper}" ${parallel} cleandir ||
1086		    bomb "Failed to make cleandir in ${kernelbuildpath}"
1087		${runcmd} cd "${TOP}"
1088	fi
1089	[ -x "${TOOLDIR}/bin/${toolprefix}config" ] \
1090	|| bomb "${TOOLDIR}/bin/${toolprefix}config does not exist. You need to \"$0 tools\" first."
1091	${runcmd} "${TOOLDIR}/bin/${toolprefix}config" -b "${kernelbuildpath}" \
1092		-s "${TOP}/sys" "${kernelconfpath}" ||
1093	    bomb "${toolprefix}config failed for ${kernelconf}"
1094	${runcmd} cd "${kernelbuildpath}"
1095	${runcmd} "${makewrapper}" ${parallel} depend ||
1096	    bomb "Failed to make depend in ${kernelbuildpath}"
1097	${runcmd} "${makewrapper}" ${parallel} all ||
1098	    bomb "Failed to make all in ${kernelbuildpath}"
1099	${runcmd} cd "${TOP}"
1100
1101	if [ "${runcmd}" != "echo" ]; then
1102		statusmsg "Kernels built from ${kernelconf}:"
1103		kernlist=$(awk '$1 == "config" { print $2 }' ${kernelconfpath})
1104		for kern in ${kernlist:-netbsd}; do
1105			[ -f "${kernelbuildpath}/${kern}" ] && \
1106			    echo "  ${kernelbuildpath}/${kern}"
1107		done | tee -a "${results}"
1108	fi
1109}
1110
1111releasekernel()
1112{
1113	getkernelconf $1
1114	kernelreldir="${RELEASEDIR}/${MACHINE}/binary/kernel"
1115	${runcmd} mkdir -p "${kernelreldir}"
1116	kernlist=$(awk '$1 == "config" { print $2 }' ${kernelconfpath})
1117	for kern in ${kernlist:-netbsd}; do
1118		builtkern="${kernelbuildpath}/${kern}"
1119		[ -f "${builtkern}" ] || continue
1120		releasekern="${kernelreldir}/${kern}-${kernelconfname}.gz"
1121		statusmsg "Kernel copy:      ${releasekern}"
1122		${runcmd} gzip -c -9 < "${builtkern}" > "${releasekern}"
1123	done
1124}
1125
1126installworld()
1127{
1128	dir="$1"
1129	${runcmd} "${makewrapper}" INSTALLWORLDDIR="${dir}" installworld ||
1130	    bomb "Failed to make installworld to ${dir}"
1131	statusmsg "Successful installworld to ${dir}"
1132}
1133
1134
1135main()
1136{
1137	initdefaults
1138	_args=$@
1139	parseoptions "$@"
1140
1141	build_start=$(date)
1142	statusmsg "${progname} command: $0 $@"
1143	statusmsg "${progname} started: ${build_start}"
1144
1145	statusmsg "HOST_SH:          ${HOST_SH}"
1146
1147	rebuildmake
1148	validatemakeparams
1149	createmakewrapper
1150
1151	# Perform the operations.
1152	#
1153	for op in ${operations}; do
1154		case "${op}" in
1155
1156		makewrapper)
1157			# no-op
1158			;;
1159
1160		tools)
1161			buildtools
1162			;;
1163
1164		sets)
1165			statusmsg "Building sets from pre-populated ${DESTDIR}"
1166			${runcmd} "${makewrapper}" ${parallel} ${op} ||
1167			    bomb "Failed to make ${op}"
1168			statusmsg "Successful make ${op}"
1169			;;
1170
1171		obj|build|distribution|iso-image|release|sourcesets|syspkgs|params)
1172			${runcmd} "${makewrapper}" ${parallel} ${op} ||
1173			    bomb "Failed to make ${op}"
1174			statusmsg "Successful make ${op}"
1175			;;
1176
1177		kernel=*)
1178			arg=${op#*=}
1179			buildkernel "${arg}"
1180			;;
1181
1182		releasekernel=*)
1183			arg=${op#*=}
1184			releasekernel "${arg}"
1185			;;
1186
1187		install=*)
1188			arg=${op#*=}
1189			if [ "${arg}" = "/" ] && \
1190			    (	[ "${uname_s}" != "NetBSD" ] || \
1191				[ "${uname_m}" != "${MACHINE}" ] ); then
1192				bomb "'${op}' must != / for cross builds."
1193			fi
1194			installworld "${arg}"
1195			;;
1196
1197		*)
1198			bomb "Unknown operation \`${op}'"
1199			;;
1200
1201		esac
1202	done
1203
1204	statusmsg "${progname} started: ${build_start}"
1205	statusmsg "${progname} ended:   $(date)"
1206	if [ -s "${results}" ]; then
1207		echo "===> Summary of results:"
1208		sed -e 's/^===>//;s/^/	/' "${results}"
1209		echo "===> ."
1210	fi
1211}
1212
1213main "$@"
1214