endif
include ${BUILDRUMP_TOOLFLAGS}
-APP_TOOLS_DIR:= $(abspath .)
+_CCVARIANT:=$(shell ${RUMPMAKE} -f bsd.own.mk -V '$${HAVE_LLVM:Dclang:Ugcc}')
+_CXXVARIANT:=$(shell ${RUMPMAKE} -f bsd.own.mk -V '$${HAVE_LLVM:Dclang++:Ug++}')
-APP_TOOL_FILES= configure make gmake toolchain.cmake recipe.s
+_FILES= toolchain.cmake recipe.s
+FILES= $(_FILES:%=$(TOOLTUPLE)-%)
-APP_TOOL_SPECS= specs-compile_or_ferment specs-stub
+_SPECS= specs-compile_or_ferment specs-stub
+SPECS= ${_SPECS} specs-bake-${TOOLTUPLE}-${PLATFORM}
-APP_TOOL_PASSTHROUGH= ar as cpp ld nm objcopy objdump ranlib readelf
-APP_TOOL_PASSTHROUGH+= size strings strip
+_BINS= ar as cpp ld nm objcopy objdump ranlib readelf size strings strip
+BINS= $(_BINS:%=$(TOOLTUPLE)-%)
+BINS+= $(TOOLTUPLE)-$(_CCVARIANT) $(TOOLTUPLE)-$(_CXXVARIANT)
+BINS+= rumpbake rumprun rumpstop
-_CCVARIANT:=$(shell ${RUMPMAKE} -f bsd.own.mk -V '$${HAVE_LLVM:Dclang:Ugcc}')
-_CXXVARIANT:=$(shell ${RUMPMAKE} -f bsd.own.mk -V '$${HAVE_LLVM:Dclang++:Ug++}')
+.PHONY: app-tools
+app-tools: ${FILES} ${SPECS} ${BINS}
include ../global.mk
LDFLAGS_BAKE:= ${LDFLAGS.${PLATFORM}.${MACHINE_ARCH}}
-_APP_TOOL_TARGETS:= \
- $(APP_TOOL_FILES:%=$(APP_TOOLS_DIR)/$(TOOLTUPLE)-%) \
- $(APP_TOOLS_DIR)/$(TOOLTUPLE)-$(_CCVARIANT) \
- $(APP_TOOLS_DIR)/$(TOOLTUPLE)-$(_CXXVARIANT) \
- $(APP_TOOL_SPECS:%=$(APP_TOOLS_DIR)/%) \
- $(APP_TOOL_PASSTHROUGH:%=$(APP_TOOLS_DIR)/$(TOOLTUPLE)-%) \
- $(APP_TOOLS_DIR)/specs-bake-$(TOOLTUPLE)-$(PLATFORM)
+BRSOURCEDIR:=$(dir ${AR})
+BRLIBEXECDIR:= ${INSTALLDIR}/libexec/rumprun-${PLATFORM}-${MACHINE_ARCH}/
-.PHONY: app-tools
-app-tools: $(_APP_TOOL_TARGETS)
+LIBEXEC_CC:= $(subst ${BRSOURCEDIR},${BRLIBEXECDIR},${CC})
+LIBEXEC_CXX:= $(subst ${BRSOURCEDIR},${BRLIBEXECDIR},${CXX})
-APP_TOOLS_MAKE := $(APP_TOOLS_DIR)/$(TOOLTUPLE)-make
-APP_TOOLS_CC := $(APP_TOOLS_DIR)/$(TOOLTUPLE)-${_CCVARIANT}
-APP_TOOLS_CXX := $(APP_TOOLS_DIR)/$(TOOLTUPLE)-${_CXXVARIANT}
+TOOLS_CC := ${RRDEST}/bin/$(TOOLTUPLE)-${_CCVARIANT}
+TOOLS_CXX := ${RRDEST}/bin/$(TOOLTUPLE)-${_CXXVARIANT}
-define APPTOOLS_templ
-$(APP_TOOLS_DIR)/${2}: \
- $(APP_TOOLS_DIR)/${1} Makefile
+define templ
+${2}: ${1} Makefile
sed <$$< >$$@.tmp \
- -e 's#!CC!#$(CC)#g;' \
- -e 's#!CXX!#$(CXX)#g;' \
- -e 's#!APPTOOLS_CC!#$(APP_TOOLS_CC)#g;' \
- -e 's#!APPTOOLS_CXX!#$(APP_TOOLS_CXX)#g;' \
+ -e 's#!CC!#$(LIBEXEC_CC)#g;' \
+ -e 's#!CXX!#$(LIBEXEC_CXX)#g;' \
+ -e 's#!APPTOOLS_CC!#$(TOOLS_CC)#g;' \
+ -e 's#!APPTOOLS_CXX!#$(TOOLS_CXX)#g;' \
-e 's#!MACHINE_ARCH!#$(MACHINE_ARCH)#g;' \
-e 's#!GNUPLATFORM!#$(TOOLTUPLE)#g;' \
-e 's#!DESTDIR!#$(RRDEST)#g;' \
- -e 's#!APPTOOLS_DIR!#$(APP_TOOLS_DIR)#g;' \
-e 's#!APPTOOLS_PLATFORM!#$(PLATFORM)#g;' \
-e 's#!CPPFLAGS!#$(BUILDRUMP_TOOL_CPPFLAGS)#g;' \
-e 's#!CFLAGS!#$(BUILDRUMP_TOOL_CFLAGS)#g;' \
-e 's#!CXXFLAGS!#$(BUILDRUMP_TOOL_CXXFLAGS)#g;' \
-e 's#!LDFLAGS_BAKE!#$(LDFLAGS_BAKE)#g;'
- if test -x $$<; then chmod +x $$@.tmp; fi
mv -f $$@.tmp $$@
endef
-$(foreach tool,${APP_TOOL_FILES},$(eval \
- $(call APPTOOLS_templ,${tool}.in,$(TOOLTUPLE)-${tool})))
-$(foreach spec,${APP_TOOL_SPECS},$(eval \
- $(call APPTOOLS_templ,${spec}.in,${spec})))
-$(eval $(call APPTOOLS_templ,cc.in,$(TOOLTUPLE)-${_CCVARIANT}))
-$(eval $(call APPTOOLS_templ,cc.in,$(TOOLTUPLE)-${_CXXVARIANT}))
-$(eval $(call APPTOOLS_templ,specs-bake.in,specs-bake-$(TOOLTUPLE)-$(PLATFORM)))
-
-define APPTOOLS_passthrough
+$(foreach file,${_FILES},$(eval \
+ $(call templ,${file}.in,$(TOOLTUPLE)-${file})))
+$(foreach spec,${_SPECS},$(eval \
+ $(call templ,${spec}.in,${spec})))
+$(eval $(call templ,cc.in,$(TOOLTUPLE)-${_CCVARIANT}))
+$(eval $(call templ,cc.in,$(TOOLTUPLE)-${_CXXVARIANT}))
+$(eval $(call templ,specs-bake.in,specs-bake-$(TOOLTUPLE)-$(PLATFORM)))
+$(eval $(call templ,rumpbake.in,rumpbake))
+
+define binwrapper
uptool_$1=$(shell echo $1 | tr '[:lower:]' '[:upper:]')
toolval_$1=$${$${uptool_$1}}
-$(APP_TOOLS_DIR)/$(TOOLTUPLE)-$1:
- printf '#!/bin/sh\n\nexec %s "$$$${@}"\n' $${toolval_${1}} >$$@.tmp
- chmod +x $$@.tmp
- mv -f $$@.tmp $$@
+$(TOOLTUPLE)-$1:
+ printf '#!/bin/sh\n\nexec %s "$$$${@}"\n' \
+ $$(subst ${BRSOURCEDIR},${BRLIBEXECDIR},$${toolval_${1}}) >$$@
+
+BRTOOLS+= $${toolval_${1}}
endef
-$(foreach t,${APP_TOOL_PASSTHROUGH},$(eval $(call APPTOOLS_passthrough,${t})))
+$(foreach t,${_BINS},$(eval $(call binwrapper,${t})))
+
+${BRLIBEXECDIR}:
+ mkdir -p $@
+
+${INSTALLDIR}/etc:
+ mkdir -p $@
+
+install-buildrumpwrappers: ${BRLIBEXECDIR} ${BRTOOLS}
+ install -m 0755 ${BRTOOLS} ${CC} ${CXX} ${BRLIBEXECDIR}
+
+install-bins: ${BINS}
+ install -m 0755 ${BINS} ${INSTALLDIR}/bin
+
+install-files: ${SPECS} ${FILES} ${INSTALLDIR}/etc
+ install -m 0644 ${FILES} ${SPECS} ${INSTALLDIR}/share
+ install -m 0644 rumpbake.conf ${INSTALLDIR}/etc
+
+install: install-buildrumpwrappers install-bins install-files
clean:
- rm -f $(_APP_TOOL_TARGETS)
+ rm -f ${FILES} ${SPECS} ${BINS}
case ${MODE} in
compile)
exec ${CC} ${CFLAGS} -no-integrated-cpp \
- -specs=!APPTOOLS_DIR!/specs-compile_or_ferment \
+ -specs=!DESTDIR!/share/specs-compile_or_ferment \
"$@" ${EXTRALIBS}
;;
ferment)
# with no rump components. '-u main' is necessary to pull in main if the
# user is linking it in from a library.
${CC} ${CFLAGS} -no-integrated-cpp \
- -specs=!APPTOOLS_DIR!/specs-compile_or_ferment \
+ -specs=!DESTDIR!/share/specs-compile_or_ferment \
-Wl,-r -Wl,-u,main \
- "$@" !APPTOOLS_DIR!/!GNUPLATFORM!-recipe.s ${EXTRALIBS} || die
+ "$@" !DESTDIR!/share/!GNUPLATFORM!-recipe.s ${EXTRALIBS} || die
# If the presumed output file did not change, and the compiler
# did not flag an error, assume this is a command which does not
# Try a stub link with minimal rump components. If that fails then stop.
${CC} ${CFLAGS} -no-integrated-cpp \
- -specs=!APPTOOLS_DIR!/specs-stub \
+ -specs=!DESTDIR!/share/specs-stub \
${OUTFILE} -o /dev/null
if [ $? -ne 0 ]; then
if [ "${RUMPRUN_STUBLINK}" = "succeed" ]; then
0: .asciz "rumpkernel.org"
1: .p2align 2
2: .asciz "rumprun_tuple: !GNUPLATFORM!"
- .asciz "rumprun_tooldir: !APPTOOLS_DIR!"
+ .asciz "rumprun_tooldir: !DESTDIR!"
.asciz "rumprun_backingcc: !CC!"
/* XXX: cc frontend cflags should not be here */
.asciz "rumprun_cflags: !CFLAGS!"
+++ /dev/null
-#!/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=20150930
-
-#
-# rumpbake: script for final stage linking ("baking") of a unikernel image
-#
-
-: ${READELF:=readelf}
-unset runcmd
-
-if [ "${RUMPRUN_WARNING_STFU}" != 'please' ]; then
- exec 3>&1 1>&2
- echo
- echo !!!
- echo !!! NOTE: rumpbake 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 (${CURCONF})"
-}
-
-_nothaveconf ()
-{
-
- for x in ${ALLCONFIGS}; do
- [ "${x}" != "${1}" ] \
- || _die "config ${1} already exists (${CURCONF})"
- 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
-_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 ${CURCONF} mismatch: expect ${_RUMPBAKE_VERSION}, got \"$1\"
- _VERSOK=true
-}
-
-create ()
-{
- local confname descr
-
- confname=$1
- shift || _die "create: not enough arguments (${CURCONF})"
- [ -n "$*" ] || _die "create: need description (${CURCONF})"
-
- if ! echo ${confname} | egrep -q '^(|xen|hw)_'; then
- _die "create: invalid conf \"$confname\" (${CURCONF})"
- fi
-
- _nothaveconf ${confname}
-
- ALLCONFIGS="${ALLCONFIGS} ${confname}"
- eval CONFDESCR_${confname}=\"${*}\"
-}
-
-assimilate ()
-{
- local to from
-
- to=$1
- shift || _die not enough arguments to assimilate
- _haveconf ${to}
-
- for from; do
- _haveconf ${from}
- eval CONFIG_${to}=\"\${CONFIG_${to}} \${CONFIG_${from}}\"
- done
- _uniq CONFIG_${to}
-}
-
-nuke ()
-{
-
- [ $# -eq 1 ] || _die "nuke: wrong number of args (${CURCONF})"
- _haveconf ${1}
- _filter ${1} ALLCONFIGS
-}
-
-add ()
-{
- local confname
-
- confname=$1
- shift || _die "not enough args to add (${CURCONF})"
-
- _haveconf ${confname}
- eval CONFIG_${confname}=\"\${CONFIG_${confname}} $@\"
- _uniq CONFIG_${confname}
-}
-
-remove ()
-{
- local confname compvar
-
- confname=$1
- shift || _die "not enough args to remove (${CURCONF})"
-
- _haveconf ${confname}
-
- compvar=CONFIG_${confname}
- for x; do
- _filter ${x} ${compvar}
- done
-}
-
-# debug routine
-debugdump ()
-{
- local confname
-
- confname=$1
- shift || _die "not enough args to debugdump (${CURCONF})"
-
- _haveconf ${confname}
-
- eval echo \${CONFIG_${confname}}
-}
-
-_usage ()
-{
- cat <<EOM
-rumpbake version: ${_RUMPBAKE_VERSION}
-
-usage: rumpbake [-c conffile] config output input [input ...]
- rumpbake list
-
-When invoked the single argument "list", lists supported target boards.
-
-Else, creates a rumprunnable unikernel:
- config : rumprun board configuration to use.
- output : output file name for the unikernel image.
- input : executable(s) to bake.
-EOM
- exit 1
-}
-
-_nuketmpdir ()
-{
-
- nukeme="${TMPDIR}"
- TMPDIR=''
- ${runcmd} rm -rf ${nukeme}
-}
-
-_readconfig ()
-{
- local x
-
- CURCONF="${1}"
-
- if [ ! -f "${CURCONF}" ]; then
- echo "rumpbake: error: Configuration file ${CURCONF} not found"
- exit 1
- fi
-
- _VERSOK=false
- . "${CURCONF}"
- ${_VERSOK} || _die "config version not specified (${CURCONF})"
-
- unset CURCONF
-
- # limit visibility of _configs
- for x in ${ALLCONFIGS}; do
- [ "${x#_}" = "${x}" ] || _filter ${x} ALLCONFIGS
- done
-}
-
-_getoneinfo ()
-{
-
- bin="$1"
- var="$2"
- unset tmp
-
- notesect=.note.rumprun.bakerecipe
- tmp="$(${READELF} -p ${notesect} ${bin} 2>/dev/null \
- | sed -n '/.*rumprun_'"${var}"': /p')"
- [ -n "${tmp}" ] \
- || _die "Could not extract \"${var}\" from ${bin}. Not rumprun bin?"
-
- # now that we've verified the entry is present, reduce to
- # contents (which may be empty)
- tmp="${tmp#*rumprun_${var}: }"
-
- cvar=$(echo ${var} | tr '[a-z]' '[A-Z]')
-
- eval [ \"\${RUMPBAKE_${cvar}:=${tmp}}\" = \"${tmp}\" ] || \
- _die ${var} mismatch in binaries
-}
-
-_getbininfo ()
-{
-
- # extract bake recipe
- for x in tuple tooldir backingcc cflags; do
- _getoneinfo "${1}" ${x}
- done
-}
-
-APP_TOOLS_DIR=$(dirname $0)
-
-_readconfig "${APP_TOOLS_DIR}/rumpbake.conf"
-
-while getopts "c:n" opt; do
- case "${opt}" in
- c)
- _readconfig "${OPTARG}"
- ;;
- 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
-
-OUTPUT="${2}"
-[ $# -gt 2 ] || _usage
-shift 2
-
-# We need readelf to extract the ELF note with the baking recipe.
-# Just any readelf will do, but we need one.
-type ${READELF} >/dev/null 2>&1 \
- || _die 'Cannot find ${READELF}. Set $READELF env variable'
-unset RUMPBAKE_BACKINGCC
-unset RUMPBAKE_TUPLE
-unset RUMPBAKE_CFLAGS
-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 "rumpbake: error: unsupported config \"$config\""
- exit 1
-fi
-
-PLATFORM=${config%%_*}
-eval LIBS="\${CONFIG_${config}}"
-
-# duh
-TMPDIR=/tmp/rumpbake.XXXXXX
-[ -z "${runcmd}" ] && TMPDIR=$(mktemp -d ${TMPDIR})
-trap _nuketmpdir 0 INT TERM
-
-# 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}/${RUMPBAKE_TUPLE}-objcopy \
- --redefine-sym main=rumpbake_main${objnum} \
- ${f} ${TMPDIR}/tmp${objnum}.obj
- allobjs="${allobjs} ${TMPDIR}/tmp${objnum}.obj"
- objnum=$((${objnum}+1))
-done
-
-# Final link using cc to produce the unikernel image.
-${runcmd} ${RUMPBAKE_BACKINGCC} ${RUMPBAKE_CFLAGS} \
- -specs=${RUMPBAKE_TOOLDIR}/specs-bake-${RUMPBAKE_TUPLE}-${PLATFORM} \
- -o ${OUTPUT} ${allobjs} \
- -Wl,--whole-archive ${LIBS} || exit 1
-
-exit 0
--- /dev/null
+#!/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=20150930
+
+#
+# rumpbake: script for final stage linking ("baking") of a unikernel image
+#
+
+: ${READELF:=readelf}
+unset runcmd
+
+if [ "${RUMPRUN_WARNING_STFU}" != 'please' ]; then
+ exec 3>&1 1>&2
+ echo
+ echo !!!
+ echo !!! NOTE: rumpbake 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 (${CURCONF})"
+}
+
+_nothaveconf ()
+{
+
+ for x in ${ALLCONFIGS}; do
+ [ "${x}" != "${1}" ] \
+ || _die "config ${1} already exists (${CURCONF})"
+ 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
+_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 ${CURCONF} mismatch: expect ${_RUMPBAKE_VERSION}, got \"$1\"
+ _VERSOK=true
+}
+
+create ()
+{
+ local confname descr
+
+ confname=$1
+ shift || _die "create: not enough arguments (${CURCONF})"
+ [ -n "$*" ] || _die "create: need description (${CURCONF})"
+
+ if ! echo ${confname} | egrep -q '^(|xen|hw)_'; then
+ _die "create: invalid conf \"$confname\" (${CURCONF})"
+ fi
+
+ _nothaveconf ${confname}
+
+ ALLCONFIGS="${ALLCONFIGS} ${confname}"
+ eval CONFDESCR_${confname}=\"${*}\"
+}
+
+assimilate ()
+{
+ local to from
+
+ to=$1
+ shift || _die not enough arguments to assimilate
+ _haveconf ${to}
+
+ for from; do
+ _haveconf ${from}
+ eval CONFIG_${to}=\"\${CONFIG_${to}} \${CONFIG_${from}}\"
+ done
+ _uniq CONFIG_${to}
+}
+
+nuke ()
+{
+
+ [ $# -eq 1 ] || _die "nuke: wrong number of args (${CURCONF})"
+ _haveconf ${1}
+ _filter ${1} ALLCONFIGS
+}
+
+add ()
+{
+ local confname
+
+ confname=$1
+ shift || _die "not enough args to add (${CURCONF})"
+
+ _haveconf ${confname}
+ eval CONFIG_${confname}=\"\${CONFIG_${confname}} $@\"
+ _uniq CONFIG_${confname}
+}
+
+remove ()
+{
+ local confname compvar
+
+ confname=$1
+ shift || _die "not enough args to remove (${CURCONF})"
+
+ _haveconf ${confname}
+
+ compvar=CONFIG_${confname}
+ for x; do
+ _filter ${x} ${compvar}
+ done
+}
+
+# debug routine
+debugdump ()
+{
+ local confname
+
+ confname=$1
+ shift || _die "not enough args to debugdump (${CURCONF})"
+
+ _haveconf ${confname}
+
+ eval echo \${CONFIG_${confname}}
+}
+
+_usage ()
+{
+ cat <<EOM
+rumpbake version: ${_RUMPBAKE_VERSION}
+
+usage: rumpbake [-c conffile] config output input [input ...]
+ rumpbake list
+
+When invoked the single argument "list", lists supported target boards.
+
+Else, creates a rumprunnable unikernel:
+ config : rumprun board configuration to use.
+ output : output file name for the unikernel image.
+ input : executable(s) to bake.
+EOM
+ exit 1
+}
+
+_nuketmpdir ()
+{
+
+ nukeme="${TMPDIR}"
+ TMPDIR=''
+ ${runcmd} rm -rf ${nukeme}
+}
+
+_readconfig ()
+{
+ local x
+
+ CURCONF="${1}"
+
+ if [ ! -f "${CURCONF}" ]; then
+ echo "rumpbake: error: Configuration file ${CURCONF} not found"
+ exit 1
+ fi
+
+ _VERSOK=false
+ . "${CURCONF}"
+ ${_VERSOK} || _die "config version not specified (${CURCONF})"
+
+ unset CURCONF
+
+ # limit visibility of _configs
+ for x in ${ALLCONFIGS}; do
+ [ "${x#_}" = "${x}" ] || _filter ${x} ALLCONFIGS
+ done
+}
+
+_getoneinfo ()
+{
+
+ bin="$1"
+ var="$2"
+ unset tmp
+
+ notesect=.note.rumprun.bakerecipe
+ tmp="$(${READELF} -p ${notesect} ${bin} 2>/dev/null \
+ | sed -n '/.*rumprun_'"${var}"': /p')"
+ [ -n "${tmp}" ] \
+ || _die "Could not extract \"${var}\" from ${bin}. Not rumprun bin?"
+
+ # now that we've verified the entry is present, reduce to
+ # contents (which may be empty)
+ tmp="${tmp#*rumprun_${var}: }"
+
+ cvar=$(echo ${var} | tr '[a-z]' '[A-Z]')
+
+ eval [ \"\${RUMPBAKE_${cvar}:=${tmp}}\" = \"${tmp}\" ] || \
+ _die ${var} mismatch in binaries
+}
+
+_getbininfo ()
+{
+
+ # extract bake recipe
+ for x in tuple tooldir backingcc cflags; do
+ _getoneinfo "${1}" ${x}
+ done
+}
+
+_readconfig "!DESTDIR!/etc/rumpbake.conf"
+
+while getopts "c:n" opt; do
+ case "${opt}" in
+ c)
+ _readconfig "${OPTARG}"
+ ;;
+ 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
+
+OUTPUT="${2}"
+[ $# -gt 2 ] || _usage
+shift 2
+
+# We need readelf to extract the ELF note with the baking recipe.
+# Just any readelf will do, but we need one.
+type ${READELF} >/dev/null 2>&1 \
+ || _die 'Cannot find ${READELF}. Set $READELF env variable'
+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 "rumpbake: error: unsupported config \"$config\""
+ exit 1
+fi
+
+PLATFORM=${config%%_*}
+eval LIBS="\${CONFIG_${config}}"
+
+# duh
+TMPDIR=/tmp/rumpbake.XXXXXX
+[ -z "${runcmd}" ] && TMPDIR=$(mktemp -d ${TMPDIR})
+trap _nuketmpdir 0 INT TERM
+
+# 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=rumpbake_main${objnum} \
+ ${f} ${TMPDIR}/tmp${objnum}.obj
+ allobjs="${allobjs} ${TMPDIR}/tmp${objnum}.obj"
+ objnum=$((${objnum}+1))
+done
+
+# Final link using cc to produce the unikernel image.
+${runcmd} ${RUMPBAKE_BACKINGCC} ${RUMPBAKE_CFLAGS} \
+ -specs=${RUMPBAKE_TOOLDIR}/share/specs-bake-${RUMPBAKE_TUPLE}-${PLATFORM} \
+ -o ${OUTPUT} ${allobjs} \
+ -Wl,--whole-archive ${LIBS} || exit 1
+
+exit 0
builduserspace ()
{
- ${MAKE} -C app-tools
+ ${MAKE} -C app-tools BUILDRR=true
+ ${MAKE} -C app-tools BUILDRR=true install
usermtree ${STAGING}