diff options
-rw-r--r-- | Documentation/building/cross-building.md | 28 | ||||
-rwxr-xr-x | cross/build-rootfs.sh | 50 | ||||
-rw-r--r-- | cross/toolchain.cmake | 59 | ||||
-rw-r--r-- | cross/tryrun.cmake | 26 |
4 files changed, 117 insertions, 46 deletions
diff --git a/Documentation/building/cross-building.md b/Documentation/building/cross-building.md index 5a4060c910..d0047f90af 100644 --- a/Documentation/building/cross-building.md +++ b/Documentation/building/cross-building.md @@ -16,13 +16,13 @@ Build using "-arm" as the architecture. For example: C:\coreclr> build.cmd -arm -debug -Cross Compilation for ARM on Linux -================================== +Cross Compilation for ARM, ARM64 or x86 on Linux +================================================ Through cross compilation, on Linux it is possible to build CoreCLR for arm or arm64. -Requirements ------------- +Requirements for targetting Debian based distros +------------------------------------------------ You need a Debian based host and the following packages needs to be installed: @@ -37,14 +37,30 @@ and conversely for arm64: ben@ubuntu ~/git/coreclr/ $ sudo apt-get install binutils-aarch64-linux-gnu +Requirements for targetting ARM or ARM64 Alpine Linux +----------------------------------------------------- + +You can use any Linux distro as a host. The qemu, qemu-user-static and binfmt-support packages need to be installed (the names may be different for some distros). + +In addition, to cross compile CoreCLR, the binutils for Alpine need to be built from the https://github.com/richfelker/musl-cross-make repo, since they are not available as packages. + +To build them, use the following steps: +* Clone the repo +* Create a new config.mak file in the root directory of the repo and add the following lines into it: + * `TARGET = armv6-alpine-linux-musleabihf` for ARM or `TARGET = aarch64-alpine-linux-musl` for ARM64 + * `OUTPUT = /usr` + * `BINUTILS_CONFIG=--enable-gold=yes` +* Run `make` with current directory set to the root of the repo +* Run `sudo make install` + Generating the rootfs --------------------- The `cross\build-rootfs.sh` script can be used to download the files needed for cross compilation. It will generate an rootfs as this is what CoreCLR targets. Usage: ./cross/build-rootfs.sh [BuildArch] [LinuxCodeName] [lldbx.y] [--skipunmount] BuildArch can be: arm(default), armel, arm64, x86 - LinuxCodeName - optional, Code name for Linux, can be: trusty(default), vivid, wily, xenial. If BuildArch is armel, LinuxCodeName is jessie(default) or tizen. - lldbx.y - optional, LLDB version, can be: lldb3.6(default), lldb3.8 + LinuxCodeName - optional, Code name for Linux, can be: trusty(default), vivid, wily, xenial or alpine. If BuildArch is armel, LinuxCodeName is jessie(default) or tizen. + lldbx.y - optional, LLDB version, can be: lldb3.6(default), lldb3.8. This is ignored when building rootfs for Alpine Linux. The `build-rootfs.sh` script must be run as root as it has to make some symlinks to the system, it will by default generate the rootfs in `cross\rootfs\<BuildArch>` however this can be changed by setting the `ROOTFS_DIR` environment variable. diff --git a/cross/build-rootfs.sh b/cross/build-rootfs.sh index 1f42c75578..ec6af484fa 100755 --- a/cross/build-rootfs.sh +++ b/cross/build-rootfs.sh @@ -4,8 +4,8 @@ usage() { echo "Usage: $0 [BuildArch] [LinuxCodeName] [lldbx.y] [--skipunmount]" echo "BuildArch can be: arm(default), armel, arm64, x86" - echo "LinuxCodeName - optional, Code name for Linux, can be: trusty(default), vivid, wily, xenial, zesty. If BuildArch is armel, LinuxCodeName is jessie(default) or tizen." - echo "lldbx.y - optional, LLDB version, can be: lldb3.6(default), lldb3.8, lldb3.9, lldb4.0, no-lldb" + echo "LinuxCodeName - optional, Code name for Linux, can be: trusty(default), vivid, wily, xenial, zesty, alpine. If BuildArch is armel, LinuxCodeName is jessie(default) or tizen." + echo "lldbx.y - optional, LLDB version, can be: lldb3.6(default), lldb3.8, lldb3.9, lldb4.0, no-lldb. Ignored for alpine" echo "--skipunmount - optional, will skip the unmount of rootfs folder." exit 1 } @@ -22,14 +22,24 @@ __SkipUnmount=0 # base development support __UbuntuPackages="build-essential" +__AlpinePackages="alpine-base" +__AlpinePackages+=" build-base" +__AlpinePackages+=" linux-headers" +__AlpinePackages+=" lldb-dev" +__AlpinePackages+=" llvm-dev" + # symlinks fixer __UbuntuPackages+=" symlinks" # CoreCLR and CoreFX dependencies -__UbuntuPackages+=" gettext" -__UbuntuPackages+=" libunwind8-dev" -__UbuntuPackages+=" liblttng-ust-dev" __UbuntuPackages+=" libicu-dev" +__UbuntuPackages+=" liblttng-ust-dev" +__UbuntuPackages+=" libunwind8-dev" + +__AlpinePackages+=" gettext-dev" +__AlpinePackages+=" icu-dev" +__AlpinePackages+=" libunwind-dev" +__AlpinePackages+=" lttng-ust-dev" # CoreFX dependencies __UbuntuPackages+=" libcurl4-openssl-dev" @@ -37,6 +47,11 @@ __UbuntuPackages+=" libkrb5-dev" __UbuntuPackages+=" libssl-dev" __UbuntuPackages+=" zlib1g-dev" +__AlpinePackages+=" curl-dev" +__AlpinePackages+=" krb5-dev" +__AlpinePackages+=" openssl-dev" +__AlpinePackages+=" zlib-dev" + __UnprocessedBuildArgs= for i in "$@" ; do lowerI="$(echo $i | awk '{print tolower($0)}')" @@ -48,10 +63,14 @@ for i in "$@" ; do arm) __BuildArch=arm __UbuntuArch=armhf + __AlpineArch=armhf + __QEMUArch=arm ;; arm64) __BuildArch=arm64 __UbuntuArch=arm64 + __AlpineArch=aarch64 + __QEMUArch=aarch64 ;; armel) __BuildArch=armel @@ -113,6 +132,10 @@ for i in "$@" ; do __UbuntuRepo= __Tizen=tizen ;; + alpine) + __LinuxCodeName=alpine + __UbuntuRepo= + ;; --skipunmount) __SkipUnmount=1 ;; @@ -140,7 +163,22 @@ if [ -d "$__RootfsDir" ]; then rm -rf $__RootfsDir fi -if [[ -n $__LinuxCodeName ]]; then +if [[ "$__LinuxCodeName" == "alpine" ]]; then + __ApkToolsVersion=2.9.1 + __AlpineVersion=3.7 + __ApkToolsDir=$(mktemp -d) + wget https://github.com/alpinelinux/apk-tools/releases/download/v$__ApkToolsVersion/apk-tools-$__ApkToolsVersion-x86_64-linux.tar.gz -P $__ApkToolsDir + tar -xf $__ApkToolsDir/apk-tools-$__ApkToolsVersion-x86_64-linux.tar.gz -C $__ApkToolsDir + mkdir -p $__RootfsDir/usr/bin + cp -v /usr/bin/qemu-$__QEMUArch-static $__RootfsDir/usr/bin + $__ApkToolsDir/apk-tools-$__ApkToolsVersion/apk \ + -X http://dl-cdn.alpinelinux.org/alpine/v$__AlpineVersion/main \ + -X http://dl-cdn.alpinelinux.org/alpine/v$__AlpineVersion/community \ + -X http://dl-cdn.alpinelinux.org/alpine/edge/testing \ + -U --allow-untrusted --root $__RootfsDir --arch $__AlpineArch --initdb \ + add $__AlpinePackages + rm -r $__ApkToolsDir +elif [[ -n $__LinuxCodeName ]]; then qemu-debootstrap --arch $__UbuntuArch $__LinuxCodeName $__RootfsDir $__UbuntuRepo cp $__CrossDir/$__BuildArch/sources.list.$__LinuxCodeName $__RootfsDir/etc/apt/sources.list chroot $__RootfsDir apt-get update diff --git a/cross/toolchain.cmake b/cross/toolchain.cmake index ea8d6cabf8..071d411241 100644 --- a/cross/toolchain.cmake +++ b/cross/toolchain.cmake @@ -1,4 +1,5 @@ set(CROSS_ROOTFS $ENV{ROOTFS_DIR}) + set(TARGET_ARCH_NAME $ENV{TARGET_BUILD_ARCH}) set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_VERSION 1) @@ -11,13 +12,21 @@ if(TARGET_ARCH_NAME STREQUAL "armel") endif() elseif(TARGET_ARCH_NAME STREQUAL "arm") set(CMAKE_SYSTEM_PROCESSOR armv7l) - set(TOOLCHAIN "arm-linux-gnueabihf") + if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf) + set(TOOLCHAIN "armv6-alpine-linux-musleabihf") + else() + set(TOOLCHAIN "arm-linux-gnueabihf") + endif() elseif(TARGET_ARCH_NAME STREQUAL "arm64") set(CMAKE_SYSTEM_PROCESSOR aarch64) - set(TOOLCHAIN "aarch64-linux-gnu") + if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/aarch64-alpine-linux-musl) + set(TOOLCHAIN "aarch64-alpine-linux-musl") + else() + set(TOOLCHAIN "aarch64-linux-gnu") + endif() elseif(TARGET_ARCH_NAME STREQUAL "x86") set(CMAKE_SYSTEM_PROCESSOR i686) - set(TOOLCHAIN "i386-linux-gnu") + set(TOOLCHAIN "i686-linux-gnu") else() message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, arm64 and x86 are supported!") endif() @@ -27,12 +36,7 @@ if(TARGET_ARCH_NAME STREQUAL "armel") if(DEFINED TIZEN_TOOLCHAIN) include_directories(SYSTEM ${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}/include/c++/) include_directories(SYSTEM ${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}/include/c++/armv7l-tizen-linux-gnueabi) - else() # TODO: this setting assumes debian armel rootfs - include_directories(SYSTEM ${CROSS_ROOTFS}/usr/include/c++/4.9) - include_directories(SYSTEM ${CROSS_ROOTFS}/usr/include/${TOOLCHAIN}/c++/4.9) endif() -elseif(TARGET_ARCH_NAME STREQUAL "arm64") - include_directories(SYSTEM ${CROSS_ROOTFS}/usr/include) endif() # add_compile_param - adds only new options without duplicates. @@ -43,7 +47,7 @@ macro(add_compile_param) message(FATAL_ERROR "Wrong using add_compile_param! Two or three parameters must be given! See add_compile_param description.") endif() foreach(OPTION ${ARGV1}) - if(NOT ${ARGV0} MATCHES "${OPTION}") + if(NOT ${ARGV0} MATCHES "${OPTION}($| )") set(${ARGV0} "${${ARGV0}} ${OPTION}") if(${ARGC} EQUAL "3") # CACHE FORCE mode set(${ARGV0} "${${ARGV0}}" CACHE STRING "${ARGV2}" FORCE) @@ -54,52 +58,47 @@ endmacro() # Specify link flags add_compile_param(CROSS_LINK_FLAGS "--sysroot=${CROSS_ROOTFS}") +add_compile_param(CROSS_LINK_FLAGS "--gcc-toolchain=${CROSS_ROOTFS}/usr") +add_compile_param(CROSS_LINK_FLAGS "--target=${TOOLCHAIN}") add_compile_param(CROSS_LINK_FLAGS "-fuse-ld=gold") + if(TARGET_ARCH_NAME STREQUAL "armel") - add_compile_param(CROSS_LINK_FLAGS "-target ${TOOLCHAIN}") if(DEFINED TIZEN_TOOLCHAIN) # For Tizen only add_compile_param(CROSS_LINK_FLAGS "-B${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}") add_compile_param(CROSS_LINK_FLAGS "-L${CROSS_ROOTFS}/lib") add_compile_param(CROSS_LINK_FLAGS "-L${CROSS_ROOTFS}/usr/lib") add_compile_param(CROSS_LINK_FLAGS "-L${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}") - else() - add_compile_param(CROSS_LINK_FLAGS "-B${CROSS_ROOTFS}/usr/lib/gcc/${TOOLCHAIN}/4.9") - add_compile_param(CROSS_LINK_FLAGS "-L${CROSS_ROOTFS}/usr/lib/${TOOLCHAIN}") - add_compile_param(CROSS_LINK_FLAGS "-L${CROSS_ROOTFS}/lib/${TOOLCHAIN}") - add_compile_param(CROSS_LINK_FLAGS "-L${CROSS_ROOTFS}/usr/lib/gcc/${TOOLCHAIN}/4.9") endif() -elseif(TARGET_ARCH_NAME MATCHES "^(arm|arm64)$") - add_compile_param(CROSS_LINK_FLAGS "-target ${TOOLCHAIN}") - add_compile_param(CROSS_LINK_FLAGS "-B${CROSS_ROOTFS}/usr/lib/gcc/${TOOLCHAIN}") - add_compile_param(CROSS_LINK_FLAGS "-L${CROSS_ROOTFS}/lib/${TOOLCHAIN}") -else() # x86 case - add_compile_param(CROSS_LINK_FLAGS "-B${CROSS_ROOTFS}/usr/lib/gcc/i686-linux-gnu") - add_compile_param(CROSS_LINK_FLAGS "-L${CROSS_ROOTFS}/lib/${TOOLCHAIN}") - add_compile_param(CROSS_LINK_FLAGS "-L${CROSS_ROOTFS}/usr/lib/${TOOLCHAIN}") +elseif(TARGET_ARCH_NAME STREQUAL "x86") add_compile_param(CROSS_LINK_FLAGS "-m32") endif() + add_compile_param(CMAKE_EXE_LINKER_FLAGS "${CROSS_LINK_FLAGS}" "TOOLCHAIN_EXE_LINKER_FLAGS") add_compile_param(CMAKE_SHARED_LINKER_FLAGS "${CROSS_LINK_FLAGS}" "TOOLCHAIN_EXE_LINKER_FLAGS") add_compile_param(CMAKE_MODULE_LINKER_FLAGS "${CROSS_LINK_FLAGS}" "TOOLCHAIN_EXE_LINKER_FLAGS") # Specify compile options -add_compile_options(--sysroot=${CROSS_ROOTFS}) +add_compile_options("--sysroot=${CROSS_ROOTFS}") +add_compile_options("--target=${TOOLCHAIN}") +add_compile_options("--gcc-toolchain=${CROSS_ROOTFS}/usr") + +if(TARGET_ARCH_NAME MATCHES "^(arm|armel|arm64)$") + set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN}) + set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN}) + set(CMAKE_ASM_COMPILER_TARGET ${TOOLCHAIN}) +endif() + if(TARGET_ARCH_NAME MATCHES "^(arm|armel)$") add_compile_options(-mthumb) add_compile_options(-mfpu=vfpv3) if(TARGET_ARCH_NAME STREQUAL "armel") - add_compile_options(-target armv7-linux-gnueabi) add_compile_options(-mfloat-abi=softfp) if(DEFINED TIZEN_TOOLCHAIN) add_compile_options(-Wno-deprecated-declarations) # compile-time option add_compile_options(-D__extern_always_inline=inline) # compile-time option endif() - else() # arm case - add_compile_options(-target armv7-linux-gnueabihf) endif() -elseif(TARGET_ARCH_NAME STREQUAL "arm64") - add_compile_options(-target ${TOOLCHAIN}) -else() # x86 case +elseif(TARGET_ARCH_NAME STREQUAL "x86") add_compile_options(-m32) add_compile_options(-Wno-error=unused-command-line-argument) endif() diff --git a/cross/tryrun.cmake b/cross/tryrun.cmake index 16eb2e11a8..d0bd77dc97 100644 --- a/cross/tryrun.cmake +++ b/cross/tryrun.cmake @@ -1,9 +1,18 @@ +set(CROSS_ROOTFS $ENV{ROOTFS_DIR}) set(TARGET_ARCH_NAME $ENV{TARGET_BUILD_ARCH}) macro(set_cache_value) set(${ARGV0} ${ARGV1} CACHE STRING "Result from TRY_RUN" FORCE) endmacro() +if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf OR + EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/aarch64-alpine-linux-musl) + + SET(ALPINE_LINUX 1) +else() + SET(ALPINE_LINUX 0) +endif() + if(TARGET_ARCH_NAME MATCHES "^(armel|arm|arm64|x86)$") set_cache_value(FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL_EXITCODE 1) set_cache_value(GETPWUID_R_SETS_ERRNO_EXITCODE 0) @@ -33,13 +42,22 @@ if(TARGET_ARCH_NAME MATCHES "^(armel|arm|arm64|x86)$") set_cache_value(PTHREAD_CREATE_MODIFIES_ERRNO_EXITCODE 1) set_cache_value(REALPATH_SUPPORTS_NONEXISTENT_FILES_EXITCODE 1) set_cache_value(SEM_INIT_MODIFIES_ERRNO_EXITCODE 1) - set_cache_value(SSCANF_CANNOT_HANDLE_MISSING_EXPONENT_EXITCODE 1) - set_cache_value(SSCANF_SUPPORT_ll_EXITCODE 0) - set_cache_value(UNGETC_NOT_RETURN_EOF_EXITCODE 0) + + + if(ALPINE_LINUX) + set_cache_value(SSCANF_CANNOT_HANDLE_MISSING_EXPONENT_EXITCODE 0) + set_cache_value(SSCANF_SUPPORT_ll_EXITCODE 1) + set_cache_value(UNGETC_NOT_RETURN_EOF_EXITCODE 1) + else() + set_cache_value(SSCANF_CANNOT_HANDLE_MISSING_EXPONENT_EXITCODE 1) + set_cache_value(SSCANF_SUPPORT_ll_EXITCODE 0) + set_cache_value(UNGETC_NOT_RETURN_EOF_EXITCODE 0) + endif() + else() message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, arm64 and x86 are supported!") endif() if(TARGET_ARCH_NAME STREQUAL "x86") - set_cache_value(HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES 0) + set_cache_value(HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES_EXITCODE 0) endif() |