From 1e1d29c2af646b21c04f7a27614317a19ee01bc5 Mon Sep 17 00:00:00 2001 From: s1341 Date: Thu, 6 May 2021 07:15:34 +0300 Subject: treewide: Support aarch64-android using minimal prebuilt components This PR adds a new aarch64 android toolchain, which leverages the existing crossSystem infrastructure and LLVM builders to generate a working toolchain with minimal prebuilt components. The only thing that is prebuilt is the bionic libc. This is because it is practically impossible to compile bionic outside of an AOSP tree. I tried and failed, braver souls may prevail. For now I just grab the relevant binaries from https://android.googlesource.com/. I also grab the msm kernel sources from there to generate headers. I've included a minor patch to the existing kernel-headers derivation in order to expose an internal function. Everything else, from binutils up, is using stock code. Many thanks to @Ericson2314 for his help on this, and for building such a powerful system in the first place! One motivation for this is to be able to build a toolchain which will work on an aarch64 linux machine. To my knowledge, there is no existing toolchain for an aarch64-linux builder and an aarch64-android target. --- pkgs/build-support/cc-wrapper/default.nix | 4 + .../compilers/llvm/12/compiler-rt/default.nix | 10 +- pkgs/development/compilers/llvm/12/default.nix | 24 ++++- pkgs/os-specific/linux/bionic-prebuilt/default.nix | 113 +++++++++++++++++++++ .../linux/bionic-prebuilt/ndk-version.patch | 42 ++++++++ pkgs/os-specific/linux/kernel-headers/default.nix | 22 +++- pkgs/top-level/all-packages.nix | 10 +- 7 files changed, 213 insertions(+), 12 deletions(-) create mode 100644 pkgs/os-specific/linux/bionic-prebuilt/default.nix create mode 100644 pkgs/os-specific/linux/bionic-prebuilt/ndk-version.patch (limited to 'pkgs') diff --git a/pkgs/build-support/cc-wrapper/default.nix b/pkgs/build-support/cc-wrapper/default.nix index 36a98a180b3..be5c3bca235 100644 --- a/pkgs/build-support/cc-wrapper/default.nix +++ b/pkgs/build-support/cc-wrapper/default.nix @@ -491,6 +491,10 @@ stdenv.mkDerivation { echo "-arch ${targetPlatform.darwinArch}" >> $out/nix-support/cc-cflags '' + + optionalString targetPlatform.isAndroid '' + echo "-D__ANDROID_API__=${targetPlatform.sdkVer}" >> $out/nix-support/cc-cflags + '' + # There are a few tools (to name one libstdcxx5) which do not work # well with multi line flags, so make the flags single line again + '' diff --git a/pkgs/development/compilers/llvm/12/compiler-rt/default.nix b/pkgs/development/compilers/llvm/12/compiler-rt/default.nix index b880a0071b9..8ca01e44a54 100644 --- a/pkgs/development/compilers/llvm/12/compiler-rt/default.nix +++ b/pkgs/development/compilers/llvm/12/compiler-rt/default.nix @@ -4,14 +4,15 @@ let useLLVM = stdenv.hostPlatform.useLLVM or false; bareMetal = stdenv.hostPlatform.parsed.kernel.name == "none"; + haveLibc = stdenv.cc.libc != null; inherit (stdenv.hostPlatform) isMusl; in stdenv.mkDerivation rec { - pname = "compiler-rt"; + pname = "compiler-rt" + lib.optionalString (haveLibc) "-libc"; inherit version; - src = fetch pname "0d444qihq9jhqnfv003cr704v363va72zl6qaw2algj1c85cva45"; + src = fetch "compiler-rt" "0d444qihq9jhqnfv003cr704v363va72zl6qaw2algj1c85cva45"; nativeBuildInputs = [ cmake python3 llvm.dev ]; buildInputs = lib.optional stdenv.hostPlatform.isDarwin libcxxabi; @@ -29,14 +30,15 @@ stdenv.mkDerivation rec { "-DCOMPILER_RT_BUILD_XRAY=OFF" "-DCOMPILER_RT_BUILD_LIBFUZZER=OFF" "-DCOMPILER_RT_BUILD_PROFILE=OFF" - ] ++ lib.optionals (useLLVM || bareMetal) [ + ] ++ lib.optionals ((useLLVM || bareMetal) && !haveLibc) [ "-DCMAKE_C_COMPILER_WORKS=ON" "-DCMAKE_CXX_COMPILER_WORKS=ON" "-DCOMPILER_RT_BAREMETAL_BUILD=ON" "-DCMAKE_SIZEOF_VOID_P=${toString (stdenv.hostPlatform.parsed.cpu.bits / 8)}" + ] ++ lib.optionals (useLLVM && !haveLibc) [ + "-DCMAKE_C_FLAGS=-nodefaultlibs" ] ++ lib.optionals (useLLVM) [ "-DCOMPILER_RT_BUILD_BUILTINS=ON" - "-DCMAKE_C_FLAGS=-nodefaultlibs" #https://stackoverflow.com/questions/53633705/cmake-the-c-compiler-is-not-able-to-compile-a-simple-test-program "-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY" ] ++ lib.optionals (bareMetal) [ diff --git a/pkgs/development/compilers/llvm/12/default.nix b/pkgs/development/compilers/llvm/12/default.nix index 33db315f625..57017a9a098 100644 --- a/pkgs/development/compilers/llvm/12/default.nix +++ b/pkgs/development/compilers/llvm/12/default.nix @@ -131,6 +131,8 @@ let echo "-B${targetLlvmLibraries.compiler-rt}/lib" >> $out/nix-support/cc-cflags '' + lib.optionalString (!stdenv.targetPlatform.isWasm) '' echo "--unwindlib=libunwind" >> $out/nix-support/cc-cflags + '' + lib.optionalString (stdenv.targetPlatform.isAndroid && stdenv.targetPlatform.useLLVM) '' + echo "-lunwind" >> $out/nix-support/cc-ldflags '' + lib.optionalString stdenv.targetPlatform.isWasm '' echo "-fno-exceptions" >> $out/nix-support/cc-cflags '' + mkExtraBuildCommands cc; @@ -181,17 +183,37 @@ let '' + mkExtraBuildCommands0 cc; }; + lldClangNoCompilerRtWithLibc = wrapCCWith rec { + cc = tools.clang-unwrapped; + libcxx = null; + bintools = wrapBintoolsWith { + inherit (tools) bintools; + }; + extraPackages = [ ]; + extraBuildCommands = mkExtraBuildCommands0 cc; + }; + }); libraries = lib.makeExtensible (libraries: let callPackage = newScope (libraries // buildLlvmTools // { inherit stdenv cmake libxml2 python3 isl release_version version fetch; }); in { - compiler-rt = callPackage ./compiler-rt ({ inherit llvm_meta; } // + compiler-rt-libc = callPackage ./compiler-rt ({ inherit llvm_meta; } // + (lib.optionalAttrs (stdenv.hostPlatform.useLLVM or false) { + stdenv = overrideCC stdenv buildLlvmTools.lldClangNoCompilerRtWithLibc; + })); + + compiler-rt-no-libc = callPackage ./compiler-rt ({ inherit llvm_meta; } // (lib.optionalAttrs (stdenv.hostPlatform.useLLVM or false) { stdenv = overrideCC stdenv buildLlvmTools.lldClangNoCompilerRt; })); + # N.B. condition is safe because without useLLVM both are the same. + compiler-rt = if stdenv.hostPlatform.isAndroid + then libraries.compiler-rt-libc + else libraries.compiler-rt-no-libc; + stdenv = overrideCC stdenv buildLlvmTools.clang; libcxxStdenv = overrideCC stdenv buildLlvmTools.libcxxClang; diff --git a/pkgs/os-specific/linux/bionic-prebuilt/default.nix b/pkgs/os-specific/linux/bionic-prebuilt/default.nix new file mode 100644 index 00000000000..4536067cbf3 --- /dev/null +++ b/pkgs/os-specific/linux/bionic-prebuilt/default.nix @@ -0,0 +1,113 @@ +{ stdenvNoCC, lib, fetchurl, fetchzip, pkgs +}: +let + + prebuilt_crt = fetchzip { + url = "https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/+archive/98dce673ad97a9640c5d90bbb1c718e75c21e071/lib/gcc/aarch64-linux-android/4.9.x.tar.gz"; + sha256 = "sha256-LLD2OJi78sNN5NulOsJZl7Ei4F1EUYItGG6eUsKWULc="; + stripRoot = false; + }; + + prebuilt_libs = fetchzip { + url = "https://android.googlesource.com/platform/prebuilts/ndk/+archive/f2c77d8ba8a7f5c2d91771e31164f29be0b8ff98/platform/platforms/android-30/arch-arm64/usr/lib.tar.gz"; + sha256 = "sha256-TZBV7+D1QvKOCEi+VNGT5SStkgj0xRbyWoLH65zSrjw="; + stripRoot = false; + }; + + prebuilt_ndk_crt = fetchzip { + url = "https://android.googlesource.com/toolchain/prebuilts/ndk/r23/+archive/6c5fa4c0d3999b9ee932f6acbd430eb2f31f3151/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/30.tar.gz"; + sha256 = "sha256-KHw+cCwAwlm+5Nwp1o8WONqdi4BBDhFaVVr+7GxQ5uE="; + stripRoot = false; + }; + + ndk_support_headers = fetchzip { + url ="https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86/+archive/0e7f808fa26cce046f444c9616d9167dafbfb272/clang-r416183b/include/c++/v1/support.tar.gz"; + sha256 = "sha256-NBv7Pk1CEaz8ns9moleEERr3x/rFmVmG33LgFSeO6fY="; + stripRoot = false; + }; + + kernelHeaders = pkgs.makeLinuxHeaders { + version = "android-common-11-5.4"; + src = fetchurl { + url = "https://android.googlesource.com/kernel/common/+archive/48ffcbf0b9e7f0280bfb8c32c68da0aaf0fdfef6.tar.gz"; + sha256 = "0ksm1243zm9hsv0a6q9v15jabf2rivsn14kmnm2qw6zk3mjd4jvv"; + }; + }; + +in +stdenvNoCC.mkDerivation rec { + pname = "bionic-prebuilt"; + version = "ndk-release-r23"; + + src = fetchurl { + url = "https://android.googlesource.com/platform/bionic/+archive/00e8ce1142d8823b0d2fc8a98b40119b0f1f02cd.tar.gz"; + sha256 = "0cfkwdcb2c9nnlmkx0inbsja3cyiha71nj92lm66m5an70zc3b8q"; + }; + + sourceRoot = "."; + + NIX_DONT_SET_RPATH = true; + + dontConfigure = true; + dontBuild = true; + + patches = [ + ./ndk-version.patch + ]; + + postPatch = '' + substituteInPlace libc/include/sys/cdefs.h --replace \ + "__has_builtin(__builtin_umul_overflow)" "1" + substituteInPlace libc/include/bits/ioctl.h --replace \ + "!defined(BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD)" "0" + ''; + + installPhase= '' + # copy the bionic headers + mkdir -p $out/include/support $out/include/android + cp -vr libc/include/* $out/include + # copy the kernel headers + cp -vr ${kernelHeaders}/include/* $out/include/ + + chmod -R +w $out/include/linux + + # fix a bunch of kernel headers so that things can actually be found + sed -i 's,struct epoll_event {,#include \nstruct Xepoll_event {,' $out/include/linux/eventpoll.h + sed -i 's,struct in_addr {,typedef unsigned int in_addr_t;\nstruct in_addr {,' $out/include/linux/in.h + sed -i 's,struct udphdr {,struct Xudphdr {,' $out/include/linux/udp.h + sed -i 's,union semun {,union Xsemun {,' $out/include/linux/sem.h + sed -i 's,struct __kernel_sockaddr_storage,#define sockaddr_storage __kernel_sockaddr_storage\nstruct __kernel_sockaddr_storage,' $out/include/linux/socket.h + sed -i 's,#ifndef __UAPI_DEF_.*$,#if 1,' $out/include/linux/libc-compat.h + substituteInPlace $out/include/linux/in.h --replace "__be32 imr_" "struct in_addr imr_" + substituteInPlace $out/include/linux/in.h --replace "__be32 imsf_" "struct in_addr imsf_" + substituteInPlace $out/include/linux/sysctl.h --replace "__unused" "_unused" + + # what could possibly live in + touch $out/include/linux/compiler.h + + # copy the support headers + cp -vr ${ndk_support_headers}* $out/include/support/ + + mkdir $out/lib + cp -v ${prebuilt_crt.out}/*.o $out/lib/ + cp -v ${prebuilt_crt.out}/libgcc.a $out/lib/ + cp -v ${prebuilt_ndk_crt.out}/*.o $out/lib/ + for i in libc.so libm.so libdl.so liblog.so; do + cp -v ${prebuilt_libs.out}/$i $out/lib/ + done + + mkdir -p $dev/include + cp -v $out/include/*.h $dev/include/ + ''; + + outputs = [ "out" "dev" ]; + passthru.linuxHeaders = kernelHeaders; + + meta = with lib; { + description = "The Android libc implementation"; + homepage = "https://android.googlesource.com/platform/bionic/"; + license = licenses.mit; + platforms = platforms.linux; + maintainers = with maintainers; [ s1341 ]; + }; +} diff --git a/pkgs/os-specific/linux/bionic-prebuilt/ndk-version.patch b/pkgs/os-specific/linux/bionic-prebuilt/ndk-version.patch new file mode 100644 index 00000000000..a6842ed479f --- /dev/null +++ b/pkgs/os-specific/linux/bionic-prebuilt/ndk-version.patch @@ -0,0 +1,42 @@ +--- a/libc/include/android/ndk-version.h 2021-04-01 16:08:03.109183965 +0300 ++++ b/libc/include/android/ndk-version.h 2021-04-01 16:07:19.811424641 +0300 +@@ -0,0 +1,39 @@ ++#pragma once ++ ++/** ++ * Set to 1 if this is an NDK, unset otherwise. See ++ * https://android.googlesource.com/platform/bionic/+/master/docs/defines.md. ++ */ ++#define __ANDROID_NDK__ 1 ++ ++/** ++ * Major version of this NDK. ++ * ++ * For example: 16 for r16. ++ */ ++#define __NDK_MAJOR__ 22 ++ ++/** ++ * Minor version of this NDK. ++ * ++ * For example: 0 for r16 and 1 for r16b. ++ */ ++#define __NDK_MINOR__ 0 ++ ++/** ++ * Set to 0 if this is a release build, or 1 for beta 1, ++ * 2 for beta 2, and so on. ++ */ ++#define __NDK_BETA__ 0 ++ ++/** ++ * Build number for this NDK. ++ * ++ * For a local development build of the NDK, this is -1. ++ */ ++#define __NDK_BUILD__ 7026061 ++ ++/** ++ * Set to 1 if this is a canary build, 0 if not. ++ */ ++#define __NDK_CANARY__ 0 diff --git a/pkgs/os-specific/linux/kernel-headers/default.nix b/pkgs/os-specific/linux/kernel-headers/default.nix index 34e80ac8222..d9dac5e53a5 100644 --- a/pkgs/os-specific/linux/kernel-headers/default.nix +++ b/pkgs/os-specific/linux/kernel-headers/default.nix @@ -1,4 +1,9 @@ -{ stdenvNoCC, lib, buildPackages, fetchurl, perl, elf-header }: +{ stdenvNoCC, lib, buildPackages, fetchurl, perl, elf-header +, bison ? null, flex ? null, python ? null, rsync ? null +}: + +assert stdenvNoCC.hostPlatform.isAndroid -> + (flex != null && bison != null && python != null && rsync != null); let makeLinuxHeaders = { src, version, patches ? [] }: stdenvNoCC.mkDerivation { @@ -13,7 +18,11 @@ let # We do this so we have a build->build, not build->host, C compiler. depsBuildBuild = [ buildPackages.stdenv.cc ]; # `elf-header` is null when libc provides `elf.h`. - nativeBuildInputs = [ perl elf-header ]; + nativeBuildInputs = [ + perl elf-header + ] ++ lib.optionals stdenvNoCC.hostPlatform.isAndroid [ + flex bison python rsync + ]; extraIncludeDirs = lib.optional stdenvNoCC.hostPlatform.isPowerPC ["ppc"]; @@ -21,6 +30,8 @@ let hardeningDisable = lib.optional stdenvNoCC.buildPlatform.isDarwin "format"; + sourceRoot = lib.optionalString stdenvNoCC.hostPlatform.isAndroid "."; + makeFlags = [ "SHELL=bash" # Avoid use of runtime build->host compilers for checks. These @@ -36,9 +47,12 @@ let # Skip clean on darwin, case-sensitivity issues. buildPhase = lib.optionalString (!stdenvNoCC.buildPlatform.isDarwin) '' make mrproper $makeFlags - '' + '' + '' + (if stdenvNoCC.hostPlatform.isAndroid then '' + make defconfig + make headers_install + '' else '' make headers $makeFlags - ''; + ''); checkPhase = '' make headers_check $makeFlags diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 49f96c5a269..c45bec11f19 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -11127,6 +11127,8 @@ in llvmPackages_7 else if isFreeBSD then llvmPackages_7 + else if isAndroid then + llvmPackages_12 else if isLinux then llvmPackages_7 else if isWasm then @@ -13993,8 +13995,10 @@ in bicgl = callPackage ../development/libraries/science/biology/bicgl { }; # TODO(@Ericson2314): Build bionic libc from source - bionic = assert stdenv.hostPlatform.useAndroidPrebuilt; - pkgs."androidndkPkgs_${stdenv.hostPlatform.ndkVer}".libraries; + bionic = if stdenv.hostPlatform.useAndroidPrebuilt + then pkgs."androidndkPkgs_${stdenv.hostPlatform.ndkVer}".libraries + else callPackage ../os-specific/linux/bionic-prebuilt { }; + bobcat = callPackage ../development/libraries/bobcat { }; @@ -19992,7 +19996,7 @@ in lkl = callPackage ../applications/virtualization/lkl { }; inherit (callPackages ../os-specific/linux/kernel-headers { }) - linuxHeaders; + linuxHeaders makeLinuxHeaders; kernelPatches = callPackage ../os-specific/linux/kernel/patches.nix { }; -- cgit 1.4.1