├── .buildkite
└── pipeline.yml
├── .github
└── FUNDING.yml
├── .gitmodules
├── .in-static-haskell-nix
├── Main.hs
├── README.md
├── Setup.hs
├── ci.nix
├── default.nix
├── example-scotty-app.cabal
├── nixpkgs.nix
├── setup-git-hooks
├── static-stack
├── README.md
├── build-static-stack.sh
└── default.nix
├── static-stack2nix-builder-example
├── .gitignore
├── README.md
├── Setup.hs
├── app
│ └── Main.hs
├── default.nix
├── example-project.cabal
├── package.yaml
├── src
│ └── Lib.hs
└── stack.yaml
├── static-stack2nix-builder
├── default.nix
└── stack2nix-script.nix
├── submodules-update
├── survey
└── default.nix
└── update-example-commits.sh
/.buildkite/pipeline.yml:
--------------------------------------------------------------------------------
1 | steps:
2 |
3 | # The order here is defined for fast feedback when breaking something.
4 |
5 | # -O0 builds come first for fast feedback.
6 |
7 | - label: (-O0) -A working
8 | command: |
9 | NIX_PATH=nixpkgs=nixpkgs nix-build --no-link survey/default.nix \
10 | --arg disableOptimization true -A working
11 |
12 | - label: (-O0) -A workingStackageExecutables
13 | command: |
14 | NIX_PATH=nixpkgs=nixpkgs nix-build --no-link survey/default.nix \
15 | --arg disableOptimization true -A workingStackageExecutables
16 |
17 | # Normal builds
18 |
19 | - label: -A working
20 | command: |
21 | NIX_PATH=nixpkgs=nixpkgs nix-build --no-link survey/default.nix \
22 | -A working
23 |
24 | - label: -A workingStackageExecutables
25 | command: |
26 | NIX_PATH=nixpkgs=nixpkgs nix-build --no-link survey/default.nix \
27 | -A workingStackageExecutables
28 |
29 | # integer-simple builds
30 |
31 | # Doesn't pass yet
32 | # - label: (integer-simple)
33 | # command: |
34 | # NIX_PATH=nixpkgs=nixpkgs nix-build --no-link survey/default.nix \
35 | # --arg integer-simple true -A working -A workingStackageExecutables
36 |
37 | # Note on GHC versions:
38 | # It really only makes sense to test the compiler version matching the version
39 | # of Stackage that was the base for nixpkgs's `haskellPackages`.
40 | # Any other GHC version should be tested via `stack2nix` builds.
41 |
42 | # Other
43 |
44 | - label: stack2nix-example
45 | command: |
46 | cd static-stack2nix-builder-example/ && $(nix-build --no-link -A fullBuildScript)
47 |
48 | # Stack via stack2nix
49 |
50 | - label: static-stack
51 | command: "cd static-stack && ./build-static-stack.sh"
52 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | open_collective: static-haskell-nix
2 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "nixpkgs"]
2 | path = nixpkgs
3 | url = https://github.com/NixOS/nixpkgs.git
4 |
--------------------------------------------------------------------------------
/.in-static-haskell-nix:
--------------------------------------------------------------------------------
1 | The presence of this file indicates that we're inside the static-haskell-nix project.
2 |
--------------------------------------------------------------------------------
/Main.hs:
--------------------------------------------------------------------------------
1 | {-# LANGUAGE OverloadedStrings #-}
2 |
3 | import Web.Scotty
4 |
5 | import Data.Monoid (mconcat)
6 |
7 | main = scotty 3000 $ do
8 | get "/:word" $ do
9 | beam <- param "word"
10 | html $ mconcat ["
Scotty, ", beam, " me up!
"]
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://opencollective.com/static-haskell-nix) [](https://buildkite.com/nh2/static-haskell-nix)
2 |
3 | # static-haskell-nix
4 |
5 | With this repository you can easily build most Haskell programs into fully static Linux executables.
6 |
7 | * results are fully static executables (`ldd` says `not a dynamic executable`)
8 | * to make that possible, each exe and all dependencies (including ghc) are built against [`musl`](https://www.musl-libc.org/) instead of glibc
9 |
10 | static-haskell-nix can [successfully build > 90% of Stackage executables](https://github.com/nh2/static-haskell-nix/issues/4#issuecomment-406838083), so chances are high it can build yours.
11 |
12 | ## History
13 |
14 | `glibc` encourages dynamic linking to the extent that correct functionality under static linking is somewhere between difficult and bug-ridden.
15 | For this reason, static linking, despite its many advantages (details [here](https://github.com/NixOS/nixpkgs/issues/43795)) has become less and less common.
16 |
17 | Due to GHC's dependency on a libc, and many libraries depending on C libraries for which Linux distributions often do not include static library archive files, this situation has resulted in fully static Haskell programs being extremely hard to produce for the common Haskeller, even though the language is generally well-suited for static linking.
18 |
19 | This project solves this.
20 |
21 | It was inspired by a [blog post by Vaibhav Sagar](https://vaibhavsagar.com/blog/2018/01/03/static-haskell-nix/),
22 | and a [comment by Will Dietz](https://github.com/NixOS/nixpkgs/pull/37598#issuecomment-375117019) about musl.
23 |
24 | Work on this so far was sponsored largely by my free time, [FP Complete](https://haskell.fpcomplete.com/) and their clients, and the contributors mentioned [here](https://github.com/NixOS/nixpkgs/issues/43795#issue-342546855).
25 |
26 | By now we have a nixpkgs issue on [Fully static Haskell executables](https://github.com/NixOS/nixpkgs/issues/43795) (progress on which is currently this repo, with plans to later merge it into nixpkgs), and [a merged nixpkgs overlay for static nixpkgs in general](https://github.com/NixOS/nixpkgs/pull/48803).
27 |
28 | There's also nixpkgs's `pkgsStatic` package set, which can also build many Haskell packages statically with `musl`. Differences are:
29 |
30 | * Type of compilation:
31 | * `pkgsStatic` uses cross-compilation infrastructure, which is inherently more complex, and more difficult to get into.
32 | * `static-haskell-nix` just replaces the libc, and compiles normally. This allows to build packages that cannot (yet) be cross-compiled.
33 | * `.a` + `.so` files:
34 | * `pkgsStatic` does _exclusively_ static builds, it generates only `.a` files and no `.so` files.
35 | * `static-haskell-nix` generates both `.a` and `.so` files, which allows more intermediate software to run (e.g. some build systems using Python libraries doing `dlopen()` on some `.so` files).
36 | * In the past, this made a big difference for TemplateHaskell, which worked well only when `.so` files are present. This seems to have improved. `static-haskell-nix` now has an off-by-default flag `useArchiveFilesForTemplateHaskell` that users are encouraged to test.
37 | * Hacky fixes:
38 | * `static-haskell-nix` contains a large amount of per-package fixes for static builds for which we haven't found a way to integrate them cleanly into nixpkgs yet.
39 | * Pinning:
40 | * `static-haskell-nix` does not impede nixpkgs progress, as it is maintained out of the nixkpgs.
41 |
42 | In general, any contribution to `static-haskell-nix` or `pkgsStatic` benefits the respective other one.
43 |
44 | A goal is to shrink `static-haskell-nix` over time, moving those parts into nixpkgs that do not slow down nixpkgs's fast pace.
45 |
46 | ## Funding
47 |
48 | You can support this project financially [on OpenCollective](https://opencollective.com/static-haskell-nix). Goals:
49 |
50 | * [x] **Dedicated build server** - [Goal reached!](https://opencollective.com/static-haskell-nix/updates/build-server-funding-goal-reached) Thanks to our awesome [contributors](https://opencollective.com/static-haskell-nix#contributors)!
51 |
52 | The first and main goal is to get to ~28 EUR/month to buy a cheap Hetzner dedicated build server for fast CI and pushing to Cachix. It will also allow anybody to download almost any executable on Stackage pre-built as a static binary, so that people can try out Haskell programs easily without having to install lots of dependencies.
53 |
54 | Because the server is so cheap, already 1 or 2 EUR/month will bring us to that goal quickly.
55 |
56 | [
](https://hercules-ci.com)
57 | The **storage infrastructure** ([Cachix](https://cachix.org)) for downloading pre-built packages is **sponsored by the [awesome guys](https://hercules-ci.com/#about) from Hercules CI**.
58 | They are building a nix-based CI service you can safely run on your own infrastructure. _static-haskell-nix_ also uses it.
59 |
If your company or project needs that, check [**Hercules CI**](https://hercules-ci.com) out!
60 |
61 | ## Testing
62 |
63 | We have multiple CIs:
64 |
65 | * [HerculesCI](https://hercules-ci.com/github/nh2/static-haskell-nix/): Builds with pinned nixpkgs.
66 | Publicly visible, but requires free sign-in. Click the most recent job to which 100s of binaries we build.
67 | * [BuildKite](https://buildkite.com/nh2/static-haskell-nix/):
68 | * Builds with pinned nixpkgs (submodule): Should always be green.
69 | * Builds with latest nixpkgs `unstable`, daily: Shows up as **Scheduled build**.
70 | May break when nixpkgs upstream changes.
71 |
72 | ## Building a minimal example (don't use this in practice)
73 |
74 | `default.nix` builds an example executable (originally from https://github.com/vaibhavsagar/experiments). Run:
75 |
76 | ```
77 | NIX_PATH=nixpkgs=nixpkgs nix-build --no-link
78 | ```
79 |
80 | This prints a path that contains the fully linked static executable in the `bin` subdirectory.
81 |
82 | This example is so that you get the general idea.
83 | In practice, you probably want to use one of the approaches from the "Building arbitrary packages" or "Building stack projects" sections below.
84 |
85 | ## Binary caches for faster building (optional)
86 |
87 | Install [cachix](https://static-haskell-nix.cachix.org/) and run `cachix use static-haskell-nix` before your `nix-build`.
88 |
89 | If you get a warning during `cachix use`, read [this](https://github.com/cachix/cachix/issues/56#issuecomment-423820198).
90 |
91 | If you don't want to install `cachix` for some reason or `cachix use` doesn't work, you should also be able to manually set up your `nix.conf` (e.g. in `$HOME/.config/nix/nix.conf`; you may have to create the file) to have contents like this:
92 |
93 | ```
94 | extra-substituters = http://static-haskell-nix-ci.nh2.me:5000 https://cache.nixos.org https://static-haskell-nix.cachix.org
95 | extra-trusted-public-keys = static-haskell-nix-ci-cache-key:Z7ZpqYFHVs467ctsqZADpjQ/XkSHx6pm5XBZ4KZW3/w= static-haskell-nix.cachix.org-1:Q17HawmAwaM1/BfIxaEDKAxwTOyRVhPG5Ji9K3+FvUU=
96 | ```
97 |
98 | or append to command lines:
99 |
100 | ```sh
101 | --option extra-substituters 'http://static-haskell-nix-ci.nh2.me:5000' --option extra-trusted-public-keys 'static-haskell-nix-ci-cache-key:Z7ZpqYFHVs467ctsqZADpjQ/XkSHx6pm5XBZ4KZW3/w='
102 | ```
103 |
104 | Note that you may not get cached results if you use a different `nix` version than I used to produce the cache (I used `2.0.4` as of writing, which you can get from [here](https://nixos.org/releases/nix/nix-2.0.4/install)).
105 |
106 | ## Building arbitrary packages
107 |
108 | The [`survey`](./survey) directory maintains a select set of Haskell executables that are known and not known to work with this approach; contributions are welcome to grow the set of working executables.
109 | Run for example:
110 |
111 | ```
112 | NIX_PATH=nixpkgs=nixpkgs nix-build --no-link survey/default.nix -A working
113 | ```
114 |
115 | There are multiple package sets available in the survey (select via `-A`):
116 |
117 | * `working` -- build all exes known to be working
118 | * `notWorking` -- build all exes known to be not working (help welcome to make them work)
119 | * `haskellPackages.somePackage` -- build a specific package from our overridden package set
120 |
121 | If you are a nix user, you can easily `import` this functionality and add an override to add your own packages.
122 |
123 | ## Building `stack` projects
124 |
125 | The [`static-stack2nix-builder-example`](./static-stack2nix-builder-example) directory shows how to build any `stack`-based project statically.
126 |
127 | Until Stack 2.3, the official static build of `stack` itself was built using this method (Stack >= 2.3 static builds are built in an Alpine Docker image after GHC on Alpine started working again, see [here](https://github.com/commercialhaskell/stack/pull/5267)).
128 | The [`static-stack`](./static-stack) directory shows how Stack itself can be built statically with static-haskell-nix.
129 | `stack` is a big package with many dependencies, demonstrating that it works also for large projects.
130 |
131 | ## Related important open issues
132 |
133 | You can contribute to these to help static Haskell executables:
134 |
135 | * https://github.com/haskell/cabal/issues/8455
136 |
137 | ## FAQ
138 |
139 | * I get `cannot find section .dynamic`. Is this an error?
140 | * No, this is an informational message printed by `patchelf`. If your final looks like
141 | ```
142 | ...
143 | cannot find section .dynamic
144 | /nix/store/dax3wjbjfrcwj6r3mafxj5fx6wcg5zbp-stack-2.3.0.1
145 | ```
146 | then `/nix/store/dax3wjbjfrcwj6r3mafxj5fx6wcg5zbp-stack-2.3.0.1` is your final output _store path_ whose `/bin` directory contains your static executable.
147 | * I get `stack2nix: user error (No such package mypackage-1.2.3 in the cabal database. Did you run cabal update?)`.
148 | * You most likely have to bump the date like `hackageSnapshot = "2019-05-08T00:00:00Z";` to a newer date (past the time that package-version was added to Hackage).
149 | * I get a linker error.
150 | What's a good way to investigate what the linker invocation is?
151 | * Pass `-v` to Cabal, and to GHC itself:
152 | ```sh
153 | nix-build --expr '(import ./survey/default.nix {}).haskellPackages.YOURPACKAGE.overrideAttrs (old: { configureFlags = (old.configureFlags or []) ++ ["-v" "--ghc-options=-v"]; })'
154 | ```
155 | Look for `*** Linker:` in the GHC output.
156 | * Can I build Stack projects with resolvers that are too old to be supported by Stack >= 2?
157 | * No. For that you need need to use an old `static-haskell-nix` version: The one before [this PR](https://github.com/nh2/static-haskell-nix/pull/98) was merged.
158 | * I get some other error. Can I just file an issue and have you help me with it?
159 | * Yes. If possible (especially if your project is open source), please push some code so that your issue can be easily reproduced.
160 |
161 |
162 | ## Open questions
163 |
164 | * Nixpkgs issue [Provide middle-ground overlay between pkgsMusl and pkgsStatic](https://github.com/NixOS/nixpkgs/issues/61575):
165 |
166 | Should nixpkgs provide a `makeStaticAndSharedLibraries` adapter to provide a package set?
167 | That might be better (but more difficult) than what we do now, with `dontDisableStaticOverlay`, because:
168 | * `dontDisableStatic` is to prevent `--disable-static` to autoconf, which is really specific to C + autoconf.
169 | A package set should do more than that, also for Meson, CMake, etc.
170 | `nh2` started implementing this idea in nixpkgs branch `static-haskell-nix-nixos-24.05-makeStaticAndSharedLibraries`.
171 |
172 | * Can we avoid building bootstrap tools?
173 | * Our current overlays also build `xgcc`, `gcc`, `binutils`, and so on.
174 | * This is because we override all packages to have e.g. `.a` files, and some of those are also dependencies of e.g. `gcc`.
175 | * `pkgsStatic` avoids that by being a `cross` toolchain.
176 | * But might this cause additional issues?
177 | Because `cross` may have additional complexities when building the actual packages we're interested in, vs just switching the libc ("native" compilation)?
178 | Unclear.
179 | * For now, we accept those additional builds.
180 |
181 | * How should we handle `pkg-config` regarding static dependencies?
182 |
183 | E.g. `libtiff` depends on `lerc` and `libtiff-4.pc` correctly declares
184 |
185 | ```
186 | Libs.private: -llzma -lLerc -ljpeg -ldeflate -lz -lm
187 | Requires.private: liblzma libjpeg libdeflate zlib
188 | ```
189 |
190 | But the `.pc` file does not include the path on which `libLerc.a` can be found, nor does anything in nixpkgs set `PKG_CONFIG_PATH` such that `Lerc.pc` is on it.
191 | Thus, linking a static binary that uses `libtiff-4.pc` fails with
192 |
193 | ```
194 | cannot find -lLerc: No such file or directory
195 | ```
196 |
197 | * Should we use `propagatedBuildInputs` for this?
198 | * Yes! We can use `stdenvAdapters.propagateBuildInputs`.
199 | * Current problem: Using that in a native compilation (instead of cross as `pkgsMusl` does) causes:
200 | ```
201 | error: build of '/nix/store/...-stdenv-linux.drv' failed: output '/nix/store/...-stdenv-linux' is not allowed to refer to the following paths:
202 | /nix/store/...-binutils-patchelfed-ld-wrapper-2.41
203 | /nix/store/...-pcre2-10.43-dev
204 | /nix/store/...-gmp-with-cxx-6.3.0-dev
205 | /nix/store/...-musl-iconv-1.2.3
206 | /nix/store/...-binutils-2.41
207 | /nix/store/...-bootstrap-tools
208 | ```
209 | * John Ericson explained that the bootstrap rebuild avoidance (mentioned in a point above) also solves this issue for `pkgsStatic`.
210 | So we probably need to do something similar.
211 | * After fixing that, we still need to fix `libtiff` to include `lerc` in `Requires.private`.
212 | * Done in https://github.com/NixOS/nixpkgs/pull/320105
213 |
--------------------------------------------------------------------------------
/Setup.hs:
--------------------------------------------------------------------------------
1 | import Distribution.Simple
2 | main = defaultMain
3 |
--------------------------------------------------------------------------------
/ci.nix:
--------------------------------------------------------------------------------
1 | # HerculesCI config
2 | let
3 | survey = import ./survey {};
4 | in survey.working // survey.workingStackageExecutables
5 |
--------------------------------------------------------------------------------
/default.nix:
--------------------------------------------------------------------------------
1 | # Note: This is just a minimal example. For proper usage, see the README.
2 |
3 | { nixpkgs ? (import ./nixpkgs.nix).pkgsMusl, compiler ? "ghc8107", strip ? true }:
4 |
5 |
6 | let
7 |
8 | pkgs = nixpkgs.pkgsMusl;
9 |
10 | example-scotty-app = { mkDerivation, base, scotty, stdenv }:
11 | mkDerivation {
12 | pname = "example-scotty-app";
13 | version = "0.1.0.0";
14 | src = pkgs.lib.sourceByRegex ./. [
15 | ".*\\.cabal$"
16 | "^Setup.hs$"
17 | "^Main.hs$"
18 | ];
19 | isLibrary = false;
20 | isExecutable = true;
21 | enableSharedExecutables = false;
22 | enableSharedLibraries = false;
23 | executableHaskellDepends = [ base scotty ];
24 | license = pkgs.lib.licenses.bsd3;
25 | configureFlags = [
26 | "--ghc-option=-optl=-static"
27 | "--extra-lib-dirs=${pkgs.gmp6.override { withStatic = true; }}/lib"
28 | "--extra-lib-dirs=${pkgs.zlib.static}/lib"
29 | "--extra-lib-dirs=${pkgs.libffi.overrideAttrs (old: { dontDisableStatic = true; })}/lib"
30 | ] ++ pkgs.lib.optionals (!strip) [
31 | "--disable-executable-stripping"
32 | ] ;
33 | };
34 |
35 | normalHaskellPackages = pkgs.haskell.packages.${compiler};
36 |
37 | haskellPackages = with pkgs.haskell.lib; normalHaskellPackages.override {
38 | overrides = self: super: {
39 | # Dependencies we need to patch
40 | };
41 | };
42 |
43 | drv = haskellPackages.callPackage example-scotty-app {};
44 |
45 | in
46 | if pkgs.lib.inNixShell then drv.env else drv
47 |
--------------------------------------------------------------------------------
/example-scotty-app.cabal:
--------------------------------------------------------------------------------
1 | name: example-scotty-app
2 | version: 0.1.0.0
3 | license: BSD3
4 | build-type: Simple
5 | cabal-version: >=1.10
6 |
7 | executable example-scotty-app
8 | main-is: Main.hs
9 | build-depends: base >=4.9 && <5
10 | , scotty
11 | default-language: Haskell2010
12 | ld-options: -static
13 |
--------------------------------------------------------------------------------
/nixpkgs.nix:
--------------------------------------------------------------------------------
1 | # If this env var is set, use latest nixpkgs unstable.
2 | # We use that for scheduled builds tracking nixpkgs unstable on CI.
3 | # Of course that is NOT reproducible.
4 | if builtins.getEnv "STATIC_HASKELL_NIX_CI_NIXPKGS_UNSTABLE_BUILD" == "1"
5 | then
6 | let
7 | # You can set e.g. to build with `master`:
8 | # STATIC_HASKELL_NIX_CI_NIXPKGS_UNSTABLE_BUILD=1
9 | # NIXPKGS_URL=https://github.com/NixOS/nixpkgs/archive/master.tar.gz
10 | NIXPKGS_URL_var = builtins.getEnv "NIXPKGS_URL";
11 | nixpkgsUrl =
12 | if NIXPKGS_URL_var != null && NIXPKGS_URL_var != ""
13 | then NIXPKGS_URL_var
14 | else "https://nixos.org/channels/nixpkgs-unstable/nixexprs.tar.xz";
15 | nixpkgs = import (fetchTarball nixpkgsUrl) {};
16 | msg = "Using version ${nixpkgs.lib.version} of nixpkgs-unstable channel.";
17 | in builtins.trace msg nixpkgs
18 | else
19 | # If a `./nixpkgs` submodule exists, use that.
20 | # Note that this will take precedence over setting NIX_PATH!
21 | # We prefer this such that `static-stack2nix-builder` and specifically
22 | # `static-stack2nix-builder-example` can just import `nixpkgs.nix`
23 | # in CI and when called during development to get the right version of
24 | # nixpkgs.
25 | if builtins.pathExists ./nixpkgs/pkgs
26 | then import ./nixpkgs {}
27 | # Pinned nixpkgs version; should be kept up-to-date with our submodule.
28 | # This is nixos-23.11 as of 2024-01-01, with minimal patches currently having open nixpkgs PR (see commits for PR links).
29 | else import (fetchTarball https://github.com/nh2/nixpkgs/archive/ede5282c487a1fd2de64303ba59adad6726f1225.tar.gz) {}
30 |
--------------------------------------------------------------------------------
/setup-git-hooks:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -eo pipefail
3 |
4 | # Must be run from top of the git directory
5 |
6 | mkdir -p .git/hooks
7 | rm -f .git/hooks/post-checkout
8 | ln -s ../../submodules-update .git/hooks/post-checkout
9 | ln -s ../../submodules-update .git/hooks/post-rewrite
10 |
--------------------------------------------------------------------------------
/static-stack/README.md:
--------------------------------------------------------------------------------
1 | # Fully statically linked `stack`
2 |
3 | This builds a fully statically linked `stack` executable that should work on any 64-bit Linux distribution.
4 |
5 | It uses nix to build everything, including `ghc`, against the `musl` libc.
6 |
7 | ## Building
8 |
9 | ```
10 | $(nix-build --no-link -A fullBuildScript --argstr stackDir /absolute/path/to/stack/source)
11 | ```
12 |
13 | We use the `$(nix-build ...)` script approach in order to pin the version of `nix` itself for reproducibility, and because the call to `stack2nix` needs Internet access and thus has to run outside of the nix build sandbox.
14 |
15 | If you get an error such as:
16 |
17 | > stack2nix: user error (No such package foo-1.2.3.4 in the cabal database. Did you run cabal update?)
18 |
19 | then update the `hackageSnapshot` date in `default.nix` to a date that includes the package and version.
20 |
21 | ## Binary caches for faster building (optional)
22 |
23 | You can use the caches described in the [top-level README](../README.md#binary-caches-for-faster-building-optional) for faster building.
24 |
25 | ## `stack` binaries
26 |
27 | Static `stack` binaries I built this way, for download:
28 |
29 | * The [official static stack v2.1.3 release](https://github.com/commercialhaskell/stack/releases/tag/v2.1.3) is built using this
30 | * The [official static stack v2.1.1 release](https://github.com/commercialhaskell/stack/releases/tag/v2.1.1) is built using this
31 | * The [official static stack v1.9.3 release](https://github.com/commercialhaskell/stack/releases/tag/v1.9.3) is built using this
32 | * [stack v1.7.1 for 64-bit Linux](https://github.com/nh2/stack/releases/tag/v1.6.5)
33 | * [stack v1.6.5 for 64-bit Linux](https://github.com/nh2/stack/releases/tag/v1.6.5)
34 |
--------------------------------------------------------------------------------
/static-stack/build-static-stack.sh:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env bash
2 |
3 | set -eu -o pipefail
4 |
5 | mkdir -p static-stack-test-dir
6 | curl -L https://github.com/commercialhaskell/stack/archive/v2.7.1.tar.gz | tar -xz -C static-stack-test-dir
7 |
8 | $(nix-build --no-link -A fullBuildScript --argstr stackDir $PWD/static-stack-test-dir/stack-*)
9 |
--------------------------------------------------------------------------------
/static-stack/default.nix:
--------------------------------------------------------------------------------
1 | # Builds a static `stack` executable from a stack source dir.
2 | #
3 | # Usage:
4 | #
5 | # $(nix-build --no-link -A fullBuildScript --argstr stackDir /absolute/path/to/stack/source)
6 | {
7 | stackDir ? "/absolute/path/to/stack/source",
8 | stack2nix-output-path ? "custom-stack2nix-output.nix",
9 | }:
10 | let
11 | cabalPackageName = "stack";
12 | compiler = "ghc8104"; # matching stack-lts-12.yaml
13 |
14 | pkgs = import ../nixpkgs {};
15 |
16 | stack2nix-script = import ../static-stack2nix-builder/stack2nix-script.nix {
17 | inherit pkgs;
18 | inherit compiler;
19 | stack-project-dir = stackDir; # where stack.yaml is
20 | hackageSnapshot = "2021-07-12T00:00:00Z"; # pins e.g. extra-deps without hashes or revisions
21 | };
22 |
23 | static-stack2nix-builder = import ../static-stack2nix-builder/default.nix {
24 | normalPkgs = pkgs;
25 | inherit cabalPackageName compiler stack2nix-output-path;
26 | # disableOptimization = true; # for compile speed
27 | };
28 |
29 | static_package = with pkgs.haskell.lib;
30 | overrideCabal
31 | (appendConfigureFlags
32 | static-stack2nix-builder.static_package
33 | [
34 | # Official release flags:
35 | "-fsupported-build"
36 | "-fhide-dependency-versions"
37 | "-f-disable-git-info" # stack2nix turns that on, we turn it off again
38 | ]
39 | )
40 | (old: {
41 | # Enabling git info needs these extra deps.
42 | # TODO Make `stack2nix` accept per-package Cabal flags,
43 | # so that `cabal2nix` would automatically add
44 | # the right dependencies for us.
45 | executableHaskellDepends = (old.executableHaskellDepends or []) ++
46 | (with static-stack2nix-builder.haskell-static-nix_output.haskellPackages; [
47 | githash
48 | optparse-simple
49 | ]);
50 | # Put `git` on PATH, because `githash` calls it.
51 | preConfigure = ''
52 | export PATH=${pkgs.git}/bin:$PATH
53 | git --version
54 | '';
55 | });
56 |
57 | # Full invocation, including pinning `nix` version itself.
58 | fullBuildScript = pkgs.writeShellScript "stack2nix-and-build-script.sh" ''
59 | set -eu -o pipefail
60 | STACK2NIX_OUTPUT_PATH=$(${stack2nix-script})
61 | ${pkgs.nix}/bin/nix-build --no-link -A static_package --argstr stack2nix-output-path "$STACK2NIX_OUTPUT_PATH" "$@"
62 | '';
63 |
64 | in
65 | {
66 | inherit static_package;
67 | inherit fullBuildScript;
68 | # For debugging:
69 | inherit stack2nix-script;
70 | inherit static-stack2nix-builder;
71 | }
72 |
--------------------------------------------------------------------------------
/static-stack2nix-builder-example/.gitignore:
--------------------------------------------------------------------------------
1 | .stack-work/
2 |
--------------------------------------------------------------------------------
/static-stack2nix-builder-example/README.md:
--------------------------------------------------------------------------------
1 | # example-project
2 |
3 | Example stack-based project that shows how to use `static-stack2nix-builder`.
4 |
5 | ## Usage in your project
6 |
7 | Copy the [`default.nix`](./default.nix) into your project, and adjust it as needed.
8 |
9 | It has instructions for running inside.
10 |
--------------------------------------------------------------------------------
/static-stack2nix-builder-example/Setup.hs:
--------------------------------------------------------------------------------
1 | import Distribution.Simple
2 | main = defaultMain
3 |
--------------------------------------------------------------------------------
/static-stack2nix-builder-example/app/Main.hs:
--------------------------------------------------------------------------------
1 | module Main where
2 |
3 | import Lib
4 |
5 | main :: IO ()
6 | main = someFunc
7 |
--------------------------------------------------------------------------------
/static-stack2nix-builder-example/default.nix:
--------------------------------------------------------------------------------
1 | # Run using:
2 | #
3 | # $(nix-build --no-link -A fullBuildScript)
4 | {
5 | stack2nix-output-path ? "custom-stack2nix-output.nix",
6 | }:
7 | let
8 | cabalPackageName = "example-project";
9 | compiler = "ghc8104"; # matching stack.yaml
10 |
11 | # Pin static-haskell-nix version.
12 | static-haskell-nix =
13 | if builtins.pathExists ../.in-static-haskell-nix
14 | then toString ../. # for the case that we're in static-haskell-nix itself, so that CI always builds the latest version.
15 | # Update this hash to use a different `static-haskell-nix` version:
16 | else fetchTarball https://github.com/nh2/static-haskell-nix/archive/57147ba740363712f589d24dfa005c8c7f6d1056.tar.gz;
17 |
18 | # Pin nixpkgs version
19 | # By default to the one `static-haskell-nix` provides, but you may also give
20 | # your own as long as it has the necessary patches, using e.g.
21 | # pkgs = import (fetchTarball https://github.com/nh2/nixpkgs/archive/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa123.tar.gz) {};
22 | pkgs = import "${static-haskell-nix}/nixpkgs.nix";
23 |
24 | stack2nix-script = import "${static-haskell-nix}/static-stack2nix-builder/stack2nix-script.nix" {
25 | inherit pkgs;
26 | inherit compiler;
27 | stack-project-dir = toString ./.; # where stack.yaml is
28 | hackageSnapshot = "2021-07-11T00:00:00Z"; # pins e.g. extra-deps without hashes or revisions
29 | };
30 |
31 | static-stack2nix-builder = import "${static-haskell-nix}/static-stack2nix-builder/default.nix" {
32 | normalPkgs = pkgs;
33 | inherit cabalPackageName compiler stack2nix-output-path;
34 | # disableOptimization = true; # for compile speed
35 | };
36 |
37 | # Full invocation, including pinning `nix` version itself.
38 | fullBuildScript = pkgs.writeShellScript "stack2nix-and-build-script.sh" ''
39 | set -eu -o pipefail
40 | STACK2NIX_OUTPUT_PATH=$(${stack2nix-script})
41 | export NIX_PATH=nixpkgs=${pkgs.path}
42 | ${pkgs.nix}/bin/nix-build --no-link -A static_package --argstr stack2nix-output-path "$STACK2NIX_OUTPUT_PATH" "$@"
43 | '';
44 |
45 | in
46 | {
47 | static_package = static-stack2nix-builder.static_package;
48 | inherit fullBuildScript;
49 | # For debugging:
50 | inherit stack2nix-script;
51 | inherit static-stack2nix-builder;
52 | }
53 |
--------------------------------------------------------------------------------
/static-stack2nix-builder-example/example-project.cabal:
--------------------------------------------------------------------------------
1 | cabal-version: 1.12
2 |
3 | -- This file has been generated from package.yaml by hpack version 0.31.2.
4 | --
5 | -- see: https://github.com/sol/hpack
6 | --
7 | -- hash: f29499e26d59c63f4043d8f0d8ba9bf25eb9fb9877cde46564e5e1579fe55b11
8 |
9 | name: example-project
10 | version: 0.1.0.0
11 | author: Niklas Hambüchen
12 | maintainer: mail@nh2.me
13 | license: BSD3
14 | build-type: Simple
15 |
16 | library
17 | exposed-modules:
18 | Lib
19 | other-modules:
20 | Paths_example_project
21 | hs-source-dirs:
22 | src
23 | build-depends:
24 | base >=4.7 && <5
25 | default-language: Haskell2010
26 |
27 | executable example-project-exe
28 | main-is: Main.hs
29 | other-modules:
30 | Paths_example_project
31 | hs-source-dirs:
32 | app
33 | ghc-options: -threaded -rtsopts -with-rtsopts=-N
34 | build-depends:
35 | base >=4.7 && <5
36 | , example-project
37 | default-language: Haskell2010
38 |
--------------------------------------------------------------------------------
/static-stack2nix-builder-example/package.yaml:
--------------------------------------------------------------------------------
1 | name: example-project
2 | version: 0.1.0.0
3 | license: BSD3
4 | author: "Niklas Hambüchen"
5 | maintainer: "mail@nh2.me"
6 |
7 | dependencies:
8 | - base >= 4.7 && < 5
9 |
10 | library:
11 | source-dirs: src
12 |
13 | executables:
14 | example-project-exe:
15 | source-dirs: app
16 | main: Main.hs
17 | ghc-options:
18 | - -threaded
19 | - -rtsopts
20 | - -with-rtsopts=-N
21 | dependencies:
22 | - example-project
23 |
--------------------------------------------------------------------------------
/static-stack2nix-builder-example/src/Lib.hs:
--------------------------------------------------------------------------------
1 | module Lib
2 | ( someFunc
3 | ) where
4 |
5 | someFunc :: IO ()
6 | someFunc = putStrLn "someFunc"
7 |
--------------------------------------------------------------------------------
/static-stack2nix-builder-example/stack.yaml:
--------------------------------------------------------------------------------
1 | resolver: lts-18.2
2 | packages:
3 | - .
4 |
--------------------------------------------------------------------------------
/static-stack2nix-builder/default.nix:
--------------------------------------------------------------------------------
1 | # Helper to build static executables from a Haskell stack project's source dir.
2 | # Use this after having generated a stack2nix output, e.g. with
3 | # `stack2nix-script.nix`.
4 | {
5 | # The name of the cabal package to build, e.g. "pandoc".
6 | cabalPackageName ? "myproject",
7 |
8 | # Compiler name in nixpkgs, e.g. "ghc8104".
9 | # Must match the one in the `resolver` in `stack.yaml`.
10 | # If you get this wrong, you'll likely get an error like
11 | # : cannot satisfy -package-id Cabal-2.4.1.0-ALhzvdqe44A7vLWPOxSupv
12 | # TODO: Make `stack2nix` tell us that.
13 | compiler ? "ghc8104",
14 |
15 | # Path to `stack2nix` output that shall be used as Haskell packages.
16 | # You should usually give this the store path that `stack2nix-script` outputs.
17 | stack2nix-output-path,
18 |
19 | # Pin nixpkgs version.
20 | normalPkgs ? import (fetchTarball https://github.com/nh2/nixpkgs/archive/8d536f36256d30d8fa47b24caafb1af6405889f3.tar.gz) {},
21 |
22 | # Use `integer-simple` instead of `integer-gmp` to avoid linking in
23 | # this LGPL dependency statically.
24 | integer-simple ? false,
25 |
26 | # Enable for faster building, but not proper releases.
27 | disableOptimization ? false,
28 | }:
29 | let
30 |
31 | static-haskell-nix_pkgsMusl = (import ../survey/default.nix {
32 | inherit normalPkgs;
33 | inherit compiler;
34 | inherit disableOptimization;
35 | }).pkgs;
36 |
37 | stack2nix_output = import stack2nix-output-path { pkgs = static-haskell-nix_pkgsMusl; };
38 |
39 | pkgs_with_stack2nix_packages_inside = static-haskell-nix_pkgsMusl.extend (final: previous: {
40 | haskell = final.lib.recursiveUpdate previous.haskell {
41 | packages."${compiler}" = stack2nix_output;
42 | };
43 | });
44 |
45 | haskell-static-nix_output = (import ../survey/default.nix {
46 | normalPkgs = pkgs_with_stack2nix_packages_inside;
47 | inherit compiler;
48 | inherit disableOptimization;
49 | inherit integer-simple;
50 | });
51 |
52 | static_package = haskell-static-nix_output.haskellPackages."${cabalPackageName}";
53 |
54 | # Provide this to make builds extra reproducible by also pinning the version
55 | # of `nix` itself, as changing nix versions can change the build env.
56 | pinnedNix = normalPkgs.nix;
57 |
58 | in {
59 | inherit static-haskell-nix_pkgsMusl;
60 | inherit stack2nix_output;
61 | inherit pkgs_with_stack2nix_packages_inside;
62 | inherit haskell-static-nix_output;
63 | inherit static_package;
64 | inherit pinnedNix;
65 | }
66 |
--------------------------------------------------------------------------------
/static-stack2nix-builder/stack2nix-script.nix:
--------------------------------------------------------------------------------
1 | # Creates a script that runs `stack2nix` on a given stack project's source dir.
2 | # Arguments given to the script are given to `stack2nix`.
3 | # Running the script adds the generated output file to the nix store
4 | # and prints the store store path to stdout.
5 | #
6 | {
7 | # nixpkgs to use.
8 | pkgs,
9 |
10 | # ghc to use; only because without a GHC on path, stack complains:
11 | # stack2nix: No compiler found, expected minor version match with ghc-8.10.4 (x86_64) (based on resolver setting ...
12 | # This happens even when using the Stack API (as stack2nix does),
13 | # and stack2nix doen't currently accept or set the `--system-ghc`
14 | # flag to skip the check (maybe it should to eschew this option;
15 | # I suspect our operation here never uses GHC).
16 | # TODO: This shouldn't be necessary since `stack2nix` commit
17 | # Set `--system-ghc` via stack API.
18 | # But somehow stack2nix still complains about it;
19 | # perhaps we didn't use the Stack API correctly.
20 | compiler,
21 |
22 | # Path to directory containing `stack.yaml`.
23 | stack-project-dir,
24 |
25 | # Hackage snapshot time to pass to `stack2nix`.
26 | # This determines the versions of package revisions in stack `extra-deps`
27 | # that are not pinned to a revision.
28 | # Example: "2019-05-08T00:00:00Z"
29 | hackageSnapshot,
30 |
31 | # stack.yaml file to use.
32 | # Must be in the `stack-project-dir` (usually next to wherever the normal
33 | # stack.yaml is) because Stack will search for its `packages` relative
34 | # to this file.
35 | # Useful when you want to give a customised stack.yaml,
36 | # e.g. when adding extra cabal flags to packages for static builds,
37 | # such as the `integer-simple` flag to the `text` library.
38 | stack-yaml ? "stack.yaml",
39 | }:
40 | # `stack2nix` requires `cabal` on $PATH.
41 | # We put our nixpkgs's version of `nix` on $PATH for reproducibility.
42 | # Everything but `nix-store --add` must print to stderr so that the
43 | # script prints only the final store path to stdout.
44 | # The output is generated to a `mktemp --directory` so that parallel
45 | # invocations don't influence each other.
46 | # Note in this script we should qualify all executables from nix packages
47 | # (or put them on PATH accordingly)
48 | # as it's run in the user's shell (not in a normal nix build environment,
49 | # since `stack2nix` needs internet access), so we can't make any assumptions
50 | # about shell builtins or what's on PATH. For example, if `mktemp` is from
51 | # `busybox` instead of `coreutils`, it may not support the `--directory`
52 | # option.
53 | # And for example the `nixos/nix` Docker container is minimal and supplies
54 | # many executables from `busybox`, such as `mktemp` and `wget`.
55 | let
56 | # Shell utils called by stack2nix or the script itself:
57 | add_to_PATH = [
58 | "${pkgs.coreutils}/bin" # `mktemp` et al
59 | "${pkgs.cabal-install}/bin" # `cabal`
60 | "${pkgs.nix}/bin" # various `nix-*` commands
61 | "${pkgs.wget}/bin" # `wget`
62 | "${pkgs.haskell.compiler.${compiler}}/bin" # `ghc` version matching target stack.yaml
63 | ];
64 |
65 | fixed_stack2nix =
66 | pkgs.haskellPackages.callCabal2nix "stack2nix" (pkgs.fetchFromGitHub {
67 | owner = "nh2";
68 | repo = "stack2nix";
69 | rev = "c20097d4edf82256484a733544579d4b5e0f2808";
70 | sha256 = "1lpwc20q62z9a9fpksd9q10x1jz8l29psx4dqsff759srj4chy9p";
71 | }) {};
72 | in
73 | pkgs.writeShellScript "stack2nix-build-script.sh" ''
74 | set -eu -o pipefail
75 | export NIX_PATH=nixpkgs=${pkgs.path}
76 | export PATH=${pkgs.lib.concatStringsSep ":" add_to_PATH}:$PATH
77 | OUT_DIR=$(mktemp --directory -t stack2nix-output-dir.XXXXXXXXXX)
78 | set -x
79 | ${fixed_stack2nix}/bin/stack2nix "${stack-project-dir}" --stack-yaml "${stack-yaml}" --hackage-snapshot "${hackageSnapshot}" -o "$OUT_DIR/stack2nix-output.nix" "$@" 1>&2
80 | nix-store --add "$OUT_DIR/stack2nix-output.nix"
81 | ''
82 |
--------------------------------------------------------------------------------
/submodules-update:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | [ "$SKIP_POST_CHECKOUT_HOOK" = 1 ] && exit 0
3 | git submodule sync && git submodule update --init --recursive
4 |
--------------------------------------------------------------------------------
/survey/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | tracing ? false, # Enable this to see debug traces
3 |
4 | normalPkgs ? import ../nixpkgs.nix,
5 |
6 | overlays ? [],
7 |
8 | approach ? # "pkgsMusl" or "pkgsStatic"
9 | # TODO `pkgsStatic` support is currently not maintained and will likely be removed,
10 | # because `pkgsMusl` is a better base for what we need.
11 | # See https://github.com/NixOS/nixpkgs/issues/61575
12 | # TODO Find out why `pkgsStatic` creates ~3x larger binaries.
13 | "pkgsMusl", # does not exercise cross compilation
14 | # "pkgsStatic", # exercises cross compilation
15 |
16 | # Note that we must NOT use something like `import normalPkgs.path {}`.
17 | # It is bad because it removes previous overlays.
18 | pkgs ? (normalPkgs.appendOverlays [
19 | ])."${approach}",
20 |
21 | # When changing this, also change the default version of Cabal declared below
22 | compiler ? "ghc965",
23 |
24 | # Tries to use `.a` files when evaluating TH, instead of `.so` files.
25 | useArchiveFilesForTemplateHaskell ? false,
26 |
27 | # See https://gitlab.haskell.org/ghc/ghc/-/wikis/commentary/libraries/version-history
28 | defaultCabalPackageVersionComingWithGhc ?
29 | ({
30 | ghc8107 = "Cabal_3_2_1_0";
31 | ghc902 = "Cabal_3_4_1_0";
32 | ghc928 = "Cabal_3_6_3_0";
33 | ghc948 = "Cabal_3_8_1_0";
34 | ghc963 = "Cabal_3_10_1_0";
35 | ghc965 = "Cabal_3_10_3_0";
36 | }."${compiler}"),
37 |
38 | # Use `integer-simple` instead of `integer-gmp` to avoid linking in
39 | # this LGPL dependency statically.
40 | integer-simple ? false,
41 |
42 | # Enable for fast iteration.
43 | # Note that this doesn't always work. I've already found tons of bugs
44 | # in packages when `-O0` is used, like
45 | # * https://github.com/bos/double-conversion/issues/26
46 | # * https://github.com/bos/blaze-textual/issues/11
47 | # and also a few ultra-weird errors like `hpack` failing to link with
48 | # errors like this when building `hpack` from a `stack2nix` project
49 | # built statically:
50 | # /nix/store/...-binutils-2.31.1/bin/ld: /nix/store/...-Cabal-2.4.1.0/lib/ghc-8.6.4/x86_64-linux-ghc-8.6.4/Cabal-2.4.1.0-.../libHSCabal-2.4.1.0-CZ6S6W3ko5J53WiB3G8d5G.a(Class.o):(.text.s2t5E_info+0x45): undefined reference to `parseczm3zi1zi13zi0zm2FiyouGhSt6Ln2s2okK4LQ_TextziParsecziPrim_zlz3fUzg2_info'
51 | # after which resuming the build with `./Setup build --ghc-option=-O`
52 | # (with `-O`!) I saw the likely cause:
53 | # /nix/store/waszsfh43jli6p8d0my8cb5ahrcksxif-Cabal-2.4.1.0/lib/ghc-8.6.4/x86_64-linux-ghc-8.6.4/Cabal-2.4.1.0-CZ6S6W3ko5J53WiB3G8d5G/Distribution/Parsec/Class.hi
54 | # Declaration for explicitEitherParsec
55 | # Unfolding of explicitEitherParsec:
56 | # Can't find interface-file declaration for variable $fApplicativeParsecT1
57 | # Probable cause: bug in .hi-boot file, or inconsistent .hi file
58 | # Use -ddump-if-trace to get an idea of which file caused the error
59 | # so use this carefully.
60 | # I hope that garbage like the last error will go away once we finally
61 | # no longer have to patch Cabal and inject it into packages.
62 | disableOptimization ? false,
63 | }:
64 |
65 | let
66 |
67 | trace = message: value:
68 | if tracing then builtins.trace message value else value;
69 |
70 | lib = pkgs.lib;
71 |
72 | approachPkgs = pkgs;
73 |
74 | # Function that tells us if a given entry in a `haskellPackages` package set
75 | # is a proper Haskell package (as opposed to some fancy function like
76 | # `.override` and the likes).
77 | isProperHaskellPackage = val:
78 | lib.isDerivation val && # must pass lib.isDerivation
79 | val ? env; # must have an .env key
80 |
81 | # Function that tells us if a given Haskell package has an executable.
82 | # Pass only Haskell packages to this!
83 | # Filter away other stuff with `isProperHaskellPackage` first.
84 | isExecutable = pkg:
85 | (pkgs.haskell.lib.overrideCabal pkg (drv: {
86 | passthru.isExecutable = drv.isExecutable or false;
87 | })).isExecutable;
88 |
89 | # Turn e.g. `Cabal_1_2_3_4` into `1.2.3.4`.
90 | cabalDottedVersion =
91 | builtins.replaceStrings ["_"] ["."]
92 | (builtins.substring
93 | (builtins.stringLength "Cabal_")
94 | (builtins.stringLength defaultCabalPackageVersionComingWithGhc)
95 | defaultCabalPackageVersionComingWithGhc
96 | );
97 |
98 | areCabalPatchesRequired =
99 | builtins.length (requiredCabalPatchesList cabalDottedVersion) != 0;
100 |
101 | # Nixpkgs contains both Hackage and Stackage packages.
102 | # We want to build only executables that are on Stackage because
103 | # we know that those should build.
104 | # Find all Stackage package names here so we can use them
105 | # as a filter.
106 | # Done by parsing the configuration file that contains
107 | # which packages come from Stackage.
108 | # Contains a list of package names (strings).
109 | stackagePackages =
110 | let
111 | stackageInfoPath = pkgs.path + "/pkgs/development/haskell-modules/configuration-hackage2nix/stackage.yaml";
112 | pythonWithYaml = normalPkgs.python3Packages.python.withPackages (pkgs: [pkgs.pyyaml]);
113 | stackage-packages-file = normalPkgs.runCommand "stackage-packages" {} ''
114 | ${pythonWithYaml}/bin/python -c 'import yaml, json; x = yaml.safe_load(open("${stackageInfoPath}")); print(json.dumps([line.split(" ")[0] for line in x["default-package-overrides"]]))' > $out
115 | '';
116 | stackage-packages = builtins.fromJSON (builtins.readFile stackage-packages-file);
117 | in
118 | stackage-packages;
119 |
120 | # Turns a list into a "set" (map where all values are {}).
121 | keySet = list: builtins.listToAttrs (map (name: lib.nameValuePair name {}) list);
122 |
123 | # Making it a set for faster lookup
124 | stackagePackagesSet = keySet stackagePackages;
125 | isStackagePackage = name: builtins.hasAttr name stackagePackagesSet;
126 |
127 | stackageCommit = "8832644c5601994e27f4c5a0d986941c85b52abc";
128 | stackage-build-constraints-yaml = pkgs.fetchurl {
129 | # Needs to be updated when nixpkgs updates the Stackage LTS from which packages come.
130 | # But we use it only for the blacklist so keeping it tightly up to date is not so critical.
131 | url = "https://raw.githubusercontent.com/commercialhaskell/stackage/${stackageCommit}/build-constraints.yaml";
132 | sha256 = "1g9w1bicjbji52zjkspa9vqw0ghy8zm59wcmrb53iz87h23c0qkh";
133 | };
134 | # The Stackage `build-constraints.yaml` filed as a nix value.
135 | stackage-build-constraints =
136 | let
137 | pythonWithYaml = pkgs.python3Packages.python.withPackages (pkgs: [pkgs.pyyaml]);
138 | # We remove the "packages" key because that one has all the author names,
139 | # which contain unicode escapes, which `builtins.fromJSON` cannot handle
140 | # (as of nix 2.0.4).
141 | build-constraints-json-file = normalPkgs.runCommand "stackage-build-constraints-${stackageCommit}.json" {} ''
142 | ${pythonWithYaml}/bin/python -c 'import yaml, json; x = yaml.load(open("${stackage-build-constraints-yaml}")); del x["packages"]; print(json.dumps(x))' > $out
143 | '';
144 | in
145 | builtins.fromJSON (builtins.readFile build-constraints-json-file);
146 |
147 | buildPlatformHaskellPackagesWithFixedCabal = with pkgs.haskell.lib;
148 | let
149 | # For cross (`pkgsStatic`) the Setup.hs -> ./Setup compilation happens on
150 | # the *host* platform, not the target platform, so we need to use the
151 | # normal (no-musl) Cabal for that.
152 | # For non-cross (`pkgsMusl`) we need to use the musl-Cabal because
153 | # otherwise we get linking errors with missing glibc symbols.
154 | pkgsToUseForSetupExe =
155 | if approach == "pkgsStatic"
156 | then normalPkgs
157 | else pkgs;
158 | haskellPackagesToUseForSetupExe =
159 | if integer-simple
160 | then pkgsToUseForSetupExe.haskell.packages.integer-simple."${compiler}"
161 | else pkgsToUseForSetupExe.haskell.packages."${compiler}";
162 | in
163 | haskellPackagesToUseForSetupExe.override (old: {
164 | overrides = pkgs.lib.composeExtensions (old.overrides or (_: _: {})) (self: super: {
165 |
166 | Cabal =
167 | # Note [When Cabal is `null` in a package set]
168 | #
169 | # If null, super.Cabal is a non-overriden package coming with GHC.
170 | # In that case, we can't patch it (we can't add patches to derivations that are null).
171 | # So we need to instead add a not-with-GHC Cabal package and patch that.
172 | # The best choice for that is the version that comes with the GHC.
173 | # Unfortunately we can't query that easily, so we maintain that manually
174 | # in `defaultCabalPackageVersionComingWithGhc`.
175 | # Currently all our Cabal patches are upstreamed, so this is technically
176 | # not necessary currently; however, we keep this infrastructure in case
177 | # we need to patch Cabal again in the future.
178 | #
179 | # If there are no patches to apply, keep original Cabal,
180 | # even if `null` (to get the one that comes with GHC).
181 | if not areCabalPatchesRequired
182 | then super.Cabal
183 | else
184 | if builtins.isNull super.Cabal
185 | then applyPatchesToCabalDrv super."${defaultCabalPackageVersionComingWithGhc}"
186 | else applyPatchesToCabalDrv super.Cabal;
187 |
188 | });
189 | });
190 |
191 | # TODO `haskellPackagesWithFailingStackageTestsDisabled` is currently unused
192 | # now that we've switched to overlays, we may want to use it again in the future.
193 |
194 | # A `haskellPackages` set in which tests are skipped (`dontCheck`) for
195 | # all packages that are marked as failing their tests on Stackage
196 | # or known for failing their tests for other reasons.
197 | # Note this may disable more tests than necessary because some packages'
198 | # tests may work fine in nix when they don't work on Stackage,
199 | # for example due to more system dependencies being available.
200 | haskellPackagesWithFailingStackageTestsDisabled = with pkgs.haskell.lib; haskellPackages.override (old: {
201 | overrides = pkgs.lib.composeExtensions (old.overrides or (_: _: {})) (self: super:
202 | let
203 | # This map contains the package names that we don't want to run tests on,
204 | # either because they fail on Stackage or because they fail for us
205 | # with specific reasons given.
206 | skipTestPackageNames =
207 | stackage-build-constraints.expected-test-failures ++
208 | stackage-build-constraints.skipped-tests ++
209 | [
210 | # Tests don't pass on local checkout either (checked on ef3e203e9578)
211 | # because its own executable is not in PATH ("ghc: could not execute: doctest-driver-gen")
212 | "doctest-driver-gen"
213 | # https://github.com/ekmett/ad/issues/73 (floating point precision)
214 | # TODO: Remove when https://github.com/ekmett/ad/pull/76 is merged and available
215 | "ad"
216 | ];
217 | # Making it a set for faster lookup
218 | failuresSet = keySet skipTestPackageNames;
219 | isFailure = name: builtins.hasAttr name failuresSet;
220 |
221 | packagesWithTestsToDisable =
222 | lib.filterAttrs (name: value:
223 | if isFailure name
224 | then
225 | trace "disabling tests (because it is in skipTestPackageNames) for ${name}"
226 | true
227 | else false
228 | ) super;
229 | packagesWithTestsDisabled =
230 | lib.mapAttrs (name: value:
231 | # We have to do a null check because some builtin packages like
232 | # `text` seem to have just `null` as a value. Not sure why that is.
233 | (if value != null then dontCheck value else value)
234 | ) packagesWithTestsToDisable;
235 | numPackagesTestsDisabled = lib.length (builtins.attrNames packagesWithTestsDisabled);
236 | in
237 | trace "Disabled tests for ${toString numPackagesTestsDisabled} packages"
238 | packagesWithTestsDisabled
239 | );
240 | });
241 |
242 |
243 | # Stackage package names we want to blacklist.
244 | blacklist = [
245 | # TODO: Try to remove when https://github.com/NixOS/nixpkgs/pull/128746 is available to us
246 | "alsa-pcm" "alsa-seq" "ALUT" "OpenAL" "sdl2" "sdl2-gfx" "sdl2-image" "sdl2-mixer" "sdl2-ttf"
247 |
248 | # depends on `sbv` -> `openjdk`, which pulls in a huge dependency closure
249 | "crackNum"
250 |
251 | # Incorrectly depends on `ocaml`, which `pkgsMusl` cannot currently build
252 | # (error: `ld: -r and -pie may not be used together`).
253 | # TODO: Remove when https://github.com/NixOS/cabal2nix/pull/509 has landed.
254 | "liquid-fixpoint"
255 |
256 | # Doesn't build in `normalPkgs.haskellPackages` either
257 | "mercury-api"
258 |
259 | # https://github.com/nh2/static-haskell-nix/issues/6#issuecomment-420494800
260 | "sparkle"
261 |
262 | # These ones currently don't compile for not-yet-investigated reasons:
263 | "amqp-utils"
264 | "elynx"
265 | "hopenpgp-tools"
266 | "hw-eliasfano"
267 | "hw-ip"
268 | "leveldb-haskell"
269 | "mpi-hs"
270 | "mpi-hs-binary"
271 | "mpi-hs-cereal"
272 | "place-cursor-at"
273 | "sandwich-webdriver"
274 | "slynx"
275 | "spacecookie"
276 | "zip"
277 | ];
278 |
279 | # All Stackage executables who (and whose dependencies) are not marked
280 | # as broken in nixpkgs.
281 | # This is a subset of a `haskellPackages` package set.
282 | stackageExecutables =
283 | let
284 | normalHaskellPackages =
285 | if integer-simple
286 | then pkgs.haskell.packages.integer-simple."${compiler}"
287 | else pkgs.haskell.packages."${compiler}";
288 |
289 | stackageExecutables =
290 | let
291 | # Predicate copied from nixpkgs' `transitive-broken-packages.nix`:
292 | isEvaluatingUnbroken = v: (builtins.tryEval (v.outPath or null)).success && lib.isDerivation v && !v.meta.broken;
293 | in
294 | lib.filterAttrs
295 | (name: p:
296 | p != null && # packages that come with GHC are `null`
297 | isStackagePackage name &&
298 | !(lib.elem name blacklist) &&
299 | isExecutable p &&
300 | isEvaluatingUnbroken p
301 | )
302 | normalHaskellPackages;
303 |
304 | stackageExecutablesNames = builtins.attrNames stackageExecutables;
305 | nMany = lib.length stackageExecutablesNames;
306 | in
307 | trace
308 | ("selected stackage executables:\n"
309 | + lib.concatStringsSep "\n" stackageExecutablesNames
310 | + "\n---\n${toString nMany} Stackage executables total"
311 | )
312 | stackageExecutables;
313 |
314 | # Making it a set for faster lookup
315 | stackageExecutablesSet = keySet (builtins.attrNames stackageExecutables);
316 | isStackageExecutable = name: builtins.hasAttr name stackageExecutablesSet;
317 |
318 | # Cherry-picking cabal fixes
319 |
320 | makeCabalPatch = { name, url, sha256 }:
321 | let
322 | # We use `runCommand` on a plain patch file instead of using
323 | # `fetchpatch`'s `includes` or `stripLen` features to not run
324 | # into the perils of:
325 | # https://github.com/NixOS/nixpkgs/issues/48567
326 | plainPatchFile = pkgs.fetchpatch { inherit name url sha256; };
327 |
328 | # Explanation:
329 | # * A patch created for the cabal project's source tree will
330 | # always have subdirs `Cabal` and `cabal-install`; the
331 | # `Cabal` nix derivation is already the `Cabal` subtree.
332 | # * We run `filterdiff -i` to keep only changes from the patch
333 | # that apply to the `Cabal` subtree.
334 | # * We run `filterdiff -x` to remove Changelog files which
335 | # almost always conflict.
336 | # * `-p1` strips away the `a/` and `b/` before `-i`/`-x` apply.
337 | # * `strip=2` removes e.g `a/Cabal` so that the patch applies
338 | # directly to that source tree, `--add*prefix` adds back the
339 | # `a/` and `b/` that `patch -p1` expects.
340 | patchOnCabalLibraryFilesOnly = pkgs.runCommand "${name}-Cabal-only" {} ''
341 | ${pkgs.patchutils}/bin/filterdiff \
342 | -p1 -i 'Cabal/*' -x 'Cabal/ChangeLog.md' \
343 | --strip=2 --addoldprefix=a/ --addnewprefix=b/ \
344 | ${plainPatchFile} > $out
345 |
346 | if [ ! -s "$out" ]; then
347 | echo "error: Filtered patch '$out' is empty (while the original patch file was not)!" 1>&2
348 | echo "Check your includes and excludes." 1>&2
349 | echo "Normalizd patch file was:" 1>&2
350 | cat "${plainPatchFile}" 1>&2
351 | exit 1
352 | fi
353 | '';
354 |
355 | in
356 | patchOnCabalLibraryFilesOnly;
357 |
358 | # Returns the list of patches that a given cabal derivation needs to work well
359 | # for static building.
360 | requiredCabalPatchesList = cabalDottedVersionString:
361 | # Patches we know are merged in a certain cabal version
362 | # (we include them conditionally here anyway, for the case
363 | # that the user specifies a different Cabal version e.g. via
364 | # `stack2nix`):
365 | if pkgs.lib.versionOlder cabalDottedVersionString "3.0.0.0"
366 | then
367 | (builtins.concatLists [
368 | # -L flag deduplication
369 | # https://github.com/haskell/cabal/pull/5356
370 | (lib.optional (pkgs.lib.versionOlder cabalDottedVersionString "2.4.0.0") (makeCabalPatch {
371 | name = "5356.patch";
372 | url = "https://github.com/haskell/cabal/commit/fd6ff29e268063f8a5135b06aed35856b87dd991.patch";
373 | sha256 = "1l5zwrbdrra789c2sppvdrw3b8jq241fgavb8lnvlaqq7sagzd1r";
374 | }))
375 | # Patches that as of writing aren't merged yet:
376 | ]) ++ [
377 | # TODO Move this into the above section when merged in some Cabal version:
378 | # --enable-executable-static
379 | # https://github.com/haskell/cabal/pull/5446
380 | (if pkgs.lib.versionOlder cabalDottedVersionString "2.4.0.0"
381 | then
382 | # Older cabal, from https://github.com/nh2/cabal/commits/dedupe-more-include-and-linker-flags-enable-static-executables-flag-pass-ld-options-to-ghc-Cabal-v2.2.0.1
383 | (makeCabalPatch {
384 | name = "5446.patch";
385 | url = "https://github.com/haskell/cabal/commit/748f07b50724f2618798d200894f387020afc300.patch";
386 | sha256 = "1zmbalkdbd1xyf0kw5js74bpifhzhm16c98kn7kkgrwql1pbdyp5";
387 | })
388 | else
389 | (makeCabalPatch {
390 | name = "5446.patch";
391 | url = "https://github.com/haskell/cabal/commit/cb221c23c274f79dcab65aef3756377af113ae21.patch";
392 | sha256 = "02qalj5y35lq22f19sz3c18syym53d6bdqzbnx9f6z3m7xg591p1";
393 | })
394 | )
395 | # TODO Move this into the above section when merged in some Cabal version:
396 | # ld-option passthrough
397 | # https://github.com/haskell/cabal/pull/5451
398 | (if pkgs.lib.versionOlder cabalDottedVersionString "2.4.0.0"
399 | then
400 | # Older cabal, from https://github.com/nh2/cabal/commits/dedupe-more-include-and-linker-flags-enable-static-executables-flag-pass-ld-options-to-ghc-Cabal-v2.2.0.1
401 | (makeCabalPatch {
402 | name = "5451.patch";
403 | url = "https://github.com/haskell/cabal/commit/b66be72db3b34ea63144b45fcaf61822e0fade87.patch";
404 | sha256 = "0hndkfb96ry925xzx85km8y8pfv5ka5jz3jvy3m4l23jsrsd06c9";
405 | })
406 | else
407 | (makeCabalPatch {
408 | name = "5451.patch";
409 | url = "https://github.com/haskell/cabal/commit/0aeb541393c0fce6099ea7b0366c956e18937791.patch";
410 | sha256 = "0pa9r79730n1kah8x54jrd6zraahri21jahasn7k4ng30rnnidgz";
411 | })
412 | )
413 | ]
414 | # cabal >= 3.0.0.0 currently needs no patches.
415 | else [];
416 |
417 | applyPatchesToCabalDrv = cabalDrv: pkgs.haskell.lib.overrideCabal cabalDrv (old: {
418 | patches = (old.patches or []) ++ requiredCabalPatchesList cabalDrv.version;
419 | });
420 |
421 | useFixedCabal = if !areCabalPatchesRequired then (drv: drv) else
422 | let
423 | patchIfCabal = drv:
424 | if (drv.pname or "") == "Cabal" # the `ghc` package has not `pname` attribute, so we default to "" here
425 | then applyPatchesToCabalDrv drv
426 | else drv;
427 | patchCabalInPackageList = drvs:
428 | let
429 | # Packages that come with the GHC version used have
430 | # `null` as their derivation (e.g. `text` or `Cabal`
431 | # if they are not overridden). We filter them out here.
432 | nonNullPackageList = builtins.filter (drv: !(builtins.isNull drv)) drvs;
433 | in
434 | map patchIfCabal nonNullPackageList;
435 | fixedCabal = buildPlatformHaskellPackagesWithFixedCabal.Cabal;
436 | in
437 | drv: (pkgs.haskell.lib.overrideCabal drv (old: {
438 | # If the package already depends on some explicit version
439 | # of Cabal, patch it, so that it has --enable-executable-static.
440 | # If it doesn't (it depends on the version of Cabal that comes
441 | # with GHC instead), add the same version that comes with
442 | # that GHC, but with our patches.
443 | # Unfortunately we don't have the final package set at hand
444 | # here, so we use the `haskellPackagesWithLibsReadyForStaticLinking`
445 | # one instead which has set `Cabal = ...` appropriately.
446 | setupHaskellDepends = patchCabalInPackageList ((old.setupHaskellDepends or []) ++ [fixedCabal]);
447 | # We don't need to add it to `libraryHaskellDepends` (see note
448 | # [Fixed Cabal for Setup.hs->somePackage->Cabal dependencies])
449 | # here because we already add it to the package set itself
450 | # down in `haskellLibsReadyForStaticLinkingOverlay`.
451 | # In fact, adding it here breaks e.g. the example in
452 | # `static-stack`, because `stack2nix` adds stacks specified
453 | # `Cabal` dependency as `libraryHaskellDepends`
454 | # (which is then patched via `applyPatchesToCabalDrv` in
455 | # `haskellLibsReadyForStaticLinkingOverlay`) and adding
456 | # it here would add a second, different Cabal version to the
457 | # ghc package DB.
458 | })).overrideAttrs (old: {
459 | # Adding the fixed Cabal version to `setupHaskellDepends` is not enough:
460 | # There may already be one in there, in which case GHC picks an
461 | # arbitrary one.
462 | # So we determine the package key of the Cabal we want, and pass it
463 | # directly to GHC.
464 | # Tip: If you want to debug this when it's failing, see
465 | # https://github.com/NixOS/nixpkgs/issues/65210#issuecomment-513515829
466 | # A common reason for it to fail is when the wrong `compiler` is given;
467 | # in that case, the build log of the `Cabal` package involved will show
468 | # two different ghc versions, and the output's `lib` directory will also
469 | # contain 2 different ghc versions (one with the `.o` files and one with
470 | # the `.conf` file).
471 | preCompileBuildDriver = ''
472 | cabalPackageId=$(basename --suffix=.conf ${fixedCabal}/lib/ghc-*/package.conf.d/*.conf)
473 | echo "Determined cabalPackageId as $cabalPackageId"
474 |
475 | setupCompileFlags="$setupCompileFlags -package-id $cabalPackageId"
476 | '';
477 | });
478 |
479 | # Takes a zlib derivation and overrides it to have both .a and .so files.
480 | statify_zlib = zlib_drv:
481 | (zlib_drv.override {
482 | shared = true;
483 | static = true;
484 | splitStaticOutput = false;
485 | }).overrideAttrs (old: { dontDisableStatic = true; });
486 |
487 | # Takes a curl derivation and overrides it to have both .a and .so files,
488 | # and have the `curl` executable be statically linked.
489 | statify_curl_including_exe = curl_drv: zlib_both:
490 | (curl_drv.override (old: {
491 | # Disable gss support, because that requires `krb5`, which
492 | # (as mentioned in note [krb5 can only be static XOR shared]) is a
493 | # library that cannot build both .a and .so files in its build system.
494 | # That means that if we enable it, we can no longer build the
495 | # dynamically-linked `curl` binary from the overlay
496 | # `archiveFilesOverlay` below where `statify_curl_including_exe` is used.
497 | gssSupport = false;
498 | zlib = zlib_both;
499 | brotliSupport = false; # When brotli is enabled, the `curl` package currently fails to link in `CCLD curl` with error `ld: ../lib/.libs/libcurl.so: undefined reference to `_kBrotliPrefixCodeRanges'`
500 | })).overrideAttrs (old: {
501 | dontDisableStatic = true;
502 |
503 | configureFlags = (old.configureFlags or []) ++ [
504 | "--enable-static"
505 | # Use environment variable to override the `pkg-config` command
506 | # to have `--static`, as even curl's `--enable-static` configure option
507 | # does not currently make it itself invoke `pkg-config` with that flag.
508 | # See: https://github.com/curl/curl/issues/503#issuecomment-150680789
509 | # While one would usually do
510 | # PKG_CONFIG="pkg-config --static" ./configure ...
511 | # nix's generic stdenv builder does not support passing environment
512 | # variables before `./configure`, and doing `PKG_CONFIG = "false";`
513 | # as a nix attribute doesn't work either for unknown reasons
514 | # (it gets set in the `bash` executing the build, but something resets
515 | # it for the child process invocations); luckily, `./configure`
516 | # also accepts env variables at the end as arguments.
517 | # However, they apparently have to be single paths, so passing
518 | # ./configure ... PKG_CONFIG="pkg-config --static"
519 | # does not work, so we use `writeScript` instead.
520 | #
521 | # (Personally I think that passing `--enable-static` to curl should
522 | # probably instruct it to pass `--static` to `pkg-config` itself.)
523 | "PKG_CONFIG=${pkgs.writeScript "pkgconfig-static-wrapper" "exec pkg-config --static $@"}"
524 | ];
525 |
526 | # Additionally, flags to also build a static `curl` executable:
527 |
528 | # Note: It is important that in the eventual `libtool` invocation,
529 | # `-all-static` comes before (or instead of) `-static`.
530 | # This is because the first of them "wins setting the mode".
531 | # See https://lists.gnu.org/archive/html/libtool/2006-12/msg00047.html
532 | # libtool makes various problems with static linking.
533 | # Some of them are is well-described by
534 | # https://github.com/sabotage-linux/sabotage/commit/57a989a2e23c9e46501da1227f371da59d212ae4
535 | # However, so far, `-all-static` seems to have the same effect
536 | # of convincing libtool to NOT drop the `-static` flag.
537 | # Other places where this was dicussed (in case you have to debug this in
538 | # the future) are:
539 | # https://debbugs.gnu.org/cgi/bugreport.cgi?bug=11064
540 | # https://github.com/esnet/iperf/issues/632
541 | # Another common thing that people do is to pass `-static --static`,
542 | # with the intent that `--static` isn't eaten by libtool but still
543 | # accepted by e.g. gcc. In our case as of writing (nixpkgs commit bc94dcf50),
544 | # this isn't enough. That is because:
545 | # * The `--with-*=/path` options given to curl's `./configure`
546 | # are usually `.lib` split outputs that contain only headers and
547 | # pkg-config `.pc` files. OK so far.
548 | # * For some of these, e.g. for libssh2, curl's `./configure` turns them
549 | # into `LDFLAGS=-L/...libssh2-dev/lib`, which doesn't do anything to
550 | # libtool, gcc or ld, because `*-dev/lib` contains only `lib/pkgconfig`
551 | # and no libraries.
552 | # * But for others, e.g. for libnghttp2, curl's `./configure` resolves
553 | # them by taking the actual `-L` flags out of the `.pc` file, and turns
554 | # them into e.g. `LDFLAGS=-L/...nghttp2-lib/lib`, which contains
555 | # `{ *.la, *.a, *.so }`.
556 | # * When libtool is invoked with such `LDFLAGS`, it adds two entries to
557 | # `./lib/libcurl.la`'s `dependency_libs=`: `-L/...nghttp2-lib/lib` and
558 | # `/...nghttp2-lib/lib/*.la`.
559 | # When the `.la` path is given, libtool will read it, and pass the
560 | # `.so` file referred to within as a positional argument to e.g. gcc,
561 | # even when linking statically, which will result in linker error
562 | # ld: attempted static link of dynamic object `/...-nghttp2-lib/lib/libnghttp2.so'
563 | # I believe this is what
564 | # https://github.com/sabotage-linux/sabotage/commit/57a989a2e23c9e46501da1227f371da59d212ae4
565 | # fixes.
566 | # If we pass `-all-static` to libtool, it won't do the things in the last
567 | # bullet point, causing static linking to succeed.
568 | makeFlags = [ "curl_LDFLAGS=-all-static" ];
569 | });
570 |
571 |
572 | fixGhc = ghcPackage0: lib.pipe ghcPackage0 [
573 | # musl does not support libdw's alleged need for `dlopen()`, see:
574 | # https://github.com/nh2/static-haskell-nix/pull/116#issuecomment-1585786484
575 | #
576 | # Nixpkgs has the `enableDwarf` argument only for GHCs versions that are built
577 | # with Hadrian (`common-hadrian.nix`), which in nixpkgs is the case for GHC >= 9.6.
578 | # So set `enableDwarf = true`, but not for older versions known to not use Hadrian.
579 | (ghcPackage:
580 | if lib.any (prefix: lib.strings.hasPrefix prefix compiler) ["ghc8" "ghc90" "ghc92" "ghc94"]
581 | then ghcPackage # GHC < 9.6, no Hadrian
582 | else ghcPackage.override { enableDwarf = false; }
583 | )
584 | (ghcPackage:
585 | ghcPackage.override {
586 | enableRelocatedStaticLibs = useArchiveFilesForTemplateHaskell;
587 | enableShared = !useArchiveFilesForTemplateHaskell;
588 | }
589 | )
590 | ];
591 |
592 |
593 | # For static builds, all `buildInputs` should become `propagatedBuildInputs`.
594 | # This is because a final link will necessarily have access to all recursive
595 | # dependencies.
596 | #
597 | # (`pkgsStatic` does this too, as `makeStatic` in `adapters.nix` uses
598 | # the `propagateBuildInputs` adapter.)
599 | #
600 | # Examples where this matters:
601 | #
602 | # * `pkg-config`:
603 | # * `libwebp` depends on `libtiff` which depends on `lerc`.
604 | # `libtiff-4.pc` correctly declares (with my patch
605 | # https://gitlab.com/libtiff/libtiff/-/merge_requests/633):
606 | #
607 | # Libs.private: -llzma -lLerc -ljpeg -ldeflate -lz -lm
608 | # Requires.private: liblzma Lerc libjpeg libdeflate zlib
609 | #
610 | # But the `.pc` file does not include the path on which `libLerc.a`
611 | # can be found.
612 | # Thus we would normally get error:
613 | #
614 | # cannot find -lLerc: No such file or directory
615 | #
616 | # That is supposed to be resolved via `pkg-config --static --libs libtiff-4`,
617 | # which is supposed to chase down the `Requires.private: Lerc` dependency,
618 | # finding the correct path of `libLerc.a` from `Lerc.pc`.
619 | # But for that to work `Lerc.pc` must be on `PKG_CONFIG_PATH`.
620 | # nixpkgs includes the `PKG_CONFIG_PATH` of `lerc` in the build
621 | # of `libwebp` only if `lerc` is in `propagatedBuildInputs` of `libtiff`.
622 | propagatedBuildInputsOverlay = final: previous: {
623 | # Doing this like `pkgsStatic` does it via `makeStatic` in `adapters.nix`.
624 | # Problem build error:
625 | # error: build of '/nix/store/...-stdenv-linux.drv' failed: output '/nix/store/...-stdenv-linux' is not allowed to refer to the following paths:
626 | # /nix/store/...-binutils-patchelfed-ld-wrapper-2.41
627 | # /nix/store/...-pcre2-10.43-dev
628 | # /nix/store/...-gmp-with-cxx-6.3.0-dev
629 | # /nix/store/...-musl-iconv-1.2.3
630 | # /nix/store/...-binutils-2.41
631 | # /nix/store/...-bootstrap-tools
632 | #
633 | # Tipp by sterni:
634 | #
635 | # You only want to apply the adapter to the `pkgsHostTarget` package set's `stdenv`.
636 | # There is no clean way to really detect in an overlay what
637 | # "absolute" position in the chained package sets you are modifying.
638 | # `pkgsStatic` uses `isStatic` as an indicator
639 | # (see `adaptStdenv` in `pkgs/stdenv/cross/default.nix`).
640 | # (I suppose this adapter will only work for cross nixpkgs in its current state.)
641 | stdenv = previous.stdenvAdapters.propagateBuildInputs previous.stdenv;
642 | };
643 |
644 | # Workaround to the above, overriding packages manually that need it.
645 | propagatedBuildInputsManuallyOverlay = final: previous:
646 | let
647 | prop = drv: drv.overrideAttrs (oldAttrs: {
648 | propagatedBuildInputs = (oldAttrs.propagatedBuildInputs or []) ++ (oldAttrs.buildInputs or []);
649 | });
650 | in
651 | {
652 | libtiff = prop previous.libtiff;
653 | gd = prop previous.gd;
654 | };
655 |
656 | # pkgsPropagatedBuildInputs = pkgs.extend propagatedBuildInputsOverlay;
657 | pkgsPropagatedBuildInputs = pkgs.extend propagatedBuildInputsManuallyOverlay;
658 |
659 |
660 | applyDontDisableStatic = pkgsSet: lib.mapAttrs (pkgName: pkgValue:
661 | if pkgValue ? overrideAttrs then
662 | pkgValue.overrideAttrs (old: { dontDisableStatic = true; })
663 | else
664 | pkgValue)
665 | pkgsSet;
666 |
667 | dontDisableStaticOverlay = final: previous:
668 | (applyDontDisableStatic previous) // {
669 | xorg = applyDontDisableStatic previous.xorg;
670 | };
671 |
672 | pkgsDontDisableStatic = pkgsPropagatedBuildInputs.extend dontDisableStaticOverlay;
673 |
674 |
675 | # Overlay that enables `.a` files for as many system packages as possible.
676 | # This is in *addition* to `.so` files.
677 | # See also https://github.com/NixOS/nixpkgs/issues/61575
678 | # TODO Instead of overriding each individual package manually,
679 | # override them all at once similar to how `makeStaticLibraries`
680 | # in `adapters.nix` does it (but without disabling shared).
681 | archiveFilesOverlay = final: previous: {
682 |
683 | # Note [Packages that cause bootstrap compiler recompilation]
684 | # The following packages are compiler bootstrap dependencies.
685 | # While we could override them to have static libraries
686 | # (now that https://github.com/NixOS/nixpkgs/issues/61682 is fixed),
687 | # we don't currently because that would make even the compiler bootstrapping recompile.
688 | # Instead we make up new package names with `_static` at the end,
689 | # and explicitly give them to packages.
690 | # See also the above link for the total list of packages that are relevant for this.
691 | # As of original finding it is, as per `pkgs/stdenv/linux/default.nix`:
692 | # gzip bzip2 xz bash coreutils diffutils findutils gawk
693 | # gnumake gnused gnutar gnugrep gnupatch patchelf
694 | # attr acl zlib pcre
695 | # TODO: Check if this really saves enough compilation to be worth the added complexity.
696 | # Alternatively, try to override the bootstrap compiler to use the original
697 | # ones; then we can override the normal names here.
698 | acl_static = previous.acl.overrideAttrs (old: { dontDisableStatic = true; });
699 | attr_static = previous.attr.overrideAttrs (old: { dontDisableStatic = true; });
700 | bash_static = previous.bash.overrideAttrs (old: { dontDisableStatic = true; });
701 | bzip2_static = (previous.bzip2.override { enableStatic = true; }).overrideAttrs (old: { dontDisableStatic = true; });
702 | coreutils_static = previous.coreutils.overrideAttrs (old: { dontDisableStatic = true; });
703 | diffutils_static = previous.diffutils.overrideAttrs (old: { dontDisableStatic = true; });
704 | findutils_static = previous.findutils.overrideAttrs (old: { dontDisableStatic = true; });
705 | gawk_static = previous.gawk.overrideAttrs (old: { dontDisableStatic = true; });
706 | gnugrep_static = previous.gnugrep.overrideAttrs (old: { dontDisableStatic = true; });
707 | gnumake_static = previous.gnumake.overrideAttrs (old: { dontDisableStatic = true; });
708 | gnupatch_static = previous.gnupatch.overrideAttrs (old: { dontDisableStatic = true; });
709 | gnused_static = previous.gnused.overrideAttrs (old: { dontDisableStatic = true; });
710 | gnutar_static = previous.gnutar.overrideAttrs (old: { dontDisableStatic = true; });
711 | gzip_static = previous.gzip.overrideAttrs (old: { dontDisableStatic = true; });
712 | patchelf_static = previous.patchelf.overrideAttrs (old: { dontDisableStatic = true; });
713 | pcre_static = previous.pcre.overrideAttrs (old: { dontDisableStatic = true; });
714 | xz_static = previous.xz.overrideAttrs (old: { dontDisableStatic = true; });
715 | zlib_both = statify_zlib previous.zlib;
716 | # Also override the original packages with a throw (which as of writing
717 | # has no effect) so we can know when the bug gets fixed in the future.
718 | # [previously there were overrides here, but they stopped working, read below]
719 | # For unknown reason we can't do this check on `zlib`, because if we do, we get:
720 | #
721 | # while evaluating the attribute 'zlib_static' at /home/niklas/src/haskell/static-haskell-nix/survey/default.nix:498:5:
722 | # while evaluating the attribute 'zlib.override' at /home/niklas/src/haskell/static-haskell-nix/survey/default.nix:525:5:
723 | # while evaluating 'issue_61682_throw' at /home/niklas/src/haskell/static-haskell-nix/survey/default.nix:455:29, called from /home/niklas/src/haskell/static-haskell-nix/survey/default.nix:525:12:
724 | # If you see this, nixpkgs #61682 has been fixed and zlib should be overridden
725 | #
726 | # So somehow, the above `zlib_static` uses *this* `zlib`, even though
727 | # the above uses `previous.zlib.override` and thus shouldn't see this one.
728 |
729 | # Disable failing tests for postgresql on musl that should have no impact
730 | # on the libpq that we need (collate.icu.utf8 and foreign regression tests)
731 | # This approach is copied from PostgREST, see https://github.com/PostgREST/postgrest/pull/2002/files#diff-72929db01d3c689277a1e7777b5df1dbbb20c5de41d1502ff8ac6b443a4e74c6R45
732 | postgresql = (previous.postgresql_14.overrideAttrs (old: { doCheck = false; })).override {
733 | # We need libpq, which does not need systemd,
734 | # and systemd doesn't currently build with musl.
735 | systemdSupport = false;
736 | # Kerberos is problematic on static:
737 | # configure: error: could not find function 'gss_init_sec_context' required for GSSAPI
738 | gssSupport = false;
739 | };
740 |
741 | procps = previous.procps.override {
742 | # systemd doesn't currently build with musl.
743 | withSystemd = false;
744 | };
745 |
746 | fontconfig = previous.fontconfig.overrideAttrs (old: {
747 | configureFlags = (old.configureFlags or []) ++ [
748 | "--enable-static"
749 | ];
750 | });
751 | fontforge = previous.fontforge.override ({
752 | # Currently produces linker errors like:
753 | # ld: ../../lib/libfontforge.so.4: undefined reference to `_kBrotliPrefixCodeRanges'
754 | # ld: ../../lib/libfontforge.so.4: undefined reference to `woff2::Write255UShort(std::vector
755 | # ld: ../../lib/libfontforge.so.4: undefined reference to `BrotliGetDictionary'
756 | # ld: ../../lib/libfontforge.so.4: undefined reference to `woff2::Store255UShort(int, unsigned long*, unsigned char*)'
757 | # ld: ../../lib/libfontforge.so.4: undefined reference to `BrotliDefaultAllocFunc'
758 | woff2 = null;
759 | });
760 |
761 | libjpeg = previous.libjpeg.override (old: { enableStatic = true; });
762 | libjpeg_turbo = previous.libjpeg_turbo.override (old: { enableStatic = true; });
763 |
764 | openblas = (previous.openblas.override { enableStatic = true; });
765 |
766 | libusb1 = previous.libusb1.override { withStatic = true; enableUdev = false; };
767 |
768 | openssl = previous.openssl.override { static = true; };
769 |
770 | zstd = previous.zstd.override { enableStatic = true; };
771 |
772 | # Disabling kerberos support for now, as openssh's `./configure` fails to
773 | # detect its functions due to linker error, so the build breaks, see #68.
774 | openssh = previous.openssh.override { withKerberos = false; };
775 |
776 | krb5 = previous.krb5.override {
777 | # Note [krb5 can only be static XOR shared]
778 | # krb5 does not support building both static and shared at the same time.
779 | # That means *anything* on top of this overlay trying to link krb5
780 | # dynamically from this overlay will fail with linker errors.
781 | staticOnly = true;
782 | };
783 |
784 | # For unclear reasons, brotli builds its `.a` files by default, but adds a `-static`
785 | # infix to their names:
786 | #
787 | # libbrotlicommon-static.a
788 | # libbrotlidec-static.a
789 | # libbrotlienc-static.a
790 | #
791 | # Its pkg-config `.pc` file thus does not support static linking. See:
792 | # https://github.com/google/brotli/issues/795#issuecomment-1373595520
793 | # and
794 | # https://github.com/google/brotli/pull/655#issuecomment-864395830
795 | #
796 | # In my opinion this is rather pointless, because `.a` files are always "static".
797 | #
798 | # We correct it here by renaming the files accordingly.
799 | brotli = previous.brotli.overrideAttrs (old: {
800 | postInstall = ''
801 | for f in "$lib"/lib/*-static.a; do
802 | ln -s --verbose "$f" "$(dirname "$f")/$(basename "$f" '-static.a').a"
803 | done
804 | '';
805 | });
806 |
807 | # woff2 currently builds against the `brotli` static libs only with a patch
808 | # that's enabled by its `static` argument.
809 | woff2 = previous.woff2.override { static = true; };
810 |
811 | libnfc = previous.libnfc.override { static = true; };
812 |
813 | # See comments on `statify_curl_including_exe` for the interaction with krb5!
814 | # As mentioned in [Packages that cause bootstrap compiler recompilation], we can't
815 | # override zlib to have static libs, so we have to pass in `zlib_both` explicitly
816 | # so that `curl` can use it.
817 | curl = statify_curl_including_exe previous.curl final.zlib_both;
818 |
819 | # curlMinimal also needs to be statified.
820 | curlMinimal = statify_curl_including_exe previous.curlMinimal final.zlib_both;
821 |
822 | # `fetchurl` uses our overridden `curl` above, but `fetchurl` overrides
823 | # `zlib` in `curl`, see
824 | # https://github.com/NixOS/nixpkgs/blob/4a5c0e029ddbe89aa4eb4da7949219fe4e3f8472/pkgs/top-level/all-packages.nix#L296-L299
825 | # so because of [Packages that cause bootstrap compiler recompilation],
826 | # it will undo our `zlib` override in `curl` done above (for `curl`
827 | # use via `fetchurl`).
828 | # So we need to explicitly put our zlib into that one's curl here.
829 | fetchurl = previous.fetchurl.override (old: {
830 | # Can't use `zlib_both` here (infinite recursion), so we
831 | # re-`statify_zlib` `final.zlib` here (interesting that
832 | # `previous.zlib` also leads to infinite recursion at time of writing).
833 | # We also disable kerberos (`gssSupport`) here again, because for
834 | # some unknown reason it sneaks back in.
835 | curl = old.curl.override { zlib = statify_zlib final.zlib; gssSupport = false; };
836 | });
837 |
838 | R = (previous.R.override {
839 | # R supports EITHER static or shared libs.
840 | static = true;
841 | # The Haskell package `H` depends on R, which pulls in OpenJDK,
842 | # which is not patched for musl support yet in nixpkgs.
843 | # Disable Java support for now.
844 | javaSupport = false;
845 | }).overrideAttrs (old: {
846 | # Testsuite newly seems to have at least one segfaulting test case.
847 | # Disable test suite for now; Alpine also does it:
848 | # https://git.alpinelinux.org/aports/tree/community/R/APKBUILD?id=e2bce14c748aacb867713cb81a91fad6e8e7f7f6#n56
849 | doCheck = false;
850 | });
851 |
852 | bash-completion = previous.bash-completion.overrideAttrs (old: {
853 | # Disable tests because it some of them seem dynamic linking specific:
854 | # FAILED test/t/test_getconf.py::TestGetconf::test_1 - assert
856 | doCheck = false;
857 | });
858 |
859 | # As of writing, emacs still doesn't build, erroring with:
860 | # Segmentation fault ./temacs --batch --no-build-details --load loadup bootstrap
861 | emacs = previous.emacs.override {
862 | # Requires librsvg (in Rust), which gives:
863 | # missing bootstrap url for platform x86_64-unknown-linux-musl
864 | withX = false;
865 | withGTK3 = false; # needs to be disabled because `withX` is disabled above
866 | systemd = null; # does not build with musl
867 | };
868 |
869 | # Disable sphinx for some python packages to not pull in its huge
870 | # dependency tree; it pulls in among others:
871 | # Ruby, Python, Perl, Rust, OpenGL, Xorg, gtk, LLVM.
872 | #
873 | # Which Python packages to override is informed by this dependency tree:
874 | # nix-store -q --tree $(NIX_PATH=nixpkgs=nixpkgs nix-instantiate survey/default.nix -A workingStackageExecutables)
875 | # and searching for `-sphinx`.
876 | python3 = previous.python3.override {
877 | # Careful, we're using a different self and super here!
878 | packageOverrides = finalPython: previousPython: {
879 |
880 | fonttools = previousPython.fonttools.override {
881 | sphinx = null;
882 | };
883 |
884 | matplotlib = previousPython.matplotlib.override {
885 | sphinx = null;
886 | };
887 |
888 | };
889 | };
890 |
891 | # I'm not sure why this is needed. As far as I can tell, libdevil doesn't
892 | # directly link to libdeflate. But libdevil does link to libtiff, which
893 | # uses libdeflate.
894 | #
895 | # However, if libdevil doesn't have libdeflate as a buildInput, building
896 | # libdevil fails with linking errors.
897 | #
898 | # I wasn't able to report this upstream, because in nixpkgs libdevil and
899 | # pkgsMusl.libdevil build correctly. Some transitive dependencies for
900 | # pkgsStatic.libdevil fail to build, so it is hard to say whether this is a
901 | # static-haskell-nix problem, or just a static-linking problem.
902 | libdevil = previous.libdevil.overrideAttrs (oldAttrs: {
903 | buildInputs = oldAttrs.buildInputs ++ [ final.libdeflate ];
904 | });
905 |
906 | };
907 |
908 | pkgsWithArchiveFiles = pkgsDontDisableStatic.extend archiveFilesOverlay;
909 |
910 |
911 | setupGhcOverlay = final: previous:
912 | let
913 | initialHaskellPackages =
914 | if integer-simple
915 | # Note we don't have to set the `-finteger-simple` flag for packages that GHC
916 | # depends on (e.g. text), because nix + GHC already do this for us:
917 | # https://github.com/ghc/ghc/blob/ghc-8.4.3-release/ghc.mk#L620-L626
918 | # https://github.com/peterhoeg/nixpkgs/commit/50050f3cc9e006daa6800f15a29e258c6e6fa4b3#diff-2f6f8fd152c14d37ebd849aa6382257aR35
919 | then final.haskell.packages.integer-simple."${compiler}"
920 | else final.haskell.packages."${compiler}";
921 | in
922 | {
923 | haskell = previous.haskell // {
924 | packages = previous.haskell.packages // {
925 | "${compiler}" = previous.haskell.packages."${compiler}".override {
926 | ghc = fixGhc previous.haskell.compiler."${compiler}";
927 | };
928 | };
929 | };
930 | haskellPackages = initialHaskellPackages;
931 | };
932 |
933 | pkgsWithGhc = pkgsWithArchiveFiles.extend setupGhcOverlay;
934 |
935 |
936 | # This overlay "fixes up" Haskell libraries so that static linking works.
937 | # See note "Don't add new packages here" below!
938 | haskellLibsReadyForStaticLinkingOverlay = final: previous: {
939 | # Helper function to add pkg-config static lib flags to a Haskell derivation.
940 | # We put it directly into the `pkgs` package set so that following overlays
941 | # can use it as well if they want to.
942 | #
943 | # Note that for linking the order of libraries given on the command line matters:
944 | # https://stackoverflow.com/questions/11893996/why-does-the-order-of-l-option-in-gcc-matter
945 | # Before my GHC change https://gitlab.haskell.org/ghc/ghc/merge_requests/1589
946 | # was merged that ensured the order is correct, we used a hack using
947 | # `--ld-option=-Wl,--start-group` to make the order not matter.
948 | staticHaskellHelpers.addStaticLinkerFlagsWithPkgconfig = haskellDrv: pkgConfigNixPackages: pkgconfigFlagsString:
949 | with final.haskell.lib; overrideCabal haskellDrv (old: {
950 | # We can't pass all linker flags in one go as `ld-options` because
951 | # the generic Haskell builder doesn't let us pass flags containing spaces.
952 | preConfigure = builtins.concatStringsSep "\n" [
953 | (old.preConfigure or "")
954 | # Note: Assigning the `pkg-config` output to a variable instead of
955 | # substituting it directly in the `for` loop so that `set -e` catches
956 | # when it fails.
957 | # See https://unix.stackexchange.com/questions/23026/how-can-i-get-bash-to-exit-on-backtick-failure-in-a-similar-way-to-pipefail/23099#23099
958 | # This was a bug for long where we didn't notice; shell is unsafe garbage.
959 | ''
960 | set -e
961 |
962 | PKGCONFIG_OUTPUT=$(pkg-config --static ${pkgconfigFlagsString})
963 |
964 | configureFlags+=$(for flag in $PKGCONFIG_OUTPUT; do echo -n " --ld-option=$flag"; done)
965 | ''
966 | ];
967 | # TODO Somehow change nixpkgs (the generic haskell builder?) so that
968 | # putting `curl_static` into `libraryPkgconfigDepends` is enough
969 | # and the manual modification of `configureFlags` is not necessary.
970 | libraryPkgconfigDepends = (old.libraryPkgconfigDepends or []) ++ pkgConfigNixPackages;
971 | # `generic-builder.nix` already adds `pkg-config` as a `nativeBuildInput`
972 | # e.g. if `libraryPkgconfigDepends` is not empty, but if it was, and we
973 | # override it here, it does not notice, so we add `pkg-config` explicitly
974 | # in that case.
975 | buildTools = (old.buildTools or []) ++ [ pkgs.pkg-config ];
976 | });
977 |
978 |
979 | haskellPackages = previous.haskellPackages.override (old: {
980 | overrides = final.lib.composeExtensions (old.overrides or (_: _: {})) (self: super:
981 | with final.haskell.lib;
982 | with final.staticHaskellHelpers;
983 | let
984 | callCabal2nix =
985 | final.haskellPackages.callCabal2nix;
986 |
987 | add_integer-simple_if_needed = haskellPkgs: haskellPkgs // (
988 | # If the `integer-simple` flag is given, and there isn't already
989 | # an `integer-simple` in the Haskell package set, add one as `null`.
990 | # This works around the problem that `stack2nix`-generated Haskell
991 | # package sets lack the `integer-simple` entries, even when everything
992 | # is compiled with integer-simple, which leads to
993 | # Setup: Encountered missing dependencies:
994 | # integer-simple
995 | # This PR fixes it in stack2nix:
996 | # https://github.com/input-output-hk/stack2nix/pull/167
997 | # We still maintain the addition here so that users can use upstream
998 | # `stack2nix` without problems.
999 | if integer-simple && !(builtins.hasAttr "integer-simple" haskellPkgs) then {
1000 | integer-simple = null;
1001 | } else {});
1002 |
1003 | in add_integer-simple_if_needed {
1004 |
1005 | # This overrides settings for all Haskell packages.
1006 | mkDerivation = attrs: super.mkDerivation (attrs // {
1007 |
1008 | # Disable haddocks to save time and because for some reason, haddock (e.g. for aeson)
1009 | # fails with
1010 | # : can't load .so/.DLL for: libgmp.so (libgmp.so: cannot open shared object file: No such file or directory)
1011 | # when we use `pkgsStatic`. Need to investigate.
1012 | doHaddock = false;
1013 |
1014 | # Disable profiling to save build time.
1015 | enableLibraryProfiling = false;
1016 | enableExecutableProfiling = false;
1017 |
1018 | # Skip tests on -O0 because some tests are extremely slow on -O0.
1019 | # This prevents us from finding upstream correctness issues that
1020 | # appear only with -O0,
1021 | # such as https://github.com/bos/double-conversion/issues/26
1022 | # but that's OK for now as we want -O0 mainly for faster feedback.
1023 | # doCheck = !disableOptimization;
1024 |
1025 | # If `disableOptimization` is on for fast iteration, pass `-O0` to GHC.
1026 | # We use `buildFlags` instead of `configureFlags` so that it's
1027 | # also in effect for packages which specify e.g.
1028 | # `ghc-options: -O2` in their .cabal file.
1029 | buildFlags = (attrs.buildFlags or []) ++ builtins.concatLists [
1030 | (final.lib.optional disableOptimization "--ghc-option=-O0")
1031 | # GHC compilation does not scale well on high-core machines like our CI.
1032 | # Making compilation more efficient.
1033 | # (map (o: "--ghc-option=" + o) [
1034 | # "-j4" # Limit parallel compilation
1035 | # "+RTS"
1036 | # "-maxN4" # Limit threads
1037 | # "-A64M" "-qb0" # See https://trofi.github.io/posts/193-scaling-ghc-make.html
1038 | # "-RTS"
1039 | # ])
1040 | ];
1041 |
1042 | # Note [Slow stripping]:
1043 | # There is currently a 300x `strip` performance regression in
1044 | # `binutils`, making some strips take 5 minutes instead of 1 second.
1045 | # Disable stripping of libraries (`.a` files) until it's solved:
1046 | # https://github.com/NixOS/nixpkgs/issues/129467
1047 | # https://sourceware.org/bugzilla/show_bug.cgi?id=28058
1048 | # We continue to strip executables because they don't seem to
1049 | # be affected by the regression.
1050 | #
1051 | # There is also the consideration to keep `dontStrip = true;` the default,
1052 | # so that people can decide at the very end whether they prefer small
1053 | # executable sizes, or increased debuggability by keeping debug symbols.
1054 | # However, until the `-g` issue
1055 | # https://gitlab.haskell.org/ghc/ghc/-/issues/15960
1056 | # is figured out, it may be best to not enable `-g`, and thus
1057 | # not-stripping isn't as useful.
1058 | configureFlags = (attrs.configureFlags or []) ++ [ "--disable-library-stripping" ];
1059 | });
1060 |
1061 | # Note:
1062 | #
1063 | # Don't add new packages here.
1064 | #
1065 | # Only override existing ones in the minimal way possible.
1066 | # This is for the use case that somebody passes us a Haskell package
1067 | # set (e.g. generated with `stack2nix`) and just wants us to fix
1068 | # up all their packages so that static linking works.
1069 | # If we unconditionally add packages here, we will override
1070 | # whatever packages they've passed us in.
1071 |
1072 | # Override zlib Haskell package to use the system zlib package
1073 | # that has `.a` files added.
1074 | # This is because the system zlib package can't be overridden accordingly,
1075 | # see note [Packages that cause bootstrap compiler recompilation].
1076 | zlib = super.zlib.override { zlib = final.zlib_both; };
1077 |
1078 | # The `properties` test suite takes > 30 minutes with `-O0`.
1079 | aeson-diff =
1080 | (if disableOptimization then dontCheck else lib.id)
1081 | super.aeson-diff;
1082 |
1083 | # Tests use `inspection-testing` which cannot work on `-O0`.
1084 | ap-normalize =
1085 | (if disableOptimization then dontCheck else lib.id)
1086 | super.ap-normalize;
1087 |
1088 | # Fails the tests
1089 | # issue379.Lazy.unionWith
1090 | # issue379.union
1091 | # TODO: File an upstream bug for that, after reproducing it outside of nix.
1092 | unordered-containers =
1093 | (if disableOptimization then dontCheck else lib.id)
1094 | super.unordered-containers;
1095 |
1096 | # Fails the tests
1097 | # FromJSONKey
1098 | # -: OK
1099 | # -: OK
1100 | # -: OK
1101 | # -: OK
1102 | # -: FAIL
1103 | # tests/UnitTests.hs:309:
1104 | # Const Text
1105 | # Use -p '$0=="tests.unit.FromJSONKey.-"' to rerun this test only.
1106 | #
1107 | # TODO: File an upstream bug for that, after reproducing it outside of nix.
1108 | aeson =
1109 | (if disableOptimization then dontCheck else lib.id)
1110 | super.aeson;
1111 |
1112 | # Has an inspection test which fails on -O0, which makse sense.
1113 | postgresql-simple =
1114 | (if disableOptimization then dontCheck else lib.id)
1115 | super.postgresql-simple;
1116 |
1117 | arbtt =
1118 | addStaticLinkerFlagsWithPkgconfig
1119 | super.arbtt
1120 | (with final; [
1121 | nettle
1122 |
1123 | xorg.libX11
1124 | xorg.libXdmcp
1125 | xorg.libXau
1126 | xorg.libxcb
1127 | ])
1128 | "--libs nettle x11-xcb";
1129 |
1130 | # `criterion`'s test suite fails with a timeout if its dependent
1131 | # libraries (apparently `bytestring`) are compiled with `-O0`.
1132 | # Even increasing the timeout 5x did not help!
1133 | criterion =
1134 | (if disableOptimization then dontCheck else lib.id)
1135 | super.criterion;
1136 |
1137 | # `double-conversion`'s test suite fails when `-O0` is used
1138 | # because `realToFrac NaN /= NaN` on `-O0` (Haskell does not
1139 | # provide a reasonable way to convert `Double -> CDouble`,
1140 | # totally bonkers).
1141 | # See https://github.com/bos/double-conversion/issues/26
1142 | double-conversion =
1143 | (if disableOptimization then dontCheck else lib.id)
1144 | super.double-conversion;
1145 |
1146 | blaze-textual =
1147 | let
1148 | # `blaze-textual`'s implementation is wrong when `-O0` is used,
1149 | # see https://github.com/bos/blaze-textual/issues/11.
1150 | # If we did `disableOptimization`, re-enable it for this package.
1151 | # TODO Remove this when https://github.com/bos/blaze-textual/pull/12 is merged and in nixpkgs.
1152 | handleDisableOptimisation = drv:
1153 | if disableOptimization
1154 | then appendBuildFlag drv "--ghc-option=-O"
1155 | else drv;
1156 | # `blaze-textual` has a flag that needs to be given explicitly
1157 | # if `integer-simple` is to be used.
1158 | # TODO Put this into the `integer-simple` compiler set in nixpkgs? In:
1159 | # https://github.com/NixOS/nixpkgs/blob/ef89b398/pkgs/top-level/haskell-packages.nix#L184
1160 | handleIntegerSimple = drv:
1161 | if integer-simple
1162 | then enableCabalFlag drv "integer-simple"
1163 | else drv;
1164 | in handleIntegerSimple (handleDisableOptimisation super.blaze-textual);
1165 |
1166 | # `weigh`'s test suite fails when `-O0` is used
1167 | # because that package inherently relies on optimisation to be on.
1168 | weigh =
1169 | (if disableOptimization then dontCheck else lib.id)
1170 | super.weigh;
1171 |
1172 | # Tests use `inspection-testing` which cannot work on `-O0`.
1173 | generic-data =
1174 | (if disableOptimization then dontCheck else lib.id)
1175 | super.generic-data;
1176 |
1177 | # Tests use `inspection-testing` which cannot work on `-O0`.
1178 | # This seems to happen only in nixpkgs, I could not reproduce it with `stack test --fast`.
1179 | #
1180 | # 1) cast correctly fails to extract aChar from A
1181 | # Make sure the expression has an NFData instance! See docs at https://github.com/CRogers/should-not-typecheck#nfdata-a-constraint. Full error:
1182 | # tests/Examples.hs:188:7: error: [GHC-39999]
1183 | # • Ambiguous type variable ‘a0’ arising from a use of ‘shouldNotTypecheck’
1184 | # prevents the constraint ‘(NFData a0)’ from being solved.
1185 | # Probable fix: use a type annotation to specify what ‘a0’ should be.
1186 | records-sop =
1187 | (if disableOptimization then dontCheck else lib.id)
1188 | super.records-sop;
1189 |
1190 | # `HsOpenSSL` has a bug where assertions are only triggered on `-O0`.
1191 | # This breaks its test suite.
1192 | # https://github.com/vshabanov/HsOpenSSL/issues/44
1193 | HsOpenSSL =
1194 | (if disableOptimization then dontCheck else lib.id)
1195 | super.HsOpenSSL;
1196 |
1197 | # Note [Fixed Cabal for Setup.hs->somePackage->Cabal dependencies]
1198 | # We have to add our fixed Cabal to the package set because otherwise
1199 | # packages that depend on Cabal (e.g. `cabal-doctest`) will depend
1200 | # on the unfixed Cabal, and when some other Setup.hs depends
1201 | # on such a package, GHC will choose the unfixed Cabal to use.
1202 | # `pkgsStatic` does not need this because with it, because when
1203 | # cross-compiling, the Setup.hs is compiled with a completely different
1204 | # package set.
1205 | # Example packages:
1206 | # Some getting: unrecognized 'configure' option `--enable-executable-static'
1207 | # influxdb
1208 | # wreq
1209 | # servant-server
1210 | # Some getting: *** abort because of serious configure-time warning from Cabal (multiple different package versions in project)
1211 | # stack2nix
1212 | Cabal = if !areCabalPatchesRequired then super.Cabal else # no patches needed -> don't even try to access any attributes
1213 | if approach == "pkgsMusl"
1214 | then ( # Example package where this matters: `focuslist`
1215 | # See note [When Cabal is `null` in a package set].
1216 | # Also note we can't just use `buildPlatformHaskellPackagesWithFixedCabal.Cabal`
1217 | # here because that one may have different dependencies
1218 | # (e.g. `text` may have been overridden here but not there),
1219 | # which would lead to the
1220 | # This package indirectly depends on multiple versions of the same package
1221 | # warning.
1222 | if builtins.isNull super.Cabal
1223 | # Note this addition is an exception to the "Don't add new packages here"
1224 | # rule from above, and we only do it if Cabal is not yet
1225 | # in the package set.
1226 | then applyPatchesToCabalDrv super."${defaultCabalPackageVersionComingWithGhc}"
1227 | else applyPatchesToCabalDrv super.Cabal
1228 | )
1229 | else super.Cabal; # `pkgsStatic` does not need that
1230 |
1231 | # Helpers for other packages
1232 |
1233 | hpc-coveralls = appendPatch super.hpc-coveralls (builtins.fetchurl "https://github.com/guillaume-nargeot/hpc-coveralls/pull/73/commits/344217f513b7adfb9037f73026f5d928be98d07f.patch");
1234 |
1235 | conduit-extra =
1236 | # TODO Remove this once we no longer care about conduit-extra < 1.3.1.1.
1237 | # Test-suite failing nondeterministically, see https://github.com/snoyberg/conduit/issues/385
1238 | # I've already checked that it's fixed on 1.3.1.1; we just keep this
1239 | # for a while longer for `stack2nix` users.
1240 | (if final.lib.versionOlder super.conduit-extra.version "1.3.1.1" then dontCheck else lib.id)
1241 | super.conduit-extra;
1242 |
1243 | # See https://github.com/hslua/hslua/issues/67
1244 | # It's not clear if it's safe to disable this as key functionality may be broken
1245 | hslua = dontCheck super.hslua;
1246 |
1247 | # Test suite takes > 1h CPU time with 1600% CPU on my CI machine.
1248 | hw-balancedparens = dontCheck super.hw-balancedparens;
1249 |
1250 | # Test suite tries to connect to dbus, can't work in sandbox.
1251 | credential-store = dontCheck super.credential-store;
1252 |
1253 | # Test suite calls all kinds of shell utilities, can't work in sandbox.
1254 | dotenv = dontCheck super.dotenv;
1255 |
1256 | # Test suite fails time-dependently:
1257 | # https://github.com/peti/cabal2spec/commit/6078778c06be45eb468f4770a3924c7be190f558
1258 | # TODO: Remove once a release > 2.4.1 is available to us.
1259 | cabal2spec = dontCheck super.cabal2spec;
1260 |
1261 | # Single test suite failure:
1262 | # set;get socket option (Pub): FAIL
1263 | # *** Failed! Exception: 'ZMQError { errno = 22, source = "setByteStringOpt", message = "Invalid argument" }' (after 1 test):
1264 | # ZapDomain (Restricted "")
1265 | # Use --quickcheck-replay=307313 to reproduce.
1266 | zeromq4-haskell = dontCheck super.zeromq4-haskell;
1267 |
1268 | # Fails in doctests with:
1269 | # doctests: /nix/store/v5lw9170rw5s9vm69qsmd5ybns7yv2dj-ghc-8.6.4/lib/ghc-8.6.4/ghc-prim-0.5.3/HSghc-prim-0.5.3.o: unknown symbol `exp'
1270 | # doctests: doctests: unable to load package `ghc-prim-0.5.3'
1271 | lens-regex = dontCheck super.lens-regex;
1272 |
1273 | # Fails in doctests with:
1274 | # focuslist-doctests: /nix/store/v5lw9170rw5s9vm69qsmd5ybns7yv2dj-ghc-8.6.4/lib/ghc-8.6.4/ghc-prim-0.5.3/HSghc-prim-0.5.3.o: unknown symbol `exp'
1275 | # focuslist-doctests: focuslist-doctests: unable to load package `ghc-prim-0.5.3'
1276 | focuslist = dontCheck super.focuslist;
1277 |
1278 | # Fails in doctests with:
1279 | # doctests: /nix/store/nda51m9gymbx9qvzmjpfd4393jqq0gdm-ghc-8.6.5/lib/ghc-8.6.5/ghc-prim-0.5.3/HSghc-prim-0.5.3.o: unknown symbol `exp'
1280 | # doctests: doctests: unable to load package `ghc-prim-0.5.3'
1281 | yesod-paginator = dontCheck super.yesod-paginator;
1282 |
1283 | # Workaround for `zip`'s dependency `bzlib-conduit` using `extra-libraries: bz`
1284 | # instead of `pkgconfig-depends`.
1285 | # TODO: Make a PR to fix that.
1286 | zip =
1287 | addStaticLinkerFlagsWithPkgconfig
1288 | (super.zip.overrideAttrs (old: { configureFlags = (old.configureFlags or []) ++ ["--ghc-options=-v"]; }))
1289 | [ final.bzip2_static ]
1290 | "--libs bzip2";
1291 |
1292 | # Override libs explicitly that can't be overridden with overlays.
1293 | # See note [Packages that cause bootstrap compiler recompilation].
1294 | regex-pcre = super.regex-pcre.override { pcre = final.pcre_static; };
1295 | pcre-light = super.pcre-light.override { pcre = final.pcre_static; };
1296 | bzlib-conduit = super.bzlib-conduit.override { bzip2 = final.bzip2_static; };
1297 |
1298 | # Tests fail with: doctests: : Dynamic loading not supported
1299 | BNFC = dontCheck super.BNFC;
1300 |
1301 | # 200 ms test timeout is not suitable for massively parallel CI.
1302 | # See https://github.com/jensblanck/cdar/issues/7
1303 | cdar-mBound = dontCheck super.cdar-mBound;
1304 |
1305 | darcs =
1306 | addStaticLinkerFlagsWithPkgconfig
1307 | # (super.darcs.override { curl = curl_static; })
1308 | super.darcs
1309 | [ final.curl ]
1310 | # Ideally we'd like to use
1311 | # pkg-config --static --libs libcurl
1312 | # but that doesn't work because that output contains `-Wl,...` flags
1313 | # which aren't accepted by `ld` and thus cannot be passed as `ld-option`s.
1314 | # See https://github.com/curl/curl/issues/2775 for an investigation of why.
1315 | "--libs-only-L --libs-only-l libcurl";
1316 |
1317 | # For https://github.com/BurntSushi/erd/issues/40
1318 | # As of writing, not in Stackage.
1319 | # Currently fails with linker error, see `yesod-paginator` below.
1320 | erd = doJailbreak super.erd;
1321 |
1322 | # Test timeout is too tight on `-O0`.
1323 | Glob =
1324 | (if disableOptimization then dontCheck else lib.id)
1325 | super.Glob;
1326 |
1327 | # Tests fail with: doctests: : Dynamic loading not supported
1328 | headroom = dontCheck super.headroom;
1329 |
1330 | # We need to explicitly get blas from openblasCompat, since
1331 | # otherwise openblas is used and Haskell programs like `resistor-cube`
1332 | # won't be able to find libblas.
1333 | blas-ffi = super.blas-ffi.override {
1334 | blas = final.openblasCompat;
1335 | };
1336 |
1337 | hmatrix =
1338 | # musl does not have `random_r()`.
1339 | (enableCabalFlag super.hmatrix "no-random_r")
1340 | .override { openblasCompat = final.openblasCompat; };
1341 |
1342 | # Tests fail with: doctests: : Dynamic loading not supported
1343 | hw-xml = dontCheck super.hw-xml;
1344 | hw-packed-vector = dontCheck super.hw-packed-vector;
1345 |
1346 | # Test suite segfaults (perhaps because R's test suite also does?).
1347 | inline-r = dontCheck super.inline-r;
1348 |
1349 | # Tests fail with: doctests: : Dynamic loading not supported
1350 | openapi3 = dontCheck super.openapi3;
1351 |
1352 | mysql-json-table =
1353 | addStaticLinkerFlagsWithPkgconfig
1354 | super.mysql-json-table
1355 | [ final.openssl final.zlib_both ]
1356 | "--libs openssl zlib";
1357 |
1358 | # TODO For the below packages, it would be better if we could somehow make all users
1359 | # of postgresql-libpq link in openssl via pkgconfig.
1360 | hasql-notifications =
1361 | addStaticLinkerFlagsWithPkgconfig
1362 | super.hasql-notifications
1363 | [ final.openssl final.postgresql ]
1364 | "--libs libpq";
1365 | hasql-queue =
1366 | addStaticLinkerFlagsWithPkgconfig
1367 | super.hasql-queue
1368 | [ final.openssl final.postgresql ]
1369 | "--libs libpq";
1370 | pg-harness-server =
1371 | addStaticLinkerFlagsWithPkgconfig
1372 | super.pg-harness-server
1373 | [ final.openssl final.postgresql ]
1374 | "--libs libpq";
1375 | postgrest =
1376 | addStaticLinkerFlagsWithPkgconfig
1377 | super.postgrest
1378 | [ final.openssl final.postgresql ]
1379 | "--libs libpq";
1380 | postgresql-orm =
1381 | addStaticLinkerFlagsWithPkgconfig
1382 | super.postgresql-orm
1383 | [ final.openssl final.postgresql ]
1384 | "--libs libpq";
1385 | postgresql-schema =
1386 | addStaticLinkerFlagsWithPkgconfig
1387 | super.postgresql-schema
1388 | [ final.openssl final.postgresql ]
1389 | "--libs openssl libpq";
1390 | postgresql-simple-migration =
1391 | addStaticLinkerFlagsWithPkgconfig
1392 | super.postgresql-simple-migration
1393 | [ final.openssl ]
1394 | "--libs openssl";
1395 | squeal-postgresql =
1396 | addStaticLinkerFlagsWithPkgconfig
1397 | super.squeal-postgresql
1398 | [ final.openssl final.postgresql ]
1399 | "--libs openssl libpq";
1400 | tmp-postgres =
1401 | addStaticLinkerFlagsWithPkgconfig
1402 | (dontCheck super.tmp-postgres) # flaky/stuck tests: https://github.com/jfischoff/tmp-postgres/issues/273
1403 | [ final.openssl ]
1404 | "--libs openssl";
1405 |
1406 | # This one needs `libcrypto` explicitly for reasons not yet investigated. `libpq` should pull it in via `openssl`.
1407 | postgresql-migration =
1408 | addStaticLinkerFlagsWithPkgconfig
1409 | super.postgresql-migration
1410 | [ final.openssl final.postgresql ]
1411 | "--libs libpq libcrypto";
1412 |
1413 | xml-to-json =
1414 | addStaticLinkerFlagsWithPkgconfig
1415 | super.xml-to-json
1416 | [ final.curl final.expat ]
1417 | # Ideally we'd like to use
1418 | # pkg-config --static --libs libcurl
1419 | # but that doesn't work because that output contains `-Wl,...` flags
1420 | # which aren't accepted by `ld` and thus cannot be passed as `ld-option`s.
1421 | # See https://github.com/curl/curl/issues/2775 for an investigation of why.
1422 | "--libs-only-L --libs-only-l libcurl expat";
1423 |
1424 | nfc =
1425 | addStaticLinkerFlagsWithPkgconfig
1426 | super.nfc
1427 | [ final.libusb-compat-0_1 final.libusb1 ]
1428 | "--libs libusb";
1429 |
1430 | # This package's dependency `rounded` currently fails its test with a patterm match error.
1431 | aern2-real =
1432 | addStaticLinkerFlagsWithPkgconfig
1433 | super.aern2-real
1434 | [ final.mpfr final.gmp ]
1435 | "--libs mpfr gmp";
1436 |
1437 | hopenpgp-tools =
1438 | addStaticLinkerFlagsWithPkgconfig
1439 | super.hopenpgp-tools
1440 | [ final.nettle final.bzip2_static ]
1441 | "--libs nettle bzip2";
1442 |
1443 | sdl2-gfx =
1444 | addStaticLinkerFlagsWithPkgconfig
1445 | super.sdl2-gfx
1446 | (with final; [
1447 | nettle
1448 | SDL2
1449 | SDL2_gfx
1450 |
1451 | xorg.libX11
1452 | libXext
1453 | libXcursor
1454 | xorg.libXdmcp
1455 | libXinerama
1456 | libXi
1457 | libXrandr
1458 | libXxf86vm
1459 | libXScrnSaver
1460 | xorg.libXrender
1461 | libXfixes
1462 | xorg.libXau
1463 | xorg.libxcb
1464 | xorg.libpthreadstubs
1465 | ])
1466 | "--libs nettle sdl2 SDL2_gfx xcursor";
1467 |
1468 | sdl2-image =
1469 | addStaticLinkerFlagsWithPkgconfig
1470 | super.sdl2-image
1471 | (with final; [
1472 | nettle
1473 | SDL2
1474 | SDL2_image
1475 |
1476 | xorg.libX11
1477 | libXext
1478 | libXcursor
1479 | xorg.libXdmcp
1480 | libXinerama
1481 | libXi
1482 | libXrandr
1483 | libXxf86vm
1484 | libXScrnSaver
1485 | xorg.libXrender
1486 | libXfixes
1487 | xorg.libXau
1488 | xorg.libxcb
1489 | xorg.libpthreadstubs
1490 |
1491 | libjpeg
1492 | libpng
1493 | libtiff
1494 | zlib_both
1495 | lzma
1496 | libwebp
1497 | ])
1498 | "--libs nettle sdl2 SDL2_image xcursor libpng libjpeg libtiff-4 libwebp";
1499 |
1500 | # Test hangs for 10 hours on CI machine.
1501 | midi = dontCheck super.midi;
1502 |
1503 | # With optimisations disabled, some tests of its test suite don't
1504 | # finish within the 25 seconds timeout.
1505 | skylighting-core =
1506 | (if disableOptimization then dontCheck else lib.id)
1507 | super.skylighting-core;
1508 |
1509 | # Test suite loops forever without optimisations..
1510 | text-short =
1511 | (if disableOptimization then dontCheck else lib.id)
1512 | super.text-short;
1513 |
1514 | # Flaky QuickCheck test failure:
1515 | # *** Failed! "00:01": expected Just 00:00:60, found Just 00:01:00 (after 95 tests and 2 shrinks):
1516 | # See https://github.com/haskellari/time-compat/issues/23
1517 | time-compat = dontCheck super.time-compat;
1518 |
1519 | # Test suite takes > 1h CPU time with 1600% CPU on my CI machine.
1520 | # Does pass after that time though, maybe high thread counds work badly here.
1521 | tomland = dontCheck super.tomland;
1522 |
1523 | # Added for #14
1524 | tttool = callCabal2nix "tttool" (final.fetchFromGitHub {
1525 | owner = "entropia";
1526 | repo = "tip-toi-reveng";
1527 | rev = "f83977f1bc117f8738055b978e3cfe566b433483";
1528 | sha256 = "05bbn63sn18s6c7gpcmzbv4hyfhn1i9bd2bw76bv6abr58lnrwk3";
1529 | }) {};
1530 |
1531 | # TODO Find out why these overrides are necessary, given that they all come from `final`
1532 | # (somehow without them, xmonad gives linker errors).
1533 | # Most likely it is because the `libX*` packages are available once on the top-level
1534 | # namespace (where we override them), and once under `xorg.libX*`, where we don't
1535 | # override them; it seems that `X11` depends on the latter.
1536 | X11 = super.X11.override {
1537 | libX11 = final.xorg.libX11;
1538 | libXext = final.xorg.libXext;
1539 | libXinerama = final.xorg.libXinerama;
1540 | libXrandr = final.xorg.libXrandr;
1541 | libXrender = final.xorg.libXrender;
1542 | libXScrnSaver = final.xorg.libXScrnSaver;
1543 | };
1544 |
1545 | # Note that xmonad links, but it doesn't run, because it tries to open
1546 | # `libgmp.so.3` at run time.
1547 | xmonad =
1548 | let
1549 | # Work around xmonad in `haskell-packages.nix` having hardcoded `$doc`
1550 | # which is the empty string when haddock is disabled.
1551 | # Same as https://github.com/NixOS/nixpkgs/pull/61526 but for
1552 | # https://github.com/NixOS/cabal2nix/blob/fe32a4cdb909cc0a25d37ec371453b1bb0d4f134/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs#L294-L295
1553 | # TODO: Remove when https://github.com/NixOS/cabal2nix/pull/416 is merged and available in nixpkgs.
1554 | fixPostInstallWithHaddockDisabled = pkg: overrideCabal pkg (old: { postInstall = ""; });
1555 | in
1556 | appendConfigureFlag (addStaticLinkerFlagsWithPkgconfig
1557 | (fixPostInstallWithHaddockDisabled super.xmonad)
1558 | (with final; [ xorg.libpthreadstubs xorg.libxcb xorg.libXau xorg.libXrender xorg.libXdmcp ])
1559 | "--libs xcb xau xrender xdmcp") [
1560 | ];
1561 |
1562 | leveldb-haskell =
1563 | appendConfigureFlag super.leveldb-haskell [
1564 | # Similar to https://github.com/nh2/static-haskell-nix/issues/10
1565 | "--ld-option=-Wl,--start-group --ld-option=-Wl,-lstdc++"
1566 | ];
1567 |
1568 | zeromq4-patterns =
1569 | dontCheck # test suite hangs forever
1570 | (appendConfigureFlag super.zeromq4-patterns [
1571 | # Similar to https://github.com/nh2/static-haskell-nix/issues/10
1572 | "--ld-option=-Wl,--start-group --ld-option=-Wl,-lstdc++"
1573 | ]);
1574 |
1575 | cryptonite =
1576 | if integer-simple
1577 | then disableCabalFlag super.cryptonite "integer-gmp"
1578 | else super.cryptonite;
1579 |
1580 | # The test-suite of this package loops forever on 100% CPU (at least on `-O0`).
1581 | bench-show = dontCheck super.bench-show;
1582 | # The test-suite of this package loops forever on 100% CPU (at least on `-O0`).
1583 | # TODO Investigate that because `loop` is nh2's own package.
1584 | loop = dontCheck super.loop;
1585 | # The test-suite of this package loops forever on 100% CPU (at least on `-O0`).
1586 | matrix = dontCheck super.matrix;
1587 | # The test-suite of this package loops forever on 100% CPU (at least on `-O0`).
1588 | # TODO Ask Bas about it
1589 | scientific =
1590 | if integer-simple
1591 | then dontCheck super.scientific
1592 | else super.scientific;
1593 | # The test-suite of this package loops forever on 100% CPU (at least on `-O0`).
1594 | x509-validation =
1595 | if integer-simple
1596 | then dontCheck super.x509-validation
1597 | else super.x509-validation;
1598 |
1599 | # Tests depend on util-linux which depends on systemd
1600 | hakyll =
1601 | dontCheck (overrideCabal super.hakyll (drv: {
1602 | testToolDepends = [];
1603 | }));
1604 |
1605 | # Inspection tests fail on `disableOptimization`with
1606 | # examples/Fusion.hs:25:1: sumUpSort `hasNoType` GHC.Types.[] failed expectedly.
1607 | inspection-testing =
1608 | (if disableOptimization then dontCheck else lib.id)
1609 | super.inspection-testing;
1610 |
1611 | # Inspection tests fail on `disableOptimization`with
1612 | # examples/Fusion.hs:25:1: sumUpSort `hasNoType` GHC.Types.[] failed expectedly
1613 | algebraic-graphs =
1614 | (if disableOptimization then dontCheck else lib.id)
1615 | super.algebraic-graphs;
1616 |
1617 | # Test suite tries to connect to the Internet
1618 | aur = dontCheck super.aur;
1619 |
1620 | # Test suite tries to run `minisat` which is not on PATH
1621 | ersatz = dontCheck super.ersatz;
1622 |
1623 | # Seems to time out on `-O0` (but does not print that timeout
1624 | # is the failure reason).
1625 | numeric-prelude =
1626 | (if disableOptimization then dontCheck else lib.id)
1627 | super.numeric-prelude;
1628 |
1629 | # Assertion failure with `-O0` because then assertions are actually checked:
1630 | # https://github.com/haskell/ghc-events/issues/106
1631 | ghc-events =
1632 | (if disableOptimization then dontCheck else lib.id)
1633 | super.ghc-events;
1634 |
1635 | # Test suite uses `timeout` to check performance, bad idea.
1636 | # https://github.com/frasertweedale/hs-jose/blob/c2f6690df5672dc1e089d1fa9ab7a4298f06c55d/test/Perf.hs#L38C16-L38C19
1637 | jose =
1638 | (if disableOptimization then dontCheck else lib.id)
1639 | super.jose;
1640 |
1641 | # doctests test suite fails with:
1642 | # /build/trifecta-2.1/src/Text/Trifecta/Util/It.hs:61: failure in expression `let keepIt a = Pure a'
1643 | # expected:
1644 | # but got: /nix/store/xz6sgnl68v00yhfk25cfankpdf7g57cs-binutils-2.31.1/bin/ld: warning: type and size of dynamic symbol `TextziTrifectaziDelta_zdfHasDeltaByteString_closure' are not defined
1645 | trifecta = dontCheck super.trifecta;
1646 |
1647 | # Test suite needs a missing dependency:
1648 | # Configuring range-set-list-0.1.3.1...
1649 | # ...
1650 | # Setup: Encountered missing or private dependencies:
1651 | # tasty >=0.8 && <1.4
1652 | range-set-list =
1653 | dontCheck (overrideCabal super.range-set-list { broken = false; });
1654 |
1655 | # Test suite fails:
1656 | #
1657 | # doctests: FAIL
1658 | # Exception: : Dynamic loading not supported
1659 | # Parse a content-less file: FAIL
1660 | # Exception: test-files/trivial.proto: openFile: does not exist (No such file or directory)
1661 | # 2 out of 71 tests failed (1.97s)
1662 | proto3-suite = dontCheck super.proto3-suite;
1663 |
1664 | # Fix syntax error in test.
1665 | # Remove when nixpkgs has data-diverse >= 4.7.1.0, see:
1666 | # https://github.com/louispan/data-diverse/commit/50d79a011d2a9c55ca4b21a424f177d6bbd2663c
1667 | data-diverse = markUnbroken (dontCheck super.data-diverse);
1668 | });
1669 |
1670 | });
1671 | };
1672 |
1673 |
1674 | pkgsWithHaskellLibsReadyForStaticLinking = pkgsWithGhc.extend haskellLibsReadyForStaticLinkingOverlay;
1675 |
1676 | # Overlay all Haskell executables are statically linked.
1677 | staticHaskellBinariesOverlay = final: previous: {
1678 | haskellPackages = previous.haskellPackages.override (old: {
1679 | overrides = final.lib.composeExtensions (old.overrides or (_: _: {})) (self: super:
1680 | let
1681 | # We have to use `useFixedCabal` here, and cannot just rely on the
1682 | # "Cabal = ..." we override up in `haskellPackagesWithLibsReadyForStaticLinking`,
1683 | # because that `Cabal` isn't used in all packages:
1684 | # If a package doesn't explicitly depend on the `Cabal` package, then
1685 | # for compiling its `Setup.hs` the Cabal package that comes with GHC
1686 | # (that is in the default GHC package DB) is used instead, which
1687 | # obviously doesn' thave our patches.
1688 | statify = drv:
1689 | with final.haskell.lib;
1690 | final.lib.foldl
1691 | appendConfigureFlag
1692 | (disableLibraryProfiling (disableSharedExecutables (useFixedCabal drv)))
1693 | (builtins.concatLists [
1694 | [
1695 | "--enable-executable-static" # requires `useFixedCabal`
1696 | # `enableShared` seems to be required to avoid `recompile with -fPIC` errors on some packages.
1697 | "--extra-lib-dirs=${final.ncurses.override { enableStatic = true; }}/lib"
1698 | ]
1699 | # TODO Figure out why this and the below libffi are necessary.
1700 | # `working` and `workingStackageExecutables` don't seem to need that,
1701 | # but `static-stack2nix-builder-example` does.
1702 | (final.lib.optionals (!integer-simple) [
1703 | "--extra-lib-dirs=${final.gmp6.override { withStatic = true; }}/lib"
1704 | ])
1705 | (final.lib.optionals (!integer-simple && approach == "pkgsMusl") [
1706 | # GHC needs this if it itself wasn't already built against static libffi
1707 | # (which is the case in `pkgsStatic` only):
1708 | "--extra-lib-dirs=${final.libffi}/lib"
1709 | ])
1710 | ]);
1711 | in
1712 | final.lib.mapAttrs
1713 | (name: value:
1714 | if (isProperHaskellPackage value && isExecutable value) then statify value else value
1715 | )
1716 | super
1717 | );
1718 | });
1719 | };
1720 |
1721 |
1722 | pkgsWithStaticHaskellBinaries = pkgsWithHaskellLibsReadyForStaticLinking.extend staticHaskellBinariesOverlay;
1723 |
1724 |
1725 | # Legacy names
1726 | haskellPackagesWithLibsReadyForStaticLinking = pkgsWithHaskellLibsReadyForStaticLinking.haskellPackages;
1727 | haskellPackages = pkgsWithStaticHaskellBinaries.haskellPackages;
1728 |
1729 |
1730 |
1731 | in
1732 | rec {
1733 | working = {
1734 | inherit (haskellPackages)
1735 | hello # Minimal dependencies
1736 | stack # Many dependencies
1737 | hlint
1738 | ShellCheck
1739 | cabal-install
1740 | bench
1741 | dhall
1742 | dhall-json
1743 | # postgrest # Dependency `configurator-pg-0.2.7` does not build due to `megaparsec >=7.0.0 && <9.3` (This is fixed in `configurator-pg- 0.2.8`)
1744 | # proto3-suite # Dependency `proto3-wire-1.4.0` does not build due to `bytestring >=0.10.6.0 && <0.11.0`
1745 | hsyslog # Small example of handling https://github.com/NixOS/nixpkgs/issues/43849 correctly
1746 | # aura # `aur` maked as broken in nixpkgs, but works here with `allowBroken = true;` actually
1747 | ;
1748 | } // (if approach == "pkgsStatic" then {} else {
1749 | # Packages that work with `pkgsMusl` but fail with `pkgsStatic`:
1750 |
1751 | inherit (haskellPackages)
1752 | # cachix fails on `pkgsStatic` with
1753 | # cycle detected in the references of '/nix/store/...-cachix-0.2.0-x86_64-unknown-linux-musl-bin' from '/nix/store/...-cachix-0.2.0-x86_64-unknown-linux-musl'
1754 | # because somehow the `Paths_cachix` module gets linked into the library,
1755 | # and it contains a reference to the `binDir`, which is a separate nix output.
1756 | #
1757 | # There's probably a lack of dead-code elimination with `pkgsStatic`,
1758 | # but even if that worked, this is odd because this should work even
1759 | # when you *use* the `binDir` thing in your executable.
1760 | # cachix # fails on latest nixpkgs master due to cachix -> nix -> pkgsStatic.busybox dependency, see https://github.com/nh2/static-haskell-nix/pull/61#issuecomment-544331652
1761 | # darcs fails on `pkgsStatic` because
1762 | darcs # Has native dependencies (`libcurl` and its dependencies)
1763 | # pandoc fails on `pkgsStatic` because Lua doesn't currently build there.
1764 | pandoc # Depends on Lua
1765 | # xmonad fails on `pkgsStatic` because `libXScrnSaver` fails to build there.
1766 | xmonad
1767 | ;
1768 | });
1769 |
1770 | notWorking = {
1771 | inherit (haskellPackages)
1772 | tttool # see #14 # TODO reenable after fixing Package `HPDF-1.4.10` being marked as broken and failing to evaluate
1773 | ;
1774 | };
1775 |
1776 | all = working // notWorking;
1777 |
1778 |
1779 | # Tries to build all executables on Stackage.
1780 | allStackageExecutables =
1781 | lib.filterAttrs (name: x: isStackageExecutable name) haskellPackages;
1782 |
1783 | workingStackageExecutables =
1784 | builtins.removeAttrs allStackageExecutables [
1785 | # List of executables that don't work for reasons not yet investigated.
1786 | # When changing this file, we should always check if this list grows or shrinks.
1787 | "Agda" # fails on `emacs` not building
1788 | "align-audio" # like `audacity`
1789 | "Allure" # depends on `LambdaHack` also in this list
1790 | "audacity" # lots of linker errors, likely lack of pkg-config; needs investigation
1791 | "cuda" # needs `allowUnfree = true`; enabling it gives `unsupported platform for the pure Linux stdenv`
1792 | "diagrams-builder" # needs `glib` which is problematic
1793 | "diagrams-cairo" # `gtk2hs` bug building `glib`: https://github.com/nh2/static-haskell-nix/issues/4#issuecomment-1634681846
1794 | "gtk-sni-tray" # needs `gi-gtk` which requires `glib` which is problematic
1795 | "gtk3" # Haskell package `glib` fails with `Ambiguous module name ‘Gtk2HsSetup’: it was found in multiple packages: gtk2hs-buildtools-0.13.8.0 gtk2hs-buildtools-0.13.8.0`
1796 | "hackage-cli" # `cannot find -lbrotlienc`
1797 | "ihaskell" # linker error to `zmq` and various libraries
1798 | "LambdaHack" # fails `systemd` dependency erroring on `#include `
1799 | "learn-physics" # needs opengl: `cannot find -lGLU` `-lGL`
1800 | "magico" # undefined reference to `_gfortran_concat_string'
1801 | "monomer" # needs `nanovg` which is in this list
1802 | "nanovg" # needs opengl: `cannot find -lGLU` `-lGL`
1803 | "odbc" # `cannot find -lodbc`, `cannot find -ldouble-conversion`
1804 | "pango" # `gtk2hs` bug building `glib`: https://github.com/nh2/static-haskell-nix/issues/4#issuecomment-1634681846
1805 | "qchas" # `_gfortran_concat_string` linker error via openblas
1806 | "rhine-gloss" # needs opengl: `cannot find -lGLU` `-lGL`
1807 | "sound-collage" # like `audacity`
1808 | "split-record" # like `audacity`
1809 | "termonad" # needs `glib` which is problematic
1810 | ];
1811 |
1812 | inherit normalPkgs;
1813 | inherit approachPkgs;
1814 | # Export as `pkgs` our final overridden nixpkgs.
1815 | pkgs = pkgsWithStaticHaskellBinaries;
1816 |
1817 | inherit lib;
1818 |
1819 | inherit pkgsWithGhc;
1820 | inherit pkgsPropagatedBuildInputs;
1821 | inherit pkgsDontDisableStatic;
1822 | inherit pkgsWithArchiveFiles;
1823 | inherit pkgsWithStaticHaskellBinaries;
1824 |
1825 | inherit haskellPackagesWithFailingStackageTestsDisabled;
1826 | inherit haskellPackagesWithLibsReadyForStaticLinking;
1827 | inherit haskellPackages;
1828 | }
1829 |
--------------------------------------------------------------------------------
/update-example-commits.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -eu -o pipefail
3 |
4 | # Convenience script for the task of updating the git commits in the
5 | # example files.
6 |
7 | # Update file
8 | COMMIT="$(git rev-parse HEAD)"
9 | perl -pi -e "s:/static-haskell-nix/archive/........................................:/static-haskell-nix/archive/${COMMIT}:g" static-stack2nix-builder-example/default.nix
10 |
11 | # Commit
12 | git reset
13 | git add static-stack2nix-builder-example/default.nix
14 | git commit -m 'Update example commits'
15 |
--------------------------------------------------------------------------------