build.sh revision 1.80
1#! /usr/bin/env sh
2#  $NetBSD: build.sh,v 1.80 2003/01/04 12:55:32 lukem Exp $
3#
4# Top level build wrapper, for a system containing no tools.
5#
6# This script should run on any POSIX-compliant shell.  For systems
7# with a strange /bin/sh, "ksh" or "bash" may be an ample alternative.
8#
9# Note, however, that due to the way the interpreter is invoked above,
10# if a POSIX-compliant shell is the first in the PATH, you won't have
11# to take any further action.
12#
13
14bomb()
15{
16	echo ""
17	echo "ERROR: $@"
18	echo "*** BUILD ABORTED ***"
19	exit 1
20}
21
22cd "$(dirname $0)"
23[ -d usr.bin/make ] ||
24    bomb "build.sh must be run from the top source level"
25[ -f share/mk/bsd.own.mk ] ||
26    bomb "src/share/mk is missing; please re-fetch the source tree"
27
28uname_s=$(uname -s 2>/dev/null)
29uname_m=$(uname -m 2>/dev/null)
30
31# If $PWD is a valid name of the current directory, POSIX mandates that pwd
32# return it by default which causes problems in the presence of symlinks.
33# Unsetting PWD is simpler than changing every occurrence of pwd to use -P.
34#
35# XXX Except that doesn't work on Solaris.
36unset PWD
37if [ "${uname_s}" = "SunOS" ]; then
38	TOP=$(pwd -P)
39else
40	TOP=$(pwd)
41fi
42
43getarch()
44{
45	# Translate a MACHINE into a default MACHINE_ARCH.
46	case $MACHINE in
47		acorn26|acorn32|cats|netwinder|shark|*arm)
48			MACHINE_ARCH=arm;;
49
50		sun2)
51			MACHINE_ARCH=m68000;;
52
53		amiga|atari|cesfic|hp300|sun3|*68k)
54			MACHINE_ARCH=m68k;;
55
56		mipsco|newsmips|sbmips|sgimips)
57			MACHINE_ARCH=mipseb;;
58
59		algor|arc|cobalt|evbmips|hpcmips|playstation2|pmax)
60			MACHINE_ARCH=mipsel;;
61
62		pc532)
63			MACHINE_ARCH=ns32k;;
64
65		bebox|prep|sandpoint|*ppc)
66			MACHINE_ARCH=powerpc;;
67
68		evbsh3|mmeye)
69			MACHINE_ARCH=sh3eb;;
70
71		dreamcast|hpcsh)
72			MACHINE_ARCH=sh3el;;
73
74		hp700)
75			MACHINE_ARCH=hppa;;
76
77		evbsh5)
78			MACHINE_ARCH=sh5el;;
79
80		alpha|i386|sparc|sparc64|vax|x86_64)
81			MACHINE_ARCH=$MACHINE;;
82
83		*)	bomb "unknown target MACHINE: $MACHINE";;
84	esac
85}
86
87validatearch()
88{
89	# Ensure that the MACHINE_ARCH exists (and is supported by build.sh).
90	case $MACHINE_ARCH in
91		alpha|arm|armeb|hppa|i386|m68000|m68k|mipse[bl]|ns32k|powerpc|sh[35]e[bl]|sparc|sparc64|vax|x86_64)
92			;;
93
94		*)	bomb "unknown target MACHINE_ARCH: $MACHINE_ARCH";;
95	esac
96}
97
98getmakevar()
99{
100	$make -m ${TOP}/share/mk -s -f- _x_ <<EOF
101_x_:
102	echo \${$1}
103.include <bsd.prog.mk>
104.include <bsd.kernobj.mk>
105EOF
106}
107
108resolvepath()
109{
110	case $OPTARG in
111	/*)	;;
112	*)	OPTARG="$TOP/$OPTARG";;
113	esac
114}
115
116usage()
117{
118	cat <<_usage_
119Usage:
120$(basename $0) [-bdEnortUu] [-a arch] [-B buildid] [-D dest] [-i instdir]
121    [-j njob] [-k kernel] [-M obj] [-m mach] [-O obj] [-R release] [-T tools]
122    [-V var=[value]] [-w wrapper]
123
124    -a arch	set MACHINE_ARCH to arch (otherwise deduced from MACHINE)
125    -B buildid	set BUILDID to buildid
126    -b		build nbmake and nbmake wrapper script, if needed
127    -D dest	set DESTDIR to dest
128    -d		build a full distribution into DESTDIR (including etc files)
129    -E		set "expert" mode; disables some DESTDIR checks
130    -i instdir	installworld from DESTDIR to instdir
131    -j njob	run up to njob jobs in parallel; see make(1)
132    -k kernel	build a kernel using the named configuration file
133    -M obj	set obj root directory to obj (sets MAKEOBJDIRPREFIX)
134    -m mach	set MACHINE to mach (not required if NetBSD native)
135    -n		show commands that would be executed, but do not execute them
136    -O obj	set obj root directory to obj (sets a MAKEOBJDIR pattern)
137    -o		set MKOBJDIRS=no (do not create objdirs at start of build)
138    -R release	build a release (and set RELEASEDIR to release)
139    -r		remove contents of TOOLDIR and DESTDIR before building
140    -T tools	set TOOLDIR to tools
141    -t		build and install tools only (implies -b)
142    -U		set UNPRIVED
143    -u		set UPDATE
144    -V v=[val]	set variable \`v' to \`val'
145    -w wrapper	create nbmake script at wrapper
146		(default TOOLDIR/bin/nbmake-MACHINE)
147
148Note: if -T is unset and TOOLDIR is not set in the environment,
149      nbmake will be [re]built unconditionally.
150_usage_
151	exit 1
152}
153
154# Set defaults.
155MAKEFLAGS=
156buildtarget=build
157do_buildsystem=true
158do_buildkernel=false
159do_buildtools=false
160do_rebuildmake=false
161do_removedirs=false
162expert_mode=false
163makeenv=
164makewrapper=
165installworlddir=
166opt_a=no
167opts='a:B:bD:dEhi:j:k:M:m:nO:oR:rT:tUuV:w:'
168runcmd=
169
170if type getopts >/dev/null 2>&1; then
171	# Use POSIX getopts.
172	getoptcmd='getopts $opts opt && opt=-$opt'
173	optargcmd=':'
174else
175	type getopt >/dev/null 2>&1 ||
176	    bomb "/bin/sh shell is too old; try ksh or bash"
177
178	# Use old-style getopt(1) (doesn't handle whitespace in args).
179	args="$(getopt $opts $*)"
180	[ $? = 0 ] || usage
181	set -- $args
182
183	getoptcmd='[ $# -gt 0 ] && opt="$1" && shift'
184	optargcmd='OPTARG="$1"; shift'
185fi
186
187# Parse command line options.
188while eval $getoptcmd; do
189    case $opt in
190	-a)	eval $optargcmd
191		MACHINE_ARCH=$OPTARG; opt_a=yes;;
192
193	-B)	eval $optargcmd
194		BUILDID=$OPTARG;;
195
196	-b)	do_buildsystem=false;;
197
198	-D)	eval $optargcmd; resolvepath
199		DESTDIR="$OPTARG"; export DESTDIR
200		makeenv="$makeenv DESTDIR";;
201
202	-d)	buildtarget=distribution;;
203
204	-E)	expert_mode=true;;
205
206	-i)	eval $optargcmd
207		installworlddir=$OPTARG;;
208
209	-j)	eval $optargcmd
210		parallel="-j $OPTARG";;
211
212	-k)	do_buildkernel=true; do_buildsystem=false
213		eval $optargcmd
214		kernconfname=$OPTARG;;
215
216	-M)	eval $optargcmd; resolvepath
217		MAKEOBJDIRPREFIX="$OPTARG"; export MAKEOBJDIRPREFIX
218		makeobjdir=$OPTARG
219		makeenv="$makeenv MAKEOBJDIRPREFIX";;
220
221	# -m overrides MACHINE_ARCH unless "-a" is specified
222	-m)	eval $optargcmd
223		MACHINE=$OPTARG; [ "$opt_a" != "yes" ] && getarch;;
224
225	-n)	runcmd=echo;;
226
227	-O)	eval $optargcmd; resolvepath
228		MAKEOBJDIR="\${.CURDIR:C,^$TOP,$OPTARG,}"; export MAKEOBJDIR
229		makeobjdir=$OPTARG
230		makeenv="$makeenv MAKEOBJDIR";;
231
232	-o)	MKOBJDIRS=no;;
233
234	-R)	eval $optargcmd; resolvepath
235		RELEASEDIR=$OPTARG; export RELEASEDIR
236		makeenv="$makeenv RELEASEDIR"
237		buildtarget=release;;
238
239	-r)	do_removedirs=true; do_rebuildmake=true;;
240
241	-T)	eval $optargcmd; resolvepath
242		TOOLDIR="$OPTARG"; export TOOLDIR;;
243
244	-t)	do_buildtools=true; do_buildsystem=false;;
245
246	-U)	UNPRIVED=yes; export UNPRIVED
247		makeenv="$makeenv UNPRIVED";;
248
249	-u)	UPDATE=yes; export UPDATE
250		makeenv="$makeenv UPDATE";;
251
252	-V)	eval $optargcmd
253		case "${OPTARG}" in
254		    # XXX: consider restricting which variables can be changed?
255		[a-zA-Z_][a-zA-Z_0-9]*=*)
256			var=${OPTARG%%=*}
257			value=${OPTARG#*=}
258			eval "${var}=\"${value}\"; export ${var}"
259			makeenv="$makeenv ${var}"
260			;;
261		*)
262			echo "-V argument must be of the form 'var=[value]'"
263			usage;;
264		esac
265		;;
266
267	-w)	eval $optargcmd; resolvepath
268		makewrapper="$OPTARG";;
269
270	--)		break;;
271	-'?'|-h)	usage;;
272    esac
273done
274
275# Set up MACHINE*.  On a NetBSD host, these are allowed to be unset.
276if [ -z "$MACHINE" ]; then
277	if [ "${uname_s}" != "NetBSD" ]; then
278		echo "MACHINE must be set, or -m must be used, for cross builds."
279		echo ""; usage
280	fi
281	MACHINE=${uname_m}
282fi
283[ -n "$MACHINE_ARCH" ] || getarch
284validatearch
285
286# Set up default make(1) environment.
287makeenv="$makeenv TOOLDIR MACHINE MACHINE_ARCH MAKEFLAGS"
288if [ ! -z "$BUILDID" ]; then
289	makeenv="$makeenv BUILDID"
290fi
291MAKEFLAGS="-m $TOP/share/mk $MAKEFLAGS MKOBJDIRS=${MKOBJDIRS-yes}"
292export MAKEFLAGS MACHINE MACHINE_ARCH
293
294# Test make source file timestamps against installed nbmake binary,
295# if TOOLDIR is pre-set.
296#
297# Note that we do NOT try to grovel "mk.conf" here to find out if TOOLDIR
298# is set there, because it can contain make variable expansions and other
299# stuff only parseable *after* we have a working nbmake.  So this logic
300# can only work if the user has pre-set TOOLDIR in the environment or
301# used the -T option to build.sh.
302#
303make="${TOOLDIR-nonexistent}/bin/nbmake"
304if [ -x $make ]; then
305	for f in usr.bin/make/*.[ch] usr.bin/make/lst.lib/*.[ch]; do
306		if [ $f -nt $make ]; then
307			do_rebuildmake=true; break
308		fi
309	done
310else
311	do_rebuildmake=true
312fi
313
314# Build bootstrap nbmake if needed.
315if $do_rebuildmake; then
316	$runcmd echo "===> Bootstrapping nbmake"
317	tmpdir="${TMPDIR-/tmp}/nbbuild$$"
318
319	$runcmd mkdir "$tmpdir" || bomb "cannot mkdir: $tmpdir"
320	trap "cd /; rm -r -f \"$tmpdir\"" 0
321	trap "exit 1" 1 2 3 15
322	$runcmd cd "$tmpdir"
323
324	$runcmd env CC="${HOST_CC-cc}" CPPFLAGS="${HOST_CPPFLAGS}" \
325		CFLAGS="${HOST_CFLAGS--O}" LDFLAGS="${HOST_LDFLAGS}" \
326		"$TOP/tools/make/configure" \
327		|| bomb "configure of nbmake failed"
328	$runcmd sh buildmake.sh || bomb "build of nbmake failed"
329
330	make="$tmpdir/nbmake"
331	$runcmd cd "$TOP"
332	$runcmd rm -f usr.bin/make/*.o usr.bin/make/lst.lib/*.o
333fi
334
335EXTERNAL_TOOLCHAIN=$(getmakevar EXTERNAL_TOOLCHAIN)
336if [ "$runcmd" = "echo" ]; then
337	TOOLCHAIN_MISSING=no
338else
339	TOOLCHAIN_MISSING=$(getmakevar TOOLCHAIN_MISSING)
340fi
341if [ "${TOOLCHAIN_MISSING}" = "yes" -a \
342     "${EXTERNAL_TOOLCHAIN}" = "" ]; then
343	echo "ERROR: build.sh (in-tree cross-toolchain) is not yet available for"
344	echo
345	echo "MACHINE: ${MACHINE}"
346	echo "MACHINE_ARCH: ${MACHINE_ARCH}"
347	echo
348	echo "All builds for this platform should be done via a traditional make"
349	echo
350	echo "If you wish to use an external cross-toolchain, set"
351	echo
352	echo "EXTERNAL_TOOLCHAIN=<path to toolchain root>"
353	echo
354	echo "in either the environment or mk.conf and rerun"
355	echo
356	echo "$0 $*"
357	exit 1
358fi
359
360# If TOOLDIR isn't already set, make objdirs in "tools" in case the
361# default setting from <bsd.own.mk> is used.
362if [ -z "$TOOLDIR" ] && [ "$MKOBJDIRS" != "no" ]; then
363	$runcmd cd tools
364	$runcmd $make -m ${TOP}/share/mk obj NOSUBDIR= \
365		|| bomb "make obj failed in tools"
366	$runcmd cd "$TOP"
367fi
368
369#
370# If setting -M or -O to root an obj dir make sure the base directory is made
371# before continuing as bsd.own.mk will need this to pick up _SRC_TOP_OBJ_
372#
373if [ "$MKOBJDIRS" != "no" ] && [ ! -z "$makeobjdir" ]; then
374	$runcmd mkdir -p "$makeobjdir"
375fi
376
377# Find DESTDIR and TOOLDIR.
378if [ "$runcmd" = "echo" ]; then
379	# shown symbolically with -n because these may come from mk.conf
380	DESTDIR='$DESTDIR'
381	TOOLDIR='$TOOLDIR'
382else
383	DESTDIR=$(getmakevar DESTDIR)
384	[ $? = 0 ] || bomb "getmakevar DESTDIR failed"
385	$runcmd echo "===> DESTDIR path: $DESTDIR"
386
387	TOOLDIR=$(getmakevar TOOLDIR)
388	[ $? = 0 ] || bomb "getmakevar TOOLDIR failed"
389	$runcmd echo "===> TOOLDIR path: $TOOLDIR"
390
391	export DESTDIR TOOLDIR
392fi
393
394# Check validity of TOOLDIR and DESTDIR.
395if [ -z "$TOOLDIR" ] || [ "$TOOLDIR" = "/" ]; then
396	bomb "TOOLDIR '$TOOLDIR' invalid"
397fi
398removedirs="$TOOLDIR"
399
400if [ -z "$DESTDIR" ] || [ "$DESTDIR" = "/" ]; then
401	if $do_buildsystem; then
402		if [ "$buildtarget" != "build" ] || \
403		   [ "${uname_s}" != "NetBSD" ] || \
404		   [ "${uname_m}" != "$MACHINE" ]; then
405			bomb "DESTDIR must be set to a non-root path for cross builds or -d or -R."
406		fi
407		if ! $expert_mode; then
408			bomb "DESTDIR must be set to a non-root path for non -E (expert) builds"
409		fi
410		$runcmd echo "===> WARNING: Building to /, in expert mode."
411		$runcmd echo "===>          This may cause your system to break!  Reasons include:"
412		$runcmd echo "===>             - your kernel is not up to date"
413		$runcmd echo "===>             - the libraries or toolchain have changed"
414		$runcmd echo "===>          YOU HAVE BEEN WARNED!"
415	fi
416else
417	removedirs="$removedirs $DESTDIR"
418fi
419
420if [ "$installworlddir" = "/" ]; then
421	if [ "${uname_s}" != "NetBSD" ] || \
422	   [ "${uname_m}" != "$MACHINE" ]; then
423		bomb "-i installworlddir must be set to a non-root path for cross builds."
424	fi
425fi
426
427# Remove the target directories.
428if $do_removedirs; then
429	for f in $removedirs; do
430		$runcmd echo "===> Removing $f"
431		$runcmd rm -r -f $f
432	done
433fi
434
435# Recreate $TOOLDIR.
436$runcmd mkdir -p "$TOOLDIR/bin" || bomb "mkdir of '$TOOLDIR/bin' failed"
437
438# Install nbmake if it was built.
439if $do_rebuildmake; then
440	$runcmd rm -f "$TOOLDIR/bin/nbmake"
441	$runcmd cp $make "$TOOLDIR/bin/nbmake" \
442		|| bomb "failed to install \$TOOLDIR/bin/nbmake"
443	make="$TOOLDIR/bin/nbmake"
444	$runcmd rm -r -f "$tmpdir"
445	trap 0 1 2 3 15
446fi
447
448# Build a nbmake wrapper script, usable by hand as well as by build.sh.
449if [ -z "$makewrapper" ]; then
450	makewrapper="$TOOLDIR/bin/nbmake-$MACHINE"
451	if [ ! -z "$BUILDID" ]; then
452		makewrapper="$makewrapper-$BUILDID"
453	fi
454fi
455
456$runcmd rm -f "$makewrapper"
457if [ "$runcmd" = "echo" ]; then
458	echo 'cat <<EOF >'$makewrapper
459	makewrapout=
460else
461	makewrapout=">>\$makewrapper"
462fi
463
464eval cat <<EOF $makewrapout
465#! /bin/sh
466# Set proper variables to allow easy "make" building of a NetBSD subtree.
467# Generated from:  \$NetBSD: build.sh,v 1.80 2003/01/04 12:55:32 lukem Exp $
468#
469
470EOF
471for f in $makeenv; do
472	eval echo "$f=\'\$$(echo $f)\'\;\ export\ $f" $makewrapout
473done
474eval echo "USETOOLS=yes\; export USETOOLS" $makewrapout
475
476eval cat <<'EOF' $makewrapout
477
478exec "$TOOLDIR/bin/nbmake" ${1+"$@"}
479EOF
480[ "$runcmd" = "echo" ] && echo EOF
481$runcmd chmod +x "$makewrapper"
482
483if $do_buildsystem; then
484	# Build everything.
485	${runcmd-exec} "$makewrapper" $parallel $buildtarget \
486		|| bomb "failed to make $buildtarget"
487else
488	# One or more of do_buildtools and do_buildkernel
489	# might be set.  Do them in the appropriate order.
490	if $do_buildtools; then
491		if [ "$MKOBJDIRS" != "no" ]; then
492			$runcmd "$makewrapper" $parallel obj-tools \
493				|| bomb "failed to make obj-tools"
494		fi
495		$runcmd cd tools
496		if [ "$UPDATE" = "" ]; then
497			$runcmd "$makewrapper" cleandir dependall install \
498				|| bomb "failed to make tools"
499		else
500			$runcmd "$makewrapper" dependall install \
501				|| bomb "failed to make tools"
502		fi
503	fi
504	if $do_buildkernel; then
505		if ! $do_buildtools; then
506			# Building tools every time we build a kernel
507			# is clearly unnecessary.  We could try to
508			# figure out whether rebuilding the tools is
509			# necessary this time, but it doesn't seem
510			# worth the trouble.  Instead, we say it's the
511			# user's responsibility to rebuild the tools if
512			# necessary.
513			$runcmd echo "===> Building kernel" \
514				"without building new tools"
515		fi
516		$runcmd echo "===> Building kernel ${kernconfname}"
517		# The correct value of KERNOBJDIR might depend on a
518		# prior "make obj" in TOP/etc.
519		if [ "$MKOBJDIRS" != "no" ] && [ ! -z "$makeobjdir" ]; then
520			$runcmd cd "$TOP/etc"
521			$runcmd "$makewrapper" obj \
522				|| bomb "failed to make obj in etc"
523			$runcmd cd "$TOP"
524		fi
525		if [ "$runcmd" = "echo" ]; then
526			# shown symbolically with -n
527			# because getmakevar might not work yet
528			KERNCONFDIR='$KERNCONFDIR'
529			KERNOBJDIR='$KERNOBJDIR'
530		else
531			KERNCONFDIR="$( getmakevar KERNCONFDIR )"
532			[ $? = 0 ] || bomb "getmakevar KERNCONFDIR failed"
533			KERNOBJDIR="$( getmakevar KERNOBJDIR )"
534			[ $? = 0 ] || bomb "getmakevar KERNOBJDIR failed"
535		fi
536		case "${kernconfname}" in
537		*/*)
538			kernconfpath="${kernconfname}"
539			kernconfbase="$( basename "${kernconfname}" )"
540			;;
541		*)
542			kernconfpath="${KERNCONFDIR}/${kernconfname}"
543			kernconfbase="${kernconfname}"
544			;;
545		esac
546		kernbuilddir="${KERNOBJDIR}/${kernconfbase}"
547		$runcmd echo "===> Kernel build directory: ${kernbuilddir}"
548		$runcmd mkdir -p "${kernbuilddir}" \
549			|| bomb "cannot mkdir: ${kernbuilddir}"
550		if [ "$UPDATE" = "" ]; then
551			$runcmd cd "${kernbuilddir}"
552			$runcmd "$makewrapper" cleandir \
553				|| bomb "make cleandir failed in " \
554					"${kernbuilddir}"
555			$runcmd cd "$TOP"
556		fi
557		$runcmd "${TOOLDIR}/bin/nbconfig" \
558			-b "${kernbuilddir}" \
559			-s "${TOP}/sys" "${kernconfpath}" \
560			|| bomb "nbconfig failed for ${kernconfname}"
561		$runcmd cd "${kernbuilddir}"
562		$runcmd "$makewrapper" depend \
563			|| bomb "make depend failed in ${kernbuilddir}"
564		$runcmd "$makewrapper" $parallel all \
565			|| bomb "make all failed in ${kernbuilddir}"
566		$runcmd echo "===> New kernel should be in ${kernbuilddir}"
567	fi
568fi
569
570if [ -n "$installworlddir" ]; then
571	${runcmd-exec} "$makewrapper" INSTALLWORLDDIR=${installworlddir} \
572		installworld || bomb "failed to make installworld"
573fi
574