1{
2 lowPrio,
3 newScope,
4 pkgs,
5 targetPackages,
6 lib,
7 stdenv,
8 libxcrypt,
9 substitute,
10 replaceVars,
11 fetchFromGitHub,
12 fetchpatch,
13 fetchpatch2,
14 overrideCC,
15 wrapCCWith,
16 wrapBintoolsWith,
17 buildPackages,
18 buildLlvmTools, # tools, but from the previous stage, for cross
19 targetLlvmLibraries, # libraries, but from the next stage, for cross
20 targetLlvm,
21 # This is the default binutils, but with *this* version of LLD rather
22 # than the default LLVM version's, if LLD is the choice. We use these for
23 # the `useLLVM` bootstrapping below.
24 bootBintoolsNoLibc ? if stdenv.targetPlatform.linker == "lld" then null else pkgs.bintoolsNoLibc,
25 bootBintools ? if stdenv.targetPlatform.linker == "lld" then null else pkgs.bintools,
26 darwin,
27 gitRelease ? null,
28 officialRelease ? null,
29 monorepoSrc ? null,
30 version ? null,
31 patchesFn ? lib.id,
32 # Allows passthrough to packages via newScope. This makes it possible to
33 # do `(llvmPackages.override { <someLlvmDependency> = bar; }).clang` and get
34 # an llvmPackages whose packages are overridden in an internally consistent way.
35 ...
36}@args:
37
38assert lib.assertMsg (lib.xor (gitRelease != null) (officialRelease != null)) (
39 "must specify `gitRelease` or `officialRelease`"
40 + (lib.optionalString (gitRelease != null) " — not both")
41);
42
43let
44 monorepoSrc' = monorepoSrc;
45
46 metadata = rec {
47 # Import releaseInfo separately to avoid infinite recursion
48 inherit
49 (import ./common-let.nix {
50 inherit (args)
51 lib
52 gitRelease
53 officialRelease
54 version
55 ;
56 })
57 releaseInfo
58 ;
59 inherit (releaseInfo) release_version version;
60 inherit
61 (import ./common-let.nix {
62 inherit
63 lib
64 fetchFromGitHub
65 release_version
66 gitRelease
67 officialRelease
68 monorepoSrc'
69 version
70 ;
71 })
72 llvm_meta
73 monorepoSrc
74 ;
75 src = monorepoSrc;
76 versionDir =
77 (builtins.toString ../.)
78 + "/${if (gitRelease != null) then "git" else lib.versions.major release_version}";
79 getVersionFile =
80 p:
81 builtins.path {
82 name = builtins.baseNameOf p;
83 path =
84 let
85 patches = args.patchesFn (import ./patches.nix);
86
87 constraints = patches."${p}" or null;
88 matchConstraint =
89 {
90 before ? null,
91 after ? null,
92 path,
93 }:
94 let
95 check = fn: value: if value == null then true else fn release_version value;
96 matchBefore = check lib.versionOlder before;
97 matchAfter = check lib.versionAtLeast after;
98 in
99 matchBefore && matchAfter;
100
101 patchDir =
102 toString
103 (
104 if constraints == null then
105 { path = metadata.versionDir; }
106 else
107 (lib.findFirst matchConstraint { path = metadata.versionDir; } constraints)
108 ).path;
109 in
110 "${patchDir}/${p}";
111 };
112 };
113
114 tools = lib.makeExtensible (
115 tools:
116 let
117 callPackage = newScope (tools // args // metadata);
118 clangVersion = lib.versions.major metadata.release_version;
119 mkExtraBuildCommands0 =
120 cc:
121 ''
122 rsrc="$out/resource-root"
123 mkdir "$rsrc"
124 echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
125 ''
126 # clang standard c headers are incompatible with FreeBSD so we have to put them in -idirafter instead of -resource-dir
127 # see https://github.com/freebsd/freebsd-src/commit/f382bac49b1378da3c2dd66bf721beaa16b5d471
128 + (
129 if stdenv.targetPlatform.isFreeBSD then
130 ''
131 echo "-idirafter ${lib.getLib cc}/lib/clang/${clangVersion}/include" >> $out/nix-support/cc-cflags
132 ''
133 else
134 ''
135 ln -s "${lib.getLib cc}/lib/clang/${clangVersion}/include" "$rsrc"
136 ''
137 );
138 mkExtraBuildCommandsBasicRt =
139 cc:
140 mkExtraBuildCommands0 cc
141 + ''
142 ln -s "${targetLlvmLibraries.compiler-rt-no-libc.out}/lib" "$rsrc/lib"
143 '';
144 mkExtraBuildCommands =
145 cc:
146 mkExtraBuildCommands0 cc
147 + ''
148 ln -s "${targetLlvmLibraries.compiler-rt.out}/lib" "$rsrc/lib"
149 ln -s "${targetLlvmLibraries.compiler-rt.out}/share" "$rsrc/share"
150 '';
151
152 bintoolsNoLibc' = if bootBintoolsNoLibc == null then tools.bintoolsNoLibc else bootBintoolsNoLibc;
153 bintools' = if bootBintools == null then tools.bintools else bootBintools;
154 in
155 {
156 libllvm = callPackage ./llvm {
157 };
158
159 # `llvm` historically had the binaries. When choosing an output explicitly,
160 # we need to reintroduce `outputSpecified` to get the expected behavior e.g. of lib.get*
161 llvm = tools.libllvm;
162
163 tblgen = callPackage ./tblgen.nix {
164 patches =
165 builtins.filter
166 # Crude method to drop polly patches if present, they're not needed for tblgen.
167 (p: (!lib.hasInfix "-polly" p))
168 tools.libllvm.patches;
169 clangPatches = [
170 # Would take tools.libclang.patches, but this introduces a cycle due
171 # to replacements depending on the llvm outpath (e.g. the LLVMgold patch).
172 # So take the only patch known to be necessary.
173 (metadata.getVersionFile "clang/gnu-install-dirs.patch")
174 ];
175 };
176
177 libclang = callPackage ./clang {
178 };
179
180 clang-unwrapped = tools.libclang;
181
182 llvm-manpages = lowPrio (
183 tools.libllvm.override {
184 enableManpages = true;
185 python3 = pkgs.python3; # don't use python-boot
186 }
187 );
188
189 clang-manpages = lowPrio (
190 tools.libclang.override {
191 enableManpages = true;
192 python3 = pkgs.python3; # don't use python-boot
193 }
194 );
195
196 # Wrapper for standalone command line utilities
197 clang-tools = callPackage ./clang-tools { };
198
199 # pick clang appropriate for package set we are targeting
200 clang =
201 if stdenv.targetPlatform.libc == null then
202 tools.clangNoLibc
203 else if stdenv.targetPlatform.useLLVM or false then
204 tools.clangUseLLVM
205 else if (pkgs.targetPackages.stdenv or args.stdenv).cc.isGNU then
206 tools.libstdcxxClang
207 else
208 tools.libcxxClang;
209
210 libstdcxxClang = wrapCCWith rec {
211 cc = tools.clang-unwrapped;
212 # libstdcxx is taken from gcc in an ad-hoc way in cc-wrapper.
213 libcxx = null;
214 extraPackages = [ targetLlvmLibraries.compiler-rt ];
215 extraBuildCommands = mkExtraBuildCommands cc;
216 };
217
218 libcxxClang = wrapCCWith rec {
219 cc = tools.clang-unwrapped;
220 libcxx = targetLlvmLibraries.libcxx;
221 extraPackages = [ targetLlvmLibraries.compiler-rt ];
222 extraBuildCommands = mkExtraBuildCommands cc;
223 };
224
225 lld = callPackage ./lld {
226 };
227
228 lldbPlugins = lib.makeExtensible (
229 lldbPlugins:
230 let
231 callPackage = newScope (lldbPlugins // tools // args // metadata);
232 in
233 lib.recurseIntoAttrs { llef = callPackage ./lldb-plugins/llef.nix { }; }
234 );
235
236 lldb = callPackage ./lldb { };
237
238 lldb-manpages = lowPrio (
239 tools.lldb.override {
240 enableManpages = true;
241 python3 = pkgs.python3; # don't use python-boot
242 }
243 );
244
245 # Below, is the LLVM bootstrapping logic. It handles building a
246 # fully LLVM toolchain from scratch. No GCC toolchain should be
247 # pulled in. As a consequence, it is very quick to build different
248 # targets provided by LLVM and we can also build for what GCC
249 # doesn’t support like LLVM. Probably we should move to some other
250 # file.
251
252 bintools-unwrapped = callPackage ./bintools.nix { };
253
254 bintoolsNoLibc = wrapBintoolsWith {
255 bintools = tools.bintools-unwrapped;
256 libc = targetPackages.preLibcHeaders;
257 };
258
259 bintools = wrapBintoolsWith { bintools = tools.bintools-unwrapped; };
260
261 clangUseLLVM = wrapCCWith rec {
262 cc = tools.clang-unwrapped;
263 libcxx = targetLlvmLibraries.libcxx;
264 bintools = bintools';
265 extraPackages = [
266 targetLlvmLibraries.compiler-rt
267 ]
268 ++ lib.optionals (!stdenv.targetPlatform.isWasm && !stdenv.targetPlatform.isFreeBSD) [
269 targetLlvmLibraries.libunwind
270 ];
271 extraBuildCommands = mkExtraBuildCommands cc;
272 nixSupport.cc-cflags = [
273 "-rtlib=compiler-rt"
274 "-Wno-unused-command-line-argument"
275 "-B${targetLlvmLibraries.compiler-rt}/lib"
276 ]
277 ++ lib.optional (
278 !stdenv.targetPlatform.isWasm && !stdenv.targetPlatform.isFreeBSD
279 ) "--unwindlib=libunwind"
280 ++ lib.optional (
281 !stdenv.targetPlatform.isWasm
282 && !stdenv.targetPlatform.isFreeBSD
283 && stdenv.targetPlatform.useLLVM or false
284 ) "-lunwind"
285 ++ lib.optional stdenv.targetPlatform.isWasm "-fno-exceptions";
286 nixSupport.cc-ldflags = lib.optionals (
287 !stdenv.targetPlatform.isWasm && !stdenv.targetPlatform.isFreeBSD
288 ) [ "-L${targetLlvmLibraries.libunwind}/lib" ];
289 };
290
291 clangWithLibcAndBasicRtAndLibcxx = wrapCCWith rec {
292 cc = tools.clang-unwrapped;
293 libcxx = targetLlvmLibraries.libcxx;
294 bintools = bintools';
295 extraPackages = [
296 targetLlvmLibraries.compiler-rt-no-libc
297 ]
298 ++
299 lib.optionals
300 (
301 !stdenv.targetPlatform.isWasm && !stdenv.targetPlatform.isFreeBSD && !stdenv.targetPlatform.isDarwin
302 )
303 [
304 targetLlvmLibraries.libunwind
305 ];
306 extraBuildCommands = mkExtraBuildCommandsBasicRt cc;
307 nixSupport.cc-cflags = [
308 "-rtlib=compiler-rt"
309 "-Wno-unused-command-line-argument"
310 "-B${targetLlvmLibraries.compiler-rt-no-libc}/lib"
311 ]
312 ++ lib.optional (
313 !stdenv.targetPlatform.isWasm && !stdenv.targetPlatform.isFreeBSD && !stdenv.targetPlatform.isDarwin
314 ) "--unwindlib=libunwind"
315 ++ lib.optional (
316 !stdenv.targetPlatform.isWasm
317 && !stdenv.targetPlatform.isFreeBSD
318 && stdenv.targetPlatform.useLLVM or false
319 ) "-lunwind"
320 ++ lib.optional stdenv.targetPlatform.isWasm "-fno-exceptions";
321 nixSupport.cc-ldflags = lib.optionals (
322 !stdenv.targetPlatform.isWasm && !stdenv.targetPlatform.isFreeBSD && !stdenv.targetPlatform.isDarwin
323 ) [ "-L${targetLlvmLibraries.libunwind}/lib" ];
324 };
325
326 clangWithLibcAndBasicRt = wrapCCWith rec {
327 cc = tools.clang-unwrapped;
328 libcxx = null;
329 bintools = bintools';
330 extraPackages = [ targetLlvmLibraries.compiler-rt-no-libc ];
331 extraBuildCommands = mkExtraBuildCommandsBasicRt cc;
332 nixSupport.cc-cflags = [
333 "-rtlib=compiler-rt"
334 "-B${targetLlvmLibraries.compiler-rt-no-libc}/lib"
335 "-nostdlib++"
336 ]
337 ++ lib.optional stdenv.targetPlatform.isWasm "-fno-exceptions";
338 };
339
340 clangNoLibcWithBasicRt = wrapCCWith rec {
341 cc = tools.clang-unwrapped;
342 libcxx = null;
343 bintools = bintoolsNoLibc';
344 extraPackages = [ targetLlvmLibraries.compiler-rt-no-libc ];
345 extraBuildCommands = mkExtraBuildCommandsBasicRt cc;
346 nixSupport.cc-cflags = [
347 "-rtlib=compiler-rt"
348 "-B${targetLlvmLibraries.compiler-rt-no-libc}/lib"
349 ]
350 ++ lib.optional stdenv.targetPlatform.isWasm "-fno-exceptions";
351 };
352
353 clangNoLibcNoRt = wrapCCWith rec {
354 cc = tools.clang-unwrapped;
355 libcxx = null;
356 bintools = bintoolsNoLibc';
357 extraPackages = [ ];
358 # "-nostartfiles" used to be needed for pkgsLLVM, causes problems so don't include it.
359 extraBuildCommands = mkExtraBuildCommands0 cc;
360 nixSupport.cc-cflags = lib.optional stdenv.targetPlatform.isWasm "-fno-exceptions";
361 };
362
363 # This is an "oddly ordered" bootstrap just for Darwin. Probably
364 # don't want it otherwise.
365 clangNoCompilerRtWithLibc =
366 wrapCCWith rec {
367 cc = tools.clang-unwrapped;
368 libcxx = null;
369 bintools = bintools';
370 extraPackages = [ ];
371 extraBuildCommands = mkExtraBuildCommands0 cc;
372 }
373 # FIXME: This should be inside the `wrapCCWith` call.
374 // lib.optionalAttrs stdenv.targetPlatform.isWasm {
375 nixSupport.cc-cflags = [ "-fno-exceptions" ];
376 };
377
378 # Aliases
379 clangNoCompilerRt = tools.clangNoLibcNoRt;
380 clangNoLibc = tools.clangNoLibcWithBasicRt;
381 clangNoLibcxx = tools.clangWithLibcAndBasicRt;
382
383 mlir = callPackage ./mlir { };
384 }
385 // lib.optionalAttrs (lib.versionAtLeast metadata.release_version "19") {
386 bolt = callPackage ./bolt {
387 };
388 }
389 // lib.optionalAttrs (lib.versionOlder metadata.release_version "22") {
390 libclc = callPackage ./libclc { };
391 }
392 // lib.optionalAttrs (lib.versionAtLeast metadata.release_version "20") {
393 flang = callPackage ./flang {
394 mlir = tools.mlir;
395 };
396 }
397 );
398
399 libraries = lib.makeExtensible (
400 libraries:
401 let
402 callPackage = newScope (libraries // buildLlvmTools // args // metadata);
403 in
404 (
405 {
406 compiler-rt-libc = callPackage ./compiler-rt (
407 let
408 # temp rename to avoid infinite recursion
409 stdenv =
410 # Darwin needs to use a bootstrap stdenv to avoid an infinite recursion when cross-compiling.
411 if args.stdenv.hostPlatform.isDarwin then
412 overrideCC darwin.bootstrapStdenv buildLlvmTools.clangWithLibcAndBasicRtAndLibcxx
413 else if args.stdenv.hostPlatform.useLLVM or false then
414 overrideCC args.stdenv buildLlvmTools.clangWithLibcAndBasicRtAndLibcxx
415 else
416 args.stdenv;
417 in
418 {
419 inherit stdenv;
420 }
421 // lib.optionalAttrs (stdenv.hostPlatform.useLLVM or false) {
422 libxcrypt = (libxcrypt.override { inherit stdenv; }).overrideAttrs (old: {
423 configureFlags = old.configureFlags ++ [ "--disable-symvers" ];
424 });
425 }
426 );
427
428 compiler-rt-no-libc = callPackage ./compiler-rt {
429 doFakeLibgcc = stdenv.hostPlatform.useLLVM or false;
430 stdenv =
431 # Darwin needs to use a bootstrap stdenv to avoid an infinite recursion when cross-compiling.
432 if stdenv.hostPlatform.isDarwin then
433 overrideCC darwin.bootstrapStdenv buildLlvmTools.clangNoLibcNoRt
434 else
435 overrideCC stdenv buildLlvmTools.clangNoLibcNoRt;
436 };
437
438 compiler-rt =
439 if
440 stdenv.hostPlatform.libc == null
441 # Building the with-libc compiler-rt and WASM doesn't yet work,
442 # because wasilibc doesn't provide some expected things. See
443 # compiler-rt's file for further details.
444 || stdenv.hostPlatform.isWasm
445 # Failing `#include <term.h>` in
446 # `lib/sanitizer_common/sanitizer_platform_limits_freebsd.cpp`
447 # sanitizers, not sure where to get it.
448 || stdenv.hostPlatform.isFreeBSD
449 then
450 libraries.compiler-rt-no-libc
451 else
452 libraries.compiler-rt-libc;
453
454 stdenv = overrideCC stdenv buildLlvmTools.clang;
455
456 libcxxStdenv = overrideCC stdenv buildLlvmTools.libcxxClang;
457
458 libcxx = callPackage ./libcxx {
459 stdenv =
460 if stdenv.hostPlatform.isDarwin then
461 overrideCC darwin.bootstrapStdenv buildLlvmTools.clangWithLibcAndBasicRt
462 else
463 overrideCC stdenv buildLlvmTools.clangWithLibcAndBasicRt;
464 };
465
466 libunwind = callPackage ./libunwind {
467 stdenv = overrideCC stdenv buildLlvmTools.clangWithLibcAndBasicRt;
468 };
469
470 openmp = callPackage ./openmp {
471 };
472 }
473 // lib.optionalAttrs (lib.versionAtLeast metadata.release_version "20") {
474 libc-overlay = callPackage ./libc {
475 isFullBuild = false;
476 # Use clang due to "gnu::naked" not working on aarch64.
477 # Issue: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77882
478 stdenv = overrideCC stdenv buildLlvmTools.clang;
479 };
480
481 libc-full = callPackage ./libc {
482 isFullBuild = true;
483 # Use clang due to "gnu::naked" not working on aarch64.
484 # Issue: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77882
485 stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcNoRt;
486 cmake =
487 if stdenv.targetPlatform.libc == "llvm" then buildPackages.cmakeMinimal else buildPackages.cmake;
488 python3 =
489 if stdenv.targetPlatform.libc == "llvm" then
490 buildPackages.python3Minimal
491 else
492 buildPackages.python3;
493 };
494
495 libc = if stdenv.targetPlatform.libc == "llvm" then libraries.libc-full else libraries.libc-overlay;
496 }
497 )
498 );
499
500 noExtend = extensible: lib.attrsets.removeAttrs extensible [ "extend" ];
501in
502{
503 inherit tools libraries;
504 inherit (metadata) release_version;
505}
506// (noExtend libraries)
507// (noExtend tools)