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.
15 # There's some dragons here. Build host and target concepts are being mixed up.
16 ndkInfoFun = { config, ... }: {
17 x86_64-apple-darwin = {
18 double = "darwin-x86_64";
20 x86_64-unknown-linux-gnu = {
21 double = "linux-x86_64";
23 i686-unknown-linux-android = {
24 triple = "i686-linux-android";
27 x86_64-unknown-linux-android = {
28 triple = "x86_64-linux-android";
31 armv7a-unknown-linux-androideabi = {
33 triple = "arm-linux-androideabi";
35 aarch64-unknown-linux-android = {
37 triple = "aarch64-linux-android";
40 (throw "Android NDK doesn't support ${config}, as far as we know");
42 buildInfo = ndkInfoFun stdenv.buildPlatform;
43 hostInfo = ndkInfoFun stdenv.hostPlatform;
44 targetInfo = ndkInfoFun stdenv.targetPlatform;
46 inherit (stdenv.targetPlatform) sdkVer;
47 suffixSalt = lib.replaceStrings ["-" "."] ["_" "_"] stdenv.targetPlatform.config;
49 # targetInfo.triple is what Google thinks the toolchain should be, this is a little
50 # different from what we use. We make it four parts to conform with the existing
51 # standard more properly.
52 targetConfig = lib.optionalString (stdenv.targetPlatform != stdenv.hostPlatform) (stdenv.targetPlatform.config);
57 binaries = stdenv.mkDerivation {
58 pname = "${targetConfig}-ndk-toolchain";
59 inherit (androidndk) version;
60 nativeBuildInputs = [ makeWrapper autoPatchelfHook ];
61 propagatedBuildInputs = [ androidndk ];
63 isClang = true; # clang based cc, but bintools ld
70 autoPatchelfIgnoreMissingDeps = true;
72 # https://developer.android.com/ndk/guides/other_build_systems
74 cp -r ${androidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${buildInfo.double} $out/toolchain
75 find $out/toolchain -type d -exec chmod 777 {} \;
77 if [ ! -d $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${sdkVer} ]; then
78 echo "NDK does not contain libraries for SDK version ${sdkVer}";
82 ln -vfs $out/toolchain/sysroot/usr/lib $out/lib
83 ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/*.so $out/lib/
84 ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/*.a $out/lib/
86 ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${sdkVer}/*.so $out/lib/
87 ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${sdkVer}/*.o $out/lib/
89 echo "INPUT(-lc++_static)" > $out/lib/libc++.a
91 ln -s $out/toolchain/bin $out/bin
92 ln -s $out/toolchain/${targetInfo.triple}/bin/* $out/bin/
93 for f in $out/bin/${targetInfo.triple}-*; do
94 ln -s $f ''${f/${targetInfo.triple}-/${targetConfig}-}
96 for f in $(find $out/toolchain -type d -name ${targetInfo.triple}); do
97 ln -s $f ''${f/${targetInfo.triple}/${targetConfig}}
100 rm -f $out/bin/${targetConfig}-ld
101 ln -s $out/bin/lld $out/bin/${targetConfig}-ld
104 for tool in llvm-*; do
105 ln -sf $tool ${targetConfig}-$(echo $tool | sed 's/llvm-//')
106 ln -sf $tool $(echo $tool | sed 's/llvm-//')
109 # handle last, as llvm-as is for llvm bytecode
110 ln -sf $out/bin/${targetInfo.triple}-as $out/bin/${targetConfig}-as
111 ln -sf $out/bin/${targetInfo.triple}-as $out/bin/as
113 patchShebangs $out/bin
117 binutils = wrapBintoolsWith {
119 libc = targetAndroidndkPkgs.libraries;
124 # for packages expecting libcompiler-rt, etc. to come from here (stdenv.cc.cc.lib)
125 lib = targetAndroidndkPkgs.libraries;
128 libc = targetAndroidndkPkgs.libraries;
129 extraBuildCommands = ''
130 echo "-D__ANDROID_API__=${stdenv.targetPlatform.sdkVer}" >> $out/nix-support/cc-cflags
131 # Android needs executables linked with -pie since version 5.0
132 # Use -fPIC for compilation, and link with -pie if no -shared flag used in ldflags
133 echo "-target ${targetInfo.triple} -fPIC" >> $out/nix-support/cc-cflags
134 echo "-z,noexecstack -z,relro -z,now" >> $out/nix-support/cc-ldflags
135 echo 'if [[ ! " $@ " =~ " -shared " ]]; then NIX_LDFLAGS_${suffixSalt}+=" -pie"; fi' >> $out/nix-support/add-flags.sh
136 echo "-Xclang -mnoexecstack" >> $out/nix-support/cc-cxxflags
137 if [ ${targetInfo.triple} == arm-linux-androideabi ]; then
138 # https://android.googlesource.com/platform/external/android-cmake/+/refs/heads/cmake-master-dev/android.toolchain.cmake
139 echo "--fix-cortex-a8" >> $out/nix-support/cc-ldflags
144 # Bionic lib C and other libraries.
146 # We use androidndk from the previous stage, else we waste time or get cycles
147 # cross-compiling packages to wrap incorrectly wrap binaries we don't include
149 libraries = runCommand "bionic-prebuilt" {} ''
150 lpath=${buildAndroidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${buildInfo.double}/sysroot/usr/lib/${targetInfo.triple}/${sdkVer}
151 if [ ! -d $lpath ]; then
152 echo "NDK does not contain libraries for SDK version ${sdkVer} <$lpath>"
156 cp $lpath/*.so $lpath/*.a $out/lib