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 cc ? null,
14 libc ? null,
15 bintools,
16 coreutils ? null,
17 apple-sdk ? null,
18 zlib ? null,
19 nativeTools,
20 noLibc ? false,
21 nativeLibc,
22 nativePrefix ? "",
23 propagateDoc ? cc != null && cc ? man,
24 extraTools ? [ ],
25 extraPackages ? [ ],
26 extraBuildCommands ? "",
27 nixSupport ? { },
28 isGNU ? false,
29 isClang ? cc.isClang or false,
30 isZig ? cc.isZig or false,
31 isArocc ? cc.isArocc or false,
32 isCcache ? cc.isCcache or false,
33 gnugrep ? null,
34 expand-response-params,
35 libcxx ? null,
36
37 # Whether or not to add `-B` and `-L` to `nix-support/cc-{c,ld}flags`
38 useCcForLibs ?
39
40 # Always add these flags for Clang, because in order to compile (most
41 # software) it needs libraries that are shipped and compiled with gcc.
42 if isClang then
43 true
44
45 # Never add these flags for a build!=host cross-compiler or a host!=target
46 # ("cross-built-native") compiler; currently nixpkgs has a special build
47 # path for these (`crossStageStatic`). Hopefully at some point that build
48 # path will be merged with this one and this conditional will be removed.
49 else if (with stdenvNoCC; buildPlatform != hostPlatform || hostPlatform != targetPlatform) then
50 false
51
52 # Never add these flags when wrapping the bootstrapFiles' compiler; it has a
53 # /usr/-like layout with everything smashed into a single outpath, so it has
54 # no trouble finding its own libraries.
55 else if (cc.passthru.isFromBootstrapFiles or false) then
56 false
57
58 # Add these flags when wrapping `xgcc` (the first compiler that nixpkgs builds)
59 else if (cc.passthru.isXgcc or false) then
60 true
61
62 # Add these flags when wrapping `stdenv.cc`
63 else if (cc.stdenv.cc.cc.passthru.isXgcc or false) then
64 true
65
66 # Do not add these flags in any other situation. This is `false` mainly to
67 # prevent these flags from being added when wrapping *old* versions of gcc
68 # (e.g. `gcc6Stdenv`), since they will cause the old gcc to get `-B` and
69 # `-L` flags pointing at the new gcc's libstdc++ headers. Example failure:
70 # https://hydra.nixos.org/build/213125495
71 else
72 false,
73
74 # the derivation at which the `-B` and `-L` flags added by `useCcForLibs` will point
75 gccForLibs ? if useCcForLibs then cc else null,
76 fortify-headers ? null,
77 includeFortifyHeaders ? null,
78}:
79
80assert nativeTools -> !propagateDoc && nativePrefix != "";
81assert !nativeTools -> cc != null && coreutils != null && gnugrep != null;
82assert !(nativeLibc && noLibc);
83assert (noLibc || nativeLibc) == (libc == null);
84
85let
86 inherit (lib)
87 attrByPath
88 concatMapStrings
89 concatStringsSep
90 escapeShellArg
91 escapeShellArgs
92 getBin
93 getDev
94 getLib
95 getName
96 getVersion
97 mapAttrsToList
98 optional
99 optionalAttrs
100 optionals
101 optionalString
102 removePrefix
103 replaceStrings
104 toList
105 versionAtLeast
106 ;
107
108 inherit (stdenvNoCC) hostPlatform targetPlatform;
109
110 includeFortifyHeaders' =
111 if includeFortifyHeaders != null then
112 includeFortifyHeaders
113 else
114 (targetPlatform.libc == "musl" && isGNU);
115
116 # Prefix for binaries. Customarily ends with a dash separator.
117 #
118 # TODO(@Ericson2314) Make unconditional, or optional but always true by default.
119 targetPrefix = optionalString (targetPlatform != hostPlatform) (targetPlatform.config + "-");
120
121 ccVersion = getVersion cc;
122 ccName = removePrefix targetPrefix (getName cc);
123
124 libc_bin = optionalString (libc != null) (getBin libc);
125 libc_dev = optionalString (libc != null) (getDev libc);
126 libc_lib = optionalString (libc != null) (getLib libc);
127 cc_solib = getLib cc + optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}";
128
129 # The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
130 coreutils_bin = optionalString (!nativeTools) (getBin coreutils);
131
132 # The "suffix salt" is a arbitrary string added in the end of env vars
133 # defined by cc-wrapper's hooks so that multiple cc-wrappers can be used
134 # without interfering. For the moment, it is defined as the target triple,
135 # adjusted to be a valid bash identifier. This should be considered an
136 # unstable implementation detail, however.
137 suffixSalt =
138 replaceStrings [ "-" "." ] [ "_" "_" ] targetPlatform.config
139 + lib.optionalString (targetPlatform.isDarwin && targetPlatform.isStatic) "_static";
140
141 useGccForLibs =
142 useCcForLibs
143 && libcxx == null
144 && !targetPlatform.isDarwin
145 && !(targetPlatform.useLLVM or false)
146 && !(targetPlatform.useAndroidPrebuilt or false)
147 && !(targetPlatform.isiOS or false)
148 && gccForLibs != null;
149 gccForLibs_solib =
150 getLib gccForLibs + optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}";
151
152 # Analogously to cc_solib and gccForLibs_solib
153 libcxx_solib = "${getLib libcxx}/lib";
154
155 # The following two functions, `isGccArchSupported` and
156 # `isGccTuneSupported`, only handle those situations where a flag
157 # (`-march` or `-mtune`) is accepted by one compiler but rejected
158 # by another, and both compilers are relevant to nixpkgs. We are
159 # not trying to maintain a complete list of all flags accepted by
160 # all versions of all compilers ever in nixpkgs.
161 #
162 # The two main cases of interest are:
163 #
164 # - One compiler is gcc and the other is clang
165 # - One compiler is pkgs.gcc and the other is bootstrap-files.gcc
166 # -- older compilers (for example bootstrap's GCC 5) fail with
167 # -march=too-modern-cpu
168
169 isGccArchSupported =
170 arch:
171 if targetPlatform.isPower then
172 false
173 # powerpc does not allow -march=
174 else if isGNU then
175 {
176 # Generic
177 x86-64-v2 = versionAtLeast ccVersion "11.0";
178 x86-64-v3 = versionAtLeast ccVersion "11.0";
179 x86-64-v4 = versionAtLeast ccVersion "11.0";
180
181 # Intel
182 skylake = true;
183 skylake-avx512 = true;
184 cannonlake = versionAtLeast ccVersion "8.0";
185 icelake-client = versionAtLeast ccVersion "8.0";
186 icelake-server = versionAtLeast ccVersion "8.0";
187 cascadelake = versionAtLeast ccVersion "9.0";
188 cooperlake = versionAtLeast ccVersion "10.0";
189 tigerlake = versionAtLeast ccVersion "10.0";
190 knm = versionAtLeast ccVersion "8.0";
191 alderlake = versionAtLeast ccVersion "12.0";
192 sapphirerapids = versionAtLeast ccVersion "11.0";
193 emeraldrapids = versionAtLeast ccVersion "13.0";
194 sierraforest = versionAtLeast ccVersion "13.0";
195
196 # AMD
197 znver1 = true;
198 znver2 = versionAtLeast ccVersion "9.0";
199 znver3 = versionAtLeast ccVersion "11.0";
200 znver4 = versionAtLeast ccVersion "13.0";
201 znver5 = versionAtLeast ccVersion "14.0";
202
203 # LoongArch64
204 # https://gcc.gnu.org/gcc-12/changes.html#loongarch
205 # la464 was added together with loongarch64 support
206 # https://gcc.gnu.org/gcc-14/changes.html#loongarch
207 "la64v1.0" = versionAtLeast ccVersion "14.0";
208 "la64v1.1" = versionAtLeast ccVersion "14.0";
209 la664 = versionAtLeast ccVersion "14.0";
210 }
211 .${arch} or true
212 else if isClang then
213 {
214 #Generic
215 x86-64-v2 = versionAtLeast ccVersion "12.0";
216 x86-64-v3 = versionAtLeast ccVersion "12.0";
217 x86-64-v4 = versionAtLeast ccVersion "12.0";
218
219 # Intel
220 cannonlake = versionAtLeast ccVersion "5.0";
221 icelake-client = versionAtLeast ccVersion "7.0";
222 icelake-server = versionAtLeast ccVersion "7.0";
223 knm = versionAtLeast ccVersion "7.0";
224 alderlake = versionAtLeast ccVersion "16.0";
225 sapphirerapids = versionAtLeast ccVersion "12.0";
226 emeraldrapids = versionAtLeast ccVersion "16.0";
227
228 # AMD
229 znver1 = versionAtLeast ccVersion "4.0";
230 znver2 = versionAtLeast ccVersion "9.0";
231 znver3 = versionAtLeast ccVersion "12.0";
232 znver4 = versionAtLeast ccVersion "16.0";
233 znver5 = versionAtLeast ccVersion "19.1";
234
235 # LoongArch64
236 # https://releases.llvm.org/16.0.0/tools/clang/docs/ReleaseNotes.html#loongarch-support
237 # la464 was added together with loongarch64 support
238 # https://releases.llvm.org/19.1.0/tools/clang/docs/ReleaseNotes.html#loongarch-support
239 "la64v1.0" = versionAtLeast ccVersion "19.1";
240 "la64v1.1" = versionAtLeast ccVersion "19.1";
241 la664 = versionAtLeast ccVersion "19.1";
242 }
243 .${arch} or true
244 else
245 false;
246
247 isGccTuneSupported =
248 tune:
249 # for x86 -mtune= takes the same values as -march, plus two more:
250 if targetPlatform.isx86 then
251 {
252 generic = true;
253 intel = true;
254 }
255 .${tune} or (isGccArchSupported tune)
256 # on arm64, the -mtune= values are specific processors
257 else if targetPlatform.isAarch64 then
258 (
259 if isGNU then
260 {
261 cortex-a53 = true;
262 cortex-a72 = true;
263 "cortex-a72.cortex-a53" = true;
264 }
265 .${tune} or false
266 else if isClang then
267 {
268 cortex-a53 = versionAtLeast ccVersion "3.9"; # llvm dfc5d1
269 }
270 .${tune} or false
271 else
272 false
273 )
274 else if targetPlatform.isPower then
275 # powerpc does not support -march
276 true
277 else if targetPlatform.isMips then
278 # for mips -mtune= takes the same values as -march
279 isGccArchSupported tune
280 else
281 false;
282
283 # Clang does not support as many `-mtune=` values as gcc does;
284 # this function will return the best possible approximation of the
285 # provided `-mtune=` value, or `null` if none exists.
286 #
287 # Note: this function can make use of ccVersion; for example, `if
288 # versionOlder ccVersion "12" then ...`
289 findBestTuneApproximation =
290 tune:
291 let
292 guess =
293 if isClang then
294 {
295 # clang does not tune for big.LITTLE chips
296 "cortex-a72.cortex-a53" = "cortex-a72";
297 }
298 .${tune} or tune
299 else
300 tune;
301 in
302 if isGccTuneSupported guess then guess else null;
303
304 thumb = if targetPlatform.gcc.thumb then "thumb" else "arm";
305 tune =
306 if targetPlatform ? gcc.tune then findBestTuneApproximation targetPlatform.gcc.tune else null;
307
308 # Machine flags. These are necessary to support
309
310 # TODO: We should make a way to support miscellaneous machine
311 # flags and other gcc flags as well.
312
313 machineFlags =
314 # Always add -march based on cpu in triple. Sometimes there is a
315 # discrepancy (x86_64 vs. x86-64), so we provide an "arch" arg in
316 # that case.
317 optional (
318 targetPlatform ? gcc.arch
319 && !(targetPlatform.isDarwin && targetPlatform.isAarch64)
320 && isGccArchSupported targetPlatform.gcc.arch
321 ) "-march=${targetPlatform.gcc.arch}"
322 ++
323 # TODO: aarch64-darwin has mcpu incompatible with gcc
324 optional (
325 targetPlatform ? gcc.cpu && !(targetPlatform.isDarwin && targetPlatform.isAarch64)
326 ) "-mcpu=${targetPlatform.gcc.cpu}"
327 ++
328 # -mfloat-abi only matters on arm32 but we set it here
329 # unconditionally just in case. If the abi specifically sets hard
330 # vs. soft floats we use it here.
331 optional (targetPlatform ? gcc.float-abi) "-mfloat-abi=${targetPlatform.gcc.float-abi}"
332 ++ optional (targetPlatform ? gcc.fpu) "-mfpu=${targetPlatform.gcc.fpu}"
333 ++ optional (targetPlatform ? gcc.mode) "-mmode=${targetPlatform.gcc.mode}"
334 ++ optional (targetPlatform ? gcc.thumb) "-m${thumb}"
335 ++ optional (tune != null) "-mtune=${tune}"
336 ++
337 optional (targetPlatform ? gcc.strict-align)
338 "-m${optionalString (!targetPlatform.gcc.strict-align) "no-"}strict-align"
339 ++ optional (
340 targetPlatform ? gcc.cmodel
341 &&
342 # TODO: clang on powerpcspe also needs a condition: https://github.com/llvm/llvm-project/issues/71356
343 # https://releases.llvm.org/18.1.6/tools/clang/docs/ReleaseNotes.html#loongarch-support
344 ((targetPlatform.isLoongArch64 && isClang) -> versionAtLeast ccVersion "18.1")
345 ) "-mcmodel=${targetPlatform.gcc.cmodel}";
346
347 defaultHardeningFlags = bintools.defaultHardeningFlags or [ ];
348
349 # if cc.hardeningUnsupportedFlagsByTargetPlatform exists, this is
350 # called with the targetPlatform as an argument and
351 # cc.hardeningUnsupportedFlags is completely ignored - the function
352 # is responsible for including the constant hardeningUnsupportedFlags
353 # list however it sees fit.
354 ccHardeningUnsupportedFlags =
355 if cc ? hardeningUnsupportedFlagsByTargetPlatform then
356 cc.hardeningUnsupportedFlagsByTargetPlatform targetPlatform
357 else
358 (cc.hardeningUnsupportedFlags or [ ]);
359
360 darwinPlatformForCC = optionalString targetPlatform.isDarwin (
361 if (targetPlatform.darwinPlatform == "macos" && isGNU) then
362 "macosx"
363 else
364 targetPlatform.darwinPlatform
365 );
366in
367
368assert includeFortifyHeaders' -> fortify-headers != null;
369
370# Ensure bintools matches
371assert libc_bin == bintools.libc_bin;
372assert libc_dev == bintools.libc_dev;
373assert libc_lib == bintools.libc_lib;
374assert nativeTools == bintools.nativeTools;
375assert nativeLibc == bintools.nativeLibc;
376assert nativePrefix == bintools.nativePrefix;
377
378stdenvNoCC.mkDerivation {
379 pname = targetPrefix + (if name != "" then name else "${ccName}-wrapper");
380 version = optionalString (cc != null) ccVersion;
381
382 preferLocalBuild = true;
383
384 outputs = [
385 "out"
386 ]
387 ++ optionals propagateDoc [
388 "man"
389 "info"
390 ];
391
392 # Cannot be in "passthru" due to "substituteAll"
393 inherit isArocc;
394
395 passthru = {
396 inherit targetPrefix suffixSalt;
397 # "cc" is the generic name for a C compiler, but there is no one for package
398 # providing the linker and related tools. The two we use now are GNU
399 # Binutils, and Apple's "cctools"; "bintools" as an attempt to find an
400 # unused middle-ground name that evokes both.
401 inherit bintools;
402 inherit
403 cc
404 libc
405 libcxx
406 nativeTools
407 nativeLibc
408 nativePrefix
409 isGNU
410 isClang
411 isZig
412 ;
413
414 emacsBufferSetup = pkgs: ''
415 ; We should handle propagation here too
416 (mapc
417 (lambda (arg)
418 (when (file-directory-p (concat arg "/include"))
419 (setenv "NIX_CFLAGS_COMPILE_${suffixSalt}" (concat (getenv "NIX_CFLAGS_COMPILE_${suffixSalt}") " -isystem " arg "/include"))))
420 '(${concatStringsSep " " (map (pkg: "\"${pkg}\"") pkgs)}))
421 '';
422
423 # Expose expand-response-params we are /actually/ using. In stdenv
424 # bootstrapping, expand-response-params usually comes from an earlier stage,
425 # so it is important to expose this for reference checking.
426 inherit expand-response-params;
427
428 inherit nixSupport;
429
430 inherit defaultHardeningFlags;
431 };
432
433 dontBuild = true;
434 dontConfigure = true;
435 enableParallelBuilding = true;
436
437 # TODO(@connorbaker):
438 # This is a quick fix unblock builds broken by https://github.com/NixOS/nixpkgs/pull/370750.
439 dontCheckForBrokenSymlinks = true;
440
441 unpackPhase = ''
442 src=$PWD
443 '';
444
445 wrapper = ./cc-wrapper.sh;
446
447 installPhase = ''
448 mkdir -p $out/bin $out/nix-support
449
450 wrap() {
451 local dst="$1"
452 local wrapper="$2"
453 export prog="$3"
454 export use_response_file_by_default=${if isClang && !isCcache then "1" else "0"}
455 substituteAll "$wrapper" "$out/bin/$dst"
456 chmod +x "$out/bin/$dst"
457 }
458 ''
459
460 + (
461 if nativeTools then
462 ''
463 echo ${if targetPlatform.isDarwin then cc else nativePrefix} > $out/nix-support/orig-cc
464
465 ccPath="${if targetPlatform.isDarwin then cc else nativePrefix}/bin"
466 ''
467 else
468 ''
469 echo $cc > $out/nix-support/orig-cc
470
471 ccPath="${cc}/bin"
472 ''
473 )
474
475 # Create symlinks to everything in the bintools wrapper.
476 + ''
477 for bbin in $bintools/bin/*; do
478 mkdir -p "$out/bin"
479 ln -s "$bbin" "$out/bin/$(basename $bbin)"
480 done
481 ''
482
483 # We export environment variables pointing to the wrapped nonstandard
484 # cmds, lest some lousy configure script use those to guess compiler
485 # version.
486 + ''
487 export named_cc=${targetPrefix}cc
488 export named_cxx=${targetPrefix}c++
489
490 if [ -e $ccPath/${targetPrefix}gcc ]; then
491 wrap ${targetPrefix}gcc $wrapper $ccPath/${targetPrefix}gcc
492 ln -s ${targetPrefix}gcc $out/bin/${targetPrefix}cc
493 export named_cc=${targetPrefix}gcc
494 export named_cxx=${targetPrefix}g++
495 elif [ -e $ccPath/clang ]; then
496 wrap ${targetPrefix}clang $wrapper $ccPath/clang
497 ln -s ${targetPrefix}clang $out/bin/${targetPrefix}cc
498 export named_cc=${targetPrefix}clang
499 export named_cxx=${targetPrefix}clang++
500 elif [ -e $ccPath/arocc ]; then
501 wrap ${targetPrefix}arocc $wrapper $ccPath/arocc
502 ln -s ${targetPrefix}arocc $out/bin/${targetPrefix}cc
503 export named_cc=${targetPrefix}arocc
504 fi
505
506 if [ -e $ccPath/${targetPrefix}g++ ]; then
507 wrap ${targetPrefix}g++ $wrapper $ccPath/${targetPrefix}g++
508 ln -s ${targetPrefix}g++ $out/bin/${targetPrefix}c++
509 elif [ -e $ccPath/clang++ ]; then
510 wrap ${targetPrefix}clang++ $wrapper $ccPath/clang++
511 ln -s ${targetPrefix}clang++ $out/bin/${targetPrefix}c++
512 fi
513
514 if [ -e $ccPath/${targetPrefix}cpp ]; then
515 wrap ${targetPrefix}cpp $wrapper $ccPath/${targetPrefix}cpp
516 elif [ -e $ccPath/cpp ]; then
517 wrap ${targetPrefix}cpp $wrapper $ccPath/cpp
518 fi
519 ''
520
521 # No need to wrap gnat, gnatkr, gnatname or gnatprep; we can just symlink them in
522 + optionalString cc.langAda or false ''
523 for cmd in gnatbind gnatchop gnatclean gnatlink gnatls gnatmake; do
524 wrap ${targetPrefix}$cmd ${./gnat-wrapper.sh} $ccPath/${targetPrefix}$cmd
525 done
526
527 for cmd in gnat gnatkr gnatname gnatprep; do
528 ln -s $ccPath/${targetPrefix}$cmd $out/bin/${targetPrefix}$cmd
529 done
530
531 # this symlink points to the unwrapped gnat's output "out". It is used by
532 # our custom gprconfig compiler description to find GNAT's ada runtime. See
533 # ../../development/ada-modules/gprbuild/{boot.nix, nixpkgs-gnat.xml}
534 ln -sf ${cc} $out/nix-support/gprconfig-gnat-unwrapped
535 ''
536
537 + optionalString cc.langD or false ''
538 wrap ${targetPrefix}gdc $wrapper $ccPath/${targetPrefix}gdc
539 ''
540
541 + optionalString cc.langFortran or false ''
542 wrap ${targetPrefix}gfortran $wrapper $ccPath/${targetPrefix}gfortran
543 ln -sv ${targetPrefix}gfortran $out/bin/${targetPrefix}g77
544 ln -sv ${targetPrefix}gfortran $out/bin/${targetPrefix}f77
545 export named_fc=${targetPrefix}gfortran
546 ''
547
548 + optionalString cc.langJava or false ''
549 wrap ${targetPrefix}gcj $wrapper $ccPath/${targetPrefix}gcj
550 ''
551
552 + optionalString cc.langGo or false ''
553 wrap ${targetPrefix}gccgo $wrapper $ccPath/${targetPrefix}gccgo
554 wrap ${targetPrefix}go ${./go-wrapper.sh} $ccPath/${targetPrefix}go
555 '';
556
557 strictDeps = true;
558 propagatedBuildInputs = [
559 bintools
560 ]
561 ++ extraTools
562 ++ optionals cc.langD or cc.langJava or false [ zlib ];
563 depsTargetTargetPropagated = optional (libcxx != null) libcxx ++ extraPackages;
564
565 setupHooks = [
566 ../setup-hooks/role.bash
567 ]
568 ++ optional (cc.langC or true) ./setup-hook.sh
569 ++ optional (cc.langFortran or false) ./fortran-hook.sh
570 ++ optional (targetPlatform.isWindows) (
571 stdenvNoCC.mkDerivation {
572 name = "win-dll-hook.sh";
573 dontUnpack = true;
574 installPhase = ''
575 echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib" > $out
576 echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib64" >> $out
577 echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib32" >> $out
578 '';
579 }
580 );
581
582 postFixup =
583 # Ensure flags files exists, as some other programs cat them. (That these
584 # are considered an exposed interface is a bit dubious, but fine for now.)
585 ''
586 touch "$out/nix-support/cc-cflags"
587 touch "$out/nix-support/cc-ldflags"
588 ''
589
590 # Backwards compatibility for packages expecting this file, e.g. with
591 # `$NIX_CC/nix-support/dynamic-linker`.
592 #
593 # TODO(@Ericson2314): Remove this after stable release and force
594 # everyone to refer to bintools-wrapper directly.
595 + optionalString (!isArocc) ''
596 if [[ -f "$bintools/nix-support/dynamic-linker" ]]; then
597 ln -s "$bintools/nix-support/dynamic-linker" "$out/nix-support"
598 fi
599 if [[ -f "$bintools/nix-support/dynamic-linker-m32" ]]; then
600 ln -s "$bintools/nix-support/dynamic-linker-m32" "$out/nix-support"
601 fi
602 ''
603
604 ##
605 ## GCC libs for non-GCC support
606 ##
607 + optionalString (useGccForLibs && isClang) ''
608
609 echo "-B${gccForLibs}/lib/gcc/${targetPlatform.config}/${gccForLibs.version}" >> $out/nix-support/cc-cflags
610 ''
611 + optionalString (useGccForLibs && !isArocc) ''
612 echo "-L${gccForLibs}/lib/gcc/${targetPlatform.config}/${gccForLibs.version}" >> $out/nix-support/cc-ldflags
613 echo "-L${gccForLibs_solib}/lib" >> $out/nix-support/cc-ldflags
614 ''
615
616 # TODO We would like to connect this to `useGccForLibs`, but we cannot yet
617 # because `libcxxStdenv` on linux still needs this. Maybe someday we'll
618 # always set `useLLVM` on Darwin, and maybe also break down `useLLVM` into
619 # fine-grained use flags (libgcc vs compiler-rt, ld.lld vs legacy, libc++
620 # vs libstdc++, etc.) since Darwin isn't `useLLVM` on all counts. (See
621 # https://clang.llvm.org/docs/Toolchain.html for all the axes one might
622 # break `useLLVM` into.)
623 +
624 optionalString
625 (
626 isClang
627 && targetPlatform.isLinux
628 && !(targetPlatform.useAndroidPrebuilt or false)
629 && !(targetPlatform.useLLVM or false)
630 && gccForLibs != null
631 )
632 (
633 ''
634 echo "--gcc-toolchain=${gccForLibs}" >> $out/nix-support/cc-cflags
635
636 # Pull in 'cc.out' target to get 'libstdc++fs.a'. It should be in
637 # 'cc.lib'. But it's a gcc package bug.
638 # TODO(trofi): remove once gcc is fixed to move libraries to .lib output.
639 echo "-L${gccForLibs}/${
640 optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}"
641 }/lib" >> $out/nix-support/cc-ldflags
642 ''
643 # this ensures that when clang passes -lgcc_s to lld (as it does
644 # when building e.g. firefox), lld is able to find libgcc_s.so
645 + optionals (!isArocc) (
646 concatMapStrings (libgcc: ''
647 echo "-L${libgcc}/lib" >> $out/nix-support/cc-ldflags
648 '') (toList (gccForLibs.libgcc or [ ]))
649 )
650 )
651
652 ##
653 ## General libc support
654 ##
655
656 # The "-B${libc_lib}/lib/" flag is a quick hack to force gcc to link
657 # against the crt1.o from our own glibc, rather than the one in
658 # /usr/lib. (This is only an issue when using an `impure'
659 # compiler/linker, i.e., one that searches /usr/lib and so on.)
660 #
661 # Unfortunately, setting -B appears to override the default search
662 # path. Thus, the gcc-specific "../includes-fixed" directory is
663 # now longer searched and glibc's <limits.h> header fails to
664 # compile, because it uses "#include_next <limits.h>" to find the
665 # limits.h file in ../includes-fixed. To remedy the problem,
666 # another -idirafter is necessary to add that directory again.
667 + optionalString (libc != null) (
668 ''
669 touch "$out/nix-support/libc-cflags"
670 touch "$out/nix-support/libc-ldflags"
671 ''
672 + optionalString (!isArocc) ''
673 echo "-B${libc_lib}${libc.libdir or "/lib/"}" >> $out/nix-support/libc-crt1-cflags
674 ''
675 + optionalString (!(cc.langD or false)) ''
676 echo "-${
677 if isArocc then "I" else "idirafter"
678 } ${libc_dev}${libc.incdir or "/include"}" >> $out/nix-support/libc-cflags
679 ''
680 + optionalString (isGNU && (!(cc.langD or false))) ''
681 for dir in "${cc}"/lib/gcc/*/*/include-fixed; do
682 echo '-idirafter' ''${dir} >> $out/nix-support/libc-cflags
683 done
684 ''
685 + ''
686
687 echo "${libc_lib}" > $out/nix-support/orig-libc
688 echo "${libc_dev}" > $out/nix-support/orig-libc-dev
689 ''
690 # fortify-headers is a set of wrapper headers that augment libc
691 # and use #include_next to pass through to libc's true
692 # implementations, so must appear before them in search order.
693 # in theory a correctly placed -idirafter could be used, but in
694 # practice the compiler may have been built with a --with-headers
695 # like option that forces the libc headers before all -idirafter,
696 # hence -isystem here.
697 + optionalString includeFortifyHeaders' ''
698 echo "-isystem ${fortify-headers}/include" >> $out/nix-support/libc-cflags
699 ''
700 )
701
702 ##
703 ## General libc++ support
704 ##
705
706 # We have a libc++ directly, we have one via "smuggled" GCC, or we have one
707 # bundled with the C compiler because it is GCC
708 +
709 optionalString
710 (libcxx != null || (useGccForLibs && gccForLibs.langCC or false) || (isGNU && cc.langCC or false))
711 ''
712 touch "$out/nix-support/libcxx-cxxflags"
713 touch "$out/nix-support/libcxx-ldflags"
714 ''
715 # Adding -isystem flags should be done only for clang; gcc
716 # already knows how to find its own libstdc++, and adding
717 # additional -isystem flags will confuse gfortran (see
718 # https://github.com/NixOS/nixpkgs/pull/209870#issuecomment-1500550903)
719 + optionalString (libcxx == null && isClang && (useGccForLibs && gccForLibs.langCC or false)) ''
720 for dir in ${gccForLibs}/include/c++/*; do
721 echo "-isystem $dir" >> $out/nix-support/libcxx-cxxflags
722 done
723 for dir in ${gccForLibs}/include/c++/*/${targetPlatform.config}; do
724 echo "-isystem $dir" >> $out/nix-support/libcxx-cxxflags
725 done
726 ''
727 + optionalString (libcxx.isLLVM or false) ''
728 echo "-isystem ${getDev libcxx}/include/c++/v1" >> $out/nix-support/libcxx-cxxflags
729 echo "-stdlib=libc++" >> $out/nix-support/libcxx-ldflags
730 ''
731 # GCC NG friendly libc++
732 + optionalString (libcxx != null && libcxx.isGNU or false) ''
733 echo "-isystem ${getDev libcxx}/include" >> $out/nix-support/libcxx-cxxflags
734 ''
735
736 ##
737 ## Initial CFLAGS
738 ##
739
740 # GCC shows ${cc_solib}/lib in `gcc -print-search-dirs', but not
741 # ${cc_solib}/lib64 (even though it does actually search there...)..
742 # This confuses libtool. So add it to the compiler tool search
743 # path explicitly.
744 + optionalString (!nativeTools && !isArocc) ''
745 if [ -e "${cc_solib}/lib64" -a ! -L "${cc_solib}/lib64" ]; then
746 ccLDFlags+=" -L${cc_solib}/lib64"
747 ccCFlags+=" -B${cc_solib}/lib64"
748 fi
749 ccLDFlags+=" -L${cc_solib}/lib"
750 ccCFlags+=" -B${cc_solib}/lib"
751
752 ''
753 + optionalString (cc.langAda or false && !isArocc) ''
754 touch "$out/nix-support/gnat-cflags"
755 touch "$out/nix-support/gnat-ldflags"
756 basePath=$(echo $cc/lib/*/*/*)
757 ccCFlags+=" -B$basePath -I$basePath/adainclude"
758 gnatCFlags="-I$basePath/adainclude -I$basePath/adalib"
759
760 echo "$gnatCFlags" >> $out/nix-support/gnat-cflags
761 ''
762 + ''
763 echo "$ccLDFlags" >> $out/nix-support/cc-ldflags
764 echo "$ccCFlags" >> $out/nix-support/cc-cflags
765 ''
766 + optionalString (targetPlatform.isDarwin && (libcxx != null) && (cc.isClang or false)) ''
767 echo " -L${libcxx_solib}" >> $out/nix-support/cc-ldflags
768 ''
769
770 ## Prevent clang from seeing /usr/include. There is a desire to achieve this
771 ## through alternate means because it breaks -sysroot and related functionality.
772 #
773 # This flag prevents global system header directories from
774 # leaking through on non‐NixOS Linux. However, on macOS, the
775 # SDK path is used as the sysroot, and forcing `-nostdlibinc`
776 # breaks `-isysroot` with an unwrapped compiler. As macOS has
777 # no `/usr/include`, there’s essentially no risk to dropping
778 # the flag there. See discussion in NixOS/nixpkgs#191152.
779 #
780 +
781 optionalString
782 (
783 (cc.isClang or false)
784 && !(cc.isROCm or false)
785 && !targetPlatform.isDarwin
786 && !targetPlatform.isAndroid
787 )
788 ''
789 echo " -nostdlibinc" >> $out/nix-support/cc-cflags
790 ''
791
792 ##
793 ## Man page and info support
794 ##
795 + optionalString propagateDoc ''
796 ln -s ${cc.man} $man
797 ln -s ${cc.info} $info
798 ''
799 + optionalString (cc.langD or cc.langJava or false && !isArocc) ''
800 echo "-B${zlib}${zlib.libdir or "/lib/"}" >> $out/nix-support/libc-cflags
801 ''
802
803 ##
804 ## Hardening support
805 ##
806 + ''
807 export hardening_unsupported_flags="${concatStringsSep " " ccHardeningUnsupportedFlags}"
808 ''
809
810 # Do not prevent omission of framepointers on x86 32bit due to the small
811 # number of general purpose registers. Keeping EBP available provides
812 # non-trivial performance benefits.
813 # Also skip s390/s390x as it fails to build glibc and causes
814 # performance regressions:
815 # https://bugs.launchpad.net/ubuntu-z-systems/+bug/2064538
816 # https://github.com/NixOS/nixpkgs/issues/428260
817 + (
818 let
819 enable_fp = !targetPlatform.isx86_32 && !targetPlatform.isS390;
820 enable_leaf_fp =
821 enable_fp
822 && (
823 targetPlatform.isx86_64
824 || targetPlatform.isAarch64
825 || (targetPlatform.isRiscV && (!isGNU || versionAtLeast ccVersion "15.1"))
826 );
827 in
828 optionalString enable_fp ''
829 echo " -fno-omit-frame-pointer ${optionalString enable_leaf_fp "-mno-omit-leaf-frame-pointer "}" >> $out/nix-support/cc-cflags-before
830 ''
831 )
832
833 # For clang, this is handled in add-clang-cc-cflags-before.sh
834 + optionalString (!isClang && machineFlags != [ ]) ''
835 printf "%s\n" ${lib.escapeShellArgs machineFlags} >> $out/nix-support/cc-cflags-before
836 ''
837
838 # TODO: categorize these and figure out a better place for them
839 + optionalString targetPlatform.isWindows ''
840 hardening_unsupported_flags+=" pic"
841 ''
842 + optionalString targetPlatform.isMinGW ''
843 hardening_unsupported_flags+=" stackprotector fortify"
844 ''
845 + optionalString targetPlatform.isAvr ''
846 hardening_unsupported_flags+=" stackprotector pic"
847 ''
848 + optionalString (targetPlatform.libc == "newlib" || targetPlatform.libc == "newlib-nano") ''
849 hardening_unsupported_flags+=" stackprotector fortify pie pic"
850 ''
851 + optionalString (targetPlatform.libc == "musl" && targetPlatform.isx86_32) ''
852 hardening_unsupported_flags+=" stackprotector"
853 ''
854 + optionalString targetPlatform.isNetBSD ''
855 hardening_unsupported_flags+=" stackprotector fortify"
856 ''
857 + optionalString cc.langAda or false ''
858 hardening_unsupported_flags+=" format stackprotector strictoverflow"
859 ''
860 + optionalString cc.langD or false ''
861 hardening_unsupported_flags+=" format"
862 ''
863 + optionalString cc.langFortran or false ''
864 hardening_unsupported_flags+=" format"
865 ''
866 + optionalString targetPlatform.isWasm ''
867 hardening_unsupported_flags+=" stackprotector fortify pie pic"
868 ''
869 + optionalString targetPlatform.isMicroBlaze ''
870 hardening_unsupported_flags+=" stackprotector"
871 ''
872
873 + optionalString (libc != null && targetPlatform.isAvr && !isArocc) ''
874 for isa in avr5 avr3 avr4 avr6 avr25 avr31 avr35 avr51 avrxmega2 avrxmega4 avrxmega5 avrxmega6 avrxmega7 tiny-stack; do
875 echo "-B${getLib libc}/avr/lib/$isa" >> $out/nix-support/libc-crt1-cflags
876 done
877 ''
878
879 + optionalString targetPlatform.isAndroid ''
880 echo "-D__ANDROID_API__=${targetPlatform.androidSdkVersion}" >> $out/nix-support/cc-cflags
881 ''
882
883 # There are a few tools (to name one libstdcxx5) which do not work
884 # well with multi line flags, so make the flags single line again
885 + ''
886 for flags in "$out/nix-support"/*flags*; do
887 substituteInPlace "$flags" --replace $'\n' ' '
888 done
889
890 substituteAll ${./add-flags.sh} $out/nix-support/add-flags.sh
891 substituteAll ${./add-hardening.sh} $out/nix-support/add-hardening.sh
892 substituteAll ${../wrapper-common/utils.bash} $out/nix-support/utils.bash
893 substituteAll ${../wrapper-common/darwin-sdk-setup.bash} $out/nix-support/darwin-sdk-setup.bash
894 ''
895
896 + optionalString cc.langAda or false ''
897 substituteAll ${./add-gnat-extra-flags.sh} $out/nix-support/add-gnat-extra-flags.sh
898 ''
899
900 ##
901 ## General Clang support
902 ## Needs to go after ^ because the for loop eats \n and makes this file an invalid script
903 ##
904 + optionalString isClang ''
905 # Escape twice: once for this script, once for the one it gets substituted into.
906 export machineFlags=${escapeShellArg (escapeShellArgs machineFlags)}
907 export defaultTarget=${targetPlatform.config}
908 substituteAll ${./add-clang-cc-cflags-before.sh} $out/nix-support/add-local-cc-cflags-before.sh
909 ''
910
911 ##
912 ## Extra custom steps
913 ##
914 + extraBuildCommands
915 + concatStringsSep "; " (
916 mapAttrsToList (name: value: "echo ${toString value} >> $out/nix-support/${name}") nixSupport
917 );
918
919 env = {
920 inherit isClang;
921
922 # for substitution in utils.bash
923 # TODO(@sternenseemann): invent something cleaner than passing in "" in case of absence
924 expandResponseParams = lib.optionalString (expand-response-params != "") (
925 lib.getExe expand-response-params
926 );
927 # TODO(@sternenseemann): rename env var via stdenv rebuild
928 shell = getBin runtimeShell + runtimeShell.shellPath or "";
929 gnugrep_bin = optionalString (!nativeTools) gnugrep;
930 rm = if nativeTools then "rm" else lib.getExe' coreutils "rm";
931 mktemp = if nativeTools then "mktemp" else lib.getExe' coreutils "mktemp";
932 # stdenv.cc.cc should not be null and we have nothing better for now.
933 # if the native impure bootstrap is gotten rid of this can become `inherit cc;` again.
934 cc = optionalString (!nativeTools) cc;
935 wrapperName = "CC_WRAPPER";
936 inherit suffixSalt coreutils_bin bintools;
937 inherit libc_bin libc_dev libc_lib;
938 inherit darwinPlatformForCC;
939 default_hardening_flags_str = builtins.toString defaultHardeningFlags;
940 }
941 // lib.mapAttrs (_: lib.optionalString targetPlatform.isDarwin) {
942 # These will become empty strings when not targeting Darwin.
943 inherit (targetPlatform) darwinMinVersion darwinMinVersionVariable;
944 }
945 // lib.optionalAttrs (stdenvNoCC.targetPlatform.isDarwin && apple-sdk != null) {
946 # Wrapped compilers should do something useful even when no SDK is provided at `DEVELOPER_DIR`.
947 fallback_sdk = apple-sdk.__spliced.buildTarget or apple-sdk;
948 };
949
950 meta =
951 let
952 cc_ = optionalAttrs (cc != null) cc;
953 in
954 (optionalAttrs (cc_ ? meta) (removeAttrs cc.meta [ "priority" ]))
955 // {
956 description = attrByPath [ "meta" "description" ] "System C compiler" cc_ + " (wrapper script)";
957 priority = 10;
958 mainProgram = if name != "" then name else "${targetPrefix}${ccName}";
959 };
960}