Skip to content

Commit 939365b

Browse files
committed
Support for armv7a-bionic (android)
This adds support to haskell.nix for building for armv7a-android. It includes - various minor fixes - a lot of bionic (libc) patches for ghc - no gold on 32bit android - android overlay: mostly static - disable KTLS on openssl for android
1 parent d489996 commit 939365b

14 files changed

+780
-17
lines changed

compiler/ghc/default.nix

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ let self =
4545

4646
, enableDWARF ? false
4747

48-
, enableTerminfo ?
48+
, enableTerminfo ? !stdenv.targetPlatform.isAndroid &&
4949
# Terminfo does not work on older ghc cross arm and windows compilers
50-
(!haskell-nix.haskellLib.isCrossTarget || !(stdenv.targetPlatform.isAarch64 || stdenv.targetPlatform.isWindows) || builtins.compareVersions ghc-version "8.10" >= 0)
50+
(!haskell-nix.haskellLib.isCrossTarget || !(stdenv.targetPlatform.isAarch32 || stdenv.targetPlatform.isAarch64 || stdenv.targetPlatform.isWindows) || builtins.compareVersions ghc-version "8.10" >= 0)
5151

5252
, # Wheter to build in NUMA support
5353
enableNUMA ? true
@@ -426,7 +426,10 @@ stdenv.mkDerivation (rec {
426426
export NIX_LDFLAGS+=" -rpath $out/lib/${targetPrefix}ghc-${ghc-version}"
427427
'' + lib.optionalString stdenv.isDarwin ''
428428
export NIX_LDFLAGS+=" -no_dtrace_dof"
429-
'' + lib.optionalString targetPlatform.useAndroidPrebuilt ''
429+
'' +
430+
# we really want "+armv7-a,+soft-float,+neon" as features, but llvm will
431+
# fail with those :facepalm:
432+
lib.optionalString targetPlatform.useAndroidPrebuilt ''
430433
sed -i -e '5i ,("armv7a-unknown-linux-androideabi", ("e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64", "cortex-a8", ""))' llvm-targets
431434
'' + lib.optionalString targetPlatform.isMusl ''
432435
echo "patching llvm-targets for musl targets..."
@@ -501,7 +504,7 @@ stdenv.mkDerivation (rec {
501504
++ lib.optional stdenv.targetPlatform.isMusl "pie"
502505
++ lib.optional enableDWARF "fortify";
503506

504-
postInstall = lib.optionalString (enableNUMA && targetPlatform.isLinux) ''
507+
postInstall = lib.optionalString (enableNUMA && targetPlatform.isLinux && !targetPlatform.isAarch32 && !targetPlatform.isAndroid) ''
505508
# Patch rts.conf to ensure libnuma can be found
506509
507510
for file in $(find "$out/lib" -name "rts*.conf"); do

lib/call-cabal-project-to-nix.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,8 +437,8 @@ let
437437
cabal.project.freeze
438438
chmod +w cabal.project.freeze
439439
''}
440-
export SSL_CERT_FILE=${cacert}/etc/ssl/certs/ca-bundle.crt
441-
export GIT_SSL_CAINFO=${cacert}/etc/ssl/certs/ca-bundle.crt
440+
export SSL_CERT_FILE=${evalPackages.cacert}/etc/ssl/certs/ca-bundle.crt
441+
export GIT_SSL_CAINFO=${evalPackages.cacert}/etc/ssl/certs/ca-bundle.crt
442442
443443
CABAL_DIR=${
444444
# This creates `.cabal` directory that is as it would have

overlays/android.nix

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,31 @@ _final: prev: prev.lib.optionalAttrs prev.stdenv.hostPlatform.isAndroid ({
1111
'';
1212
# my current thinking is that this is due to the android toolchain using r23, api30.
1313
});
14-
libffi = prev.libffi.overrideAttrs (_: {
14+
libffi = prev.libffi.overrideAttrs ( old: {
1515
dontDisableStatic = true;
16+
configureFlags = old.configureFlags ++ [ "--disable-shared" ];
1617

1718
hardeningDisable = [ "fortify" "stackprotector" "format" ];
19+
} // prev.lib.optionalAttrs (prev.stdenv.hostPlatform.isAarch32 || prev.stdenv.hostPlatform.isAarch64) {
1820
# see libiconv. We want to target a lower minsdk
1921
postConfigure = ''
20-
echo "#undef HAVE_MEMFD_CREATE" >> aarch64-unknown-linux-android/fficonfig.h
22+
echo "#undef HAVE_MEMFD_CREATE" >> ${prev.stdenv.hostPlatform.config}/fficonfig.h
2123
'';
2224
});
23-
gmp6 = (prev.gmp6.override { withStatic = true; }).overrideAttrs(_: {
25+
gmp6 = (prev.gmp6.override { withStatic = true; }).overrideAttrs(old: {
2426
hardeningDisable = [ "fortify" "stackprotector" "format" ];
27+
configureFlags = old.configureFlags ++ [ "--disable-shared" ];
2528
});
29+
zlib = prev.zlib.override { shared = false; static = true; };
30+
# kernel tls (ktls) doesn't work with the android kernel. And will complain
31+
# about lots of implicitly declared functions and undeclared identifiers,
32+
# because the android (linux) kernel doesn't expose those.
33+
openssl = prev.openssl.override { static = true; enableKTLS = false; };
34+
2635
}) // prev.lib.optionalAttrs prev.stdenv.targetPlatform.isAndroid ({
27-
bionic = prev.bionic.override { enableStatic = true; };
36+
# we still need the shared libraries to link against on the platform. GHC
37+
# has been neutered to not even try loading shared libs and will use dynamic ones.
38+
# We also link iserv against the static libs, so that we have a fully static
39+
# android (bionic/linux) iserv we can execute on glibc/linux.
40+
bionic = prev.bionic.override { enableStatic = true; enableShared = true; };
2841
})

overlays/bootstrap.nix

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,9 @@ in {
163163
++ fromUntil "8.10.2" "8.10.3" ./patches/ghc/MR3714-backported-to-8.10.2.patch
164164

165165
# See https://github.com/input-output-hk/haskell.nix/issues/1027
166+
++ final.lib.optional (versionAtLeast "8.10.3" && versionLessThan "9.2" && final.stdenv.targetPlatform.isAarch32) ./patches/ghc/ghc-8.10-3434-armv7a.patch
166167
++ final.lib.optional (versionAtLeast "8.10.3" && versionLessThan "9.2" && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/ghc-8.10-3434.patch
167-
++ final.lib.optional (versionAtLeast "9.2.1" && versionLessThan "9.3" && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/ghc-9.2-3434.patch
168+
++ final.lib.optional (versionAtLeast "9.2.1" && versionLessThan "9.3" && (final.stdenv.targetPlatform.isAarch64 || final.stdenv.targetPlatform.isAndroid)) ./patches/ghc/ghc-9.2-3434.patch
168169

169170
++ fromUntil "8.10.1" "9.4" ./patches/ghc/ghc-acrt-iob-func.patch
170171
++ fromUntil "8.10.1" "9.2" ./patches/ghc/ghc-mprotect-nonzero-len.patch
@@ -247,16 +248,27 @@ in {
247248
++ final.lib.optionals (final.stdenv.targetPlatform.isGhcjs) (fromUntil "9.6.3" "9.8" ./patches/ghc/ghc-9.6.3-JS-implement-TH-support.patch)
248249
++ fromUntil "9.8.1" "9.8.2" ./patches/ghc/ghc-9.8-cabal-c-soures-fix.patch
249250
++ fromUntil "9.6.3" "9.9" ./patches/ghc/ghc-9.6.3-Cabal-9384.patch
251+
++ final.lib.optionals (final.stdenv.targetPlatform.isWindows) (fromUntil "9.4.1" "9.5" ./patches/ghc/ghc-9.4-hadrian-win-cross.patch)
252+
++ fromUntil "9.6.1" "9.8" ./patches/ghc/MR10116.patch
253+
++ fromUntil "9.4.1" "9.6" ./patches/ghc/hadrian-build-deriveConstants-genprimopcode-ghc94.patch
254+
++ fromUntil "9.6.1" "9.8" ./patches/ghc/hadrian-build-deriveConstants-genprimopcode.patch
255+
++ final.lib.optional (versionAtLeast "8.10" && versionLessThan "9.4" && final.stdenv.targetPlatform != final.stdenv.hostPlatform) ./patches/ghc/ghc-make-stage-1-lib-ghc.patch
250256

251257
# the following is a partial reversal of https://gitlab.haskell.org/ghc/ghc/-/merge_requests/4391, to address haskell.nix#1227
252258
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/mmap-next.patch
253259
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/m32_alloc.patch
260+
261+
# Android
254262
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid) ./patches/ghc/rts-android-jemalloc-qemu.patch
255263
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid) ./patches/ghc/stack-protector-symbols.patch
256-
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid) ./patches/ghc/libraries-prim-os-android.patch
264+
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid && final.stdenv.targetPlatform.isAarch32) ./patches/ghc/libraries-prim-os-android-armv7a.patch
265+
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/libraries-prim-os-android.patch
257266
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid) ./patches/ghc/ghc-rts-linker-condbr.patch
258-
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid) ./patches/ghc/ghc-8.10.7-linker-weak-and-common.patch
259-
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid) ./patches/ghc/libc-memory-symbols.patch
267+
# due to mmap-next renaming we need different ones for aarch64 and aarch32 m(
268+
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid && final.stdenv.targetPlatform.isAarch32) ./patches/ghc/ghc-8.10.7-linker-weak-and-common-armv7a.patch
269+
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/ghc-8.10.7-linker-weak-and-common.patch
270+
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid && final.stdenv.targetPlatform.isAarch32) ./patches/ghc/libc-memory-symbols-armv7a.patch
271+
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/libc-memory-symbols.patch
260272
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid) ./patches/ghc/android-base-needs-iconv.patch
261273
++ final.lib.optional (versionAtLeast "8.10" && versionLessThan "9.4" && final.stdenv.targetPlatform != final.stdenv.hostPlatform) ./patches/ghc/ghc-make-stage-1-lib-ghc.patch
262274
++ final.lib.optional (versionAtLeast "8.10" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/ghc-8.10-better-symbol-addr-debug.patch
@@ -274,6 +286,10 @@ in {
274286
# Fix the bad fixups: https://gitlab.haskell.org/ghc/ghc/-/commit/2adc050857a9c1b992040fbfd55fbe65b2851b19
275287
++ final.lib.optional (versionAtLeast "9.6" && versionLessThan "9.6.4" && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/2adc050857a9c1b992040fbfd55fbe65b2851b19.patch
276288
++ final.lib.optional (versionAtLeast "8.10.7" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAarch64 && final.stdenv.targetPlatform.isMusl && final.stdenv.targetPlatform != final.stdenv.hostPlatform) ./patches/ghc/ghc-8.10-aarch64-musl-gettimeofday.patch
289+
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.2" && final.stdenv.targetPlatform.isAndroid && final.stdenv.targetPlatform.isAarch32) ./patches/ghc/ghc-8.10-android.patch
290+
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.2" && final.stdenv.targetPlatform.isAndroid && final.stdenv.targetPlatform.isAarch32) ./patches/ghc/ghc-8.10.7-android-bionic-symbols.patch
291+
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.2" && final.stdenv.targetPlatform.isAndroid && final.stdenv.targetPlatform.isAarch32) ./patches/ghc/ghc-8.10.7-bionic-libc.patch
292+
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.2" && final.stdenv.targetPlatform.isAndroid && final.stdenv.targetPlatform.isAarch32) ./patches/ghc/ghc-8.10.7-cross-dont-build-stage2-tools.patch
277293
;
278294
in ({
279295
ghc865 = final.callPackage ../compiler/ghc (traceWarnOld "8.6" {

overlays/linux-cross.nix

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,22 @@
1313
, ...
1414
}:
1515
let
16+
# For 32bit android, we need to pass -no-pie, as we otherwise
17+
# get -pie injected into the linker flags. We don't want that.
18+
# If we target 32bit android, we need remote-iserv to be runnable
19+
# in a 32bit linux (via qemu-arm user mode emulation). If we have
20+
# -pie enabled, it will produce a static-pie executable, which
21+
# seems a lot like what we want but will crash on launch. It appears
22+
# the the __stack_chk_guard lookups go through some lookup table, and
23+
# while the relocations for the lookup table are correct, the __stack_chk_guard
24+
# address isn't properly relocated. This could also be because libc isn't
25+
# supposed to be staticlly linked really. However because we are lacking
26+
# the loader for arm on linux, we can't used dynamically linked executables
27+
# until one in /system/bin/linker is provided.
28+
#
29+
# We also need to run armv7a-android in unshare --user --pid --fork, to
30+
# ensure that we get a low pid < 65535 for android (If we run outside)
31+
# of nix build envs.
1632

1733
# we want this to hold only for arm (32 and 64bit) for now.
1834
isLinuxCross = haskellLib.isCrossHost && hostPlatform.isLinux && (hostPlatform.isAarch32 || hostPlatform.isAarch64);
@@ -24,12 +40,13 @@ let
2440
else iserv-proxy-interpreter;
2541
in
2642
writeShellScriptBin ("iserv-wrapper" + lib.optionalString enableProfiling "-prof") ''
43+
#!${stdenv.shell}
2744
set -euo pipefail
2845
# Unset configure flags as configure should have run already
2946
unset configureFlags
3047
PORT=$((5000 + $RANDOM % 5000))
3148
(>&2 echo "---> Starting ${interpreter.exeName} on port $PORT")
32-
${qemu}/bin/qemu-${qemuSuffix} ${interpreter.override (lib.optionalAttrs hostPlatform.isAndroid { setupBuildFlags = ["--ghc-option=-optl-static" ];})}/bin/${interpreter.exeName} tmp $PORT &
49+
${qemu}/bin/qemu-${qemuSuffix} ${interpreter.override (lib.optionalAttrs hostPlatform.isAndroid { setupBuildFlags = ["--ghc-option=-optl-static" ] ++ lib.optional hostPlatform.isAarch32 "--ghc-option=-optl-no-pie";})}/bin/${interpreter.exeName} tmp $PORT &
3350
(>&2 echo "---| ${interpreter.exeName} should have started on $PORT")
3451
RISERV_PID="$!"
3552
${iserv-proxy}/bin/iserv-proxy $@ 127.0.0.1 "$PORT"
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
diff --git a/libraries/ghc-prim/ghc-prim.cabal b/libraries/ghc-prim/ghc-prim.cabal
2+
index c633124..2bd51c0 100644
3+
--- a/libraries/ghc-prim/ghc-prim.cabal
4+
+++ b/libraries/ghc-prim/ghc-prim.cabal
5+
@@ -70,7 +70,7 @@ Library
6+
if os(linux)
7+
-- we need libm, but for musl and other's we might need libc, as libm
8+
-- is just an empty shell.
9+
- extra-libraries: c, m
10+
+ extra-libraries: c, m
11+
12+
c-sources:
13+
cbits/atomic.c
14+
diff --git a/rts/RtsSymbols.c b/rts/RtsSymbols.c
15+
index 9ca696c..b4a85e5 100644
16+
--- a/rts/RtsSymbols.c
17+
+++ b/rts/RtsSymbols.c
18+
@@ -1000,6 +1000,18 @@
19+
#define RTS_LIBGCC_SYMBOLS
20+
#endif
21+
22+
+
23+
+#if !defined(DYNAMIC) && defined(linux_HOST_OS)
24+
+// we need these for static musl builds. However when
25+
+// linking shared objects (DLLs) this will fail, hence
26+
+// we do not include them when building with -DDYNAMIC
27+
+#define RTS_LINKER_SYMBOLS \
28+
+ SymI_NeedsProto(__fini_array_start) \
29+
+ SymI_NeedsProto(__fini_array_end)
30+
+#else
31+
+#define RTS_LINKER_SYMBOLS
32+
+#endif
33+
+
34+
/* entirely bogus claims about types of these symbols */
35+
#define SymI_NeedsProto(vvv) extern void vvv(void);
36+
#define SymI_NeedsDataProto(vvv) extern StgWord vvv[];
37+
@@ -1028,6 +1040,7 @@ RTS_DARWIN_ONLY_SYMBOLS
38+
RTS_OPENBSD_ONLY_SYMBOLS
39+
RTS_LIBGCC_SYMBOLS
40+
RTS_LIBFFI_SYMBOLS
41+
+RTS_LINKER_SYMBOLS
42+
#undef SymI_NeedsProto
43+
#undef SymI_NeedsDataProto
44+
#undef SymI_HasProto
45+
@@ -1068,6 +1081,8 @@ RTS_LIBFFI_SYMBOLS
46+
#define SymI_HasProto_deprecated(vvv) \
47+
{ #vvv, (void*)0xBAADF00D, true },
48+
49+
+void *RTS_DYNAMIC = NULL;
50+
+
51+
RtsSymbolVal rtsSyms[] = {
52+
RTS_SYMBOLS
53+
RTS_RET_SYMBOLS
54+
@@ -1078,6 +1093,7 @@ RtsSymbolVal rtsSyms[] = {
55+
RTS_OPENBSD_ONLY_SYMBOLS
56+
RTS_LIBGCC_SYMBOLS
57+
RTS_LIBFFI_SYMBOLS
58+
+ RTS_LINKER_SYMBOLS
59+
SymI_HasDataProto(nonmoving_write_barrier_enabled)
60+
#if defined(darwin_HOST_OS) && defined(i386_HOST_ARCH)
61+
// dyld stub code contains references to this,
62+
@@ -1085,5 +1101,6 @@ RtsSymbolVal rtsSyms[] = {
63+
// lazy pointers as nonlazy.
64+
{ "dyld_stub_binding_helper", (void*)0xDEADBEEF, false },
65+
#endif
66+
+ { "_DYNAMIC", (void*)(&RTS_DYNAMIC), false },
67+
{ 0, 0, false } /* sentinel */
68+
};

0 commit comments

Comments
 (0)