From 884924e7de72e7bf97721657238a386f63188d02 Mon Sep 17 00:00:00 2001
From: Basil Fierz <basil.fierz@hotmail.com>
Date: Thu, 20 Apr 2023 21:45:24 +0200
Subject: [PATCH] Run AARCH64 tests using qemu instead of a native runner

---
 azure-pipelines.yml            | 277 ++++++++++++++++-----------------
 ci/aarch64-gcc-toolchain.cmake |  45 ++++++
 ci/azure-pipeline-generic.yml  |  17 +-
 3 files changed, 198 insertions(+), 141 deletions(-)
 create mode 100644 ci/aarch64-gcc-toolchain.cmake

diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 4c1cfb7c..ba1ad677 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -1,142 +1,141 @@
-# Azure test pipeline
-# Triggers build tests for Windows, Linux and MacOS for various configuarations
-
 trigger:
-- master
+  - master
 
 jobs:
-- job: Linux
-  strategy:
-    matrix:
-      Debug_SSE2:
-        buildConfig: 'Debug'
-        configVectorization: 'SSE 2'
-        configCodeCoverage: 'on'
-        configGraphicsD3D12: 'off'
-        configGraphicsOpenGL: 'on'
-        configGraphicsEGL: 'on'
-      Debug_AVX:
-        buildConfig: 'Debug'
-        configVectorization: 'AVX'
-        configCodeCoverage: 'off'
-        configGraphicsD3D12: 'off'
-        configGraphicsOpenGL: 'on'
-        configGraphicsEGL: 'on'
-      Release_AVX:
-        buildConfig: 'Release'
-        configVectorization: 'AVX'
-        configCodeCoverage: 'off'
-        configGraphicsD3D12: 'off'
-        configGraphicsOpenGL: 'on'
-        configGraphicsEGL: 'on'
-      Release_AVX2:
-        buildConfig: 'Release'
-        configVectorization: 'AVX 2'
-        configCodeCoverage: 'off'
-        configGraphicsD3D12: 'off'
-        configGraphicsOpenGL: 'on'
-        configGraphicsEGL: 'on'
-  pool:
-    vmImage: 'ubuntu-20.04'
-  steps:
-  - template: ci/azure-pipeline-generic.yml
-- job: Linux_ARM
-  strategy:
-    matrix:
-      Debug_NEON:
-        buildTargetArch: 'arm'
-        buildConfig: 'Debug'
-        configVectorization: 'NEON'
-        configCodeCoverage: 'off'
-        configGraphicsD3D12: 'off'
-        configGraphicsOpenGL: 'off'
-        configGraphicsEGL: 'off'
-      Release_NEON:
-        buildTargetArch: 'arm'
-        buildConfig: 'Release'
-        configVectorization: 'NEON'
-        configCodeCoverage: 'off'
-        configGraphicsD3D12: 'off'
-        configGraphicsOpenGL: 'off'
-        configGraphicsEGL: 'off'
-  pool:
-    vmImage: 'ubuntu-20.04'
-  steps:
-  - template: ci/azure-pipeline-generic.yml
-- job: Linux_ARM64
-  strategy:
-    matrix:
-      Debug_NEON:
-        buildConfig: 'Debug'
-        configVectorization: 'NEON'
-        configCodeCoverage: 'off'
-        configGraphicsD3D12: 'off'
-        configGraphicsOpenGL: 'off'
-        configGraphicsEGL: 'off'
-      Release_NEON:
-        buildConfig: 'Release'
-        configVectorization: 'NEON'
-        configCodeCoverage: 'off'
-        configGraphicsD3D12: 'off'
-        configGraphicsOpenGL: 'off'
-        configGraphicsEGL: 'off'
-  pool:
-    name: 'Linux ARM64'
-  steps:
-  - template: ci/azure-pipeline-generic.yml
-- job: MacOS
-  strategy:
-    matrix:
-      Debug_SSE2:
-        buildConfig: 'Debug'
-        configVectorization: 'SSE 2'
-        configCodeCoverage: 'off'
-        configGraphicsD3D12: 'off'
-        configGraphicsOpenGL: 'off'
-        configGraphicsEGL: 'off'
-      Release_SSE2:
-        buildConfig: 'Release'
-        configVectorization: 'SSE 2'
-        configCodeCoverage: 'off'
-        configGraphicsD3D12: 'off'
-        configGraphicsOpenGL: 'off'
-        configGraphicsEGL: 'off'
-  pool:
-    vmImage: 'macos-latest'
-  steps:
-  - template: ci/azure-pipeline-generic.yml
-- job: Windows
-  strategy:
-    matrix:
-      Debug_SSE2:
-        buildConfig: 'Debug'
-        configVectorization: 'SSE 2'
-        configCodeCoverage: 'on'
-        configGraphicsD3D12: 'on'
-        configGraphicsOpenGL: 'on'
-        configGraphicsEGL: 'off'
-      Debug_AVX:
-        buildConfig: 'Debug'
-        configVectorization: 'AVX'
-        configCodeCoverage: 'off'
-        configGraphicsD3D12: 'on'
-        configGraphicsOpenGL: 'on'
-        configGraphicsEGL: 'off'
-      Release_AVX:
-        buildConfig: 'Release'
-        configVectorization: 'AVX'
-        configCodeCoverage: 'off'
-        configGraphicsD3D12: 'on'
-        configGraphicsOpenGL: 'on'
-        configGraphicsEGL: 'off'
-      Release_AVX2:
-        buildConfig: 'Release'
-        configVectorization: 'AVX 2'
-        configCodeCoverage: 'off'
-        configGraphicsD3D12: 'on'
-        configGraphicsOpenGL: 'on'
-        configGraphicsEGL: 'off'
-  pool:
-    vmImage: 'windows-2019'
-  steps:
-  - template: ci/azure-pipeline-generic.yml
+  - job: Linux
+    strategy:
+      matrix:
+        Debug_SSE2:
+          buildConfig: 'Debug'
+          configVectorization: 'SSE 2'
+          configCodeCoverage: 'on'
+          configGraphicsD3D12: 'off'
+          configGraphicsOpenGL: 'on'
+          configGraphicsEGL: 'on'
+        Debug_AVX:
+          buildConfig: 'Debug'
+          configVectorization: 'AVX'
+          configCodeCoverage: 'off'
+          configGraphicsD3D12: 'off'
+          configGraphicsOpenGL: 'on'
+          configGraphicsEGL: 'on'
+        Release_AVX:
+          buildConfig: 'Release'
+          configVectorization: 'AVX'
+          configCodeCoverage: 'off'
+          configGraphicsD3D12: 'off'
+          configGraphicsOpenGL: 'on'
+          configGraphicsEGL: 'on'
+        Release_AVX2:
+          buildConfig: 'Release'
+          configVectorization: 'AVX 2'
+          configCodeCoverage: 'off'
+          configGraphicsD3D12: 'off'
+          configGraphicsOpenGL: 'on'
+          configGraphicsEGL: 'on'
+    pool:
+      vmImage: 'ubuntu-20.04'
+    steps:
+      - template: ci/azure-pipeline-generic.yml
+  - job: Linux_ARM
+    strategy:
+      matrix:
+        Debug_NEON:
+          buildTargetArch: 'arm'
+          buildConfig: 'Debug'
+          configVectorization: 'NEON'
+          configCodeCoverage: 'off'
+          configGraphicsD3D12: 'off'
+          configGraphicsOpenGL: 'off'
+          configGraphicsEGL: 'off'
+        Release_NEON:
+          buildTargetArch: 'arm'
+          buildConfig: 'Release'
+          configVectorization: 'NEON'
+          configCodeCoverage: 'off'
+          configGraphicsD3D12: 'off'
+          configGraphicsOpenGL: 'off'
+          configGraphicsEGL: 'off'
+    pool:
+      vmImage: 'ubuntu-20.04'
+    steps:
+      - template: ci/azure-pipeline-generic.yml
+  - job: Linux_ARM64
+    strategy:
+      matrix:
+        Debug_NEON:
+          buildTargetArch: 'aarch64'
+          buildConfig: 'Debug'
+          configVectorization: 'NEON'
+          configCodeCoverage: 'off'
+          configGraphicsD3D12: 'off'
+          configGraphicsOpenGL: 'off'
+          configGraphicsEGL: 'off'
+        Release_NEON:
+          buildTargetArch: 'aarch64'
+          buildConfig: 'Release'
+          configVectorization: 'NEON'
+          configCodeCoverage: 'off'
+          configGraphicsD3D12: 'off'
+          configGraphicsOpenGL: 'off'
+          configGraphicsEGL: 'off'
+    pool:
+      vmImage: 'ubuntu-20.04'
+    steps:
+      - template: ci/azure-pipeline-generic.yml
+  - job: MacOS
+    strategy:
+      matrix:
+        Debug_SSE2:
+          buildConfig: 'Debug'
+          configVectorization: 'SSE 2'
+          configCodeCoverage: 'off'
+          configGraphicsD3D12: 'off'
+          configGraphicsOpenGL: 'off'
+          configGraphicsEGL: 'off'
+        Release_SSE2:
+          buildConfig: 'Release'
+          configVectorization: 'SSE 2'
+          configCodeCoverage: 'off'
+          configGraphicsD3D12: 'off'
+          configGraphicsOpenGL: 'off'
+          configGraphicsEGL: 'off'
+    pool:
+      vmImage: 'macos-latest'
+    steps:
+      - template: ci/azure-pipeline-generic.yml
+  - job: Windows
+    strategy:
+      matrix:
+        Debug_SSE2:
+          buildConfig: 'Debug'
+          configVectorization: 'SSE 2'
+          configCodeCoverage: 'on'
+          configGraphicsD3D12: 'on'
+          configGraphicsOpenGL: 'on'
+          configGraphicsEGL: 'off'
+        Debug_AVX:
+          buildConfig: 'Debug'
+          configVectorization: 'AVX'
+          configCodeCoverage: 'off'
+          configGraphicsD3D12: 'on'
+          configGraphicsOpenGL: 'on'
+          configGraphicsEGL: 'off'
+        Release_AVX:
+          buildConfig: 'Release'
+          configVectorization: 'AVX'
+          configCodeCoverage: 'off'
+          configGraphicsD3D12: 'on'
+          configGraphicsOpenGL: 'on'
+          configGraphicsEGL: 'off'
+        Release_AVX2:
+          buildConfig: 'Release'
+          configVectorization: 'AVX 2'
+          configCodeCoverage: 'off'
+          configGraphicsD3D12: 'on'
+          configGraphicsOpenGL: 'on'
+          configGraphicsEGL: 'off'
+    pool:
+      vmImage: 'windows-2019'
+    steps:
+      - template: ci/azure-pipeline-generic.yml
diff --git a/ci/aarch64-gcc-toolchain.cmake b/ci/aarch64-gcc-toolchain.cmake
new file mode 100644
index 00000000..b0988349
--- /dev/null
+++ b/ci/aarch64-gcc-toolchain.cmake
@@ -0,0 +1,45 @@
+# Source: https://github.com/vpetrigo/arm-cmake-toolchains
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_PROCESSOR aarch64)
+
+if(MINGW OR CYGWIN OR WIN32)
+    set(UTIL_SEARCH_CMD where)
+elseif(UNIX OR APPLE)
+    set(UTIL_SEARCH_CMD which)
+endif()
+
+set(TOOLCHAIN_TRIPLE aarch64-linux-gnu)
+set(TOOLCHAIN_PREFIX ${TOOLCHAIN_TRIPLE}-)
+
+execute_process(
+    COMMAND ${UTIL_SEARCH_CMD} ${TOOLCHAIN_PREFIX}gcc
+    OUTPUT_VARIABLE BINUTILS_PATH
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+get_filename_component(ARM_TOOLCHAIN_DIR ${BINUTILS_PATH} DIRECTORY)
+
+# Without that flag CMake is not able to pass test compilation check
+if(${CMAKE_VERSION} VERSION_EQUAL "3.6.0" OR ${CMAKE_VERSION} VERSION_GREATER "3.6")
+    set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+else()
+    set(CMAKE_EXE_LINKER_FLAGS_INIT "--specs=nosys.specs")
+endif()
+
+set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc)
+set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
+set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++)
+
+set(CMAKE_OBJCOPY ${ARM_TOOLCHAIN_DIR}/${TOOLCHAIN_PREFIX}objcopy CACHE INTERNAL "objcopy tool")
+set(CMAKE_SIZE_UTIL ${ARM_TOOLCHAIN_DIR}/${TOOLCHAIN_PREFIX}size CACHE INTERNAL "size tool")
+
+# Theoretically, sysroot limits the search of libraries to the installation location of the cross-compilation SDK.
+# For some reason SYSROOT is applied twice on Ubuntu, thus we ignore SYSROOT
+# set(CMAKE_SYSROOT ${ARM_TOOLCHAIN_DIR}/../${TOOLCHAIN_TRIPLE})
+set(CMAKE_SYSROOT /)
+set(CMAKE_FIND_ROOT_PATH ${BINUTILS_PATH})
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+# Configure the emulator
+set(CMAKE_CROSSCOMPILING_EMULATOR qemu-aarch64 -L ${ARM_TOOLCHAIN_DIR}/../${TOOLCHAIN_TRIPLE})
diff --git a/ci/azure-pipeline-generic.yml b/ci/azure-pipeline-generic.yml
index 1af1aa6a..679702c5 100644
--- a/ci/azure-pipeline-generic.yml
+++ b/ci/azure-pipeline-generic.yml
@@ -14,8 +14,15 @@ steps:
         # Setup: https://gist.github.com/luk6xff/9f8d2520530a823944355e59343eadc1
         sudo apt-get update
         sudo apt-get install qemu-user
-        sudo apt-get install gcc-arm-linux-gnueabi binutils-arm-linux-gnueabi
-        sudo apt-get install g++-arm-linux-gnueabihf libstdc++-10-dev-armhf-cross libc6-armhf-cross
+        sudo apt-get install gcc-arm-linux-gnueabi libc6-armhf-cross binutils-arm-linux-gnueabi
+        sudo apt-get install g++-arm-linux-gnueabihf libstdc++-10-dev-armhf-cross
+      }
+      if ('$(buildTargetArch)' -eq 'aarch64') {
+        # Setup: https://gist.github.com/luk6xff/9f8d2520530a823944355e59343eadc1
+        sudo apt-get update
+        sudo apt-get install qemu-user
+        sudo apt-get install gcc-aarch64-linux-gnu libc6-dev-arm64-cross binutils-aarch64-linux-gnu
+        sudo apt-get install g++-aarch64-linux-gnu libstdc++-10-dev-arm64-cross
       }
 
       if ('$(configCodeCoverage)' -eq 'on') {
@@ -80,6 +87,12 @@ steps:
       cmakeArgs: -DCMAKE_TOOLCHAIN_FILE=../ci/arm-gcc-toolchain.cmake -DCMAKE_BUILD_TYPE=$(buildConfig) -DVCL_CODE_COVERAGE:BOOL=$(configCodeCoverage) -DVCL_D3D12_SUPPORT=$(configGraphicsD3D12) -DVCL_OPENGL_SUPPORT=$(configGraphicsOpenGL) -DVCL_BUILD_BENCHMARKS:BOOL=off -DVCL_BUILD_TESTS:BOOL=on -DVCL_BUILD_TOOLS:BOOL=off -DVCL_BUILD_EXAMPLES:BOOL=off -DVCL_VECTORIZE:STRING="$(configVectorization)" ..
     condition: eq(variables['buildTargetArch'], 'arm')
 
+  - task: CMake@1
+    inputs:
+      workingDirectory: 'build'
+      cmakeArgs: -DCMAKE_TOOLCHAIN_FILE=../ci/aarch64-gcc-toolchain.cmake -DCMAKE_BUILD_TYPE=$(buildConfig) -DVCL_CODE_COVERAGE:BOOL=$(configCodeCoverage) -DVCL_D3D12_SUPPORT=$(configGraphicsD3D12) -DVCL_OPENGL_SUPPORT=$(configGraphicsOpenGL) -DVCL_BUILD_BENCHMARKS:BOOL=off -DVCL_BUILD_TESTS:BOOL=on -DVCL_BUILD_TOOLS:BOOL=off -DVCL_BUILD_EXAMPLES:BOOL=off -DVCL_VECTORIZE:STRING="$(configVectorization)" ..
+    condition: eq(variables['buildTargetArch'], 'aarch64')
+
   - pwsh: |
       # MacOS requires a specific SDK root for C++
       if ($IsMacOS) {