Skip to content

Commit

Permalink
Merge pull request #804 from reflex-frp/nixpkgs-unstable
Browse files Browse the repository at this point in the history
Add support for aarch64-darwin and aarch64-linux (uses nixpkgs-22.11)
  • Loading branch information
ali-abrar authored Dec 6, 2023
2 parents 7e35474 + d8d4baf commit f231e24
Show file tree
Hide file tree
Showing 23 changed files with 346 additions and 105 deletions.
10 changes: 10 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

This project's release branch is `master`. This log is written from the perspective of the release branch: when changes hit `master`, they are considered released.

## v1.2.0.0

* Add support for aarch64-darwin (apple silicon macs) and aarch64-linux. See [docs/platform-support.md](./docs/platform-support.md) for more information about what's supported and what isn't on each platform.
* nixpkgs updated to 22.11
* *Breaking change*: Disable webkit2gtk backend for reflex-dom by default. To enable it, use the useWebkit2Gtk flag in `default.nix`.
* *Breaking change*: Remove deprecated cabal2nixResult
* Haskell Libraries Updates
* reflex-dom 0.6.3.1
* ios: Update ios-deploy to v1.12.2

## v1.1.2.0 - 2023-09-07

* Haskell Libraries Updated
Expand Down
30 changes: 24 additions & 6 deletions android/impl.nix
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
env: with env;
let overrideAndroidCabal = package: overrideCabal package (drv: {
preConfigure = (drv.preConfigure or "") + ''
sed -i 's%^executable *\(.*\)$%executable lib\1.so\n cc-options: -shared -fPIC\n ld-options: -shared -Wl,--gc-sections,--version-script=${./haskellActivity.version},-u,Java_systems_obsidian_HaskellActivity_haskellStartMain,-u,hs_main\n ghc-options: -shared -fPIC -threaded -no-hs-main -lHSrts_thr -lffi -lm -llog%i' *.cabal
# -Wl,--unresolved-symbols=ignore-in-object-files
preConfigure = (drv.preConfigure or "") + ''
export NIX_CFLAGS_LINK="-no-pie -v"
sed -i 's%^executable *\(.*\)$%executable lib\1.so\n cc-options: -no-pie -shared -fPIC\n ld-options: -no-pie -shared -Wl,--gc-sections,--version-script=${./haskellActivity.version},-u,Java_systems_obsidian_HaskellActivity_haskellStartMain,-u,hs_main\n ghc-options: -fPIC -shared -no-pie -threaded -no-hs-main -lHSrts_thr -lffi -lm -llog%i' *.cabal
'';
});
# -no-hs-main
configureFlags = (drv.configureFlags or []) ++ [
"--enable-shared"
];
});
/*
overrideAndroidCabal = package: overrideCabal package (drv: {
preConfigure = ''
export NIX_CFLAGS_COMPILE=""
export NIX_CFLAGS_LINK="-v -no-pie"
'';
});
*/
androidenv = nixpkgs.androidenv;
#TODO: Keep the signing key for dev mode more consistent, e.g. in ~/.config/reflex-platform, so that the app can be reinstalled in-place
addDeployScript = src: nixpkgs.runCommand "android-app" {
Expand All @@ -14,16 +28,20 @@ let overrideAndroidCabal = package: overrideCabal package (drv: {
substitute ${./deploy.sh} $out/bin/deploy \
--subst-var-by coreutils ${nixpkgs.coreutils} \
--subst-var-by adb ${androidenv.androidPkgs_9_0.platform-tools} \
--subst-var-by java ${nixpkgs.openjdk11} \
--subst-var-by java ${nixpkgs.openjdk17_headless} \
--subst-var-by out $out
chmod +x "$out/bin/deploy"
'';
buildInputs = [ androidenv.androidPkgs_9_0.androidsdk ];
} "";
buildGradleApp = import ./build-gradle-app.nix {
inherit (nixpkgs) stdenv lib jdk gnumake gawk file runCommand
which gradle fetchurl buildEnv;
inherit (nixpkgs) stdenv lib gnumake gawk file runCommand
which fetchurl buildEnv;
inherit androidenv;
gradle = nixpkgs.gradle.override {
java = nixpkgs.buildPackages.openjdk11_headless;
};
jdk = nixpkgs.buildPackages.openjdk17_headless;
};
inherit (nixpkgs.lib) splitString escapeShellArg mapAttrs attrNames concatStrings optionalString;
in {
Expand Down
110 changes: 74 additions & 36 deletions default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
, useFastWeak ? true
, useReflexOptimizer ? false
, useTextJSString ? true # Use an implementation of "Data.Text" that uses the more performant "Data.JSString" from ghcjs-base under the hood.
, useWebkit2Gtk ? false # Enable webkit2gtk to build reflex-dom desktop apps
, __useTemplateHaskell ? true # Deprecated, just here until we remove feature from reflex and stop CIing it
, __useNewerCompiler ? true
, iosSdkVersion ? "16.1"
Expand All @@ -19,6 +20,7 @@

let iosSupport = system == "x86_64-darwin";
androidSupport = lib.elem system [ "x86_64-linux" ];
ghc86Support = lib.elem system ["x86_64-linux" "x86_64-darwin"];

xcodeVer = {
"16.1" = "14.1";
Expand Down Expand Up @@ -49,13 +51,19 @@ let iosSupport = system == "x86_64-darwin";
bootPkgs = super.haskell.packages.ghc865Binary // {
happy = super.haskell.packages.ghc865Binary.happy_1_19_12;
};
useLdGold = !(self.stdenv.targetPlatform.isAarch32) && self.stdenv.hostPlatform.useAndroidPrebuilt;
enableDocs = false;
enableHaddockProgram = false;
};
ghcSplices-8_10 = (super.haskell.compiler.ghc8107.override {
# New option for GHC 8.10. Explicitly enable profiling builds
enableProfiledLibs = true;
bootPkgs = super.haskell.packages.ghc865Binary // {
happy = super.haskell.packages.ghc865Binary.happy_1_19_12;
};
#enableShared = self.stdenv.hostPlatform == self.stdenv.targetPlatform;
#enableShared = false;
bootPkgs = if (super.stdenv.hostPlatform.isAarch64) then (super.haskell.packages.ghc8107Binary // {
happy = super.haskell.packages.ghc8107Binary.happy_1_19_12;
}) else
(super.haskell.packages.ghc865Binary // { happy = super.haskell.packages.ghc865Binary.happy_1_19_12; });
}).overrideAttrs (drv: {
src = nixpkgs.hackGet ./haskell-overlays/splices-load-save/dep/ghc-8.10;
# When building from the ghc git repo, ./boot must be run before configuring, whereas
Expand Down Expand Up @@ -94,7 +102,8 @@ let iosSupport = system == "x86_64-darwin";
useFastWeak useReflexOptimizer enableLibraryProfiling enableTraceReflexEvents
useTextJSString enableExposeAllUnfoldings __useTemplateHaskell
haskellOverlaysPre
haskellOverlaysPost;
haskellOverlaysPost
useWebkit2Gtk;
inherit ghcSavedSplices-8_6 ghcSavedSplices-8_10;
};
};
Expand All @@ -105,13 +114,13 @@ let iosSupport = system == "x86_64-darwin";
libiconv = super.darwin.libiconv.overrideAttrs (_:
lib.optionalAttrs (self.stdenv.hostPlatform != self.stdenv.buildPlatform) {
postInstall = "rm $out/include/libcharset.h $out/include/localcharset.h";
configureFlags = ["--disable-shared" "--enable-static"];
configureFlags = ["--enable-shared" "--enable-static"];
});
};
};
zlib = super.zlib.override (lib.optionalAttrs
(self.stdenv.hostPlatform != self.stdenv.buildPlatform)
{ static = true; shared = false; });
};
{ static = true; shared = true; });
};

mobileGhcOverlay = import ./nixpkgs-overlays/mobile-ghc { inherit lib; };

Expand All @@ -120,33 +129,53 @@ let iosSupport = system == "x86_64-darwin";
nixpkgsArgs = {
inherit system;
overlays = [
(import ./nixpkgs-overlays/ghc.nix { inherit lib; })
hackGetOverlay
bindHaskellOverlays
forceStaticLibs
splicesEval
mobileGhcOverlay
allCabalHashesOverlay
(self: super: {
binutils-unwrapped = super.binutils-unwrapped.override {
autoreconfHook = lib.optional self.stdenv.buildPlatform.isDarwin super.autoreconfHook269;

runtimeShellPackage = if (self.stdenv.hostPlatform.isGhcjs || self.stdenv.targetPlatform.isiOS)
then super.buildPackages.runtimeShellPackage
else super.runtimeShellPackage;

polkit = super.polkit.override {
gobject-introspection = super.gobject-introspection-unwrapped;
};

# Bump ios-deploy
# - for faster deployments
# - fixes debug deploy with iOS 16/macos 12.3/ xcode 13.4.1
darwin = super.darwin // {
ios-deploy = super.darwin.ios-deploy.overrideAttrs (_: {
version = "HEAD";
darwin = super.darwin.overrideScope (dself: dsuper: {
ios-deploy = dsuper.ios-deploy.overrideAttrs (_: {
version = "1.12.2";
src = self.fetchFromGitHub {
owner = "ios-control";
repo = "ios-deploy";
rev = "b3254438719b6bc82ceab1f630e7d642a9acfac5"; # unreleased
sha256 = "W45Qjr3xqvDWieLBgt4//nthxxcc3hgrJNrpSk7vWj8=";
rev = "ed7de7792d28a5110242748649047a95c95ea917";
sha256 = "082w7j490khfpbv1diwrjixjbg9g93wdr2khyzdhv8xmzzwq4lad";
};
});
});
openjdk16-bootstrap = super.openjdk16-bootstrap.override {
gtkSupport = false;
};
adoptopenjdk-hotspot-bin-16 = super.adoptopenjdk-hotspot-bin-16.override {
gtkSupport = false;
};

sqlite = super.sqlite.overrideAttrs (old: lib.optionalAttrs (self.stdenv.hostPlatform.useAndroidPrebuilt or false) {
postBuild = ''
mkdir -p $debug
'';
});

libiconv = super.libiconv.overrideAttrs (old: lib.optionalAttrs (self.stdenv.hostPlatform.useAndroidPrebuilt or false) {
configureFlags = [ "--disable-shared" "--enable-static" ];
});

libffi = if (self.stdenv.hostPlatform.useAndroidPrebuilt or false) then super.libffi_3_3 else super.libffi;
})
(import ./nixpkgs-overlays/ghc.nix { inherit lib; })
] ++ nixpkgsOverlays;
config = config // {
permittedInsecurePackages = (config.permittedInsecurePackages or []) ++ [
Expand All @@ -166,24 +195,41 @@ let iosSupport = system == "x86_64-darwin";
wasmCross = nixpkgs.hackGet ./wasm-cross;
webGhcSrc = (import (wasmCross + /webghc.nix) { inherit fetchgit; }).ghc8107SplicesSrc;
nixpkgsCross = {
# NOTE(Dylan Green):
# sdkVer 30 is the minimum for android, else we have to use libffi 3.3
# bionic doesn't support/expose memfd_create before sdk30
# https://android.googlesource.com/platform/bionic/+/refs/heads/master/docs/status.md
# Look for "new libc functions in R (API Level 30):", memfd_create will be one of the functions /
# symbols we need to build newer libffi
# This means we'll drop all SDKs pre-30

# NOTE(Dylan Green):
# We don't want to use "isStatic" here as we still rely on shared-objects
# adding "isStatic" completely disables generating most SOs, and we still need them
# for libffi (at the very least). Currently the big issues are caused by the linker attempting (and failing)
# to link against a dynamic crtbegin.o (crtbegin.c) bionic does provide a static crtbegin, although the linker
# defaults to a dynamic version

# TODO(Dylan Green):
# Look into making this a proper static build up into "reflex-todomvc"
android = lib.mapAttrs (_: args: nixpkgsFunc (nixpkgsArgs // args)) rec {
aarch64 = {
crossSystem = lib.systems.examples.aarch64-android-prebuilt //
{ isStatic = true; };
sdkVer = "30";
crossSystem = lib.systems.examples.aarch64-android-prebuilt // {
#isStatic = true;
sdkVer = "30";
};
};
aarch32 = {
crossSystem = lib.systems.examples.armv7a-android-prebuilt // {
isStatic = true;
# Choose an old version so it's easier to find phones to test on
sdkVer = "23";
#isStatic = true;
sdkVer = "30";
};
};
};
ios = lib.mapAttrs (_: args: nixpkgsFunc (nixpkgsArgs // args)) rec {
simulator64 = {
crossSystem = lib.systems.examples.iphone64-simulator // {
#isStatic = true;
isStatic = true;
sdkVer = iosSdkVersion;
inherit xcodeVer;
};
Expand Down Expand Up @@ -229,12 +275,6 @@ let iosSupport = system == "x86_64-darwin";
override = new: makeRecursivelyOverridable (x.override (old: (combineOverrides old new)));
};

cabal2nixResult = src: builtins.trace "cabal2nixResult is deprecated; use ghc.haskellSrc2nix or ghc.callCabal2nix instead" (ghc.haskellSrc2nix {
name = "for-unknown-package";
src = "file://${src}";
sha256 = null;
});

ghcSavedSplices = if __useNewerCompiler then ghcSavedSplices-8_10 else ghcSavedSplices-8_6;
ghcSavedSplices-8_6 = (makeRecursivelyOverridable nixpkgs.haskell.packages.integer-simple.ghcSplices-8_6).override {
overrides = lib.foldr lib.composeExtensions (_: _: {}) (let
Expand Down Expand Up @@ -269,8 +309,7 @@ let iosSupport = system == "x86_64-darwin";
ghcjs = if __useNewerCompiler then ghcjs8_10 else ghcjs8_6;
ghcjs8_6 = (makeRecursivelyOverridable (nixpkgsCross.ghcjs.haskell.packages.ghcjs86.override (old: {
ghc = old.ghc.override {
bootPkgs = with nixpkgsCross.ghcjs.buildPackages.haskell.packages;
ghc865 // { happy = ghc865.callHackage "happy" "1.19.9" {}; };
bootPkgs = old.ghc.bootPkgs // { happy = old.ghc.bootPkgs.happy_1_19_12; };
cabal-install = import ./haskell-overlays/ghcjs-8.6/cabal-install.nix { inherit nixpkgs; };
ghcjsSrc = import ./haskell-overlays/ghcjs-8.6/src.nix {
inherit (nixpkgs.stdenvNoCC) mkDerivation;
Expand Down Expand Up @@ -514,7 +553,6 @@ in let this = rec {
cabal-install
ghcid
hasktags
hlint
stylish-haskell # Recent stylish-haskell only builds with AMP in place
reflex-ghci
;
Expand Down Expand Up @@ -589,7 +627,7 @@ in let this = rec {
iosReflexTodomvc iosSimulatorReflexTodomvc
];

inherit cabal2nixResult system androidSupport iosSupport;
inherit system androidSupport iosSupport ghc86Support;
project = args: import ./project this (args ({ pkgs = nixpkgs; } // this));
tryReflexShell = pinBuildInputs ("shell-" + system) tryReflexPackages;
ghcjsExternsJs = ./ghcjs.externs.js;
Expand Down
23 changes: 23 additions & 0 deletions docs/platform-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Supported Platforms

reflex-platform supports building *on* x86_64 and aarch64 linux and macOS systems. It supports building *for* Android, iOS, Javascript, Linux, and macOS targets.

Depending on the build system you are using, you can build for the following targets:

| | Javascript | Android | iOS | Linux x86_64 | Linux aarch64 | macOS (intel) | macOS (m1/m2) |
|---------------|------------|---------|-----|--------------|---------------|---------------|---------------|
| Linux x86_64 ||| || | | |
| Linux aarch64 || | | || | |
| macOS (intel) || || | || |
| macOS (m1/m2) || | | | | ||

* On aarch64 platforms (aarch64-linux and aarch64-darwin), we do not support ghc-8.6.5 or ghcjs-8.6.5.
* From Linux, you can't build for iOS or macOS because the apple toolchain is restricted to macOS.
* Android builds aren't yet supported from macOS.
* When building a desktop app on x86_64-linux you can use webkitgtk, but that isn't yet supported on aarch64-linux. You can, however, build your backend executable and warp-based frontend executables on either architecture.
* When building a desktop app on macOS you can use wkwebview or warp.
* 32-bit android builds are only supported via ghc-8.6.5 because later versions of ghc don't support that platform.

## Binary Caches

Binary caches are provided for x86_64-linux, x86_64-darwin, and aarch64-darwin. We will be adding an aarch64-linux cache in the future.
11 changes: 6 additions & 5 deletions docs/project-development.rst
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,12 @@ Building the frontend with GHC can drastically speed up build times, and
enables you to test from GHCi for even faster reloads.

JSaddle is a set of libraries that allows Reflex-DOM to swap out its
JavaScript backend easily. By default, Reflex-DOM’s ``mainWidget`` will
work on GHC out of the box, using the ``jsaddle-webkit2gtk`` backend. So
simply building your ``frontend`` package using GHC will produce a
working native program that renders DOM using WebKit. This is
recommended for native desktop releases.
JavaScript backend easily. By default, Reflex-DOM’s ``mainWidget`` will work on
GHC out of the box, using the default backend for your platform (e.g.,
jsaddle-warp on linux, wkwebview on macOS). So simply building your
``frontend`` package using GHC will produce a working program that renders DOM.
To select the webkit2gtk backend for reflex-dom on linux, set the useWebkit2Gtk
flag to true in default.nix. Note that webkit2gtk only works on x86_64-linux.

To build this with ``nix-build``:

Expand Down
44 changes: 39 additions & 5 deletions haskell-overlays/android/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,45 @@ in
self: super: {
_dep = super._dep or {} // thunkSet ./dep;

android-activity = self.callPackage self._dep.android-activity {
inherit (nixpkgs.buildPackages) jdk;
};

android-activity = haskellLib.overrideCabal (self.callCabal2nix "android-activity" (self._dep.android-activity + "/") {
log = nixpkgs.androidndkPkgs_24.libraries;
}) (drv: let
jdk-fixed = (nixpkgs.buildPackages.jdk17.override {
headless = true;
enableGnome2 = false;
enableJavaFX = false;
openjdk17-bootstrap = nixpkgs.buildPackages.openjdk17-bootstrap.override {
gtkSupport = false;
};
});
in {
librarySystemDepends = (drv.librarySystemDepends or []) ++ [ jdk-fixed ];
enableSharedExecutables = true;
enableSharedLibraries = true;
enableStaticLibraries = false;
buildTools = (drv.buildTools or []) ++ [ ];
configureFlags = (drv.configureFlags or []) ++ [
"--enable-shared"
#"-v3"
];
});

syb = haskellLib.overrideCabal super.syb (drv: { jailbreak = true; });
cabal-doctest = null;

# Break version bounds on base for GHC HEAD.
lifted-async = haskellLib.doJailbreak super.lifted-async;
safe-exceptions = haskellLib.doJailbreak super.safe-exceptions;


blaze-textual = haskellLib.enableCabalFlag super.blaze-textual "integer-simple";
cryptonite = haskellLib.disableCabalFlag super.cryptonite "integer-gmp";


OneTuple = haskellLib.overrideCabal super.OneTuple (drv: {
libraryHaskellDepends = (drv.libraryHaskellDepends or []) ++ [
self.hashable
];
});
hashable = enableFPic super.hashable;
primitive = enableFPic super.primitive;

Expand All @@ -34,6 +59,15 @@ self: super: {
enableSharedExecutables = false;
});

# HACK(Dylan Green):
# Temporary fix for RPATH troubles regarding attoparsec
attoparsec = haskellLib.overrideCabal super.attoparsec (drv: {
preFixup = ''
rm -rf "$(pwd)"
mkdir "$(pwd)"
'';
});

# HACK(matthewbauer):
# Temporary fix for https://github.com/ekmett/free/issues/176
# Optimizations are broken on some ARM-based systems for some reason.
Expand Down
Loading

0 comments on commit f231e24

Please sign in to comment.