Skip to content

Commit 4a625b7

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 fce554b commit 4a625b7

14 files changed

+775
-18
lines changed

compiler/ghc/default.nix

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

4545
, enableDWARF ? false
4646

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

5151
, # Wheter to build in NUMA support
5252
enableNUMA ? true
@@ -323,7 +323,10 @@ stdenv.mkDerivation (rec {
323323
export NIX_LDFLAGS+=" -rpath $out/lib/${targetPrefix}ghc-${ghc-version}"
324324
'' + lib.optionalString stdenv.isDarwin ''
325325
export NIX_LDFLAGS+=" -no_dtrace_dof"
326-
'' + lib.optionalString targetPlatform.useAndroidPrebuilt ''
326+
'' +
327+
# we really want "+armv7-a,+soft-float,+neon" as features, but llvm will
328+
# fail with those :facepalm:
329+
lib.optionalString targetPlatform.useAndroidPrebuilt ''
327330
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
328331
'' + lib.optionalString targetPlatform.isMusl ''
329332
echo "patching llvm-targets for musl targets..."
@@ -393,7 +396,7 @@ stdenv.mkDerivation (rec {
393396
++ lib.optional stdenv.targetPlatform.isAarch32 "pic"
394397
++ lib.optional stdenv.targetPlatform.isMusl "pie";
395398

396-
postInstall = lib.optionalString (enableNUMA && targetPlatform.isLinux) ''
399+
postInstall = lib.optionalString (enableNUMA && targetPlatform.isLinux && !targetPlatform.isAarch32 && !targetPlatform.isAndroid) ''
397400
# Patch rts.conf to ensure libnuma can be found
398401
399402
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
@@ -467,8 +467,8 @@ let
467467
cabal.project.freeze
468468
chmod +w cabal.project.freeze
469469
''}
470-
export SSL_CERT_FILE=${cacert}/etc/ssl/certs/ca-bundle.crt
471-
export GIT_SSL_CAINFO=${cacert}/etc/ssl/certs/ca-bundle.crt
470+
export SSL_CERT_FILE=${evalPackages.cacert}/etc/ssl/certs/ca-bundle.crt
471+
export GIT_SSL_CAINFO=${evalPackages.cacert}/etc/ssl/certs/ca-bundle.crt
472472
473473
echo "Using index-state ${index-state-found}"
474474
CABAL_DIR=${

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: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,9 @@ in {
150150
++ fromUntil "8.10.2" "8.10.3" ./patches/ghc/MR3714-backported-to-8.10.2.patch
151151

152152
# See https://github.com/input-output-hk/haskell.nix/issues/1027
153+
++ final.lib.optional (versionAtLeast "8.10.3" && versionLessThan "9.2" && final.stdenv.targetPlatform.isAarch32) ./patches/ghc/ghc-8.10-3434-armv7a.patch
153154
++ final.lib.optional (versionAtLeast "8.10.3" && versionLessThan "9.2" && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/ghc-8.10-3434.patch
154-
++ final.lib.optional (versionAtLeast "9.2.1" && versionLessThan "9.3" && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/ghc-9.2-3434.patch
155+
++ 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
155156

156157
++ fromUntil "8.10.1" "9.4" ./patches/ghc/ghc-acrt-iob-func.patch
157158
++ fromUntil "8.10.1" "9.4" ./patches/ghc/ghc-mprotect-nonzero-len.patch
@@ -186,18 +187,28 @@ in {
186187
++ fromUntil "9.6.1" "9.8" ./patches/ghc/MR10116.patch
187188
++ fromUntil "9.4.1" "9.6" ./patches/ghc/hadrian-build-deriveConstants-genprimopcode-ghc94.patch
188189
++ fromUntil "9.6.1" "9.8" ./patches/ghc/hadrian-build-deriveConstants-genprimopcode.patch
190+
++ final.lib.optional (versionAtLeast "8.10" && versionLessThan "9.4" && final.stdenv.targetPlatform != final.stdenv.hostPlatform) ./patches/ghc/ghc-make-stage-1-lib-ghc.patch
189191

190192
# the following is a partial reversal of https://gitlab.haskell.org/ghc/ghc/-/merge_requests/4391, to address haskell.nix#1227
191193
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/mmap-next.patch
192194
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/m32_alloc.patch
195+
196+
# Android
193197
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid) ./patches/ghc/rts-android-jemalloc-qemu.patch
194198
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid) ./patches/ghc/stack-protector-symbols.patch
195-
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid) ./patches/ghc/libraries-prim-os-android.patch
199+
++ 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
200+
++ 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
196201
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid) ./patches/ghc/ghc-rts-linker-condbr.patch
197-
++ 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
198-
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid) ./patches/ghc/libc-memory-symbols.patch
202+
# due to mmap-next renaming we need different ones for aarch64 and aarch32 m(
203+
++ 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
204+
++ 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
205+
++ 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
206+
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/libc-memory-symbols.patch
199207
++ final.lib.optional (versionAtLeast "8.10.6" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAndroid) ./patches/ghc/android-base-needs-iconv.patch
200-
++ final.lib.optional (versionAtLeast "8.10" && versionLessThan "9.4" && final.stdenv.targetPlatform != final.stdenv.hostPlatform) ./patches/ghc/ghc-make-stage-1-lib-ghc.patch
208+
++ 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
209+
++ 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
210+
++ 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
211+
++ 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
201212
;
202213
in ({
203214
ghc865 = final.callPackage ../compiler/ghc (traceWarnOld "8.6" {

overlays/linux-cross.nix

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,22 @@ in
2727
let
2828

2929
# we want this to hold only for arm (32 and 64bit) for now.
30+
# For 32bit android, we need to pass -no-pie, as we otherwise
31+
# get -pie injected into the linker flags. We don't want that.
32+
# If we target 32bit android, we need remote-iserv to be runnable
33+
# in a 32bit linux (via qemu-arm user mode emulation). If we have
34+
# -pie enabled, it will produce a static-pie executable, which
35+
# seems a lot like what we want but will crash on launch. It appears
36+
# the the __stack_chk_guard lookups go through some lookup table, and
37+
# while the relocations for the lookup table are correct, the __stack_chk_guard
38+
# address isn't properly relocated. This could also be because libc isn't
39+
# supposed to be staticlly linked really. However because we are lacking
40+
# the loader for arm on linux, we can't used dynamically linked executables
41+
# until one in /system/bin/linker is provided.
42+
#
43+
# We also need to run armv7a-android in unshare --user --pid --fork, to
44+
# ensure that we get a low pid < 65535 for android (If we run outside)
45+
# of nix build envs.
3046
isLinuxCross = buildPlatform != hostPlatform && hostPlatform.isLinux && (hostPlatform.isAarch32 || hostPlatform.isAarch64);
3147
qemuIservWrapper = writeScriptBin "iserv-wrapper" ''
3248
#!${stdenv.shell}
@@ -35,7 +51,7 @@ let
3551
unset configureFlags
3652
PORT=$((5000 + $RANDOM % 5000))
3753
(>&2 echo "---> Starting ${iserv-proxy-interpreter.exeName} on port $PORT")
38-
${qemu}/bin/qemu-${qemuSuffix} ${iserv-proxy-interpreter.override (lib.optionalAttrs hostPlatform.isAndroid { setupBuildFlags = ["--ghc-option=-optl-static" ];})}/bin/${iserv-proxy-interpreter.exeName} tmp $PORT &
54+
${qemu}/bin/qemu-${qemuSuffix} ${iserv-proxy-interpreter.override (lib.optionalAttrs hostPlatform.isAndroid { setupBuildFlags = ["--ghc-option=-optl-static" ] ++ lib.optional hostPlatform.isAarch32 "--ghc-option=-optl-no-pie";})}/bin/remote-iserv tmp $PORT &
3955
(>&2 echo "---| ${iserv-proxy-interpreter.exeName} should have started on $PORT")
4056
RISERV_PID="$!"
4157
${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)