15 assert !stdenv.targetPlatform.hasSharedLibraries -> !enableShared;
28 (targetPlatform != hostPlatform && (enableShared || targetPlatform.isMinGW) && withoutTargetLibc)
34 installTargets = "install-gcc install-target-libgcc";
42 # nixpkgs did not add the "libgcc" output until gcc11. In theory
43 # the following condition can be changed to `true`, but that has not
45 lib.optionals (lib.versionAtLeast version "11.0")
49 targetPlatformSlash = if hostPlatform == targetPlatform then "" else "${targetPlatform.config}/";
51 # If we are building a cross-compiler and the target libc provided
52 # to us at build time has a libgcc, use that instead of building a
53 # new one. This avoids having two separate (but identical) libgcc
54 # outpaths in the closure of most packages, which can be confusing.
55 useLibgccFromTargetLibc = libcCross != null && libcCross ? passthru.libgcc;
58 (!stdenv.targetPlatform.isWindows || (with stdenv; targetPlatform == hostPlatform))
60 && !stdenv.hostPlatform.isDarwin
62 && !useLibgccFromTargetLibc;
64 # For some reason libgcc_s.so has major-version "2" on m68k but
65 # "1" everywhere else. Might be worth changing this to "*".
66 libgcc_s-version-major = if targetPlatform.isM68k then "2" else "1";
75 lib.optionalAttrs useLibgccFromTargetLibc {
76 passthru = (previousAttrs.passthru or { }) // {
77 inherit (libcCross) libgcc;
87 lib.optionalAttrs ((!langC) || langJit || enableLibGccOutput) {
88 outputs = previousAttrs.outputs ++ lib.optionals enableLibGccOutput [ "libgcc" ];
89 # This is a separate phase because gcc assembles its phase scripts
90 # in bash instead of nix (we should fix that).
92 (previousAttrs.preFixupPhases or [ ])
93 ++ lib.optionals ((!langC) || enableLibGccOutput) [ "preFixupLibGccPhase" ];
95 # delete extra/unused builds of libgcc_s in non-langC builds
96 # (i.e. libgccjit, gnat, etc) to avoid potential confusion
97 lib.optionalString (!langC) ''
98 rm -f $out/lib/libgcc_s.so*
101 # move `libgcc_s.so` into its own output, `$libgcc`
102 # We maintain $libgcc/lib/$target/ structure to make sure target
103 # strip runs over libgcc_s.so and remove debug references to headers:
104 # https://github.com/NixOS/nixpkgs/issues/316114
105 + lib.optionalString enableLibGccOutput (
107 # move libgcc from lib to its own output (libgcc)
108 mkdir -p $libgcc/${targetPlatformSlash}lib
109 mv $lib/${targetPlatformSlash}lib/libgcc_s.so $libgcc/${targetPlatformSlash}lib/
110 mv $lib/${targetPlatformSlash}lib/libgcc_s.so.${libgcc_s-version-major} $libgcc/${targetPlatformSlash}lib/
111 ln -s $libgcc/${targetPlatformSlash}lib/libgcc_s.so $lib/${targetPlatformSlash}lib/
112 ln -s $libgcc/${targetPlatformSlash}lib/libgcc_s.so.${libgcc_s-version-major} $lib/${targetPlatformSlash}lib/
114 + lib.optionalString (targetPlatformSlash != "") ''
115 ln -s ${targetPlatformSlash}lib $libgcc/lib
118 # Nixpkgs ordinarily turns dynamic linking into pseudo-static linking:
119 # libraries are still loaded dynamically, exactly which copy of each
120 # library is loaded is permanently fixed at compile time (via RUNPATH).
121 # For libgcc_s we must revert to the "impure dynamic linking" style found
122 # in imperative software distributions. We must do this because
123 # `libgcc_s` calls `malloc()` and therefore has a `DT_NEEDED` for `libc`,
124 # which creates two problems:
126 # 1. A circular package dependency `glibc`<-`libgcc`<-`glibc`
128 # 2. According to the `-Wl,-rpath` flags added by Nixpkgs' `ld-wrapper`,
129 # the two versions of `glibc` in the cycle above are actually
130 # different packages. The later one is compiled by this `gcc`, but
131 # the earlier one was compiled by the compiler *that compiled* this
132 # `gcc` (usually the bootstrapFiles). In any event, the `glibc`
133 # dynamic loader won't honor that specificity without namespaced
134 # manual loads (`dlmopen()`). Once a `libc` is present in the address
135 # space of a process, that `libc` will be used to satisfy all
136 # `DT_NEEDED`s for `libc`, regardless of `RUNPATH`s.
138 # So we wipe the RUNPATH using `patchelf --set-rpath ""`. We can't use
139 # `patchelf --remove-rpath`, because at least as of patchelf 0.15.0 it
140 # will leave the old RUNPATH string in the file where the reference
141 # scanner can still find it:
143 # https://github.com/NixOS/patchelf/issues/453
145 # Note: we might be using the bootstrapFiles' copy of patchelf, so we have
146 # to keep doing it this way until both the issue is fixed *and* all the
147 # bootstrapFiles are regenerated, on every platform.
149 # This patchelfing is *not* effectively equivalent to copying
150 # `libgcc_s` into `glibc`'s outpath. There is one minor and one
153 # 1. (Minor): multiple builds of `glibc` (say, with different
154 # overrides or parameters) will all reference a single store
157 # /nix/store/xxx...xxx-gcc-libgcc/lib/libgcc_s.so.1
159 # This many-to-one referrer relationship will be visible in the store's
160 # dependency graph, and will be available to `nix-store -q` queries.
161 # Copying `libgcc_s` into each of its referrers would lose that
164 # 2. (Major): by referencing `libgcc_s.so.1`, rather than copying it, we
165 # are still able to run `nix-store -qd` on it to find out how it got
166 # built! Most importantly, we can see from that deriver which compiler
167 # was used to build it (or if it is part of the unpacked
168 # bootstrap-files). Copying `libgcc_s.so.1` from one outpath to
169 # another eliminates the ability to make these queries.
172 patchelf --set-rpath "" $libgcc/lib/libgcc_s.so.${libgcc_s-version-major}