build.sh revision 1.81
1#! /usr/bin/env sh
2#  $NetBSD: build.sh,v 1.81 2003/01/04 14:55:44 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: $(basename $0) [-bdEnortUu] [-a arch] [-B buildid] [-D dest]
120		[-i instdir] [-j njob] [-k kernel] [-M obj] [-m mach]
121		[-O obj] [-R release] [-T tools] [-V var=[value]] [-w wrapper]
122
123    -a arch	set MACHINE_ARCH to arch (otherwise deduced from MACHINE)
124    -B buildid	set BUILDID to buildid
125    -b		build nbmake and nbmake wrapper script, if needed
126    -D dest	set DESTDIR to dest
127    -d		build a full distribution into DESTDIR (including etc files)
128    -E		set "expert" mode; disables some DESTDIR checks
129    -i instdir	installworld from DESTDIR to instdir (after build completes)
130    -j njob	run up to njob jobs in parallel; see make(1)
131    -k kernel	build a kernel using the named configuration file
132    -M obj	set obj root directory to obj (sets MAKEOBJDIRPREFIX)
133    -m mach	set MACHINE to mach (not required if NetBSD native)
134    -n		show commands that would be executed, but do not execute them
135    -O obj	set obj root directory to obj (sets a MAKEOBJDIR pattern)
136    -o		set MKOBJDIRS=no (do not create objdirs at start of build)
137    -R release	build a release (and set RELEASEDIR to release)
138    -r		remove contents of TOOLDIR and DESTDIR before building
139    -T tools	set TOOLDIR to tools
140    -t		build and install tools only (implies -b)
141    -U		set UNPRIVED
142    -u		set UPDATE
143    -V v=[val]	set variable \`v' to \`val'
144    -w wrapper	create nbmake script at wrapper
145		(default TOOLDIR/bin/nbmake-MACHINE)
146
147Notes:
148    *	The last specified option with "build" functionality will be run.
149    *	If -T is unset and TOOLDIR is not set in the environment,
150	nbmake will be [re]built unconditionally.
151_usage_
152	exit 1
153}
154
155# Set defaults.
156MAKEFLAGS=
157buildtarget=build
158do_buildsystem=true
159do_buildkernel=false
160do_buildtools=false
161do_rebuildmake=false
162do_removedirs=false
163expert_mode=false
164makeenv=
165makewrapper=
166installworlddir=
167opt_a=no
168opts='a:B:bD:dEhi:j:k:M:m:nO:oR:rT:tUuV:w:'
169runcmd=
170
171if type getopts >/dev/null 2>&1; then
172	# Use POSIX getopts.
173	getoptcmd='getopts $opts opt && opt=-$opt'
174	optargcmd=':'
175else
176	type getopt >/dev/null 2>&1 ||
177	    bomb "/bin/sh shell is too old; try ksh or bash"
178
179	# Use old-style getopt(1) (doesn't handle whitespace in args).
180	args="$(getopt $opts $*)"
181	[ $? = 0 ] || usage
182	set -- $args
183
184	getoptcmd='[ $# -gt 0 ] && opt="$1" && shift'
185	optargcmd='OPTARG="$1"; shift'
186fi
187
188# Parse command line options.
189while eval $getoptcmd; do
190    case $opt in
191	-a)	eval $optargcmd
192		MACHINE_ARCH=$OPTARG; opt_a=yes;;
193
194	-B)	eval $optargcmd
195		BUILDID=$OPTARG;;
196
197	-b)	do_buildsystem=false;;
198
199	-D)	eval $optargcmd; resolvepath
200		DESTDIR="$OPTARG"; export DESTDIR
201		makeenv="$makeenv DESTDIR";;
202
203	-d)	buildtarget=distribution;;
204
205	-E)	expert_mode=true;;
206
207	-i)	eval $optargcmd
208		installworlddir=$OPTARG;;
209
210	-j)	eval $optargcmd
211		parallel="-j $OPTARG";;
212
213	-k)	do_buildkernel=true; do_buildsystem=false
214		eval $optargcmd
215		kernconfname=$OPTARG;;
216
217	-M)	eval $optargcmd; resolvepath
218		MAKEOBJDIRPREFIX="$OPTARG"; export MAKEOBJDIRPREFIX
219		makeobjdir=$OPTARG
220		makeenv="$makeenv MAKEOBJDIRPREFIX";;
221
222	# -m overrides MACHINE_ARCH unless "-a" is specified
223	-m)	eval $optargcmd
224		MACHINE=$OPTARG; [ "$opt_a" != "yes" ] && getarch;;
225
226	-n)	runcmd=echo;;
227
228	-O)	eval $optargcmd; resolvepath
229		MAKEOBJDIR="\${.CURDIR:C,^$TOP,$OPTARG,}"; export MAKEOBJDIR
230		makeobjdir=$OPTARG
231		makeenv="$makeenv MAKEOBJDIR";;
232
233	-o)	MKOBJDIRS=no;;
234
235	-R)	eval $optargcmd; resolvepath
236		RELEASEDIR=$OPTARG; export RELEASEDIR
237		makeenv="$makeenv RELEASEDIR"
238		buildtarget=release;;
239
240	-r)	do_removedirs=true; do_rebuildmake=true;;
241
242	-T)	eval $optargcmd; resolvepath
243		TOOLDIR="$OPTARG"; export TOOLDIR;;
244
245	-t)	do_buildtools=true; do_buildsystem=false;;
246
247	-U)	UNPRIVED=yes; export UNPRIVED
248		makeenv="$makeenv UNPRIVED";;
249
250	-u)	UPDATE=yes; export UPDATE
251		makeenv="$makeenv UPDATE";;
252
253	-V)	eval $optargcmd
254		case "${OPTARG}" in
255		    # XXX: consider restricting which variables can be changed?
256		[a-zA-Z_][a-zA-Z_0-9]*=*)
257			var=${OPTARG%%=*}
258			value=${OPTARG#*=}
259			eval "${var}=\"${value}\"; export ${var}"
260			makeenv="$makeenv ${var}"
261			;;
262		*)
263			echo "-V argument must be of the form 'var=[value]'"
264			usage;;
265		esac
266		;;
267
268	-w)	eval $optargcmd; resolvepath
269		makewrapper="$OPTARG";;
270
271	--)		break;;
272	-'?'|-h)	usage;;
273    esac
274done
275
276# Set up MACHINE*.  On a NetBSD host, these are allowed to be unset.
277if [ -z "$MACHINE" ]; then
278	if [ "${uname_s}" != "NetBSD" ]; then
279		echo "MACHINE must be set, or -m must be used, for cross builds."
280		echo ""; usage
281	fi
282	MACHINE=${uname_m}
283fi
284[ -n "$MACHINE_ARCH" ] || getarch
285validatearch
286
287# Set up default make(1) environment.
288makeenv="$makeenv TOOLDIR MACHINE MACHINE_ARCH MAKEFLAGS"
289if [ ! -z "$BUILDID" ]; then
290	makeenv="$makeenv BUILDID"
291fi
292MAKEFLAGS="-m $TOP/share/mk $MAKEFLAGS MKOBJDIRS=${MKOBJDIRS-yes}"
293export MAKEFLAGS MACHINE MACHINE_ARCH
294
295# Test make source file timestamps against installed nbmake binary,
296# if TOOLDIR is pre-set.
297#
298# Note that we do NOT try to grovel "mk.conf" here to find out if TOOLDIR
299# is set there, because it can contain make variable expansions and other
300# stuff only parseable *after* we have a working nbmake.  So this logic
301# can only work if the user has pre-set TOOLDIR in the environment or
302# used the -T option to build.sh.
303#
304make="${TOOLDIR-nonexistent}/bin/nbmake"
305if [ -x $make ]; then
306	for f in usr.bin/make/*.[ch] usr.bin/make/lst.lib/*.[ch]; do
307		if [ $f -nt $make ]; then
308			do_rebuildmake=true; break
309		fi
310	done
311else
312	do_rebuildmake=true
313fi
314
315# Build bootstrap nbmake if needed.
316if $do_rebuildmake; then
317	$runcmd echo "===> Bootstrapping nbmake"
318	tmpdir="${TMPDIR-/tmp}/nbbuild$$"
319
320	$runcmd mkdir "$tmpdir" || bomb "cannot mkdir: $tmpdir"
321	trap "cd /; rm -r -f \"$tmpdir\"" 0
322	trap "exit 1" 1 2 3 15
323	$runcmd cd "$tmpdir"
324
325	$runcmd env CC="${HOST_CC-cc}" CPPFLAGS="${HOST_CPPFLAGS}" \
326		CFLAGS="${HOST_CFLAGS--O}" LDFLAGS="${HOST_LDFLAGS}" \
327		"$TOP/tools/make/configure" \
328		|| bomb "configure of nbmake failed"
329	$runcmd sh buildmake.sh || bomb "build of nbmake failed"
330
331	make="$tmpdir/nbmake"
332	$runcmd cd "$TOP"
333	$runcmd rm -f usr.bin/make/*.o usr.bin/make/lst.lib/*.o
334fi
335
336EXTERNAL_TOOLCHAIN=$(getmakevar EXTERNAL_TOOLCHAIN)
337if [ "$runcmd" = "echo" ]; then
338	TOOLCHAIN_MISSING=no
339else
340	TOOLCHAIN_MISSING=$(getmakevar TOOLCHAIN_MISSING)
341fi
342if [ "${TOOLCHAIN_MISSING}" = "yes" -a \
343     "${EXTERNAL_TOOLCHAIN}" = "" ]; then
344	echo "ERROR: build.sh (in-tree cross-toolchain) is not yet available for"
345	echo
346	echo "MACHINE: ${MACHINE}"
347	echo "MACHINE_ARCH: ${MACHINE_ARCH}"
348	echo
349	echo "All builds for this platform should be done via a traditional make"
350	echo
351	echo "If you wish to use an external cross-toolchain, set"
352	echo
353	echo "EXTERNAL_TOOLCHAIN=<path to toolchain root>"
354	echo
355	echo "in either the environment or mk.conf and rerun"
356	echo
357	echo "$0 $*"
358	exit 1
359fi
360
361# If TOOLDIR isn't already set, make objdirs in "tools" in case the
362# default setting from <bsd.own.mk> is used.
363if [ -z "$TOOLDIR" ] && [ "$MKOBJDIRS" != "no" ]; then
364	$runcmd cd tools
365	$runcmd $make -m ${TOP}/share/mk obj NOSUBDIR= \
366		|| bomb "make obj failed in tools"
367	$runcmd cd "$TOP"
368fi
369
370#
371# If setting -M or -O to root an obj dir make sure the base directory is made
372# before continuing as bsd.own.mk will need this to pick up _SRC_TOP_OBJ_
373#
374if [ "$MKOBJDIRS" != "no" ] && [ ! -z "$makeobjdir" ]; then
375	$runcmd mkdir -p "$makeobjdir"
376fi
377
378# Find DESTDIR and TOOLDIR.
379if [ "$runcmd" = "echo" ]; then
380	# shown symbolically with -n because these may come from mk.conf
381	DESTDIR='$DESTDIR'
382	TOOLDIR='$TOOLDIR'
383else
384	DESTDIR=$(getmakevar DESTDIR)
385	[ $? = 0 ] || bomb "getmakevar DESTDIR failed"
386	$runcmd echo "===> DESTDIR path: $DESTDIR"
387
388	TOOLDIR=$(getmakevar TOOLDIR)
389	[ $? = 0 ] || bomb "getmakevar TOOLDIR failed"
390	$runcmd echo "===> TOOLDIR path: $TOOLDIR"
391
392	export DESTDIR TOOLDIR
393fi
394
395# Check validity of TOOLDIR and DESTDIR.
396if [ -z "$TOOLDIR" ] || [ "$TOOLDIR" = "/" ]; then
397	bomb "TOOLDIR '$TOOLDIR' invalid"
398fi
399removedirs="$TOOLDIR"
400
401if [ -z "$DESTDIR" ] || [ "$DESTDIR" = "/" ]; then
402	if $do_buildsystem; then
403		if [ "$buildtarget" != "build" ] || \
404		   [ "${uname_s}" != "NetBSD" ] || \
405		   [ "${uname_m}" != "$MACHINE" ]; then
406			bomb "DESTDIR must be set to a non-root path for cross builds or -d or -R."
407		fi
408		if ! $expert_mode; then
409			bomb "DESTDIR must be set to a non-root path for non -E (expert) builds"
410		fi
411		$runcmd echo "===> WARNING: Building to /, in expert mode."
412		$runcmd echo "===>          This may cause your system to break!  Reasons include:"
413		$runcmd echo "===>             - your kernel is not up to date"
414		$runcmd echo "===>             - the libraries or toolchain have changed"
415		$runcmd echo "===>          YOU HAVE BEEN WARNED!"
416	fi
417else
418	removedirs="$removedirs $DESTDIR"
419fi
420
421if [ "$installworlddir" = "/" ]; then
422	if [ "${uname_s}" != "NetBSD" ] || \
423	   [ "${uname_m}" != "$MACHINE" ]; then
424		bomb "-i installworlddir must be set to a non-root path for cross builds."
425	fi
426fi
427
428# Remove the target directories.
429if $do_removedirs; then
430	for f in $removedirs; do
431		$runcmd echo "===> Removing $f"
432		$runcmd rm -r -f $f
433	done
434fi
435
436# Recreate $TOOLDIR.
437$runcmd mkdir -p "$TOOLDIR/bin" || bomb "mkdir of '$TOOLDIR/bin' failed"
438
439# Install nbmake if it was built.
440if $do_rebuildmake; then
441	$runcmd rm -f "$TOOLDIR/bin/nbmake"
442	$runcmd cp $make "$TOOLDIR/bin/nbmake" \
443		|| bomb "failed to install \$TOOLDIR/bin/nbmake"
444	make="$TOOLDIR/bin/nbmake"
445	$runcmd rm -r -f "$tmpdir"
446	trap 0 1 2 3 15
447fi
448
449# Build a nbmake wrapper script, usable by hand as well as by build.sh.
450if [ -z "$makewrapper" ]; then
451	makewrapper="$TOOLDIR/bin/nbmake-$MACHINE"
452	if [ ! -z "$BUILDID" ]; then
453		makewrapper="$makewrapper-$BUILDID"
454	fi
455fi
456
457$runcmd rm -f "$makewrapper"
458if [ "$runcmd" = "echo" ]; then
459	echo 'cat <<EOF >'$makewrapper
460	makewrapout=
461else
462	makewrapout=">>\$makewrapper"
463fi
464
465eval cat <<EOF $makewrapout
466#! /bin/sh
467# Set proper variables to allow easy "make" building of a NetBSD subtree.
468# Generated from:  \$NetBSD: build.sh,v 1.81 2003/01/04 14:55:44 lukem Exp $
469#
470
471EOF
472for f in $makeenv; do
473	eval echo "$f=\'\$$(echo $f)\'\;\ export\ $f" $makewrapout
474done
475eval echo "USETOOLS=yes\; export USETOOLS" $makewrapout
476
477eval cat <<'EOF' $makewrapout
478
479exec "$TOOLDIR/bin/nbmake" ${1+"$@"}
480EOF
481[ "$runcmd" = "echo" ] && echo EOF
482$runcmd chmod +x "$makewrapper"
483
484if $do_buildsystem; then
485	# Build everything.
486	${runcmd-exec} "$makewrapper" $parallel $buildtarget \
487		|| bomb "failed to make $buildtarget"
488else
489	# One or more of do_buildtools and do_buildkernel
490	# might be set.  Do them in the appropriate order.
491	if $do_buildtools; then
492		if [ "$MKOBJDIRS" != "no" ]; then
493			$runcmd "$makewrapper" $parallel obj-tools \
494				|| bomb "failed to make obj-tools"
495		fi
496		$runcmd cd tools
497		if [ "$UPDATE" = "" ]; then
498			$runcmd "$makewrapper" cleandir dependall install \
499				|| bomb "failed to make tools"
500		else
501			$runcmd "$makewrapper" dependall install \
502				|| bomb "failed to make tools"
503		fi
504	fi
505	if $do_buildkernel; then
506		if ! $do_buildtools; then
507			# Building tools every time we build a kernel
508			# is clearly unnecessary.  We could try to
509			# figure out whether rebuilding the tools is
510			# necessary this time, but it doesn't seem
511			# worth the trouble.  Instead, we say it's the
512			# user's responsibility to rebuild the tools if
513			# necessary.
514			$runcmd echo "===> Building kernel" \
515				"without building new tools"
516		fi
517		$runcmd echo "===> Building kernel ${kernconfname}"
518		# The correct value of KERNOBJDIR might depend on a
519		# prior "make obj" in TOP/etc.
520		if [ "$MKOBJDIRS" != "no" ] && [ ! -z "$makeobjdir" ]; then
521			$runcmd cd "$TOP/etc"
522			$runcmd "$makewrapper" obj \
523				|| bomb "failed to make obj in etc"
524			$runcmd cd "$TOP"
525		fi
526		if [ "$runcmd" = "echo" ]; then
527			# shown symbolically with -n
528			# because getmakevar might not work yet
529			KERNCONFDIR='$KERNCONFDIR'
530			KERNOBJDIR='$KERNOBJDIR'
531		else
532			KERNCONFDIR="$( getmakevar KERNCONFDIR )"
533			[ $? = 0 ] || bomb "getmakevar KERNCONFDIR failed"
534			KERNOBJDIR="$( getmakevar KERNOBJDIR )"
535			[ $? = 0 ] || bomb "getmakevar KERNOBJDIR failed"
536		fi
537		case "${kernconfname}" in
538		*/*)
539			kernconfpath="${kernconfname}"
540			kernconfbase="$( basename "${kernconfname}" )"
541			;;
542		*)
543			kernconfpath="${KERNCONFDIR}/${kernconfname}"
544			kernconfbase="${kernconfname}"
545			;;
546		esac
547		kernbuilddir="${KERNOBJDIR}/${kernconfbase}"
548		$runcmd echo "===> Kernel build directory: ${kernbuilddir}"
549		$runcmd mkdir -p "${kernbuilddir}" \
550			|| bomb "cannot mkdir: ${kernbuilddir}"
551		if [ "$UPDATE" = "" ]; then
552			$runcmd cd "${kernbuilddir}"
553			$runcmd "$makewrapper" cleandir \
554				|| bomb "make cleandir failed in " \
555					"${kernbuilddir}"
556			$runcmd cd "$TOP"
557		fi
558		$runcmd "${TOOLDIR}/bin/nbconfig" \
559			-b "${kernbuilddir}" \
560			-s "${TOP}/sys" "${kernconfpath}" \
561			|| bomb "nbconfig failed for ${kernconfname}"
562		$runcmd cd "${kernbuilddir}"
563		$runcmd "$makewrapper" depend \
564			|| bomb "make depend failed in ${kernbuilddir}"
565		$runcmd "$makewrapper" $parallel all \
566			|| bomb "make all failed in ${kernbuilddir}"
567		$runcmd echo "===> New kernel should be in ${kernbuilddir}"
568	fi
569fi
570
571if [ -n "$installworlddir" ]; then
572	${runcmd-exec} "$makewrapper" INSTALLWORLDDIR=${installworlddir} \
573		installworld || bomb "failed to make installworld"
574fi
575