x86_64: rewrite comparisons
[zig.git] / build.zig
blobe53135ccdfa685ef38980a4ae8d37ee1c1f2ce75
1 const std = @import("std");
2 const builtin = std.builtin;
3 const tests = @import("test/tests.zig");
4 const BufMap = std.BufMap;
5 const mem = std.mem;
6 const ArrayList = std.ArrayList;
7 const io = std.io;
8 const fs = std.fs;
9 const InstallDirectoryOptions = std.Build.InstallDirectoryOptions;
10 const assert = std.debug.assert;
11 const DevEnv = @import("src/dev.zig").Env;
12 const ValueInterpretMode = enum { direct, by_name };
14 const zig_version: std.SemanticVersion = .{ .major = 0, .minor = 14, .patch = 0 };
15 const stack_size = 46 * 1024 * 1024;
17 pub fn build(b: *std.Build) !void {
18     const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false;
19     const target = b.standardTargetOptions(.{
20         .default_target = .{
21             .ofmt = if (only_c) .c else null,
22         },
23     });
24     const optimize = b.standardOptimizeOption(.{});
26     const flat = b.option(bool, "flat", "Put files into the installation prefix in a manner suited for upstream distribution rather than a posix file system hierarchy standard") orelse false;
27     const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode");
28     const use_zig_libcxx = b.option(bool, "use-zig-libcxx", "If libc++ is needed, use zig's bundled version, don't try to integrate with the system") orelse false;
30     const test_step = b.step("test", "Run all the tests");
31     const skip_install_lib_files = b.option(bool, "no-lib", "skip copying of lib/ files and langref to installation prefix. Useful for development") orelse false;
32     const skip_install_langref = b.option(bool, "no-langref", "skip copying of langref to the installation prefix") orelse skip_install_lib_files;
33     const std_docs = b.option(bool, "std-docs", "include standard library autodocs") orelse false;
34     const no_bin = b.option(bool, "no-bin", "skip emitting compiler binary") orelse false;
35     const enable_superhtml = b.option(bool, "enable-superhtml", "Check langref output HTML validity") orelse false;
37     const langref_file = generateLangRef(b);
38     const install_langref = b.addInstallFileWithDir(langref_file, .prefix, "doc/langref.html");
39     const check_langref = superHtmlCheck(b, langref_file);
40     if (enable_superhtml) install_langref.step.dependOn(check_langref);
42     const check_autodocs = superHtmlCheck(b, b.path("lib/docs/index.html"));
43     if (enable_superhtml) {
44         test_step.dependOn(check_langref);
45         test_step.dependOn(check_autodocs);
46     }
47     if (!skip_install_langref) {
48         b.getInstallStep().dependOn(&install_langref.step);
49     }
51     const autodoc_test = b.addObject(.{
52         .name = "std",
53         .zig_lib_dir = b.path("lib"),
54         .root_module = b.createModule(.{
55             .root_source_file = b.path("lib/std/std.zig"),
56             .target = target,
57             .optimize = .Debug,
58         }),
59     });
60     const install_std_docs = b.addInstallDirectory(.{
61         .source_dir = autodoc_test.getEmittedDocs(),
62         .install_dir = .prefix,
63         .install_subdir = "doc/std",
64     });
65     //if (enable_tidy) install_std_docs.step.dependOn(check_autodocs);
66     if (std_docs) {
67         b.getInstallStep().dependOn(&install_std_docs.step);
68     }
70     if (flat) {
71         b.installFile("LICENSE", "LICENSE");
72         b.installFile("README.md", "README.md");
73     }
75     const langref_step = b.step("langref", "Build and install the language reference");
76     langref_step.dependOn(&install_langref.step);
78     const std_docs_step = b.step("std-docs", "Build and install the standard library documentation");
79     std_docs_step.dependOn(&install_std_docs.step);
81     const docs_step = b.step("docs", "Build and install documentation");
82     docs_step.dependOn(langref_step);
83     docs_step.dependOn(std_docs_step);
85     const skip_debug = b.option(bool, "skip-debug", "Main test suite skips debug builds") orelse false;
86     const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false;
87     const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release;
88     const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release;
89     const skip_release_safe = b.option(bool, "skip-release-safe", "Main test suite skips release-safe builds") orelse skip_release;
90     const skip_non_native = b.option(bool, "skip-non-native", "Main test suite skips non-native builds") orelse false;
91     const skip_libc = b.option(bool, "skip-libc", "Main test suite skips tests that link libc") orelse false;
92     const skip_single_threaded = b.option(bool, "skip-single-threaded", "Main test suite skips tests that are single-threaded") orelse false;
93     const skip_translate_c = b.option(bool, "skip-translate-c", "Main test suite skips translate-c tests") orelse false;
94     const skip_run_translated_c = b.option(bool, "skip-run-translated-c", "Main test suite skips run-translated-c tests") orelse false;
96     const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;
98     const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false;
99     const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse static_llvm;
100     const llvm_has_m68k = b.option(
101         bool,
102         "llvm-has-m68k",
103         "Whether LLVM has the experimental target m68k enabled",
104     ) orelse false;
105     const llvm_has_csky = b.option(
106         bool,
107         "llvm-has-csky",
108         "Whether LLVM has the experimental target csky enabled",
109     ) orelse false;
110     const llvm_has_arc = b.option(
111         bool,
112         "llvm-has-arc",
113         "Whether LLVM has the experimental target arc enabled",
114     ) orelse false;
115     const llvm_has_xtensa = b.option(
116         bool,
117         "llvm-has-xtensa",
118         "Whether LLVM has the experimental target xtensa enabled",
119     ) orelse false;
120     const enable_ios_sdk = b.option(bool, "enable-ios-sdk", "Run tests requiring presence of iOS SDK and frameworks") orelse false;
121     const enable_macos_sdk = b.option(bool, "enable-macos-sdk", "Run tests requiring presence of macOS SDK and frameworks") orelse enable_ios_sdk;
122     const enable_symlinks_windows = b.option(bool, "enable-symlinks-windows", "Run tests requiring presence of symlinks on Windows") orelse false;
123     const config_h_path_option = b.option([]const u8, "config_h", "Path to the generated config.h");
125     if (!skip_install_lib_files) {
126         b.installDirectory(.{
127             .source_dir = b.path("lib"),
128             .install_dir = if (flat) .prefix else .lib,
129             .install_subdir = if (flat) "lib" else "zig",
130             .exclude_extensions = &[_][]const u8{
131                 // exclude files from lib/std/compress/testdata
132                 ".gz",
133                 ".z.0",
134                 ".z.9",
135                 ".zst.3",
136                 ".zst.19",
137                 "rfc1951.txt",
138                 "rfc1952.txt",
139                 "rfc8478.txt",
140                 // exclude files from lib/std/compress/flate/testdata
141                 ".expect",
142                 ".expect-noinput",
143                 ".golden",
144                 ".input",
145                 "compress-e.txt",
146                 "compress-gettysburg.txt",
147                 "compress-pi.txt",
148                 "rfc1951.txt",
149                 // exclude files from lib/std/compress/lzma/testdata
150                 ".lzma",
151                 // exclude files from lib/std/compress/xz/testdata
152                 ".xz",
153                 // exclude files from lib/std/tz/
154                 ".tzif",
155                 // exclude files from lib/std/tar/testdata
156                 ".tar",
157                 // others
158                 "README.md",
159             },
160             .blank_extensions = &[_][]const u8{
161                 "test.zig",
162             },
163         });
164     }
166     if (only_install_lib_files)
167         return;
169     const entitlements = b.option([]const u8, "entitlements", "Path to entitlements file for hot-code swapping without sudo on macOS");
170     const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");
171     const tracy_callstack = b.option(bool, "tracy-callstack", "Include callstack information with Tracy data. Does nothing if -Dtracy is not provided") orelse (tracy != null);
172     const tracy_allocation = b.option(bool, "tracy-allocation", "Include allocation information with Tracy data. Does nothing if -Dtracy is not provided") orelse (tracy != null);
173     const tracy_callstack_depth: u32 = b.option(u32, "tracy-callstack-depth", "Declare callstack depth for Tracy data. Does nothing if -Dtracy_callstack is not provided") orelse 10;
174     const force_gpa = b.option(bool, "force-gpa", "Force the compiler to use GeneralPurposeAllocator") orelse false;
175     const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse (enable_llvm or only_c);
176     const sanitize_thread = b.option(bool, "sanitize-thread", "Enable thread-sanitization") orelse false;
177     const strip = b.option(bool, "strip", "Omit debug information");
178     const valgrind = b.option(bool, "valgrind", "Enable valgrind integration");
179     const pie = b.option(bool, "pie", "Produce a Position Independent Executable");
180     const value_interpret_mode = b.option(ValueInterpretMode, "value-interpret-mode", "How the compiler translates between 'std.builtin' types and its internal datastructures") orelse .direct;
181     const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false;
183     const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: {
184         if (strip == true) break :blk @as(u32, 0);
185         if (optimize != .Debug) break :blk 0;
186         break :blk 4;
187     };
189     const exe = addCompilerStep(b, .{
190         .optimize = optimize,
191         .target = target,
192         .strip = strip,
193         .valgrind = valgrind,
194         .sanitize_thread = sanitize_thread,
195         .single_threaded = single_threaded,
196     });
197     exe.pie = pie;
198     exe.entitlements = entitlements;
200     exe.build_id = b.option(
201         std.zig.BuildId,
202         "build-id",
203         "Request creation of '.note.gnu.build-id' section",
204     );
206     if (no_bin) {
207         b.getInstallStep().dependOn(&exe.step);
208     } else {
209         const install_exe = b.addInstallArtifact(exe, .{
210             .dest_dir = if (flat) .{ .override = .prefix } else .default,
211         });
212         b.getInstallStep().dependOn(&install_exe.step);
213     }
215     test_step.dependOn(&exe.step);
217     if (target.result.os.tag == .windows and target.result.abi == .gnu) {
218         // LTO is currently broken on mingw, this can be removed when it's fixed.
219         exe.want_lto = false;
220     }
222     const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend");
223     exe.use_llvm = use_llvm;
224     exe.use_lld = use_llvm;
226     const exe_options = b.addOptions();
227     exe.root_module.addOptions("build_options", exe_options);
229     exe_options.addOption(u32, "mem_leak_frames", mem_leak_frames);
230     exe_options.addOption(bool, "skip_non_native", skip_non_native);
231     exe_options.addOption(bool, "have_llvm", enable_llvm);
232     exe_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k);
233     exe_options.addOption(bool, "llvm_has_csky", llvm_has_csky);
234     exe_options.addOption(bool, "llvm_has_arc", llvm_has_arc);
235     exe_options.addOption(bool, "llvm_has_xtensa", llvm_has_xtensa);
236     exe_options.addOption(bool, "force_gpa", force_gpa);
237     exe_options.addOption(DevEnv, "dev", b.option(DevEnv, "dev", "Build a compiler with a reduced feature set for development of specific features") orelse if (only_c) .bootstrap else .full);
238     exe_options.addOption(ValueInterpretMode, "value_interpret_mode", value_interpret_mode);
240     if (link_libc) {
241         exe.root_module.link_libc = true;
242     }
244     const is_debug = optimize == .Debug;
245     const enable_debug_extensions = b.option(bool, "debug-extensions", "Enable commands and options useful for debugging the compiler") orelse is_debug;
246     const enable_logging = b.option(bool, "log", "Enable debug logging with --debug-log") orelse is_debug;
247     const enable_link_snapshots = b.option(bool, "link-snapshot", "Whether to enable linker state snapshots") orelse false;
249     const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git.");
250     const version_slice = if (opt_version_string) |version| version else v: {
251         if (!std.process.can_spawn) {
252             std.debug.print("error: version info cannot be retrieved from git. Zig version must be provided using -Dversion-string\n", .{});
253             std.process.exit(1);
254         }
255         const version_string = b.fmt("{d}.{d}.{d}", .{ zig_version.major, zig_version.minor, zig_version.patch });
257         var code: u8 = undefined;
258         const git_describe_untrimmed = b.runAllowFail(&[_][]const u8{
259             "git",
260             "-C",
261             b.build_root.path orelse ".",
262             "describe",
263             "--match",
264             "*.*.*",
265             "--tags",
266             "--abbrev=9",
267         }, &code, .Ignore) catch {
268             break :v version_string;
269         };
270         const git_describe = mem.trim(u8, git_describe_untrimmed, " \n\r");
272         switch (mem.count(u8, git_describe, "-")) {
273             0 => {
274                 // Tagged release version (e.g. 0.10.0).
275                 if (!mem.eql(u8, git_describe, version_string)) {
276                     std.debug.print("Zig version '{s}' does not match Git tag '{s}'\n", .{ version_string, git_describe });
277                     std.process.exit(1);
278                 }
279                 break :v version_string;
280             },
281             2 => {
282                 // Untagged development build (e.g. 0.10.0-dev.2025+ecf0050a9).
283                 var it = mem.splitScalar(u8, git_describe, '-');
284                 const tagged_ancestor = it.first();
285                 const commit_height = it.next().?;
286                 const commit_id = it.next().?;
288                 const ancestor_ver = try std.SemanticVersion.parse(tagged_ancestor);
289                 if (zig_version.order(ancestor_ver) != .gt) {
290                     std.debug.print("Zig version '{}' must be greater than tagged ancestor '{}'\n", .{ zig_version, ancestor_ver });
291                     std.process.exit(1);
292                 }
294                 // Check that the commit hash is prefixed with a 'g' (a Git convention).
295                 if (commit_id.len < 1 or commit_id[0] != 'g') {
296                     std.debug.print("Unexpected `git describe` output: {s}\n", .{git_describe});
297                     break :v version_string;
298                 }
300                 // The version is reformatted in accordance with the https://semver.org specification.
301                 break :v b.fmt("{s}-dev.{s}+{s}", .{ version_string, commit_height, commit_id[1..] });
302             },
303             else => {
304                 std.debug.print("Unexpected `git describe` output: {s}\n", .{git_describe});
305                 break :v version_string;
306             },
307         }
308     };
309     const version = try b.allocator.dupeZ(u8, version_slice);
310     exe_options.addOption([:0]const u8, "version", version);
312     if (enable_llvm) {
313         const cmake_cfg = if (static_llvm) null else blk: {
314             if (findConfigH(b, config_h_path_option)) |config_h_path| {
315                 const file_contents = fs.cwd().readFileAlloc(b.allocator, config_h_path, max_config_h_bytes) catch unreachable;
316                 break :blk parseConfigH(b, file_contents);
317             } else {
318                 std.log.warn("config.h could not be located automatically. Consider providing it explicitly via \"-Dconfig_h\"", .{});
319                 break :blk null;
320             }
321         };
323         if (cmake_cfg) |cfg| {
324             // Inside this code path, we have to coordinate with system packaged LLVM, Clang, and LLD.
325             // That means we also have to rely on stage1 compiled c++ files. We parse config.h to find
326             // the information passed on to us from cmake.
327             if (cfg.cmake_prefix_path.len > 0) {
328                 var it = mem.tokenizeScalar(u8, cfg.cmake_prefix_path, ';');
329                 while (it.next()) |path| {
330                     b.addSearchPrefix(path);
331                 }
332             }
334             try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx);
335         } else {
336             // Here we are -Denable-llvm but no cmake integration.
337             try addStaticLlvmOptionsToModule(exe.root_module);
338         }
339         if (target.result.os.tag == .windows) {
340             // LLVM depends on networking as of version 18.
341             exe.root_module.linkSystemLibrary("ws2_32", .{});
343             exe.root_module.linkSystemLibrary("version", .{});
344             exe.root_module.linkSystemLibrary("uuid", .{});
345             exe.root_module.linkSystemLibrary("ole32", .{});
346         }
347     }
349     const semver = try std.SemanticVersion.parse(version);
350     exe_options.addOption(std.SemanticVersion, "semver", semver);
352     exe_options.addOption(bool, "enable_debug_extensions", enable_debug_extensions);
353     exe_options.addOption(bool, "enable_logging", enable_logging);
354     exe_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
355     exe_options.addOption(bool, "enable_tracy", tracy != null);
356     exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);
357     exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);
358     exe_options.addOption(u32, "tracy_callstack_depth", tracy_callstack_depth);
359     exe_options.addOption(bool, "value_tracing", value_tracing);
360     if (tracy) |tracy_path| {
361         const client_cpp = b.pathJoin(
362             &[_][]const u8{ tracy_path, "public", "TracyClient.cpp" },
363         );
365         // On mingw, we need to opt into windows 7+ to get some features required by tracy.
366         const tracy_c_flags: []const []const u8 = if (target.result.os.tag == .windows and target.result.abi == .gnu)
367             &[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined", "-D_WIN32_WINNT=0x601" }
368         else
369             &[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" };
371         exe.root_module.addIncludePath(.{ .cwd_relative = tracy_path });
372         exe.root_module.addCSourceFile(.{ .file = .{ .cwd_relative = client_cpp }, .flags = tracy_c_flags });
373         if (!enable_llvm) {
374             exe.root_module.linkSystemLibrary("c++", .{ .use_pkg_config = .no });
375         }
376         exe.root_module.link_libc = true;
378         if (target.result.os.tag == .windows) {
379             exe.root_module.linkSystemLibrary("dbghelp", .{});
380             exe.root_module.linkSystemLibrary("ws2_32", .{});
381         }
382     }
384     const test_filters = b.option([]const []const u8, "test-filter", "Skip tests that do not match any filter") orelse &[0][]const u8{};
385     const test_target_filters = b.option([]const []const u8, "test-target-filter", "Skip tests whose target triple do not match any filter") orelse &[0][]const u8{};
386     const test_slow_targets = b.option(bool, "test-slow-targets", "Enable running module tests for targets that have a slow compiler backend") orelse false;
388     var chosen_opt_modes_buf: [4]builtin.OptimizeMode = undefined;
389     var chosen_mode_index: usize = 0;
390     if (!skip_debug) {
391         chosen_opt_modes_buf[chosen_mode_index] = builtin.OptimizeMode.Debug;
392         chosen_mode_index += 1;
393     }
394     if (!skip_release_safe) {
395         chosen_opt_modes_buf[chosen_mode_index] = builtin.OptimizeMode.ReleaseSafe;
396         chosen_mode_index += 1;
397     }
398     if (!skip_release_fast) {
399         chosen_opt_modes_buf[chosen_mode_index] = builtin.OptimizeMode.ReleaseFast;
400         chosen_mode_index += 1;
401     }
402     if (!skip_release_small) {
403         chosen_opt_modes_buf[chosen_mode_index] = builtin.OptimizeMode.ReleaseSmall;
404         chosen_mode_index += 1;
405     }
406     const optimization_modes = chosen_opt_modes_buf[0..chosen_mode_index];
408     const fmt_include_paths = &.{ "lib", "src", "test", "tools", "build.zig", "build.zig.zon" };
409     const fmt_exclude_paths = &.{"test/cases"};
410     const do_fmt = b.addFmt(.{
411         .paths = fmt_include_paths,
412         .exclude_paths = fmt_exclude_paths,
413     });
414     b.step("fmt", "Modify source files in place to have conforming formatting").dependOn(&do_fmt.step);
416     const check_fmt = b.step("test-fmt", "Check source files having conforming formatting");
417     check_fmt.dependOn(&b.addFmt(.{
418         .paths = fmt_include_paths,
419         .exclude_paths = fmt_exclude_paths,
420         .check = true,
421     }).step);
422     test_step.dependOn(check_fmt);
424     const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
425     try tests.addCases(b, test_cases_step, test_filters, test_target_filters, target, .{
426         .skip_translate_c = skip_translate_c,
427         .skip_run_translated_c = skip_run_translated_c,
428     }, .{
429         .enable_llvm = enable_llvm,
430         .llvm_has_m68k = llvm_has_m68k,
431         .llvm_has_csky = llvm_has_csky,
432         .llvm_has_arc = llvm_has_arc,
433         .llvm_has_xtensa = llvm_has_xtensa,
434     });
435     test_step.dependOn(test_cases_step);
437     const test_modules_step = b.step("test-modules", "Run the per-target module tests");
438     test_step.dependOn(test_modules_step);
440     test_modules_step.dependOn(tests.addModuleTests(b, .{
441         .test_filters = test_filters,
442         .test_target_filters = test_target_filters,
443         .test_slow_targets = test_slow_targets,
444         .root_src = "test/behavior.zig",
445         .name = "behavior",
446         .desc = "Run the behavior tests",
447         .optimize_modes = optimization_modes,
448         .include_paths = &.{},
449         .skip_single_threaded = skip_single_threaded,
450         .skip_non_native = skip_non_native,
451         .skip_libc = skip_libc,
452         .use_llvm = use_llvm,
453         .max_rss = 1 * 1024 * 1024 * 1024,
454     }));
456     test_modules_step.dependOn(tests.addModuleTests(b, .{
457         .test_filters = test_filters,
458         .test_target_filters = test_target_filters,
459         .test_slow_targets = test_slow_targets,
460         .root_src = "test/c_import.zig",
461         .name = "c-import",
462         .desc = "Run the @cImport tests",
463         .optimize_modes = optimization_modes,
464         .include_paths = &.{"test/c_import"},
465         .skip_single_threaded = true,
466         .skip_non_native = skip_non_native,
467         .skip_libc = skip_libc,
468         .use_llvm = use_llvm,
469     }));
471     test_modules_step.dependOn(tests.addModuleTests(b, .{
472         .test_filters = test_filters,
473         .test_target_filters = test_target_filters,
474         .test_slow_targets = test_slow_targets,
475         .root_src = "lib/compiler_rt.zig",
476         .name = "compiler-rt",
477         .desc = "Run the compiler_rt tests",
478         .optimize_modes = optimization_modes,
479         .include_paths = &.{},
480         .skip_single_threaded = true,
481         .skip_non_native = skip_non_native,
482         .skip_libc = true,
483         .use_llvm = use_llvm,
484         .no_builtin = true,
485     }));
487     test_modules_step.dependOn(tests.addModuleTests(b, .{
488         .test_filters = test_filters,
489         .test_target_filters = test_target_filters,
490         .test_slow_targets = test_slow_targets,
491         .root_src = "lib/c.zig",
492         .name = "universal-libc",
493         .desc = "Run the universal libc tests",
494         .optimize_modes = optimization_modes,
495         .include_paths = &.{},
496         .skip_single_threaded = true,
497         .skip_non_native = skip_non_native,
498         .skip_libc = true,
499         .use_llvm = use_llvm,
500         .no_builtin = true,
501     }));
503     test_modules_step.dependOn(tests.addModuleTests(b, .{
504         .test_filters = test_filters,
505         .test_target_filters = test_target_filters,
506         .test_slow_targets = test_slow_targets,
507         .root_src = "lib/std/std.zig",
508         .name = "std",
509         .desc = "Run the standard library tests",
510         .optimize_modes = optimization_modes,
511         .include_paths = &.{},
512         .skip_single_threaded = skip_single_threaded,
513         .skip_non_native = skip_non_native,
514         .skip_libc = skip_libc,
515         .use_llvm = use_llvm,
516         // I observed a value of 4572626944 on the M2 CI.
517         .max_rss = 5029889638,
518     }));
520     const unit_tests_step = b.step("test-unit", "Run the compiler source unit tests");
521     test_step.dependOn(unit_tests_step);
523     const unit_tests = b.addTest(.{
524         .root_module = b.createModule(.{
525             .root_source_file = b.path("src/main.zig"),
526             .optimize = optimize,
527             .target = target,
528             .link_libc = link_libc,
529             .single_threaded = single_threaded,
530         }),
531         .filters = test_filters,
532         .use_llvm = use_llvm,
533         .use_lld = use_llvm,
534         .zig_lib_dir = b.path("lib"),
535     });
536     unit_tests.root_module.addOptions("build_options", exe_options);
537     unit_tests_step.dependOn(&b.addRunArtifact(unit_tests).step);
539     test_step.dependOn(tests.addCompareOutputTests(b, test_filters, optimization_modes));
540     test_step.dependOn(tests.addStandaloneTests(
541         b,
542         optimization_modes,
543         enable_macos_sdk,
544         enable_ios_sdk,
545         enable_symlinks_windows,
546     ));
547     test_step.dependOn(tests.addCAbiTests(b, .{
548         .test_target_filters = test_target_filters,
549         .skip_non_native = skip_non_native,
550         .skip_release = skip_release,
551     }));
552     test_step.dependOn(tests.addLinkTests(b, enable_macos_sdk, enable_ios_sdk, enable_symlinks_windows));
553     test_step.dependOn(tests.addStackTraceTests(b, test_filters, optimization_modes));
554     test_step.dependOn(tests.addCliTests(b));
555     test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filters, optimization_modes));
556     if (tests.addDebuggerTests(b, .{
557         .test_filters = test_filters,
558         .test_target_filters = test_target_filters,
559         .gdb = b.option([]const u8, "gdb", "path to gdb binary"),
560         .lldb = b.option([]const u8, "lldb", "path to lldb binary"),
561         .optimize_modes = optimization_modes,
562         .skip_single_threaded = skip_single_threaded,
563         .skip_non_native = skip_non_native,
564         .skip_libc = skip_libc,
565     })) |test_debugger_step| test_step.dependOn(test_debugger_step);
567     try addWasiUpdateStep(b, version);
569     const update_mingw_step = b.step("update-mingw", "Update zig's bundled mingw");
570     const opt_mingw_src_path = b.option([]const u8, "mingw-src", "path to mingw-w64 source directory");
571     if (opt_mingw_src_path) |mingw_src_path| {
572         const update_mingw_exe = b.addExecutable(.{
573             .name = "update_mingw",
574             .root_module = b.createModule(.{
575                 .target = b.graph.host,
576                 .root_source_file = b.path("tools/update_mingw.zig"),
577             }),
578         });
579         const update_mingw_run = b.addRunArtifact(update_mingw_exe);
580         update_mingw_run.addDirectoryArg(b.path("lib"));
581         update_mingw_run.addDirectoryArg(.{ .cwd_relative = mingw_src_path });
583         update_mingw_step.dependOn(&update_mingw_run.step);
584     } else {
585         update_mingw_step.dependOn(&b.addFail("The -Dmingw-src=... option is required for this step").step);
586     }
588     const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases");
589     try tests.addIncrementalTests(b, test_incremental_step);
590     test_step.dependOn(test_incremental_step);
593 fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
594     const semver = try std.SemanticVersion.parse(version);
596     const exe = addCompilerStep(b, .{
597         .optimize = .ReleaseSmall,
598         .target = b.resolveTargetQuery(std.Target.Query.parse(.{
599             .arch_os_abi = "wasm32-wasi",
600             // * `extended_const` is not supported by the `wasm-opt` version in CI.
601             // * `nontrapping_bulk_memory_len0` is supported by `wasm2c`.
602             .cpu_features = "baseline-extended_const+nontrapping_bulk_memory_len0",
603         }) catch unreachable),
604     });
606     const exe_options = b.addOptions();
607     exe.root_module.addOptions("build_options", exe_options);
609     exe_options.addOption(u32, "mem_leak_frames", 0);
610     exe_options.addOption(bool, "have_llvm", false);
611     exe_options.addOption(bool, "force_gpa", false);
612     exe_options.addOption([:0]const u8, "version", version);
613     exe_options.addOption(std.SemanticVersion, "semver", semver);
614     exe_options.addOption(bool, "enable_debug_extensions", false);
615     exe_options.addOption(bool, "enable_logging", false);
616     exe_options.addOption(bool, "enable_link_snapshots", false);
617     exe_options.addOption(bool, "enable_tracy", false);
618     exe_options.addOption(bool, "enable_tracy_callstack", false);
619     exe_options.addOption(bool, "enable_tracy_allocation", false);
620     exe_options.addOption(u32, "tracy_callstack_depth", 0);
621     exe_options.addOption(bool, "value_tracing", false);
622     exe_options.addOption(DevEnv, "dev", .bootstrap);
624     // zig1 chooses to interpret values by name. The tradeoff is as follows:
625     //
626     // * We lose a small amount of performance. This is essentially irrelevant for zig1.
627     //
628     // * We lose the ability to perform trivial renames on certain `std.builtin` types without
629     //   zig1.wasm updates. For instance, we cannot rename an enum from PascalCase fields to
630     //   snake_case fields without an update.
631     //
632     // * We gain the ability to add and remove fields to and from `std.builtin` types without
633     //   zig1.wasm updates. For instance, we can add a new tag to `CallingConvention` without
634     //   an update.
635     //
636     // Because field renames only happen when we apply a breaking change to the language (which
637     // is becoming progressively rarer), but tags may be added to or removed from target-dependent
638     // types over time in response to new targets coming into use, we gain more than we lose here.
639     exe_options.addOption(ValueInterpretMode, "value_interpret_mode", .by_name);
641     const run_opt = b.addSystemCommand(&.{
642         "wasm-opt",
643         "-Oz",
644         "--enable-bulk-memory",
645         "--enable-mutable-globals",
646         "--enable-nontrapping-float-to-int",
647         "--enable-sign-ext",
648     });
649     run_opt.addArtifactArg(exe);
650     run_opt.addArg("-o");
651     run_opt.addFileArg(b.path("stage1/zig1.wasm"));
653     const copy_zig_h = b.addUpdateSourceFiles();
654     copy_zig_h.addCopyFileToSource(b.path("lib/zig.h"), "stage1/zig.h");
656     const update_zig1_step = b.step("update-zig1", "Update stage1/zig1.wasm");
657     update_zig1_step.dependOn(&run_opt.step);
658     update_zig1_step.dependOn(&copy_zig_h.step);
661 const AddCompilerStepOptions = struct {
662     optimize: std.builtin.OptimizeMode,
663     target: std.Build.ResolvedTarget,
664     strip: ?bool = null,
665     valgrind: ?bool = null,
666     sanitize_thread: ?bool = null,
667     single_threaded: ?bool = null,
670 fn addCompilerStep(b: *std.Build, options: AddCompilerStepOptions) *std.Build.Step.Compile {
671     const compiler_mod = b.createModule(.{
672         .root_source_file = b.path("src/main.zig"),
673         .target = options.target,
674         .optimize = options.optimize,
675         .strip = options.strip,
676         .sanitize_thread = options.sanitize_thread,
677         .single_threaded = options.single_threaded,
678         .code_model = switch (options.target.result.cpu.arch) {
679             // NB:
680             // For loongarch, LLVM supports only small, medium and large
681             // code model. If we don't explicitly specify the code model,
682             // the default value `small' will be used.
683             //
684             // Since zig binary itself is relatively large, using a `small'
685             // code model will cause
686             //
687             // relocation R_LARCH_B26 out of range
688             //
689             // error when linking a loongarch32/loongarch64 zig binary.
690             //
691             // Here we explicitly set code model to `medium' to avoid this
692             // error.
693             .loongarch32, .loongarch64 => .medium,
694             else => .default,
695         },
696         .valgrind = options.valgrind,
697     });
699     const aro_mod = b.createModule(.{
700         .root_source_file = b.path("lib/compiler/aro/aro.zig"),
701     });
703     const aro_translate_c_mod = b.createModule(.{
704         .root_source_file = b.path("lib/compiler/aro_translate_c.zig"),
705     });
707     aro_translate_c_mod.addImport("aro", aro_mod);
708     compiler_mod.addImport("aro", aro_mod);
709     compiler_mod.addImport("aro_translate_c", aro_translate_c_mod);
711     const exe = b.addExecutable(.{
712         .name = "zig",
713         .max_rss = 7_800_000_000,
714         .root_module = compiler_mod,
715     });
716     exe.stack_size = stack_size;
718     return exe;
721 const exe_cflags = [_][]const u8{
722     "-std=c++17",
723     "-D__STDC_CONSTANT_MACROS",
724     "-D__STDC_FORMAT_MACROS",
725     "-D__STDC_LIMIT_MACROS",
726     "-D_GNU_SOURCE",
727     "-fno-exceptions",
728     "-fno-rtti",
729     "-fno-stack-protector",
730     "-fvisibility-inlines-hidden",
731     "-Wno-type-limits",
732     "-Wno-missing-braces",
733     "-Wno-comment",
736 fn addCmakeCfgOptionsToExe(
737     b: *std.Build,
738     cfg: CMakeConfig,
739     exe: *std.Build.Step.Compile,
740     use_zig_libcxx: bool,
741 ) !void {
742     const mod = exe.root_module;
743     const target = mod.resolved_target.?.result;
745     if (target.isDarwin()) {
746         // useful for package maintainers
747         exe.headerpad_max_install_names = true;
748     }
750     mod.addObjectFile(.{ .cwd_relative = b.pathJoin(&.{
751         cfg.cmake_binary_dir,
752         "zigcpp",
753         b.fmt("{s}{s}{s}", .{
754             cfg.cmake_static_library_prefix,
755             "zigcpp",
756             cfg.cmake_static_library_suffix,
757         }),
758     }) });
759     assert(cfg.lld_include_dir.len != 0);
760     mod.addIncludePath(.{ .cwd_relative = cfg.lld_include_dir });
761     mod.addIncludePath(.{ .cwd_relative = cfg.llvm_include_dir });
762     mod.addLibraryPath(.{ .cwd_relative = cfg.llvm_lib_dir });
763     addCMakeLibraryList(mod, cfg.clang_libraries);
764     addCMakeLibraryList(mod, cfg.lld_libraries);
765     addCMakeLibraryList(mod, cfg.llvm_libraries);
767     if (use_zig_libcxx) {
768         mod.link_libcpp = true;
769     } else {
770         // System -lc++ must be used because in this code path we are attempting to link
771         // against system-provided LLVM, Clang, LLD.
772         const need_cpp_includes = true;
773         const static = cfg.llvm_linkage == .static;
774         const lib_suffix = if (static) target.staticLibSuffix()[1..] else target.dynamicLibSuffix()[1..];
775         switch (target.os.tag) {
776             .linux => {
777                 // First we try to link against the detected libcxx name. If that doesn't work, we fall
778                 // back to -lc++ and cross our fingers.
779                 addCxxKnownPath(b, cfg, exe, b.fmt("lib{s}.{s}", .{ cfg.system_libcxx, lib_suffix }), "", need_cpp_includes) catch |err| switch (err) {
780                     error.RequiredLibraryNotFound => {
781                         mod.link_libcpp = true;
782                     },
783                     else => |e| return e,
784                 };
785                 mod.linkSystemLibrary("unwind", .{});
786             },
787             .ios, .macos, .watchos, .tvos, .visionos => {
788                 mod.link_libcpp = true;
789             },
790             .windows => {
791                 if (target.abi != .msvc) mod.link_libcpp = true;
792             },
793             .freebsd => {
794                 if (static) {
795                     try addCxxKnownPath(b, cfg, exe, b.fmt("libc++.{s}", .{lib_suffix}), null, need_cpp_includes);
796                     try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes);
797                 } else {
798                     try addCxxKnownPath(b, cfg, exe, b.fmt("libc++.{s}", .{lib_suffix}), null, need_cpp_includes);
799                 }
800             },
801             .openbsd => {
802                 try addCxxKnownPath(b, cfg, exe, b.fmt("libc++.{s}", .{lib_suffix}), null, need_cpp_includes);
803                 try addCxxKnownPath(b, cfg, exe, b.fmt("libc++abi.{s}", .{lib_suffix}), null, need_cpp_includes);
804             },
805             .netbsd, .dragonfly => {
806                 if (static) {
807                     try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes);
808                     try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes);
809                 } else {
810                     try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes);
811                 }
812             },
813             .solaris, .illumos => {
814                 try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes);
815                 try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes);
816             },
817             .haiku => {
818                 try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes);
819             },
820             else => {},
821         }
822     }
824     if (cfg.dia_guids_lib.len != 0) {
825         mod.addObjectFile(.{ .cwd_relative = cfg.dia_guids_lib });
826     }
829 fn addStaticLlvmOptionsToModule(mod: *std.Build.Module) !void {
830     // Adds the Zig C++ sources which both stage1 and stage2 need.
831     //
832     // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling
833     // in a dependency on llvm::cfg::Update<llvm::BasicBlock*>::dump() which is
834     // unavailable when LLVM is compiled in Release mode.
835     const zig_cpp_cflags = exe_cflags ++ [_][]const u8{"-DNDEBUG=1"};
836     mod.addCSourceFiles(.{
837         .files = &zig_cpp_sources,
838         .flags = &zig_cpp_cflags,
839     });
841     for (clang_libs) |lib_name| {
842         mod.linkSystemLibrary(lib_name, .{});
843     }
845     for (lld_libs) |lib_name| {
846         mod.linkSystemLibrary(lib_name, .{});
847     }
849     for (llvm_libs) |lib_name| {
850         mod.linkSystemLibrary(lib_name, .{});
851     }
853     mod.linkSystemLibrary("z", .{});
854     mod.linkSystemLibrary("zstd", .{});
856     if (mod.resolved_target.?.result.os.tag != .windows or mod.resolved_target.?.result.abi != .msvc) {
857         // This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries.
858         mod.linkSystemLibrary("c++", .{});
859     }
861     if (mod.resolved_target.?.result.os.tag == .windows) {
862         mod.linkSystemLibrary("version", .{});
863         mod.linkSystemLibrary("uuid", .{});
864         mod.linkSystemLibrary("ole32", .{});
865     }
868 fn addCxxKnownPath(
869     b: *std.Build,
870     ctx: CMakeConfig,
871     exe: *std.Build.Step.Compile,
872     objname: []const u8,
873     errtxt: ?[]const u8,
874     need_cpp_includes: bool,
875 ) !void {
876     if (!std.process.can_spawn)
877         return error.RequiredLibraryNotFound;
879     const path_padded = run: {
880         var args = std.ArrayList([]const u8).init(b.allocator);
881         try args.append(ctx.cxx_compiler);
882         var it = std.mem.tokenizeAny(u8, ctx.cxx_compiler_arg1, &std.ascii.whitespace);
883         while (it.next()) |arg| try args.append(arg);
884         try args.append(b.fmt("-print-file-name={s}", .{objname}));
885         break :run b.run(args.items);
886     };
887     var tokenizer = mem.tokenizeAny(u8, path_padded, "\r\n");
888     const path_unpadded = tokenizer.next().?;
889     if (mem.eql(u8, path_unpadded, objname)) {
890         if (errtxt) |msg| {
891             std.debug.print("{s}", .{msg});
892         } else {
893             std.debug.print("Unable to determine path to {s}\n", .{objname});
894         }
895         return error.RequiredLibraryNotFound;
896     }
897     // By default, explicit library paths are not checked for being linker scripts,
898     // but libc++ may very well be one, so force all inputs to be checked when passing
899     // an explicit path to libc++.
900     exe.allow_so_scripts = true;
901     exe.root_module.addObjectFile(.{ .cwd_relative = path_unpadded });
903     // TODO a way to integrate with system c++ include files here
904     // c++ -E -Wp,-v -xc++ /dev/null
905     if (need_cpp_includes) {
906         // I used these temporarily for testing something but we obviously need a
907         // more general purpose solution here.
908         //exe.root_module.addIncludePath("/nix/store/2lr0fc0ak8rwj0k8n3shcyz1hz63wzma-gcc-11.3.0/include/c++/11.3.0");
909         //exe.root_module.addIncludePath("/nix/store/2lr0fc0ak8rwj0k8n3shcyz1hz63wzma-gcc-11.3.0/include/c++/11.3.0/x86_64-unknown-linux-gnu");
910     }
913 fn addCMakeLibraryList(mod: *std.Build.Module, list: []const u8) void {
914     var it = mem.tokenizeScalar(u8, list, ';');
915     while (it.next()) |lib| {
916         if (mem.startsWith(u8, lib, "-l")) {
917             mod.linkSystemLibrary(lib["-l".len..], .{});
918         } else if (mod.resolved_target.?.result.os.tag == .windows and
919             mem.endsWith(u8, lib, ".lib") and !fs.path.isAbsolute(lib))
920         {
921             mod.linkSystemLibrary(lib[0 .. lib.len - ".lib".len], .{});
922         } else {
923             mod.addObjectFile(.{ .cwd_relative = lib });
924         }
925     }
928 const CMakeConfig = struct {
929     llvm_linkage: std.builtin.LinkMode,
930     cmake_binary_dir: []const u8,
931     cmake_prefix_path: []const u8,
932     cmake_static_library_prefix: []const u8,
933     cmake_static_library_suffix: []const u8,
934     cxx_compiler: []const u8,
935     cxx_compiler_arg1: []const u8,
936     lld_include_dir: []const u8,
937     lld_libraries: []const u8,
938     clang_libraries: []const u8,
939     llvm_lib_dir: []const u8,
940     llvm_include_dir: []const u8,
941     llvm_libraries: []const u8,
942     dia_guids_lib: []const u8,
943     system_libcxx: []const u8,
946 const max_config_h_bytes = 1 * 1024 * 1024;
948 fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 {
949     if (config_h_path_option) |path| {
950         var config_h_or_err = fs.cwd().openFile(path, .{});
951         if (config_h_or_err) |*file| {
952             file.close();
953             return path;
954         } else |_| {
955             std.log.err("Could not open provided config.h: \"{s}\"", .{path});
956             std.process.exit(1);
957         }
958     }
960     var check_dir = fs.path.dirname(b.graph.zig_exe).?;
961     while (true) {
962         var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable;
963         defer dir.close();
965         // Check if config.h is present in dir
966         var config_h_or_err = dir.openFile("config.h", .{});
967         if (config_h_or_err) |*file| {
968             file.close();
969             return fs.path.join(
970                 b.allocator,
971                 &[_][]const u8{ check_dir, "config.h" },
972             ) catch unreachable;
973         } else |e| switch (e) {
974             error.FileNotFound => {},
975             else => unreachable,
976         }
978         // Check if we reached the source root by looking for .git, and bail if so
979         var git_dir_or_err = dir.openDir(".git", .{});
980         if (git_dir_or_err) |*git_dir| {
981             git_dir.close();
982             return null;
983         } else |_| {}
985         // Otherwise, continue search in the parent directory
986         const new_check_dir = fs.path.dirname(check_dir);
987         if (new_check_dir == null or mem.eql(u8, new_check_dir.?, check_dir)) {
988             return null;
989         }
990         check_dir = new_check_dir.?;
991     }
994 fn parseConfigH(b: *std.Build, config_h_text: []const u8) ?CMakeConfig {
995     var ctx: CMakeConfig = .{
996         .llvm_linkage = undefined,
997         .cmake_binary_dir = undefined,
998         .cmake_prefix_path = undefined,
999         .cmake_static_library_prefix = undefined,
1000         .cmake_static_library_suffix = undefined,
1001         .cxx_compiler = undefined,
1002         .cxx_compiler_arg1 = "",
1003         .lld_include_dir = undefined,
1004         .lld_libraries = undefined,
1005         .clang_libraries = undefined,
1006         .llvm_lib_dir = undefined,
1007         .llvm_include_dir = undefined,
1008         .llvm_libraries = undefined,
1009         .dia_guids_lib = undefined,
1010         .system_libcxx = undefined,
1011     };
1013     const mappings = [_]struct { prefix: []const u8, field: []const u8 }{
1014         .{
1015             .prefix = "#define ZIG_CMAKE_BINARY_DIR ",
1016             .field = "cmake_binary_dir",
1017         },
1018         .{
1019             .prefix = "#define ZIG_CMAKE_PREFIX_PATH ",
1020             .field = "cmake_prefix_path",
1021         },
1022         .{
1023             .prefix = "#define ZIG_CMAKE_STATIC_LIBRARY_PREFIX ",
1024             .field = "cmake_static_library_prefix",
1025         },
1026         .{
1027             .prefix = "#define ZIG_CMAKE_STATIC_LIBRARY_SUFFIX ",
1028             .field = "cmake_static_library_suffix",
1029         },
1030         .{
1031             .prefix = "#define ZIG_CXX_COMPILER ",
1032             .field = "cxx_compiler",
1033         },
1034         .{
1035             .prefix = "#define ZIG_CXX_COMPILER_ARG1 ",
1036             .field = "cxx_compiler_arg1",
1037         },
1038         .{
1039             .prefix = "#define ZIG_LLD_INCLUDE_PATH ",
1040             .field = "lld_include_dir",
1041         },
1042         .{
1043             .prefix = "#define ZIG_LLD_LIBRARIES ",
1044             .field = "lld_libraries",
1045         },
1046         .{
1047             .prefix = "#define ZIG_CLANG_LIBRARIES ",
1048             .field = "clang_libraries",
1049         },
1050         .{
1051             .prefix = "#define ZIG_LLVM_LIBRARIES ",
1052             .field = "llvm_libraries",
1053         },
1054         .{
1055             .prefix = "#define ZIG_DIA_GUIDS_LIB ",
1056             .field = "dia_guids_lib",
1057         },
1058         .{
1059             .prefix = "#define ZIG_LLVM_INCLUDE_PATH ",
1060             .field = "llvm_include_dir",
1061         },
1062         .{
1063             .prefix = "#define ZIG_LLVM_LIB_PATH ",
1064             .field = "llvm_lib_dir",
1065         },
1066         .{
1067             .prefix = "#define ZIG_SYSTEM_LIBCXX",
1068             .field = "system_libcxx",
1069         },
1070         // .prefix = ZIG_LLVM_LINK_MODE parsed manually below
1071     };
1073     var lines_it = mem.tokenizeAny(u8, config_h_text, "\r\n");
1074     while (lines_it.next()) |line| {
1075         inline for (mappings) |mapping| {
1076             if (mem.startsWith(u8, line, mapping.prefix)) {
1077                 var it = mem.splitScalar(u8, line, '"');
1078                 _ = it.first(); // skip the stuff before the quote
1079                 const quoted = it.next().?; // the stuff inside the quote
1080                 const trimmed = mem.trim(u8, quoted, " ");
1081                 @field(ctx, mapping.field) = toNativePathSep(b, trimmed);
1082             }
1083         }
1084         if (mem.startsWith(u8, line, "#define ZIG_LLVM_LINK_MODE ")) {
1085             var it = mem.splitScalar(u8, line, '"');
1086             _ = it.next().?; // skip the stuff before the quote
1087             const quoted = it.next().?; // the stuff inside the quote
1088             ctx.llvm_linkage = if (mem.eql(u8, quoted, "shared")) .dynamic else .static;
1089         }
1090     }
1091     return ctx;
1094 fn toNativePathSep(b: *std.Build, s: []const u8) []u8 {
1095     const duplicated = b.allocator.dupe(u8, s) catch unreachable;
1096     for (duplicated) |*byte| switch (byte.*) {
1097         '/' => byte.* = fs.path.sep,
1098         else => {},
1099     };
1100     return duplicated;
1103 const zig_cpp_sources = [_][]const u8{
1104     // These are planned to stay even when we are self-hosted.
1105     "src/zig_llvm.cpp",
1106     "src/zig_clang.cpp",
1107     "src/zig_llvm-ar.cpp",
1108     "src/zig_clang_driver.cpp",
1109     "src/zig_clang_cc1_main.cpp",
1110     "src/zig_clang_cc1as_main.cpp",
1113 const clang_libs = [_][]const u8{
1114     "clangFrontendTool",
1115     "clangCodeGen",
1116     "clangFrontend",
1117     "clangDriver",
1118     "clangSerialization",
1119     "clangSema",
1120     "clangStaticAnalyzerFrontend",
1121     "clangStaticAnalyzerCheckers",
1122     "clangStaticAnalyzerCore",
1123     "clangAnalysis",
1124     "clangASTMatchers",
1125     "clangAST",
1126     "clangParse",
1127     "clangSema",
1128     "clangAPINotes",
1129     "clangBasic",
1130     "clangEdit",
1131     "clangLex",
1132     "clangARCMigrate",
1133     "clangRewriteFrontend",
1134     "clangRewrite",
1135     "clangCrossTU",
1136     "clangIndex",
1137     "clangToolingCore",
1138     "clangExtractAPI",
1139     "clangSupport",
1140     "clangInstallAPI",
1141     "clangAST",
1143 const lld_libs = [_][]const u8{
1144     "lldMinGW",
1145     "lldELF",
1146     "lldCOFF",
1147     "lldWasm",
1148     "lldMachO",
1149     "lldCommon",
1151 // This list can be re-generated with `llvm-config --libfiles` and then
1152 // reformatting using your favorite text editor. Note we do not execute
1153 // `llvm-config` here because we are cross compiling. Also omit LLVMTableGen
1154 // from these libs.
1155 const llvm_libs = [_][]const u8{
1156     "LLVMWindowsManifest",
1157     "LLVMXRay",
1158     "LLVMLibDriver",
1159     "LLVMDlltoolDriver",
1160     "LLVMTextAPIBinaryReader",
1161     "LLVMCoverage",
1162     "LLVMLineEditor",
1163     "LLVMSandboxIR",
1164     "LLVMXCoreDisassembler",
1165     "LLVMXCoreCodeGen",
1166     "LLVMXCoreDesc",
1167     "LLVMXCoreInfo",
1168     "LLVMX86TargetMCA",
1169     "LLVMX86Disassembler",
1170     "LLVMX86AsmParser",
1171     "LLVMX86CodeGen",
1172     "LLVMX86Desc",
1173     "LLVMX86Info",
1174     "LLVMWebAssemblyDisassembler",
1175     "LLVMWebAssemblyAsmParser",
1176     "LLVMWebAssemblyCodeGen",
1177     "LLVMWebAssemblyUtils",
1178     "LLVMWebAssemblyDesc",
1179     "LLVMWebAssemblyInfo",
1180     "LLVMVEDisassembler",
1181     "LLVMVEAsmParser",
1182     "LLVMVECodeGen",
1183     "LLVMVEDesc",
1184     "LLVMVEInfo",
1185     "LLVMSystemZDisassembler",
1186     "LLVMSystemZAsmParser",
1187     "LLVMSystemZCodeGen",
1188     "LLVMSystemZDesc",
1189     "LLVMSystemZInfo",
1190     "LLVMSparcDisassembler",
1191     "LLVMSparcAsmParser",
1192     "LLVMSparcCodeGen",
1193     "LLVMSparcDesc",
1194     "LLVMSparcInfo",
1195     "LLVMRISCVTargetMCA",
1196     "LLVMRISCVDisassembler",
1197     "LLVMRISCVAsmParser",
1198     "LLVMRISCVCodeGen",
1199     "LLVMRISCVDesc",
1200     "LLVMRISCVInfo",
1201     "LLVMPowerPCDisassembler",
1202     "LLVMPowerPCAsmParser",
1203     "LLVMPowerPCCodeGen",
1204     "LLVMPowerPCDesc",
1205     "LLVMPowerPCInfo",
1206     "LLVMNVPTXCodeGen",
1207     "LLVMNVPTXDesc",
1208     "LLVMNVPTXInfo",
1209     "LLVMMSP430Disassembler",
1210     "LLVMMSP430AsmParser",
1211     "LLVMMSP430CodeGen",
1212     "LLVMMSP430Desc",
1213     "LLVMMSP430Info",
1214     "LLVMMipsDisassembler",
1215     "LLVMMipsAsmParser",
1216     "LLVMMipsCodeGen",
1217     "LLVMMipsDesc",
1218     "LLVMMipsInfo",
1219     "LLVMLoongArchDisassembler",
1220     "LLVMLoongArchAsmParser",
1221     "LLVMLoongArchCodeGen",
1222     "LLVMLoongArchDesc",
1223     "LLVMLoongArchInfo",
1224     "LLVMLanaiDisassembler",
1225     "LLVMLanaiCodeGen",
1226     "LLVMLanaiAsmParser",
1227     "LLVMLanaiDesc",
1228     "LLVMLanaiInfo",
1229     "LLVMHexagonDisassembler",
1230     "LLVMHexagonCodeGen",
1231     "LLVMHexagonAsmParser",
1232     "LLVMHexagonDesc",
1233     "LLVMHexagonInfo",
1234     "LLVMBPFDisassembler",
1235     "LLVMBPFAsmParser",
1236     "LLVMBPFCodeGen",
1237     "LLVMBPFDesc",
1238     "LLVMBPFInfo",
1239     "LLVMAVRDisassembler",
1240     "LLVMAVRAsmParser",
1241     "LLVMAVRCodeGen",
1242     "LLVMAVRDesc",
1243     "LLVMAVRInfo",
1244     "LLVMARMDisassembler",
1245     "LLVMARMAsmParser",
1246     "LLVMARMCodeGen",
1247     "LLVMARMDesc",
1248     "LLVMARMUtils",
1249     "LLVMARMInfo",
1250     "LLVMAMDGPUTargetMCA",
1251     "LLVMAMDGPUDisassembler",
1252     "LLVMAMDGPUAsmParser",
1253     "LLVMAMDGPUCodeGen",
1254     "LLVMAMDGPUDesc",
1255     "LLVMAMDGPUUtils",
1256     "LLVMAMDGPUInfo",
1257     "LLVMAArch64Disassembler",
1258     "LLVMAArch64AsmParser",
1259     "LLVMAArch64CodeGen",
1260     "LLVMAArch64Desc",
1261     "LLVMAArch64Utils",
1262     "LLVMAArch64Info",
1263     "LLVMOrcDebugging",
1264     "LLVMOrcJIT",
1265     "LLVMWindowsDriver",
1266     "LLVMMCJIT",
1267     "LLVMJITLink",
1268     "LLVMInterpreter",
1269     "LLVMExecutionEngine",
1270     "LLVMRuntimeDyld",
1271     "LLVMOrcTargetProcess",
1272     "LLVMOrcShared",
1273     "LLVMDWP",
1274     "LLVMDebugInfoLogicalView",
1275     "LLVMDebugInfoGSYM",
1276     "LLVMOption",
1277     "LLVMObjectYAML",
1278     "LLVMObjCopy",
1279     "LLVMMCA",
1280     "LLVMMCDisassembler",
1281     "LLVMLTO",
1282     "LLVMPasses",
1283     "LLVMHipStdPar",
1284     "LLVMCFGuard",
1285     "LLVMCoroutines",
1286     "LLVMipo",
1287     "LLVMVectorize",
1288     "LLVMLinker",
1289     "LLVMInstrumentation",
1290     "LLVMFrontendOpenMP",
1291     "LLVMFrontendOffloading",
1292     "LLVMFrontendOpenACC",
1293     "LLVMFrontendHLSL",
1294     "LLVMFrontendDriver",
1295     "LLVMExtensions",
1296     "LLVMDWARFLinkerParallel",
1297     "LLVMDWARFLinkerClassic",
1298     "LLVMDWARFLinker",
1299     "LLVMCodeGenData",
1300     "LLVMGlobalISel",
1301     "LLVMMIRParser",
1302     "LLVMAsmPrinter",
1303     "LLVMSelectionDAG",
1304     "LLVMCodeGen",
1305     "LLVMTarget",
1306     "LLVMObjCARCOpts",
1307     "LLVMCodeGenTypes",
1308     "LLVMIRPrinter",
1309     "LLVMInterfaceStub",
1310     "LLVMFileCheck",
1311     "LLVMFuzzMutate",
1312     "LLVMScalarOpts",
1313     "LLVMInstCombine",
1314     "LLVMAggressiveInstCombine",
1315     "LLVMTransformUtils",
1316     "LLVMBitWriter",
1317     "LLVMAnalysis",
1318     "LLVMProfileData",
1319     "LLVMSymbolize",
1320     "LLVMDebugInfoBTF",
1321     "LLVMDebugInfoPDB",
1322     "LLVMDebugInfoMSF",
1323     "LLVMDebugInfoDWARF",
1324     "LLVMObject",
1325     "LLVMTextAPI",
1326     "LLVMMCParser",
1327     "LLVMIRReader",
1328     "LLVMAsmParser",
1329     "LLVMMC",
1330     "LLVMDebugInfoCodeView",
1331     "LLVMBitReader",
1332     "LLVMFuzzerCLI",
1333     "LLVMCore",
1334     "LLVMRemarks",
1335     "LLVMBitstreamReader",
1336     "LLVMBinaryFormat",
1337     "LLVMTargetParser",
1338     "LLVMSupport",
1339     "LLVMDemangle",
1342 fn generateLangRef(b: *std.Build) std.Build.LazyPath {
1343     const doctest_exe = b.addExecutable(.{
1344         .name = "doctest",
1345         .root_module = b.createModule(.{
1346             .root_source_file = b.path("tools/doctest.zig"),
1347             .target = b.graph.host,
1348             .optimize = .Debug,
1349         }),
1350     });
1352     var dir = b.build_root.handle.openDir("doc/langref", .{ .iterate = true }) catch |err| {
1353         std.debug.panic("unable to open '{}doc/langref' directory: {s}", .{
1354             b.build_root, @errorName(err),
1355         });
1356     };
1357     defer dir.close();
1359     var wf = b.addWriteFiles();
1361     var it = dir.iterateAssumeFirstIteration();
1362     while (it.next() catch @panic("failed to read dir")) |entry| {
1363         if (std.mem.startsWith(u8, entry.name, ".") or entry.kind != .file)
1364             continue;
1366         const out_basename = b.fmt("{s}.out", .{std.fs.path.stem(entry.name)});
1367         const cmd = b.addRunArtifact(doctest_exe);
1368         cmd.addArgs(&.{
1369             "--zig",        b.graph.zig_exe,
1370             // TODO: enhance doctest to use "--listen=-" rather than operating
1371             // in a temporary directory
1372             "--cache-root", b.cache_root.path orelse ".",
1373         });
1374         cmd.addArgs(&.{ "--zig-lib-dir", b.fmt("{}", .{b.graph.zig_lib_directory}) });
1375         cmd.addArgs(&.{"-i"});
1376         cmd.addFileArg(b.path(b.fmt("doc/langref/{s}", .{entry.name})));
1378         cmd.addArgs(&.{"-o"});
1379         _ = wf.addCopyFile(cmd.addOutputFileArg(out_basename), out_basename);
1380     }
1382     const docgen_exe = b.addExecutable(.{
1383         .name = "docgen",
1384         .root_module = b.createModule(.{
1385             .root_source_file = b.path("tools/docgen.zig"),
1386             .target = b.graph.host,
1387             .optimize = .Debug,
1388         }),
1389     });
1391     const docgen_cmd = b.addRunArtifact(docgen_exe);
1392     docgen_cmd.addArgs(&.{"--code-dir"});
1393     docgen_cmd.addDirectoryArg(wf.getDirectory());
1395     docgen_cmd.addFileArg(b.path("doc/langref.html.in"));
1396     return docgen_cmd.addOutputFileArg("langref.html");
1399 fn superHtmlCheck(b: *std.Build, html_file: std.Build.LazyPath) *std.Build.Step {
1400     const run_superhtml = b.addSystemCommand(&.{
1401         "superhtml", "check",
1402     });
1403     run_superhtml.addFileArg(html_file);
1404     run_superhtml.expectExitCode(0);
1405     return &run_superhtml.step;