1 { lib, stdenv, makeWrapper
2 , runCommand, wrapBintoolsWith, wrapCCWith, autoPatchelfHook
3 , buildAndroidndk, androidndk, targetAndroidndkPkgs
7 # Mapping from a platform to information needed to unpack NDK stuff for that
10 # N.B. The Android NDK uses slightly different LLVM-style platform triples
11 # than we do. We don't just use theirs because ours are less ambiguous and
12 # some builds need that clarity.
14 ndkBuildInfoFun = { config, ... }: {
15 x86_64-apple-darwin = {
16 double = "darwin-x86_64";
18 x86_64-unknown-linux-gnu = {
19 double = "linux-x86_64";
22 (throw "Android NDK doesn't support building on ${config}, as far as we know");
24 ndkTargetInfoFun = { config, ... }: {
25 i686-unknown-linux-android = {
26 triple = "i686-linux-android";
29 x86_64-unknown-linux-android = {
30 triple = "x86_64-linux-android";
33 armv7a-unknown-linux-androideabi = {
35 triple = "arm-linux-androideabi";
37 aarch64-unknown-linux-android = {
39 triple = "aarch64-linux-android";
42 (throw "Android NDK doesn't support targetting ${config}, as far as we know");
44 buildInfo = ndkBuildInfoFun stdenv.buildPlatform;
45 targetInfo = ndkTargetInfoFun stdenv.targetPlatform;
47 inherit (stdenv.targetPlatform) sdkVer;
48 suffixSalt = lib.replaceStrings ["-" "."] ["_" "_"] stdenv.targetPlatform.config;
50 # targetInfo.triple is what Google thinks the toolchain should be, this is a little
51 # different from what we use. We make it four parts to conform with the existing
52 # standard more properly.
53 targetPrefix = lib.optionalString (stdenv.targetPlatform != stdenv.hostPlatform) (stdenv.targetPlatform.config + "-");
58 binaries = stdenv.mkDerivation {
59 pname = "${targetPrefix}ndk-toolchain";
60 inherit (androidndk) version;
61 nativeBuildInputs = [ makeWrapper autoPatchelfHook ];
62 propagatedBuildInputs = [ androidndk ];
65 isClang = true; # clang based cc, but bintools ld
72 autoPatchelfIgnoreMissingDeps = true;
74 # https://developer.android.com/ndk/guides/other_build_systems
76 cp -r ${androidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${buildInfo.double} $out/toolchain
77 find $out/toolchain -type d -exec chmod 777 {} \;
79 if [ ! -d $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${sdkVer} ]; then
80 echo "NDK does not contain libraries for SDK version ${sdkVer}";
84 ln -vfs $out/toolchain/sysroot/usr/lib $out/lib
85 ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/*.so $out/lib/
86 ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/*.a $out/lib/
88 ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${sdkVer}/*.so $out/lib/
89 ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${sdkVer}/*.o $out/lib/
91 echo "INPUT(-lc++_static)" > $out/lib/libc++.a
93 ln -s $out/toolchain/bin $out/bin
94 ln -s $out/toolchain/${targetInfo.triple}/bin/* $out/bin/
95 for f in $out/bin/${targetInfo.triple}-*; do
96 ln -s $f ''${f/${targetInfo.triple}-/${targetPrefix}}
98 for f in $(find $out/toolchain -type d -name ${targetInfo.triple}); do
99 ln -s $f ''${f/${targetInfo.triple}/${targetPrefix}}
102 rm -f $out/bin/${targetPrefix}ld
103 ln -s $out/bin/lld $out/bin/${targetPrefix}ld
106 for tool in llvm-*; do
107 ln -sf $tool ${targetPrefix}$(echo $tool | sed 's/llvm-//')
108 ln -sf $tool $(echo $tool | sed 's/llvm-//')
111 # handle last, as llvm-as is for llvm bytecode
112 ln -sf $out/bin/${targetInfo.triple}-as $out/bin/${targetPrefix}as
113 ln -sf $out/bin/${targetInfo.triple}-as $out/bin/as
115 patchShebangs $out/bin
119 binutils = wrapBintoolsWith {
121 libc = targetAndroidndkPkgs.libraries;
126 # for packages expecting libcompiler-rt, etc. to come from here (stdenv.cc.cc.lib)
127 lib = targetAndroidndkPkgs.libraries;
130 libc = targetAndroidndkPkgs.libraries;
131 extraBuildCommands = ''
132 echo "-D__ANDROID_API__=${stdenv.targetPlatform.sdkVer}" >> $out/nix-support/cc-cflags
133 # Android needs executables linked with -pie since version 5.0
134 # Use -fPIC for compilation, and link with -pie if no -shared flag used in ldflags
135 echo "-target ${targetInfo.triple} -fPIC" >> $out/nix-support/cc-cflags
136 echo "-z,noexecstack -z,relro -z,now -z,muldefs" >> $out/nix-support/cc-ldflags
137 echo 'expandResponseParams "$@"' >> $out/nix-support/add-flags.sh
138 echo 'if [[ ! (" ''${params[@]} " =~ " -shared ") && ! (" ''${params[@]} " =~ " -no-pie ") ]]; then NIX_LDFLAGS_${suffixSalt}+=" -pie"; fi' >> $out/nix-support/add-flags.sh
139 echo "-Xclang -mnoexecstack" >> $out/nix-support/cc-cxxflags
140 if [ ${targetInfo.triple} == arm-linux-androideabi ]; then
141 # https://android.googlesource.com/platform/external/android-cmake/+/refs/heads/cmake-master-dev/android.toolchain.cmake
142 echo "--fix-cortex-a8" >> $out/nix-support/cc-ldflags
147 # Bionic lib C and other libraries.
149 # We use androidndk from the previous stage, else we waste time or get cycles
150 # cross-compiling packages to wrap incorrectly wrap binaries we don't include
152 libraries = runCommand "bionic-prebuilt" {} ''
153 lpath=${buildAndroidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${buildInfo.double}/sysroot/usr/lib/${targetInfo.triple}/${sdkVer}
154 if [ ! -d $lpath ]; then
155 echo "NDK does not contain libraries for SDK version ${sdkVer} <$lpath>"
159 cp $lpath/*.so $lpath/*.a $out/lib