-
Notifications
You must be signed in to change notification settings - Fork 9
/
static.nix
161 lines (155 loc) · 7.22 KB
/
static.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
{ 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;
haskell-tools =
pkgs.lib.optionalAttrs (withHLS && (compiler-not-in (
pkgs.lib.optional (builtins.compareVersions compiler.version "9.7" >= 0) compiler-nix-name) "Haskell Language Server")) { hls = tool "haskell-language-server"; }
// pkgs.lib.optionalAttrs (withHlint && (compiler-not-in (
pkgs.lib.optional (builtins.compareVersions compiler.version "9.8" >= 0) compiler-nix-name) "HLint")) { hlint = tool "hlint"; };
# 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; [
])
++ builtins.attrValues haskell-tools
++ pkgs.lib.optional withIOG (with pkgs; [ cddl cbor-diag ])
;
passthru = {
plans = if haskell-tools == {} then {} else
pkgs.pkgsBuildBuild.linkFarm "plans"
(builtins.mapAttrs (_: t: t.project.plan-nix) haskell-tools);
};
})