nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{
2 config,
3 lib,
4 stdenv,
5 makeWrapper,
6 runCommand,
7 wrapBintoolsWith,
8 wrapCCWith,
9 autoPatchelfHook,
10 llvmPackages,
11 buildAndroidndk,
12 androidndk,
13 targetAndroidndkPkgs,
14}:
15
16let
17 # Mapping from a platform to information needed to unpack NDK stuff for that
18 # platform.
19 #
20 # N.B. The Android NDK uses slightly different LLVM-style platform triples
21 # than we do. We don't just use theirs because ours are less ambiguous and
22 # some builds need that clarity.
23 #
24 ndkBuildInfoFun =
25 fallback:
26 {
27 x86_64-apple-darwin = {
28 double = "darwin-x86_64";
29 };
30 x86_64-unknown-linux-gnu = {
31 double = "linux-x86_64";
32 };
33 }
34 .${stdenv.buildPlatform.config} or fallback;
35
36 ndkTargetInfoFun =
37 fallback:
38 {
39 i686-unknown-linux-android = {
40 triple = "i686-linux-android";
41 arch = "x86";
42 };
43 x86_64-unknown-linux-android = {
44 triple = "x86_64-linux-android";
45 arch = "x86_64";
46 };
47 armv7a-unknown-linux-androideabi = {
48 arch = "arm";
49 triple = "arm-linux-androideabi";
50 };
51 aarch64-unknown-linux-android = {
52 arch = "arm64";
53 triple = "aarch64-linux-android";
54 };
55 }
56 .${stdenv.targetPlatform.config} or fallback;
57
58 buildInfo = ndkBuildInfoFun (
59 throw "Android NDK doesn't support building on ${stdenv.buildPlatform.config}, as far as we know"
60 );
61 targetInfo = ndkTargetInfoFun (
62 throw "Android NDK doesn't support targetting ${stdenv.targetPlatform.config}, as far as we know"
63 );
64
65 androidSdkVersion =
66 if
67 (stdenv.targetPlatform ? androidSdkVersion && stdenv.targetPlatform.androidSdkVersion != null)
68 then
69 stdenv.targetPlatform.androidSdkVersion
70 else
71 (throw "`androidSdkVersion` is not set during the importing of nixpkgs");
72 suffixSalt = lib.replaceStrings [ "-" "." ] [ "_" "_" ] stdenv.targetPlatform.config;
73
74 # targetInfo.triple is what Google thinks the toolchain should be, this is a little
75 # different from what we use. We make it four parts to conform with the existing
76 # standard more properly.
77 targetPrefix = lib.optionalString (stdenv.targetPlatform != stdenv.hostPlatform) (
78 stdenv.targetPlatform.config + "-"
79 );
80in
81
82if !config.allowAliases && (ndkBuildInfoFun null == null || ndkTargetInfoFun null == null) then
83 # Don't throw without aliases to not break CI.
84 null
85else
86 lib.recurseIntoAttrs rec {
87 # Misc tools
88 binaries = stdenv.mkDerivation {
89 pname = "${targetPrefix}ndk-toolchain";
90 inherit (androidndk) version;
91 nativeBuildInputs = [
92 makeWrapper
93 autoPatchelfHook
94 ];
95 propagatedBuildInputs = [ androidndk ];
96 passthru = {
97 inherit targetPrefix;
98 isClang = true; # clang based cc, but bintools ld
99 inherit (llvmPackages.clang.cc) hardeningUnsupportedFlagsByTargetPlatform;
100 };
101 dontUnpack = true;
102 dontBuild = true;
103 dontStrip = true;
104 dontConfigure = true;
105 dontPatch = true;
106 autoPatchelfIgnoreMissingDeps = true;
107 installPhase = ''
108 # https://developer.android.com/ndk/guides/other_build_systems
109 mkdir -p $out
110 cp -r ${androidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${buildInfo.double} $out/toolchain
111 find $out/toolchain -type d -exec chmod 777 {} \;
112
113 if [ ! -d $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${androidSdkVersion} ]; then
114 echo "NDK does not contain libraries for SDK version ${androidSdkVersion}";
115 exit 1
116 fi
117
118 ln -vfs $out/toolchain/sysroot/usr/lib $out/lib
119 ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/*.so $out/lib/
120 ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/*.a $out/lib/
121 chmod +w $out/lib/*
122 ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${androidSdkVersion}/*.so $out/lib/
123 ln -s $out/toolchain/sysroot/usr/lib/${targetInfo.triple}/${androidSdkVersion}/*.o $out/lib/
124
125 echo "INPUT(-lc++_static)" > $out/lib/libc++.a
126
127 ln -s $out/toolchain/bin $out/bin
128 ln -s $out/toolchain/${targetInfo.triple}/bin/* $out/bin/
129 for f in $out/bin/${targetInfo.triple}-*; do
130 ln -s $f ''${f/${targetInfo.triple}-/${targetPrefix}}
131 done
132 for f in $(find $out/toolchain -type d -name ${targetInfo.triple}); do
133 ln -s $f ''${f/${targetInfo.triple}/${targetPrefix}}
134 done
135
136 rm -f $out/bin/${targetPrefix}ld
137 ln -s $out/bin/lld $out/bin/${targetPrefix}ld
138
139 (cd $out/bin;
140 for tool in llvm-*; do
141 ln -sf $tool ${targetPrefix}$(echo $tool | sed 's/llvm-//')
142 ln -sf $tool $(echo $tool | sed 's/llvm-//')
143 done)
144
145 ln -sf $out/bin/yasm $out/bin/${targetPrefix}as
146 ln -sf $out/bin/yasm $out/bin/as
147
148 patchShebangs $out/bin
149 '';
150 meta = {
151 description = "Android NDK toolchain, tuned for other platforms";
152 license = with lib.licenses; [ unfree ];
153 teams = [ lib.teams.android ];
154 };
155 };
156
157 binutils = wrapBintoolsWith {
158 bintools = binaries;
159 libc = targetAndroidndkPkgs.libraries;
160 };
161
162 clang = wrapCCWith {
163 cc = binaries // {
164 # for packages expecting libcompiler-rt, etc. to come from here (stdenv.cc.cc.lib)
165 lib = targetAndroidndkPkgs.libraries;
166 };
167 bintools = binutils;
168 libc = targetAndroidndkPkgs.libraries;
169 extraBuildCommands = ''
170 echo "-D__ANDROID_API__=${stdenv.targetPlatform.androidSdkVersion}" >> $out/nix-support/cc-cflags
171 # Android needs executables linked with -pie since version 5.0
172 # Use -fPIC for compilation, and link with -pie if no -shared flag used in ldflags
173 echo "-target ${targetInfo.triple} -fPIC" >> $out/nix-support/cc-cflags
174 echo "-z,noexecstack -z,relro -z,now -z,muldefs" >> $out/nix-support/cc-ldflags
175 echo 'expandResponseParams "$@"' >> $out/nix-support/add-flags.sh
176 echo 'if [[ ! (" ''${params[@]} " =~ " -shared ") && ! (" ''${params[@]} " =~ " -no-pie ") ]]; then NIX_LDFLAGS_${suffixSalt}+=" -pie"; fi' >> $out/nix-support/add-flags.sh
177 echo "-Xclang -mnoexecstack" >> $out/nix-support/cc-cxxflags
178 if [ ${targetInfo.triple} == arm-linux-androideabi ]; then
179 # https://android.googlesource.com/platform/external/android-cmake/+/refs/heads/cmake-master-dev/android.toolchain.cmake
180 echo "--fix-cortex-a8" >> $out/nix-support/cc-ldflags
181 fi
182 '';
183 };
184
185 # Bionic lib C and other libraries.
186 #
187 # We use androidndk from the previous stage, else we waste time or get cycles
188 # cross-compiling packages to wrap incorrectly wrap binaries we don't include
189 # anyways.
190 libraries = runCommand "bionic-prebuilt" { } ''
191 lpath=${buildAndroidndk}/libexec/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/${buildInfo.double}/sysroot/usr/lib/${targetInfo.triple}/${androidSdkVersion}
192 if [ ! -d $lpath ]; then
193 echo "NDK does not contain libraries for SDK version ${androidSdkVersion} <$lpath>"
194 exit 1
195 fi
196 mkdir -p $out/lib
197 cp $lpath/*.so $lpath/*.a $out/lib
198 chmod +w $out/lib/*
199 cp $lpath/* $out/lib
200 '';
201 }