#!/bin/bash # Note: not intended to be invoked directly, see rebuild.sh. # # Rebuilds Crosvm and its dependencies from a clean state. : ${TOOLS_DIR:="$(pwd)/tools"} # Stable is usually too old for crosvm, but make sure you bump this # up as far as you can each time this script is touched.. RUST_TOOLCHAIN_VER=1.65.0 setup_env() { : ${SOURCE_DIR:="$(pwd)/source"} : ${WORKING_DIR:="$(pwd)/working"} : ${CUSTOM_MANIFEST:=""} ARCH="$(uname -m)" : ${OUTPUT_DIR:="$(pwd)/${ARCH}-linux-gnu"} OUTPUT_BIN_DIR="${OUTPUT_DIR}/bin" OUTPUT_ETC_DIR="${OUTPUT_DIR}/etc" OUTPUT_SECCOMP_DIR="${OUTPUT_ETC_DIR}/seccomp" export PATH="${PATH}:${TOOLS_DIR}:${HOME}/.local/bin" export PKG_CONFIG_PATH="${WORKING_DIR}/usr/lib/pkgconfig" } set -e set -x fatal_echo() { echo "$@" exit 1 } prepare_cargo() { echo Setting up cargo... cd rm -rf .cargo # Sometimes curl hangs. When it does, retry retry curl -L \ --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup-init chmod +x rustup-init ./rustup-init -y --no-modify-path --default-toolchain ${RUST_TOOLCHAIN_VER} source $HOME/.cargo/env if [[ -n "$1" ]]; then rustup target add "$1" fi rm -f rustup-init if [[ -n "$1" ]]; then cat >>~/.cargo/config < "${TOOLS_DIR}/repo" chmod a+x "${TOOLS_DIR}/repo" # Gfxstream needs a new-ish version of CMake mkdir -p "${TOOLS_DIR}/cmake" cd "${TOOLS_DIR}/cmake" curl -O -L https://cmake.org/files/v3.22/cmake-3.22.1-linux-$(uname -m).sh chmod +x cmake-3.22.1-linux-$(uname -m).sh sudo ./cmake-3.22.1-linux-$(uname -m).sh --skip-license --exclude-subdir --prefix=/usr/local cmake --version # Meson getting started guide mentions that the distro version is frequently # outdated and recommends installing via pip. pip3 install --no-warn-script-location meson # Tools for building gfxstream pip3 install absl-py pip3 install urlfetch case "$(uname -m)" in aarch64) prepare_cargo ;; x86_64) # Cross-compilation is x86_64 specific sudo apt install -y crossbuild-essential-arm64 prepare_cargo aarch64-unknown-linux-gnu ;; esac } retry() { for i in $(seq 5); do "$@" && return 0 sleep 1 done return 1 } fetch_source() { echo "Fetching source..." mkdir -p "${SOURCE_DIR}" cd "${SOURCE_DIR}" if ! git config user.name; then git config --global user.name "AOSP Crosvm Builder" git config --global user.email "nobody@android.com" git config --global color.ui false fi if [[ -z "${CUSTOM_MANIFEST}" ]]; then # Building Crosvm currently depends using Chromium's directory scheme for subproject # directories ('third_party' vs 'external'). fatal_echo "CUSTOM_MANIFEST must be provided. You most likely want to provide a full path to" \ "a copy of device/google/cuttlefish_vmm/manifest.xml." fi cp ${CUSTOM_MANIFEST} manifest.xml repo init --depth=1 -q -u https://android.googlesource.com/platform/manifest -m $PWD/manifest.xml repo sync } prepare_source() { if [ "$(ls -A $SOURCE_DIR)" ]; then echo "${SOURCE_DIR} is non empty. Run this from an empty directory if you wish to fetch the source." 1>&2 exit 2 fi fetch_source } resync_source() { echo "Deleting source directory..." rm -rf "${SOURCE_DIR}/.*" rm -rf "${SOURCE_DIR}/*" fetch_source } # $1 = installed library filename debuglink() { objcopy --only-keep-debug "${OUTPUT_BIN_DIR}/$1" "${OUTPUT_BIN_DIR}/$1.debug" strip --strip-debug "${OUTPUT_BIN_DIR}/$1" cd "${OUTPUT_BIN_DIR}" objcopy --add-gnu-debuglink="$1.debug" "$1" cd - } compile_libdrm() { cd "${SOURCE_DIR}/external/libdrm" # Ensure pkg-config file supplies rpath to dependent libraries grep "install_rpath" meson.build || \ sed -i "s|install : true,|install : true, install_rpath : '\$ORIGIN',|" meson.build meson build \ --libdir="${WORKING_DIR}/usr/lib" \ --prefix="${WORKING_DIR}/usr" \ -Damdgpu=false \ -Dfreedreno=false \ -Dintel=false \ -Dlibkms=false \ -Dnouveau=false \ -Dradeon=false \ -Dvc4=false \ -Dvmwgfx=false cd build ninja install cp -a "${WORKING_DIR}"/usr/lib/libdrm.so* "${OUTPUT_BIN_DIR}" debuglink libdrm.so.2.4.0 } compile_minijail() { echo "Compiling Minijail..." cd "${SOURCE_DIR}/platform/minijail" if ! grep '^# cuttlefish_vmm-rebuild-mark' Makefile; then # Link minijail-sys rust crate dynamically to minijail sed -i '/BUILD_STATIC_LIBS/d' rust/minijail-sys/build.rs sed -i 's,static=minijail.pic,dylib=minijail,' rust/minijail-sys/build.rs # Use Android prebuilt C files instead of generating them sed -i 's,\(.*\.gen\.c: \),DISABLED_\1,' Makefile cat >>Makefile <>lib.rs < "${OUTPUT_DIR}/cargo_version.txt" rustup show > "${OUTPUT_DIR}/rustup_show.txt" } compile_crosvm_seccomp() { echo "Processing Crosvm Seccomp..." cd "${SOURCE_DIR}/platform/crosvm" case ${ARCH} in x86_64) subdir="${ARCH}" ;; amd64) subdir="x86_64" ;; arm64) subdir="aarch64" ;; aarch64) subdir="${ARCH}" ;; *) echo "${ARCH} is not supported" exit 15 esac inlined_policy_list="\ jail/seccomp/$subdir/common_device.policy \ jail/seccomp/$subdir/gpu_common.policy \ jail/seccomp/$subdir/serial.policy \ jail/seccomp/$subdir/net.policy \ jail/seccomp/$subdir/block.policy \ jail/seccomp/$subdir/vvu.policy \ jail/seccomp/$subdir/vhost_user.policy \ jail/seccomp/$subdir/vhost_vsock.policy" for policy_file in "jail/seccomp/$subdir/"*.policy; do [[ "$inlined_policy_list" = *"$policy_file"* ]] && continue jail/seccomp/policy-inliner.sh $inlined_policy_list <"$policy_file" | \ grep -ve "^@frequency" \ >"${OUTPUT_SECCOMP_DIR}"/$(basename "$policy_file") done } compile() { echo "Compiling..." mkdir -p \ "${WORKING_DIR}" \ "${OUTPUT_DIR}" \ "${OUTPUT_BIN_DIR}" \ "${OUTPUT_ETC_DIR}" \ "${OUTPUT_SECCOMP_DIR}" if [[ $BUILD_CROSVM -eq 1 ]]; then compile_libdrm compile_minijail compile_minigbm compile_epoxy compile_virglrenderer compile_libffi # wayland depends on it compile_wayland fi if [[ $BUILD_GFXSTREAM -eq 1 ]]; then compile_gfxstream fi compile_crosvm compile_crosvm_seccomp if [[ $BUILD_SWIFTSHADER -eq 1 ]]; then compile_swiftshader fi dpkg-query -W > "${OUTPUT_DIR}/builder-packages.txt" echo "Results in ${OUTPUT_DIR}" } aarch64_retry() { BUILD_CROSVM=1 BUILD_GFXSTREAM=1 BUILD_SWIFTSHADER=1 compile } aarch64_build() { rm -rf "${WORKING_DIR}/*" aarch64_retry } x86_64_retry() { MINIGBM_DRV="I915 RADEON VC4" BUILD_CROSVM=1 BUILD_GFXSTREAM=1 BUILD_SWIFTSHADER=1 compile } x86_64_build() { rm -rf "${WORKING_DIR}/*" x86_64_retry } if [[ $# -lt 1 ]]; then echo Choosing default config set setup_env prepare_source x86_64_build fi echo Steps: "$@" for i in "$@"; do echo $i case "$i" in ARCH=*) ARCH="${i/ARCH=/}" ;; CUSTOM_MANIFEST=*) CUSTOM_MANIFEST="${i/CUSTOM_MANIFEST=/}" ;; aarch64_build) $i ;; aarch64_retry) $i ;; setup_env) $i ;; install_packages) $i ;; fetch_source) $i ;; resync_source) $i ;; prepare_source) $i ;; x86_64_build) $i ;; x86_64_retry) $i ;; *) echo $i unknown 1>&2 echo usage: $0 'install_packages|prepare_source|resync_source|fetch_source|$(uname -m)_build|$(uname -m)_retry' 1>&2 exit 2 ;; esac done