-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prevent nix/store references in static builds #3194
Prevent nix/store references in static builds #3194
Conversation
f88b0ea
to
3a1d5af
Compare
So I tried to enable split-sections on stack and cabal builds:
This means I will try to make the split-sections setting depend on the OS type. And then I will have to look into pkgsStatic and why it doesn't work there as expected. |
3a1d5af
to
26c2f4f
Compare
Seems hard to do with stack.yaml. A better option might be to not build the dynamic ubuntu executable with stack anymore, but take one of the cabal builds that run anyway instead. Then, cabal will build with -split-sections and stack without.
All of those are now solved. The "only" references remaining are the haskell libraries via |
Yeah, that LGTM. We don't publish that ubuntu executable anyway. IIRC it's just for verifying stack works. |
26c2f4f
to
7625a84
Compare
Ah, right. That makes it easy. I removed the ubuntu executable from the list of artifacts for each MR, no need to store it there, then. At the same time, I also re-enabled the freebsd executable as part of a release, which was disabled because of Cirrus timeouts? I hope that this works again. |
And... immediately the first freebsd build times out. Well the job to fetch the executable from cirrus times out - and that's very likely because this job runs before the cirrus CI job even exists. The latest commit adds a fix to the fetch script, which should deal with this case properly. |
7625a84
to
1b6f5b0
Compare
This makes the static build fail in case any references to the nix store are left over. Those will increase the closure size of the nix derivation massively and lead to a huge docker image. At the same time, those references will not be functional on non-nix systems, to which the static executable is distributed, anyway.
By passing -split-sections to all dependencies, GHC will link only the modules we actually use and not the full package for each dependency. This does neither work on MacOS nor Windows, thus we don't do it for stack right now. Stripping unused symbols in CI will further decrease the size of those files.
This is not used in the release process anyway, because we are using the static build.
This was temporarily disabled, because of timeouts in Cirrus. This seems to work well again.
Turns out that, for For now, we'll need to apply the patch in my pull request to use |
…aller again This works around NixOS/nixpkgs#286285 to use -split-sections in a cross-compiling scenario. This will reduce the size of the static executable and also remove the remaining references to /nix/store/.. reducing closure size dramatically. This also fixes the docker image blowing up in size since we switched to pkgsStatic.
1b6f5b0
to
299dac4
Compare
This worked nicely, the docker image is now around 5 MB again. The prepopulate nix job is currently running out of diskspace, though:
This is because we are re-building the whole dependency chain for haskell packages at once in this PR. I will have to look into setting up the cachix token again and push this from my local machine where it is already built. |
Ofc, I can't seed the macos job locally. The other test failures seem to be random github actions failures. I now pushed the branch to the postgrest repo instead of my fork and started a manually triggered run of the Cachix workflow to seed everything: https://github.com/PostgREST/postgrest/actions/runs/7785206895 |
Seems like I will need to fix the "Seed Cachix" workflow first. Just building the |
Loadtest is still failing, but that's unrelated. Everything else passed after seeding the cache. Merging. |
This adds a check to confirm that the static executable we build via nix does not have any references to /nix/store anymore. This currently fails with paths to the following derivations, as noted in #3169 (comment):
Most of those were introduced in 259d97a and c94aa9c - but the openssl-etc reference was there before, already. Before the switch to pkgsStatic, this didn't blow up closure size that much, so went unnoticed.
But even before, the references that OpenSSL was storing to the sysconfdir (/etc) would not have worked on a non-nix system. This should be possible to fix with a
--sysconfdir
configure flag. Not sure, yet, about the other openssl reference, which has already been replaced by nixpkgs'remove-references-to
.The libpq reference is just an oversight when I introduced the new
libpq
derivation which I fixed in the second commit. The libkrb5 references can probably be solved similarly - we just didn't build with GSSAPI support, so that's new.This leaves us with three haskell dependencies - and at first glance, this seems quite random. The thing here is, that in the new executable, the auto-generated
Paths_xxx
modules for those packages are included. Those three are likely the only dependencies we use that have such a module and that's why they show up. IIRC those Paths modules are actually Template Haskell - and should not be referenced in the final bundle at all. The fact they show up means that GHC is linking way too much stuff into our executable now. The unpacked size of the build artifact is a whopping 51 MB for it now - compared to 17 MB before the switch.How what happened here and why? I don't exactly know, yet, but looking at the last CI run before the switch at https://github.com/PostgREST/postgrest/actions/runs/7660083430 we have:
Those sizes are zipped, but correspond to the sizes mentioned above. Now, those two seem to match up nice: We expect the dynamic build to be smaller than the static build, right?
But note that we also have zipped sizes of:
Those are very similar to the new static build, which is around 12-13 MB zipped: https://github.com/PostgREST/postgrest/actions/runs/7670588137. In fact, those dynamically linked builds also contain all the Paths modules, just without a
/nix/store
path, because they were build outside. Example:This means, that the new static build didn't "break" this in an isolated way, but rather:
Interestingly, the dynamic package build via
nix-build -A postgrestPackage
(not exposed as artifcat anywhere) is also small.I have not been able to find out exactly why this happens, but here are my observations and ideas:
.so
file, in the static overlay we also get a.a
file.Because nix enables--enable-split-sections
, we also get a bunch of.hi
,.p_hi
anddyn_hi
files - one for each module a package exposes.My best guess is that somehow GHC looses the ability to
use theonly links in the code we need. Instead we seem to link in all of the.hi
files directly, so that it.a
files, so basically each package in full.