1{
2 lib,
3 stdenv,
4 targetPackages,
5 fetchurl,
6 fetchpatch,
7 noSysDirs,
8 langC ? true,
9 langCC ? true,
10 langFortran ? false,
11 langAda ? false,
12 langObjC ? stdenv.targetPlatform.isDarwin,
13 langObjCpp ? stdenv.targetPlatform.isDarwin,
14 langD ? false,
15 langGo ? false,
16 reproducibleBuild ? true,
17 profiledCompiler ? false,
18 langJit ? false,
19 langRust ? false,
20 cargo,
21 staticCompiler ? false,
22 enableShared ? stdenv.targetPlatform.hasSharedLibraries,
23 enableLTO ? stdenv.hostPlatform.hasSharedLibraries,
24 texinfo ? null,
25 perl ? null, # optional, for texi2pod (then pod2man)
26 gmp,
27 mpfr,
28 libmpc,
29 gettext,
30 which,
31 patchelf,
32 binutils,
33 isl ? null, # optional, for the Graphite optimization framework.
34 zlib ? null,
35 libucontext ? null,
36 gnat-bootstrap ? null,
37 enableMultilib ? false,
38 enablePlugin ? (lib.systems.equals stdenv.hostPlatform stdenv.buildPlatform), # Whether to support user-supplied plug-ins
39 name ? "gcc",
40 libcCross ? null,
41 threadsCross ? null, # for MinGW
42 withoutTargetLibc ? false,
43 flex,
44 gnused ? null,
45 buildPackages,
46 pkgsBuildTarget,
47 libxcrypt,
48 disableGdbPlugin ?
49 !enablePlugin
50 || (stdenv.targetPlatform.isAvr && stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64),
51 nukeReferences,
52 callPackage,
53 majorMinorVersion,
54 apple-sdk,
55 cctools,
56 darwin,
57}:
58
59let
60 inherit (lib)
61 callPackageWith
62 filter
63 getBin
64 maintainers
65 makeLibraryPath
66 makeSearchPathOutput
67 mapAttrs
68 optional
69 optionalAttrs
70 optionals
71 optionalString
72 pipe
73 platforms
74 versionAtLeast
75 versions
76 ;
77
78 gccVersions = import ./versions.nix;
79 version = gccVersions.fromMajorMinor majorMinorVersion;
80
81 majorVersion = versions.major version;
82 atLeast14 = versionAtLeast version "14";
83 atLeast13 = versionAtLeast version "13";
84 atLeast12 = versionAtLeast version "12";
85 atLeast11 = versionAtLeast version "11";
86 atLeast10 = versionAtLeast version "10";
87 is14 = majorVersion == "14";
88 is13 = majorVersion == "13";
89 is12 = majorVersion == "12";
90 is11 = majorVersion == "11";
91 is10 = majorVersion == "10";
92 is9 = majorVersion == "9";
93
94 # releases have a form: MAJOR.MINOR.MICRO, like 14.2.1
95 # snapshots have a form like MAJOR.MINOR.MICRO.DATE, like 14.2.1.20250322
96 isSnapshot = lib.length (lib.splitVersion version) == 4;
97 # return snapshot date of gcc's given version:
98 # "14.2.1.20250322" -> "20250322"
99 # "14.2.0" -> ""
100 snapDate = lib.concatStrings (lib.drop 3 (lib.splitVersion version));
101 # return base version without a snapshot:
102 # "14.2.1.20250322" -> "14.2.1"
103 # "14.2.0" -> "14.2.0"
104 baseVersion = lib.concatStringsSep "." (lib.take 3 (lib.splitVersion version));
105
106 disableBootstrap = atLeast11 && !stdenv.hostPlatform.isDarwin && (atLeast12 -> !profiledCompiler);
107
108 inherit (stdenv) buildPlatform hostPlatform targetPlatform;
109 targetConfig =
110 if (!lib.systems.equals targetPlatform hostPlatform) then targetPlatform.config else null;
111
112 patches = callFile ./patches { };
113
114 # Cross-gcc settings (build == host != target)
115 crossMingw = (!lib.systems.equals targetPlatform hostPlatform) && targetPlatform.isMinGW;
116 stageNameAddon = optionalString withoutTargetLibc "-nolibc";
117 crossNameAddon = optionalString (
118 !lib.systems.equals targetPlatform hostPlatform
119 ) "${targetPlatform.config}${stageNameAddon}-";
120
121 callFile = callPackageWith {
122 # lets
123 inherit
124 majorVersion
125 isSnapshot
126 version
127 buildPlatform
128 hostPlatform
129 targetPlatform
130 targetConfig
131 patches
132 crossMingw
133 stageNameAddon
134 crossNameAddon
135 ;
136 # inherit generated with 'nix eval --json --impure --expr "with import ./. {}; lib.attrNames (lib.functionArgs gcc${majorVersion}.cc.override)" | jq '.[]' --raw-output'
137 inherit
138 apple-sdk
139 binutils
140 buildPackages
141 cargo
142 withoutTargetLibc
143 darwin
144 disableBootstrap
145 disableGdbPlugin
146 enableLTO
147 enableMultilib
148 enablePlugin
149 enableShared
150 fetchpatch
151 fetchurl
152 flex
153 gettext
154 gmp
155 gnat-bootstrap
156 gnused
157 isl
158 langAda
159 langC
160 langCC
161 langD
162 langFortran
163 langGo
164 langJit
165 langObjC
166 langObjCpp
167 langRust
168 lib
169 libcCross
170 libmpc
171 libucontext
172 libxcrypt
173 mpfr
174 name
175 noSysDirs
176 nukeReferences
177 patchelf
178 perl
179 pkgsBuildTarget
180 profiledCompiler
181 reproducibleBuild
182 staticCompiler
183 stdenv
184 targetPackages
185 texinfo
186 threadsCross
187 which
188 zlib
189 ;
190 };
191
192in
193
194# Make sure we get GNU sed.
195assert stdenv.buildPlatform.isDarwin -> gnused != null;
196
197# The go frontend is written in c++
198assert langGo -> langCC;
199assert langAda -> gnat-bootstrap != null;
200
201# TODO: fixup D bootstrapping, probably by using gdc11 (and maybe other changes).
202# error: GDC is required to build d
203assert atLeast12 -> !langD;
204
205# threadsCross is just for MinGW
206assert threadsCross != { } -> stdenv.targetPlatform.isWindows;
207
208# profiledCompiler builds inject non-determinism in one of the compilation stages.
209# If turned on, we can't provide reproducible builds anymore
210assert reproducibleBuild -> profiledCompiler == false;
211
212pipe
213 ((callFile ./common/builder.nix { }) (
214 {
215 pname = "${crossNameAddon}${name}";
216 # retain snapshot date in package version, but not in final version
217 # as the version is frequently used to construct pathnames (at least
218 # in cc-wrapper).
219 name = "${crossNameAddon}${name}-${version}";
220 version = baseVersion;
221
222 src = fetchurl {
223 url =
224 if isSnapshot then
225 "mirror://gcc/snapshots/${majorVersion}-${snapDate}/gcc-${majorVersion}-${snapDate}.tar.xz"
226 else
227 "mirror://gcc/releases/gcc-${version}/gcc-${version}.tar.xz";
228 ${if is10 || is11 || is13 then "hash" else "sha256"} = gccVersions.srcHashForVersion version;
229 };
230
231 inherit patches;
232
233 outputs = [
234 "out"
235 "man"
236 "info"
237 ] ++ optional (!langJit) "lib";
238
239 setOutputFlags = false;
240
241 libc_dev = stdenv.cc.libc_dev;
242
243 hardeningDisable = [
244 "format"
245 "pie"
246 "stackclashprotection"
247 ] ++ optionals (is11 && langAda) [ "fortify3" ];
248
249 postPatch =
250 ''
251 configureScripts=$(find . -name configure)
252 for configureScript in $configureScripts; do
253 patchShebangs $configureScript
254 done
255
256 # Make sure nixpkgs versioning match upstream one
257 # to ease version-based comparisons.
258 gcc_base_version=$(< gcc/BASE-VER)
259 if [[ ${baseVersion} != $gcc_base_version ]]; then
260 echo "Please update 'version' variable:"
261 echo " Expected: '$gcc_base_version'"
262 echo " Actual: '${version}'"
263 exit 1
264 fi
265 ''
266 # This should kill all the stdinc frameworks that gcc and friends like to
267 # insert into default search paths.
268 + optionalString hostPlatform.isDarwin ''
269 substituteInPlace gcc/config/darwin-c.c${optionalString atLeast12 "c"} \
270 --replace 'if (stdinc)' 'if (0)'
271
272 substituteInPlace libgcc/config/t-slibgcc-darwin \
273 --replace "-install_name @shlib_slibdir@/\$(SHLIB_INSTALL_NAME)" "-install_name ''${!outputLib}/lib/\$(SHLIB_INSTALL_NAME)"
274
275 substituteInPlace libgfortran/configure \
276 --replace "-install_name \\\$rpath/\\\$soname" "-install_name ''${!outputLib}/lib/\\\$soname"
277 ''
278 + (optionalString ((!lib.systems.equals targetPlatform hostPlatform) || stdenv.cc.libc != null)
279 # On NixOS, use the right path to the dynamic linker instead of
280 # `/lib/ld*.so'.
281 (
282 let
283 libc = if libcCross != null then libcCross else stdenv.cc.libc;
284 in
285 (
286 ''
287 echo "fixing the {GLIBC,UCLIBC,MUSL}_DYNAMIC_LINKER macros..."
288 for header in "gcc/config/"*-gnu.h "gcc/config/"*"/"*.h
289 do
290 grep -q _DYNAMIC_LINKER "$header" || continue
291 echo " fixing $header..."
292 sed -i "$header" \
293 -e 's|define[[:blank:]]*\([UCG]\+\)LIBC_DYNAMIC_LINKER\([0-9]*\)[[:blank:]]"\([^\"]\+\)"$|define \1LIBC_DYNAMIC_LINKER\2 "${libc.out}\3"|g' \
294 -e 's|define[[:blank:]]*MUSL_DYNAMIC_LINKER\([0-9]*\)[[:blank:]]"\([^\"]\+\)"$|define MUSL_DYNAMIC_LINKER\1 "${libc.out}\2"|g'
295 done
296 ''
297 + optionalString (targetPlatform.libc == "musl") ''
298 sed -i gcc/config/linux.h -e '1i#undef LOCAL_INCLUDE_DIR'
299 ''
300 )
301 )
302 )
303 + optionalString targetPlatform.isAvr (''
304 makeFlagsArray+=(
305 '-s' # workaround for hitting hydra log limit
306 'LIMITS_H_TEST=false'
307 )
308 '');
309
310 inherit
311 noSysDirs
312 staticCompiler
313 withoutTargetLibc
314 libcCross
315 crossMingw
316 ;
317
318 inherit (callFile ./common/dependencies.nix { })
319 depsBuildBuild
320 nativeBuildInputs
321 depsBuildTarget
322 buildInputs
323 depsTargetTarget
324 ;
325
326 preConfigure =
327 (callFile ./common/pre-configure.nix { })
328 + optionalString atLeast10 ''
329 ln -sf ${libxcrypt}/include/crypt.h libsanitizer/sanitizer_common/crypt.h
330 '';
331
332 dontDisableStatic = true;
333
334 configurePlatforms = [
335 "build"
336 "host"
337 "target"
338 ];
339
340 configureFlags = callFile ./common/configure-flags.nix { };
341
342 inherit targetConfig;
343
344 buildFlags =
345 # we do not yet have Nix-driven profiling
346 assert atLeast12 -> (profiledCompiler -> !disableBootstrap);
347 if atLeast11 then
348 let
349 target =
350 optionalString (profiledCompiler) "profiled"
351 + optionalString (
352 (lib.systems.equals targetPlatform hostPlatform)
353 && (lib.systems.equals hostPlatform buildPlatform)
354 && !disableBootstrap
355 ) "bootstrap";
356 in
357 optional (target != "") target
358 else
359 optional (
360 (lib.systems.equals targetPlatform hostPlatform) && (lib.systems.equals hostPlatform buildPlatform)
361 ) (if profiledCompiler then "profiledbootstrap" else "bootstrap");
362
363 inherit (callFile ./common/strip-attributes.nix { })
364 stripDebugList
365 stripDebugListTarget
366 preFixup
367 ;
368
369 # https://gcc.gnu.org/PR109898
370 enableParallelInstalling = false;
371
372 env = mapAttrs (_: v: toString v) (
373 {
374
375 NIX_NO_SELF_RPATH = true;
376
377 # https://gcc.gnu.org/install/specific.html#x86-64-x-solaris210
378 ${if hostPlatform.system == "x86_64-solaris" then "CC" else null} = "gcc -m64";
379
380 # Setting $CPATH and $LIBRARY_PATH to make sure both `gcc' and `xgcc' find the
381 # library headers and binaries, regardless of the language being compiled.
382 #
383 # The LTO code doesn't find zlib, so we just add it to $CPATH and
384 # $LIBRARY_PATH in this case.
385 #
386 # Cross-compiling, we need gcc not to read ./specs in order to build the g++
387 # compiler (after the specs for the cross-gcc are created). Having
388 # LIBRARY_PATH= makes gcc read the specs from ., and the build breaks.
389
390 CPATH = optionals (lib.systems.equals targetPlatform hostPlatform) (
391 makeSearchPathOutput "dev" "include" ([ ] ++ optional (zlib != null) zlib)
392 );
393
394 LIBRARY_PATH = optionals (lib.systems.equals targetPlatform hostPlatform) (
395 makeLibraryPath (optional (zlib != null) zlib)
396 );
397
398 NIX_LDFLAGS = optionalString hostPlatform.isSunOS "-lm";
399
400 inherit (callFile ./common/extra-target-flags.nix { })
401 EXTRA_FLAGS_FOR_TARGET
402 EXTRA_LDFLAGS_FOR_TARGET
403 ;
404 }
405 //
406 optionalAttrs (!atLeast12 && stdenv.cc.isClang && (!lib.systems.equals targetPlatform hostPlatform))
407 {
408 NIX_CFLAGS_COMPILE = "-Wno-register";
409 }
410 );
411
412 passthru = {
413 inherit
414 langC
415 langCC
416 langObjC
417 langObjCpp
418 langAda
419 langFortran
420 langGo
421 langD
422 version
423 ;
424 isGNU = true;
425 hardeningUnsupportedFlags =
426 optional (!atLeast11) "zerocallusedregs"
427 ++ optionals (!atLeast12) [
428 "fortify3"
429 "trivialautovarinit"
430 ]
431 ++ optional (
432 !(targetPlatform.isLinux && targetPlatform.isx86_64 && targetPlatform.libc == "glibc")
433 ) "shadowstack"
434 ++ optional (!(targetPlatform.isLinux && targetPlatform.isAarch64)) "pacret"
435 ++ optionals (langFortran) [
436 "fortify"
437 "format"
438 ];
439 };
440
441 enableParallelBuilding = true;
442 inherit enableShared enableMultilib;
443
444 meta =
445 {
446 inherit (callFile ./common/meta.nix { })
447 homepage
448 license
449 description
450 longDescription
451 platforms
452 teams
453 ;
454 }
455 // optionalAttrs (!atLeast11) {
456 badPlatforms = [ "aarch64-darwin" ];
457 }
458 // optionalAttrs is10 {
459 badPlatforms =
460 if (!lib.systems.equals targetPlatform hostPlatform) then [ "aarch64-darwin" ] else [ ];
461 };
462 }
463 // optionalAttrs (!atLeast10 && stdenv.targetPlatform.isDarwin) {
464 # GCC <10 requires default cctools `strip` instead of `llvm-strip` used by Darwin bintools.
465 preBuild = ''
466 makeFlagsArray+=('STRIP=${getBin cctools}/bin/${stdenv.cc.targetPrefix}strip')
467 '';
468 }
469 // optionalAttrs enableMultilib {
470 dontMoveLib64 = true;
471 }
472 ))
473 (
474 [
475 (callPackage ./common/libgcc.nix {
476 inherit
477 version
478 langC
479 langCC
480 langJit
481 targetPlatform
482 hostPlatform
483 withoutTargetLibc
484 enableShared
485 libcCross
486 ;
487 })
488 ]
489 ++ optionals atLeast11 [
490 (callPackage ./common/checksum.nix { inherit langC langCC; })
491 ]
492 )