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