devx/static.nix
Yvan Sraka c79eecfe19
Fix #132: add support for GHC 9.6.4 (#134)
* Fix #132: add support for GHC 9.6.4

`nix flake lock --update-input haskellNix`

* Drop ghc99

* Set hlint for 9.2.8 to 3.6.1

* Bump max compiler.

Maybe we want to this actually be "unreleased"?

* disable hls for 9.7+

We need to find a hls (and have it in haskell.nix) that builds with 9.8 🤦

* Try to fix tools

* 9.0 use lhs 2.4

* Split out IOGFull into static as well.

* cleanup R

* fix typo

* R doesn't build for aarch64-musl

* Disable R on aarch64; disable hls on -js and -windows

* Disable R (libjpeg-turbo fails to build for x86_64-musl)

---------

Co-authored-by: Moritz Angermann <moritz.angermann@gmail.com>
2024-04-16 00:32:45 +00:00

154 lines
6.9 KiB
Nix

{ self, pkgs, compiler, compiler-nix-name, toolsModule, withHLS ? true, withHlint ? true, withIOG ? true, withIOGFull ? false }:
let tool-version-map = import ./tool-map.nix;
tool = tool-name: pkgs.pkgsBuildBuild.haskell-nix.tool compiler-nix-name tool-name [(tool-version-map compiler-nix-name tool-name) toolsModule];
cabal-install = pkgs.pkgsBuildBuild.haskell-nix.nix-tools-unchecked.exes.cabal;
# add a trace helper. This will trace a message about disabling a component despite requesting it, if it's not supported in that compiler.
compiler-not-in = compiler-list: name: (if __elem compiler-nix-name compiler-list then __trace "No ${name}. Not yet compatible with ${compiler-nix-name}" false else true);
# * wrapped tools:
# fixup-nix-deps allows us to drop dylibs from macOS executables that can be
# linked directly.
fixup-nix-deps = pkgs.writeShellApplication {
name = "fixup-nix-deps";
text = ''
for nixlib in $(otool -L "$1" |awk '/nix\/store/{ print $1 }'); do
case "$nixlib" in
*libiconv.dylib) install_name_tool -change "$nixlib" /usr/lib/libiconv.dylib "$1" ;;
*libffi.*.dylib) install_name_tool -change "$nixlib" /usr/lib/libffi.dylib "$1" ;;
*libc++.*.dylib) install_name_tool -change "$nixlib" /usr/lib/libc++.dylib "$1" ;;
*libz.dylib) install_name_tool -change "$nixlib" /usr/lib/libz.dylib "$1" ;;
*) ;;
esac
done
'';
};
# A cabal-install wrapper that sets the appropriate static flags
wrapped-cabal = pkgs.writeShellApplication {
name = "cabal";
runtimeInputs = [ cabal-install pkgs.curl ];
text = with pkgs; ''
# We do not want to quote NIX_CABAL_FLAGS
# it will leave an empty argument, if they are empty.
# shellcheck disable=SC2086
case "$1" in
build)
cabal \
"$@" \
$NIX_CABAL_FLAGS \
--disable-shared --enable-static \
--ghc-option=-L${lib.getLib static-gmp}/lib \
--ghc-option=-L${lib.getLib static-libsodium-vrf}/lib \
--ghc-option=-L${lib.getLib static-secp256k1}/lib \
--ghc-option=-L${lib.getLib static-libblst}/lib \
--ghc-option=-L${lib.getLib static-openssl}/lib
;;
clean|unpack)
cabal "$@"
;;
*)
cabal $NIX_CABAL_FLAGS "$@"
;;
esac
'';
};
quirks = (import ./quirks.nix { inherit pkgs; static = true; });
in
pkgs.mkShell (rec {
# Note [cabal override]:
#
# We need to override the `cabal` command and pass --ghc-options for the
# libraries. This is fairly annoying, but necessary, as ghc will otherwise
# pick up the dynamic libraries, instead of the static ones.
#
# Note [static gmp]:
#
# We can only link GMP statically, because the thing we are linking is fully
# open source, and licenses accordingly. Otherwise we'd have to link gmp
# dynamically. This requirement will be gone with gmp-bignum.
#
NIX_CABAL_FLAGS = pkgs.lib.optionals pkgs.stdenv.hostPlatform.isMusl [
"--with-ghc=${if pkgs.stdenv.hostPlatform.isAarch64 then "aarch64" else "x86_64"}-unknown-linux-musl-ghc"
"--with-ghc-pkg=${if pkgs.stdenv.hostPlatform.isAarch64 then "aarch64" else "x86_64"}-unknown-linux-musl-ghc-pkg"
"--with-hsc2hs=${if pkgs.stdenv.hostPlatform.isAarch64 then "aarch64" else "x86_64"}-unknown-linux-musl-hsc2hs"
# ensure that the linker knows we want a static build product
"--enable-executable-static"
];
hardeningDisable = pkgs.lib.optionals pkgs.stdenv.hostPlatform.isMusl [ "format" "pie" ];
inherit (quirks) CABAL_PROJECT_LOCAL_TEMPLATE;
# This is required to prevent
#
# WARNING: [...]ghc is loading libcrypto in an unsafe way
# [...]
# The build process terminated with exit code -6
#
# We want to load the libcrypto from the openssl path, not from
# the system path.
DYLD_LIBRARY_PATH= with pkgs; "${lib.getLib openssl}/lib";
shellHook =
with pkgs;
let flavor = "${compiler-nix-name}-static"
+ lib.optionalString (!withHLS && !withHlint) "-minimal"
+ lib.optionalString withIOG "-iog"
;
in ''
export PS1="\[\033[01;33m\][\w]$\[\033[00m\] "
export DYLD_LIBRARY_PATH="${DYLD_LIBRARY_PATH}";
${figlet}/bin/figlet -f rectangles 'IOG Haskell Shell'
${figlet}/bin/figlet -f small "*= static edition =*"
echo "Revision (input-output-hk/devx): ${if self ? rev then self.rev else "unknown/dirty checkout"}."
echo "NOTE (macos): you can use fixup-nix-deps FILE, to fix iconv, ffi, and zlib dependencies that point to the /nix/store"
export CABAL_DIR=$HOME/.cabal-static
echo "CABAL_DIR set to $CABAL_DIR"
echo "DYLD_LIBRARY_PATH set to $DYLD_LIBRARY_PATH"
echo ""
'' + (quirks.hint flavor) + quirks.shellHook;
# these are _target_ libs, e.g. ones we want to link the build
# product against. These are also the ones that showup in the
# PKG_CONFIG_PATH.
buildInputs = with pkgs; ([
# for libstdc++; ghc not being able to find this properly is bad,
# it _should_ probably call out to a g++ or clang++ but doesn't.
stdenv.cc.cc.lib
]) ++ map lib.getDev ([
pcre
static-gmp
static-openssl
static-zlib
] ++ lib.optionals withIOG [
static-libblst
static-libsodium-vrf
static-secp256k1
icu # for cardano-cli
gh
jq
yq-go
] ++ lib.optionals withIOGFull [
# for plutus; but unavailable for static/aarch64, or static even.
# R fails in almost any direction. For now, we just disable it.
(if (pkgs.stdenv.hostPlatform.isAarch64 || pkgs.stdenv.hostPlatform.isMusl) then null else R)
postgresql # for db-sync
]);
# these are _native_ libs, we need to drive the compilation environment
# they will _not_ be part of the final build product.
nativeBuildInputs = [
wrapped-cabal
fixup-nix-deps
# We are happy to use a _shared_ compiler; we only want the build
# products to be static.
(compiler.override { enableShared = true; })
] ++ (with pkgs; [
(pkgs.pkg-config or pkgconfig)
stdenv.cc.cc.lib ]) ++ (with pkgs.buildPackages; [
])
++ pkgs.lib.optional (withHLS && (compiler-not-in (
pkgs.lib.optional (builtins.compareVersions compiler.version "9.7" >= 0) compiler-nix-name) "Haskell Language Server")) (tool "haskell-language-server")
++ pkgs.lib.optional (withHlint && (compiler-not-in (
pkgs.lib.optional (builtins.compareVersions compiler.version "9.8" >= 0) compiler-nix-name) "HLint")) (tool "hlint")
++ pkgs.lib.optional withIOG (with pkgs; [ cddl cbor-diag ])
;
})