about summary refs log tree commit diff
path: root/pkgs/development/androidndk-pkgs
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2022-06-29 18:24:19 +0900
committerJari Vetoniemi <mailroxas@gmail.com>2022-06-29 18:27:16 +0900
commit5f1923d67e1ecdc2176f017d7d2008aa1c908baf (patch)
tree76d4fecf0ec91e67ea289baae1e8b41d280197a1 /pkgs/development/androidndk-pkgs
parent72f17cca89ec773e5845f5fa1bffcf0b7a4e2094 (diff)
androidenv: fix android cross-compilers
These were completely broken. Even if they managed to output a binary,
it wouldn't actually run on the actual device.
Diffstat (limited to 'pkgs/development/androidndk-pkgs')
-rw-r--r--pkgs/development/androidndk-pkgs/androidndk-pkgs.nix149
-rw-r--r--pkgs/development/androidndk-pkgs/default.nix4
2 files changed, 118 insertions, 35 deletions
diff --git a/pkgs/development/androidndk-pkgs/androidndk-pkgs.nix b/pkgs/development/androidndk-pkgs/androidndk-pkgs.nix
index 736e088454e7f..dc9802ea7f9e0 100644
--- a/pkgs/development/androidndk-pkgs/androidndk-pkgs.nix
+++ b/pkgs/development/androidndk-pkgs/androidndk-pkgs.nix
@@ -1,6 +1,6 @@
 { lib, stdenv
-, makeWrapper
-, runCommand, wrapBintoolsWith, wrapCCWith
+, makeWrapper, python
+, runCommand, wrapBintoolsWith, wrapCCWith, autoPatchelfHook
 , buildAndroidndk, androidndk, targetAndroidndkPkgs
 }:
 
@@ -11,6 +11,9 @@ let
   # 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.
+  #
+  # FIXME:
+  # There's some dragons here. Build host and target concepts are being mixed up.
   ndkInfoFun = { config, ... }: {
     x86_64-apple-darwin = {
       double = "darwin-x86_64";
@@ -21,65 +24,123 @@ let
     i686-unknown-linux-android = {
       triple = "i686-linux-android";
       arch = "x86";
+      # LEGACY
       toolchain = "x86";
       gccVer = "4.9";
     };
     x86_64-unknown-linux-android = {
       triple = "x86_64-linux-android";
       arch = "x86_64";
+      # LEGACY
       toolchain = "x86_64";
       gccVer = "4.9";
     };
     armv7a-unknown-linux-androideabi = {
       arch = "arm";
       triple = "arm-linux-androideabi";
+      # LEGACY
       toolchain = "arm-linux-androideabi";
       gccVer = "4.9";
     };
     aarch64-unknown-linux-android = {
       arch = "arm64";
       triple = "aarch64-linux-android";
+      # LEGACY
       toolchain = "aarch64-linux-android";
       gccVer = "4.9";
     };
   }.${config} or
     (throw "Android NDK doesn't support ${config}, as far as we know");
 
+  buildInfo = ndkInfoFun stdenv.buildPlatform;
   hostInfo = ndkInfoFun stdenv.hostPlatform;
   targetInfo = ndkInfoFun stdenv.targetPlatform;
 
-  prefix = lib.optionalString (stdenv.targetPlatform != stdenv.hostPlatform) (stdenv.targetPlatform.config + "-");
+  inherit (stdenv.targetPlatform) sdkVer;
+  suffixSalt = lib.replaceStrings ["-" "."] ["_" "_"] stdenv.targetPlatform.config;
+
+  # targetInfo.triple is what Google thinks the toolchain should be, this is a little
+  # different from what we use. We make it four parts to conform with the existing
+  # standard more properly.
+  targetConfig = lib.optionalString (stdenv.targetPlatform != stdenv.hostPlatform) (stdenv.targetPlatform.config);
 in
 
 rec {
   # Misc tools
-  binaries = runCommand "ndk-toolchain-binutils" {
-    pname = "ndk-toolchain-binutils";
+  binaries = stdenv.mkDerivation {
+    pname = "${targetConfig}-ndk-toolchain";
     inherit (androidndk) version;
-    nativeBuildInputs = [ makeWrapper ];
+    nativeBuildInputs = [ makeWrapper python autoPatchelfHook ];
     propagatedBuildInputs = [ androidndk ];
     passthru = {
-      targetPrefix = prefix;
       isClang = true; # clang based cc, but bintools ld
     };
-  } ''
-    mkdir -p $out/bin
-
-    # llvm toolchain
-    for prog in ${androidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${hostInfo.double}/bin/*; do
-      ln -s $prog $out/bin/$(basename $prog)
-      ln -s $prog $out/bin/${prefix}$(basename $prog)
-    done
-
-    # bintools toolchain
-    for prog in ${androidndk}/libexec/android-sdk/ndk-bundle/toolchains/${targetInfo.toolchain}-${targetInfo.gccVer}/prebuilt/${hostInfo.double}/bin/*; do
-      prog_suffix=$(basename $prog | sed 's/${targetInfo.triple}-//')
-      ln -s $prog $out/bin/${stdenv.targetPlatform.config}-$prog_suffix
-    done
-
-    # shitty googly wrappers
-    rm -f $out/bin/${stdenv.targetPlatform.config}-gcc $out/bin/${stdenv.targetPlatform.config}-g++
-  '';
+    dontUnpack = true;
+    dontBuild = true;
+    dontStrip = true;
+    dontConfigure = true;
+    dontPatch = true;
+    autoPatchelfIgnoreMissingDeps = true;
+    installPhase = ''
+      if [ ! -d ${androidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${buildInfo.double} ]; then
+        # LEGACY: make-standalone-toolchain is deprecated
+        #         https://developer.android.com/ndk/guides/standalone_toolchain
+        ${androidndk}/libexec/android-sdk/ndk-bundle/build/tools/make-standalone-toolchain.sh --arch=${targetInfo.arch} --install-dir=$out/toolchain --platform=${sdkVer} --force
+      else
+        # https://developer.android.com/ndk/guides/other_build_systems
+        mkdir -p $out
+        cp -r ${androidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${buildInfo.double} $out/toolchain
+        find $out/toolchain -type d -exec chmod 777 {} \;
+      fi
+
+      if [ ! -d $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${sdkVer} ]; then
+        echo "NDK does not contain libraries for SDK version ${sdkVer}";
+        exit 1
+      fi
+
+      ln -vfs $out/toolchain/sysroot/usr/lib $out/lib
+      ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/*.so $out/lib/
+      ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/*.a $out/lib/
+      chmod +w $out/lib/*
+      ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${sdkVer}/*.so $out/lib/
+      ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${sdkVer}/*.o $out/lib/
+
+      echo "INPUT(-lc++_static)" > $out/lib/libc++.a
+
+      ln -s $out/toolchain/bin $out/bin
+      ln -s $out/toolchain/${targetInfo.triple}/bin/* $out/bin/
+      for f in $out/bin/${targetInfo.triple}-*; do
+        ln -s $f ''${f/${targetInfo.triple}-/${targetConfig}-}
+      done
+      for f in $(find $out/toolchain -type d -name ${targetInfo.triple}); do
+        ln -s $f ''${f/${targetInfo.triple}/${targetConfig}}
+      done
+
+      # LEGACY: get rid of gcc and g++, otherwise wrapCCWith will use them instead of clang
+      rm -f $out/bin/${targetConfig}-gcc $out/bin/${targetConfig}-g++
+
+      # LEGACY: ld doesn't properly include transitive library dependencies.
+      #         Let's use gold instead
+      rm -f $out/bin/${targetConfig}-ld
+      if [[ -f  $out/bin/${targetConfig}-ld.gold ]]; then
+        ln -s $out/bin/${targetConfig}-ld.gold $out/bin/${targetConfig}-ld
+      else
+        ln -s $out/bin/lld $out/bin/${targetConfig}-ld
+      fi
+
+      (cd $out/bin;
+        for tool in llvm-*; do
+          ln -sf $tool ${targetConfig}-$(echo $tool | sed 's/llvm-//')
+          ln -sf $tool $(echo $tool | sed 's/llvm-//')
+        done)
+
+      # handle last, as llvm-as is for llvm bytecode
+      ln -sf $out/bin/${targetInfo.triple}-as $out/bin/${targetConfig}-as
+      ln -sf $out/bin/${targetInfo.triple}-as $out/bin/as
+
+      patchShebangs $out/bin
+    '';
+  };
 
   binutils = wrapBintoolsWith {
     bintools = binaries;
@@ -95,9 +156,22 @@ rec {
     libc = targetAndroidndkPkgs.libraries;
     extraBuildCommands = ''
       echo "-D__ANDROID_API__=${stdenv.targetPlatform.sdkVer}" >> $out/nix-support/cc-cflags
-      echo "-target ${stdenv.targetPlatform.config}" >> $out/nix-support/cc-cflags
-      echo "-resource-dir=$(echo ${androidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${hostInfo.double}/lib*/clang/*)" >> $out/nix-support/cc-cflags
-      echo "--gcc-toolchain=${androidndk}/libexec/android-sdk/ndk-bundle/toolchains/${targetInfo.toolchain}-${targetInfo.gccVer}/prebuilt/${hostInfo.double}" >> $out/nix-support/cc-cflags
+      if [ ! -d ${androidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${hostInfo.double} ]; then
+        # LEGACY: probably won't work for any recent android
+        echo "--gcc-toolchain=${androidndk}/libexec/android-sdk/ndk-bundle/toolchains/${targetInfo.toolchain}-${targetInfo.gccVer}/prebuilt/${hostInfo.double}" >> $out/nix-support/cc-cflags
+        echo "-fuse-ld=$out/bin/${targetConfig}-ld.gold -L${binaries}/lib" >> $out/nix-support/cc-ldflags
+      else
+        # Android needs executables linked with -pie since version 5.0
+        # Use -fPIC for compilation, and link with -pie if no -shared flag used in ldflags
+        echo "-target ${targetInfo.triple} -fPIC" >> $out/nix-support/cc-cflags
+        echo "-z,noexecstack -z,relro -z,now" >> $out/nix-support/cc-ldflags
+        echo 'if [[ ! " $@ " =~ " -shared " ]]; then NIX_LDFLAGS_${suffixSalt}+=" -pie"; fi' >> $out/nix-support/add-flags.sh
+        echo "-Xclang -mnoexecstack" >> $out/nix-support/cc-cxxflags
+      fi
+      if [ ${targetInfo.triple} == arm-linux-androideabi ]; then
+        # https://android.googlesource.com/platform/external/android-cmake/+/refs/heads/cmake-master-dev/android.toolchain.cmake
+        echo "--fix-cortex-a8" >> $out/nix-support/cc-ldflags
+      fi
     '';
   };
 
@@ -107,10 +181,19 @@ rec {
   # cross-compiling packages to wrap incorrectly wrap binaries we don't include
   # anyways.
   libraries = runCommand "bionic-prebuilt" {} ''
-    mkdir -p $out
-    cp -r ${buildAndroidndk}/libexec/android-sdk/ndk-bundle/sysroot/usr/include $out/include
-    chmod +w $out/include
-    cp -r ${buildAndroidndk}/libexec/android-sdk/ndk-bundle/sysroot/usr/include/${targetInfo.triple}/* $out/include
-    ln -s ${buildAndroidndk}/libexec/android-sdk/ndk-bundle/platforms/android-${stdenv.hostPlatform.sdkVer}/arch-${hostInfo.arch}/usr/${if hostInfo.arch == "x86_64" then "lib64" else "lib"} $out/lib
+    if [ -d ${buildAndroidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt ]; then
+      lpath=${buildAndroidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${buildInfo.double}/sysroot/usr/lib/${targetInfo.triple}/${sdkVer}
+    else
+      # LEGACY
+      lpath=${buildAndroidndk}/libexec/android-sdk/ndk-bundle/platforms/android-${sdkVer}/arch-${hostInfo.arch}/usr/${if hostInfo.arch == "x86_64" then "lib64" else "lib"}
+    fi
+    if [ ! -d $lpath ]; then
+      echo "NDK does not contain libraries for SDK version ${sdkVer} <$lpath>"
+      exit 1
+    fi
+    mkdir -p $out/lib
+    cp $lpath/*.so $lpath/*.a $out/lib
+    chmod +w $out/lib/*
+    cp $lpath/* $out/lib
   '';
 }
diff --git a/pkgs/development/androidndk-pkgs/default.nix b/pkgs/development/androidndk-pkgs/default.nix
index 5f71304d38555..1648a918b87bc 100644
--- a/pkgs/development/androidndk-pkgs/default.nix
+++ b/pkgs/development/androidndk-pkgs/default.nix
@@ -19,7 +19,7 @@
     import ./androidndk-pkgs.nix {
       inherit lib;
       inherit (buildPackages)
-        makeWrapper;
+        makeWrapper python autoPatchelfHook;
       inherit (pkgs)
         stdenv
         runCommand wrapBintoolsWith wrapCCWith;
@@ -49,7 +49,7 @@
     import ./androidndk-pkgs.nix {
       inherit lib;
       inherit (buildPackages)
-        makeWrapper;
+        makeWrapper python autoPatchelfHook;
       inherit (pkgs)
         stdenv
         runCommand wrapBintoolsWith wrapCCWith;