#!/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_string board "$DEFAULT_BOARD" \ "The name of the board to set up." DEFINE_string board_root "" \ "Path of the board root to install into. Defaults to /build/." DEFINE_boolean configure $FLAGS_TRUE \ "Update config files in /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" FLAGS_HELP="usage: $(basename $0) [flags] Installs cross toolchain libraries into a board_root. 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) 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" elif [ "$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() { if [[ ! -e "${BOARD_SETUP}" ]]; then return 0 fi local board_version=$(. "${BOARD_SETUP}"; echo "${LIBC_VERSION}") local toolchain_version=$(cross_get_version glibc) if [[ "${board_version}" = "${toolchain_version}" ]]; then return 1 fi return 0 } install_toolchain_in_provided() { local gcc_ver="$1" local glibc_ver="$2" # Tell portage that toolchain packages are already installed in the sysroot. sudo_clobber "$BOARD_PROFILE/package.provided" << EOF sys-devel/gcc-$gcc_ver sys-libs/glibc-$glibc_ver EOF } # Install all of the stuff that depends on the toolchain versions # into the board root. install_toolchain_in_board() { local cmds local gcc_ver=$(cross_get_version gcc) local libc_ver=$(cross_get_version glibc) if [[ -z ${gcc_ver} || -z ${libc_ver} ]]; then die "Cannot find toolchain to install into board root" fi echo "Installing the toolchain into the board root." # Untar glibc to get most of the headers required to build. local libc_tar="glibc-${libc_ver}.tbz2" # Install libc libraries. if [ "${CHOST}" != "$FLAGS_toolchain" ] ; then local libc_path="${PKGDIR}/cross-${FLAGS_toolchain}/${libc_tar}" 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 \ || warn 'libc debug info not copied.'" ) # TODO(asharif): Remove this hack after a while. local board_gcc_dir="${BOARD_ROOT}/usr/lib/gcc" if [[ -L "${board_gcc_dir}" ]] ; then cmd+=("rm -f '${board_gcc_dir}'") fi sudo_multi "${cmds[@]}" copy_gcc_libs "${BOARD_ROOT}" "cross-$FLAGS_toolchain/gcc-$gcc_ver" else cmds=( "mkdir -p '${BOARD_ROOT}'{/usr,}/lib64 '${BOARD_ROOT}/usr/lib/debug'" "ln -sfT '${BOARD_ROOT}/usr/lib64' '${BOARD_ROOT}/usr/lib'" "ln -sfT '${BOARD_ROOT}/lib64' '${BOARD_ROOT}/lib'" "emerge --oneshot --nodeps -k --root='${BOARD_ROOT}' \ =sys-libs/glibc-${libc_ver}" ) sudo_multi "${cmds[@]}" fi # Some header files are needed also for rpcbind (NFS support) # TODO: Figure out a better way of doing this too? cmds=( "cp -a /usr/include/rpcsvc/mount.h '${BOARD_ROOT}/usr/include/rpcsvc'" "cp -a /usr/include/rpcsvc/rquota.h '${BOARD_ROOT}/usr/include/rpcsvc'" "cp -a /usr/include/rpcsvc/nfs_prot.h '${BOARD_ROOT}/usr/include/rpcsvc'" "cp -a /usr/include/rpcsvc/yppasswd.h '${BOARD_ROOT}/usr/include/rpcsvc'" ) sudo_multi "${cmds[@]}" if [[ ${FLAGS_configure} -eq ${FLAGS_TRUE} ]]; then install_toolchain_in_provided "$gcc_ver" "$libc_ver" # Configure new libc version in make.conf.board_setup. sudo sed -i -e "/^LIBC_VERSION=/d" "$BOARD_SETUP" echo "LIBC_VERSION=\"$libc_ver\"" | sudo_append "$BOARD_SETUP" fi } set -u if [ -z "$FLAGS_board" ] ; then die "--board required." fi get_board_and_variant $FLAGS_board "" BOARD_ROOT="${FLAGS_board_root:-/build/${BOARD_VARIANT}}" BOARD_ETC="${BOARD_ROOT}/etc" BOARD_SETUP="${BOARD_ETC}/make.conf.board_setup" BOARD_PROFILE="${BOARD_ETC}/portage/profile" all_toolchains=( $(get_all_board_toolchains "${BOARD}") ) : ${FLAGS_toolchain:=${all_toolchains[0]}} if [ -z "${FLAGS_toolchain}" ]; then die "No toolchain specified in board overlay 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