build.zig (72270B) - Raw
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 io = std.io; 7 const fs = std.fs; 8 const InstallDirectoryOptions = std.Build.InstallDirectoryOptions; 9 const assert = std.debug.assert; 10 const DevEnv = @import("src/dev.zig").Env; 11 const ValueInterpretMode = enum { direct, by_name }; 12 const corpus = @import("stage0/corpus.zig"); 13 14 const zig0_headers = &[_][]const u8{ 15 "air.h", 16 "ast.h", 17 "astgen.h", 18 "common.h", 19 "compilation.h", 20 "intern_pool.h", 21 "parser.h", 22 "sema.h", 23 "type.h", 24 "value.h", 25 "verbose_air.h", 26 "verbose_intern_pool.h", 27 "wyhash.h", 28 "zcu.h", 29 "zcu_per_thread.h", 30 "zir.h", 31 }; 32 const zig0_c_lib_files = &[_][]const u8{ 33 "air.c", 34 "ast.c", 35 "astgen.c", 36 "intern_pool.c", 37 "parser.c", 38 "sema.c", 39 "tokenizer.c", 40 "type.c", 41 "value.c", 42 "verbose_air.c", 43 "verbose_intern_pool.c", 44 "wyhash.c", 45 "zig0.c", 46 "zcu.c", 47 "zcu_per_thread.c", 48 "zir.c", 49 }; 50 const zig0_all_c_files = zig0_c_lib_files ++ &[_][]const u8{"main.c"}; 51 const zig0_cflags = &[_][]const u8{ 52 "-std=c99", 53 "-pedantic", 54 "-Wall", 55 "-Wvla", 56 "-Wextra", 57 "-Werror", 58 "-Wshadow", 59 "-Wswitch", 60 "-Walloca", 61 "-Wformat=2", 62 "-fno-common", 63 "-Wconversion", 64 "-Wuninitialized", 65 "-Wdouble-promotion", 66 "-fstack-protector-all", 67 "-Wimplicit-fallthrough", 68 "-Wno-unused-function", 69 }; 70 const zig0_compilers = &[_][]const u8{ "zig", "clang", "gcc", "tcc" }; 71 72 const zig_version: std.SemanticVersion = .{ .major = 0, .minor = 15, .patch = 3 }; 73 const stack_size = 46 * 1024 * 1024; 74 75 pub fn build(b: *std.Build) !void { 76 const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false; 77 const target = b.standardTargetOptions(.{ 78 .default_target = .{ 79 .ofmt = if (only_c) .c else null, 80 }, 81 }); 82 const optimize = b.standardOptimizeOption(.{}); 83 84 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; 85 const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode"); 86 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; 87 88 const test_step = b.step("test", "Run all the tests"); 89 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; 90 const skip_install_langref = b.option(bool, "no-langref", "skip copying of langref to the installation prefix") orelse skip_install_lib_files; 91 const std_docs = b.option(bool, "std-docs", "include standard library autodocs") orelse false; 92 const no_bin = b.option(bool, "no-bin", "skip emitting compiler binary") orelse false; 93 const enable_superhtml = b.option(bool, "enable-superhtml", "Check langref output HTML validity") orelse false; 94 95 const langref_file = generateLangRef(b); 96 const install_langref = b.addInstallFileWithDir(langref_file, .prefix, "doc/langref.html"); 97 const check_langref = superHtmlCheck(b, langref_file); 98 if (enable_superhtml) install_langref.step.dependOn(check_langref); 99 100 const check_autodocs = superHtmlCheck(b, b.path("lib/docs/index.html")); 101 if (enable_superhtml) { 102 test_step.dependOn(check_langref); 103 test_step.dependOn(check_autodocs); 104 } 105 if (!skip_install_langref) { 106 b.getInstallStep().dependOn(&install_langref.step); 107 } 108 109 const autodoc_test = b.addObject(.{ 110 .name = "std", 111 .zig_lib_dir = b.path("lib"), 112 .root_module = b.createModule(.{ 113 .root_source_file = b.path("lib/std/std.zig"), 114 .target = target, 115 .optimize = .Debug, 116 }), 117 }); 118 const install_std_docs = b.addInstallDirectory(.{ 119 .source_dir = autodoc_test.getEmittedDocs(), 120 .install_dir = .prefix, 121 .install_subdir = "doc/std", 122 }); 123 //if (enable_tidy) install_std_docs.step.dependOn(check_autodocs); 124 if (std_docs) { 125 b.getInstallStep().dependOn(&install_std_docs.step); 126 } 127 128 if (flat) { 129 b.installFile("LICENSE", "LICENSE"); 130 b.installFile("README.md", "README.md"); 131 } 132 133 const langref_step = b.step("langref", "Build and install the language reference"); 134 langref_step.dependOn(&install_langref.step); 135 136 const std_docs_step = b.step("std-docs", "Build and install the standard library documentation"); 137 std_docs_step.dependOn(&install_std_docs.step); 138 139 const docs_step = b.step("docs", "Build and install documentation"); 140 docs_step.dependOn(langref_step); 141 docs_step.dependOn(std_docs_step); 142 143 const skip_debug = b.option(bool, "skip-debug", "Main test suite skips debug builds") orelse false; 144 const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false; 145 const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release; 146 const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release; 147 const skip_release_safe = b.option(bool, "skip-release-safe", "Main test suite skips release-safe builds") orelse skip_release; 148 const skip_non_native = b.option(bool, "skip-non-native", "Main test suite skips non-native builds") orelse false; 149 const skip_libc = b.option(bool, "skip-libc", "Main test suite skips tests that link libc") orelse false; 150 const skip_single_threaded = b.option(bool, "skip-single-threaded", "Main test suite skips tests that are single-threaded") orelse false; 151 const skip_compile_errors = b.option(bool, "skip-compile-errors", "Main test suite skips compile error tests") orelse false; 152 const skip_translate_c = b.option(bool, "skip-translate-c", "Main test suite skips translate-c tests") orelse false; 153 const skip_run_translated_c = b.option(bool, "skip-run-translated-c", "Main test suite skips run-translated-c tests") orelse false; 154 const skip_freebsd = b.option(bool, "skip-freebsd", "Main test suite skips targets with freebsd OS") orelse false; 155 const skip_netbsd = b.option(bool, "skip-netbsd", "Main test suite skips targets with netbsd OS") orelse false; 156 const skip_windows = b.option(bool, "skip-windows", "Main test suite skips targets with windows OS") orelse false; 157 const skip_macos = b.option(bool, "skip-macos", "Main test suite skips targets with macos OS") orelse false; 158 const skip_linux = b.option(bool, "skip-linux", "Main test suite skips targets with linux OS") orelse false; 159 const skip_llvm = b.option(bool, "skip-llvm", "Main test suite skips targets that use LLVM backend") orelse false; 160 161 const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false; 162 163 const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false; 164 const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse static_llvm; 165 const llvm_has_m68k = b.option( 166 bool, 167 "llvm-has-m68k", 168 "Whether LLVM has the experimental target m68k enabled", 169 ) orelse false; 170 const llvm_has_csky = b.option( 171 bool, 172 "llvm-has-csky", 173 "Whether LLVM has the experimental target csky enabled", 174 ) orelse false; 175 const llvm_has_arc = b.option( 176 bool, 177 "llvm-has-arc", 178 "Whether LLVM has the experimental target arc enabled", 179 ) orelse false; 180 const llvm_has_xtensa = b.option( 181 bool, 182 "llvm-has-xtensa", 183 "Whether LLVM has the experimental target xtensa enabled", 184 ) orelse false; 185 const enable_ios_sdk = b.option(bool, "enable-ios-sdk", "Run tests requiring presence of iOS SDK and frameworks") orelse false; 186 const enable_macos_sdk = b.option(bool, "enable-macos-sdk", "Run tests requiring presence of macOS SDK and frameworks") orelse enable_ios_sdk; 187 const enable_symlinks_windows = b.option(bool, "enable-symlinks-windows", "Run tests requiring presence of symlinks on Windows") orelse false; 188 const config_h_path_option = b.option([]const u8, "config_h", "Path to the generated config.h"); 189 190 if (!skip_install_lib_files) { 191 b.installDirectory(.{ 192 .source_dir = b.path("lib"), 193 .install_dir = if (flat) .prefix else .lib, 194 .install_subdir = if (flat) "lib" else "zig", 195 .exclude_extensions = &[_][]const u8{ 196 // exclude files from lib/std/compress/testdata 197 ".gz", 198 ".z.0", 199 ".z.9", 200 ".zst.3", 201 ".zst.19", 202 "rfc1951.txt", 203 "rfc1952.txt", 204 "rfc8478.txt", 205 // exclude files from lib/std/compress/flate/testdata 206 ".expect", 207 ".expect-noinput", 208 ".golden", 209 ".input", 210 "compress-e.txt", 211 "compress-gettysburg.txt", 212 "compress-pi.txt", 213 "rfc1951.txt", 214 // exclude files from lib/std/compress/lzma/testdata 215 ".lzma", 216 // exclude files from lib/std/compress/xz/testdata 217 ".xz", 218 // exclude files from lib/std/tz/ 219 ".tzif", 220 // exclude files from lib/std/tar/testdata 221 ".tar", 222 // others 223 "README.md", 224 }, 225 .blank_extensions = &[_][]const u8{ 226 "test.zig", 227 }, 228 }); 229 } 230 231 if (only_install_lib_files) 232 return; 233 234 const entitlements = b.option([]const u8, "entitlements", "Path to entitlements file for hot-code swapping without sudo on macOS"); 235 const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source"); 236 const tracy_callstack = b.option(bool, "tracy-callstack", "Include callstack information with Tracy data. Does nothing if -Dtracy is not provided") orelse (tracy != null); 237 const tracy_allocation = b.option(bool, "tracy-allocation", "Include allocation information with Tracy data. Does nothing if -Dtracy is not provided") orelse (tracy != null); 238 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; 239 const debug_gpa = b.option(bool, "debug-allocator", "Force the compiler to use DebugAllocator") orelse false; 240 const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse (enable_llvm or only_c); 241 const sanitize_thread = b.option(bool, "sanitize-thread", "Enable thread-sanitization") orelse false; 242 const strip = b.option(bool, "strip", "Omit debug information"); 243 const valgrind = b.option(bool, "valgrind", "Enable valgrind integration"); 244 const pie = b.option(bool, "pie", "Produce a Position Independent Executable"); 245 const value_interpret_mode = b.option(ValueInterpretMode, "value-interpret-mode", "How the compiler translates between 'std.builtin' types and its internal datastructures") orelse .direct; 246 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; 247 248 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: { 249 if (strip == true) break :blk @as(u32, 0); 250 if (optimize != .Debug) break :blk 0; 251 break :blk 4; 252 }; 253 254 const exe = addCompilerStep(b, .{ 255 .optimize = optimize, 256 .target = target, 257 .strip = strip, 258 .valgrind = valgrind, 259 .sanitize_thread = sanitize_thread, 260 .single_threaded = single_threaded, 261 }); 262 exe.pie = pie; 263 exe.entitlements = entitlements; 264 265 const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend"); 266 exe.use_llvm = use_llvm; 267 exe.use_lld = use_llvm; 268 269 if (no_bin) { 270 b.getInstallStep().dependOn(&exe.step); 271 } else { 272 const install_exe = b.addInstallArtifact(exe, .{ 273 .dest_dir = if (flat) .{ .override = .prefix } else .default, 274 }); 275 b.getInstallStep().dependOn(&install_exe.step); 276 } 277 278 test_step.dependOn(&exe.step); 279 280 const exe_options = b.addOptions(); 281 exe.root_module.addOptions("build_options", exe_options); 282 283 exe_options.addOption(u32, "mem_leak_frames", mem_leak_frames); 284 exe_options.addOption(bool, "skip_non_native", skip_non_native); 285 exe_options.addOption(bool, "have_llvm", enable_llvm); 286 exe_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k); 287 exe_options.addOption(bool, "llvm_has_csky", llvm_has_csky); 288 exe_options.addOption(bool, "llvm_has_arc", llvm_has_arc); 289 exe_options.addOption(bool, "llvm_has_xtensa", llvm_has_xtensa); 290 exe_options.addOption(bool, "debug_gpa", debug_gpa); 291 const dev_mode: DevEnv = b.option(DevEnv, "dev", "Build a compiler with a reduced feature set for development of specific features") orelse if (only_c) .bootstrap else .full; 292 exe_options.addOption(DevEnv, "dev", dev_mode); 293 exe_options.addOption(ValueInterpretMode, "value_interpret_mode", value_interpret_mode); 294 295 if (link_libc) { 296 exe.root_module.link_libc = true; 297 } 298 299 const is_debug = optimize == .Debug; 300 const enable_debug_extensions = b.option(bool, "debug-extensions", "Enable commands and options useful for debugging the compiler") orelse is_debug; 301 const enable_logging = b.option(bool, "log", "Enable debug logging with --debug-log") orelse is_debug; 302 const enable_link_snapshots = b.option(bool, "link-snapshot", "Whether to enable linker state snapshots") orelse false; 303 304 const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git."); 305 const version_slice = if (opt_version_string) |version| version else v: { 306 if (!std.process.can_spawn) { 307 std.debug.print("error: version info cannot be retrieved from git. Zig version must be provided using -Dversion-string\n", .{}); 308 std.process.exit(1); 309 } 310 const version_string = b.fmt("{d}.{d}.{d}", .{ zig_version.major, zig_version.minor, zig_version.patch }); 311 312 var code: u8 = undefined; 313 const git_describe_untrimmed = b.runAllowFail(&[_][]const u8{ 314 "git", 315 "-C", b.build_root.path orelse ".", // affects the --git-dir argument 316 "--git-dir", ".git", // affected by the -C argument 317 "describe", "--match", "*.*.*", // 318 "--tags", "--abbrev=9", 319 }, &code, .Ignore) catch { 320 break :v version_string; 321 }; 322 const git_describe = mem.trim(u8, git_describe_untrimmed, " \n\r"); 323 324 switch (mem.count(u8, git_describe, "-")) { 325 0 => { 326 // Tagged release version (e.g. 0.10.0). 327 if (!mem.eql(u8, git_describe, version_string)) { 328 std.debug.print("Zig version '{s}' does not match Git tag '{s}'\n", .{ version_string, git_describe }); 329 std.process.exit(1); 330 } 331 break :v version_string; 332 }, 333 2 => { 334 // Untagged development build (e.g. 0.10.0-dev.2025+ecf0050a9). 335 var it = mem.splitScalar(u8, git_describe, '-'); 336 const tagged_ancestor = it.first(); 337 const commit_height = it.next().?; 338 const commit_id = it.next().?; 339 340 const ancestor_ver = try std.SemanticVersion.parse(tagged_ancestor); 341 if (zig_version.order(ancestor_ver) != .gt) { 342 std.debug.print("Zig version '{f}' must be greater than tagged ancestor '{f}'\n", .{ zig_version, ancestor_ver }); 343 std.process.exit(1); 344 } 345 346 // Check that the commit hash is prefixed with a 'g' (a Git convention). 347 if (commit_id.len < 1 or commit_id[0] != 'g') { 348 std.debug.print("Unexpected `git describe` output: {s}\n", .{git_describe}); 349 break :v version_string; 350 } 351 352 // The version is reformatted in accordance with the https://semver.org specification. 353 break :v b.fmt("{s}-dev.{s}+{s}", .{ version_string, commit_height, commit_id[1..] }); 354 }, 355 else => { 356 std.debug.print("Unexpected `git describe` output: {s}\n", .{git_describe}); 357 break :v version_string; 358 }, 359 } 360 }; 361 const version = try b.allocator.dupeZ(u8, version_slice); 362 exe_options.addOption([:0]const u8, "version", version); 363 364 if (enable_llvm) { 365 const cmake_cfg = if (static_llvm) null else blk: { 366 if (findConfigH(b, config_h_path_option)) |config_h_path| { 367 const file_contents = fs.cwd().readFileAlloc(b.allocator, config_h_path, max_config_h_bytes) catch unreachable; 368 break :blk parseConfigH(b, file_contents); 369 } else { 370 std.log.warn("config.h could not be located automatically. Consider providing it explicitly via \"-Dconfig_h\"", .{}); 371 break :blk null; 372 } 373 }; 374 375 if (cmake_cfg) |cfg| { 376 // Inside this code path, we have to coordinate with system packaged LLVM, Clang, and LLD. 377 // That means we also have to rely on stage1 compiled c++ files. We parse config.h to find 378 // the information passed on to us from cmake. 379 if (cfg.cmake_prefix_path.len > 0) { 380 var it = mem.tokenizeScalar(u8, cfg.cmake_prefix_path, ';'); 381 while (it.next()) |path| { 382 b.addSearchPrefix(path); 383 } 384 } 385 386 try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx); 387 } else { 388 // Here we are -Denable-llvm but no cmake integration. 389 try addStaticLlvmOptionsToModule(exe.root_module, .{ 390 .llvm_has_m68k = llvm_has_m68k, 391 .llvm_has_csky = llvm_has_csky, 392 .llvm_has_arc = llvm_has_arc, 393 .llvm_has_xtensa = llvm_has_xtensa, 394 }); 395 } 396 if (target.result.os.tag == .windows) { 397 // LLVM depends on networking as of version 18. 398 exe.root_module.linkSystemLibrary("ws2_32", .{}); 399 400 exe.root_module.linkSystemLibrary("version", .{}); 401 exe.root_module.linkSystemLibrary("uuid", .{}); 402 exe.root_module.linkSystemLibrary("ole32", .{}); 403 } 404 } 405 406 const semver = try std.SemanticVersion.parse(version); 407 exe_options.addOption(std.SemanticVersion, "semver", semver); 408 409 exe_options.addOption(bool, "enable_debug_extensions", enable_debug_extensions); 410 exe_options.addOption(bool, "enable_logging", enable_logging); 411 exe_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots); 412 exe_options.addOption(bool, "enable_tracy", tracy != null); 413 exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack); 414 exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation); 415 exe_options.addOption(u32, "tracy_callstack_depth", tracy_callstack_depth); 416 exe_options.addOption(bool, "value_tracing", value_tracing); 417 if (tracy) |tracy_path| { 418 const client_cpp = b.pathJoin( 419 &[_][]const u8{ tracy_path, "public", "TracyClient.cpp" }, 420 ); 421 422 const tracy_c_flags: []const []const u8 = &.{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" }; 423 424 exe.root_module.addIncludePath(.{ .cwd_relative = tracy_path }); 425 exe.root_module.addCSourceFile(.{ .file = .{ .cwd_relative = client_cpp }, .flags = tracy_c_flags }); 426 if (!enable_llvm) { 427 exe.root_module.linkSystemLibrary("c++", .{ .use_pkg_config = .no }); 428 } 429 exe.root_module.link_libc = true; 430 431 if (target.result.os.tag == .windows) { 432 exe.root_module.linkSystemLibrary("dbghelp", .{}); 433 exe.root_module.linkSystemLibrary("ws2_32", .{}); 434 } 435 } 436 437 const test_filters = b.option([]const []const u8, "test-filter", "Skip tests that do not match any filter") orelse &[0][]const u8{}; 438 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{}; 439 const test_extra_targets = b.option(bool, "test-extra-targets", "Enable running module tests for additional targets") orelse false; 440 441 var chosen_opt_modes_buf: [4]builtin.OptimizeMode = undefined; 442 var chosen_mode_index: usize = 0; 443 if (!skip_debug) { 444 chosen_opt_modes_buf[chosen_mode_index] = builtin.OptimizeMode.Debug; 445 chosen_mode_index += 1; 446 } 447 if (!skip_release_safe) { 448 chosen_opt_modes_buf[chosen_mode_index] = builtin.OptimizeMode.ReleaseSafe; 449 chosen_mode_index += 1; 450 } 451 if (!skip_release_fast) { 452 chosen_opt_modes_buf[chosen_mode_index] = builtin.OptimizeMode.ReleaseFast; 453 chosen_mode_index += 1; 454 } 455 if (!skip_release_small) { 456 chosen_opt_modes_buf[chosen_mode_index] = builtin.OptimizeMode.ReleaseSmall; 457 chosen_mode_index += 1; 458 } 459 const optimization_modes = chosen_opt_modes_buf[0..chosen_mode_index]; 460 461 const fmt_include_paths = &.{ "lib", "src", "test", "tools", "build.zig", "build.zig.zon" }; 462 const fmt_exclude_paths = &.{ "test/cases", "test/behavior/zon" }; 463 const do_fmt = b.addFmt(.{ 464 .paths = fmt_include_paths, 465 .exclude_paths = fmt_exclude_paths, 466 }); 467 b.step("fmt", "Modify source files in place to have conforming formatting").dependOn(&do_fmt.step); 468 469 const check_fmt = b.step("test-fmt", "Check source files having conforming formatting"); 470 check_fmt.dependOn(&b.addFmt(.{ 471 .paths = fmt_include_paths, 472 .exclude_paths = fmt_exclude_paths, 473 .check = true, 474 }).step); 475 test_step.dependOn(check_fmt); 476 477 const test_cases_step = b.step("test-cases", "Run the main compiler test cases"); 478 try tests.addCases(b, test_cases_step, target, .{ 479 .test_filters = test_filters, 480 .test_target_filters = test_target_filters, 481 .skip_compile_errors = skip_compile_errors, 482 .skip_non_native = skip_non_native, 483 .skip_freebsd = skip_freebsd, 484 .skip_netbsd = skip_netbsd, 485 .skip_windows = skip_windows, 486 .skip_macos = skip_macos, 487 .skip_linux = skip_linux, 488 .skip_llvm = skip_llvm, 489 .skip_libc = skip_libc, 490 }, .{ 491 .skip_translate_c = skip_translate_c, 492 .skip_run_translated_c = skip_run_translated_c, 493 }, .{ 494 .enable_llvm = enable_llvm, 495 .llvm_has_m68k = llvm_has_m68k, 496 .llvm_has_csky = llvm_has_csky, 497 .llvm_has_arc = llvm_has_arc, 498 .llvm_has_xtensa = llvm_has_xtensa, 499 }); 500 test_step.dependOn(test_cases_step); 501 502 const test_modules_step = b.step("test-modules", "Run the per-target module tests"); 503 test_step.dependOn(test_modules_step); 504 505 test_modules_step.dependOn(tests.addModuleTests(b, .{ 506 .test_filters = test_filters, 507 .test_target_filters = test_target_filters, 508 .test_extra_targets = test_extra_targets, 509 .root_src = "test/behavior.zig", 510 .name = "behavior", 511 .desc = "Run the behavior tests", 512 .optimize_modes = optimization_modes, 513 .include_paths = &.{}, 514 .skip_single_threaded = skip_single_threaded, 515 .skip_non_native = skip_non_native, 516 .skip_freebsd = skip_freebsd, 517 .skip_netbsd = skip_netbsd, 518 .skip_windows = skip_windows, 519 .skip_macos = skip_macos, 520 .skip_linux = skip_linux, 521 .skip_llvm = skip_llvm, 522 .skip_libc = skip_libc, 523 // 3888779264 was observed on an x86_64-linux-gnu host. 524 .max_rss = 4000000000, 525 })); 526 527 test_modules_step.dependOn(tests.addModuleTests(b, .{ 528 .test_filters = test_filters, 529 .test_target_filters = test_target_filters, 530 .test_extra_targets = test_extra_targets, 531 .root_src = "test/c_import.zig", 532 .name = "c-import", 533 .desc = "Run the @cImport tests", 534 .optimize_modes = optimization_modes, 535 .include_paths = &.{"test/c_import"}, 536 .skip_single_threaded = true, 537 .skip_non_native = skip_non_native, 538 .skip_freebsd = skip_freebsd, 539 .skip_netbsd = skip_netbsd, 540 .skip_windows = skip_windows, 541 .skip_macos = skip_macos, 542 .skip_linux = skip_linux, 543 .skip_llvm = skip_llvm, 544 .skip_libc = skip_libc, 545 })); 546 547 test_modules_step.dependOn(tests.addModuleTests(b, .{ 548 .test_filters = test_filters, 549 .test_target_filters = test_target_filters, 550 .test_extra_targets = test_extra_targets, 551 .root_src = "lib/compiler_rt.zig", 552 .name = "compiler-rt", 553 .desc = "Run the compiler_rt tests", 554 .optimize_modes = optimization_modes, 555 .include_paths = &.{}, 556 .skip_single_threaded = true, 557 .skip_non_native = skip_non_native, 558 .skip_freebsd = skip_freebsd, 559 .skip_netbsd = skip_netbsd, 560 .skip_windows = skip_windows, 561 .skip_macos = skip_macos, 562 .skip_linux = skip_linux, 563 .skip_llvm = skip_llvm, 564 .skip_libc = true, 565 .no_builtin = true, 566 })); 567 568 test_modules_step.dependOn(tests.addModuleTests(b, .{ 569 .test_filters = test_filters, 570 .test_target_filters = test_target_filters, 571 .test_extra_targets = test_extra_targets, 572 .root_src = "lib/c.zig", 573 .name = "zigc", 574 .desc = "Run the zigc tests", 575 .optimize_modes = optimization_modes, 576 .include_paths = &.{}, 577 .skip_single_threaded = true, 578 .skip_non_native = skip_non_native, 579 .skip_freebsd = skip_freebsd, 580 .skip_netbsd = skip_netbsd, 581 .skip_windows = skip_windows, 582 .skip_macos = skip_macos, 583 .skip_linux = skip_linux, 584 .skip_llvm = skip_llvm, 585 .skip_libc = true, 586 .no_builtin = true, 587 })); 588 589 test_modules_step.dependOn(tests.addModuleTests(b, .{ 590 .test_filters = test_filters, 591 .test_target_filters = test_target_filters, 592 .test_extra_targets = test_extra_targets, 593 .root_src = "lib/std/std.zig", 594 .name = "std", 595 .desc = "Run the standard library tests", 596 .optimize_modes = optimization_modes, 597 .include_paths = &.{}, 598 .skip_single_threaded = skip_single_threaded, 599 .skip_non_native = skip_non_native, 600 .skip_freebsd = skip_freebsd, 601 .skip_netbsd = skip_netbsd, 602 .skip_windows = skip_windows, 603 .skip_macos = skip_macos, 604 .skip_linux = skip_linux, 605 .skip_llvm = skip_llvm, 606 .skip_libc = skip_libc, 607 // I observed a value of 5605064704 on the M2 CI. 608 .max_rss = 6165571174, 609 })); 610 611 const unit_tests_step = b.step("test-unit", "Run the compiler source unit tests"); 612 test_step.dependOn(unit_tests_step); 613 614 const unit_tests = b.addTest(.{ 615 .root_module = addCompilerMod(b, .{ 616 .optimize = optimize, 617 .target = target, 618 .single_threaded = single_threaded, 619 }), 620 .filters = test_filters, 621 .use_llvm = use_llvm, 622 .use_lld = use_llvm, 623 .zig_lib_dir = b.path("lib"), 624 }); 625 if (link_libc) { 626 unit_tests.root_module.link_libc = true; 627 } 628 unit_tests.root_module.addOptions("build_options", exe_options); 629 unit_tests_step.dependOn(&b.addRunArtifact(unit_tests).step); 630 631 test_step.dependOn(tests.addCompareOutputTests(b, test_filters, optimization_modes)); 632 test_step.dependOn(tests.addStandaloneTests( 633 b, 634 optimization_modes, 635 enable_macos_sdk, 636 enable_ios_sdk, 637 enable_symlinks_windows, 638 )); 639 test_step.dependOn(tests.addCAbiTests(b, .{ 640 .test_target_filters = test_target_filters, 641 .skip_non_native = skip_non_native, 642 .skip_freebsd = skip_freebsd, 643 .skip_netbsd = skip_netbsd, 644 .skip_windows = skip_windows, 645 .skip_macos = skip_macos, 646 .skip_linux = skip_linux, 647 .skip_llvm = skip_llvm, 648 .skip_release = skip_release, 649 })); 650 test_step.dependOn(tests.addLinkTests(b, enable_macos_sdk, enable_ios_sdk, enable_symlinks_windows)); 651 test_step.dependOn(tests.addStackTraceTests(b, test_filters, optimization_modes)); 652 test_step.dependOn(tests.addCliTests(b)); 653 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filters, optimization_modes)); 654 if (tests.addDebuggerTests(b, .{ 655 .test_filters = test_filters, 656 .test_target_filters = test_target_filters, 657 .gdb = b.option([]const u8, "gdb", "path to gdb binary"), 658 .lldb = b.option([]const u8, "lldb", "path to lldb binary"), 659 .optimize_modes = optimization_modes, 660 .skip_single_threaded = skip_single_threaded, 661 .skip_libc = skip_libc, 662 })) |test_debugger_step| test_step.dependOn(test_debugger_step); 663 if (tests.addLlvmIrTests(b, .{ 664 .enable_llvm = enable_llvm, 665 .test_filters = test_filters, 666 .test_target_filters = test_target_filters, 667 })) |test_llvm_ir_step| test_step.dependOn(test_llvm_ir_step); 668 669 try addWasiUpdateStep(b, version); 670 671 const update_mingw_step = b.step("update-mingw", "Update zig's bundled mingw"); 672 const opt_mingw_src_path = b.option([]const u8, "mingw-src", "path to mingw-w64 source directory"); 673 if (opt_mingw_src_path) |mingw_src_path| { 674 const update_mingw_exe = b.addExecutable(.{ 675 .name = "update_mingw", 676 .root_module = b.createModule(.{ 677 .target = b.graph.host, 678 .root_source_file = b.path("tools/update_mingw.zig"), 679 }), 680 }); 681 const update_mingw_run = b.addRunArtifact(update_mingw_exe); 682 update_mingw_run.addDirectoryArg(b.path("lib")); 683 update_mingw_run.addDirectoryArg(.{ .cwd_relative = mingw_src_path }); 684 685 update_mingw_step.dependOn(&update_mingw_run.step); 686 } else { 687 update_mingw_step.dependOn(&b.addFail("The -Dmingw-src=... option is required for this step").step); 688 } 689 690 const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases"); 691 try tests.addIncrementalTests(b, test_incremental_step); 692 test_step.dependOn(test_incremental_step); 693 694 // zig0 (C implementation) build steps 695 const zig0_cc = b.option([]const u8, "zig0-cc", "C compiler for zig0 tests") orelse "zig"; 696 const zig0_no_exec = b.option(bool, "zig0-no-exec", "Compile zig0 test binary without running it") orelse false; 697 const zig0_test_timeout = b.option([]const u8, "zig0-test-timeout", "Test execution timeout for zig0"); 698 const zig0_valgrind = valgrind orelse false; 699 700 const zig0_target = blk: { 701 var query = target.query; 702 const arch = query.cpu_arch orelse @import("builtin").cpu.arch; 703 if (arch == .x86_64) { 704 // Valgrind doesn't support AVX-512 instructions (EVEX prefix). 705 // Subtract all AVX-512 features so the zig CC won't emit them. 706 const F = std.Target.x86.Feature; 707 const avx512_features = [_]F{ 708 .avx512f, .avx512bw, 709 .avx512cd, .avx512dq, 710 .avx512vl, .avx512bf16, 711 .avx512bitalg, .avx512er, 712 .avx512fp16, .avx512ifma, 713 .avx512pf, .avx512vbmi, 714 .avx512vbmi2, .avx512vnni, 715 .avx512vp2intersect, .avx512vpopcntdq, 716 .evex512, 717 }; 718 for (avx512_features) |f| 719 query.cpu_features_sub.addFeature(@intFromEnum(f)); 720 } 721 break :blk b.resolveTargetQuery(query); 722 }; 723 724 // Separate build_options for zig0 tests with a fixed version string, so 725 // that the verbose_dumper cache is not invalidated on every git commit. 726 const zig0_airgen_options = b.addOptions(); 727 zig0_airgen_options.addOption(u32, "mem_leak_frames", mem_leak_frames); 728 zig0_airgen_options.addOption(bool, "skip_non_native", skip_non_native); 729 // air_gen only needs source->AIR (no codegen), so disable LLVM. 730 zig0_airgen_options.addOption(bool, "have_llvm", false); 731 zig0_airgen_options.addOption(bool, "llvm_has_m68k", false); 732 zig0_airgen_options.addOption(bool, "llvm_has_csky", false); 733 zig0_airgen_options.addOption(bool, "llvm_has_arc", false); 734 zig0_airgen_options.addOption(bool, "llvm_has_xtensa", false); 735 zig0_airgen_options.addOption(bool, "debug_gpa", debug_gpa); 736 zig0_airgen_options.addOption(DevEnv, "dev", .full); 737 zig0_airgen_options.addOption(ValueInterpretMode, "value_interpret_mode", value_interpret_mode); 738 zig0_airgen_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, "0.15.2-zig0-dev")); 739 zig0_airgen_options.addOption(std.SemanticVersion, "semver", try std.SemanticVersion.parse("0.15.2-zig0-dev")); 740 zig0_airgen_options.addOption(bool, "enable_debug_extensions", enable_debug_extensions); 741 zig0_airgen_options.addOption(bool, "enable_logging", enable_logging); 742 zig0_airgen_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots); 743 zig0_airgen_options.addOption(bool, "enable_tracy", tracy != null); 744 zig0_airgen_options.addOption(bool, "enable_tracy_callstack", tracy_callstack); 745 zig0_airgen_options.addOption(bool, "enable_tracy_allocation", tracy_allocation); 746 zig0_airgen_options.addOption(u32, "tracy_callstack_depth", tracy_callstack_depth); 747 zig0_airgen_options.addOption(bool, "value_tracing", value_tracing); 748 749 // ReleaseFast, because we trust compiler will emit the correct AIR 750 // under all modes. 751 const air_gen_result = addAirGen(b, zig0_airgen_options, .ReleaseFast); 752 753 const prepare_zig0 = b.step("prepare-zig0", "Generate pre-computed AIR files for zig0 tests"); 754 prepare_zig0.dependOn(air_gen_result.step); 755 756 const test_zig0_step = b.step("test-zig0", "Run zig0 C implementation tests"); 757 addZig0TestStep(b, test_zig0_step, zig0_target, optimize, zig0_cc, zig0_no_exec, zig0_valgrind, zig0_test_timeout, air_gen_result); 758 759 // zig0 standalone executable 760 const zig0_step = b.step("zig0", "Build zig0 standalone executable"); 761 const zig0_mod = b.createModule(.{ 762 .target = zig0_target, 763 .optimize = optimize, 764 }); 765 zig0_mod.addCSourceFiles(.{ 766 .root = b.path("stage0"), 767 .files = zig0_all_c_files, 768 .flags = zig0_cflags, 769 }); 770 zig0_mod.linkSystemLibrary("c", .{}); 771 const zig0_exe = b.addExecutable(.{ 772 .name = "zig0", 773 .root_module = zig0_mod, 774 }); 775 const zig0_install = b.addInstallArtifact(zig0_exe, .{}); 776 zig0_step.dependOn(&zig0_install.step); 777 778 const fmt_zig0 = b.step("fmt-zig0", "Format zig0 C code"); 779 const clang_format = b.addSystemCommand(&.{ "clang-format", "-i" }); 780 for (zig0_all_c_files ++ zig0_headers) |f| clang_format.addFileArg(b.path(b.fmt("stage0/{s}", .{f}))); 781 fmt_zig0.dependOn(&clang_format.step); 782 783 const lint_zig0 = b.step("lint-zig0", "Run zig0 linters"); 784 for (zig0_all_c_files) |cfile| { 785 const clang_analyze = b.addSystemCommand(&.{ 786 "clang", 787 "--analyze", 788 "--analyzer-output", 789 "text", 790 "-Wno-unused-command-line-argument", 791 "-Werror", 792 "-Xclang", 793 "-analyzer-disable-checker", 794 "-Xclang", 795 "unix.Malloc", 796 }); 797 clang_analyze.addFileArg(b.path(b.fmt("stage0/{s}", .{cfile}))); 798 clang_analyze.step.name = b.fmt("clang --analyze ({s})", .{cfile}); 799 clang_analyze.expectExitCode(0); 800 lint_zig0.dependOn(&clang_analyze.step); 801 802 // Uses >20GiB of memory, disabled for now. 803 // const gcc_analyze = b.addSystemCommand(&.{ 804 // "gcc", 805 // "-c", 806 // "--analyzer", 807 // "-Werror", 808 // "-o", 809 // "/dev/null", 810 // }); 811 // gcc_analyze.addFileArg(b.path(b.fmt("stage0/{s}", .{cfile}))); 812 // gcc_analyze.expectExitCode(0); 813 // lint_zig0.dependOn(&gcc_analyze.step); 814 815 const cppcheck = b.addSystemCommand(&.{ 816 "cppcheck", 817 "--quiet", 818 "--error-exitcode=1", 819 "--check-level=exhaustive", 820 "--enable=warning,style,performance,portability", 821 "--inline-suppr", 822 }); 823 cppcheck.addFileArg(b.path(b.fmt("stage0/{s}", .{cfile}))); 824 cppcheck.step.name = b.fmt("cppcheck ({s})", .{cfile}); 825 cppcheck.expectExitCode(0); 826 lint_zig0.dependOn(&cppcheck.step); 827 } 828 829 // TODO enable unusedFunction when it's settled. 830 //const cppcheck_unused = b.addSystemCommand(&.{ 831 // "cppcheck", 832 // "--quiet", 833 // "--error-exitcode=1", 834 // "--check-level=exhaustive", 835 // "--enable=unusedFunction", 836 // "--inline-suppr", 837 //}); 838 //for (zig0_all_c_files) |cfile| { 839 // cppcheck_unused.addFileArg(b.path(b.fmt("stage0/{s}", .{cfile}))); 840 //} 841 //cppcheck_unused.step.name = "cppcheck (unusedFunction)"; 842 //cppcheck_unused.expectExitCode(0); 843 //lint_zig0.dependOn(&cppcheck_unused.step); 844 845 const all_zig0 = b.step("all-zig0", "Run zig0 fmt check, lint, and tests with all compilers"); 846 // fmt check (dry-run) 847 const zig0_fmt_check = b.addSystemCommand(&.{ "clang-format", "--dry-run", "-Werror" }); 848 for (zig0_all_c_files ++ zig0_headers) |f| zig0_fmt_check.addFileArg(b.path(b.fmt("stage0/{s}", .{f}))); 849 zig0_fmt_check.expectExitCode(0); 850 all_zig0.dependOn(&zig0_fmt_check.step); 851 all_zig0.dependOn(lint_zig0); 852 for (zig0_compilers) |compiler| { 853 addZig0TestStep(b, all_zig0, zig0_target, optimize, compiler, false, zig0_valgrind, zig0_test_timeout, air_gen_result); 854 } 855 } 856 857 fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { 858 const semver = try std.SemanticVersion.parse(version); 859 860 const exe = addCompilerStep(b, .{ 861 .optimize = .ReleaseSmall, 862 .target = b.resolveTargetQuery(std.Target.Query.parse(.{ 863 .arch_os_abi = "wasm32-wasi", 864 // * `extended_const` is not supported by the `wasm-opt` version in CI. 865 // * `nontrapping_bulk_memory_len0` is supported by `wasm2c`. 866 .cpu_features = "baseline-extended_const+nontrapping_bulk_memory_len0", 867 }) catch unreachable), 868 }); 869 870 const exe_options = b.addOptions(); 871 exe.root_module.addOptions("build_options", exe_options); 872 873 exe_options.addOption(u32, "mem_leak_frames", 0); 874 exe_options.addOption(bool, "have_llvm", false); 875 exe_options.addOption(bool, "debug_gpa", false); 876 exe_options.addOption([:0]const u8, "version", version); 877 exe_options.addOption(std.SemanticVersion, "semver", semver); 878 exe_options.addOption(bool, "enable_debug_extensions", false); 879 exe_options.addOption(bool, "enable_logging", false); 880 exe_options.addOption(bool, "enable_link_snapshots", false); 881 exe_options.addOption(bool, "enable_tracy", false); 882 exe_options.addOption(bool, "enable_tracy_callstack", false); 883 exe_options.addOption(bool, "enable_tracy_allocation", false); 884 exe_options.addOption(u32, "tracy_callstack_depth", 0); 885 exe_options.addOption(bool, "value_tracing", false); 886 exe_options.addOption(DevEnv, "dev", .bootstrap); 887 888 // zig1 chooses to interpret values by name. The tradeoff is as follows: 889 // 890 // * We lose a small amount of performance. This is essentially irrelevant for zig1. 891 // 892 // * We lose the ability to perform trivial renames on certain `std.builtin` types without 893 // zig1.wasm updates. For instance, we cannot rename an enum from PascalCase fields to 894 // snake_case fields without an update. 895 // 896 // * We gain the ability to add and remove fields to and from `std.builtin` types without 897 // zig1.wasm updates. For instance, we can add a new tag to `CallingConvention` without 898 // an update. 899 // 900 // Because field renames only happen when we apply a breaking change to the language (which 901 // is becoming progressively rarer), but tags may be added to or removed from target-dependent 902 // types over time in response to new targets coming into use, we gain more than we lose here. 903 exe_options.addOption(ValueInterpretMode, "value_interpret_mode", .by_name); 904 905 const run_opt = b.addSystemCommand(&.{ 906 "wasm-opt", 907 "-Oz", 908 "--enable-bulk-memory", 909 "--enable-mutable-globals", 910 "--enable-nontrapping-float-to-int", 911 "--enable-sign-ext", 912 }); 913 run_opt.addArtifactArg(exe); 914 run_opt.addArg("-o"); 915 run_opt.addFileArg(b.path("stage1/zig1.wasm")); 916 917 const copy_zig_h = b.addUpdateSourceFiles(); 918 copy_zig_h.addCopyFileToSource(b.path("lib/zig.h"), "stage1/zig.h"); 919 920 const update_zig1_step = b.step("update-zig1", "Update stage1/zig1.wasm"); 921 update_zig1_step.dependOn(&run_opt.step); 922 update_zig1_step.dependOn(©_zig_h.step); 923 } 924 925 const AddCompilerModOptions = struct { 926 optimize: std.builtin.OptimizeMode, 927 target: std.Build.ResolvedTarget, 928 strip: ?bool = null, 929 valgrind: ?bool = null, 930 sanitize_thread: ?bool = null, 931 single_threaded: ?bool = null, 932 }; 933 934 fn addCompilerMod(b: *std.Build, options: AddCompilerModOptions) *std.Build.Module { 935 const compiler_mod = b.createModule(.{ 936 .root_source_file = b.path("src/main.zig"), 937 .target = options.target, 938 .optimize = options.optimize, 939 .strip = options.strip, 940 .sanitize_thread = options.sanitize_thread, 941 .single_threaded = options.single_threaded, 942 .valgrind = options.valgrind, 943 }); 944 945 const aro_mod = b.createModule(.{ 946 .root_source_file = b.path("lib/compiler/aro/aro.zig"), 947 }); 948 949 const aro_translate_c_mod = b.createModule(.{ 950 .root_source_file = b.path("lib/compiler/aro_translate_c.zig"), 951 }); 952 953 aro_translate_c_mod.addImport("aro", aro_mod); 954 compiler_mod.addImport("aro", aro_mod); 955 compiler_mod.addImport("aro_translate_c", aro_translate_c_mod); 956 957 return compiler_mod; 958 } 959 960 fn addCompilerStep(b: *std.Build, options: AddCompilerModOptions) *std.Build.Step.Compile { 961 const exe = b.addExecutable(.{ 962 .name = "zig", 963 .max_rss = 7_800_000_000, 964 .root_module = addCompilerMod(b, options), 965 }); 966 exe.stack_size = stack_size; 967 968 return exe; 969 } 970 971 const exe_cflags = [_][]const u8{ 972 "-std=c++17", 973 "-D__STDC_CONSTANT_MACROS", 974 "-D__STDC_FORMAT_MACROS", 975 "-D__STDC_LIMIT_MACROS", 976 "-D_GNU_SOURCE", 977 "-fno-exceptions", 978 "-fno-rtti", 979 "-fno-stack-protector", 980 "-fvisibility-inlines-hidden", 981 "-Wno-type-limits", 982 "-Wno-missing-braces", 983 "-Wno-comment", 984 // `exe_cflags` is only used for static linking. 985 "-DLLVM_BUILD_STATIC", 986 "-DCLANG_BUILD_STATIC", 987 }; 988 989 fn addCmakeCfgOptionsToExe( 990 b: *std.Build, 991 cfg: CMakeConfig, 992 exe: *std.Build.Step.Compile, 993 use_zig_libcxx: bool, 994 ) !void { 995 const mod = exe.root_module; 996 const target = &mod.resolved_target.?.result; 997 998 if (target.os.tag.isDarwin()) { 999 // useful for package maintainers 1000 exe.headerpad_max_install_names = true; 1001 } 1002 1003 mod.addObjectFile(.{ .cwd_relative = b.pathJoin(&.{ 1004 cfg.cmake_binary_dir, 1005 "zigcpp", 1006 b.fmt("{s}{s}{s}", .{ 1007 cfg.cmake_static_library_prefix, 1008 "zigcpp", 1009 cfg.cmake_static_library_suffix, 1010 }), 1011 }) }); 1012 assert(cfg.lld_include_dir.len != 0); 1013 mod.addIncludePath(.{ .cwd_relative = cfg.lld_include_dir }); 1014 mod.addIncludePath(.{ .cwd_relative = cfg.llvm_include_dir }); 1015 mod.addLibraryPath(.{ .cwd_relative = cfg.llvm_lib_dir }); 1016 addCMakeLibraryList(mod, cfg.clang_libraries); 1017 addCMakeLibraryList(mod, cfg.lld_libraries); 1018 addCMakeLibraryList(mod, cfg.llvm_libraries); 1019 1020 if (use_zig_libcxx) { 1021 mod.link_libcpp = true; 1022 } else { 1023 // System -lc++ must be used because in this code path we are attempting to link 1024 // against system-provided LLVM, Clang, LLD. 1025 const need_cpp_includes = true; 1026 const static = cfg.llvm_linkage == .static; 1027 const lib_suffix = if (static) target.staticLibSuffix()[1..] else target.dynamicLibSuffix()[1..]; 1028 switch (target.os.tag) { 1029 .linux => { 1030 // First we try to link against the detected libcxx name. If that doesn't work, we fall 1031 // back to -lc++ and cross our fingers. 1032 addCxxKnownPath(b, cfg, exe, b.fmt("lib{s}.{s}", .{ cfg.system_libcxx, lib_suffix }), "", need_cpp_includes) catch |err| switch (err) { 1033 error.RequiredLibraryNotFound => { 1034 mod.link_libcpp = true; 1035 }, 1036 else => |e| return e, 1037 }; 1038 mod.linkSystemLibrary("unwind", .{}); 1039 }, 1040 .ios, .macos, .watchos, .tvos, .visionos => { 1041 mod.link_libcpp = true; 1042 }, 1043 .windows => { 1044 if (target.abi != .msvc) mod.link_libcpp = true; 1045 }, 1046 .freebsd => { 1047 try addCxxKnownPath(b, cfg, exe, b.fmt("libc++.{s}", .{lib_suffix}), null, need_cpp_includes); 1048 if (static) try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes); 1049 }, 1050 .openbsd => { 1051 // - llvm requires libexecinfo which has conflicting symbols with libc++abi 1052 // - only an issue with .a linking 1053 // - workaround is to link c++abi dynamically 1054 try addCxxKnownPath(b, cfg, exe, b.fmt("libc++.{s}", .{target.dynamicLibSuffix()[1..]}), null, need_cpp_includes); 1055 try addCxxKnownPath(b, cfg, exe, b.fmt("libc++abi.{s}", .{target.dynamicLibSuffix()[1..]}), null, need_cpp_includes); 1056 }, 1057 .netbsd, .dragonfly => { 1058 try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes); 1059 if (static) try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes); 1060 }, 1061 .solaris, .illumos => { 1062 try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes); 1063 try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes); 1064 }, 1065 .haiku => { 1066 try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes); 1067 }, 1068 else => {}, 1069 } 1070 } 1071 1072 if (cfg.dia_guids_lib.len != 0) { 1073 mod.addObjectFile(.{ .cwd_relative = cfg.dia_guids_lib }); 1074 } 1075 } 1076 1077 fn addStaticLlvmOptionsToModule(mod: *std.Build.Module, options: struct { 1078 llvm_has_m68k: bool, 1079 llvm_has_csky: bool, 1080 llvm_has_arc: bool, 1081 llvm_has_xtensa: bool, 1082 }) !void { 1083 // Adds the Zig C++ sources which both stage1 and stage2 need. 1084 // 1085 // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling 1086 // in a dependency on llvm::cfg::Update<llvm::BasicBlock*>::dump() which is 1087 // unavailable when LLVM is compiled in Release mode. 1088 const zig_cpp_cflags = exe_cflags ++ [_][]const u8{"-DNDEBUG=1"}; 1089 mod.addCSourceFiles(.{ 1090 .files = &zig_cpp_sources, 1091 .flags = &zig_cpp_cflags, 1092 }); 1093 1094 for (clang_libs) |lib_name| { 1095 mod.linkSystemLibrary(lib_name, .{}); 1096 } 1097 1098 for (lld_libs) |lib_name| { 1099 mod.linkSystemLibrary(lib_name, .{}); 1100 } 1101 1102 for (llvm_libs) |lib_name| { 1103 mod.linkSystemLibrary(lib_name, .{}); 1104 } 1105 1106 if (options.llvm_has_m68k) for (llvm_libs_m68k) |lib_name| { 1107 mod.linkSystemLibrary(lib_name, .{}); 1108 }; 1109 1110 if (options.llvm_has_csky) for (llvm_libs_csky) |lib_name| { 1111 mod.linkSystemLibrary(lib_name, .{}); 1112 }; 1113 1114 if (options.llvm_has_arc) for (llvm_libs_arc) |lib_name| { 1115 mod.linkSystemLibrary(lib_name, .{}); 1116 }; 1117 1118 if (options.llvm_has_xtensa) for (llvm_libs_xtensa) |lib_name| { 1119 mod.linkSystemLibrary(lib_name, .{}); 1120 }; 1121 1122 mod.linkSystemLibrary("z", .{}); 1123 mod.linkSystemLibrary("zstd", .{}); 1124 1125 if (mod.resolved_target.?.result.os.tag != .windows or mod.resolved_target.?.result.abi != .msvc) { 1126 // This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries. 1127 mod.linkSystemLibrary("c++", .{}); 1128 } 1129 1130 if (mod.resolved_target.?.result.os.tag == .windows) { 1131 mod.linkSystemLibrary("version", .{}); 1132 mod.linkSystemLibrary("uuid", .{}); 1133 mod.linkSystemLibrary("ole32", .{}); 1134 } 1135 } 1136 1137 fn addCxxKnownPath( 1138 b: *std.Build, 1139 ctx: CMakeConfig, 1140 exe: *std.Build.Step.Compile, 1141 objname: []const u8, 1142 errtxt: ?[]const u8, 1143 need_cpp_includes: bool, 1144 ) !void { 1145 if (!std.process.can_spawn) 1146 return error.RequiredLibraryNotFound; 1147 1148 const path_padded = run: { 1149 var args = std.array_list.Managed([]const u8).init(b.allocator); 1150 try args.append(ctx.cxx_compiler); 1151 var it = std.mem.tokenizeAny(u8, ctx.cxx_compiler_arg1, &std.ascii.whitespace); 1152 while (it.next()) |arg| try args.append(arg); 1153 try args.append(b.fmt("-print-file-name={s}", .{objname})); 1154 break :run b.run(args.items); 1155 }; 1156 var tokenizer = mem.tokenizeAny(u8, path_padded, "\r\n"); 1157 const path_unpadded = tokenizer.next().?; 1158 if (mem.eql(u8, path_unpadded, objname)) { 1159 if (errtxt) |msg| { 1160 std.debug.print("{s}", .{msg}); 1161 } else { 1162 std.debug.print("Unable to determine path to {s}\n", .{objname}); 1163 } 1164 return error.RequiredLibraryNotFound; 1165 } 1166 // By default, explicit library paths are not checked for being linker scripts, 1167 // but libc++ may very well be one, so force all inputs to be checked when passing 1168 // an explicit path to libc++. 1169 exe.allow_so_scripts = true; 1170 exe.root_module.addObjectFile(.{ .cwd_relative = path_unpadded }); 1171 1172 // TODO a way to integrate with system c++ include files here 1173 // c++ -E -Wp,-v -xc++ /dev/null 1174 if (need_cpp_includes) { 1175 // I used these temporarily for testing something but we obviously need a 1176 // more general purpose solution here. 1177 //exe.root_module.addIncludePath("/nix/store/2lr0fc0ak8rwj0k8n3shcyz1hz63wzma-gcc-11.3.0/include/c++/11.3.0"); 1178 //exe.root_module.addIncludePath("/nix/store/2lr0fc0ak8rwj0k8n3shcyz1hz63wzma-gcc-11.3.0/include/c++/11.3.0/x86_64-unknown-linux-gnu"); 1179 } 1180 } 1181 1182 fn addCMakeLibraryList(mod: *std.Build.Module, list: []const u8) void { 1183 var it = mem.tokenizeScalar(u8, list, ';'); 1184 while (it.next()) |lib| { 1185 if (mem.startsWith(u8, lib, "-l")) { 1186 mod.linkSystemLibrary(lib["-l".len..], .{}); 1187 } else if (mod.resolved_target.?.result.os.tag == .windows and 1188 mem.endsWith(u8, lib, ".lib") and !fs.path.isAbsolute(lib)) 1189 { 1190 mod.linkSystemLibrary(lib[0 .. lib.len - ".lib".len], .{}); 1191 } else { 1192 mod.addObjectFile(.{ .cwd_relative = lib }); 1193 } 1194 } 1195 } 1196 1197 const CMakeConfig = struct { 1198 llvm_linkage: std.builtin.LinkMode, 1199 cmake_binary_dir: []const u8, 1200 cmake_prefix_path: []const u8, 1201 cmake_static_library_prefix: []const u8, 1202 cmake_static_library_suffix: []const u8, 1203 cxx_compiler: []const u8, 1204 cxx_compiler_arg1: []const u8, 1205 lld_include_dir: []const u8, 1206 lld_libraries: []const u8, 1207 clang_libraries: []const u8, 1208 llvm_lib_dir: []const u8, 1209 llvm_include_dir: []const u8, 1210 llvm_libraries: []const u8, 1211 dia_guids_lib: []const u8, 1212 system_libcxx: []const u8, 1213 }; 1214 1215 const max_config_h_bytes = 1 * 1024 * 1024; 1216 1217 fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 { 1218 if (config_h_path_option) |path| { 1219 var config_h_or_err = fs.cwd().openFile(path, .{}); 1220 if (config_h_or_err) |*file| { 1221 file.close(); 1222 return path; 1223 } else |_| { 1224 std.log.err("Could not open provided config.h: \"{s}\"", .{path}); 1225 std.process.exit(1); 1226 } 1227 } 1228 1229 var check_dir = fs.path.dirname(b.graph.zig_exe).?; 1230 while (true) { 1231 var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable; 1232 defer dir.close(); 1233 1234 // Check if config.h is present in dir 1235 var config_h_or_err = dir.openFile("config.h", .{}); 1236 if (config_h_or_err) |*file| { 1237 file.close(); 1238 return fs.path.join( 1239 b.allocator, 1240 &[_][]const u8{ check_dir, "config.h" }, 1241 ) catch unreachable; 1242 } else |e| switch (e) { 1243 error.FileNotFound => {}, 1244 else => unreachable, 1245 } 1246 1247 // Check if we reached the source root by looking for .git, and bail if so 1248 var git_dir_or_err = dir.openDir(".git", .{}); 1249 if (git_dir_or_err) |*git_dir| { 1250 git_dir.close(); 1251 return null; 1252 } else |_| {} 1253 1254 // Otherwise, continue search in the parent directory 1255 const new_check_dir = fs.path.dirname(check_dir); 1256 if (new_check_dir == null or mem.eql(u8, new_check_dir.?, check_dir)) { 1257 return null; 1258 } 1259 check_dir = new_check_dir.?; 1260 } 1261 } 1262 1263 fn parseConfigH(b: *std.Build, config_h_text: []const u8) ?CMakeConfig { 1264 var ctx: CMakeConfig = .{ 1265 .llvm_linkage = undefined, 1266 .cmake_binary_dir = undefined, 1267 .cmake_prefix_path = undefined, 1268 .cmake_static_library_prefix = undefined, 1269 .cmake_static_library_suffix = undefined, 1270 .cxx_compiler = undefined, 1271 .cxx_compiler_arg1 = "", 1272 .lld_include_dir = undefined, 1273 .lld_libraries = undefined, 1274 .clang_libraries = undefined, 1275 .llvm_lib_dir = undefined, 1276 .llvm_include_dir = undefined, 1277 .llvm_libraries = undefined, 1278 .dia_guids_lib = undefined, 1279 .system_libcxx = undefined, 1280 }; 1281 1282 const mappings = [_]struct { prefix: []const u8, field: []const u8 }{ 1283 .{ 1284 .prefix = "#define ZIG_CMAKE_BINARY_DIR ", 1285 .field = "cmake_binary_dir", 1286 }, 1287 .{ 1288 .prefix = "#define ZIG_CMAKE_PREFIX_PATH ", 1289 .field = "cmake_prefix_path", 1290 }, 1291 .{ 1292 .prefix = "#define ZIG_CMAKE_STATIC_LIBRARY_PREFIX ", 1293 .field = "cmake_static_library_prefix", 1294 }, 1295 .{ 1296 .prefix = "#define ZIG_CMAKE_STATIC_LIBRARY_SUFFIX ", 1297 .field = "cmake_static_library_suffix", 1298 }, 1299 .{ 1300 .prefix = "#define ZIG_CXX_COMPILER ", 1301 .field = "cxx_compiler", 1302 }, 1303 .{ 1304 .prefix = "#define ZIG_CXX_COMPILER_ARG1 ", 1305 .field = "cxx_compiler_arg1", 1306 }, 1307 .{ 1308 .prefix = "#define ZIG_LLD_INCLUDE_PATH ", 1309 .field = "lld_include_dir", 1310 }, 1311 .{ 1312 .prefix = "#define ZIG_LLD_LIBRARIES ", 1313 .field = "lld_libraries", 1314 }, 1315 .{ 1316 .prefix = "#define ZIG_CLANG_LIBRARIES ", 1317 .field = "clang_libraries", 1318 }, 1319 .{ 1320 .prefix = "#define ZIG_LLVM_LIBRARIES ", 1321 .field = "llvm_libraries", 1322 }, 1323 .{ 1324 .prefix = "#define ZIG_DIA_GUIDS_LIB ", 1325 .field = "dia_guids_lib", 1326 }, 1327 .{ 1328 .prefix = "#define ZIG_LLVM_INCLUDE_PATH ", 1329 .field = "llvm_include_dir", 1330 }, 1331 .{ 1332 .prefix = "#define ZIG_LLVM_LIB_PATH ", 1333 .field = "llvm_lib_dir", 1334 }, 1335 .{ 1336 .prefix = "#define ZIG_SYSTEM_LIBCXX", 1337 .field = "system_libcxx", 1338 }, 1339 // .prefix = ZIG_LLVM_LINK_MODE parsed manually below 1340 }; 1341 1342 var lines_it = mem.tokenizeAny(u8, config_h_text, "\r\n"); 1343 while (lines_it.next()) |line| { 1344 inline for (mappings) |mapping| { 1345 if (mem.startsWith(u8, line, mapping.prefix)) { 1346 var it = mem.splitScalar(u8, line, '"'); 1347 _ = it.first(); // skip the stuff before the quote 1348 const quoted = it.next().?; // the stuff inside the quote 1349 const trimmed = mem.trim(u8, quoted, " "); 1350 @field(ctx, mapping.field) = toNativePathSep(b, trimmed); 1351 } 1352 } 1353 if (mem.startsWith(u8, line, "#define ZIG_LLVM_LINK_MODE ")) { 1354 var it = mem.splitScalar(u8, line, '"'); 1355 _ = it.next().?; // skip the stuff before the quote 1356 const quoted = it.next().?; // the stuff inside the quote 1357 ctx.llvm_linkage = if (mem.eql(u8, quoted, "shared")) .dynamic else .static; 1358 } 1359 } 1360 return ctx; 1361 } 1362 1363 fn toNativePathSep(b: *std.Build, s: []const u8) []u8 { 1364 const duplicated = b.allocator.dupe(u8, s) catch unreachable; 1365 for (duplicated) |*byte| switch (byte.*) { 1366 '/' => byte.* = fs.path.sep, 1367 else => {}, 1368 }; 1369 return duplicated; 1370 } 1371 1372 const zig_cpp_sources = [_][]const u8{ 1373 // These are planned to stay even when we are self-hosted. 1374 "src/zig_llvm.cpp", 1375 "src/zig_clang.cpp", 1376 "src/zig_llvm-ar.cpp", 1377 "src/zig_clang_driver.cpp", 1378 "src/zig_clang_cc1_main.cpp", 1379 "src/zig_clang_cc1as_main.cpp", 1380 }; 1381 1382 const clang_libs = [_][]const u8{ 1383 "clangFrontendTool", 1384 "clangCodeGen", 1385 "clangFrontend", 1386 "clangDriver", 1387 "clangSerialization", 1388 "clangSema", 1389 "clangStaticAnalyzerFrontend", 1390 "clangStaticAnalyzerCheckers", 1391 "clangStaticAnalyzerCore", 1392 "clangAnalysis", 1393 "clangASTMatchers", 1394 "clangAST", 1395 "clangParse", 1396 "clangSema", 1397 "clangAPINotes", 1398 "clangBasic", 1399 "clangEdit", 1400 "clangLex", 1401 "clangARCMigrate", 1402 "clangRewriteFrontend", 1403 "clangRewrite", 1404 "clangCrossTU", 1405 "clangIndex", 1406 "clangToolingCore", 1407 "clangExtractAPI", 1408 "clangSupport", 1409 "clangInstallAPI", 1410 "clangAST", 1411 }; 1412 const lld_libs = [_][]const u8{ 1413 "lldMinGW", 1414 "lldELF", 1415 "lldCOFF", 1416 "lldWasm", 1417 "lldMachO", 1418 "lldCommon", 1419 }; 1420 // This list can be re-generated with `llvm-config --libfiles` and then 1421 // reformatting using your favorite text editor. Note we do not execute 1422 // `llvm-config` here because we are cross compiling. Also omit LLVMTableGen 1423 // from these libs. 1424 const llvm_libs = [_][]const u8{ 1425 "LLVMWindowsManifest", 1426 "LLVMXRay", 1427 "LLVMLibDriver", 1428 "LLVMDlltoolDriver", 1429 "LLVMTelemetry", 1430 "LLVMTextAPIBinaryReader", 1431 "LLVMCoverage", 1432 "LLVMLineEditor", 1433 "LLVMXCoreDisassembler", 1434 "LLVMXCoreCodeGen", 1435 "LLVMXCoreDesc", 1436 "LLVMXCoreInfo", 1437 "LLVMX86TargetMCA", 1438 "LLVMX86Disassembler", 1439 "LLVMX86AsmParser", 1440 "LLVMX86CodeGen", 1441 "LLVMX86Desc", 1442 "LLVMX86Info", 1443 "LLVMWebAssemblyDisassembler", 1444 "LLVMWebAssemblyAsmParser", 1445 "LLVMWebAssemblyCodeGen", 1446 "LLVMWebAssemblyUtils", 1447 "LLVMWebAssemblyDesc", 1448 "LLVMWebAssemblyInfo", 1449 "LLVMVEDisassembler", 1450 "LLVMVEAsmParser", 1451 "LLVMVECodeGen", 1452 "LLVMVEDesc", 1453 "LLVMVEInfo", 1454 "LLVMSystemZDisassembler", 1455 "LLVMSystemZAsmParser", 1456 "LLVMSystemZCodeGen", 1457 "LLVMSystemZDesc", 1458 "LLVMSystemZInfo", 1459 "LLVMSPIRVCodeGen", 1460 "LLVMSPIRVDesc", 1461 "LLVMSPIRVInfo", 1462 "LLVMSPIRVAnalysis", 1463 "LLVMSparcDisassembler", 1464 "LLVMSparcAsmParser", 1465 "LLVMSparcCodeGen", 1466 "LLVMSparcDesc", 1467 "LLVMSparcInfo", 1468 "LLVMRISCVTargetMCA", 1469 "LLVMRISCVDisassembler", 1470 "LLVMRISCVAsmParser", 1471 "LLVMRISCVCodeGen", 1472 "LLVMRISCVDesc", 1473 "LLVMRISCVInfo", 1474 "LLVMPowerPCDisassembler", 1475 "LLVMPowerPCAsmParser", 1476 "LLVMPowerPCCodeGen", 1477 "LLVMPowerPCDesc", 1478 "LLVMPowerPCInfo", 1479 "LLVMNVPTXCodeGen", 1480 "LLVMNVPTXDesc", 1481 "LLVMNVPTXInfo", 1482 "LLVMMSP430Disassembler", 1483 "LLVMMSP430AsmParser", 1484 "LLVMMSP430CodeGen", 1485 "LLVMMSP430Desc", 1486 "LLVMMSP430Info", 1487 "LLVMMipsDisassembler", 1488 "LLVMMipsAsmParser", 1489 "LLVMMipsCodeGen", 1490 "LLVMMipsDesc", 1491 "LLVMMipsInfo", 1492 "LLVMLoongArchDisassembler", 1493 "LLVMLoongArchAsmParser", 1494 "LLVMLoongArchCodeGen", 1495 "LLVMLoongArchDesc", 1496 "LLVMLoongArchInfo", 1497 "LLVMLanaiDisassembler", 1498 "LLVMLanaiCodeGen", 1499 "LLVMLanaiAsmParser", 1500 "LLVMLanaiDesc", 1501 "LLVMLanaiInfo", 1502 "LLVMHexagonDisassembler", 1503 "LLVMHexagonCodeGen", 1504 "LLVMHexagonAsmParser", 1505 "LLVMHexagonDesc", 1506 "LLVMHexagonInfo", 1507 "LLVMBPFDisassembler", 1508 "LLVMBPFAsmParser", 1509 "LLVMBPFCodeGen", 1510 "LLVMBPFDesc", 1511 "LLVMBPFInfo", 1512 "LLVMAVRDisassembler", 1513 "LLVMAVRAsmParser", 1514 "LLVMAVRCodeGen", 1515 "LLVMAVRDesc", 1516 "LLVMAVRInfo", 1517 "LLVMARMDisassembler", 1518 "LLVMARMAsmParser", 1519 "LLVMARMCodeGen", 1520 "LLVMARMDesc", 1521 "LLVMARMUtils", 1522 "LLVMARMInfo", 1523 "LLVMAMDGPUTargetMCA", 1524 "LLVMAMDGPUDisassembler", 1525 "LLVMAMDGPUAsmParser", 1526 "LLVMAMDGPUCodeGen", 1527 "LLVMAMDGPUDesc", 1528 "LLVMAMDGPUUtils", 1529 "LLVMAMDGPUInfo", 1530 "LLVMAArch64Disassembler", 1531 "LLVMAArch64AsmParser", 1532 "LLVMAArch64CodeGen", 1533 "LLVMAArch64Desc", 1534 "LLVMAArch64Utils", 1535 "LLVMAArch64Info", 1536 "LLVMOrcDebugging", 1537 "LLVMOrcJIT", 1538 "LLVMWindowsDriver", 1539 "LLVMMCJIT", 1540 "LLVMJITLink", 1541 "LLVMInterpreter", 1542 "LLVMExecutionEngine", 1543 "LLVMRuntimeDyld", 1544 "LLVMOrcTargetProcess", 1545 "LLVMOrcShared", 1546 "LLVMDWP", 1547 "LLVMDebugInfoLogicalView", 1548 "LLVMDebugInfoGSYM", 1549 "LLVMOption", 1550 "LLVMObjectYAML", 1551 "LLVMObjCopy", 1552 "LLVMMCA", 1553 "LLVMMCDisassembler", 1554 "LLVMLTO", 1555 "LLVMPasses", 1556 "LLVMHipStdPar", 1557 "LLVMCFGuard", 1558 "LLVMCoroutines", 1559 "LLVMipo", 1560 "LLVMVectorize", 1561 "LLVMSandboxIR", 1562 "LLVMLinker", 1563 "LLVMInstrumentation", 1564 "LLVMFrontendOpenMP", 1565 "LLVMFrontendOffloading", 1566 "LLVMFrontendOpenACC", 1567 "LLVMFrontendHLSL", 1568 "LLVMFrontendDriver", 1569 "LLVMFrontendAtomic", 1570 "LLVMExtensions", 1571 "LLVMDWARFLinkerParallel", 1572 "LLVMDWARFLinkerClassic", 1573 "LLVMDWARFLinker", 1574 "LLVMGlobalISel", 1575 "LLVMMIRParser", 1576 "LLVMAsmPrinter", 1577 "LLVMSelectionDAG", 1578 "LLVMCodeGen", 1579 "LLVMTarget", 1580 "LLVMObjCARCOpts", 1581 "LLVMCodeGenTypes", 1582 "LLVMCGData", 1583 "LLVMIRPrinter", 1584 "LLVMInterfaceStub", 1585 "LLVMFileCheck", 1586 "LLVMFuzzMutate", 1587 "LLVMScalarOpts", 1588 "LLVMInstCombine", 1589 "LLVMAggressiveInstCombine", 1590 "LLVMTransformUtils", 1591 "LLVMBitWriter", 1592 "LLVMAnalysis", 1593 "LLVMProfileData", 1594 "LLVMSymbolize", 1595 "LLVMDebugInfoBTF", 1596 "LLVMDebugInfoPDB", 1597 "LLVMDebugInfoMSF", 1598 "LLVMDebugInfoCodeView", 1599 "LLVMDebugInfoDWARF", 1600 "LLVMObject", 1601 "LLVMTextAPI", 1602 "LLVMMCParser", 1603 "LLVMIRReader", 1604 "LLVMAsmParser", 1605 "LLVMMC", 1606 "LLVMBitReader", 1607 "LLVMFuzzerCLI", 1608 "LLVMCore", 1609 "LLVMRemarks", 1610 "LLVMBitstreamReader", 1611 "LLVMBinaryFormat", 1612 "LLVMTargetParser", 1613 "LLVMSupport", 1614 "LLVMDemangle", 1615 }; 1616 const llvm_libs_m68k = [_][]const u8{ 1617 "LLVMM68kDisassembler", 1618 "LLVMM68kAsmParser", 1619 "LLVMM68kCodeGen", 1620 "LLVMM68kDesc", 1621 "LLVMM68kInfo", 1622 }; 1623 const llvm_libs_csky = [_][]const u8{ 1624 "LLVMCSKYDisassembler", 1625 "LLVMCSKYAsmParser", 1626 "LLVMCSKYCodeGen", 1627 "LLVMCSKYDesc", 1628 "LLVMCSKYInfo", 1629 }; 1630 const llvm_libs_arc = [_][]const u8{ 1631 "LLVMARCDisassembler", 1632 "LLVMARCCodeGen", 1633 "LLVMARCDesc", 1634 "LLVMARCInfo", 1635 }; 1636 const llvm_libs_xtensa = [_][]const u8{ 1637 "LLVMXtensaDisassembler", 1638 "LLVMXtensaAsmParser", 1639 "LLVMXtensaCodeGen", 1640 "LLVMXtensaDesc", 1641 "LLVMXtensaInfo", 1642 }; 1643 1644 fn generateLangRef(b: *std.Build) std.Build.LazyPath { 1645 const doctest_exe = b.addExecutable(.{ 1646 .name = "doctest", 1647 .root_module = b.createModule(.{ 1648 .root_source_file = b.path("tools/doctest.zig"), 1649 .target = b.graph.host, 1650 .optimize = .Debug, 1651 }), 1652 }); 1653 1654 var dir = b.build_root.handle.openDir("doc/langref", .{ .iterate = true }) catch |err| { 1655 std.debug.panic("unable to open '{f}doc/langref' directory: {s}", .{ 1656 b.build_root, @errorName(err), 1657 }); 1658 }; 1659 defer dir.close(); 1660 1661 var wf = b.addWriteFiles(); 1662 1663 var it = dir.iterateAssumeFirstIteration(); 1664 while (it.next() catch @panic("failed to read dir")) |entry| { 1665 if (std.mem.startsWith(u8, entry.name, ".") or entry.kind != .file) 1666 continue; 1667 1668 const out_basename = b.fmt("{s}.out", .{std.fs.path.stem(entry.name)}); 1669 const cmd = b.addRunArtifact(doctest_exe); 1670 cmd.addArgs(&.{ 1671 "--zig", b.graph.zig_exe, 1672 // TODO: enhance doctest to use "--listen=-" rather than operating 1673 // in a temporary directory 1674 "--cache-root", b.cache_root.path orelse ".", 1675 }); 1676 cmd.addArgs(&.{ "--zig-lib-dir", b.fmt("{f}", .{b.graph.zig_lib_directory}) }); 1677 cmd.addArgs(&.{"-i"}); 1678 cmd.addFileArg(b.path(b.fmt("doc/langref/{s}", .{entry.name}))); 1679 1680 cmd.addArgs(&.{"-o"}); 1681 _ = wf.addCopyFile(cmd.addOutputFileArg(out_basename), out_basename); 1682 } 1683 1684 const docgen_exe = b.addExecutable(.{ 1685 .name = "docgen", 1686 .root_module = b.createModule(.{ 1687 .root_source_file = b.path("tools/docgen.zig"), 1688 .target = b.graph.host, 1689 .optimize = .Debug, 1690 }), 1691 }); 1692 1693 const docgen_cmd = b.addRunArtifact(docgen_exe); 1694 docgen_cmd.addArgs(&.{"--code-dir"}); 1695 docgen_cmd.addDirectoryArg(wf.getDirectory()); 1696 1697 docgen_cmd.addFileArg(b.path("doc/langref.html.in")); 1698 return docgen_cmd.addOutputFileArg("langref.html"); 1699 } 1700 1701 fn superHtmlCheck(b: *std.Build, html_file: std.Build.LazyPath) *std.Build.Step { 1702 const run_superhtml = b.addSystemCommand(&.{ 1703 "superhtml", "check", 1704 }); 1705 run_superhtml.addFileArg(html_file); 1706 run_superhtml.expectExitCode(0); 1707 return &run_superhtml.step; 1708 } 1709 1710 const AirGenResult = struct { 1711 step: *std.Build.Step, 1712 air_dir: std.Build.LazyPath, 1713 }; 1714 1715 fn addAirGen( 1716 b: *std.Build, 1717 exe_options: *std.Build.Step.Options, 1718 optimize: std.builtin.OptimizeMode, 1719 ) AirGenResult { 1720 const zig_internals_mod = b.createModule(.{ 1721 .root_source_file = b.path("src/test_exports.zig"), 1722 }); 1723 const aro_mod = b.createModule(.{ 1724 .root_source_file = b.path("lib/compiler/aro/aro.zig"), 1725 }); 1726 const aro_translate_c_mod = b.createModule(.{ 1727 .root_source_file = b.path("lib/compiler/aro_translate_c.zig"), 1728 }); 1729 aro_translate_c_mod.addImport("aro", aro_mod); 1730 zig_internals_mod.addImport("aro", aro_mod); 1731 zig_internals_mod.addImport("aro_translate_c", aro_translate_c_mod); 1732 zig_internals_mod.addOptions("build_options", exe_options); 1733 1734 const dumper_mod = b.createModule(.{ 1735 .root_source_file = b.path("src/verbose_air.zig"), 1736 .target = b.graph.host, 1737 .optimize = optimize, 1738 }); 1739 dumper_mod.addImport("zig_internals", zig_internals_mod); 1740 dumper_mod.linkSystemLibrary("c", .{}); 1741 1742 const gen_mod = b.createModule(.{ 1743 .root_source_file = b.path("src/verbose_air_gen.zig"), 1744 .target = b.graph.host, 1745 .optimize = optimize, 1746 }); 1747 gen_mod.addImport("verbose_air", dumper_mod); 1748 gen_mod.addImport("zig_internals", zig_internals_mod); 1749 gen_mod.linkSystemLibrary("c", .{}); 1750 1751 const gen_exe = b.addExecutable(.{ 1752 .name = "air_gen", 1753 .root_module = gen_mod, 1754 .use_llvm = false, 1755 .use_lld = false, 1756 }); 1757 1758 // Run generator: air_gen <output_dir> [<name> <resolved_path>]... 1759 const gen_run = b.addRunArtifact(gen_exe); 1760 const air_dir = gen_run.addOutputDirectoryArg("air"); 1761 // Add non-lib/std/ corpus files as name/path pairs. 1762 // lib/std/ files are compiled via std.zig root inside air_gen. 1763 // stage0/sema_tests/ files are also included (standalone compilation). 1764 for (corpus.files) |path| { 1765 if (std.mem.startsWith(u8, path, "lib/std/")) continue; 1766 gen_run.addArg(path); 1767 gen_run.addFileArg(b.path(path)); 1768 } 1769 1770 return .{ .step = &gen_run.step, .air_dir = air_dir }; 1771 } 1772 1773 fn addZig0TestStep( 1774 b: *std.Build, 1775 step: *std.Build.Step, 1776 target: std.Build.ResolvedTarget, 1777 optimize: std.builtin.OptimizeMode, 1778 cc: []const u8, 1779 no_exec: bool, 1780 valgrind: bool, 1781 test_timeout: ?[]const u8, 1782 air_gen: AirGenResult, 1783 ) void { 1784 // Step 1: Compile Zig test code to .o (cached independently of C objects). 1785 // NOTE: test_mod does NOT import zig_internals — stage0 tests are fast. 1786 const test_mod = b.createModule(.{ 1787 .root_source_file = b.path("stage0_test_root.zig"), 1788 .optimize = optimize, 1789 .target = target, 1790 .valgrind = true, 1791 }); 1792 test_mod.addIncludePath(b.path("stage0")); 1793 test_mod.linkSystemLibrary("c", .{}); 1794 // Make pre-computed AIR data available to tests. 1795 test_mod.addAnonymousImport("air_tag_names", .{ 1796 .root_source_file = air_gen.air_dir.path(b, "tag_names.zig"), 1797 }); 1798 test_mod.addAnonymousImport("air_data", .{ 1799 .root_source_file = air_gen.air_dir.path(b, "air_data.zig"), 1800 }); 1801 1802 const test_obj = b.addTest(.{ 1803 .root_module = test_mod, 1804 .emit_object = true, 1805 .use_llvm = false, 1806 .use_lld = false, 1807 }); 1808 test_obj.step.dependOn(air_gen.step); 1809 1810 // Step 2: Link test_obj + C objects into final executable. 1811 // No more dumper_obj — AIR is pre-computed at build time. 1812 const link_mod = b.createModule(.{ 1813 .target = target, 1814 .optimize = optimize, 1815 }); 1816 link_mod.addObject(test_obj); 1817 addZig0CSources(b, link_mod, cc, optimize); 1818 link_mod.linkSystemLibrary("c", .{}); 1819 1820 const test_exe = b.addExecutable(.{ 1821 .name = "test", 1822 .root_module = link_mod, 1823 }); 1824 1825 const timeout: ?[]const u8 = test_timeout orelse if (valgrind) null else "300"; 1826 1827 if (no_exec) { 1828 const install = b.addInstallArtifact(test_exe, .{}); 1829 step.dependOn(&install.step); 1830 } else { 1831 // Step 3: Run with test IPC protocol. 1832 const run = std.Build.Step.Run.create(b, b.fmt("test ({s})", .{cc})); 1833 if (valgrind) { 1834 run.addArgs(&.{ 1835 "valgrind", 1836 "--error-exitcode=2", 1837 "--leak-check=full", 1838 "--show-leak-kinds=all", 1839 "--errors-for-leak-kinds=all", 1840 "--track-fds=yes", 1841 "--quiet", 1842 }); 1843 } else if (timeout) |t| { 1844 run.addArgs(&.{ "timeout", t }); 1845 } 1846 run.addArtifactArg(test_exe); 1847 run.enableTestRunnerMode(); 1848 step.dependOn(&run.step); 1849 } 1850 } 1851 1852 fn addZig0CSources( 1853 b: *std.Build, 1854 mod: *std.Build.Module, 1855 cc: []const u8, 1856 optimize: std.builtin.OptimizeMode, 1857 ) void { 1858 if (std.mem.eql(u8, cc, "zig")) { 1859 mod.addCSourceFiles(.{ 1860 .root = b.path("stage0"), 1861 .files = zig0_c_lib_files, 1862 .flags = zig0_cflags, 1863 }); 1864 } else for (zig0_c_lib_files) |cfile| { 1865 const cc1 = b.addSystemCommand(&.{cc}); 1866 cc1.addArgs(zig0_cflags ++ .{"-g"}); 1867 cc1.addArg(switch (optimize) { 1868 .Debug => "-O0", 1869 .ReleaseFast, .ReleaseSafe => "-O3", 1870 .ReleaseSmall => "-Os", 1871 }); 1872 cc1.addArg("-c"); 1873 cc1.addFileArg(b.path(b.fmt("stage0/{s}", .{cfile}))); 1874 // Track headers as extra inputs so changes invalidate the cache. 1875 for (zig0_headers) |h| cc1.addFileInput(b.path(b.fmt("stage0/{s}", .{h}))); 1876 cc1.addArg("-o"); 1877 mod.addObjectFile(cc1.addOutputFileArg(b.fmt("{s}.o", .{cfile[0 .. cfile.len - 2]}))); 1878 } 1879 }