at master 8.0 kB view raw
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 )