mirror of
https://github.com/flatcar/scripts.git
synced 2026-01-15 21:41:38 +01:00
Catalyst 4 adds support for building with QEMU, so I initially leveraged this, but it turned out to be very much slower than emulating the amd64 SDK on arm64, where an arm64 build could then be mostly run without emulation. I have kept the code for the slower approach anyway since it is small and may be useful to somebody. There were several places where we assumed that amd64 was native and arm64 required emulation via QEMU. The scripts are now more architecture-agnostic, paving the way for riscv support later. We no longer set QEMU_LD_PREFIX because it prevents the SDK itself from being emulated. It also assumes there is only one non-native target, which won't be the case soon. bubblewrap does a better job of running binaries under QEMU. Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
389 lines
13 KiB
Bash
Executable File
389 lines
13 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
. "$(dirname "$0")/common.sh" || exit 1
|
|
. "${BUILD_LIBRARY_DIR}/toolchain_util.sh" || exit 1
|
|
|
|
# Script must run inside the chroot
|
|
assert_inside_chroot
|
|
|
|
assert_not_root_user
|
|
|
|
# Developer-visible flags.
|
|
DEFINE_string board "${DEFAULT_BOARD}" \
|
|
"The name of the board to set up."
|
|
DEFINE_boolean default "${FLAGS_FALSE}" \
|
|
"Set board to the default board in your chroot"
|
|
DEFINE_boolean force "${FLAGS_FALSE}" \
|
|
"Force re-creating board root."
|
|
DEFINE_boolean usepkg "${FLAGS_TRUE}" \
|
|
"Use binary packages when possible."
|
|
DEFINE_boolean usepkgonly "${FLAGS_FALSE}" \
|
|
"Only use/download binary packages."
|
|
DEFINE_boolean getbinpkg "${FLAGS_TRUE}" \
|
|
"Download binary packages from remote repository."
|
|
DEFINE_string getbinpkgver "" \
|
|
"Use binary packages from a specific version."
|
|
DEFINE_string pkgdir "" \
|
|
"Use binary packages from a custom directory instead of /build/[ARCH]/var/lib/portage/pkgs/."
|
|
DEFINE_string binhost "" \
|
|
"Use binary packages from a specific location instead of $FLATCAR_DEV_BUILDS/... "
|
|
DEFINE_boolean skip_toolchain_update "${FLAGS_FALSE}" \
|
|
"Don't update toolchain automatically."
|
|
DEFINE_boolean skip_chroot_upgrade "${FLAGS_FALSE}" \
|
|
"Don't run the chroot upgrade automatically; use with care."
|
|
DEFINE_boolean regen_configs "${FLAGS_FALSE}" \
|
|
"Regenerate all config files (useful for modifying profiles w/out rebuild)."
|
|
DEFINE_boolean regen_configs_only "${FLAGS_FALSE}" \
|
|
"Regenerate all config files and nothing else, even if nothing else is installed."
|
|
|
|
FLAGS_HELP="usage: $(basename $0) [flags]
|
|
|
|
setup_board sets up the sysroot for a particular board. This script is called
|
|
automatically when you run build_packages, so there is typically no need to
|
|
call it directly, unless you want to blow away your board (using --force).
|
|
"
|
|
show_help_if_requested "$@"
|
|
|
|
# The following options are advanced options, only available to those willing
|
|
# to read the source code. They are not shown in help output, since they are
|
|
# not needed for the typical developer workflow.
|
|
DEFINE_string libc_version "[stable]" \
|
|
"Version of libc to use."
|
|
DEFINE_boolean quiet $FLAGS_FALSE \
|
|
"Don't print warnings when board already exists."
|
|
DEFINE_string variant "" \
|
|
"Board variant."
|
|
|
|
|
|
# builds wrappers like equery-arm-generic.
|
|
# args:
|
|
# $1: command to wrap
|
|
# rest: extra arguments to pass to the command
|
|
_generate_wrapper() {
|
|
local command="${1}"
|
|
shift
|
|
local extra_args="$@"
|
|
|
|
|
|
local target="/usr/local/bin/${command}-${BOARD_VARIANT}"
|
|
sudo_clobber "${target}" <<EOF
|
|
#!/bin/bash
|
|
|
|
export PORTAGE_CONFIGROOT="$BOARD_ROOT"
|
|
export SYSROOT="\${SYSROOT:-$BOARD_ROOT}"
|
|
export ROOT="$BOARD_ROOT"
|
|
exec sudo -E ${command} ${extra_args} "\$@"
|
|
EOF
|
|
# Note: parent will process these.
|
|
wrappers+=( "${target}" )
|
|
upper=${command^^}
|
|
eval ${upper/-/_}_WRAPPER="${target}" # ${foo^^} returns toupper($foo)
|
|
}
|
|
|
|
generate_all_wrappers() {
|
|
local cmds=() wrappers=()
|
|
local wrapper qemu
|
|
|
|
# If the QEMU user space emulator is missing for this board arch, that implies
|
|
# the board arch matches the SDK arch and therefore emulation is unnecessary.
|
|
qemu=$(type -P "qemu-${BOARD_CHOST%%-*}") || unset qemu
|
|
|
|
# If emulation is necessary, then we need to create a placeholder to bind
|
|
# mount QEMU onto now. This avoids needing root to do it later.
|
|
if [[ -n ${qemu-} ]]; then
|
|
sudo mkdir -p "${BOARD_ROOT}${qemu%/*}"
|
|
sudo touch "${BOARD_ROOT}${qemu}"
|
|
fi
|
|
|
|
info "Generating wrapper scripts"
|
|
|
|
for wrapper in emerge ebuild eclean equery portageq \
|
|
qcheck qfile qlist emaint glsa-check; do
|
|
_generate_wrapper ${wrapper}
|
|
done
|
|
|
|
wrapper="/usr/local/bin/flatcar_workon-${BOARD_VARIANT}"
|
|
sudo_clobber "${wrapper}" <<EOF
|
|
#!/bin/bash
|
|
exec "${SRC_ROOT}/scripts/flatcar_workon" --board ${BOARD_VARIANT} "\$@"
|
|
EOF
|
|
wrappers+=( "${wrapper}" )
|
|
|
|
wrapper="/usr/local/bin/gdb-${BOARD_VARIANT}"
|
|
sudo_clobber "${wrapper}" <<EOF
|
|
#!/bin/bash
|
|
exec ${BOARD_CHOST}-gdb -iex 'set sysroot ${BOARD_ROOT}' "\$@"
|
|
EOF
|
|
wrappers+=( "${wrapper}" )
|
|
|
|
# A general purpose wrapper for effectively chrooting using bubblewrap,
|
|
# together with emulation by QEMU if necessary.
|
|
wrapper="/usr/local/bin/bwrap-${BOARD_VARIANT}"
|
|
sudo_clobber "${wrapper}" <<EOF
|
|
#!/bin/sh -e
|
|
_ROOT=\${1?Pass a root directory as the first argument}
|
|
shift
|
|
exec bwrap --bind "\${_ROOT}" / --tmpfs /tmp --dev-bind /dev /dev --proc /proc --bind /sys /sys ${qemu+--ro-bind ${qemu} ${qemu}} -- "\$@"
|
|
EOF
|
|
wrappers+=( "${wrapper}" )
|
|
|
|
# ldconfig cannot generate caches for non-native arches. Use QEMU and the
|
|
# native ldconfig to work around that. Don't use the bwrap wrapper above
|
|
# because it's unnecessarily complex for this use case.
|
|
wrapper="/usr/local/sbin/ldconfig-${BOARD_VARIANT}"
|
|
sudo_clobber "${wrapper}" <<EOF
|
|
#!/bin/sh
|
|
exec ${qemu-} "${BOARD_ROOT}"/sbin/ldconfig -r "${BOARD_ROOT}" "\$@"
|
|
EOF
|
|
wrappers+=( "${wrapper}" )
|
|
|
|
# Create a CHOST-based ldconfig symlink for Portage to call.
|
|
sudo ln -sfT "ldconfig-${BOARD_VARIANT}" "/usr/local/sbin/${BOARD_CHOST}-ldconfig"
|
|
|
|
cmds+=(
|
|
"chmod a+rx ${wrappers[*]}"
|
|
"chown root:root ${wrappers[*]}"
|
|
)
|
|
|
|
sudo_multi "${cmds[@]}"
|
|
}
|
|
|
|
generate_binhost_list() {
|
|
FLAGS_getbinpkgver="${FLAGS_getbinpkgver/current/${FLATCAR_VERSION_ID}}"
|
|
FLAGS_getbinpkgver="${FLAGS_getbinpkgver/latest/${FLATCAR_VERSION_ID}}"
|
|
FLAGS_getbinpkgver="${FLAGS_getbinpkgver/sdk/${FLATCAR_SDK_VERSION}}"
|
|
|
|
get_board_binhost "${BOARD}" ${FLAGS_getbinpkgver}
|
|
}
|
|
|
|
# Parse command line flags
|
|
FLAGS "$@" || exit 1
|
|
eval set -- "${FLAGS_ARGV}"
|
|
|
|
# Only now can we die on error. shflags functions leak non-zero error codes,
|
|
# so will die prematurely if 'switch_to_strict_mode' is specified before now.
|
|
switch_to_strict_mode
|
|
|
|
if [ -z "$FLAGS_board" ] ; then
|
|
error "--board required."
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "${FLAGS_usepkgonly}" -eq "${FLAGS_TRUE}" ]]; then
|
|
for flag in usepkg getbinpkg; do
|
|
fvar="FLAGS_${flag}"
|
|
if [[ "${!fvar}" -ne "${FLAGS_TRUE}" ]]; then
|
|
die_notrace "--usepkgonly is incompatible with --no${flag}"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
get_board_and_variant $FLAGS_board $FLAGS_variant
|
|
|
|
# Locations we will need
|
|
COREOS_OVERLAY="${REPO_ROOT}/src/third_party/coreos-overlay"
|
|
COREOS_CONFIG="${COREOS_OVERLAY}/coreos/config"
|
|
BOARD_ROOT="/build/${BOARD_VARIANT}"
|
|
BOARD_ETC="${BOARD_ROOT}/etc"
|
|
BOARD_ARCH=$(get_board_arch "$BOARD")
|
|
BOARD_CHOST=$(get_board_chost ${BOARD})
|
|
PORTAGE_PROFILE=$(get_board_profile "$BOARD")
|
|
BOARD_BINHOST="$FLAGS_binhost $(generate_binhost_list)"
|
|
BOARD_PKGDIR="${FLAGS_pkgdir:-${BOARD_ROOT}/var/lib/portage/pkgs}"
|
|
|
|
if [[ ${FLAGS_regen_configs_only} -eq ${FLAGS_TRUE} ]]; then
|
|
FLAGS_regen_configs=${FLAGS_TRUE}
|
|
FLAGS_skip_chroot_upgrade=${FLAGS_TRUE}
|
|
elif [[ -d "${BOARD_ROOT}" ]]; then
|
|
if [[ ${FLAGS_force} -eq ${FLAGS_TRUE} ]]; then
|
|
info "--force set. Re-creating ${BOARD_ROOT}..."
|
|
# Removal takes long. Make it asynchronous.
|
|
TEMP_DIR=`mktemp -d`
|
|
sudo mv "${BOARD_ROOT}" "${TEMP_DIR}"
|
|
sudo rm -rf "${TEMP_DIR}" &
|
|
elif [[ ${FLAGS_regen_configs} -eq ${FLAGS_FALSE} ]]; then
|
|
if [[ ${FLAGS_quiet} -eq ${FLAGS_FALSE} ]]; then
|
|
warn "Board output directory '$BOARD_ROOT' already exists."
|
|
warn "Not setting up board root. "
|
|
warn "Use --force to clobber the board root and start again."
|
|
fi
|
|
exit 0
|
|
fi
|
|
else
|
|
# Missing board root and --regen_configs_only wasn't used.
|
|
FLAGS_regen_configs=${FLAGS_FALSE}
|
|
fi
|
|
|
|
# Before we can run any tools, we need to update chroot
|
|
UPDATE_ARGS="--toolchain_boards=${BOARD}"
|
|
if [ "${FLAGS_usepkg}" -eq "${FLAGS_TRUE}" ]; then
|
|
UPDATE_ARGS+=" --usepkg"
|
|
if [[ "${FLAGS_usepkgonly}" -eq "${FLAGS_TRUE}" ]]; then
|
|
UPDATE_ARGS+=" --usepkgonly"
|
|
else
|
|
UPDATE_ARGS+=" --nousepkgonly"
|
|
fi
|
|
if [[ "${FLAGS_getbinpkg}" -eq "${FLAGS_TRUE}" ]]; then
|
|
UPDATE_ARGS+=" --getbinpkg "
|
|
else
|
|
UPDATE_ARGS+=" --nogetbinpkg "
|
|
fi
|
|
if [[ -n "${FLAGS_binhost}" ]]; then
|
|
UPDATE_ARGS+=" --binhost=${FLAGS_binhost} "
|
|
fi
|
|
else
|
|
UPDATE_ARGS+=" --nousepkg"
|
|
fi
|
|
if [ "${FLAGS_skip_toolchain_update}" -eq "${FLAGS_TRUE}" ]; then
|
|
UPDATE_ARGS+=" --skip_toolchain_update"
|
|
fi
|
|
if [ "${FLAGS_skip_chroot_upgrade}" -eq "${FLAGS_FALSE}" ] ; then
|
|
"${SRC_ROOT}/scripts"/update_chroot ${UPDATE_ARGS}
|
|
fi
|
|
|
|
# Migrate board roots that were created before the package location
|
|
# was standardized to /var/lib/portage/pkgs, build_image will fail if we
|
|
# simply forget about the old location and start writing to the new.
|
|
# Keep /packages as a compatibility symlink until everyone is updated.
|
|
if [[ ! -L "${BOARD_ROOT}/packages" ]]; then
|
|
if [[ ! -d "${BOARD_ROOT}/var/lib/portage/pkgs" ]]; then
|
|
if [[ -d "${BOARD_ROOT}/packages" ]]; then
|
|
warn "Moving board package directory to ${BOARD_ROOT}/var/lib/portage/pkgs"
|
|
sudo mkdir -p "${BOARD_ROOT}/var/lib/portage"
|
|
sudo mv "${BOARD_ROOT}/packages" "${BOARD_ROOT}/var/lib/portage/pkgs"
|
|
else
|
|
sudo mkdir -p "${BOARD_ROOT}/var/lib/portage/pkgs"
|
|
fi
|
|
fi
|
|
sudo ln -sfT "var/lib/portage/pkgs" "${BOARD_ROOT}/packages"
|
|
fi
|
|
|
|
info "Configuring portage in ${BOARD_ROOT}"
|
|
sudo mkdir -p "${BOARD_ETC}/portage/"{profile,repos.conf}
|
|
sudo ln -sfT "$(portageq get_repo_path / coreos-overlay)/coreos/user-patches" \
|
|
"${BOARD_ETC}/portage/patches"
|
|
sudo cp /etc/portage/repos.conf/* "${BOARD_ETC}"/portage/repos.conf/
|
|
# set PORTAGE_CONFIGROOT to tell eselect to modify the profile inside
|
|
# /build/<arch>-usr, but set ROOT to /, so eselect will actually find
|
|
# the profile which is outside /build/<arch>-usr, set SYSROOT to / as
|
|
# well, because it must match ROOT
|
|
sudo \
|
|
PORTAGE_CONFIGROOT="${BOARD_ROOT}" ROOT=/ SYSROOT=/ \
|
|
eselect profile set --force "${PORTAGE_PROFILE}"
|
|
|
|
# Cleanup/migrate from older make.conf files
|
|
sudo rm -f "${BOARD_ETC}/make.conf" "${BOARD_ETC}/make.conf.common"
|
|
if [[ -f "${BOARD_ETC}/make.conf.user" ]]; then
|
|
sudo mv "${BOARD_ETC}/make.conf.user" \
|
|
"${BOARD_ETC}/portage/make.conf.user"
|
|
else
|
|
sudo touch "${BOARD_ETC}/portage/make.conf.user"
|
|
fi
|
|
|
|
sudo_clobber "${BOARD_ETC}/portage/make.conf" <<EOF
|
|
# Created by setup_board
|
|
|
|
# Settings derived from the host environment
|
|
CBUILD="$(portageq envvar CHOST)"
|
|
HOSTCC="$(portageq envvar CHOST)-gcc"
|
|
DISTDIR="$(portageq envvar DISTDIR)"
|
|
MAKEOPTS="$(portageq envvar MAKEOPTS)"
|
|
PORTAGE_USERNAME="$(portageq envvar PORTAGE_USERNAME)"
|
|
|
|
# Board specific settings
|
|
CHOST="${BOARD_CHOST}"
|
|
ROOT="${BOARD_ROOT}/"
|
|
PKGDIR="${BOARD_PKGDIR}"
|
|
PORT_LOGDIR="${BOARD_ROOT}/var/log/portage"
|
|
PORTAGE_TMPDIR="${BOARD_ROOT}/var/tmp"
|
|
PORTAGE_BINHOST="${BOARD_BINHOST}"
|
|
|
|
# Generally there isn't any need to add packages to @world by default.
|
|
# You can use --select to override this.
|
|
EMERGE_DEFAULT_OPTS="--oneshot --verbose"
|
|
|
|
# Enable provenance reporting by default. Produced files are in /usr/share/SLSA
|
|
GENERATE_SLSA_PROVENANCE="true"
|
|
|
|
# Allow the user to override or define additional settings.
|
|
source "${BOARD_ETC}/portage/make.conf.user"
|
|
EOF
|
|
|
|
# required when using --regen_configs_only
|
|
sudo mkdir -p --mode=01777 "${BOARD_ROOT}"{/tmp,/var/tmp}
|
|
|
|
# make it easy to find debug symbols
|
|
sudo mkdir -p /usr/lib/debug/build
|
|
sudo ln -sfT ${BOARD_ROOT}/usr/lib/debug /usr/lib/debug/${BOARD_ROOT}
|
|
|
|
# remove bogus pkg-config wrapper
|
|
sudo rm -f "${BOARD_ROOT}/build/bin/${BOARD_CHOST}-pkg-config"
|
|
|
|
generate_all_wrappers
|
|
|
|
# Unclear why this is required but it doesn't happen automatically
|
|
info "Performing package updates..."
|
|
${EMAINT_WRAPPER} --fix movebin
|
|
${EMAINT_WRAPPER} --fix moveinst
|
|
${EMAINT_WRAPPER} --fix world
|
|
|
|
if [[ ${FLAGS_regen_configs} -eq ${FLAGS_FALSE} ]]; then
|
|
EMERGE_FLAGS=( --select --verbose "--jobs=${NUM_JOBS}" )
|
|
EMERGE_TOOLCHAIN_FLAGS=( "${EMERGE_FLAGS[@]}" )
|
|
|
|
if [[ "${FLAGS_usepkg}" -eq "${FLAGS_TRUE}" && \
|
|
"${FLAGS_getbinpkg}" -eq "${FLAGS_TRUE}" ]]
|
|
then
|
|
if [[ "${FLAGS_usepkgonly}" -eq "${FLAGS_TRUE}" ]]; then
|
|
EMERGE_FLAGS+=( --usepkgonly --rebuilt-binaries n )
|
|
else
|
|
EMERGE_FLAGS+=( --usepkg )
|
|
fi
|
|
EMERGE_FLAGS+=( --getbinpkg )
|
|
fi
|
|
|
|
info "Installing baselayout"
|
|
"${EMERGE_WRAPPER}" "${EMERGE_FLAGS[@]}" --nodeps sys-apps/baselayout
|
|
|
|
if [[ "${FLAGS_usepkg}" -ne "${FLAGS_TRUE}" ||
|
|
"${FLAGS_getbinpkg}" -ne "${FLAGS_TRUE}" ]]
|
|
then
|
|
# When binary packages are disabled we need to make sure the cross
|
|
# sysroot includes any build dependencies for the toolchain.
|
|
info "Installing toolchain build dependencies"
|
|
install_cross_libs "${BOARD_CHOST}" "${EMERGE_FLAGS[@]}" --buildpkg=n
|
|
|
|
info "Building toolchain dependencies"
|
|
"${EMERGE_WRAPPER}" --buildpkg --buildpkgonly \
|
|
--root="/usr/${BOARD_CHOST}" --sysroot="/usr/${BOARD_CHOST}" \
|
|
"${EMERGE_TOOLCHAIN_FLAGS[@]}" $(< "/usr/${BOARD_CHOST}/etc/portage/cross-${BOARD_CHOST}-depends")
|
|
info "Building toolchain"
|
|
"${EMERGE_WRAPPER}" --buildpkg --buildpkgonly \
|
|
--root="/usr/${BOARD_CHOST}" --sysroot="/usr/${BOARD_CHOST}" \
|
|
"${EMERGE_TOOLCHAIN_FLAGS[@]}" "${TOOLCHAIN_PKGS[@]}"
|
|
fi
|
|
|
|
info "Installing toolchain"
|
|
"${EMERGE_WRAPPER}" \
|
|
--usepkgonly --getbinpkg --rebuilt-binaries n \
|
|
"${EMERGE_TOOLCHAIN_FLAGS[@]}" "${TOOLCHAIN_PKGS[@]}"
|
|
fi
|
|
|
|
if [ $FLAGS_default -eq $FLAGS_TRUE ] ; then
|
|
echo $BOARD_VARIANT > "$GCLIENT_ROOT/src/scripts/.default_board"
|
|
fi
|
|
|
|
command_completed
|
|
info "The SYSROOT is: ${BOARD_ROOT}"
|
|
|
|
WORKING_ON=$("${SRC_ROOT}"/scripts/flatcar_workon list --board="${FLAGS_board}")
|
|
if [ -n "${WORKING_ON}" ]; then
|
|
info
|
|
info "Currently working on the following ebuilds for this board:"
|
|
info "${WORKING_ON}"
|
|
fi
|