From cf77c696f7ca30786acaa5b5f4325b64236f5429 Mon Sep 17 00:00:00 2001 From: Hyung-Kyu Choi Date: Thu, 9 Feb 2017 15:28:35 +0900 Subject: [PATCH] [ARM/CI] new ARM CI using Docker 1. Enable ARM cross-build using Docker For arm, rootfs is prepared inaide Docker image which is used for official pipeline build. For armel, rootfs is constructed for Tizen. Release, Debug, Checked build is available. 2. Run unit test using Docker Signed-off-by: Hyung-Kyu Choi --- cross/armel/tizen/tizen-dotnet.ks | 44 ++++++ tests/scripts/arm32_ci_script.sh | 213 ++++++++++++++++++++++++------ tests/scripts/arm32_ci_test.sh | 124 +++++++++++++++++ 3 files changed, 342 insertions(+), 39 deletions(-) create mode 100644 cross/armel/tizen/tizen-dotnet.ks create mode 100755 tests/scripts/arm32_ci_test.sh diff --git a/cross/armel/tizen/tizen-dotnet.ks b/cross/armel/tizen/tizen-dotnet.ks new file mode 100644 index 000000000000..4fca3d1c0f7b --- /dev/null +++ b/cross/armel/tizen/tizen-dotnet.ks @@ -0,0 +1,44 @@ +lang en_US.UTF-8 +keyboard us +timezone --utc Asia/Seoul + +part / --fstype="ext4" --size=3500 --ondisk=mmcblk0 --label rootfs --fsoptions=defaults,noatime + +repo --name=mobile --baseurl=http://download.tizen.org/snapshots/tizen/mobile/latest/repos/arm-wayland/packages/ --ssl_verify=no +repo --name=base --baseurl=http://download.tizen.org/snapshots/tizen/base/latest/repos/arm/packages/ --ssl_verify=no + +%packages +tar +gzip + +sed +grep +gawk +perl + +binutils +findutils +util-linux +procps-ng +tzdata +ca-certificates + +### Core FX +libicu +libuuid +libunwind +iputils +zlib +krb5 +libcurl +libopenssl + +%end + +%post + +### Update /tmp privilege +chmod 777 /tmp +#################################### + +%end diff --git a/tests/scripts/arm32_ci_script.sh b/tests/scripts/arm32_ci_script.sh index e80e8cf7bd8f..bda27850a22f 100755 --- a/tests/scripts/arm32_ci_script.sh +++ b/tests/scripts/arm32_ci_script.sh @@ -27,9 +27,14 @@ function usage { echo ' /platform/rootfs-t30.ext4 should exist' echo ' --mountPath= : The desired path for mounting the emulator rootfs (without ending /)' echo ' This path is created if not already present' - echo ' --buildConfig= : The value of config should be either Debug or Release' + echo ' --buildConfig= : The value of config should be either Debug, Checked or Release' echo ' Any other value is not accepted' echo 'Optional Arguments:' + echo ' --mode= : docker or emulator (default)' + echo ' --arm : Build using hard ABI' + echo ' --armel : Build using softfp ABI (default)' + echo ' --linuxCodeName= : Code name for Linux: For arm, trusty (default) and xenial. For armel, tizen' + echo ' --skipRootFS : Skip building rootfs' echo ' --skipTests : Presenting this option skips testing the generated binaries' echo ' If this option is not presented, then tests are run by default' echo ' using the other test related options' @@ -148,7 +153,9 @@ function handle_exit { echo 'The script is exited. Cleaning environment..' - clean_env + if [ "$__ciMode" == "emulator" ]; then + clean_env + fi } trap handle_exit EXIT @@ -229,6 +236,64 @@ function cross_build_coreclr { fi } +#Cross builds coreclr using Docker +function cross_build_coreclr_with_docker { + __currentWorkingDirectory=`pwd` + + # Check build configuration and choose Docker image + __dockerEnvironmentVariables="" + if [ "$__buildArch" == "arm" ]; then + # TODO: For arm, we are going to embed RootFS inside Docker image. + case $__linuxCodeName in + trusty) + __dockerImage=" microsoft/dotnet-buildtools-prereqs:ubuntu1404_cross_prereqs_v3" + __skipRootFS=1 + __dockerEnvironmentVariables+=" -e ROOTFS_DIR=/crossrootfs/arm" + __runtimeOS="ubuntu.14.04" + ;; + xenial) + __dockerImage=" microsoft/dotnet-buildtools-prereqs:ubuntu1604_cross_prereqs_v3" + __skipRootFS=1 + __dockerEnvironmentVariables+=" -e ROOTFS_DIR=/crossrootfs/arm" + __runtimeOS="ubuntu.16.04" + ;; + *) + exit_with_error "ERROR: $__linuxCodeName is not a supported linux name for $__buildArch" false + ;; + esac + elif [ "$__buildArch" == "armel" ]; then + # For armel Tizen, we are going to construct RootFS on the fly. + case $__linuxCodeName in + tizen) + __dockerImage=" t2wish/dotnetcore:ubuntu1404_cross_prereqs_v3" + __runtimeOS="tizen.4.0.0" + ;; + *) + echo "ERROR: $__linuxCodeName is not a supported linux name for $__buildArch" + exit_with_error "ERROR: $__linuxCodeName is not a supported linux name for $__buildArch" false + ;; + esac + else + exit_with_error "ERROR: unknown buildArch $__buildArch" false + fi + __dockerCmd="sudo docker run ${__dockerEnvironmentVariables} --privileged -i --rm -v $__currentWorkingDirectory:/opt/code -w /opt/code $__dockerImage" + + if [ $__skipRootFS == 0 ]; then + # Build rootfs + __buildRootfsCmd="./cross/build-rootfs.sh $__buildArch $__linuxCodeName --skipunmount" + + (set +x; echo "Build RootFS for $__buildArch $__linuxCodeName") + $__dockerCmd $__buildRootfsCmd + sudo chown -R $(id -u -n) cross/rootfs + fi + + # Cross building coreclr with rootfs in Docker + (set +x; echo "Start cross build coreclr for $__buildArch $__linuxCodeName") + __buildCmd="./build.sh $__buildArch cross $__verboseFlag $__skipMscorlib $__buildConfig -rebuild" + $__dockerCmd $__buildCmd + sudo chown -R $(id -u -n) ./bin +} + #Copy the needed files to the emulator to run tests function copy_to_emulator { @@ -297,13 +362,52 @@ function run_tests { EOF } +function run_tests_using_docker { + __currentWorkingDirectory=`pwd` + + # Configure docker + __dockerEnvironmentVariables="" + if [ "$__buildArch" == "arm" ]; then + case $__linuxCodeName in + trusty) + __dockerImage=" microsoft/dotnet-buildtools-prereqs:ubuntu1404_cross_prereqs_v3" + __skipRootFS=1 + __dockerEnvironmentVariables=" -e ROOTFS_DIR=/crossrootfs/arm" + ;; + xenial) + __dockerImage=" microsoft/dotnet-buildtools-prereqs:ubuntu1604_cross_prereqs_v3" + __skipRootFS=1 + __dockerEnvironmentVariables=" -e ROOTFS_DIR=/crossrootfs/arm" + ;; + *) + exit_with_error "ERROR: $__linuxCodeName is not a supported linux name for $__buildArch" false + ;; + esac + elif [ "$__buildArch" == "armel" ]; then + case $__linuxCodeName in + tizen) + __dockerImage=" t2wish/dotnetcore:ubuntu1404_cross_prereqs_v3" + ;; + *) + exit_with_error "ERROR: $__linuxCodeName is not a supported linux name for $__buildArch" false + ;; + esac + else + exit_with_error "ERROR: unknown buildArch $__buildArch" false + fi + __dockerCmd="sudo docker run ${__dockerEnvironmentVariables} --privileged -i --rm -v $__currentWorkingDirectory:/opt/code -w /opt/code $__dockerImage" + __testCmd="./tests/scripts/arm32_ci_test.sh --abi=${__buildArch} --buildConfig=${__buildConfig}" + + $__dockerCmd $__testCmd +} + #Define script variables +__ciMode="emulator" __ARMEmulRootfs=/mnt/arm-emulator-rootfs __ARMEmulPath= __ARMRootfsMountPath= __buildConfig= -# TODO: Currently test is not working correctly for a month. This will be fixed with new arm CI soon. -__skipTests=1 +__skipTests=0 __skipMscorlib= __testRootDir= __mscorlibDir= @@ -313,6 +417,8 @@ __testDirFile= __verboseFlag= __buildOS="Linux" __buildArch="armel" +__linuxCodeName="tizen" +__skipRootFS=0 __buildDirName= __initialGitHead=`git rev-parse --verify HEAD` @@ -328,10 +434,13 @@ do ;; --buildConfig=*) __buildConfig="$(echo ${arg#*=} | awk '{print tolower($0)}')" - if [[ "$__buildConfig" != "debug" && "$__buildConfig" != "release" ]]; then - exit_with_error "--buildConfig can be only Debug or Release" true + if [[ "$__buildConfig" != "debug" && "$__buildConfig" != "release" && "$__buildConfig" != "checked" ]]; then + exit_with_error "--buildConfig can be Debug, Checked or Release" true fi ;; + --mode=*) + __ciMode=${arg#*=} + ;; --skipTests) __skipTests=1 ;; @@ -356,6 +465,19 @@ do --testDirFile=*) __testDirFile=${arg#*=} ;; + --arm) + __buildArch="arm" + ;; + --armel) + __buildArch="armel" + __linuxCodeName="tizen" + ;; + --linuxCodeName=*) + __linuxCodeName=${arg#*=} + ;; + --skipRootFS) + __skipRootFS=1 + ;; -h|--help) usage ;; @@ -373,26 +495,24 @@ if [[ $(git status -s) != "" ]]; then exit 1 fi -#Check if the compulsory arguments have been presented to the script and if the input paths exist -exit_if_empty "$__ARMEmulPath" "--emulatorPath is a mandatory argument, not provided" true -exit_if_empty "$__ARMRootfsMountPath" "--mountPath is a mandatory argument, not provided" true exit_if_empty "$__buildConfig" "--buildConfig is a mandatory argument, not provided" true -exit_if_path_absent "$__ARMEmulPath/platform/rootfs-t30.ext4" "Path specified in --emulatorPath does not have the rootfs" false +if [ "$__ciMode" == "emulator" ]; then + #Check if the compulsory arguments have been presented to the script and if the input paths exist + exit_if_empty "$__ARMEmulPath" "--emulatorPath is a mandatory argument, not provided" true + exit_if_empty "$__ARMRootfsMountPath" "--mountPath is a mandatory argument, not provided" true + exit_if_path_absent "$__ARMEmulPath/platform/rootfs-t30.ext4" "Path specified in --emulatorPath does not have the rootfs" false + # Test is not available in emulator mode. + __skipTests=1 +fi +__coreFxBinDir="./bin/CoreFxBinDir" # TODO-clenup: Just for testing.... #Check if the optional arguments are present in the case that testing is to be done if [ $__skipTests == 0 ]; then exit_if_empty "$__testRootDir" "Testing requested, but --testRootDir not provided" true exit_if_path_absent "$__testRootDir" "Path specified in --testRootDir does not exist" false - exit_if_empty "$__coreFxNativeBinDir" "Testing requested but --coreFxNativeBinDir not provided" true - exit_if_path_absent "$__coreFxNativeBinDir" "Path specified in --coreFxNativeBinDir does not exist" false - exit_if_empty "$__coreFxBinDir" "Testing requested, but --coreFxBinDir not provided" true - while IFS=';' read -ra coreFxBinDirectories; do - for currDir in "${coreFxBinDirectories[@]}"; do - exit_if_path_absent "$currDir" "Path specified in --coreFxBinDir, $currDir does not exist" false - done - done <<< "$__coreFxBinDir" + exit_if_path_absent "$__coreFxBinDir" "Path specified in --coreFxBinDir does not exist" false exit_if_empty "$__testDirFile" "Testing requested, but --testDirFile not provided" true exit_if_path_absent "$__testDirFile" "Path specified in --testDirFile does not exist" false @@ -409,6 +529,8 @@ fi #Change build configuration to the capitalized form to create build product paths correctly if [[ "$__buildConfig" == "release" ]]; then __buildConfig="Release" +elif [[ "$__buildConfig" == "checked" ]]; then + __buildConfig="Checked" else __buildConfig="Debug" fi @@ -434,37 +556,50 @@ set -e ## Begin cross build (set +x; echo "Git HEAD @ $__initialGitHead") -#Mount the emulator -(set +x; echo 'Mounting emulator...') -mount_emulator +if [ "$__ciMode" == "docker" ]; then + # Complete the cross build using Docker + (set +x; echo 'Building coreclr...') + cross_build_coreclr_with_docker +else + #Mount the emulator + (set +x; echo 'Mounting emulator...') + mount_emulator -#Clean the emulator -(set +x; echo 'Cleaning emulator...') -clean_emulator + #Clean the emulator + (set +x; echo 'Cleaning emulator...') + clean_emulator -#Complete the cross build -(set +x; echo 'Building coreclr...') -cross_build_coreclr + #Complete the cross build + (set +x; echo 'Building coreclr...') + cross_build_coreclr +fi #If tests are to be skipped end the script here, else continue if [ $__skipTests == 1 ]; then exit 0 fi -## Tests are going to be performed in an emulated environment - -#Copy the needed files to the emulator before entering the emulated environment -(set +x; echo 'Setting up emulator to run tests...') -copy_to_emulator - -#Enter the emulated mode and run the tests -(set +x; echo 'Running tests...') -run_tests +__unittestResult=0 +## Begin CoreCLR test +if [ "$__ciMode" == "docker" ]; then + run_tests_using_docker + __unittestResult=$? +else + ## Tests are going to be performed in an emulated environment + #Copy the needed files to the emulator before entering the emulated environment + (set +x; echo 'Setting up emulator to run tests...') + copy_to_emulator -#Clean the environment -(set +x; echo 'Cleaning environment...') -clean_env + #Enter the emulated mode and run the tests + (set +x; echo 'Running tests...') + run_tests + __unittestResult=$? + #Clean the environment + (set +x; echo 'Cleaning environment...') + clean_env +fi (set +x; echo 'Build and test complete') +exit $__unittestResult diff --git a/tests/scripts/arm32_ci_test.sh b/tests/scripts/arm32_ci_test.sh new file mode 100755 index 000000000000..33a951e32410 --- /dev/null +++ b/tests/scripts/arm32_ci_test.sh @@ -0,0 +1,124 @@ +#!/bin/bash + +set -x + +function usage { + echo 'ARM Test Script' + echo '$ ./tests/scripts/arm32_ci_test.sh' + echo ' --abi=arm' + echo ' --buildConfig=Release' + echo 'Required Arguments:' + echo ' --abi= : arm (default) or armel' + echo ' --buildConfig= : Release (default) Checked, or Debug' +} + +# Display error message and exit +function exit_with_error { + set +x + + local errorMessage="$1" + local printUsage=$2 + + echo "ERROR: $errorMessage" + if [ "$printUsage" == "true" ]; then + echo '' + usage + fi + exit 1 +} + +# Exit if the input path does not exist +function exit_if_path_absent { + local path="$1" + local errorMessage="$2" + local printUsage=$3 + + if [ ! -f "$path" -a ! -d "$path" ]; then + exit_with_error "$errorMessage" $printUsage + fi +} + +__abi="arm" +__buildConfig="Release" + +# Parse command line arguments +for arg in "$@" +do + case $arg in + --abi=*) + __abi=${arg#*=} + if [[ "$__abi" != "arm" && "$__abi" != "armel" ]]; then + exit_with_error "--abi can be either arm or armel" true + fi + ;; + --buildConfig=*) + __buildConfig=${arg#*=} + if [[ "$__buildConfig" != "Debug" && "$__buildConfig" != "Release" && "$__buildConfig" != "Checked" ]]; then + exit_with_error "--buildConfig can be Debug, Checked or Release" true + fi + ;; + -v|--verbose) + __verboseFlag="verbose" + ;; + -h|--help) + usage + exit 0 + ;; + *) + exit_with_error "$arg not a recognized argument" true + ;; + esac +done +__buildDirName="Linux.${__abi}.${__buildConfig}" + +CORECLR_DIR=/opt/code +ARM_CHROOT_HOME_DIR=/home/coreclr + +if [ -z "${ROOTFS_DIR}" ]; then + __ROOTFS_DIR=${CORECLR_DIR}/cross/rootfs/${__abi} +else + __ROOTFS_DIR=${ROOTFS_DIR} +fi + +if [ "$__abi" == "armel" ]; then + # TODO: Make use of a single Tizen rootfs for build and test + + # TODO-cleanup: the latest docker image already has mic installed. + # Prepare Tizen (armel) environment + #echo "deb http://download.tizen.org/tools/latest-release/Ubuntu_14.04 /" >> /etc/apt/sources.list + #apt-get update + #apt-get -y -qq --force-yes install mic + + pushd ${CORECLR_DIR}/cross/armel/tizen + mic --non-interactive create fs --pack-to=tizen.tar.gz tizen-dotnet.ks + if [ -d ${__ROOTFS_DIR} ]; then + mv ${__ROOTFS_DIR} ${__ROOTFS_DIR}_build + fi + mkdir -p ${__ROOTFS_DIR} + tar -zxf mic-output/tizen.tar.gz -C ${__ROOTFS_DIR} + apt-get update + apt-get -y -qq --force-yes install --reinstall qemu binfmt-support qemu-user-static + __qemuARM=$(which qemu-arm-static) + cp $__qemuARM ${CORECLR_DIR}/cross/rootfs/armel/usr/bin/ + cp $__qemuARM ${__ROOTFS_DIR}/usr/bin/ + popd +fi + +# Mount +mkdir -p ${__ROOTFS_DIR}${ARM_CHROOT_HOME_DIR} +mount -t proc /proc ${__ROOTFS_DIR}/proc +mount -o bind /dev ${__ROOTFS_DIR}/dev +mount -o bind /dev/pts ${__ROOTFS_DIR}/dev/pts +mount -o bind /sys ${__ROOTFS_DIR}/sys +mount -o bind ${CORECLR_DIR} ${__ROOTFS_DIR}${ARM_CHROOT_HOME_DIR} + +chroot ${__ROOTFS_DIR} /bin/bash -x <