1#!/usr/bin/env bash 2set -eo pipefail 3 4function extract() { 5 echo "Extracting ${1}..." 6 case $1 in 7 *.tar.bz2) tar xjf "$1" ;; 8 *.tar.xz) tar xJf "$1" ;; 9 *.tar.gz) tar xzf "$1" ;; 10 *) 11 >&2 echo "don't know how to extract '$1'..." 12 exit 1 13 esac 14} 15 16function unpack() { 17 mkdir -p "${ARCHIVE_DIR}" 18 cd "${ARCHIVE_DIR}" || exit 2 19 local -r URL=$1 20 local -r RELATIVE_DIR=$2 21 local -r DESTINATION="${ARCHIVE_DIR}/${RELATIVE_DIR}" 22 if [[ ! -d "${DESTINATION}" ]] ; then 23 echo "Downloading ${URL}..." 24 local -r ARCHIVE_NAME=$(basename "${URL}") 25 [[ -f "${ARCHIVE_NAME}" ]] || wget --no-verbose "${URL}" 26 extract "${ARCHIVE_NAME}" 27 rm -f "${ARCHIVE_NAME}" 28 fi 29} 30 31function install_qemu() { 32 if [[ "${QEMU_ARCH}" == "DISABLED" ]]; then 33 >&2 echo 'QEMU is disabled !' 34 return 0 35 fi 36 local -r QEMU_VERSION=${QEMU_VERSION:=7.1.0} 37 local -r QEMU_TARGET=${QEMU_ARCH}-linux-user 38 39 if echo "${QEMU_VERSION} ${QEMU_TARGET}" | cmp --silent "${QEMU_INSTALL}/.build" -; then 40 echo "qemu ${QEMU_VERSION} up to date!" 41 return 0 42 fi 43 44 echo "QEMU_VERSION: ${QEMU_VERSION}" 45 echo "QEMU_TARGET: ${QEMU_TARGET}" 46 47 rm -rf "${QEMU_INSTALL}" 48 49 # Checking for a tarball before downloading makes testing easier :-) 50 local -r QEMU_URL="http://wiki.qemu-project.org/download/qemu-${QEMU_VERSION}.tar.xz" 51 local -r QEMU_DIR="qemu-${QEMU_VERSION}" 52 unpack ${QEMU_URL} ${QEMU_DIR} 53 cd ${QEMU_DIR} || exit 2 54 55 # Qemu (meson based build) depends on: pkgconf, libglib2.0, python3, ninja 56 ./configure \ 57 --prefix="${QEMU_INSTALL}" \ 58 --target-list="${QEMU_TARGET}" \ 59 --audio-drv-list= \ 60 --disable-brlapi \ 61 --disable-curl \ 62 --disable-curses \ 63 --disable-docs \ 64 --disable-gcrypt \ 65 --disable-gnutls \ 66 --disable-gtk \ 67 --disable-libnfs \ 68 --disable-libssh \ 69 --disable-nettle \ 70 --disable-opengl \ 71 --disable-sdl \ 72 --disable-virglrenderer \ 73 --disable-vte 74 75 # wrapper on ninja 76 make -j8 77 make install 78 79 echo "$QEMU_VERSION $QEMU_TARGET" > "${QEMU_INSTALL}/.build" 80} 81 82function assert_defined(){ 83 if [[ -z "${!1}" ]]; then 84 >&2 echo "Variable '${1}' must be defined" 85 exit 1 86 fi 87} 88 89function clean_build() { 90 # Cleanup previous build 91 rm -rf "${BUILD_DIR}" 92 mkdir -p "${BUILD_DIR}" 93} 94 95function expand_linaro_config() { 96 #ref: https://releases.linaro.org/components/toolchain/binaries/ 97 local -r LINARO_VERSION=7.5-2019.12 98 local -r LINARO_ROOT_URL=https://releases.linaro.org/components/toolchain/binaries/${LINARO_VERSION} 99 100 local -r GCC_VERSION=7.5.0-2019.12 101 local -r GCC_URL=${LINARO_ROOT_URL}/${TARGET}/gcc-linaro-${GCC_VERSION}-x86_64_${TARGET}.tar.xz 102 local -r GCC_RELATIVE_DIR="gcc-linaro-${GCC_VERSION}-x86_64_${TARGET}" 103 unpack "${GCC_URL}" "${GCC_RELATIVE_DIR}" 104 105 local -r SYSROOT_VERSION=2.25-2019.12 106 local -r SYSROOT_URL=${LINARO_ROOT_URL}/${TARGET}/sysroot-glibc-linaro-${SYSROOT_VERSION}-${TARGET}.tar.xz 107 local -r SYSROOT_RELATIVE_DIR=sysroot-glibc-linaro-${SYSROOT_VERSION}-${TARGET} 108 unpack "${SYSROOT_URL}" "${SYSROOT_RELATIVE_DIR}" 109 110 local -r SYSROOT_DIR=${ARCHIVE_DIR}/${SYSROOT_RELATIVE_DIR} 111 local -r STAGING_DIR=${ARCHIVE_DIR}/${SYSROOT_RELATIVE_DIR}-stage 112 local -r GCC_DIR=${ARCHIVE_DIR}/${GCC_RELATIVE_DIR} 113 114 # Write a Toolchain file 115 # note: This is manadatory to use a file in order to have the CMake variable 116 # 'CMAKE_CROSSCOMPILING' set to TRUE. 117 # ref: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-linux 118 cat >"$TOOLCHAIN_FILE" <<EOL 119set(CMAKE_SYSTEM_NAME Linux) 120set(CMAKE_SYSTEM_PROCESSOR ${TARGET}) 121 122set(CMAKE_SYSROOT ${SYSROOT_DIR}) 123set(CMAKE_STAGING_PREFIX ${STAGING_DIR}) 124 125set(tools ${GCC_DIR}) 126set(CMAKE_C_COMPILER \${tools}/bin/${TARGET}-gcc) 127set(CMAKE_CXX_COMPILER \${tools}/bin/${TARGET}-g++) 128 129set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 130set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 131set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 132set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) 133EOL 134CMAKE_ADDITIONAL_ARGS+=( -DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN_FILE}" ) 135QEMU_ARGS+=( -L "${SYSROOT_DIR}" ) 136QEMU_ARGS+=( -E LD_LIBRARY_PATH=/lib ) 137} 138 139function expand_bootlin_config() { 140 # ref: https://toolchains.bootlin.com/ 141 local -r GCC_DIR=${ARCHIVE_DIR}/${GCC_RELATIVE_DIR} 142 143 case "${TARGET}" in 144 "aarch64") 145 local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/aarch64/tarballs/aarch64--glibc--stable-2021.11-1.tar.bz2" 146 local -r GCC_PREFIX="aarch64" 147 ;; 148 "aarch64be") 149 local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/aarch64be/tarballs/aarch64be--glibc--stable-2021.11-1.tar.bz2" 150 local -r GCC_PREFIX="aarch64_be" 151 ;; 152 "ppc64le") 153 local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc64le-power8/tarballs/powerpc64le-power8--glibc--stable-2021.11-1.tar.bz2" 154 local -r GCC_PREFIX="powerpc64le" 155 ;; 156 "ppc64") 157 local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc64-power8/tarballs/powerpc64-power8--glibc--stable-2021.11-1.tar.bz2" 158 local -r GCC_PREFIX="powerpc64" 159 ;; 160 "ppc") 161 #local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc-e500mc/tarballs/powerpc-e500mc--glibc--stable-2021.11-1.tar.bz2" 162 local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/powerpc-440fp/tarballs/powerpc-440fp--glibc--stable-2021.11-1.tar.bz2" 163 local -r GCC_PREFIX="powerpc" 164 ;; 165 "riscv32") 166 local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/riscv32-ilp32d/tarballs/riscv32-ilp32d--glibc--bleeding-edge-2022.08-1.tar.bz2" 167 local -r GCC_PREFIX="riscv32" 168 ;; 169 "riscv64") 170 local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/riscv64-lp64d/tarballs/riscv64-lp64d--glibc--stable-2022.08-1.tar.bz2" 171 local -r GCC_PREFIX="riscv64" 172 ;; 173 "s390x") 174 local -r TOOLCHAIN_URL="https://toolchains.bootlin.com/downloads/releases/toolchains/s390x-z13/tarballs/s390x-z13--glibc--stable-2022.08-1.tar.bz2" 175 local -r GCC_PREFIX="s390x" 176 ;; 177 *) 178 >&2 echo 'unknown power platform' 179 exit 1 ;; 180 esac 181 182 local -r TOOLCHAIN_RELATIVE_DIR="${TARGET}" 183 unpack "${TOOLCHAIN_URL}" "${TOOLCHAIN_RELATIVE_DIR}" 184 local -r EXTRACT_DIR="${ARCHIVE_DIR}/$(basename ${TOOLCHAIN_URL%.tar.bz2})" 185 186 local -r TOOLCHAIN_DIR=${ARCHIVE_DIR}/${TOOLCHAIN_RELATIVE_DIR} 187 if [[ -d "${EXTRACT_DIR}" ]]; then 188 mv "${EXTRACT_DIR}" "${TOOLCHAIN_DIR}" 189 fi 190 191 local -r SYSROOT_DIR="${TOOLCHAIN_DIR}/${GCC_PREFIX}-buildroot-linux-gnu/sysroot" 192 #local -r STAGING_DIR=${SYSROOT_DIR}-stage 193 194 # Write a Toolchain file 195 # note: This is manadatory to use a file in order to have the CMake variable 196 # 'CMAKE_CROSSCOMPILING' set to TRUE. 197 # ref: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-linux 198 cat >"${TOOLCHAIN_FILE}" <<EOL 199set(CMAKE_SYSTEM_NAME Linux) 200set(CMAKE_SYSTEM_PROCESSOR ${GCC_PREFIX}) 201 202set(CMAKE_SYSROOT ${SYSROOT_DIR}) 203#set(CMAKE_STAGING_PREFIX ${STAGING_DIR}) 204 205set(tools ${TOOLCHAIN_DIR}) 206 207set(CMAKE_C_COMPILER \${tools}/bin/${GCC_PREFIX}-linux-gcc) 208set(CMAKE_C_FLAGS "${POWER_FLAGS}") 209set(CMAKE_CXX_COMPILER \${tools}/bin/${GCC_PREFIX}-linux-g++) 210set(CMAKE_CXX_FLAGS "${POWER_FLAGS} -L${SYSROOT_DIR}/lib") 211 212set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_DIR}) 213set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 214set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 215set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 216set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) 217EOL 218 219CMAKE_ADDITIONAL_ARGS+=( -DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN_FILE}" ) 220QEMU_ARGS+=( -L "${SYSROOT_DIR}" ) 221QEMU_ARGS+=( -E LD_PRELOAD="${SYSROOT_DIR}/usr/lib/libstdc++.so.6:${SYSROOT_DIR}/lib/libgcc_s.so.1" ) 222} 223 224function expand_codescape_config() { 225 # https://www.mips.com/develop/tools/codescape-mips-sdk/mips-toolchain-configurations/ 226 # mips-mti: MIPS32R6 and MIPS64R6 227 # mips-img: MIPS32R2 and MIPS64R2 228 229 # ref: https://codescape.mips.com/components/toolchain/2020.06-01/downloads.html 230 local -r DATE=2020.06-01 231 local -r CODESCAPE_URL=https://codescape.mips.com/components/toolchain/${DATE}/Codescape.GNU.Tools.Package.${DATE}.for.MIPS.MTI.Linux.CentOS-6.x86_64.tar.gz 232 local -r GCC_RELATIVE_DIR="mips-mti-linux-gnu/${DATE}" 233 234 # ref: https://codescape.mips.com/components/toolchain/2019.02-04/downloads.html 235 #local -r DATE=2019.02-04 236 #local -r CODESCAPE_URL=https://codescape.mips.com/components/toolchain/${DATE}/Codescape.GNU.Tools.Package.${DATE}.for.MIPS.IMG.Linux.CentOS-6.x86_64.tar.gz 237 #local -r GCC_RELATIVE_DIR="mips-img-linux-gnu/${DATE}" 238 239 local -r GCC_URL=${CODESCAPE_URL} 240 unpack "${GCC_URL}" "${GCC_RELATIVE_DIR}" 241 242 local -r GCC_DIR=${ARCHIVE_DIR}/${GCC_RELATIVE_DIR} 243 local MIPS_FLAGS="" 244 local LIBC_DIR_SUFFIX="" 245 local FLAVOUR="" 246 case "${TARGET}" in 247 "mips32") 248 MIPS_FLAGS="-EB -mips32r6 -mabi=32" 249 FLAVOUR="mips-r6-hard" 250 #MIPS_FLAGS="-EB -mips32r2 -mabi=32" 251 #FLAVOUR="mips-r2-hard" 252 LIBC_DIR_SUFFIX="lib" 253 ;; 254 "mips32el") 255 MIPS_FLAGS="-EL -mips32r6 -mabi=32" 256 FLAVOUR="mipsel-r6-hard" 257 #MIPS_FLAGS="-EL -mips32r2 -mabi=32" 258 #FLAVOUR="mipsel-r2-hard" 259 LIBC_DIR_SUFFIX="lib" 260 ;; 261 "mips64") 262 MIPS_FLAGS="-EB -mips64r6 -mabi=64" 263 FLAVOUR="mips-r6-hard" 264 #MIPS_FLAGS="-EB -mips64r2 -mabi=64" 265 #FLAVOUR="mips-r2-hard" 266 LIBC_DIR_SUFFIX="lib64" 267 ;; 268 "mips64el") 269 MIPS_FLAGS="-EL -mips64r6 -mabi=64" 270 FLAVOUR="mipsel-r6-hard" 271 #MIPS_FLAGS="-EL -mips64r2 -mabi=64" 272 #FLAVOUR="mipsel-r2-hard" 273 LIBC_DIR_SUFFIX="lib64" 274 ;; 275 *) 276 >&2 echo 'unknown mips platform' 277 exit 1 ;; 278 esac 279 local -r SYSROOT_DIR=${GCC_DIR}/sysroot 280 local -r STAGING_DIR=${SYSROOT_DIR}-stage 281 282 # Write a Toolchain file 283 # note: This is manadatory to use a file in order to have the CMake variable 284 # 'CMAKE_CROSSCOMPILING' set to TRUE. 285 # ref: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-linux 286 cat >"${TOOLCHAIN_FILE}" <<EOL 287set(CMAKE_SYSTEM_NAME Linux) 288set(CMAKE_SYSTEM_PROCESSOR ${TARGET}) 289 290set(CMAKE_SYSROOT ${SYSROOT_DIR}) 291set(CMAKE_STAGING_PREFIX ${STAGING_DIR}) 292 293set(tools ${GCC_DIR}) 294 295# R6 296set(CMAKE_C_COMPILER \${tools}/bin/mips-mti-linux-gnu-gcc) 297set(CMAKE_C_FLAGS "${MIPS_FLAGS}") 298set(CMAKE_CXX_COMPILER \${tools}/bin/mips-mti-linux-gnu-g++) 299set(CMAKE_CXX_FLAGS "${MIPS_FLAGS} -L${SYSROOT_DIR}/usr/lib64") 300 301# R2 302#set(CMAKE_C_COMPILER \${tools}/bin/mips-img-linux-gnu-gcc) 303#set(CMAKE_C_FLAGS "${MIPS_FLAGS}") 304#set(CMAKE_CXX_COMPILER \${tools}/bin/mips-img-linux-gnu-g++) 305#set(CMAKE_CXX_FLAGS "${MIPS_FLAGS}") 306 307set(CMAKE_FIND_ROOT_PATH ${GCC_DIR}) 308set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 309set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 310set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 311set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) 312EOL 313 314CMAKE_ADDITIONAL_ARGS+=( -DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN_FILE}" ) 315QEMU_ARGS+=( -L "${SYSROOT_DIR}/${FLAVOUR}" ) 316local -r LIBC_DIR=${GCC_DIR}/mips-mti-linux-gnu/lib/${FLAVOUR}/${LIBC_DIR_SUFFIX} 317#local -r LIBC_DIR=${GCC_DIR}/mips-img-linux-gnu/lib/${FLAVOUR}/${LIBC_DIR_SUFFIX} 318QEMU_ARGS+=( -E LD_PRELOAD="${LIBC_DIR}/libstdc++.so.6:${LIBC_DIR}/libgcc_s.so.1" ) 319} 320 321function build() { 322 cd "${PROJECT_DIR}" || exit 2 323 set -x 324 clean_build 325 cmake -S. -B"${BUILD_DIR}" "${CMAKE_DEFAULT_ARGS[@]}" "${CMAKE_ADDITIONAL_ARGS[@]}" 326 cmake --build "${BUILD_DIR}" --target all -j8 -v 327 set +x 328} 329 330function run_test() { 331 assert_defined QEMU_ARCH 332 if [[ "${QEMU_ARCH}" == "DISABLED" ]]; then 333 >&2 echo "QEMU is disabled for ${TARGET}" 334 return 335 fi 336 install_qemu 337 RUN_CMD="${QEMU_INSTALL}/bin/qemu-${QEMU_ARCH} ${QEMU_ARGS[*]}" 338 339 cd "${BUILD_DIR}" || exit 2 340 declare -a TEST_BINARIES=() 341 TEST_BINARIES+=($(find "${BUILD_DIR}"/test -executable -type f)) 342 TEST_BINARIES+=($(find "${BUILD_DIR}" -maxdepth 1 -executable -type f)) 343 set -x 344 set -e 345 for test_binary in ${TEST_BINARIES[*]} ; do 346 ${RUN_CMD} "${test_binary}" 347 done 348 set +e 349 set +x 350} 351 352function usage() { 353 local -r NAME=$(basename "$0") 354 echo -e "$NAME - Build using a cross toolchain. 355 356SYNOPSIS 357\t$NAME [-h|--help] [toolchain|build|qemu|test|all] 358 359DESCRIPTION 360\tCross compile using a cross toolchain. 361 362\tYou MUST define the following variables before running this script: 363\t* TARGET: 364\t\tx86_64 365\t\taarch64 aarch64be (bootlin) 366\t\taarch64-linux-gnu aarch64_be-linux-gnu (linaro) 367\t\tarm-linux-gnueabihf armv8l-linux-gnueabihf arm-linux-gnueabi (linaro) 368\t\tarmeb-linux-gnueabihf armeb-linux-gnueabi (linaro) 369\t\tmips32 mips32el (codespace) 370\t\tmips64 mips64el (codespace) 371\t\tppc (bootlin) 372\t\tppc64 ppc64le (bootlin) 373\t\triscv32 riscv64 (bootlin) 374\t\ts390x (bootlin) 375 376OPTIONS 377\t-h --help: show this help text 378\ttoolchain: download, unpack toolchain and generate CMake toolchain file 379\tbuild: toolchain + build the project using the toolchain file (note: remove previous build dir) 380\tqemu: download, unpack and build qemu 381\ttest: qemu + run all executable using qemu (note: don't build !) 382\tall: build + test (default) 383 384EXAMPLES 385* Using export: 386export TARGET=aarch64-linux-gnu 387$0 388 389* One-liner: 390TARGET=aarch64-linux-gnu $0" 391} 392 393# Main 394function main() { 395 case ${1} in 396 -h | --help) 397 usage; exit ;; 398 esac 399 400 assert_defined TARGET 401 402 declare -r PROJECT_DIR="$(cd -P -- "$(dirname -- "$0")/.." && pwd -P)" 403 declare -r ARCHIVE_DIR="${PROJECT_DIR}/build_cross/archives" 404 declare -r BUILD_DIR="${PROJECT_DIR}/build_cross/${TARGET}" 405 declare -r TOOLCHAIN_FILE=${ARCHIVE_DIR}/toolchain_${TARGET}.cmake 406 407 echo "Target: '${TARGET}'" 408 409 echo "Project dir: '${PROJECT_DIR}'" 410 echo "Archive dir: '${ARCHIVE_DIR}'" 411 echo "Build dir: '${BUILD_DIR}'" 412 echo "toolchain file: '${TOOLCHAIN_FILE}'" 413 414 declare -a CMAKE_DEFAULT_ARGS=( -G ${CMAKE_GENERATOR:-"Ninja"} ) 415 declare -a CMAKE_ADDITIONAL_ARGS=() 416 417 declare -a QEMU_ARGS=() 418 case ${TARGET} in 419 x86_64) 420 declare -r QEMU_ARCH=x86_64 ;; 421 arm-linux-gnueabihf | armv8l-linux-gnueabihf | arm-linux-gnueabi) 422 expand_linaro_config 423 declare -r QEMU_ARCH=arm ;; 424 armeb-linux-gnueabihf | armeb-linux-gnueabi) 425 expand_linaro_config 426 declare -r QEMU_ARCH=DISABLED ;; 427 aarch64-linux-gnu) 428 expand_linaro_config 429 declare -r QEMU_ARCH=aarch64 ;; 430 aarch64_be-linux-gnu) 431 expand_linaro_config 432 declare -r QEMU_ARCH=aarch64_be ;; 433 aarch64) 434 expand_bootlin_config 435 declare -r QEMU_ARCH=aarch64 ;; 436 aarch64be) 437 expand_bootlin_config 438 declare -r QEMU_ARCH=aarch64_be ;; 439 mips32) 440 expand_codescape_config 441 declare -r QEMU_ARCH=mips ;; 442 mips32el) 443 expand_codescape_config 444 declare -r QEMU_ARCH=mipsel ;; 445 mips64) 446 expand_codescape_config 447 declare -r QEMU_ARCH=mips64 ;; 448 mips64el) 449 expand_codescape_config 450 declare -r QEMU_ARCH=mips64el ;; 451 ppc64le) 452 expand_bootlin_config 453 declare -r QEMU_ARCH=ppc64le ;; 454 ppc64) 455 expand_bootlin_config 456 declare -r QEMU_ARCH=ppc64 ;; 457 ppc) 458 expand_bootlin_config 459 declare -r QEMU_ARCH=ppc ;; 460 riscv32) 461 expand_bootlin_config 462 declare -r QEMU_ARCH=riscv32 ;; 463 riscv64) 464 expand_bootlin_config 465 declare -r QEMU_ARCH=riscv64 ;; 466 s390x) 467 expand_bootlin_config 468 declare -r QEMU_ARCH=s390x ;; 469 *) 470 >&2 echo "Unknown TARGET '${TARGET}'..." 471 exit 1 ;; 472 esac 473 declare -r QEMU_INSTALL=${ARCHIVE_DIR}/qemu-${QEMU_ARCH} 474 475 case ${1} in 476 toolchain) 477 exit ;; 478 build) 479 build ;; 480 qemu) 481 install_qemu ;; 482 test) 483 run_test ;; 484 *) 485 build 486 run_test ;; 487 esac 488} 489 490main "${1:-all}" 491