| #!/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_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." |
| DEFINE_boolean cleanbuild "${FLAGS_FALSE}" \ |
| "Perform a clean build; delete sysroot if it exists before building." |
| DEFINE_boolean internal "${FLAGS_FALSE}" \ |
| "Build the internal version of chrome (set the chrome_internal USE flag)." |
| |
| # 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 |
| |
| # Chrome packages that need to be treated the same. These are the chrome and |
| # chrome follow-on packages that share the same version as chrome and are |
| # updated in lock step. |
| CHROME_PACKAGES=( |
| "chromeos-base/chromeos-chrome" |
| "chromeos-base/chrome-icu" |
| ) |
| |
| if [[ "${FLAGS_internal}" -eq "${FLAGS_TRUE}" ]]; then |
| export USE="${USE} chrome_internal" |
| fi |
| |
| # 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 |
| if [ "${FLAGS_cleanbuild}" -eq "${FLAGS_TRUE}" ]; then |
| UPDATE_ARGS+=( --force ) |
| 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 |
| for pkg in "${CHROME_PACKAGES[@]}"; do |
| EMERGE_CMD+=( "--force-remote-binary=${pkg}" ) |
| done |
| 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 |
| |
| # Figure out which packages we should be building. |
| PACKAGES=( "$@" ) |
| # Force rebuild chromeos-config because it is extremely cheap, and we do not |
| # want to reuse stale configs. |
| FORCE_LOCAL_BUILD_PKGS=( chromeos-base/chromeos-config ) |
| 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+=( "${CHROME_PACKAGES[@]}" ) |
| fi |
| fi |
| |
| # cros_workon packages always have to be rebuilt. |
| FORCE_LOCAL_BUILD_PKGS+=( "${CROS_WORKON_PKGS[@]}" ) |
| |
| # Any package that directly depends on an active cros_workon package also needs |
| # to be rebuilt in order to be correctly built against the current set of |
| # changes a user may have made to the cros_workon package. |
| if [[ ${#CROS_WORKON_PKGS[@]} -gt 0 ]]; then |
| # Collect all installed packages that depend on active cros_workon packages. |
| WORKON_PKG_CONSUMERS=() |
| mapfile -t WORKON_PKG_CONSUMERS < <( \ |
| equery-${FLAGS_board} -q depends "${CROS_WORKON_PKGS[@]}" | \ |
| sort -u | \ |
| grep -Ev "^\s*$" ) |
| |
| # Transform this list of packages with versions in to a list of just |
| # $CATEGORY/$NAME entries, since we don't want to pass packages with explicit |
| # version numbers as arguments to `emerge`. |
| if [[ ${#WORKON_PKG_CONSUMERS[@]} -gt 0 ]]; then |
| WORKON_REBUILD_PKGS=() |
| mapfile -t WORKON_REBUILD_PKGS < <( \ |
| equery-${FLAGS_board} list -p -o --format='$category/$name' \ |
| "${WORKON_PKG_CONSUMERS[@]}" | sort -u ) |
| |
| info "The following packages depend directly on an active" \ |
| "cros_workon package and will be rebuilt: ${WORKON_REBUILD_PKGS[*]}" |
| |
| FORCE_LOCAL_BUILD_PKGS+=( "${WORKON_REBUILD_PKGS[@]}" ) |
| fi |
| fi |
| |
| 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 |
| |
| # cros-workon packages are always going to be force reinstalled, so we add |
| # the forced reinstall behavior to the modified package calculation. This is |
| # necessary to include when a user has already installed a 9999 ebuild and is |
| # now reinstalling that package with additional local changes, because |
| # otherwise the modified package calculation would not see that a 'new' |
| # package is being installed. |
| if [[ ${#CROS_WORKON_PKGS[@]} -gt 0 ]]; then |
| SIM_EMERGE_FLAGS+=( |
| --reinstall-atoms="${CROS_WORKON_PKGS[*]}" |
| --usepkg-exclude="${CROS_WORKON_PKGS[*]}" |
| ) |
| fi |
| |
| # Calculate only the ebuild changes from the emerge simulation ignoring |
| # the virtual packages and the forced rebuild of autotest-all package. |
| # The lines of the following block do the following operations: |
| # 1. Do a pretend `emerge` command to get a list of what would be built. |
| # 2. Filter to only packages that will be installed to the board sysroot. |
| # 3. Filter to only packages that would be built from source and rewrite the |
| # line from Portage's full output to only $CATEGORY/$PACKAGE |
| # 4. Filter the list of packages to a heuristic set of packages known to have |
| # incorrectly specified dependencies. |
| # 5. Sort the output and remove any duplicate entries. |
| BASE_INSTALL_PKGS=( $( \ |
| sudo -E "${EMERGE_CMD[@]}" "${SIM_EMERGE_FLAGS[@]}" "${PACKAGES[@]}" | \ |
| grep -e 'to /build/' | \ |
| sed -n -E '/^\[ebuild /{s:^[^]]+\] +::;s: .*::;p}' | \ |
| grep -E '/(chromeos-config.*|coreboot-private-files.*|tast-build-deps)$' | \ |
| sort -u ) ) |
| |
| MOD_PKGS=() |
| if [[ "${#BASE_INSTALL_PKGS[@]}" -gt 0 ]]; then |
| info "Forced rebuild packages detected: ${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. |
| grep_cmd=( grep -v ) |
| for pkg in "${CHROME_PACKAGES[@]}"; do |
| grep_cmd+=( -e "${pkg}" ) |
| done |
| MOD_PKGS=( $(printf '%s\n' "${MOD_PKGS[@]}" | "${grep_cmd[@]}" || :) ) |
| 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. |
| grep_cmd=( grep -v ) |
| for pkg in "${CHROME_PACKAGES[@]}"; do |
| grep_cmd+=( -e "${pkg}" ) |
| done |
| RMOD_PKGS=( $(printf '%s\n' "${RMOD_PKGS[@]}" | "${grep_cmd[@]}" || :) ) |
| 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 |
| |
| # A list of critical system packages that should never be incidentally |
| # reinstalled as a side effect of build_packages. All packages in this list |
| # are special cased to prefer matching installed versions, overriding the |
| # typical logic of upgrading to the newest available version. |
| # |
| # This list can't include any package that gets installed to a board! |
| # Packages such as LLVM or binutils must not be in this list as the normal |
| # rebuild logic must still apply to them for board targets. |
| # |
| # TODO(crbug/1050752): Remove this list and the corresponding arguments |
| # to `emerge` below once we figure out how to exclude toolchain packages from |
| # being upgraded transitively via BDEPEND relations. |
| CRITICAL_SDK_PACKAGES=( |
| "dev-lang/rust" |
| "sys-libs/glibc" |
| "sys-devel/gcc" |
| ) |
| |
| 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" |
| "${goma_ctl}" restart |
| trap "'${goma_ctl}' stop" EXIT |
| fi |
| |
| sudo -E "${EMERGE_CMD[@]}" "${EMERGE_FLAGS[@]}" "${PACKAGES[@]}" \ |
| --useoldpkg-atoms="${CRITICAL_SDK_PACKAGES[*]}" \ |
| --rebuild-exclude="${CRITICAL_SDK_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" |