1{ lowPrio, newScope, pkgs, lib, stdenv, cmake, ninja
2, gccForLibs, preLibcCrossHeaders
3, libxml2, python3, fetchFromGitHub, overrideCC, wrapCCWith, wrapBintoolsWith
4, buildLlvmTools # tools, but from the previous stage, for cross
5, targetLlvmLibraries # libraries, but from the next stage, for cross
6, targetLlvm
7# This is the default binutils, but with *this* version of LLD rather
8# than the default LLVM version's, if LLD is the choice. We use these for
9# the `useLLVM` bootstrapping below.
10, bootBintoolsNoLibc ?
11 if stdenv.targetPlatform.linker == "lld"
12 then null
13 else pkgs.bintoolsNoLibc
14, bootBintools ?
15 if stdenv.targetPlatform.linker == "lld"
16 then null
17 else pkgs.bintools
18, darwin
19# LLVM release information; specify one of these but not both:
20, gitRelease ? null
21 # i.e.:
22 # {
23 # version = /* i.e. "15.0.0" */;
24 # rev = /* commit SHA */;
25 # rev-version = /* human readable version; i.e. "unstable-2022-26-07" */;
26 # sha256 = /* checksum for this release, can omit if specifying your own `monorepoSrc` */;
27 # }
28, officialRelease ? { version = "15.0.7"; sha256 = "sha256-wjuZQyXQ/jsmvy6y1aksCcEDXGBjuhpgngF3XQJ/T4s="; }
29 # i.e.:
30 # {
31 # version = /* i.e. "15.0.0" */;
32 # candidate = /* optional; if specified, should be: "rcN" */
33 # sha256 = /* checksum for this release, can omit if specifying your own `monorepoSrc` */;
34 # }
35# By default, we'll try to fetch a release from `github:llvm/llvm-project`
36# corresponding to the `gitRelease` or `officialRelease` specified.
37#
38# You can provide your own LLVM source by specifying this arg but then it's up
39# to you to make sure that the LLVM repo given matches the release configuration
40# specified.
41, monorepoSrc ? null
42}:
43assert let
44 int = a: if a then 1 else 0;
45 xor = a: b: ((builtins.bitXor (int a) (int b)) == 1);
46in
47 lib.assertMsg
48 (xor
49 (gitRelease != null)
50 (officialRelease != null))
51 ("must specify `gitRelease` or `officialRelease`" +
52 (lib.optionalString (gitRelease != null) " — not both"));
53let
54 monorepoSrc' = monorepoSrc;
55in let
56 releaseInfo = if gitRelease != null then rec {
57 original = gitRelease;
58 release_version = original.version;
59 version = gitRelease.rev-version;
60 } else rec {
61 original = officialRelease;
62 release_version = original.version;
63 version = if original ? candidate then
64 "${release_version}-${original.candidate}"
65 else
66 release_version;
67 };
68
69 monorepoSrc = if monorepoSrc' != null then
70 monorepoSrc'
71 else let
72 sha256 = releaseInfo.original.sha256;
73 rev = if gitRelease != null then
74 gitRelease.rev
75 else
76 "llvmorg-${releaseInfo.version}";
77 in fetchFromGitHub {
78 owner = "llvm";
79 repo = "llvm-project";
80 inherit rev sha256;
81 };
82
83 inherit (releaseInfo) release_version version;
84
85 llvm_meta = {
86 license = lib.licenses.ncsa;
87 maintainers = lib.teams.llvm.members;
88
89 # See llvm/cmake/config-ix.cmake.
90 platforms =
91 lib.platforms.aarch64 ++
92 lib.platforms.arm ++
93 lib.platforms.m68k ++
94 lib.platforms.mips ++
95 lib.platforms.power ++
96 lib.platforms.riscv ++
97 lib.platforms.s390x ++
98 lib.platforms.wasi ++
99 lib.platforms.x86;
100 };
101
102 tools = lib.makeExtensible (tools: let
103 callPackage = newScope (tools // { inherit stdenv cmake ninja libxml2 python3 release_version version monorepoSrc buildLlvmTools; });
104 mkExtraBuildCommands0 = cc: ''
105 rsrc="$out/resource-root"
106 mkdir "$rsrc"
107 ln -s "${cc.lib}/lib/clang/${release_version}/include" "$rsrc"
108 echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
109 '';
110 mkExtraBuildCommands = cc: mkExtraBuildCommands0 cc + ''
111 ln -s "${targetLlvmLibraries.compiler-rt.out}/lib" "$rsrc/lib"
112 ln -s "${targetLlvmLibraries.compiler-rt.out}/share" "$rsrc/share"
113 '';
114
115 bintoolsNoLibc' =
116 if bootBintoolsNoLibc == null
117 then tools.bintoolsNoLibc
118 else bootBintoolsNoLibc;
119 bintools' =
120 if bootBintools == null
121 then tools.bintools
122 else bootBintools;
123
124 in {
125
126 libllvm = callPackage ./llvm {
127 inherit llvm_meta;
128 };
129
130 # `llvm` historically had the binaries. When choosing an output explicitly,
131 # we need to reintroduce `outputSpecified` to get the expected behavior e.g. of lib.get*
132 llvm = tools.libllvm;
133
134 libclang = callPackage ./clang {
135 inherit llvm_meta;
136 };
137
138 clang-unwrapped = tools.libclang;
139
140 llvm-manpages = lowPrio (tools.libllvm.override {
141 enableManpages = true;
142 python3 = pkgs.python3; # don't use python-boot
143 });
144
145 clang-manpages = lowPrio (tools.libclang.override {
146 enableManpages = true;
147 python3 = pkgs.python3; # don't use python-boot
148 });
149
150 # TODO: lldb/docs/index.rst:155:toctree contains reference to nonexisting document 'design/structureddataplugins'
151 # lldb-manpages = lowPrio (tools.lldb.override {
152 # enableManpages = true;
153 # python3 = pkgs.python3; # don't use python-boot
154 # });
155
156 # pick clang appropriate for package set we are targeting
157 clang =
158 /**/ if stdenv.targetPlatform.libc == null then tools.clangNoLibc
159 else if stdenv.targetPlatform.useLLVM or false then tools.clangUseLLVM
160 else if (pkgs.targetPackages.stdenv or stdenv).cc.isGNU then tools.libstdcxxClang
161 else tools.libcxxClang;
162
163 libstdcxxClang = wrapCCWith rec {
164 cc = tools.clang-unwrapped;
165 # libstdcxx is taken from gcc in an ad-hoc way in cc-wrapper.
166 libcxx = null;
167 extraPackages = [
168 targetLlvmLibraries.compiler-rt
169 ];
170 extraBuildCommands = mkExtraBuildCommands cc;
171 };
172
173 libcxxClang = wrapCCWith rec {
174 cc = tools.clang-unwrapped;
175 libcxx = targetLlvmLibraries.libcxx;
176 extraPackages = [
177 libcxx.cxxabi
178 targetLlvmLibraries.compiler-rt
179 ];
180 extraBuildCommands = mkExtraBuildCommands cc;
181 };
182
183 lld = callPackage ./lld {
184 inherit llvm_meta;
185 };
186
187 lldb = callPackage ./lldb {
188 inherit llvm_meta;
189 inherit (darwin) libobjc bootstrap_cmds;
190 inherit (darwin.apple_sdk.libs) xpc;
191 inherit (darwin.apple_sdk.frameworks) Foundation Carbon Cocoa;
192 };
193
194 # Below, is the LLVM bootstrapping logic. It handles building a
195 # fully LLVM toolchain from scratch. No GCC toolchain should be
196 # pulled in. As a consequence, it is very quick to build different
197 # targets provided by LLVM and we can also build for what GCC
198 # doesn’t support like LLVM. Probably we should move to some other
199 # file.
200
201 bintools-unwrapped = callPackage ./bintools {};
202
203 bintoolsNoLibc = wrapBintoolsWith {
204 bintools = tools.bintools-unwrapped;
205 libc = preLibcCrossHeaders;
206 };
207
208 bintools = wrapBintoolsWith {
209 bintools = tools.bintools-unwrapped;
210 };
211
212 clangUseLLVM = wrapCCWith rec {
213 cc = tools.clang-unwrapped;
214 libcxx = targetLlvmLibraries.libcxx;
215 bintools = bintools';
216 extraPackages = [
217 libcxx.cxxabi
218 targetLlvmLibraries.compiler-rt
219 ] ++ lib.optionals (!stdenv.targetPlatform.isWasm) [
220 targetLlvmLibraries.libunwind
221 ];
222 extraBuildCommands = mkExtraBuildCommands cc;
223 nixSupport.cc-cflags =
224 [ "-rtlib=compiler-rt"
225 "-Wno-unused-command-line-argument"
226 "-B${targetLlvmLibraries.compiler-rt}/lib"
227 ]
228 ++ lib.optional (!stdenv.targetPlatform.isWasm) "--unwindlib=libunwind"
229 ++ lib.optional
230 (!stdenv.targetPlatform.isWasm && stdenv.targetPlatform.useLLVM or false)
231 "-lunwind"
232 ++ lib.optional stdenv.targetPlatform.isWasm "-fno-exceptions";
233 };
234
235 clangNoLibcxx = wrapCCWith rec {
236 cc = tools.clang-unwrapped;
237 libcxx = null;
238 bintools = bintools';
239 extraPackages = [
240 targetLlvmLibraries.compiler-rt
241 ];
242 extraBuildCommands = mkExtraBuildCommands cc;
243 nixSupport.cc-cflags = [
244 "-rtlib=compiler-rt"
245 "-B${targetLlvmLibraries.compiler-rt}/lib"
246 "-nostdlib++"
247 ];
248 };
249
250 clangNoLibc = wrapCCWith rec {
251 cc = tools.clang-unwrapped;
252 libcxx = null;
253 bintools = bintoolsNoLibc';
254 extraPackages = [
255 targetLlvmLibraries.compiler-rt
256 ];
257 extraBuildCommands = mkExtraBuildCommands cc;
258 nixSupport.cc-cflags = [
259 "-rtlib=compiler-rt"
260 "-B${targetLlvmLibraries.compiler-rt}/lib"
261 ];
262 };
263
264 clangNoCompilerRt = wrapCCWith rec {
265 cc = tools.clang-unwrapped;
266 libcxx = null;
267 bintools = bintoolsNoLibc';
268 extraPackages = [ ];
269 extraBuildCommands = mkExtraBuildCommands0 cc;
270 nixSupport.cc-cflags = [ "-nostartfiles" ];
271 };
272
273 clangNoCompilerRtWithLibc = wrapCCWith rec {
274 cc = tools.clang-unwrapped;
275 libcxx = null;
276 bintools = bintools';
277 extraPackages = [ ];
278 extraBuildCommands = mkExtraBuildCommands0 cc;
279 };
280
281 });
282
283 libraries = lib.makeExtensible (libraries: let
284 callPackage = newScope (libraries // buildLlvmTools // { inherit stdenv cmake ninja libxml2 python3 release_version version monorepoSrc; });
285 in {
286
287 compiler-rt-libc = callPackage ./compiler-rt {
288 inherit llvm_meta;
289 stdenv = if stdenv.hostPlatform.useLLVM or false
290 then overrideCC stdenv buildLlvmTools.clangNoCompilerRtWithLibc
291 else stdenv;
292 };
293
294 compiler-rt-no-libc = callPackage ./compiler-rt {
295 inherit llvm_meta;
296 stdenv = if stdenv.hostPlatform.useLLVM or false
297 then overrideCC stdenv buildLlvmTools.clangNoCompilerRt
298 else stdenv;
299 };
300
301 # N.B. condition is safe because without useLLVM both are the same.
302 compiler-rt = if stdenv.hostPlatform.isAndroid
303 then libraries.compiler-rt-libc
304 else libraries.compiler-rt-no-libc;
305
306 stdenv = overrideCC stdenv buildLlvmTools.clang;
307
308 libcxxStdenv = overrideCC stdenv buildLlvmTools.libcxxClang;
309
310 libcxxabi = let
311 # CMake will "require" a compiler capable of compiling C++ programs
312 # cxx-header's build does not actually use one so it doesn't really matter
313 # what stdenv we use here, as long as CMake is happy.
314 cxx-headers = callPackage ./libcxx {
315 inherit llvm_meta;
316 headersOnly = true;
317 };
318
319 # `libcxxabi` *doesn't* need a compiler with a working C++ stdlib but it
320 # *does* need a relatively modern C++ compiler (see:
321 # https://releases.llvm.org/15.0.0/projects/libcxx/docs/index.html#platform-and-compiler-support).
322 #
323 # So, we use the clang from this LLVM package set, like libc++
324 # "boostrapping builds" do:
325 # https://releases.llvm.org/15.0.0/projects/libcxx/docs/BuildingLibcxx.html#bootstrapping-build
326 #
327 # We cannot use `clangNoLibcxx` because that contains `compiler-rt` which,
328 # on macOS, depends on `libcxxabi`, thus forming a cycle.
329 stdenv_ = overrideCC stdenv buildLlvmTools.clangNoCompilerRtWithLibc;
330 in callPackage ./libcxxabi {
331 stdenv = stdenv_;
332 inherit llvm_meta cxx-headers;
333 };
334
335 # Like `libcxxabi` above, `libcxx` requires a fairly modern C++ compiler,
336 # so: we use the clang from this LLVM package set instead of the regular
337 # stdenv's compiler.
338 libcxx = callPackage ./libcxx {
339 inherit llvm_meta;
340 stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
341 };
342
343 libunwind = callPackage ./libunwind {
344 inherit llvm_meta;
345 stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
346 };
347
348 openmp = callPackage ./openmp {
349 inherit llvm_meta targetLlvm;
350 };
351 });
352
353in { inherit tools libraries release_version; } // libraries // tools