Open thomasjm opened 4 years ago
What's the output of nix why-depends <your image> <gcc derivation>
?
Yes - would be good to fix - we also see it in the closure size test.
@michaelpj it seems to be a direct dependency:
╚═══bin/haskell-nix-closure-exe: ….includes/rts./nix_frozen/store/ly011abgbh1n2w63rqxa98j1n6xa8zd4-gcc-9.2.0/lib/gcc/x86_64-unknow…
=> /nix_frozen/store/ly011abgbh1n2w63rqxa98j1n6xa8zd4-gcc-9.2.0
There's some mention of includes/rts
so maybe RTS related?
FWIW, non-static Haskell executables from nixpkgs also seem to depend on GCC, so it's not just us.
This looks sort of relevant as a way this can happen: https://github.com/NixOS/nixpkgs/issues/311 I think some of the lessons from this one might be relevant also: https://github.com/NixOS/nixpkgs/issues/34376
@Profpatsch, friendly ping -- any chance you know why this might happen (both here and in Nixpkgs in general)? I saw that you fixed the closure size issues with Pandoc.
Pandoc in nixpkgs is a static executable which is why it avoids this problem, I think. The question is whether it's avoidable for dynamically linked things too.
I was just investigating this in our builds.
$ grep -oa '/nix/store/9ygpwbg32bc5689hwbzsjx6x58d1l6q7-gcc-9.2.0/.*' path/to/exe
I get a large number of .h
files that appear to live in a copy of a nix store under gcc. A sampling:
/nix/store/9ygpwbg32bc5689hwbzsjx6x58d1l6q7-gcc-9.2.0/lib/gcc/x86_64-unknown-linux-gnu/9.2.0/include/nix/store/fwpn2f7a4iqszyydw7ag61zlnp6xk5d3-glibc-2.30-dev/include/bits/typesRtsMain.ctypes.hstdint-intn.hstdint-uintn.hTypes.hTSO.hBlock.hmath.hTicky.hHsFFI.hTime.hstddef.EventLogWriter.hRtsAPI.hClosures.hTypes.hInfoTables.hthread-shared-types.hpthreadtypes.htime.herrno.hOSThreads.hSpinLock.h<built-in>Messages.hThreads.hTask.hMiscClosures.hGC.hMBlock.hstruct_FILE.h FILE.hstdio.hsys_errlist.hFlags.hStable.hRts.hRtsFlags.hPrelude.hStg.h `
/nix/store/9ygpwbg32bc5689hwbzsjx6x58d1l6q7-gcc-9.2.0/lib/gcc/x86_64-unknown-linux-gnu/9.2.0/include/nix/store/fwpn2f7a4iqszyydw7ag61zlnp6xk5d3-glibc-2.30-dev/include/bits/typesrts/smProftimer.ctypes.hstdint-intn.hstdint-uintn.hTypes.hRegs.hCCS.hTSO.hGC.hBlock.hmath.hTicky.hHsFFI.hTime.stddef.h EventLogWriter.RtsAPI.hClosures.hCapability.hTypes.InfoTables.hthread-shared-types.hpthreadtypes.htime.herrno.hOSThreads.SpinLock.<built-in>Messages.Threads.Task.hMiscClosures.hMBlock.hstruct_FILE.h
/nix/store/9ygpwbg32bc5689hwbzsjx6x58d1l6q7-gcc-9.2.0/lib/gcc/x86_64-unknown-linux-gnu/9.2.0/include/nix/store/fwpn2f7a4iqszyydw7ag61zlnp6xk5d3-glibc-2.30-dev/include/bits/typesrts/smHsFFI.ctypes.hstdint-intn.hstdint-uintn.hTypes.hHsFFI.hTSO.hBlock.hmath.hTicky.hTime.hstddef.EventLogWriter.hRtsAPI.hClosures.hTypes.hInfoTables.hthread-shared-types.hpthreadtypes.htime.herrno.hOSThreads.hSpinLock.h<built-in>Messages.hThreads.hTask.hMiscClosures.hGC.hMBlock.hstruct_FILE.h FILE.h stdio.hsys_errlist.hFlags.hStable.hRts.hHeapAlloc.h
As expected, setting { dontStrip = false; enableShared = false; }
for the executable I tested eliminates the GCC dependency.
Ah nice @eamsden! That worked for me using only { dontStrip = false; }
. The way that worked best was to apply it to my executable only, not the root modules options, i.e.
packages.my-package.components.exes.my-exe.dontStrip = false;
This raises the question of why haskell.nix
seems to use dontStrip = true
by default?
https://github.com/input-output-hk/haskell.nix/pull/336#discussion_r351491851
Quoth @angerman:
The annoying part with stripping is that it sometimes breaks haskell code. This is mostly due to how haskell code is layed out in object files, and the stripper being a tad bit too agressive.
Where do you add those options? This doesn't seem to work
pkgs.haskell-nix.project {
src = pkgs.haskell-nix.haskellLib.cleanGit {
name = "foo";
src = ./.;
};
compiler-nix-name = "ghc884";
dontPatchElf = false;
dontStrip = false;
}
I met the same problem even I added the dontStrip = false
option. The docker image exceeds 300M. What else should I take a look?
Try and use nix why-depends
to find out why it depends on gcc
and post the output here if you find it.
OK, I figure it out why. In my case, I built a fully static linked haskell executable, yet somehow, there is a reference to the haskell library path in the static binary. Nix scans the static binary and found the reference path so it think that's a runtime dependency which causes it packed glibc
, gcc
, and the whole haskell dependent libs
into the final docker image. After removing the lib reference path from the static binary, the final docker image size drops to around 3Mb.
Obviously, for fully static linked executables, only patchelf --shrink-rpath
and dontStrip=false
is not enough, you need to remove all reference paths from the binary manually with nukeReferences
or removeReferencesTo
.
How do we apply the dontPatchElf
and dontStrip
options? It has not been stated in this thread nor could I find an example in the manual.
Aha, finally figured it out..
pkgs.haskell-nix.project {
src = pkgs.haskell-nix.haskellLib.cleanGit {
name = "foo";
src = ./.;
};
compiler-nix-name = "ghc884";
modules = [{
packages.yourproject.components.exes.yourproject-exe = {
dontStrip = false;
};
}];
}
https://github.com/input-output-hk/haskell.nix/pull/336#discussion_r351491851
Quoth @angerman:
The annoying part with stripping is that it sometimes breaks haskell code. This is mostly due to how haskell code is layed out in object files, and the stripper being a tad bit too agressive.
@angerman is that still the case?
If that's true, a question is whether it would be less painful to turn it off in the cases where it breaks.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
When I build an executable, the Nix dependency closure includes the full GCC compiler. When I use the Nix Docker tools to build a Docker image with a Haskell app, this blows up the size by 143 MB.
To demonstrate, I created a blank Haskell project with
stack new
and added the basicdefault.nix
from the Haskell.nix docs. You can find the repro here: https://github.com/thomasjm/haskell-nix-closure.When I build this and look at the closure, I get the following:
Notice how in addition to normal runtime libs, this contains
gcc-9.2.0-lib
(which is small and okay) as well asgcc-9.2.0
(which is big and shouldn't be a runtime dependency).