1{
2 lib,
3 stdenv,
4 version,
5 langC,
6 langCC,
7 langJit,
8 enableShared,
9 targetPlatform,
10 hostPlatform,
11 withoutTargetLibc,
12 libcCross,
13}:
14
15assert !stdenv.targetPlatform.hasSharedLibraries -> !enableShared;
16
17drv:
18lib.pipe drv
19
20 (
21 [
22
23 (
24 pkg:
25 pkg.overrideAttrs (
26 previousAttrs:
27 lib.optionalAttrs
28 (
29 (!lib.systems.equals targetPlatform hostPlatform)
30 && (enableShared || targetPlatform.isMinGW)
31 && withoutTargetLibc
32 )
33 {
34 makeFlags = [
35 "all-gcc"
36 "all-target-libgcc"
37 ];
38 installTargets = "install-gcc install-target-libgcc";
39 }
40 )
41 )
42
43 ]
44 ++ (
45 let
46 targetPlatformSlash =
47 if lib.systems.equals hostPlatform targetPlatform then "" else "${targetPlatform.config}/";
48
49 # If we are building a cross-compiler and the target libc provided
50 # to us at build time has a libgcc, use that instead of building a
51 # new one. This avoids having two separate (but identical) libgcc
52 # outpaths in the closure of most packages, which can be confusing.
53 useLibgccFromTargetLibc = libcCross != null && libcCross ? passthru.libgcc;
54
55 enableLibGccOutput =
56 (
57 !(stdenv.targetPlatform.isWindows || stdenv.targetPlatform.isCygwin)
58 || (lib.systems.equals stdenv.targetPlatform stdenv.hostPlatform)
59 )
60 && !langJit
61 && !stdenv.hostPlatform.isDarwin
62 && enableShared
63 && !useLibgccFromTargetLibc;
64
65 # For some reason libgcc_s.so has major-version "2" on m68k but
66 # "1" everywhere else. Might be worth changing this to "*".
67 libgcc_s-version-major = if targetPlatform.isM68k then "2" else "1";
68
69 in
70 [
71
72 (
73 pkg:
74 pkg.overrideAttrs (
75 previousAttrs:
76 lib.optionalAttrs useLibgccFromTargetLibc {
77 passthru = (previousAttrs.passthru or { }) // {
78 inherit (libcCross) libgcc;
79 };
80 }
81 )
82 )
83
84 (
85 pkg:
86 pkg.overrideAttrs (
87 previousAttrs:
88 lib.optionalAttrs ((!langC) || langJit || enableLibGccOutput) {
89 outputs = previousAttrs.outputs ++ lib.optionals enableLibGccOutput [ "libgcc" ];
90 # This is a separate phase because gcc assembles its phase scripts
91 # in bash instead of nix (we should fix that).
92 preFixupPhases =
93 (previousAttrs.preFixupPhases or [ ])
94 ++ lib.optionals ((!langC) || enableLibGccOutput) [ "preFixupLibGccPhase" ];
95 preFixupLibGccPhase =
96 # delete extra/unused builds of libgcc_s in non-langC builds
97 # (i.e. libgccjit, gnat, etc) to avoid potential confusion
98 lib.optionalString (!langC) ''
99 rm -f $out/lib/libgcc_s.so*
100 ''
101
102 # move `libgcc_s.so` into its own output, `$libgcc`
103 # We maintain $libgcc/lib/$target/ structure to make sure target
104 # strip runs over libgcc_s.so and remove debug references to headers:
105 # https://github.com/NixOS/nixpkgs/issues/316114
106 + lib.optionalString enableLibGccOutput (
107 ''
108 # move libgcc from lib to its own output (libgcc)
109 mkdir -p $libgcc/${targetPlatformSlash}lib
110 mv $lib/${targetPlatformSlash}lib/libgcc_s.so $libgcc/${targetPlatformSlash}lib/
111 mv $lib/${targetPlatformSlash}lib/libgcc_s.so.${libgcc_s-version-major} $libgcc/${targetPlatformSlash}lib/
112 ln -s $libgcc/${targetPlatformSlash}lib/libgcc_s.so $lib/${targetPlatformSlash}lib/
113 ln -s $libgcc/${targetPlatformSlash}lib/libgcc_s.so.${libgcc_s-version-major} $lib/${targetPlatformSlash}lib/
114 ''
115 + lib.optionalString (targetPlatformSlash != "") ''
116 ln -s ${targetPlatformSlash}lib $libgcc/lib
117 ''
118 #
119 # Nixpkgs ordinarily turns dynamic linking into pseudo-static linking:
120 # libraries are still loaded dynamically, exactly which copy of each
121 # library is loaded is permanently fixed at compile time (via RUNPATH).
122 # For libgcc_s we must revert to the "impure dynamic linking" style found
123 # in imperative software distributions. We must do this because
124 # `libgcc_s` calls `malloc()` and therefore has a `DT_NEEDED` for `libc`,
125 # which creates two problems:
126 #
127 # 1. A circular package dependency `glibc`<-`libgcc`<-`glibc`
128 #
129 # 2. According to the `-Wl,-rpath` flags added by Nixpkgs' `ld-wrapper`,
130 # the two versions of `glibc` in the cycle above are actually
131 # different packages. The later one is compiled by this `gcc`, but
132 # the earlier one was compiled by the compiler *that compiled* this
133 # `gcc` (usually the bootstrapFiles). In any event, the `glibc`
134 # dynamic loader won't honor that specificity without namespaced
135 # manual loads (`dlmopen()`). Once a `libc` is present in the address
136 # space of a process, that `libc` will be used to satisfy all
137 # `DT_NEEDED`s for `libc`, regardless of `RUNPATH`s.
138 #
139 # So we wipe the RUNPATH using `patchelf --set-rpath ""`. We can't use
140 # `patchelf --remove-rpath`, because at least as of patchelf 0.15.0 it
141 # will leave the old RUNPATH string in the file where the reference
142 # scanner can still find it:
143 #
144 # https://github.com/NixOS/patchelf/issues/453
145 #
146 # Note: we might be using the bootstrapFiles' copy of patchelf, so we have
147 # to keep doing it this way until both the issue is fixed *and* all the
148 # bootstrapFiles are regenerated, on every platform.
149 #
150 # This patchelfing is *not* effectively equivalent to copying
151 # `libgcc_s` into `glibc`'s outpath. There is one minor and one
152 # major difference:
153 #
154 # 1. (Minor): multiple builds of `glibc` (say, with different
155 # overrides or parameters) will all reference a single store
156 # path:
157 #
158 # /nix/store/xxx...xxx-gcc-libgcc/lib/libgcc_s.so.1
159 #
160 # This many-to-one referrer relationship will be visible in the store's
161 # dependency graph, and will be available to `nix-store -q` queries.
162 # Copying `libgcc_s` into each of its referrers would lose that
163 # information.
164 #
165 # 2. (Major): by referencing `libgcc_s.so.1`, rather than copying it, we
166 # are still able to run `nix-store -qd` on it to find out how it got
167 # built! Most importantly, we can see from that deriver which compiler
168 # was used to build it (or if it is part of the unpacked
169 # bootstrap-files). Copying `libgcc_s.so.1` from one outpath to
170 # another eliminates the ability to make these queries.
171 #
172 + ''
173 patchelf --set-rpath "" $libgcc/lib/libgcc_s.so.${libgcc_s-version-major}
174 ''
175 );
176 }
177 )
178 )
179 ]
180 )
181 )