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