#!/bin/sh # Makeworld dir structure should contain, at minimum: # script # makeworld (this file) # worlds # seed # base # (arch of build host: i386, amd64, etc) # base.* (virgin base tree of same arch as host, used to seed chroot for clean build) # (i386, amd64, etc) # (GENERIC, SABA, SS4200, etc) # config # make.conf # src.conf # CONFIG (Matches config name: GENERIC, SABA, SS4200, etc) # Load shlib and modules _root="$(dirname "${0}")"; . "${_root}/lib/env.sh" want log pebkac() { [ "${*}" ] && printf "%s\n\n" "${*}" echo "Usage: $(basename "${0}") -m -t -c " echo " -m Provide additional flags to make" echo " -t Target architecture (i386, amd64)" echo " -c Target configuration (in worlds//)" echo " -h Help!" echo "" echo "If, for some reason, you wish to spread out builds across multiple" echo "invocations, these might come in handy:" echo " -p Prepare chroot environment" echo " -d Don't prepare or clean up chroot during run" echo " -q Clean up chroot environment" echo "" echo "Available make targets:" for target in ${make_tgts} do echo " ${target}" done exit 1 } # Prepare chroot for build prepare() { [ "${CHROOT_DIRTY}" -a ! "${CHROOT_PREPARE}" ] && return 0 # Verify environment sanity [ -d "${build}" ] && omg "${build}: directory exists; purging" && cleanup mount | grep -q "${build}" && wtf "Stuff is mounted under ${build}; cannot continue" ls -1 "${seed}"/base.?? >/dev/null 2>&1 || wtf "Populate seed directory ${seed} first" [ -f /usr/src/sys/conf/newvers.sh ] || wtf "Need sources in /usr/src to build" # Cleanup trap here, so that an abort during prepare can clean up properly trap "cleanup" exit hup int term kill meh "Preparing build chroot" [ -d "${build}" ] && wtf "${build}: directory exists" mkdir -p "${build}" || wtf cat "${seed}"/base.?? | tar xCf "${build}" - || wtf mkdir -p "${build}/usr/obj" || wtf meh "Mounting chroot filesystems" mkdir -p "${world}/obj" mkdir -p "${world}/root" mount -t devfs devfs "${build}/dev" || wtf # Mount /usr/src as a union, so that changes to it will not affect the underlying tree # unionfs suffers from deadlocks; don't use it mount -t nullfs -r /usr/src "${build}/usr/src" || wtf mount -t nullfs "${world}/obj" "${build}/usr/obj" || wtf mount -t nullfs "${world}/root" "${build}/mnt" || wtf if [ -d "${world}/config" ] then meh "Installing build-time configuration" [ -f "${world}/config/${CONFIG}" ] && cp "${world}/config/${CONFIG}" "/usr/src/sys/${TARGET}/conf/" [ -f "${world}/config/make.conf" ] && cp "${world}/config/make.conf" "${build}/etc/" [ -f "${world}/config/src.conf" ] && cp "${world}/config/src.conf" "${build}/etc/" fi return 0 } # Cleanup chroot cleanup() { [ "${CHROOT_DIRTY}" -a ! "${CHROOT_CLEAN}" ] && return 0 meh "Cleaning up" umount -f "${build}/mnt" umount -f "${build}/usr/obj" umount -f "${build}/usr/src" umount -f "${build}/dev" mount | grep -q "${build}" && wtf "Stuff is still mounted under ${build}; not removing" chflags -R noschg "${build}" rm -Rf "${build}" trap "" exit hup int term kill return 0 } # Root directory of makeworld ROOT="$(realpath "$(dirname "${0}")/../worlds")" # Compute make -j make_cpus="$(sysctl -n hw.ncpu)" make_jobs="$(( ${make_cpus} * 2 ))" make_tgts="buildworld buildkernel distrib-dirs installworld installkernel distribution" # Defaults TARGET="$(uname -m)" CONFIG="GENERIC" MAKEOPTS="-j${make_jobs}" while getopts "m:t:c:hpdq" opt do case "${opt}" in m) MAKEOPTS="${MAKEOPTS} ${OPTARG}" ;; t) TARGET="${OPTARG}" ;; c) CONFIG="${OPTARG}" ;; p) CHROOT_PREPARE="TRUE" ;; d) CHROOT_DIRTY="TRUE" ;; q) CHROOT_CLEAN="TRUE" ;; h) pebkac ;; [?]) pebkac "Unrecognized option ${opt}" ;; esac done shift $(( $OPTIND - 1 )) # Should be root after this point want root # Build make target sequence sequence="${*:-${make_tgts}}" # Target world directory world="${ROOT}/${TARGET}/${CONFIG}" # Source chroot seed directory seed="${ROOT}/seed/base/$(uname -m)" # Root directory for chroot build="${ROOT}/world/chroot" # Environment for chroot build env=" USER=root HOME=/root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin SHELL=/bin/sh " date="$(date +%Y%m%d)" # Check if target config exists [ -d "${world}" ] || wtf "${TARGET}/${CONFIG} doesn't exist" if [ "${CHROOT_PREPARE}" ] then prepare trap "" exit meh "Chroot prepared" exit fi if [ "${CHROOT_CLEAN}" ] then cleanup meh "Chroot cleaned" exit fi meh "Making world for ${TARGET}/${CONFIG}" prepare meh "Seed: ${seed}" meh "Config: ${TARGET}/${CONFIG}" meh "Builddir: ${build}" meh "make ${MAKEOPTS}" meh "DESTDIR=${world}/root" for step in ${sequence} do meh "==> Phase: ${step}" script "${world}/${date}-${step}.log" env -i ${env} chroot "${build}" sh -c \ "cd /usr/src; time make ${MAKEOPTS} ${step} TARGET=${TARGET} KERNCONF=${CONFIG} DESTDIR=/mnt" || wtf "chroot-cmd ${phase}" done # Copy the config files into the target, to keep a record of the build options [ -f "${world}/config/${CONFIG}" ] && cp "${world}/config/${CONFIG}" "${build}/boot/kernel/" [ -f "${world}/config/make.conf" ] && cp "${world}/config/make.conf" "${build}/etc/" [ -f "${world}/config/src.conf" ] && cp "${world}/config/src.conf" "${build}/etc/"