| #!/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 |
| . "${SRC_ROOT}/platform/dev/toolchain_utils.sh" || exit 1 |
| |
| # Script must run inside the chroot |
| restart_in_chroot_if_needed "$@" |
| |
| assert_not_root_user |
| |
| # Developer-visible flags. |
| DEFINE_boolean configure $FLAGS_TRUE \ |
| "Update config files in <sysroot>/etc after installation." |
| DEFINE_boolean force $FLAGS_FALSE \ |
| "Install toolchain even if already up to date." |
| DEFINE_string toolchain "" \ |
| "Toolchain. For example: i686-pc-linux-gnu, armv7a-softfloat-linux-gnueabi" |
| DEFINE_string sysroot "" "The sysroot to install the toolchain for." |
| |
| |
| FLAGS_HELP="usage: $(basename $0) [flags] |
| |
| Installs cross toolchain libraries into a sysroot. This script is not |
| meant to be used by developers directly. Run at your own risk. |
| " |
| |
| show_help_if_requested "$@" |
| |
| # 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 |
| |
| # Get the version number of a toolchain package. |
| cross_get_version() { |
| local pkg=$1 |
| local toolchain=${2:-${FLAGS_toolchain}} |
| local cpv |
| if [[ "${CHOST}" != "${toolchain}" ]]; then |
| if [[ "${pkg}" == "gcc" ]]; then |
| # Users can install multiple versions of gcc at once, so we need to call |
| # gcc-config to find out which installed version is selected. |
| local path=$(CTARGET="${toolchain}" gcc-config -B || true) |
| cpv=$(portageq owners / "${path}" | sed -e '/^\t/d') |
| else |
| cpv=$(portageq match / "cross-${toolchain}/${pkg}" || true) |
| fi |
| else |
| if [[ "${pkg}" == glibc ]] ; then |
| cpv=$(portageq match / sys-libs/glibc || true) |
| elif [[ "${pkg}" == gcc ]] ; then |
| cpv=$(portageq match / sys-devel/gcc || true) |
| elif [[ "${pkg}" == go ]] ; then |
| cpv=$(portageq match / dev-lang/go || true) |
| else |
| die "Unknown pkg ${pkg}" |
| fi |
| fi |
| local cp=$(echo ${cpv} | sed -e 's/-r[0-9]*$//; s/-[^-]*$//') |
| local result="${cpv#$cp-}" |
| local count="$(echo $result | wc -w)" |
| if [ "${count}" -gt "1" ]; then |
| die "Multiple versions of ${pkg} installed" |
| fi |
| echo "${result}" |
| } |
| |
| # Get the version number of a toolchain package. |
| # Die if the package is not found. |
| cross_get_version_or_die() { |
| local pkg=$1 |
| local result=$(cross_get_version "$@") |
| local count="$(echo $result | wc -w)" |
| if [ "${count}" -lt "1" ]; then |
| die "Cannot find ${pkg}" |
| fi |
| echo "${result}" |
| } |
| |
| # Checks whether the libc version installed in the board |
| # matches the one installed by the toolchain. |
| board_needs_libc_update() { |
| local board_version=$(get_variable "${SYSROOT_CACHE}" "LIBC_VERSION") |
| local toolchain_version |
| # Keep `local` decl split from assignment so return code is checked. |
| toolchain_version=$(cross_get_version_or_die glibc) |
| if [[ "${board_version}" = "${toolchain_version}" ]]; then |
| return 1 |
| fi |
| return 0 |
| } |
| |
| install_toolchain_in_provided() { |
| local gcc_ver="$1" |
| local glibc_ver="$2" |
| local go_ver="$3" |
| # Tell portage that toolchain packages are already installed in the sysroot. |
| sudo mkdir -p "$BOARD_PROFILE" |
| sudo_clobber "$BOARD_PROFILE/package.provided" << EOF |
| sys-devel/gcc-$gcc_ver |
| sys-libs/glibc-$glibc_ver |
| EOF |
| if [[ -n ${go_ver} ]]; then |
| sudo_append "$BOARD_PROFILE/package.provided" << EOF |
| dev-lang/go-${go_ver} |
| EOF |
| fi |
| } |
| |
| # Install all of the stuff that depends on the toolchain versions |
| # into the board root. |
| install_toolchain_in_board() { |
| local cmds gcc_ver libc_ver go_ver |
| # Keep `local` decl split from assignments so return code is checked. |
| gcc_ver=$(cross_get_version_or_die gcc) |
| libc_ver=$(cross_get_version_or_die glibc) |
| go_ver=$(cross_get_version go) |
| if [[ -z ${gcc_ver} || -z ${libc_ver} ]]; then |
| die "Cannot find toolchain to install into board root" |
| fi |
| info "Installing the toolchain into the board root." |
| # Untar glibc to get most of the headers required to build. |
| |
| # Install libc libraries. |
| if [ "${CHOST}" != "$FLAGS_toolchain" ] ; then |
| local libc_atom="cross-${FLAGS_toolchain}/glibc-${libc_ver}" |
| local libc_path="${PKGDIR}/${libc_atom}.tbz2" |
| |
| cmds=() |
| if [[ ! -e ${libc_path} ]]; then |
| cmds+=( "emerge --nodeps -gf =${libc_atom}" ) |
| fi |
| cmds+=( |
| "tar jxpf '${libc_path}' -C '${BOARD_ROOT}' \ |
| './usr/${FLAGS_toolchain}' --strip-components=3" |
| "mkdir -p '${BOARD_ROOT}/usr/lib/debug'" |
| "tar jxpf '${libc_path}' -C '${BOARD_ROOT}/usr/lib/debug' \ |
| './usr/lib/debug/usr/${FLAGS_toolchain}' --strip-components=6 \ |
| || echo 'WARNING: libc debug info not copied.' >&2" |
| ) |
| sudo_multi "${cmds[@]}" |
| else |
| sudo emerge --oneshot --nodeps -k --root='${BOARD_ROOT}' \ |
| =sys-libs/glibc-${libc_ver} |
| fi |
| |
| if [[ ${FLAGS_configure} -eq ${FLAGS_TRUE} ]]; then |
| install_toolchain_in_provided "$gcc_ver" "$libc_ver" "$go_ver" |
| |
| set_variable "${SYSROOT_CACHE}" "LIBC_VERSION" "${libc_ver}" |
| fi |
| } |
| |
| set -u |
| |
| if [[ -z "${FLAGS_sysroot}" ]]; then |
| die "--sysroot required." |
| fi |
| |
| BOARD_ROOT="${FLAGS_sysroot}" |
| BOARD_ETC="${BOARD_ROOT}/etc" |
| BOARD_PROFILE="${BOARD_ETC}/portage/profile" |
| SYSROOT_CACHE="${BOARD_ROOT}/${SYSROOT_SETTINGS_FILE}" |
| |
| sysroot_toolchain="$(get_sysroot_config "${FLAGS_sysroot}" "CHOST")" |
| : ${FLAGS_toolchain:=${sysroot_toolchain}} |
| |
| if [ -z "${FLAGS_toolchain}" ]; then |
| die "No toolchain specified in the sysroot or on command line." |
| fi |
| |
| eval "$(portageq envvar -v CHOST PKGDIR)" |
| |
| if [[ ${FLAGS_force} -eq ${FLAGS_TRUE} ]] || \ |
| board_needs_libc_update; then |
| info "Updating libc in the board." |
| install_toolchain_in_board |
| else |
| info "Cross toolchain already up to date. Nothing to do." |
| fi |