diff --git a/lib/systems/default.nix b/lib/systems/default.nix index 0729cc7ef29..d5a206e620c 100644 --- a/lib/systems/default.nix +++ b/lib/systems/default.nix @@ -23,13 +23,15 @@ rec { config = parse.tripleFromSystem final.parsed; # Just a guess, based on `system` platform = platforms.selectBySystem final.system; + # Derived meta-data libc = - /**/ if final.isDarwin then "libSystem" - else if final.isMinGW then "msvcrt" - else if final.isMusl then "musl" - else if final.isLinux /* default */ then "glibc" + /**/ if final.isDarwin then "libSystem" + else if final.isMinGW then "msvcrt" + else if final.isMusl then "musl" + else if final.isAndroid then "bionic" + else if final.isLinux /* default */ then "glibc" # TODO(@Ericson2314) think more about other operating systems - else "native/impure"; + else "native/impure"; extensions = { sharedLibrary = /**/ if final.isDarwin then ".dylib" @@ -39,7 +41,10 @@ rec { /**/ if final.isWindows then ".exe" else ""; }; + # Misc boolean options + useAndroidPrebuilt = false; } // mapAttrs (n: v: v final.parsed) inspect.predicates // args; - in final; + in assert final.useAndroidPrebuilt -> final.isAndroid; + final; } diff --git a/lib/systems/examples.nix b/lib/systems/examples.nix index e0d08ed5dae..848737700b0 100644 --- a/lib/systems/examples.nix +++ b/lib/systems/examples.nix @@ -38,6 +38,13 @@ rec { platform = platforms.aarch64-multiplatform; }; + aarch64-android-prebuilt = rec { + config = "aarch64-unknown-linux-android"; + arch = "aarch64"; + platform = platforms.aarch64-multiplatform; + useAndroidPrebuilt = true; + }; + scaleway-c1 = armv7l-hf-multiplatform // rec { platform = platforms.scaleway-c1; inherit (platform.gcc) fpu; diff --git a/lib/systems/inspect.nix b/lib/systems/inspect.nix index ff8f6000117..ab220af46e3 100644 --- a/lib/systems/inspect.nix +++ b/lib/systems/inspect.nix @@ -34,6 +34,7 @@ rec { Cygwin = { kernel = kernels.windows; abi = abis.cygnus; }; MinGW = { kernel = kernels.windows; abi = abis.gnu; }; + Android = [ { abi = abis.android; } { abi = abis.androideabi; } ]; Musl = with abis; map (a: { abi = a; }) [ musl musleabi musleabihf ]; Kexecable = map (family: { kernel = kernels.linux; cpu.family = family; }) diff --git a/lib/systems/parse.nix b/lib/systems/parse.nix index eea471f5773..03d052f5f19 100644 --- a/lib/systems/parse.nix +++ b/lib/systems/parse.nix @@ -176,6 +176,7 @@ rec { types.abi = enum (attrValues abis); abis = setTypes types.openAbi { + android = {}; cygnus = {}; gnu = {}; msvc = {}; diff --git a/pkgs/development/mobile/androidenv/androidndk-pkgs.nix b/pkgs/development/mobile/androidenv/androidndk-pkgs.nix new file mode 100644 index 00000000000..19fc0dc812d --- /dev/null +++ b/pkgs/development/mobile/androidenv/androidndk-pkgs.nix @@ -0,0 +1,82 @@ +{ lib, hostPlatform, targetPlatform +, makeWrapper +, runCommand, wrapBintoolsWith, wrapCCWith +, buildAndroidndk, androidndk, targetAndroidndkPkgs +}: + +let + # Mapping from a platform to information needed to unpack NDK stuff for that + # platform. + # + # N.B. The Android NDK uses slightly different LLVM-style platform triples + # than we do. We don't just use theirs because ours are less ambiguous and + # some builds need that clarity. + ndkInfoFun = { config, ... }: { + "x86_64-unknown-linux-gnu" = { + double = "linux-x86_64"; + }; + "arm-unknown-linux-androideabi" = { + arch = "arm"; + triple = "arm-linux-androideabi"; + gccVer = "4.8"; + }; + "aarch64-unknown-linux-android" = { + arch = "arm64"; + triple = "aarch64-linux-android"; + gccVer = "4.9"; + }; + }.${config} or + (throw "Android NDK doesn't support ${config}, as far as we know"); + + hostInfo = ndkInfoFun hostPlatform; + targetInfo = ndkInfoFun targetPlatform; + +in + +rec { + # Misc tools + binaries = let + ndkBinDir = + "${androidndk}/libexec/${androidndk.name}/toolchains/${targetInfo.triple}-${targetInfo.gccVer}/prebuilt/${hostInfo.double}/bin"; + in runCommand "ndk-gcc-binutils" { + isGNU = true; # for cc-wrapper + nativeBuildInputs = [ makeWrapper ]; + propgatedBuildInputs = [ androidndk ]; + } '' + mkdir -p $out/bin + for prog in ${ndkBinDir}/${targetInfo.triple}-*; do + prog_suffix=$(basename $prog | sed 's/${targetInfo.triple}-//') + ln -s $prog $out/bin/${targetPlatform.config}-$prog_suffix + done + ''; + + binutils = wrapBintoolsWith { + bintools = binaries; + libc = targetAndroidndkPkgs.libraries; + }; + + gcc = wrapCCWith { + cc = binaries; + bintools = binutils; + libc = targetAndroidndkPkgs.libraries; + extraBuildCommands = + # GCC 4.9 is the first relase with "-fstack-protector" + lib.optionalString (lib.versionOlder targetInfo.gccVer "4.9") '' + sed -E \ + -i $out/nix-support/add-hardening.sh \ + -e 's|(-fstack-protector)-strong|\1|g' + ''; + }; + + # Bionic lib C and other libraries. + # + # We use androidndk from the previous stage, else we waste time or get cycles + # cross-compiling packages to wrap incorrectly wrap binaries we don't include + # anyways. + libraries = { + name = "bionic-prebuilt"; + type = "derivation"; + outPath = "${buildAndroidndk}/libexec/${buildAndroidndk.name}/platforms/android-21/arch-${hostInfo.arch}/usr/"; + drvPath = throw "fake derivation, build ${buildAndroidndk} to use"; + }; +} diff --git a/pkgs/development/mobile/androidenv/default.nix b/pkgs/development/mobile/androidenv/default.nix index 98531eeb069..c053712302d 100644 --- a/pkgs/development/mobile/androidenv/default.nix +++ b/pkgs/development/mobile/androidenv/default.nix @@ -242,4 +242,19 @@ rec { inherit (pkgs) stdenv; inherit androidsdk; }; + + androidndkPkgs = import ./androidndk-pkgs.nix { + inherit (buildPackages) + makeWrapper; + inherit (pkgs) + lib hostPlatform targetPlatform + runCommand wrapBintoolsWith wrapCCWith; + # buildPackages.foo rather than buildPackages.buildPackages.foo would work, + # but for splicing messing up on infinite recursion for the variants we + # *dont't* use. Using this workaround, but also making a test to ensure + # these two really are the same. + buildAndroidndk = buildPackages.buildPackages.androidenv.androidndk; + inherit androidndk; + targetAndroidndkPkgs = targetPackages.androidenv.androidndkPkgs; + }; } diff --git a/pkgs/stdenv/cross/default.nix b/pkgs/stdenv/cross/default.nix index 8197510eeec..8da3555c6c6 100644 --- a/pkgs/stdenv/cross/default.nix +++ b/pkgs/stdenv/cross/default.nix @@ -34,7 +34,9 @@ in bootStages ++ [ hostPlatform = crossSystem; targetPlatform = crossSystem; cc = if crossSystem.useiOSCross or false - then buildPackages.darwin.ios-cross + then buildPackages.darwin.ios-cross + else if crossSystem.useAndroidPrebuilt + then buildPackages.androidenv.androidndkPkgs.gcc else buildPackages.gcc; }; }) diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 24908b4863b..68cf3e6bb15 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -8326,6 +8326,10 @@ with pkgs; libopcodes = callPackage ../development/libraries/libopcodes { }; + # TODO(@Ericson2314): Build bionic libc from source + bionic = assert hostPlatform.useAndroidPrebuilt; + androidenv.androidndkPkgs.libraries; + bobcat = callPackage ../development/libraries/bobcat { }; boehmgc = callPackage ../development/libraries/boehm-gc { }; @@ -8862,6 +8866,7 @@ with pkgs; # libc is hackily often used from the previous stage. This `or` # hack fixes the hack, *sigh*. /**/ if name == "glibc" then targetPackages.glibcCross or glibcCross + else if name == "bionic" then targetPackages.bionic else if name == "uclibc" then uclibcCross else if name == "musl" then targetPackages.muslCross or muslCross else if name == "msvcrt" then targetPackages.windows.mingw_w64 or windows.mingw_w64 diff --git a/pkgs/top-level/release-cross.nix b/pkgs/top-level/release-cross.nix index be6dd89bf7d..ef99dbd619e 100644 --- a/pkgs/top-level/release-cross.nix +++ b/pkgs/top-level/release-cross.nix @@ -93,6 +93,7 @@ in mapTestEqual = lib.mapAttrsRecursive testEqual; in mapTestEqual { + androidndk = nativePlatforms; boehmgc = nativePlatforms; libffi = nativePlatforms; libiconv = nativePlatforms; @@ -125,12 +126,14 @@ in rpi = mapTestOnCross lib.systems.examples.raspberryPi rpiCommon; rpi-musl = mapTestOnCross lib.systems.examples.muslpi rpiCommon; - /* Linux on Aarch64 (TODO make android for real) */ - android = mapTestOnCross lib.systems.examples.aarch64-multiplatform linuxCommon; aarch64-musl = mapTestOnCross lib.systems.examples.aarch64-multiplatform-musl linuxCommon; x86_64-musl = mapTestOnCross lib.systems.examples.musl64 linuxCommon; + /* Linux on Aarch64 */ + android64 = mapTestOnCross lib.systems.examples.aarch64-android-prebuilt (linuxCommon // { + }); + /* Cross-built bootstrap tools for every supported platform */ bootstrapTools = let tools = import ../stdenv/linux/make-bootstrap-tools-cross.nix { system = "x86_64-linux"; };