#!/bin/bash # # Copyright (C) 2017 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. if [[ ! -d art ]]; then echo "Script needs to be run at the root of the android tree" exit 1 fi ALL_CONFIGS=(linux-ia32 linux-x64 linux-armv8 linux-armv7 android-armv8 android-armv7) usage() { local config local golem_target (cat << EOF Usage: $(basename "${BASH_SOURCE[0]}") [--golem=] --machine-type=MACHINE_TYPE [--tarball[=.tar.gz]] Build minimal art binaries required to run golem benchmarks either locally or on the golem servers. Creates the \$MACHINE_TYPE binaries in your \$OUT_DIR, and if --tarball was specified, it also tars the results of the build together into your file. -------------------------------------------------------- Required Flags: --machine-type=MT Specify the machine type that will be built. Optional Flags": --golem= Builds with identical commands that Golem servers use. --tarball[=o.tgz] Tar/gz the results. File name defaults to .tar.gz -j Specify how many jobs to use for parallelism. --help Print this help listing. --showcommands Show commands as they are being executed. --simulate Print commands only, don't execute commands. EOF ) | sed -e 's/^[[:space:]][[:space:]]//g' >&2 # Strip leading whitespace from heredoc. echo >&2 "Available machine types:" for config in "${ALL_CONFIGS[@]}"; do echo >&2 " $config" done echo >&2 echo >&2 "Available Golem targets:" while IFS='' read -r golem_target; do echo >&2 " $golem_target" done < <("$(thisdir)/env" --list-targets) } # Check if $1 element is in array $2 contains_element() { local e for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done return 1 } # Display a command, but don't execute it, if --showcommands was set. show_command() { if [[ $showcommands == "showcommands" ]]; then echo "$@" fi } # Execute a command, displaying it if --showcommands was set. # If --simulate is used, command is not executed. execute() { show_command "$@" execute_noshow "$@" } # Execute a command unless --simulate was used. execute_noshow() { if [[ $simulate == "simulate" ]]; then return 0 fi local prog="$1" shift "$prog" "$@" } # Export environment variable, echoing it to screen. setenv() { local name="$1" local value="$2" export $name="$value" echo export $name="$value" } # Export environment variable, echoing $3 to screen ($3 is meant to be unevaluated). setenv_escape() { local name="$1" local value="$2" local escaped_value="$3" export $name="$value" echo export $name="$escaped_value" } log_usage_error() { echo >&2 "ERROR: " "$@" echo >&2 " See --help for the correct usage information." exit 1 } log_fatal() { echo >&2 "FATAL: " "$@" exit 2 } # Get the directory of this script. thisdir() { (\cd "$(dirname "${BASH_SOURCE[0]}")" && pwd ) } # Get the path to the top of the Android source tree. gettop() { if [[ "x$ANDROID_BUILD_TOP" != "x" ]]; then echo "$ANDROID_BUILD_TOP"; else echo "$(thisdir)/../../.." fi } # Get a build variable from the Android build system. get_build_var() { local varname="$1" # include the desired target product/build-variant # which won't be set in our env if neither we nor the user first executed # source build/envsetup.sh (e.g. if simulating from a fresh shell). local extras [[ -n $target_product ]] && extras+=" TARGET_PRODUCT=$target_product" [[ -n $target_build_variant ]] && extras+=" TARGET_BUILD_VARIANT=$target_build_variant" # call dumpvar from the build system. (\cd "$(gettop)"; env $extras build/soong/soong_ui.bash --dumpvar-mode $varname) } # Defaults from command-line. mode="" # blank or 'golem' if --golem was specified. golem_target="" # --golem=$golem_target config="" # --machine-type=$config j_arg="" showcommands="" simulate="" make_tarball="" tarball="" # Parse command line arguments while [[ "$1" != "" ]]; do case "$1" in --help) usage exit 1 ;; --golem=*) mode="golem" golem_target="${1##--golem=}" if [[ "x$golem_target" == x ]]; then log_usage_error "Missing --golem target type." fi shift ;; --machine-type=*) config="${1##--machine-type=}" if ! contains_element "$config" "${ALL_CONFIGS[@]}"; then log_usage_error "Invalid --machine-type value '$config'" fi shift ;; --tarball) tarball="" # reuse the machine type name. make_tarball="make_tarball" shift ;; --tarball=*) tarball="${1##--tarball=}" make_tarball="make_tarball" shift ;; -j*) j_arg="$1" shift ;; --showcommands) showcommands="showcommands" shift ;; --simulate) simulate="simulate" shift ;; *) log_usage_error "Unknown options $1" ;; esac done ################################### ################################### ################################### if [[ -z $config ]]; then log_usage_error "--machine-type option is required." fi # --tarball defaults to the --machine-type value with .tar.gz. tarball="${tarball:-$config.tar.gz}" target_product="$TARGET_PRODUCT" target_build_variant="$TARGET_BUILD_VARIANT" # If not using --golem, use whatever the user had lunch'd prior to this script. if [[ $mode == "golem" ]]; then # This section is intended solely to be executed by a golem build server. target_build_variant=eng case "$config" in *-armv7) target_product="arm_krait" ;; *-armv8) target_product="armv8" ;; *) target_product="sdk" ;; esac if [[ $target_product = arm* ]]; then # If using the regular manifest, e.g. 'master' # The lunch command for arm will assuredly fail because we don't have device/generic/art. # # Print a human-readable error message instead of trying to lunch and failing there. if ! [[ -d "$(gettop)/device/generic/art" ]]; then log_fatal "Missing device/generic/art directory. Perhaps try master-art repo manifest?\n" \ " Cannot build ARM targets (arm_krait, armv8) for Golem." >&2 fi # We could try to keep on simulating but it seems brittle because we won't have the proper # build variables to output the right strings. fi # Get this particular target's environment variables (e.g. ART read barrier on/off). source "$(thisdir)"/env "$golem_target" || exit 1 lunch_target="$target_product-$target_build_variant" execute 'source' build/envsetup.sh # Build generic targets (as opposed to something specific like aosp_angler-eng). execute lunch "$lunch_target" # Golem uses master-art repository which is missing a lot of other libraries. setenv SOONG_ALLOW_MISSING_DEPENDENCIES true # Let the build system know we're not aiming to do a full platform build. if [ ! -d frameworks/base ]; then setenv TARGET_BUILD_UNBUNDLED true fi # Golem may be missing tools such as javac from its path. setenv_escape PATH "/usr/lib/jvm/java-8-openjdk-amd64/bin/:$PATH" '/usr/lib/jvm/java-8-openjdk-amd64/bin/:$PATH' else # Look up the default variables from the build system if they weren't set already. [[ -z $target_product ]] && target_product="$(get_build_var TARGET_PRODUCT)" [[ -z $target_build_variant ]] && target_build_variant="$(get_build_var TARGET_BUILD_VARIANT)" fi # Defaults for all machine types. make_target="build-art-target-golem" out_dir="out/x86_64" root_dir_var="PRODUCT_OUT" strip_symbols=false bit64_suffix="" tar_directories=(system data/art-test) # Per-machine type overrides if [[ $config == linux-arm* ]]; then setenv ART_TARGET_LINUX true fi case "$config" in linux-ia32|linux-x64) root_dir_var="HOST_OUT" # Android strips target builds automatically, but not host builds. strip_symbols=true make_target="build-art-host-golem" if [[ $config == linux-ia32 ]]; then out_dir="out/x86" setenv HOST_PREFER_32_BIT true else bit64_suffix="64" fi tar_directories=(bin framework usr lib${bit64_suffix}) ;; *-armv8) bit64_suffix="64" ;; *-armv7) ;; *) log_fatal "Unsupported machine-type '$config'" esac # Golem benchmark run commands expect a certain $OUT_DIR to be set, # so specify it here. # # Note: It is questionable if we want to customize this since users # could alternatively probably use their own build directly (and forgo this script). setenv OUT_DIR "$out_dir" root_dir="$(get_build_var "$root_dir_var")" if [[ $mode == "golem" ]]; then # For golem-style running only. # Sets the DT_INTERP to this path in every .so we can run the # non-system version of dalvikvm with our own copies of the dependencies (e.g. our own libc++). if [[ $config == android-* ]]; then # TODO: the linker can be relative to the binaries # (which is what we do for linux-armv8 and linux-armv7) golem_run_path="/data/local/tmp/runner/" else golem_run_path="" fi # Only do this for target builds. Host doesn't need this. if [[ $config == *-arm* ]]; then setenv CUSTOM_TARGET_LINKER "${golem_run_path}${root_dir}/system/bin/linker${bit64_suffix}" fi fi # # Main command execution below here. # (everything prior to this just sets up environment variables, # and maybe calls lunch). # execute build/soong/soong_ui.bash --make-mode "${j_arg}" "${make_target}" if $strip_symbols; then # Further reduce size by stripping symbols. execute_noshow strip $root_dir/bin/* || true show_command strip $root_dir/bin/'*' '|| true' execute_noshow strip $root_dir/lib${bit64_suffix}/'*' show_command strip $root_dir/lib${bit64_suffix}/'*' fi if [[ "$make_tarball" == "make_tarball" ]]; then # Create a tarball which is required for the golem build resource. # (In particular, each golem benchmark's run commands depend on a list of resource files # in order to have all the files it needs to actually execute, # and this tarball would satisfy that particular target+machine-type's requirements). dirs_rooted=() for tar_dir in "${tar_directories[@]}"; do dirs_rooted+=("$root_dir/$tar_dir") done execute tar -czf "${tarball}" --exclude ".git" --exclude ".gitignore" "${dirs_rooted[@]}" tar_result=$? if [[ $tar_result -ne 0 ]]; then [[ -f $tarball ]] && rm $tarball fi show_command '[[ $? -ne 0 ]] && rm' "$tarball" fi