Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1# The Nixpkgs CC is not directly usable, since it doesn't know where
2# the C library and standard header files are. Therefore the compiler
3# produced by that package cannot be installed directly in a user
4# environment and used from the command line. So we use a wrapper
5# script that sets up the right environment variables so that the
6# compiler and the linker just "work".
7
8{
9 name ? "",
10 lib,
11 stdenvNoCC,
12 runtimeShell,
13 bintools ? null,
14 libc ? null,
15 coreutils ? null,
16 gnugrep ? null,
17 apple-sdk ? null,
18 netbsd ? null,
19 sharedLibraryLoader ?
20 if libc == null then
21 null
22 else if stdenvNoCC.targetPlatform.isNetBSD then
23 if !(targetPackages ? netbsd) then
24 netbsd.ld_elf_so
25 else if libc != targetPackages.netbsd.headers then
26 targetPackages.netbsd.ld_elf_so
27 else
28 null
29 else
30 lib.getLib libc,
31 nativeTools,
32 noLibc ? false,
33 nativeLibc,
34 nativePrefix ? "",
35 propagateDoc ? bintools != null && bintools ? man,
36 extraPackages ? [ ],
37 extraBuildCommands ? "",
38 isGNU ? bintools.isGNU or false,
39 isLLVM ? bintools.isLLVM or false,
40 isCCTools ? bintools.isCCTools or false,
41 expand-response-params,
42 targetPackages ? { },
43 wrapGas ? false,
44
45 # Note: the hardening flags are part of the bintools-wrapper, rather than
46 # the cc-wrapper, because a few of them are handled by the linker.
47 defaultHardeningFlags ? [
48 "bindnow"
49 "format"
50 "fortify"
51 "fortify3"
52 "pic"
53 "relro"
54 "stackclashprotection"
55 "stackprotector"
56 "strictoverflow"
57 "zerocallusedregs"
58 ]
59 ++ lib.optional (
60 with stdenvNoCC;
61 lib.any (x: x) [
62 # OpenBSD static linking requires PIE
63 (with targetPlatform; isOpenBSD && isStatic)
64 (lib.all (x: x) [
65 # Musl-based platforms will keep "pie", other platforms will not.
66 # If you change this, make sure to update section `{#sec-hardening-in-nixpkgs}`
67 # in the nixpkgs manual to inform users about the defaults.
68 (targetPlatform.libc == "musl")
69 # Except when:
70 # - static aarch64, where compilation works, but produces segfaulting dynamically linked binaries.
71 # - static armv7l, where compilation fails.
72 (!(targetPlatform.isAarch && targetPlatform.isStatic))
73 ])
74 ]
75 ) "pie",
76}:
77
78assert propagateDoc -> bintools ? man;
79assert nativeTools -> !propagateDoc && nativePrefix != "";
80assert !nativeTools -> bintools != null && coreutils != null && gnugrep != null;
81assert !(nativeLibc && noLibc);
82assert (noLibc || nativeLibc) == (libc == null);
83
84let
85 inherit (lib)
86 attrByPath
87 concatStringsSep
88 getBin
89 getDev
90 getLib
91 getName
92 getVersion
93 hasSuffix
94 optional
95 optionalAttrs
96 optionals
97 optionalString
98 platforms
99 removePrefix
100 replaceStrings
101 ;
102
103 inherit (stdenvNoCC) hostPlatform targetPlatform;
104
105 # Prefix for binaries. Customarily ends with a dash separator.
106 #
107 # TODO(@Ericson2314) Make unconditional, or optional but always true by
108 # default.
109 targetPrefix = optionalString (targetPlatform != hostPlatform) (targetPlatform.config + "-");
110
111 bintoolsVersion = getVersion bintools;
112 bintoolsName = removePrefix targetPrefix (getName bintools);
113
114 libc_bin = optionalString (libc != null) (getBin libc);
115 libc_dev = optionalString (libc != null) (getDev libc);
116 libc_lib = optionalString (libc != null) (getLib libc);
117 bintools_bin = optionalString (!nativeTools) (getBin bintools);
118 # The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
119 coreutils_bin = optionalString (!nativeTools) (getBin coreutils);
120
121 # See description in cc-wrapper.
122 suffixSalt =
123 replaceStrings [ "-" "." ] [ "_" "_" ] targetPlatform.config
124 + lib.optionalString (targetPlatform.isDarwin && targetPlatform.isStatic) "_static";
125
126 # The dynamic linker has different names on different platforms. This is a
127 # shell glob that ought to match it.
128 dynamicLinker =
129 if sharedLibraryLoader == null then
130 ""
131 else if targetPlatform.libc == "musl" then
132 "${sharedLibraryLoader}/lib/ld-musl-*"
133 else if targetPlatform.libc == "uclibc" then
134 "${sharedLibraryLoader}/lib/ld*-uClibc.so.1"
135 else if (targetPlatform.libc == "bionic" && targetPlatform.is32bit) then
136 "/system/bin/linker"
137 else if (targetPlatform.libc == "bionic" && targetPlatform.is64bit) then
138 "/system/bin/linker64"
139 else if targetPlatform.libc == "nblibc" then
140 "${sharedLibraryLoader}/libexec/ld.elf_so"
141 else if targetPlatform.system == "i686-linux" then
142 "${sharedLibraryLoader}/lib/ld-linux.so.2"
143 else if targetPlatform.system == "x86_64-linux" then
144 "${sharedLibraryLoader}/lib/ld-linux-x86-64.so.2"
145 else if targetPlatform.system == "s390x-linux" then
146 "${sharedLibraryLoader}/lib/ld64.so.1"
147 # ELFv1 (.1) or ELFv2 (.2) ABI
148 else if targetPlatform.isPower64 then
149 "${sharedLibraryLoader}/lib/ld64.so.*"
150 # ARM with a wildcard, which can be "" or "-armhf".
151 else if (with targetPlatform; isAarch32 && isLinux) then
152 "${sharedLibraryLoader}/lib/ld-linux*.so.3"
153 else if targetPlatform.system == "aarch64-linux" then
154 "${sharedLibraryLoader}/lib/ld-linux-aarch64.so.1"
155 else if targetPlatform.system == "powerpc-linux" then
156 "${sharedLibraryLoader}/lib/ld.so.1"
157 else if targetPlatform.system == "s390-linux" then
158 "${sharedLibraryLoader}/lib/ld.so.1"
159 else if targetPlatform.system == "s390x-linux" then
160 "${sharedLibraryLoader}/lib/ld64.so.1"
161 else if targetPlatform.isMips then
162 "${sharedLibraryLoader}/lib/ld.so.1"
163 # `ld-linux-riscv{32,64}-<abi>.so.1`
164 else if targetPlatform.isRiscV then
165 "${sharedLibraryLoader}/lib/ld-linux-riscv*.so.1"
166 else if targetPlatform.isLoongArch64 then
167 "${sharedLibraryLoader}/lib/ld-linux-loongarch*.so.1"
168 else if targetPlatform.isDarwin then
169 "/usr/lib/dyld"
170 else if targetPlatform.isFreeBSD then
171 "${sharedLibraryLoader}/libexec/ld-elf.so.1"
172 else if targetPlatform.isOpenBSD then
173 "${sharedLibraryLoader}/libexec/ld.so"
174 else if hasSuffix "pc-gnu" targetPlatform.config then
175 "ld.so.1"
176 else
177 "";
178
179in
180
181stdenvNoCC.mkDerivation {
182 pname = targetPrefix + (if name != "" then name else "${bintoolsName}-wrapper");
183 version = optionalString (bintools != null) bintoolsVersion;
184
185 preferLocalBuild = true;
186
187 outputs = [ "out" ] ++ optionals propagateDoc ([ "man" ] ++ optional (bintools ? info) "info");
188
189 passthru = {
190 inherit targetPrefix suffixSalt;
191 inherit
192 bintools
193 libc
194 nativeTools
195 nativeLibc
196 nativePrefix
197 isGNU
198 isLLVM
199 ;
200
201 emacsBufferSetup = pkgs: ''
202 ; We should handle propagation here too
203 (mapc
204 (lambda (arg)
205 (when (file-directory-p (concat arg "/lib"))
206 (setenv "NIX_LDFLAGS_${suffixSalt}" (concat (getenv "NIX_LDFLAGS_${suffixSalt}") " -L" arg "/lib")))
207 (when (file-directory-p (concat arg "/lib64"))
208 (setenv "NIX_LDFLAGS_${suffixSalt}" (concat (getenv "NIX_LDFLAGS_${suffixSalt}") " -L" arg "/lib64"))))
209 '(${concatStringsSep " " (map (pkg: "\"${pkg}\"") pkgs)}))
210 '';
211
212 inherit defaultHardeningFlags;
213 };
214
215 dontBuild = true;
216 dontConfigure = true;
217
218 enableParallelBuilding = true;
219
220 unpackPhase = ''
221 src=$PWD
222 '';
223
224 installPhase = ''
225 mkdir -p $out/bin $out/nix-support
226
227 wrap() {
228 local dst="$1"
229 local wrapper="$2"
230 export prog="$3"
231 export use_response_file_by_default=${if isCCTools then "1" else "0"}
232 substituteAll "$wrapper" "$out/bin/$dst"
233 chmod +x "$out/bin/$dst"
234 }
235 ''
236
237 + (
238 if nativeTools then
239 ''
240 echo ${nativePrefix} > $out/nix-support/orig-bintools
241
242 ldPath="${nativePrefix}/bin"
243 ''
244 else
245 ''
246 echo $bintools_bin > $out/nix-support/orig-bintools
247
248 ldPath="${bintools_bin}/bin"
249 ''
250
251 # Solaris needs an additional ld wrapper.
252 + optionalString (targetPlatform.isSunOS && nativePrefix != "") ''
253 ldPath="${nativePrefix}/bin"
254 exec="$ldPath/${targetPrefix}ld"
255 wrap ld-solaris ${./ld-solaris-wrapper.sh}
256 ''
257 )
258
259 # If we are asked to wrap `gas` and this bintools has it,
260 # then symlink it (`as` will be symlinked next).
261 # This is mainly for the wrapped gnat-bootstrap on x86-64 Darwin,
262 # as it must have both the GNU assembler from cctools (installed as `gas`)
263 # and the Clang integrated assembler (installed as `as`).
264 # See pkgs/os-specific/darwin/binutils/default.nix for details.
265 + optionalString wrapGas ''
266 if [ -e $ldPath/${targetPrefix}gas ]; then
267 ln -s $ldPath/${targetPrefix}gas $out/bin/${targetPrefix}gas
268 fi
269 ''
270
271 # Create symlinks for rest of the binaries.
272 + ''
273 for binary in objdump objcopy size strings as ar nm gprof dwp c++filt addr2line \
274 ranlib readelf elfedit dlltool dllwrap windmc windres; do
275 if [ -e $ldPath/${targetPrefix}''${binary} ]; then
276 ln -s $ldPath/${targetPrefix}''${binary} $out/bin/${targetPrefix}''${binary}
277 fi
278 done
279
280 if [ -e ''${ld:-$ldPath/${targetPrefix}ld} ]; then
281 wrap ${targetPrefix}ld ${./ld-wrapper.sh} ''${ld:-$ldPath/${targetPrefix}ld}
282 fi
283
284 for variant in $ldPath/${targetPrefix}ld.*; do
285 basename=$(basename "$variant")
286 wrap $basename ${./ld-wrapper.sh} $variant
287 done
288 '';
289
290 strictDeps = true;
291 depsTargetTargetPropagated = extraPackages;
292
293 setupHooks = [
294 ../setup-hooks/role.bash
295 ./setup-hook.sh
296 ];
297
298 postFixup =
299 ##
300 ## General libc support
301 ##
302 optionalString (libc != null) (
303 ''
304 touch "$out/nix-support/libc-ldflags"
305 echo "-L${libc_lib}${libc.libdir or "/lib"}" >> $out/nix-support/libc-ldflags
306
307 echo "${libc_lib}" > $out/nix-support/orig-libc
308 echo "${libc_dev}" > $out/nix-support/orig-libc-dev
309 ''
310
311 ##
312 ## Dynamic linker support
313 ##
314 + optionalString (sharedLibraryLoader != null) ''
315 if [[ -z ''${dynamicLinker+x} ]]; then
316 echo "Don't know the name of the dynamic linker for platform '${targetPlatform.config}', so guessing instead." >&2
317 local dynamicLinker="${sharedLibraryLoader}/lib/ld*.so.?"
318 fi
319 ''
320
321 # Expand globs to fill array of options
322 + ''
323 dynamicLinker=($dynamicLinker)
324
325 case ''${#dynamicLinker[@]} in
326 0) echo "No dynamic linker found for platform '${targetPlatform.config}'." >&2;;
327 1) echo "Using dynamic linker: '$dynamicLinker'" >&2;;
328 *) echo "Multiple dynamic linkers found for platform '${targetPlatform.config}'." >&2;;
329 esac
330
331 if [ -n "''${dynamicLinker-}" ]; then
332 echo $dynamicLinker > $out/nix-support/dynamic-linker
333
334 ${
335 if targetPlatform.isDarwin then
336 ''
337 printf "export LD_DYLD_PATH=%q\n" "$dynamicLinker" >> $out/nix-support/setup-hook
338 ''
339 else
340 optionalString (sharedLibraryLoader != null) ''
341 if [ -e ${sharedLibraryLoader}/lib/32/ld-linux.so.2 ]; then
342 echo ${sharedLibraryLoader}/lib/32/ld-linux.so.2 > $out/nix-support/dynamic-linker-m32
343 fi
344 touch $out/nix-support/ld-set-dynamic-linker
345 ''
346 }
347 fi
348 ''
349 )
350
351 ##
352 ## User env support
353 ##
354
355 # Propagate the underling unwrapped bintools so that if you
356 # install the wrapper, you get tools like objdump (same for any
357 # binaries of libc).
358 + optionalString (!nativeTools) ''
359 printWords ${bintools_bin} ${
360 optionalString (libc != null) libc_bin
361 } > $out/nix-support/propagated-user-env-packages
362 ''
363
364 ##
365 ## Man page and info support
366 ##
367 + optionalString propagateDoc (
368 ''
369 ln -s ${bintools.man} $man
370 ''
371 + optionalString (bintools ? info) ''
372 ln -s ${bintools.info} $info
373 ''
374 )
375
376 ##
377 ## Hardening support
378 ##
379
380 # some linkers on some platforms don't support specific -z flags
381 + ''
382 export hardening_unsupported_flags=""
383 if [[ "$($ldPath/${targetPrefix}ld -z now 2>&1 || true)" =~ un(recognized|known)\ option ]]; then
384 hardening_unsupported_flags+=" bindnow"
385 fi
386 if [[ "$($ldPath/${targetPrefix}ld -z relro 2>&1 || true)" =~ un(recognized|known)\ option ]]; then
387 hardening_unsupported_flags+=" relro"
388 fi
389 ''
390
391 + optionalString hostPlatform.isCygwin ''
392 hardening_unsupported_flags+=" pic"
393 ''
394
395 + optionalString (targetPlatform.isAvr || targetPlatform.isWindows) ''
396 hardening_unsupported_flags+=" relro bindnow"
397 ''
398
399 + optionalString (libc != null && targetPlatform.isAvr) ''
400 for isa in avr5 avr3 avr4 avr6 avr25 avr31 avr35 avr51 avrxmega2 avrxmega4 avrxmega5 avrxmega6 avrxmega7 tiny-stack; do
401 echo "-L${getLib libc}/avr/lib/$isa" >> $out/nix-support/libc-cflags
402 done
403 ''
404
405 ##
406 ## GNU specific extra strip flags
407 ##
408
409 # TODO(@sternenseemann): make a generic strip wrapper?
410 +
411 optionalString (bintools.isGNU or false || bintools.isLLVM or false || bintools.isCCTools or false)
412 ''
413 wrap ${targetPrefix}strip ${./gnu-binutils-strip-wrapper.sh} \
414 "${bintools_bin}/bin/${targetPrefix}strip"
415 ''
416
417 ###
418 ### Remove certain timestamps from final binaries
419 ###
420 + optionalString (targetPlatform.isDarwin && !(bintools.isGNU or false)) ''
421 echo "export ZERO_AR_DATE=1" >> $out/nix-support/setup-hook
422 ''
423
424 + ''
425 for flags in "$out/nix-support"/*flags*; do
426 substituteInPlace "$flags" --replace $'\n' ' '
427 done
428
429 substituteAll ${./add-flags.sh} $out/nix-support/add-flags.sh
430 substituteAll ${./add-hardening.sh} $out/nix-support/add-hardening.sh
431 substituteAll ${../wrapper-common/utils.bash} $out/nix-support/utils.bash
432 substituteAll ${../wrapper-common/darwin-sdk-setup.bash} $out/nix-support/darwin-sdk-setup.bash
433 ''
434
435 ###
436 ### Ensure consistent LC_VERSION_MIN_MACOSX
437 ###
438 + optionalString targetPlatform.isDarwin ''
439 substituteAll ${./add-darwin-ldflags-before.sh} $out/nix-support/add-local-ldflags-before.sh
440 ''
441
442 ##
443 ## LLVM ranlab lacks -t option that libtool expects. We can just
444 ## skip it
445 ##
446
447 + optionalString (isLLVM && targetPlatform.isOpenBSD) ''
448 rm $out/bin/${targetPrefix}ranlib
449 wrap \
450 ${targetPrefix}ranlib ${./llvm-ranlib-wrapper.sh} \
451 "${bintools_bin}/bin/${targetPrefix}ranlib"
452 ''
453
454 ##
455 ## Extra custom steps
456 ##
457 + extraBuildCommands;
458
459 env = {
460 # for substitution in utils.bash
461 # TODO(@sternenseemann): invent something cleaner than passing in "" in case of absence
462 expandResponseParams = "${expand-response-params}/bin/expand-response-params";
463 # TODO(@sternenseemann): rename env var via stdenv rebuild
464 shell = (getBin runtimeShell + runtimeShell.shellPath or "");
465 gnugrep_bin = optionalString (!nativeTools) gnugrep;
466 rm = if nativeTools then "rm" else lib.getExe' coreutils "rm";
467 mktemp = if nativeTools then "mktemp" else lib.getExe' coreutils "mktemp";
468 wrapperName = "BINTOOLS_WRAPPER";
469 inherit
470 dynamicLinker
471 targetPrefix
472 suffixSalt
473 coreutils_bin
474 ;
475 inherit
476 bintools_bin
477 libc_bin
478 libc_dev
479 libc_lib
480 ;
481 default_hardening_flags_str = builtins.toString defaultHardeningFlags;
482 }
483 // lib.mapAttrs (_: lib.optionalString targetPlatform.isDarwin) {
484 # These will become empty strings when not targeting Darwin.
485 inherit (targetPlatform)
486 darwinPlatform
487 darwinSdkVersion
488 darwinMinVersion
489 darwinMinVersionVariable
490 ;
491 }
492 // lib.optionalAttrs (stdenvNoCC.targetPlatform.isDarwin && apple-sdk != null) {
493 # Wrapped compilers should do something useful even when no SDK is provided at `DEVELOPER_DIR`.
494 fallback_sdk = apple-sdk.__spliced.buildTarget or apple-sdk;
495 };
496
497 meta =
498 let
499 bintools_ = optionalAttrs (bintools != null) bintools;
500 in
501 (optionalAttrs (bintools_ ? meta) (removeAttrs bintools.meta [ "priority" ]))
502 // {
503 description =
504 attrByPath [ "meta" "description" ] "System binary utilities" bintools_ + " (wrapper script)";
505 priority = 10;
506 };
507}