ARM-CI: Add CI checks for Linux ARM Emulator
authorPrajwal A N <an.prajwal@samsung.com>
Mon, 27 Jun 2016 03:55:00 +0000 (12:55 +0900)
committerPrajwal A N <an.prajwal@samsung.com>
Thu, 7 Jul 2016 04:37:17 +0000 (13:37 +0900)
Some changes to the native part of corefx breaks builds
for the Linux ARM Emulator. Thus adding CI checks for
native part of corefx using cross build based on the
emulator rootfs.

Signed-off-by: Prajwal A N <an.prajwal@samsung.com>
Commit migrated from https://github.com/dotnet/corefx/commit/b5e214ef8c63a16da807115e3c4643b38df819a2

src/libraries/netci.groovy
src/libraries/scripts/arm32_ci_script.sh [new file with mode: 0755]

index 9edae28..fed47b0 100644 (file)
@@ -21,7 +21,8 @@ def osGroupMap = ['Ubuntu14.04':'Linux',
                   'Windows_NT':'Windows_NT',
                   'CentOS7.1': 'Linux',
                   'OpenSUSE13.2': 'Linux',
-                  'RHEL7.2': 'Linux']
+                  'RHEL7.2': 'Linux',
+                  'LinuxARMEmulator': 'Linux']
 
 // Map of os -> nuget runtime
 def targetNugetRuntimeMap = ['OSX' : 'osx.10.10-x64',
@@ -349,4 +350,49 @@ def osShortName = ['Windows 10': 'win10',
     }
 }
 
+// **************************
+// Define Linux ARM Emulator testing. This creates a per PR job which
+// cross builds native binaries for the Emulator rootfs.
+// NOTE: To add Ubuntu-ARM cross build jobs to this code, add the Ubuntu OS to the
+// OS array, branch the steps to be performed by Ubuntu and the Linux ARM emulator
+// based on the OS being handled, and handle the triggers accordingly
+// (the machine affinity of the new job remains the same)
+// **************************
+[true].each { isPR ->
+    ['Debug', 'Release'].each { configurationGroup ->
+        ['LinuxARMEmulator'].each { os ->
+            def osGroup = osGroupMap[os]
+            def newJobName = "${os.toLowerCase()}_cross_${configurationGroup.toLowerCase()}"
+            def arch = "arm-softfp"
+
+           // Setup variables to hold emulator folder path and the rootfs mount path
+           def armemul_path = '/opt/linux-arm-emulator'
+           def armrootfs_mountpath = '/opt/linux-arm-emulator-root'
+
+            def newJob = job(Utilities.getFullJobName(project, newJobName, isPR)) {
+                steps {
+                    // Call the arm32_ci_script.sh script to perform the cross build of native corefx
+                    shell("./scripts/arm32_ci_script.sh --emulatorPath=${armemul_path} --mountPath=${armrootfs_mountpath} --buildConfig=${configurationGroup.toLowerCase()} --verbose")
+                }
+            }
+
+            // The cross build jobs run on Ubuntu. The arm-cross-latest version
+            // contains the packages needed for cross building corefx
+            Utilities.setMachineAffinity(newJob, 'Ubuntu14.04', 'arm-cross-latest')
+
+            // Set up standard options.
+            Utilities.standardJobSetup(newJob, project, isPR, "*/${branch}")
+
+            // Add archival for the built binaries
+            def archiveContents = "bin/Linux.${arch}.${configurationGroup}/**"
+            Utilities.addArchival(newJob, archiveContents)
+
+            // Set up triggers
+            if (os == 'LinuxARMEmulator') {
+                Utilities.addGithubPRTriggerForBranch(newJob, branch, "Innerloop Linux ARM Emulator ${configurationGroup} Cross Build", "(?i).*test\\W+Innerloop\\W+Linux\\W+ARM\\W+Emulator\\W+${configurationGroup}\\W+Cross\\W+Build.*")
+            }
+        }
+    }
+}
+
 JobReport.Report.generateJobReport(out)
diff --git a/src/libraries/scripts/arm32_ci_script.sh b/src/libraries/scripts/arm32_ci_script.sh
new file mode 100755 (executable)
index 0000000..0a92c3d
--- /dev/null
@@ -0,0 +1,224 @@
+#!/bin/bash
+
+#Usage message
+function usage {
+    echo 'ARM Emulator Cross Build Script'
+    echo 'This script cross builds corefx source'
+    echo ''
+    echo 'Typical usage:'
+    echo '    corefx source is at ~/cfx'
+    echo '$ cd ~/cfx'
+    echo '$ ./scripts/arm32_ci_script.sh'
+    echo '    --emulatorPath=/opt/linux-arm-emulator'
+    echo '    --mountPath=/opt/linux-arm-emulator-root'
+    echo '    --buildConfig=Release'
+    echo '    --verbose'
+    echo ''
+    echo 'Required Arguments:'
+    echo '    --emulatorPath=<path>              : Path of the emulator folder (without ending /)'
+    echo '                                         <path>/platform/rootfs-t30.ext4 should exist'
+    echo '    --mountPath=<path>                 : The desired path for mounting the emulator rootfs (without ending /)'
+    echo '                                         This path is created if not already present'
+    echo '    --buildConfig=<config>             : The value of config should be either Debug or Release'
+    echo '                                         Any other value is not accepted'
+    echo 'Optional Arguments:'
+    echo '    -v --verbose                       : Build made verbose'
+    echo '    -h --help                          : Prints this usage message and exits'
+    echo ''
+    echo 'Any other argument triggers an error and this usage message is displayed'
+    exit 1
+}
+
+#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 input string is empty
+function exit_if_empty {
+    local inputString="$1"
+    local errorMessage="$2"
+    local printUsage=$3
+
+    if [ -z "$inputString" ]; then
+        exit_with_error "$errorMessage" $printUsage
+    fi
+}
+
+#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
+}
+
+#Check if the git changes were reverted completely
+function check_git_head {
+    local currentGitHead=`git rev-parse --verify HEAD`
+
+    if [[ "$__initialGitHead" != "$currentGitHead" ]]; then
+        exit_with_error "Some changes made to the code history were not completely reverted. Intial Git HEAD: $__initialGitHead, current Git HEAD: $currentGitHead" false
+    fi
+}
+
+function unmount_rootfs {
+    local rootfsFolder="$1"
+
+    if grep -qs "$rootfsFolder" /proc/mounts; then
+        sudo umount "$rootfsFolder"
+    fi
+}
+
+#Unmount the emulator file systems
+function unmount_emulator {
+    (set +x; echo 'Unmounting emulator...')
+
+    #Unmount all the mounted emulator file systems
+    unmount_rootfs "$__ARMRootfsMountPath/proc"
+    unmount_rootfs "$__ARMRootfsMountPath/dev/pts"
+    unmount_rootfs "$__ARMRootfsMountPath/dev"
+    unmount_rootfs "$__ARMRootfsMountPath/run/shm"
+    unmount_rootfs "$__ARMRootfsMountPath/sys"
+    unmount_rootfs "$__ARMRootfsMountPath"
+}
+
+#Clean the changes made to the environment by the script
+function clean_env {
+    #Unmount the emulator
+    unmount_emulator
+
+    #Check for revert of git changes
+    check_git_head
+}
+
+#Trap Ctrl-C and handle it
+function handle_ctrl_c {
+    set +x
+
+    echo 'ERROR: Ctrl-C handled. Script aborted before complete execution.'
+
+    clean_env
+
+    exit 1
+}
+trap handle_ctrl_c INT
+
+#Mount emulator to the target mount path
+function mount_emulator {
+    #Check if the mount path exists and create if neccessary
+    if [ ! -d "$__ARMRootfsMountPath" ]; then
+        sudo mkdir "$__ARMRootfsMountPath"
+    fi
+
+    #Unmount the emulator if already mounted at the mount path and mount again
+    unmount_emulator
+
+    sudo mount "$__ARMEmulPath"/platform/rootfs-t30.ext4 "$__ARMRootfsMountPath"
+    sudo mount -t proc /proc    "$__ARMRootfsMountPath"/proc
+    sudo mount -o bind /dev/    "$__ARMRootfsMountPath"/dev
+    sudo mount -o bind /dev/pts "$__ARMRootfsMountPath"/dev/pts
+    sudo mount -t tmpfs shm     "$__ARMRootfsMountPath"/run/shm
+    sudo mount -o bind /sys     "$__ARMRootfsMountPath"/sys
+}
+
+#Cross builds corefx
+function cross_build_corefx {
+#Export the needed environment variables
+    (set +x; echo 'Exporting LINUX_ARM_* environment variable')
+    source "$__ARMRootfsMountPath"/dotnet/setenv/setenv_incpath.sh "$__ARMRootfsMountPath"
+
+    #Apply the changes needed to build for the emulator rootfs
+    (set +x; echo 'Applying cross build patch to suit Linux ARM emulator rootfs')
+    git am < "$__ARMRootfsMountPath"/dotnet/setenv/corefx_cross.patch
+
+    #Cross building for emulator rootfs
+    ROOTFS_DIR="$__ARMRootfsMountPath" CPLUS_INCLUDE_PATH=$LINUX_ARM_INCPATH CXXFLAGS=$LINUX_ARM_CXXFLAGS ./build.sh $__buildArch clean cross native $__verboseFlag $__buildConfig
+
+    #Reset the code to the upstream version
+    (set +x; echo 'Rewinding HEAD to master code')
+    git reset --hard HEAD^
+}
+
+#Define script variables
+__ARMEmulPath=
+__ARMRootfsMountPath=
+__buildConfig=
+__verboseFlag=
+__buildArch="arm-softfp"
+__initialGitHead=`git rev-parse --verify HEAD`
+
+#Parse command line arguments
+for arg in "$@"
+do
+    case $arg in
+    --emulatorPath=*)
+        __ARMEmulPath=${arg#*=}
+        ;;
+    --mountPath=*)
+        __ARMRootfsMountPath=${arg#*=}
+        ;;
+    --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
+        fi
+        ;;
+    -v|--verbose)
+        __verboseFlag="verbose"
+        ;;
+    -h|--help)
+        usage
+        ;;
+    *)
+        exit_with_error "$arg not a recognized argument" true
+        ;;
+    esac
+done
+
+#Check if there are any uncommited changes in the source directory as git adds and removes patches
+if [[ $(git status -s) != "" ]]; then
+   echo 'ERROR: There are some uncommited changes. To avoid losing these changes commit them and try again.'
+   echo ''
+   git status
+   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
+
+set -x
+set -e
+
+## Begin cross build
+(set +x; echo "Git HEAD @ $__initialGitHead")
+
+#Mount the emulator
+(set +x; echo 'Mounting emulator...')
+mount_emulator
+
+#Complete the cross build
+(set +x; echo 'Building corefx...')
+cross_build_corefx
+
+#Clean the environment
+(set +x; echo 'Cleaning environment...')
+clean_env
+
+(set +x; echo 'Build complete')