blob: e477a39fd79761a8f7595c927cb41911c7b9ac99 [file] [log] [blame]
#!/bin/bash
# Copyright (c) 2011 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
# Script must run inside the chroot
restart_in_chroot_if_needed "$@"
assert_not_root_user
# Developer-visible flags.
DEFINE_string board "${DEFAULT_BOARD}" \
"The board to build packages for."
DEFINE_boolean usepkg "${FLAGS_TRUE}" \
"Use binary packages to bootstrap when possible."
DEFINE_boolean usepkgonly "${FLAGS_FALSE}" \
"Only use binary packages to bootstrap; abort if any are missing."
DEFINE_boolean workon "${FLAGS_TRUE}" \
"Force-build workon packages."
DEFINE_boolean showoutput "${FLAGS_FALSE}" \
"Show all output from parallel_emerge."
DEFINE_boolean withautotest "${FLAGS_TRUE}" \
"Build autotest client code."
DEFINE_boolean withdebugsymbols "${FLAGS_FALSE}" \
"Install the debug symbols for all packages"
DEFINE_boolean withevents "${FLAGS_FALSE}" \
"Generate events during parallel_emerge step"
DEFINE_string eventfile "${DEFAULT_EVENT_FILE}" \
"Define the file that event logs will be written."
DEFINE_boolean withrevdeps "${FLAGS_TRUE}" \
"Calculate reverse dependencies on changed ebuilds."
DEFINE_boolean autosetgov "${FLAGS_FALSE}" \
"Automatically set cpu governor to 'performance'."
DEFINE_boolean use_any_chrome "${FLAGS_TRUE}" \
"Use any Chrome prebuilt available, even if the prebuilt doesn't match exactly."
# The --board_root flag specifies the environment variables ROOT and PKGDIR.
# This allows fetching and emerging of all packages to specified board_root.
# Note that --board_root will setup the board normally in /build/$BOARD, if it's
# not setup yet. It also expects the toolchain to already be installed in the
# board_root. --usepkgonly and --norebuild are required, because building is not
# supported when board_root is set.
# enforce this)."
DEFINE_string board_root "" \
"Emerge packages to board_root."
FLAGS_HELP="usage: $(basename $0) [flags] [packages]
build_packages updates the set of binary packages needed by Chrome OS. It will
cross compile all packages that have been updated into the given target's root
and build binary packages as a side-effect. The output packages will be picked
up by the build_image script to put together a bootable Chrome OS image.
If [packages] are specified, only build those specific packages (and any
dependencies they might need).
For the fastest builds, use --nowithautotest --noworkon.
"
# 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 accept_licenses "" \
"Licenses to append to the accept list."
DEFINE_integer jobs -1 \
"How many packages to build in parallel at maximum."
DEFINE_boolean norebuild "${FLAGS_FALSE}" \
"Don't automatically rebuild dependencies."
DEFINE_boolean skip_chroot_upgrade "${FLAGS_FALSE}" \
"Don't run the chroot upgrade automatically; use with care."
DEFINE_boolean skip_toolchain_update "${FLAGS_FALSE}" \
"Don't update toolchain automatically."
DEFINE_boolean withdev "${FLAGS_TRUE}" \
"Build useful developer friendly utilities."
DEFINE_boolean withdebug "${FLAGS_TRUE}" \
"Build debug versions of Chromium-OS-specific packages."
DEFINE_boolean withfactory "${FLAGS_TRUE}" \
"Build factory installer."
DEFINE_boolean withtest "${FLAGS_TRUE}" \
"Build packages required for testing."
# The --reuse_pkgs_from_local_boards flag tells Portage to share binary
# packages between boards that are built locally, so that the total time
# required to build several boards is reduced. This flag is only useful
# when you are not able to use remote binary packages, since remote binary
# packages are usually more up to date than anything you have locally.
DEFINE_boolean reuse_pkgs_from_local_boards "${FLAGS_FALSE}" \
"Bootstrap from local packages instead of remote packages."
# --run_goma option is designed to be used on bots.
# If you're trying to build pacakges with goma in your local dev env, this is
# *not* the option you're looking for. Please see comments below.
# This option; 1) starts goma, 2) builds packages (expecting that goma is
# used), then 3) stops goma explicitly.
# 3) is a request from the goma team, so that stats/logs can be taken.
# Note: GOMA_DIR and GOMA_SERVICE_ACCOUNT_JSON_FILE are expected to be passed
# via env var.
#
# In local dev env cases, compiler_proxy is expected to keep running.
# In such a case;
# $ python ${GOMA_DIR}/goma_ctl.py ensure_start
# $ ./build_packages (... and options without --run_goma ...)
# is an expected commandline sequence. If you set --run_goma flag while
# compiler_proxy is already running, the existing compiler_proxy will be
# stopped.
DEFINE_boolean run_goma "${FLAGS_FALSE}" \
"If set to true, (re)starts goma, builds packages, and then stops goma."
# Parse command line
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
# Die on any errors.
switch_to_strict_mode
# This is a temporary measure to help the goma team check the configs while
# they transition their backend service.
# TODO(crbug.com/1032290): Delete after the goma RBE transition is complete.
if [[ "${FLAGS_run_goma}" -eq "${FLAGS_TRUE}" ]]; then
info "Environment:"
env
info "End Environment."
fi
# Right now build_packages has to be run from scripts/
. ${SRC_ROOT}/third_party/chromiumos-overlay/chromeos/config/chromeos_version.sh
# On some systems, powersave can take a long time to ramp up. Inform the user
# so they can get faster builds. https://crbug.com/1008932
if grep -qs powersave \
/sys/devices/system/cpu/cpufreq/policy*/scaling_governor; then
# Make sure we can actually support "performance".
if grep -qs performance \
/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors; then
if [[ "${FLAGS_autosetgov}" -eq "${FLAGS_TRUE}" ]]; then
info "Temporarily setting cpu governor to 'performance'"
trap "sudo cpupower -c all frequency-set -g powersave >&/dev/null" EXIT
sudo cpupower -c all frequency-set -g performance >&/dev/null
else
warn "Current CPU governor set to 'powersave' which can slow down builds."
warn "Use --autosetgov to automatically (and temporarily) switch to" \
"'performance'."
fi
fi
fi
if [[ -z "${FLAGS_board}" ]]; then
echo "Error: --board is required."
exit 1
fi
# Before we can run any tools, we need to update chroot or setup_board.
UPDATE_ARGS=()
if [[ -n ${FLAGS_accept_licenses} ]]; then
UPDATE_ARGS+=( --accept-licenses "${FLAGS_accept_licenses}" )
fi
if [ "${FLAGS_usepkg}" -eq "${FLAGS_TRUE}" ]; then
UPDATE_ARGS+=( --usepkg )
else
UPDATE_ARGS+=( --nousepkg )
fi
if [[ "${FLAGS_jobs}" -ne -1 ]]; then
UPDATE_ARGS+=( --jobs=${FLAGS_jobs} )
fi
if [ "${FLAGS_reuse_pkgs_from_local_boards}" -eq "${FLAGS_TRUE}" ]; then
UPDATE_ARGS+=( --reuse-pkgs-from-local-boards )
fi
if [ "${FLAGS_skip_toolchain_update}" -eq "${FLAGS_TRUE}" ]; then
UPDATE_ARGS+=( --skip-toolchain-update )
fi
if [ "${FLAGS_skip_chroot_upgrade}" -eq "${FLAGS_TRUE}" ]; then
UPDATE_ARGS+=( --skip-chroot-upgrade )
fi
if [[ -n ${FLAGS_board_root} ]]; then
UPDATE_ARGS+=( --board-root "${FLAGS_board_root}" )
fi
setup_board --quiet --board=${FLAGS_board} "${UPDATE_ARGS[@]}"
sudo_clear_shadow_locks "/build/${FLAGS_board}"
PORTAGE_BINHOST=$(portageq-${FLAGS_board} envvar 'PORTAGE_BINHOST')
info "PORTAGE_BINHOST: ${PORTAGE_BINHOST}"
# Setup all the emerge command/flags.
EMERGE_FLAGS=( -uDNv --backtrack=30 --newrepo )
EMERGE_CMD=(
"${CHROMITE_BIN}/parallel_emerge"
--board=${FLAGS_board}
)
if [[ "${FLAGS_use_any_chrome}" -eq "${FLAGS_TRUE}" ]]; then
EMERGE_CMD+=( "--force-remote-binary=chromeos-base/chromeos-chrome" )
fi
EMERGE_CMD+=( ${EXTRA_BOARD_FLAGS} )
if [[ "${FLAGS_usepkg}" -eq "${FLAGS_TRUE}" ||
"${FLAGS_reuse_pkgs_from_local_boards}" -eq "${FLAGS_TRUE}" ||
"${FLAGS_usepkgonly}" -eq "${FLAGS_TRUE}" ]]; then
# Use binary packages. Include all build-time dependencies,
# so as to avoid unnecessary differences between source
# and binary builds.
EMERGE_FLAGS+=( --getbinpkg --with-bdeps y )
if [[ ${FLAGS_usepkgonly} -eq ${FLAGS_TRUE} ]]; then
EMERGE_FLAGS+=( --usepkgonly )
else
EMERGE_FLAGS+=( --usepkg )
fi
fi
if [[ "${FLAGS_jobs}" -ne -1 ]]; then
EMERGE_FLAGS+=( --jobs=${FLAGS_jobs} )
fi
if [[ "${FLAGS_norebuild}" -eq "${FLAGS_FALSE}" ]]; then
EMERGE_FLAGS+=( --rebuild-if-new-rev )
fi
if [[ "${FLAGS_showoutput}" -eq "${FLAGS_TRUE}" ]]; then
EMERGE_FLAGS+=( --show-output )
fi
if [[ "${FLAGS_withdebug}" -eq "${FLAGS_FALSE}" ]]; then
export USE="${USE} -cros-debug"
fi
# TODO Handle case where passed default value, but events not enabled
if [[ "${FLAGS_eventfile}" != "${DEFAULT_EVENT_FILE}" ]]; then
FLAGS_withevents="${FLAGS_TRUE}"
fi
if [[ "${FLAGS_withevents}" -eq "${FLAGS_TRUE}" ]]; then
mkdir -p "$(dirname $FLAGS_eventfile)"
EMERGE_FLAGS+=( "--eventlogfile=${FLAGS_eventfile}" )
fi
# Figure out which packages we should be building.
PACKAGES=( "$@" )
FORCE_LOCAL_BUILD_PKGS=()
if [[ $# -eq 0 ]]; then
PACKAGES=( virtual/target-os )
if [[ "${FLAGS_withdev}" -eq "${FLAGS_TRUE}" ]]; then
PACKAGES+=( virtual/target-os-dev )
fi
if [[ "${FLAGS_withfactory}" -eq "${FLAGS_TRUE}" ]]; then
PACKAGES+=( virtual/target-os-factory )
PACKAGES+=( virtual/target-os-factory-shim )
fi
if [[ "${FLAGS_withtest}" -eq "${FLAGS_TRUE}" ]]; then
PACKAGES+=( virtual/target-os-test )
# chromeos-ssh-testkeys may generate ssh keys if the right USE flag is set.
# We force rebuilding this package from source every time, so that
# consecutive builds don't share ssh keys.
FORCE_LOCAL_BUILD_PKGS+=( chromeos-base/chromeos-ssh-testkeys )
fi
if [[ "${FLAGS_withautotest}" -eq "${FLAGS_TRUE}" ]]; then
PACKAGES+=( chromeos-base/autotest-all )
fi
fi
info "Rebuilding Portage cache"
# Before running any emerge operations, regenerate the Portage dependency cache
# in parallel.
"${EMERGE_CMD[@]}" --regen --quiet
# Verify that all packages can be emerged from scratch, without any
# backtracking. Only print the output if this step fails.
info "Checking package dependencies are correct: ${PACKAGES[*]}"
if ! OUTPUT=$(emerge-${FLAGS_board} -pe --backtrack=0 \
"${PACKAGES[@]}" 2>&1); then
printf "%s\n" "${OUTPUT}"
die_notrace "emerge detected broken ebuilds. See error message above."
fi
# Build cros_workon packages when they are changed.
CROS_WORKON_PKGS=()
if [ "${FLAGS_workon}" -eq "${FLAGS_TRUE}" ]; then
LIST_MODIFIED_PACKAGES="${CHROMITE_BIN}/cros_list_modified_packages"
MODIFIED_PACKAGES=( $("${LIST_MODIFIED_PACKAGES}" --board=${FLAGS_board}) )
info "cros_workon modified packages '${MODIFIED_PACKAGES[*]}' detected"
CROS_WORKON_PKGS+=( "${MODIFIED_PACKAGES[@]}" )
# TODO(anush): Make chrome a fake cros-workon package.
if [[ -n "${CHROME_ORIGIN}" ]]; then
CROS_WORKON_PKGS+=( chromeos-base/chromeos-chrome )
fi
fi
# cros_workon packages always have to be rebuilt.
FORCE_LOCAL_BUILD_PKGS+=( "${CROS_WORKON_PKGS[@]}" )
if [[ -n "${FLAGS_board_root}" ]]; then
export ROOT="${FLAGS_board_root}"
export PORTAGE_CONFIGROOT="${ROOT}"
export SYSROOT="${ROOT}"
export PKGDIR="${ROOT}"/packages
fi
# Temporarily modify the emerge flags so we can calculate the revdeps
# on the modified packages.
if [[ "${FLAGS_withrevdeps}" -eq "${FLAGS_TRUE}" ]]; then
info "starting reverse dependency calculations ..."
SIM_EMERGE_FLAGS=( "${EMERGE_FLAGS[@]}" --pretend --columns )
if [[ ${#PACKAGES[@]} -gt 0 ]]; then
SIM_EMERGE_FLAGS+=(
--reinstall-atoms="${PACKAGES[*]}"
--usepkg-exclude="${PACKAGES[*]}"
)
fi
# Calculate only the ebuild changes from the emerge simulation ignoring
# the virtual packages and the forced rebuild of autotest-all package.
BASE_INSTALL_PKGS=( $( \
sudo -E "${EMERGE_CMD[@]}" "${SIM_EMERGE_FLAGS[@]}" "${PACKAGES[@]}" | \
sed -n -E '/^\[ebuild /{s:^[^]]+\] +::;s: .*::;p}' | \
grep -v -e '^virtual/' -e '^chromeos-base/autotest-all' | sort -u ) )
MOD_PKGS=()
if [[ "${#BASE_INSTALL_PKGS[@]}" -gt 0 ]]; then
info "New packages being installed: ${BASE_INSTALL_PKGS[*]}."
# Convert specific versions into base package names
MOD_PKGS+=( $(\
equery-${FLAGS_board} list -p -o --format='$category/$name' \
"${BASE_INSTALL_PKGS[@]}" | sort -u ) )
# Remove Chrome as rebuilding it is expensive and almost never makes sense.
# Ignore grep exit status in case chromeos-chrome is the only package.
MOD_PKGS=( $(printf '%s\n' "${MOD_PKGS[@]}" | \
grep -v 'chromeos-base/chromeos-chrome' || :) )
fi
FORCE_LOCAL_BUILD_PKGS+=( "${MOD_PKGS[@]}" )
if [[ "${#MOD_PKGS[@]}" -gt 0 ]]; then
info "calculating reverse dependencies on packages: ${MOD_PKGS[*]}"
REV_DEPS=( $(\
equery-${FLAGS_board} -q depends --indirect "${MOD_PKGS[@]}" |\
awk '{print $1}' | grep -v ^virtual/ | sort -u) )
if [[ "${#REV_DEPS[@]}" -gt 0 ]]; then
# Convert specific versions into base package names
RMOD_PKGS=( $(\
equery-${FLAGS_board} -q list -p -o --format='$category/$name' \
"${REV_DEPS[@]}" | sort -u ) )
# Remove Chrome as rebuilding it is expensive and almost never makes
# sense. Ignore grep exit status in case chromeos-chrome is the only
# package.
RMOD_PKGS=( $(printf '%s\n' "${RMOD_PKGS[@]}" | \
grep -v 'chromeos-base/chromeos-chrome' || :) )
info "final reverse dependencies that will be rebuilt: ${RMOD_PKGS[*]}"
FORCE_LOCAL_BUILD_PKGS+=( "${RMOD_PKGS[@]}" )
fi
fi
fi # end FLAGS_withrevdeps
if [[ ${#FORCE_LOCAL_BUILD_PKGS[@]} -gt 0 ]]; then
EMERGE_FLAGS+=(
--reinstall-atoms="${FORCE_LOCAL_BUILD_PKGS[*]}"
--usepkg-exclude="${FORCE_LOCAL_BUILD_PKGS[*]}"
)
fi
info "Merging board packages now"
(
# Support goma on bots. This has to run in subshell, otherwise EXIT trap
# handler is overwritten.
if [[ "${FLAGS_run_goma}" -eq "${FLAGS_TRUE}" ]]; then
info "Starting goma compiler_proxy."
goma_ctl="${GOMA_DIR:-${HOME}/goma}/goma_ctl.py"
# TODO(crbug.com/1007384): Stop forcing Python 2.
EPYTHON="python2" "${goma_ctl}" restart
trap "EPYTHON=python2 '${goma_ctl}' stop" EXIT
fi
sudo -E "${EMERGE_CMD[@]}" "${EMERGE_FLAGS[@]}" "${PACKAGES[@]}"
)
echo "Builds complete"
if [[ ${FLAGS_withdebugsymbols} -eq ${FLAGS_TRUE} ]]; then
info "fetching the debug symbols"
sudo -E "${CHROMITE_BIN}/cros_install_debug_syms" \
"--board=${FLAGS_board}" "--all"
fi
command_completed
echo "Done"