#!/bin/sh # # Copyright (c) 2015 Antti Kantee. All Rights Reserved. # Copyright (c) 2015 Martin Lucina. All Rights Reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # _RUMPBAKE_VERSION=20160209 # # rumprun-bake: script for final stage linking ("baking") of a unikernel image # unset runcmd unset CONF unset CFGFILE if [ "$(basename $0)" = "rumpbake" ]; then echo '>>' echo '>> name "rumpbake" is deprecated. use rumprun-bake instead' echo '>> (waiting 5s for you to see this)' echo '>>' sleep 5 fi if [ "${RUMPRUN_WARNING_STFU}" != 'please' ]; then exec 3>&1 1>&2 echo echo !!! echo !!! NOTE: rumprun-bake is experimental. syntax may change in the future echo !!! echo exec 1>&3 3>&- fi _die() { echo ">> ERROR: $*" exit 1 } # # configuration management # _filter () { local filtee vname tmplist filtee=$1 vname=$2 for x in $(eval echo \${${vname}}); do [ "${filtee}" = "${x}" ] || tmplist="${tmplist} ${x}" done eval ${vname}="\${tmplist}" } _haveconf () { for x in ${ALLCONFIGS}; do [ "${x}" != "${1}" ] || return done _die "config \"${1}\" not found (${CFGFILE})" } _nothaveconf () { for x in ${ALLCONFIGS}; do [ "${x}" != "${1}" ] \ || _die "config ${1} already exists (${CFGFILE})" done } # Implement "sort | uniq" ourselves so that we don't completely # screw up the order of the arguments. not 100% sure it matters, but it's # easy enough. Also, notably, doing it locally is ~50% faster (which # starts to matter when you have enough configs). _uniq () { local listname newlist listname=$1 shift || _die need listname for _uniq eval _UNIQREMAINING=\${$listname} set -- ${_UNIQREMAINING} while [ $# -gt 0 ]; do newlist="${newlist} $1" _filter $1 _UNIQREMAINING set -- ${_UNIQREMAINING} done eval ${listname}=\${newlist} } ALLCONFIGS= version () { [ "${1}" = "${_RUMPBAKE_VERSION}" ] \ || _die ${CFGFILE} mismatch: expect ${_RUMPBAKE_VERSION}, got \"$1\" _VERSOK=true } conf () { if ! echo ${1} | egrep -q '^(xen|hw|sel4)?_'; then _die "conf: invalid \"$1\" (${CFGFILE})" fi CONF=$1 } fnoc () { unset CONF } create () { [ -n "$*" ] || _die "create: need description (${CFGFILE})" _nothaveconf ${CONF} ALLCONFIGS="${ALLCONFIGS} ${CONF}" eval CONFDESCR_${CONF}=\"${*}\" } assimilate () { local from _haveconf ${CONF} for from; do _haveconf ${from} eval CONFIG_${CONF}=\"\${CONFIG_${CONF}} \${CONFIG_${from}}\" done } nuke () { [ $# -eq 0 ] || _die "nuke: wrong number of args (${CFGFILE})" _haveconf ${CONF} _filter ${CONF} ALLCONFIGS } add () { _haveconf ${CONF} eval CONFIG_${CONF}=\"\${CONFIG_${CONF}} $@\" } remove () { local compvar _haveconf ${CONF} compvar=CONFIG_${CONF} for x; do _filter ${x} ${compvar} done } # debug routine debugdump () { _haveconf ${CONF} _uniq CONFIG_${CONF} eval echo \${CONFIG_${CONF}} } _usage () { cat <> ${TMPDIR}/manualcmds ;; n) runcmd=echo ;; *) _usage ;; esac done shift $((${OPTIND}-1)) TARGET="${1}" if [ "${TARGET}" = "list" ]; then for x in ${ALLCONFIGS}; do eval mydesc="\${CONFDESCR_${x}}" printf '%-16s' "${x}" printf ': %s' "${mydesc}" printf '\n' done exit 0 fi if [ "${TARGET}" = "describe" ]; then CONFIG=$2 else CONFIG=$1 fi # process potential manual commands if [ -f ${TMPDIR}/manualcmds ]; then printf "version %s\n" ${_RUMPBAKE_VERSION} > ${TMPDIR}/cmdconfig printf "conf %s\n" ${CONFIG} >> ${TMPDIR}/cmdconfig cat ${TMPDIR}/manualcmds >> ${TMPDIR}/cmdconfig printf 'fnoc\n' >> ${TMPDIR}/cmdconfig _readconfig ${TMPDIR}/cmdconfig fi if [ "${TARGET}" = "describe" ]; then [ $# -eq 2 ] || _die \"describe\" needs exactly one config. CONF=$2 debugdump exit 0 fi OUTPUT="${2}" [ $# -gt 2 ] || _usage shift 2 unset RUMPBAKE_BACKINGCC unset RUMPBAKE_TUPLE unset RUMPBAKE_CFLAGS # XXX: TOOLDIR is just dirname $0, so can simplify that bit unset RUMPBAKE_TOOLDIR [ $# -le 8 ] || { echo '>> max 8 binaries supported currently' ; exit 1; } # Santize the config argument passed in to remove shell # metacharacters config="$(echo ${TARGET} | sed -e 's/-/_/g' -e 's/[^A-Za-z0-9_]//g')" for c in ${ALLCONFIGS}; do [ "$c" = "$config" ] && break done if [ "$c" != "$config" ]; then echo "rumprun-bake: error: unsupported config \"$config\"" exit 1 fi _uniq CONFIG_${config} PLATFORM=${config%%_*} eval LIBS="\${CONFIG_${config}}" # Check if the file is a relocatable object produced by a rumprun toolchain. # Create a temporary object with a unique "main" objnum=1 allobjs= for f in "$@"; do _getbininfo ${f} ${runcmd} ${RUMPBAKE_TOOLDIR}/bin/${RUMPBAKE_TUPLE}-objcopy \ --redefine-sym main=rumprun_main${objnum} \ ${f} ${TMPDIR}/tmp${objnum}.obj allobjs="${allobjs} ${TMPDIR}/tmp${objnum}.obj" objnum=$((${objnum}+1)) done MACHINE_GNU_ARCH=${RUMPBAKE_TUPLE%%-*} # Final link using cc to produce the unikernel image. ${runcmd} ${RUMPBAKE_BACKINGCC} ${RUMPBAKE_CFLAGS} !EXTRACCFLAGS! \ --sysroot ${RUMPBAKE_TOOLDIR}/rumprun-${MACHINE_GNU_ARCH} \ -specs=${RUMPBAKE_TOOLDIR}/rumprun-${MACHINE_GNU_ARCH}/lib/rumprun-${PLATFORM}/specs-bake \ -o ${OUTPUT} ${allobjs} \ -Wl,--whole-archive ${LIBS} || exit 1 exit 0