| 1 | const std = @import("std"); |
| 2 | const BufMap = std.BufMap; |
| 3 | const mem = std.mem; |
| 4 | const fs = std.fs; |
| 5 | const InstallDirectoryOptions = std.Build.InstallDirectoryOptions; |
| 6 | const assert = std.debug.assert; |
| 7 | const Io = std.Io; |
| 8 | |
| 9 | const tests = @import("test/tests.zig"); |
| 10 | const DevEnv = @import("src/dev.zig").Env; |
| 11 | |
| 12 | const zig_version: std.SemanticVersion = .{ .major = 0, .minor = 17, .patch = 0 }; |
| 13 | const stack_size = 46 * 1024 * 1024; |
| 14 | |
| 15 | const IoMode = enum { threaded, evented }; |
| 16 | const ValueInterpretMode = enum { direct, by_name }; |
| 17 | |
| 18 | pub fn build(b: *std.Build) !void { |
| 19 | const arena = b.graph.arena; |
| 20 | |
| 21 | const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false; |
| 22 | const target = b.standardTargetOptions(.{ |
| 23 | .default_target = .{ |
| 24 | .ofmt = if (only_c) .c else null, |
| 25 | }, |
| 26 | }); |
| 27 | const optimize = b.standardOptimizeOption(.{}); |
| 28 | |
| 29 | 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; |
| 30 | const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode"); |
| 31 | 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; |
| 32 | |
| 33 | const test_step = b.step("test", "Run all the tests"); |
| 34 | const skip_install_lib_files = b.option(bool, "no-lib", "skip copying of lib/ files and langref to installation prefix. Useful for development") orelse only_c; |
| 35 | const skip_install_langref = b.option(bool, "no-langref", "skip copying of langref to the installation prefix") orelse skip_install_lib_files; |
| 36 | const std_docs = b.option(bool, "std-docs", "include standard library autodocs") orelse false; |
| 37 | const no_bin = b.option(bool, "no-bin", "skip emitting compiler binary") orelse false; |
| 38 | const enable_superhtml = b.option(bool, "enable-superhtml", "Check langref output HTML validity") orelse false; |
| 39 | |
| 40 | const langref_file = try generateLangRef(b); |
| 41 | const install_langref = b.addInstallFileWithDir(langref_file, .prefix, "doc/langref.html"); |
| 42 | const check_langref = superHtmlCheck(b, langref_file); |
| 43 | if (enable_superhtml) install_langref.step.dependOn(check_langref); |
| 44 | |
| 45 | const check_autodocs = superHtmlCheck(b, b.path("lib/docs/index.html")); |
| 46 | if (enable_superhtml) { |
| 47 | test_step.dependOn(check_langref); |
| 48 | test_step.dependOn(check_autodocs); |
| 49 | } |
| 50 | if (!skip_install_langref) { |
| 51 | b.getInstallStep().dependOn(&install_langref.step); |
| 52 | } |
| 53 | |
| 54 | const autodoc_test = b.addObject(.{ |
| 55 | .name = "std", |
| 56 | .zig_lib_dir = b.path("lib"), |
| 57 | .root_module = b.createModule(.{ |
| 58 | .root_source_file = b.path("lib/std/std.zig"), |
| 59 | .target = target, |
| 60 | .optimize = .debug, |
| 61 | }), |
| 62 | }); |
| 63 | const install_std_docs = b.addInstallDirectory(.{ |
| 64 | .source_dir = autodoc_test.getEmittedDocs(), |
| 65 | .install_dir = .prefix, |
| 66 | .install_subdir = "doc/std", |
| 67 | }); |
| 68 | //if (enable_tidy) install_std_docs.step.dependOn(check_autodocs); |
| 69 | if (std_docs) { |
| 70 | b.getInstallStep().dependOn(&install_std_docs.step); |
| 71 | } |
| 72 | |
| 73 | const update_cpu_features = b.addExecutable(.{ |
| 74 | .name = "update-cpu-features", |
| 75 | .root_module = b.createModule(.{ |
| 76 | .root_source_file = b.path("tools/update_cpu_features.zig"), |
| 77 | .target = b.graph.host, |
| 78 | .imports = &.{.{ |
| 79 | .name = "spirv_spec", |
| 80 | .module = b.createModule(.{ |
| 81 | .root_source_file = b.path("src/codegen/spirv/spec.zig"), |
| 82 | .target = b.graph.host, |
| 83 | }), |
| 84 | }}, |
| 85 | }), |
| 86 | }); |
| 87 | const run_update_cpu_features = b.addRunArtifact(update_cpu_features); |
| 88 | run_update_cpu_features.addPassthruArgs(); |
| 89 | |
| 90 | if (flat) { |
| 91 | b.installFile("LICENSE", "LICENSE"); |
| 92 | b.installFile("README.md", "README.md"); |
| 93 | } |
| 94 | |
| 95 | const langref_step = b.step("langref", "Build and install the language reference"); |
| 96 | langref_step.dependOn(&install_langref.step); |
| 97 | |
| 98 | const std_docs_step = b.step("std-docs", "Build and install the standard library documentation"); |
| 99 | std_docs_step.dependOn(&install_std_docs.step); |
| 100 | |
| 101 | const docs_step = b.step("docs", "Build and install documentation"); |
| 102 | docs_step.dependOn(langref_step); |
| 103 | docs_step.dependOn(std_docs_step); |
| 104 | |
| 105 | const update_cpu_features_step = b.step("update-cpu-features", "Update CPU Features"); |
| 106 | update_cpu_features_step.dependOn(&run_update_cpu_features.step); |
| 107 | |
| 108 | const no_matrix = b.option(bool, "no-matrix", "Limit test matrix to exactly one target configuration") orelse false; |
| 109 | const fuzz_only = b.option(bool, "fuzz-only", "Limit test matrix to one target suitable for fuzzing") orelse false; |
| 110 | const skip_debug = b.option(bool, "skip-debug", "Main test suite skips debug builds") orelse false; |
| 111 | const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse no_matrix; |
| 112 | const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release; |
| 113 | const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release; |
| 114 | const skip_release_safe = b.option(bool, "skip-release-safe", "Main test suite skips release-safe builds") orelse skip_release; |
| 115 | const skip_non_native = b.option(bool, "skip-non-native", "Main test suite skips non-native builds") orelse no_matrix; |
| 116 | const skip_libc = b.option(bool, "skip-libc", "Main test suite skips tests that link libc") orelse false; |
| 117 | const skip_single_threaded = b.option(bool, "skip-single-threaded", "Main test suite skips tests that are single-threaded") orelse false; |
| 118 | const skip_compile_errors = b.option(bool, "skip-compile-errors", "Main test suite skips compile error tests") orelse false; |
| 119 | const skip_spirv = b.option(bool, "skip-spirv", "Main test suite skips targets with spirv32/spirv64 architecture") orelse false; |
| 120 | const skip_wasm = b.option(bool, "skip-wasm", "Main test suite skips targets with wasm32/wasm64 architecture") orelse false; |
| 121 | const skip_freebsd = b.option(bool, "skip-freebsd", "Main test suite skips targets with freebsd OS") orelse false; |
| 122 | const skip_netbsd = b.option(bool, "skip-netbsd", "Main test suite skips targets with netbsd OS") orelse false; |
| 123 | const skip_openbsd = b.option(bool, "skip-openbsd", "Main test suite skips targets with openbsd OS") orelse false; |
| 124 | const skip_windows = b.option(bool, "skip-windows", "Main test suite skips targets with windows OS") orelse false; |
| 125 | const skip_darwin = b.option(bool, "skip-darwin", "Main test suite skips targets with darwin OSs") orelse false; |
| 126 | const skip_linux = b.option(bool, "skip-linux", "Main test suite skips targets with linux OS") orelse false; |
| 127 | const skip_llvm = b.option(bool, "skip-llvm", "Main test suite skips targets that use LLVM backend") orelse false; |
| 128 | const skip_test_incremental = b.option(bool, "skip-test-incremental", "Main test step omits dependency on test-incremental step") orelse false; |
| 129 | |
| 130 | const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false; |
| 131 | |
| 132 | const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false; |
| 133 | const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse static_llvm; |
| 134 | const llvm_has_m68k = b.option( |
| 135 | bool, |
| 136 | "llvm-has-m68k", |
| 137 | "Whether LLVM has the experimental target m68k enabled", |
| 138 | ) orelse false; |
| 139 | const llvm_has_csky = b.option( |
| 140 | bool, |
| 141 | "llvm-has-csky", |
| 142 | "Whether LLVM has the experimental target csky enabled", |
| 143 | ) orelse false; |
| 144 | const llvm_has_arc = b.option( |
| 145 | bool, |
| 146 | "llvm-has-arc", |
| 147 | "Whether LLVM has the experimental target arc enabled", |
| 148 | ) orelse false; |
| 149 | const llvm_has_xtensa = b.option( |
| 150 | bool, |
| 151 | "llvm-has-xtensa", |
| 152 | "Whether LLVM has the experimental target xtensa enabled", |
| 153 | ) orelse false; |
| 154 | const enable_ios_sdk = b.option(bool, "enable-ios-sdk", "Run tests requiring presence of iOS SDK and frameworks") orelse false; |
| 155 | const enable_macos_sdk = b.option(bool, "enable-macos-sdk", "Run tests requiring presence of macOS SDK and frameworks") orelse enable_ios_sdk; |
| 156 | const enable_symlinks_windows = b.option(bool, "enable-symlinks-windows", "Run tests requiring presence of symlinks on Windows") orelse false; |
| 157 | const config_h_path_option = b.option([]const u8, "config_h", "Path to the generated config.h"); |
| 158 | |
| 159 | if (!skip_install_lib_files) { |
| 160 | b.installDirectory(.{ |
| 161 | .source_dir = b.path("lib"), |
| 162 | .install_dir = if (flat) .prefix else .lib, |
| 163 | .install_subdir = if (flat) "lib" else "zig", |
| 164 | .exclude_extensions = &[_][]const u8{ |
| 165 | // exclude files from lib/std/compress/flate/testdata |
| 166 | ".expect", |
| 167 | ".input", |
| 168 | // exclude files from lib/std/compress/lzma/testdata |
| 169 | ".lzma", |
| 170 | // exclude files from lib/std/compress/xz/testdata |
| 171 | ".xz", |
| 172 | // exclude files from lib/std/tz/ |
| 173 | ".tzif", |
| 174 | // exclude files from lib/std/tar/testdata |
| 175 | ".tar", |
| 176 | // exclude files from lib/std/zip/testdata |
| 177 | ".zip", |
| 178 | // exclude files from lib/compiler/Maker/Fetch/git/testdata |
| 179 | ".idx", |
| 180 | ".pack", |
| 181 | // others |
| 182 | "README.md", |
| 183 | }, |
| 184 | .blank_extensions = &[_][]const u8{ |
| 185 | "test.zig", |
| 186 | }, |
| 187 | }); |
| 188 | } |
| 189 | |
| 190 | if (only_install_lib_files) |
| 191 | return; |
| 192 | |
| 193 | const entitlements = b.option([]const u8, "entitlements", "Path to entitlements file for hot-code swapping without sudo on macOS"); |
| 194 | const tracy = b.option(std.Build.LazyPath, "tracy", "Enable Tracy integration. Supply path to Tracy source"); |
| 195 | const tracy_callstack = b.option(bool, "tracy-callstack", "Include callstack information with Tracy data. Does nothing if -Dtracy is not provided. Has a significant performance impact in some cases. Default: false") orelse false; |
| 196 | const tracy_allocation = b.option(bool, "tracy-allocation", "Include allocation information with Tracy data. Does nothing if -Dtracy is not provided. Default: true") orelse (tracy != null); |
| 197 | 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 6; |
| 198 | const debug_gpa = b.option(bool, "debug-allocator", "Force the compiler to use SafeAllocator") orelse false; |
| 199 | const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse (enable_llvm or only_c); |
| 200 | const sanitize_thread = b.option(bool, "sanitize-thread", "Enable thread-sanitization") orelse false; |
| 201 | const strip = b.option(bool, "strip", "Omit debug information"); |
| 202 | const valgrind = b.option(bool, "valgrind", "Enable valgrind integration"); |
| 203 | const pie = b.option(bool, "pie", "Produce a Position Independent Executable"); |
| 204 | const io_mode = b.option(IoMode, "io-mode", "How the compiler performs IO") orelse .threaded; |
| 205 | const value_interpret_mode = b.option(ValueInterpretMode, "value-interpret-mode", "How the compiler translates between 'std.lang' types and its internal datastructures") orelse .direct; |
| 206 | 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; |
| 207 | |
| 208 | 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: { |
| 209 | if (strip == true) break :blk @as(u32, 0); |
| 210 | if (optimize != .debug) break :blk 0; |
| 211 | break :blk 4; |
| 212 | }; |
| 213 | |
| 214 | const exe = addCompilerStep(b, .{ |
| 215 | .optimize = optimize, |
| 216 | .target = target, |
| 217 | .strip = strip, |
| 218 | .valgrind = valgrind, |
| 219 | .sanitize_thread = sanitize_thread, |
| 220 | .single_threaded = single_threaded, |
| 221 | }); |
| 222 | exe.pie = pie; |
| 223 | // https://codeberg.org/ziglang/zig/issues/32173 |
| 224 | exe.entitlements = if (entitlements) |p| .{ .cwd_relative = p } else null; |
| 225 | exe.use_new_linker = b.option(bool, "new-linker", "Use the new linker"); |
| 226 | |
| 227 | const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend"); |
| 228 | exe.use_llvm = use_llvm; |
| 229 | |
| 230 | if (no_bin) { |
| 231 | b.getInstallStep().dependOn(&exe.step); |
| 232 | } else { |
| 233 | const install_exe = b.addInstallArtifact(exe, .{ |
| 234 | .dest_dir = if (flat) .{ .override = .prefix } else .default, |
| 235 | }); |
| 236 | b.getInstallStep().dependOn(&install_exe.step); |
| 237 | } |
| 238 | |
| 239 | test_step.dependOn(&exe.step); |
| 240 | |
| 241 | const exe_options = b.addOptions(); |
| 242 | exe.root_module.addOptions("build_options", exe_options); |
| 243 | |
| 244 | exe_options.addOption(u32, "mem_leak_frames", mem_leak_frames); |
| 245 | exe_options.addOption(bool, "have_llvm", enable_llvm); |
| 246 | exe_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k); |
| 247 | exe_options.addOption(bool, "llvm_has_csky", llvm_has_csky); |
| 248 | exe_options.addOption(bool, "llvm_has_arc", llvm_has_arc); |
| 249 | exe_options.addOption(bool, "llvm_has_xtensa", llvm_has_xtensa); |
| 250 | exe_options.addOption(bool, "debug_gpa", debug_gpa); |
| 251 | 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); |
| 252 | exe_options.addOption(IoMode, "io_mode", io_mode); |
| 253 | exe_options.addOption(ValueInterpretMode, "value_interpret_mode", value_interpret_mode); |
| 254 | |
| 255 | if (link_libc) { |
| 256 | exe.root_module.link_libc = true; |
| 257 | } |
| 258 | |
| 259 | const is_debug = optimize == .debug; |
| 260 | const enable_debug_extensions = b.option(bool, "debug-extensions", "Enable commands and options useful for debugging the compiler") orelse is_debug; |
| 261 | const enable_logging = b.option(bool, "log", "Enable debug logging with --debug-log") orelse is_debug; |
| 262 | |
| 263 | const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git."); |
| 264 | const version_slice = if (opt_version_string) |version| version else v: { |
| 265 | if (!std.process.can_spawn) { |
| 266 | std.debug.print("error: version info cannot be retrieved from git. Zig version must be provided using -Dversion-string\n", .{}); |
| 267 | std.process.exit(1); |
| 268 | } |
| 269 | |
| 270 | // Ensure git version changes get picked up. |
| 271 | git: { |
| 272 | const io = b.graph.io; |
| 273 | const git_file = b.root.openFile(io, ".git", .{ .allow_directory = false }) catch |err| switch (err) { |
| 274 | error.IsDir => { |
| 275 | b.dependOnFileContents(b.path(".git/logs/HEAD")); |
| 276 | break :git; |
| 277 | }, |
| 278 | else => |e| return e, |
| 279 | }; |
| 280 | defer git_file.close(io); |
| 281 | var line_buffer: ["gitdir: ".len + std.Io.Dir.max_path_bytes + 1]u8 = undefined; |
| 282 | var git_file_reader = git_file.reader(io, &line_buffer); |
| 283 | if (std.mem.cutPrefix(u8, std.mem.trimEnd(u8, try git_file_reader.interface.allocRemaining( |
| 284 | arena, |
| 285 | .limited("gitdir: ".len + std.Io.Dir.max_path_bytes + "\r\n".len), |
| 286 | ), "\r\n"), "gitdir: ")) |git_dir| { |
| 287 | const head_file = b.pathJoin(&.{ git_dir, "logs", "HEAD" }); |
| 288 | b.dependOnFileContents(if (std.Io.Dir.path.isAbsolute(head_file)) |
| 289 | b.graph.cwdRelativePath(head_file) |
| 290 | else |
| 291 | b.path(head_file)); |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | const version_string = b.fmt("{d}.{d}.{d}", .{ zig_version.major, zig_version.minor, zig_version.patch }); |
| 296 | |
| 297 | var code: u8 = undefined; |
| 298 | const git_describe_untrimmed = b.runAllowFail(&[_][]const u8{ |
| 299 | "git", |
| 300 | "-C", b.fmt("{f}", .{b.root}), // affects the --git-dir argument |
| 301 | "--git-dir", ".git", // affected by the -C argument |
| 302 | "describe", "--match", "*.*.*", // |
| 303 | "--tags", "--abbrev=9", |
| 304 | }, &code, .ignore) catch { |
| 305 | break :v version_string; |
| 306 | }; |
| 307 | const git_describe = mem.trim(u8, git_describe_untrimmed, " \n\r"); |
| 308 | |
| 309 | switch (mem.countScalar(u8, git_describe, '-')) { |
| 310 | 0 => { |
| 311 | // Tagged release version (e.g. 0.10.0). |
| 312 | if (!mem.eql(u8, git_describe, version_string)) { |
| 313 | std.debug.print("Zig version '{s}' does not match Git tag '{s}'\n", .{ version_string, git_describe }); |
| 314 | std.process.exit(1); |
| 315 | } |
| 316 | break :v version_string; |
| 317 | }, |
| 318 | 2 => { |
| 319 | // Untagged development build (e.g. 0.10.0-dev.2025+ecf0050a9). |
| 320 | var it = mem.splitScalar(u8, git_describe, '-'); |
| 321 | const tagged_ancestor = it.first(); |
| 322 | const commit_height = it.next().?; |
| 323 | const commit_id = it.next().?; |
| 324 | |
| 325 | const ancestor_ver = try std.SemanticVersion.parse(tagged_ancestor); |
| 326 | if (zig_version.order(ancestor_ver) != .gt) { |
| 327 | std.debug.print("Zig version '{f}' must be greater than tagged ancestor '{f}'\n", .{ zig_version, ancestor_ver }); |
| 328 | std.process.exit(1); |
| 329 | } |
| 330 | |
| 331 | // Check that the commit hash is prefixed with a 'g' (a Git convention). |
| 332 | if (commit_id.len < 1 or commit_id[0] != 'g') { |
| 333 | std.debug.print("Unexpected `git describe` output: {s}\n", .{git_describe}); |
| 334 | break :v version_string; |
| 335 | } |
| 336 | |
| 337 | // The version is reformatted in accordance with the https://semver.org specification. |
| 338 | break :v b.fmt("{s}-dev.{s}+{s}", .{ version_string, commit_height, commit_id[1..] }); |
| 339 | }, |
| 340 | else => { |
| 341 | std.debug.print("Unexpected `git describe` output: {s}\n", .{git_describe}); |
| 342 | break :v version_string; |
| 343 | }, |
| 344 | } |
| 345 | }; |
| 346 | const version = try arena.dupeSentinel(u8, version_slice, 0); |
| 347 | exe_options.addOption([:0]const u8, "version", version); |
| 348 | |
| 349 | if (enable_llvm) { |
| 350 | const cmake_cfg = if (static_llvm) null else blk: { |
| 351 | const io = b.graph.io; |
| 352 | const cwd: Io.Dir = .cwd(); |
| 353 | if (findConfigH(b, config_h_path_option)) |config_h_path| { |
| 354 | const file_contents = cwd.readFileAlloc(io, config_h_path, arena, .limited(max_config_h_bytes)) catch unreachable; |
| 355 | break :blk parseConfigH(b, file_contents); |
| 356 | } else { |
| 357 | std.log.warn("config.h could not be located automatically. Consider providing it explicitly via \"-Dconfig_h\"", .{}); |
| 358 | break :blk null; |
| 359 | } |
| 360 | }; |
| 361 | |
| 362 | if (cmake_cfg) |cfg| { |
| 363 | // Inside this code path, we have to coordinate with system packaged LLVM, Clang, and LLD. |
| 364 | // That means we also have to rely on stage1 compiled c++ files. We parse config.h to find |
| 365 | // the information passed on to us from cmake. |
| 366 | if (cfg.cmake_prefix_path.len > 0) { |
| 367 | var it = mem.tokenizeScalar(u8, cfg.cmake_prefix_path, ';'); |
| 368 | while (it.next()) |path| { |
| 369 | b.addSearchPrefix(path); |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx); |
| 374 | } else { |
| 375 | // Here we are -Denable-llvm but no cmake integration. |
| 376 | try addStaticLlvmOptionsToModule(exe.root_module, .{ |
| 377 | .llvm_has_m68k = llvm_has_m68k, |
| 378 | .llvm_has_csky = llvm_has_csky, |
| 379 | .llvm_has_arc = llvm_has_arc, |
| 380 | .llvm_has_xtensa = llvm_has_xtensa, |
| 381 | }); |
| 382 | } |
| 383 | if (target.result.os.tag == .windows) { |
| 384 | // LLVM depends on networking as of version 18. |
| 385 | exe.root_module.linkSystemLibrary("ws2_32", .{}); |
| 386 | |
| 387 | exe.root_module.linkSystemLibrary("version", .{}); |
| 388 | exe.root_module.linkSystemLibrary("uuid", .{}); |
| 389 | exe.root_module.linkSystemLibrary("ole32", .{}); |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | const semver = try std.SemanticVersion.parse(version); |
| 394 | exe_options.addOption(std.SemanticVersion, "semver", semver); |
| 395 | |
| 396 | exe_options.addOption(bool, "enable_debug_extensions", enable_debug_extensions); |
| 397 | exe_options.addOption(bool, "enable_logging", enable_logging); |
| 398 | exe_options.addOption(bool, "enable_tracy", tracy != null); |
| 399 | exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack); |
| 400 | exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation); |
| 401 | exe_options.addOption(u32, "tracy_callstack_depth", tracy_callstack_depth); |
| 402 | exe_options.addOption(bool, "value_tracing", value_tracing); |
| 403 | if (tracy) |tracy_dir| { |
| 404 | const tracy_mod = b.createModule(.{ |
| 405 | .target = target, |
| 406 | // Always build Tracy in ReleaseFast so that it doesn't make -Odebug compiler builds unusable. |
| 407 | .optimize = .fast, |
| 408 | .root_source_file = null, |
| 409 | .link_libc = true, |
| 410 | .link_libcpp = true, |
| 411 | }); |
| 412 | |
| 413 | tracy_mod.addCMacro("TRACY_ENABLE", "1"); |
| 414 | |
| 415 | if (!tracy_callstack) { |
| 416 | tracy_mod.addCMacro("TRACY_NO_CALLSTACK", "1"); |
| 417 | } |
| 418 | |
| 419 | tracy_mod.addIncludePath(tracy_dir); |
| 420 | tracy_mod.addCSourceFile(.{ .file = tracy_dir.path(b, "public/TracyClient.cpp") }); |
| 421 | |
| 422 | if (target.result.os.tag == .windows) { |
| 423 | tracy_mod.linkSystemLibrary("dbghelp", .{}); |
| 424 | tracy_mod.linkSystemLibrary("ws2_32", .{}); |
| 425 | } |
| 426 | |
| 427 | exe.root_module.addImport("tracy", tracy_mod); |
| 428 | } |
| 429 | |
| 430 | const test_filters = b.option([]const []const u8, "test-filter", "Skip tests that do not match any filter") orelse &[0][]const u8{}; |
| 431 | 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{}; |
| 432 | const test_extra_targets = b.option(bool, "test-extra-targets", "Enable running module tests for additional targets") orelse false; |
| 433 | |
| 434 | var chosen_opt_modes_buf: [4]std.lang.Optimize = undefined; |
| 435 | var chosen_mode_index: usize = 0; |
| 436 | if (!skip_debug) { |
| 437 | chosen_opt_modes_buf[chosen_mode_index] = .debug; |
| 438 | chosen_mode_index += 1; |
| 439 | } |
| 440 | if (!skip_release_safe) { |
| 441 | chosen_opt_modes_buf[chosen_mode_index] = .safe; |
| 442 | chosen_mode_index += 1; |
| 443 | } |
| 444 | if (!skip_release_fast) { |
| 445 | chosen_opt_modes_buf[chosen_mode_index] = .fast; |
| 446 | chosen_mode_index += 1; |
| 447 | } |
| 448 | if (!skip_release_small) { |
| 449 | chosen_opt_modes_buf[chosen_mode_index] = .small; |
| 450 | chosen_mode_index += 1; |
| 451 | } |
| 452 | const optimize_modes = chosen_opt_modes_buf[0..chosen_mode_index]; |
| 453 | |
| 454 | const test_only: ?tests.ModuleTestOptions.TestOnly = if (no_matrix) |
| 455 | .default |
| 456 | else if (fuzz_only) |
| 457 | .{ .fuzz = optimize } |
| 458 | else |
| 459 | null; |
| 460 | |
| 461 | const fmt_include_paths = b.pathList(&.{ "lib", "src", "test", "tools", "build.zig", "build.zig.zon" }); |
| 462 | const fmt_exclude_paths = b.pathList(&.{ "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, .{ |
| 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_spirv = skip_spirv, |
| 484 | .skip_wasm = skip_wasm, |
| 485 | .skip_freebsd = skip_freebsd, |
| 486 | .skip_netbsd = skip_netbsd, |
| 487 | .skip_openbsd = skip_openbsd, |
| 488 | .skip_windows = skip_windows, |
| 489 | .skip_darwin = skip_darwin, |
| 490 | .skip_linux = skip_linux, |
| 491 | .skip_llvm = skip_llvm, |
| 492 | .skip_libc = skip_libc, |
| 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 = optimize_modes, |
| 513 | .include_paths = &.{}, |
| 514 | .sanitize_thread = sanitize_thread, |
| 515 | .skip_single_threaded = skip_single_threaded, |
| 516 | .skip_non_native = skip_non_native, |
| 517 | .test_only = test_only, |
| 518 | .skip_spirv = skip_spirv, |
| 519 | .skip_wasm = skip_wasm, |
| 520 | .skip_freebsd = skip_freebsd, |
| 521 | .skip_netbsd = skip_netbsd, |
| 522 | .skip_openbsd = skip_openbsd, |
| 523 | .skip_windows = skip_windows, |
| 524 | .skip_darwin = skip_darwin, |
| 525 | .skip_linux = skip_linux, |
| 526 | .skip_llvm = skip_llvm, |
| 527 | .skip_libc = skip_libc, |
| 528 | .max_rss = 4_000_000_000, |
| 529 | })); |
| 530 | |
| 531 | test_modules_step.dependOn(tests.addModuleTests(b, .{ |
| 532 | .test_filters = test_filters, |
| 533 | .test_target_filters = test_target_filters, |
| 534 | .test_extra_targets = test_extra_targets, |
| 535 | .root_src = "lib/compiler_rt.zig", |
| 536 | .name = "compiler-rt", |
| 537 | .desc = "Run the compiler_rt tests", |
| 538 | .optimize_modes = optimize_modes, |
| 539 | .include_paths = &.{}, |
| 540 | .sanitize_thread = sanitize_thread, |
| 541 | .skip_single_threaded = true, |
| 542 | .skip_non_native = skip_non_native, |
| 543 | .test_only = test_only, |
| 544 | .skip_spirv = skip_spirv, |
| 545 | .skip_wasm = skip_wasm, |
| 546 | .skip_freebsd = skip_freebsd, |
| 547 | .skip_netbsd = skip_netbsd, |
| 548 | .skip_openbsd = skip_openbsd, |
| 549 | .skip_windows = skip_windows, |
| 550 | .skip_darwin = skip_darwin, |
| 551 | .skip_linux = skip_linux, |
| 552 | .skip_llvm = skip_llvm, |
| 553 | .skip_libc = true, |
| 554 | .no_builtin = true, |
| 555 | .max_rss = 4_000_000_000, |
| 556 | })); |
| 557 | |
| 558 | test_modules_step.dependOn(tests.addModuleTests(b, .{ |
| 559 | .test_filters = test_filters, |
| 560 | .test_target_filters = test_target_filters, |
| 561 | .test_extra_targets = test_extra_targets, |
| 562 | .root_src = "lib/std/std.zig", |
| 563 | .name = "std", |
| 564 | .desc = "Run the standard library tests", |
| 565 | .optimize_modes = optimize_modes, |
| 566 | .include_paths = &.{}, |
| 567 | .sanitize_thread = sanitize_thread, |
| 568 | .skip_single_threaded = skip_single_threaded, |
| 569 | .skip_non_native = skip_non_native, |
| 570 | .test_only = test_only, |
| 571 | .skip_spirv = true, |
| 572 | .skip_wasm = skip_wasm, |
| 573 | .skip_freebsd = skip_freebsd, |
| 574 | .skip_netbsd = skip_netbsd, |
| 575 | .skip_openbsd = skip_openbsd, |
| 576 | .skip_windows = skip_windows, |
| 577 | .skip_darwin = skip_darwin, |
| 578 | .skip_linux = skip_linux, |
| 579 | .skip_llvm = skip_llvm, |
| 580 | .skip_libc = skip_libc, |
| 581 | .max_rss = 9_300_000_000, |
| 582 | })); |
| 583 | |
| 584 | test_modules_step.dependOn(tests.addModuleTests(b, .{ |
| 585 | .test_filters = test_filters, |
| 586 | .test_target_filters = test_target_filters, |
| 587 | .test_extra_targets = test_extra_targets, |
| 588 | .root_src = "test/c.zig", |
| 589 | .name = "libc", |
| 590 | .desc = "Run the libc API tests", |
| 591 | .optimize_modes = optimize_modes, |
| 592 | .include_paths = &.{}, |
| 593 | .sanitize_thread = sanitize_thread, |
| 594 | .skip_single_threaded = true, |
| 595 | .skip_non_native = skip_non_native, |
| 596 | .test_only = test_only, |
| 597 | .skip_spirv = true, |
| 598 | .skip_wasm = skip_wasm, |
| 599 | .skip_freebsd = skip_freebsd, |
| 600 | .skip_netbsd = skip_netbsd, |
| 601 | .skip_openbsd = skip_openbsd, |
| 602 | .skip_windows = skip_windows, |
| 603 | .skip_darwin = skip_darwin, |
| 604 | .skip_linux = skip_linux, |
| 605 | .skip_llvm = skip_llvm, |
| 606 | .skip_libc = skip_libc, |
| 607 | .no_builtin = true, |
| 608 | .max_rss = 4_000_000_000, |
| 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 | .sanitize_thread = sanitize_thread, |
| 619 | .single_threaded = single_threaded, |
| 620 | }), |
| 621 | .filters = test_filters, |
| 622 | .use_llvm = use_llvm, |
| 623 | .use_lld = use_llvm, |
| 624 | .zig_lib_dir = b.path("lib"), |
| 625 | .max_rss = 3_000_000_000, |
| 626 | }); |
| 627 | if (link_libc) { |
| 628 | unit_tests.root_module.link_libc = true; |
| 629 | } |
| 630 | unit_tests.root_module.addOptions("build_options", exe_options); |
| 631 | unit_tests_step.dependOn(&b.addRunArtifact(unit_tests).step); |
| 632 | |
| 633 | test_step.dependOn(tests.addStandaloneTests( |
| 634 | b, |
| 635 | optimize_modes, |
| 636 | enable_macos_sdk, |
| 637 | enable_ios_sdk, |
| 638 | enable_symlinks_windows, |
| 639 | )); |
| 640 | test_step.dependOn(tests.addCAbiTests(b, .{ |
| 641 | .test_target_filters = test_target_filters, |
| 642 | .optimize_modes = optimize_modes, |
| 643 | .skip_non_native = skip_non_native, |
| 644 | .skip_wasm = skip_wasm, |
| 645 | .skip_freebsd = skip_freebsd, |
| 646 | .skip_netbsd = skip_netbsd, |
| 647 | .skip_openbsd = skip_openbsd, |
| 648 | .skip_windows = skip_windows, |
| 649 | .skip_darwin = skip_darwin, |
| 650 | .skip_linux = skip_linux, |
| 651 | .skip_llvm = skip_llvm, |
| 652 | .max_rss = 3_300_000_000, |
| 653 | })); |
| 654 | test_step.dependOn(tests.addLinkTests(b, .{ |
| 655 | .test_target_filters = test_target_filters, |
| 656 | .test_filters = test_filters, |
| 657 | .optimize_modes = optimize_modes, |
| 658 | .skip_non_native = skip_non_native, |
| 659 | .skip_freebsd = skip_freebsd, |
| 660 | .skip_netbsd = skip_netbsd, |
| 661 | .skip_openbsd = skip_openbsd, |
| 662 | .skip_windows = skip_windows, |
| 663 | .skip_darwin = skip_darwin, |
| 664 | .skip_linux = skip_linux, |
| 665 | .skip_llvm = skip_llvm, |
| 666 | .skip_libc = skip_libc, |
| 667 | .max_rss = 100_000_000, |
| 668 | })); |
| 669 | test_step.dependOn(tests.addStackTraceTests(b, .{ |
| 670 | .test_filters = test_filters, |
| 671 | .test_target_filters = test_target_filters, |
| 672 | .test_extra_targets = test_extra_targets, |
| 673 | .optimize_modes = optimize_modes, |
| 674 | .skip_non_native = skip_non_native, |
| 675 | .skip_freebsd = skip_freebsd, |
| 676 | .skip_netbsd = skip_netbsd, |
| 677 | .skip_openbsd = skip_openbsd, |
| 678 | .skip_windows = skip_windows, |
| 679 | .skip_darwin = skip_darwin, |
| 680 | .skip_linux = skip_linux, |
| 681 | .skip_llvm = skip_llvm, |
| 682 | .skip_libc = skip_libc, |
| 683 | })); |
| 684 | test_step.dependOn(tests.addErrorTraceTests(b, .{ |
| 685 | .test_filters = test_filters, |
| 686 | .test_target_filters = test_target_filters, |
| 687 | .test_extra_targets = test_extra_targets, |
| 688 | .optimize_modes = optimize_modes, |
| 689 | .skip_non_native = skip_non_native, |
| 690 | .skip_freebsd = skip_freebsd, |
| 691 | .skip_netbsd = skip_netbsd, |
| 692 | .skip_openbsd = skip_openbsd, |
| 693 | .skip_windows = skip_windows, |
| 694 | .skip_darwin = skip_darwin, |
| 695 | .skip_linux = skip_linux, |
| 696 | .skip_llvm = skip_llvm, |
| 697 | .skip_libc = skip_libc, |
| 698 | })); |
| 699 | test_step.dependOn(tests.addCliTests(b)); |
| 700 | if (tests.addDebuggerTests(b, .{ |
| 701 | .test_filters = test_filters, |
| 702 | .test_target_filters = test_target_filters, |
| 703 | .gdb = b.option([]const u8, "gdb", "path to gdb binary"), |
| 704 | .lldb = b.option([]const u8, "lldb", "path to lldb binary"), |
| 705 | .optimize_modes = optimize_modes, |
| 706 | .skip_single_threaded = skip_single_threaded, |
| 707 | .skip_libc = skip_libc, |
| 708 | })) |test_debugger_step| test_step.dependOn(test_debugger_step); |
| 709 | if (tests.addLlvmIrTests(b, .{ |
| 710 | .enable_llvm = enable_llvm, |
| 711 | .test_filters = test_filters, |
| 712 | .test_target_filters = test_target_filters, |
| 713 | })) |test_llvm_ir_step| test_step.dependOn(test_llvm_ir_step); |
| 714 | |
| 715 | try addWasiUpdateStep(b, version); |
| 716 | |
| 717 | const update_mingw_step = b.step("update-mingw", "Update zig's bundled mingw"); |
| 718 | const opt_mingw_src_path = b.option([]const u8, "mingw-src", "path to mingw-w64 source directory"); |
| 719 | if (opt_mingw_src_path) |mingw_src_path| { |
| 720 | const update_mingw_exe = b.addExecutable(.{ |
| 721 | .name = "update_mingw", |
| 722 | .root_module = b.createModule(.{ |
| 723 | .target = b.graph.host, |
| 724 | .root_source_file = b.path("tools/update_mingw.zig"), |
| 725 | }), |
| 726 | }); |
| 727 | const update_mingw_run = b.addRunArtifact(update_mingw_exe); |
| 728 | update_mingw_run.addDirectoryArg(b.path("lib")); |
| 729 | update_mingw_run.addDirectoryArg(.{ .cwd_relative = mingw_src_path }); |
| 730 | |
| 731 | update_mingw_step.dependOn(&update_mingw_run.step); |
| 732 | } else { |
| 733 | update_mingw_step.dependOn(&b.addFail("The -Dmingw-src=... option is required for this step").step); |
| 734 | } |
| 735 | |
| 736 | const check_mingw_step = b.step("check-mingw", "Checks for mingw preprocessor regressions"); |
| 737 | const mingw_preprocessor_mod = b.createModule(.{ |
| 738 | .root_source_file = b.path("src/libs/mingw/Preprocessor.zig"), |
| 739 | .target = target, |
| 740 | }); |
| 741 | |
| 742 | const check_mingw_exe = b.addExecutable(.{ |
| 743 | .name = "check_mingw", |
| 744 | .root_module = b.createModule(.{ |
| 745 | .target = b.graph.host, |
| 746 | .root_source_file = b.path("tools/check_mingw.zig"), |
| 747 | .imports = &.{ |
| 748 | .{ .name = "preprocessor", .module = mingw_preprocessor_mod }, |
| 749 | }, |
| 750 | }), |
| 751 | }); |
| 752 | const check_mingw_run = b.addRunArtifact(check_mingw_exe); |
| 753 | check_mingw_run.addDirectoryArg(b.path("lib/libc/mingw")); |
| 754 | check_mingw_step.dependOn(&check_mingw_run.step); |
| 755 | |
| 756 | { |
| 757 | const gen_oracle_exe = b.addExecutable(.{ |
| 758 | .name = "gen_parser_oracle", |
| 759 | .root_module = b.createModule(.{ |
| 760 | .root_source_file = b.path("tools/gen_parser_oracle.zig"), |
| 761 | .target = b.graph.host, |
| 762 | }), |
| 763 | }); |
| 764 | |
| 765 | const gen_oracle_step = b.step("gen-parser-oracle", "Regenerate lib/std/zig/parser_generated_oracle.zig from doc/langref/grammar.peg"); |
| 766 | const gen_oracle_run = b.addRunArtifact(gen_oracle_exe); |
| 767 | gen_oracle_run.addFileArg(b.path("doc/langref/grammar.peg")); |
| 768 | gen_oracle_run.addFileArg(b.path("lib/std/zig/parser_generated_oracle.zig")); |
| 769 | gen_oracle_step.dependOn(&gen_oracle_run.step); |
| 770 | |
| 771 | const check_oracle_step = b.step("check-parser-oracle", "Check if doc/langref/grammar.peg was modified without regenerating the oracle"); |
| 772 | const check_oracle_run = b.addRunArtifact(gen_oracle_exe); |
| 773 | check_oracle_run.addFileArg(b.path("doc/langref/grammar.peg")); |
| 774 | check_oracle_run.addFileArg(b.path("lib/std/zig/parser_generated_oracle.zig")); |
| 775 | check_oracle_run.addArg("--check"); |
| 776 | check_oracle_step.dependOn(&check_oracle_run.step); |
| 777 | test_step.dependOn(check_oracle_step); |
| 778 | } |
| 779 | |
| 780 | const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases"); |
| 781 | try tests.addIncrementalTests(b, test_incremental_step, .{ |
| 782 | .test_filters = test_filters, |
| 783 | .test_target_filters = test_target_filters, |
| 784 | .skip_non_native = skip_non_native, |
| 785 | .skip_wasm = skip_wasm, |
| 786 | .skip_freebsd = skip_freebsd, |
| 787 | .skip_netbsd = skip_netbsd, |
| 788 | .skip_openbsd = skip_openbsd, |
| 789 | .skip_windows = skip_windows, |
| 790 | .skip_darwin = skip_darwin, |
| 791 | .skip_linux = skip_linux, |
| 792 | .skip_llvm = skip_llvm, |
| 793 | }); |
| 794 | if (!skip_test_incremental) test_step.dependOn(test_incremental_step); |
| 795 | |
| 796 | if (tests.addLibcTestNszTests(b, .{ |
| 797 | .optimize_modes = optimize_modes, |
| 798 | .test_filters = test_filters, |
| 799 | .test_target_filters = test_target_filters, |
| 800 | .skip_wasm = skip_wasm, |
| 801 | .max_rss = 3_500_000_000, |
| 802 | })) |test_libc_nsz_step| test_step.dependOn(test_libc_nsz_step); |
| 803 | } |
| 804 | |
| 805 | fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { |
| 806 | const semver = try std.SemanticVersion.parse(version); |
| 807 | |
| 808 | const exe = addCompilerStep(b, .{ |
| 809 | .optimize = .small, |
| 810 | .target = b.resolveTargetQuery(std.Target.Query.parse(.{ |
| 811 | .arch_os_abi = "wasm32-wasi", |
| 812 | // * `nontrapping_bulk_memory_len0` is supported by `wasm2c`. |
| 813 | .cpu_features = "baseline+nontrapping_bulk_memory_len0", |
| 814 | }) catch unreachable), |
| 815 | }); |
| 816 | |
| 817 | const exe_options = b.addOptions(); |
| 818 | exe.root_module.addOptions("build_options", exe_options); |
| 819 | |
| 820 | exe_options.addOption(u32, "mem_leak_frames", 0); |
| 821 | exe_options.addOption(bool, "have_llvm", false); |
| 822 | exe_options.addOption(bool, "debug_gpa", false); |
| 823 | exe_options.addOption([:0]const u8, "version", version); |
| 824 | exe_options.addOption(std.SemanticVersion, "semver", semver); |
| 825 | exe_options.addOption(bool, "enable_debug_extensions", false); |
| 826 | exe_options.addOption(bool, "enable_logging", false); |
| 827 | exe_options.addOption(bool, "enable_tracy", false); |
| 828 | exe_options.addOption(bool, "enable_tracy_callstack", false); |
| 829 | exe_options.addOption(bool, "enable_tracy_allocation", false); |
| 830 | exe_options.addOption(u32, "tracy_callstack_depth", 0); |
| 831 | exe_options.addOption(bool, "value_tracing", false); |
| 832 | exe_options.addOption(DevEnv, "dev", .bootstrap); |
| 833 | exe_options.addOption(IoMode, "io_mode", .threaded); |
| 834 | |
| 835 | // zig1 chooses to interpret values by name. The tradeoff is as follows: |
| 836 | // |
| 837 | // * We lose a small amount of performance. This is essentially irrelevant for zig1. |
| 838 | // |
| 839 | // * We lose the ability to perform trivial renames on certain `std.lang` types without |
| 840 | // zig1.wasm updates. For instance, we cannot rename an enum from PascalCase fields to |
| 841 | // snake_case fields without an update. |
| 842 | // |
| 843 | // * We gain the ability to add and remove fields to and from `std.lang` types without |
| 844 | // zig1.wasm updates. For instance, we can add a new tag to `CallingConvention` without |
| 845 | // an update. |
| 846 | // |
| 847 | // Because field renames only happen when we apply a breaking change to the language (which |
| 848 | // is becoming progressively rarer), but tags may be added to or removed from target-dependent |
| 849 | // types over time in response to new targets coming into use, we gain more than we lose here. |
| 850 | exe_options.addOption(ValueInterpretMode, "value_interpret_mode", .by_name); |
| 851 | |
| 852 | const run_opt = b.addSystemCommand(&.{ |
| 853 | "wasm-opt", |
| 854 | "-Oz", |
| 855 | "--enable-bulk-memory", |
| 856 | "--enable-mutable-globals", |
| 857 | "--enable-extended-const", |
| 858 | "--enable-nontrapping-float-to-int", |
| 859 | "--enable-sign-ext", |
| 860 | }); |
| 861 | run_opt.addArtifactArg(exe); |
| 862 | run_opt.addArg("-o"); |
| 863 | const optimized_wasm = run_opt.addOutputFileArg("zig1.wasm"); |
| 864 | |
| 865 | const update_zig1 = b.addUpdateSourceFiles(); |
| 866 | update_zig1.addCopyFileToSource(optimized_wasm, "stage1/zig1.wasm"); |
| 867 | update_zig1.addCopyFileToSource(b.path("lib/zig.h"), "stage1/zig.h"); |
| 868 | |
| 869 | const update_zig1_step = b.step("update-zig1", "Update stage1/zig1.wasm"); |
| 870 | update_zig1_step.dependOn(&update_zig1.step); |
| 871 | } |
| 872 | |
| 873 | const AddCompilerModOptions = struct { |
| 874 | optimize: std.lang.Optimize, |
| 875 | target: std.Build.ResolvedTarget, |
| 876 | strip: ?bool = null, |
| 877 | valgrind: ?bool = null, |
| 878 | sanitize_thread: ?bool = null, |
| 879 | single_threaded: ?bool = null, |
| 880 | }; |
| 881 | |
| 882 | fn addCompilerMod(b: *std.Build, options: AddCompilerModOptions) *std.Build.Module { |
| 883 | const compiler_mod = b.createModule(.{ |
| 884 | .root_source_file = b.path("src/main.zig"), |
| 885 | .target = options.target, |
| 886 | .optimize = options.optimize, |
| 887 | .strip = options.strip, |
| 888 | .sanitize_thread = options.sanitize_thread, |
| 889 | .single_threaded = options.single_threaded, |
| 890 | .valgrind = options.valgrind, |
| 891 | }); |
| 892 | |
| 893 | return compiler_mod; |
| 894 | } |
| 895 | |
| 896 | fn addCompilerStep(b: *std.Build, options: AddCompilerModOptions) *std.Build.Step.Compile { |
| 897 | const exe = b.addExecutable(.{ |
| 898 | .name = "zig", |
| 899 | // This number should never be raised. If the value is exceeded, then |
| 900 | // it is considered a bug in the Zig project that building the |
| 901 | // compiler takes more than 8G of memory. |
| 902 | .max_rss = 8_000_000_000, |
| 903 | .root_module = addCompilerMod(b, options), |
| 904 | }); |
| 905 | exe.stack_size = stack_size; |
| 906 | |
| 907 | // Must match the condition in CMakeLists.txt. |
| 908 | const function_data_sections = switch (options.target.result.cpu.arch) { |
| 909 | .arm, |
| 910 | .armeb, |
| 911 | .thumb, |
| 912 | .thumbeb, |
| 913 | .hexagon, |
| 914 | .powerpc, |
| 915 | .powerpcle, |
| 916 | .powerpc64, |
| 917 | .powerpc64le, |
| 918 | => true, |
| 919 | else => false, |
| 920 | }; |
| 921 | |
| 922 | exe.link_function_sections = function_data_sections; |
| 923 | exe.link_data_sections = function_data_sections; |
| 924 | |
| 925 | return exe; |
| 926 | } |
| 927 | |
| 928 | const exe_cflags = [_][]const u8{ |
| 929 | "-std=c++17", |
| 930 | "-D__STDC_CONSTANT_MACROS", |
| 931 | "-D__STDC_FORMAT_MACROS", |
| 932 | "-D__STDC_LIMIT_MACROS", |
| 933 | "-D_GNU_SOURCE", |
| 934 | "-fno-exceptions", |
| 935 | "-fno-rtti", |
| 936 | "-fno-stack-protector", |
| 937 | "-fvisibility-inlines-hidden", |
| 938 | "-Wno-type-limits", |
| 939 | "-Wno-missing-braces", |
| 940 | "-Wno-comment", |
| 941 | // `exe_cflags` is only used for static linking. |
| 942 | "-DLLVM_BUILD_STATIC", |
| 943 | "-DCLANG_BUILD_STATIC", |
| 944 | }; |
| 945 | |
| 946 | fn addCmakeCfgOptionsToExe( |
| 947 | b: *std.Build, |
| 948 | cfg: CMakeConfig, |
| 949 | exe: *std.Build.Step.Compile, |
| 950 | use_zig_libcxx: bool, |
| 951 | ) !void { |
| 952 | const mod = exe.root_module; |
| 953 | const target = &mod.resolved_target.?.result; |
| 954 | |
| 955 | if (target.os.tag.isDarwin()) { |
| 956 | // useful for package maintainers |
| 957 | exe.headerpad_max_install_names = true; |
| 958 | } |
| 959 | |
| 960 | mod.addObjectFile(.{ .cwd_relative = b.pathJoin(&.{ |
| 961 | cfg.cmake_binary_dir, |
| 962 | "zigcpp", |
| 963 | b.fmt("{s}{s}{s}", .{ |
| 964 | cfg.cmake_static_library_prefix, |
| 965 | "zigcpp", |
| 966 | cfg.cmake_static_library_suffix, |
| 967 | }), |
| 968 | }) }); |
| 969 | assert(cfg.lld_include_dir.len != 0); |
| 970 | mod.addIncludePath(.{ .cwd_relative = cfg.lld_include_dir }); |
| 971 | mod.addIncludePath(.{ .cwd_relative = cfg.llvm_include_dir }); |
| 972 | mod.addLibraryPath(.{ .cwd_relative = cfg.llvm_lib_dir }); |
| 973 | addCMakeLibraryList(mod, cfg.clang_libraries); |
| 974 | addCMakeLibraryList(mod, cfg.lld_libraries); |
| 975 | addCMakeLibraryList(mod, cfg.llvm_libraries); |
| 976 | |
| 977 | if (use_zig_libcxx) { |
| 978 | mod.link_libcpp = true; |
| 979 | } else { |
| 980 | // System -lc++ must be used because in this code path we are attempting to link |
| 981 | // against system-provided LLVM, Clang, LLD. |
| 982 | const need_cpp_includes = true; |
| 983 | const static = cfg.llvm_linkage == .static; |
| 984 | const lib_suffix = if (static) target.staticLibSuffix()[1..] else target.dynamicLibSuffix()[1..]; |
| 985 | switch (target.os.tag) { |
| 986 | .linux => { |
| 987 | // First we try to link against the detected libcxx name. If that doesn't work, we fall |
| 988 | // back to -lc++ and cross our fingers. |
| 989 | addCxxKnownPath(b, cfg, exe, b.fmt("lib{s}.{s}", .{ cfg.system_libcxx, lib_suffix }), "", need_cpp_includes) catch |err| switch (err) { |
| 990 | error.RequiredLibraryNotFound => { |
| 991 | mod.link_libcpp = true; |
| 992 | }, |
| 993 | else => |e| return e, |
| 994 | }; |
| 995 | mod.linkSystemLibrary("unwind", .{}); |
| 996 | }, |
| 997 | .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => { |
| 998 | mod.link_libcpp = true; |
| 999 | }, |
| 1000 | .windows => { |
| 1001 | if (target.abi != .msvc) mod.link_libcpp = true; |
| 1002 | }, |
| 1003 | .freebsd => { |
| 1004 | try addCxxKnownPath(b, cfg, exe, b.fmt("libc++.{s}", .{lib_suffix}), null, need_cpp_includes); |
| 1005 | if (static) try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes); |
| 1006 | }, |
| 1007 | .openbsd => { |
| 1008 | // - llvm requires libexecinfo which has conflicting symbols with libc++abi |
| 1009 | // - only an issue with .a linking |
| 1010 | // - workaround is to link c++abi dynamically |
| 1011 | try addCxxKnownPath(b, cfg, exe, b.fmt("libc++.{s}", .{target.dynamicLibSuffix()[1..]}), null, need_cpp_includes); |
| 1012 | try addCxxKnownPath(b, cfg, exe, b.fmt("libc++abi.{s}", .{target.dynamicLibSuffix()[1..]}), null, need_cpp_includes); |
| 1013 | }, |
| 1014 | .netbsd, .dragonfly => { |
| 1015 | try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes); |
| 1016 | if (static) try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes); |
| 1017 | }, |
| 1018 | .illumos => { |
| 1019 | try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes); |
| 1020 | try addCxxKnownPath(b, cfg, exe, b.fmt("libgcc_eh.{s}", .{lib_suffix}), null, need_cpp_includes); |
| 1021 | }, |
| 1022 | .haiku => { |
| 1023 | try addCxxKnownPath(b, cfg, exe, b.fmt("libstdc++.{s}", .{lib_suffix}), null, need_cpp_includes); |
| 1024 | }, |
| 1025 | else => {}, |
| 1026 | } |
| 1027 | } |
| 1028 | |
| 1029 | if (cfg.dia_guids_lib.len != 0) { |
| 1030 | mod.addObjectFile(.{ .cwd_relative = cfg.dia_guids_lib }); |
| 1031 | } |
| 1032 | } |
| 1033 | |
| 1034 | fn addStaticLlvmOptionsToModule(mod: *std.Build.Module, options: struct { |
| 1035 | llvm_has_m68k: bool, |
| 1036 | llvm_has_csky: bool, |
| 1037 | llvm_has_arc: bool, |
| 1038 | llvm_has_xtensa: bool, |
| 1039 | }) !void { |
| 1040 | // Adds the Zig C++ sources which both stage1 and stage2 need. |
| 1041 | // |
| 1042 | // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling |
| 1043 | // in a dependency on llvm::cfg::Update<llvm::BasicBlock*>::dump() which is |
| 1044 | // unavailable when LLVM is compiled in Release mode. |
| 1045 | const zig_cpp_cflags = exe_cflags ++ [_][]const u8{"-DNDEBUG=1"}; |
| 1046 | mod.addCSourceFiles(.{ |
| 1047 | .files = &zig_cpp_sources, |
| 1048 | .flags = &zig_cpp_cflags, |
| 1049 | }); |
| 1050 | |
| 1051 | const lsl_options: std.Build.Module.LinkSystemLibraryOptions = .{ .use_pkg_config = .no }; |
| 1052 | |
| 1053 | for (clang_libs) |lib_name| { |
| 1054 | mod.linkSystemLibrary(lib_name, lsl_options); |
| 1055 | } |
| 1056 | |
| 1057 | for (lld_libs) |lib_name| { |
| 1058 | mod.linkSystemLibrary(lib_name, lsl_options); |
| 1059 | } |
| 1060 | |
| 1061 | for (llvm_libs) |lib_name| { |
| 1062 | mod.linkSystemLibrary(lib_name, lsl_options); |
| 1063 | } |
| 1064 | |
| 1065 | if (options.llvm_has_m68k) for (llvm_libs_m68k) |lib_name| { |
| 1066 | mod.linkSystemLibrary(lib_name, lsl_options); |
| 1067 | }; |
| 1068 | |
| 1069 | if (options.llvm_has_csky) for (llvm_libs_csky) |lib_name| { |
| 1070 | mod.linkSystemLibrary(lib_name, lsl_options); |
| 1071 | }; |
| 1072 | |
| 1073 | if (options.llvm_has_arc) for (llvm_libs_arc) |lib_name| { |
| 1074 | mod.linkSystemLibrary(lib_name, lsl_options); |
| 1075 | }; |
| 1076 | |
| 1077 | if (options.llvm_has_xtensa) for (llvm_libs_xtensa) |lib_name| { |
| 1078 | mod.linkSystemLibrary(lib_name, lsl_options); |
| 1079 | }; |
| 1080 | |
| 1081 | mod.linkSystemLibrary("z", lsl_options); |
| 1082 | mod.linkSystemLibrary("zstd", lsl_options); |
| 1083 | |
| 1084 | if (mod.resolved_target.?.result.os.tag != .windows or mod.resolved_target.?.result.abi != .msvc) { |
| 1085 | // This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries. |
| 1086 | mod.linkSystemLibrary("c++", lsl_options); |
| 1087 | } |
| 1088 | |
| 1089 | if (mod.resolved_target.?.result.os.tag == .windows) { |
| 1090 | mod.linkSystemLibrary("version", lsl_options); |
| 1091 | mod.linkSystemLibrary("uuid", lsl_options); |
| 1092 | mod.linkSystemLibrary("ole32", lsl_options); |
| 1093 | } |
| 1094 | } |
| 1095 | |
| 1096 | fn addCxxKnownPath( |
| 1097 | b: *std.Build, |
| 1098 | ctx: CMakeConfig, |
| 1099 | exe: *std.Build.Step.Compile, |
| 1100 | objname: []const u8, |
| 1101 | errtxt: ?[]const u8, |
| 1102 | need_cpp_includes: bool, |
| 1103 | ) !void { |
| 1104 | if (!std.process.can_spawn) return error.RequiredLibraryNotFound; |
| 1105 | |
| 1106 | const arena = b.graph.arena; |
| 1107 | |
| 1108 | const path_padded = run: { |
| 1109 | var args = std.array_list.Managed([]const u8).init(arena); |
| 1110 | try args.append(ctx.cxx_compiler); |
| 1111 | var it = std.mem.tokenizeAny(u8, ctx.cxx_compiler_arg1, &std.ascii.whitespace); |
| 1112 | while (it.next()) |arg| try args.append(arg); |
| 1113 | try args.append(b.fmt("-print-file-name={s}", .{objname})); |
| 1114 | break :run b.run(args.items); |
| 1115 | }; |
| 1116 | var tokenizer = mem.tokenizeAny(u8, path_padded, "\r\n"); |
| 1117 | const path_unpadded = tokenizer.next().?; |
| 1118 | if (mem.eql(u8, path_unpadded, objname)) { |
| 1119 | if (errtxt) |msg| { |
| 1120 | std.debug.print("{s}", .{msg}); |
| 1121 | } else { |
| 1122 | std.debug.print("Unable to determine path to {s}\n", .{objname}); |
| 1123 | } |
| 1124 | return error.RequiredLibraryNotFound; |
| 1125 | } |
| 1126 | // By default, explicit library paths are not checked for being linker scripts, |
| 1127 | // but libc++ may very well be one, so force all inputs to be checked when passing |
| 1128 | // an explicit path to libc++. |
| 1129 | exe.allow_so_scripts = true; |
| 1130 | exe.root_module.addObjectFile(.{ .cwd_relative = path_unpadded }); |
| 1131 | |
| 1132 | // TODO a way to integrate with system c++ include files here |
| 1133 | // c++ -E -Wp,-v -xc++ /dev/null |
| 1134 | if (need_cpp_includes) { |
| 1135 | // I used these temporarily for testing something but we obviously need a |
| 1136 | // more general purpose solution here. |
| 1137 | //exe.root_module.addIncludePath("/nix/store/2lr0fc0ak8rwj0k8n3shcyz1hz63wzma-gcc-11.3.0/include/c++/11.3.0"); |
| 1138 | //exe.root_module.addIncludePath("/nix/store/2lr0fc0ak8rwj0k8n3shcyz1hz63wzma-gcc-11.3.0/include/c++/11.3.0/x86_64-unknown-linux-gnu"); |
| 1139 | } |
| 1140 | } |
| 1141 | |
| 1142 | fn addCMakeLibraryList(mod: *std.Build.Module, list: []const u8) void { |
| 1143 | var it = mem.tokenizeScalar(u8, list, ';'); |
| 1144 | while (it.next()) |lib| { |
| 1145 | if (mem.startsWith(u8, lib, "-l")) { |
| 1146 | mod.linkSystemLibrary(lib["-l".len..], .{}); |
| 1147 | } else if (mod.resolved_target.?.result.os.tag == .windows and |
| 1148 | mem.endsWith(u8, lib, ".lib") and !fs.path.isAbsolute(lib)) |
| 1149 | { |
| 1150 | mod.linkSystemLibrary(lib[0 .. lib.len - ".lib".len], .{}); |
| 1151 | } else { |
| 1152 | mod.addObjectFile(.{ .cwd_relative = lib }); |
| 1153 | } |
| 1154 | } |
| 1155 | } |
| 1156 | |
| 1157 | const CMakeConfig = struct { |
| 1158 | llvm_linkage: std.lang.LinkMode, |
| 1159 | cmake_binary_dir: []const u8, |
| 1160 | cmake_prefix_path: []const u8, |
| 1161 | cmake_static_library_prefix: []const u8, |
| 1162 | cmake_static_library_suffix: []const u8, |
| 1163 | cxx_compiler: []const u8, |
| 1164 | cxx_compiler_arg1: []const u8, |
| 1165 | lld_include_dir: []const u8, |
| 1166 | lld_libraries: []const u8, |
| 1167 | clang_libraries: []const u8, |
| 1168 | llvm_lib_dir: []const u8, |
| 1169 | llvm_include_dir: []const u8, |
| 1170 | llvm_libraries: []const u8, |
| 1171 | dia_guids_lib: []const u8, |
| 1172 | system_libcxx: []const u8, |
| 1173 | }; |
| 1174 | |
| 1175 | const max_config_h_bytes = 1 * 1024 * 1024; |
| 1176 | |
| 1177 | fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 { |
| 1178 | const arena = b.graph.arena; |
| 1179 | const io = b.graph.io; |
| 1180 | const cwd: Io.Dir = .cwd(); |
| 1181 | |
| 1182 | if (config_h_path_option) |path| { |
| 1183 | var config_h_or_err = cwd.openFile(io, path, .{}); |
| 1184 | if (config_h_or_err) |*file| { |
| 1185 | file.close(io); |
| 1186 | return path; |
| 1187 | } else |_| { |
| 1188 | std.log.err("Could not open provided config.h: \"{s}\"", .{path}); |
| 1189 | std.process.exit(1); |
| 1190 | } |
| 1191 | } |
| 1192 | |
| 1193 | var check_dir = fs.path.dirname(b.graph.zig_exe).?; |
| 1194 | while (true) { |
| 1195 | var dir = cwd.openDir(io, check_dir, .{}) catch unreachable; |
| 1196 | defer dir.close(io); |
| 1197 | |
| 1198 | // Check if config.h is present in dir |
| 1199 | var config_h_or_err = dir.openFile(io, "config.h", .{}); |
| 1200 | if (config_h_or_err) |*file| { |
| 1201 | file.close(io); |
| 1202 | return fs.path.join( |
| 1203 | arena, |
| 1204 | &[_][]const u8{ check_dir, "config.h" }, |
| 1205 | ) catch unreachable; |
| 1206 | } else |e| switch (e) { |
| 1207 | error.FileNotFound => {}, |
| 1208 | else => unreachable, |
| 1209 | } |
| 1210 | |
| 1211 | // Check if we reached the source root by looking for .git, and bail if so |
| 1212 | var git_dir_or_err = dir.openDir(io, ".git", .{}); |
| 1213 | if (git_dir_or_err) |*git_dir| { |
| 1214 | git_dir.close(io); |
| 1215 | return null; |
| 1216 | } else |_| {} |
| 1217 | |
| 1218 | // Otherwise, continue search in the parent directory |
| 1219 | const new_check_dir = fs.path.dirname(check_dir); |
| 1220 | if (new_check_dir == null or mem.eql(u8, new_check_dir.?, check_dir)) { |
| 1221 | return null; |
| 1222 | } |
| 1223 | check_dir = new_check_dir.?; |
| 1224 | } |
| 1225 | } |
| 1226 | |
| 1227 | fn parseConfigH(b: *std.Build, config_h_text: []const u8) ?CMakeConfig { |
| 1228 | var ctx: CMakeConfig = .{ |
| 1229 | .llvm_linkage = undefined, |
| 1230 | .cmake_binary_dir = undefined, |
| 1231 | .cmake_prefix_path = undefined, |
| 1232 | .cmake_static_library_prefix = undefined, |
| 1233 | .cmake_static_library_suffix = undefined, |
| 1234 | .cxx_compiler = undefined, |
| 1235 | .cxx_compiler_arg1 = "", |
| 1236 | .lld_include_dir = undefined, |
| 1237 | .lld_libraries = undefined, |
| 1238 | .clang_libraries = undefined, |
| 1239 | .llvm_lib_dir = undefined, |
| 1240 | .llvm_include_dir = undefined, |
| 1241 | .llvm_libraries = undefined, |
| 1242 | .dia_guids_lib = undefined, |
| 1243 | .system_libcxx = undefined, |
| 1244 | }; |
| 1245 | |
| 1246 | const mappings = [_]struct { prefix: []const u8, field: []const u8 }{ |
| 1247 | .{ |
| 1248 | .prefix = "#define ZIG_CMAKE_BINARY_DIR ", |
| 1249 | .field = "cmake_binary_dir", |
| 1250 | }, |
| 1251 | .{ |
| 1252 | .prefix = "#define ZIG_CMAKE_PREFIX_PATH ", |
| 1253 | .field = "cmake_prefix_path", |
| 1254 | }, |
| 1255 | .{ |
| 1256 | .prefix = "#define ZIG_CMAKE_STATIC_LIBRARY_PREFIX ", |
| 1257 | .field = "cmake_static_library_prefix", |
| 1258 | }, |
| 1259 | .{ |
| 1260 | .prefix = "#define ZIG_CMAKE_STATIC_LIBRARY_SUFFIX ", |
| 1261 | .field = "cmake_static_library_suffix", |
| 1262 | }, |
| 1263 | .{ |
| 1264 | .prefix = "#define ZIG_CXX_COMPILER ", |
| 1265 | .field = "cxx_compiler", |
| 1266 | }, |
| 1267 | .{ |
| 1268 | .prefix = "#define ZIG_CXX_COMPILER_ARG1 ", |
| 1269 | .field = "cxx_compiler_arg1", |
| 1270 | }, |
| 1271 | .{ |
| 1272 | .prefix = "#define ZIG_LLD_INCLUDE_PATH ", |
| 1273 | .field = "lld_include_dir", |
| 1274 | }, |
| 1275 | .{ |
| 1276 | .prefix = "#define ZIG_LLD_LIBRARIES ", |
| 1277 | .field = "lld_libraries", |
| 1278 | }, |
| 1279 | .{ |
| 1280 | .prefix = "#define ZIG_CLANG_LIBRARIES ", |
| 1281 | .field = "clang_libraries", |
| 1282 | }, |
| 1283 | .{ |
| 1284 | .prefix = "#define ZIG_LLVM_LIBRARIES ", |
| 1285 | .field = "llvm_libraries", |
| 1286 | }, |
| 1287 | .{ |
| 1288 | .prefix = "#define ZIG_DIA_GUIDS_LIB ", |
| 1289 | .field = "dia_guids_lib", |
| 1290 | }, |
| 1291 | .{ |
| 1292 | .prefix = "#define ZIG_LLVM_INCLUDE_PATH ", |
| 1293 | .field = "llvm_include_dir", |
| 1294 | }, |
| 1295 | .{ |
| 1296 | .prefix = "#define ZIG_LLVM_LIB_PATH ", |
| 1297 | .field = "llvm_lib_dir", |
| 1298 | }, |
| 1299 | .{ |
| 1300 | .prefix = "#define ZIG_SYSTEM_LIBCXX", |
| 1301 | .field = "system_libcxx", |
| 1302 | }, |
| 1303 | // .prefix = ZIG_LLVM_LINK_MODE parsed manually below |
| 1304 | }; |
| 1305 | |
| 1306 | var lines_it = mem.tokenizeAny(u8, config_h_text, "\r\n"); |
| 1307 | while (lines_it.next()) |line| { |
| 1308 | inline for (mappings) |mapping| { |
| 1309 | if (mem.startsWith(u8, line, mapping.prefix)) { |
| 1310 | var it = mem.splitScalar(u8, line, '"'); |
| 1311 | _ = it.first(); // skip the stuff before the quote |
| 1312 | const quoted = it.next().?; // the stuff inside the quote |
| 1313 | const trimmed = mem.trim(u8, quoted, " "); |
| 1314 | @field(ctx, mapping.field) = toNativePathSep(b, trimmed); |
| 1315 | } |
| 1316 | } |
| 1317 | if (mem.startsWith(u8, line, "#define ZIG_LLVM_LINK_MODE ")) { |
| 1318 | var it = mem.splitScalar(u8, line, '"'); |
| 1319 | _ = it.next().?; // skip the stuff before the quote |
| 1320 | const quoted = it.next().?; // the stuff inside the quote |
| 1321 | ctx.llvm_linkage = if (mem.eql(u8, quoted, "shared")) .dynamic else .static; |
| 1322 | } |
| 1323 | } |
| 1324 | return ctx; |
| 1325 | } |
| 1326 | |
| 1327 | fn toNativePathSep(b: *std.Build, s: []const u8) []u8 { |
| 1328 | const arena = b.graph.arena; |
| 1329 | const duplicated = arena.dupe(u8, s) catch unreachable; |
| 1330 | for (duplicated) |*byte| switch (byte.*) { |
| 1331 | '/' => byte.* = fs.path.sep, |
| 1332 | else => {}, |
| 1333 | }; |
| 1334 | return duplicated; |
| 1335 | } |
| 1336 | |
| 1337 | const zig_cpp_sources = [_][]const u8{ |
| 1338 | // These are planned to stay even when we are self-hosted. |
| 1339 | "src/zig_llvm.cpp", |
| 1340 | "src/zig_llvm-ar.cpp", |
| 1341 | "src/zig_clang_driver.cpp", |
| 1342 | "src/zig_clang_cc1_main.cpp", |
| 1343 | "src/zig_clang_cc1as_main.cpp", |
| 1344 | }; |
| 1345 | |
| 1346 | const clang_libs = [_][]const u8{ |
| 1347 | "clangFrontendTool", |
| 1348 | "clangCodeGen", |
| 1349 | "clangStaticAnalyzerFrontend", |
| 1350 | "clangStaticAnalyzerCheckers", |
| 1351 | "clangStaticAnalyzerCore", |
| 1352 | "clangCrossTU", |
| 1353 | "clangFrontend", |
| 1354 | "clangDriver", |
| 1355 | "clangOptions", |
| 1356 | "clangSerialization", |
| 1357 | "clangSema", |
| 1358 | "clangAnalysisLifetimeSafety", |
| 1359 | "clangAnalysis", |
| 1360 | "clangASTMatchers", |
| 1361 | "clangAST", |
| 1362 | "clangParse", |
| 1363 | "clangSema", |
| 1364 | "clangAPINotes", |
| 1365 | "clangBasic", |
| 1366 | "clangEdit", |
| 1367 | "clangLex", |
| 1368 | "clangRewriteFrontend", |
| 1369 | "clangRewrite", |
| 1370 | "clangIndex", |
| 1371 | "clangFormat", |
| 1372 | "clangToolingInclusions", |
| 1373 | "clangToolingCore", |
| 1374 | "clangExtractAPI", |
| 1375 | "clangSupport", |
| 1376 | "clangInstallAPI", |
| 1377 | "clangAST", |
| 1378 | }; |
| 1379 | const lld_libs = [_][]const u8{ |
| 1380 | "lldMinGW", |
| 1381 | "lldELF", |
| 1382 | "lldCOFF", |
| 1383 | "lldWasm", |
| 1384 | "lldMachO", |
| 1385 | "lldCommon", |
| 1386 | }; |
| 1387 | // This list can be re-generated with `llvm-config --libfiles` and then |
| 1388 | // reformatting using your favorite text editor. Note we do not execute |
| 1389 | // `llvm-config` here because we are cross compiling. Also omit LLVMTableGen |
| 1390 | // from these libs. |
| 1391 | const llvm_libs = [_][]const u8{ |
| 1392 | "LLVMWindowsManifest", |
| 1393 | "LLVMXRay", |
| 1394 | "LLVMLibDriver", |
| 1395 | "LLVMDlltoolDriver", |
| 1396 | "LLVMTelemetry", |
| 1397 | "LLVMTextAPIBinaryReader", |
| 1398 | "LLVMCoverage", |
| 1399 | "LLVMLineEditor", |
| 1400 | "LLVMXCoreDisassembler", |
| 1401 | "LLVMXCoreCodeGen", |
| 1402 | "LLVMXCoreDesc", |
| 1403 | "LLVMXCoreInfo", |
| 1404 | "LLVMX86TargetMCA", |
| 1405 | "LLVMX86Disassembler", |
| 1406 | "LLVMX86AsmParser", |
| 1407 | "LLVMX86CodeGen", |
| 1408 | "LLVMX86Desc", |
| 1409 | "LLVMX86Info", |
| 1410 | "LLVMWebAssemblyDisassembler", |
| 1411 | "LLVMWebAssemblyAsmParser", |
| 1412 | "LLVMWebAssemblyCodeGen", |
| 1413 | "LLVMWebAssemblyUtils", |
| 1414 | "LLVMWebAssemblyDesc", |
| 1415 | "LLVMWebAssemblyInfo", |
| 1416 | "LLVMVEDisassembler", |
| 1417 | "LLVMVEAsmParser", |
| 1418 | "LLVMVECodeGen", |
| 1419 | "LLVMVEDesc", |
| 1420 | "LLVMVEInfo", |
| 1421 | "LLVMSystemZDisassembler", |
| 1422 | "LLVMSystemZAsmParser", |
| 1423 | "LLVMSystemZCodeGen", |
| 1424 | "LLVMSystemZDesc", |
| 1425 | "LLVMSystemZInfo", |
| 1426 | "LLVMSPIRVCodeGen", |
| 1427 | "LLVMSPIRVDesc", |
| 1428 | "LLVMSPIRVInfo", |
| 1429 | "LLVMSPIRVAnalysis", |
| 1430 | "LLVMSparcDisassembler", |
| 1431 | "LLVMSparcAsmParser", |
| 1432 | "LLVMSparcCodeGen", |
| 1433 | "LLVMSparcDesc", |
| 1434 | "LLVMSparcInfo", |
| 1435 | "LLVMRISCVTargetMCA", |
| 1436 | "LLVMRISCVDisassembler", |
| 1437 | "LLVMRISCVAsmParser", |
| 1438 | "LLVMRISCVCodeGen", |
| 1439 | "LLVMRISCVDesc", |
| 1440 | "LLVMRISCVInfo", |
| 1441 | "LLVMPowerPCDisassembler", |
| 1442 | "LLVMPowerPCAsmParser", |
| 1443 | "LLVMPowerPCCodeGen", |
| 1444 | "LLVMPowerPCDesc", |
| 1445 | "LLVMPowerPCInfo", |
| 1446 | "LLVMNVPTXCodeGen", |
| 1447 | "LLVMNVPTXDesc", |
| 1448 | "LLVMNVPTXInfo", |
| 1449 | "LLVMMSP430Disassembler", |
| 1450 | "LLVMMSP430AsmParser", |
| 1451 | "LLVMMSP430CodeGen", |
| 1452 | "LLVMMSP430Desc", |
| 1453 | "LLVMMSP430Info", |
| 1454 | "LLVMMipsDisassembler", |
| 1455 | "LLVMMipsAsmParser", |
| 1456 | "LLVMMipsCodeGen", |
| 1457 | "LLVMMipsDesc", |
| 1458 | "LLVMMipsInfo", |
| 1459 | "LLVMLoongArchDisassembler", |
| 1460 | "LLVMLoongArchAsmParser", |
| 1461 | "LLVMLoongArchCodeGen", |
| 1462 | "LLVMLoongArchDesc", |
| 1463 | "LLVMLoongArchInfo", |
| 1464 | "LLVMLanaiDisassembler", |
| 1465 | "LLVMLanaiCodeGen", |
| 1466 | "LLVMLanaiAsmParser", |
| 1467 | "LLVMLanaiDesc", |
| 1468 | "LLVMLanaiInfo", |
| 1469 | "LLVMHexagonDisassembler", |
| 1470 | "LLVMHexagonCodeGen", |
| 1471 | "LLVMHexagonAsmParser", |
| 1472 | "LLVMHexagonDesc", |
| 1473 | "LLVMHexagonInfo", |
| 1474 | "LLVMBPFDisassembler", |
| 1475 | "LLVMBPFAsmParser", |
| 1476 | "LLVMBPFCodeGen", |
| 1477 | "LLVMBPFDesc", |
| 1478 | "LLVMBPFInfo", |
| 1479 | "LLVMAVRDisassembler", |
| 1480 | "LLVMAVRAsmParser", |
| 1481 | "LLVMAVRCodeGen", |
| 1482 | "LLVMAVRDesc", |
| 1483 | "LLVMAVRInfo", |
| 1484 | "LLVMARMDisassembler", |
| 1485 | "LLVMARMAsmParser", |
| 1486 | "LLVMARMCodeGen", |
| 1487 | "LLVMARMDesc", |
| 1488 | "LLVMARMUtils", |
| 1489 | "LLVMARMInfo", |
| 1490 | "LLVMAMDGPUTargetMCA", |
| 1491 | "LLVMAMDGPUDisassembler", |
| 1492 | "LLVMAMDGPUAsmParser", |
| 1493 | "LLVMAMDGPUCodeGen", |
| 1494 | "LLVMAMDGPUDesc", |
| 1495 | "LLVMAMDGPUUtils", |
| 1496 | "LLVMAMDGPUInfo", |
| 1497 | "LLVMAArch64Disassembler", |
| 1498 | "LLVMAArch64AsmParser", |
| 1499 | "LLVMAArch64CodeGen", |
| 1500 | "LLVMAArch64Desc", |
| 1501 | "LLVMAArch64Utils", |
| 1502 | "LLVMAArch64Info", |
| 1503 | "LLVMOrcDebugging", |
| 1504 | "LLVMOrcJIT", |
| 1505 | "LLVMWindowsDriver", |
| 1506 | "LLVMMCJIT", |
| 1507 | "LLVMJITLink", |
| 1508 | "LLVMInterpreter", |
| 1509 | "LLVMExecutionEngine", |
| 1510 | "LLVMRuntimeDyld", |
| 1511 | "LLVMOrcTargetProcess", |
| 1512 | "LLVMOrcShared", |
| 1513 | "LLVMDWP", |
| 1514 | "LLVMDWARFCFIChecker", |
| 1515 | "LLVMDebugInfoLogicalView", |
| 1516 | "LLVMOption", |
| 1517 | "LLVMObjCopy", |
| 1518 | "LLVMMCA", |
| 1519 | "LLVMMCDisassembler", |
| 1520 | "LLVMDTLTO", |
| 1521 | "LLVMLTO", |
| 1522 | "LLVMFrontendOpenACC", |
| 1523 | "LLVMFrontendDriver", |
| 1524 | "LLVMExtensions", |
| 1525 | "LLVMPlugins", |
| 1526 | "LLVMPasses", |
| 1527 | "LLVMHipStdPar", |
| 1528 | "LLVMCoroutines", |
| 1529 | "LLVMCFGuard", |
| 1530 | "LLVMipo", |
| 1531 | "LLVMInstrumentation", |
| 1532 | "LLVMVectorize", |
| 1533 | "LLVMSandboxIR", |
| 1534 | "LLVMLinker", |
| 1535 | "LLVMFrontendOpenMP", |
| 1536 | "LLVMFrontendDirective", |
| 1537 | "LLVMFrontendAtomic", |
| 1538 | "LLVMFrontendOffloading", |
| 1539 | "LLVMObjectYAML", |
| 1540 | "LLVMDWARFLinkerParallel", |
| 1541 | "LLVMDWARFLinkerClassic", |
| 1542 | "LLVMDWARFLinker", |
| 1543 | "LLVMGlobalISel", |
| 1544 | "LLVMMIRParser", |
| 1545 | "LLVMAsmPrinter", |
| 1546 | "LLVMSelectionDAG", |
| 1547 | "LLVMCodeGen", |
| 1548 | "LLVMTarget", |
| 1549 | "LLVMObjCARCOpts", |
| 1550 | "LLVMCodeGenTypes", |
| 1551 | "LLVMCGData", |
| 1552 | "LLVMCAS", |
| 1553 | "LLVMIRPrinter", |
| 1554 | "LLVMInterfaceStub", |
| 1555 | "LLVMFileCheck", |
| 1556 | "LLVMFuzzMutate", |
| 1557 | "LLVMScalarOpts", |
| 1558 | "LLVMInstCombine", |
| 1559 | "LLVMAggressiveInstCombine", |
| 1560 | "LLVMTransformUtils", |
| 1561 | "LLVMBitWriter", |
| 1562 | "LLVMAnalysis", |
| 1563 | "LLVMProfileData", |
| 1564 | "LLVMSymbolize", |
| 1565 | "LLVMDebugInfoBTF", |
| 1566 | "LLVMDebugInfoPDB", |
| 1567 | "LLVMDebugInfoMSF", |
| 1568 | "LLVMDebugInfoCodeView", |
| 1569 | "LLVMDebugInfoGSYM", |
| 1570 | "LLVMDebugInfoDWARF", |
| 1571 | "LLVMObject", |
| 1572 | "LLVMTextAPI", |
| 1573 | "LLVMMCParser", |
| 1574 | "LLVMIRReader", |
| 1575 | "LLVMAsmParser", |
| 1576 | "LLVMMC", |
| 1577 | "LLVMDebugInfoDWARFLowLevel", |
| 1578 | "LLVMBitReader", |
| 1579 | "LLVMFrontendHLSL", |
| 1580 | "LLVMFuzzerCLI", |
| 1581 | "LLVMABI", |
| 1582 | "LLVMCore", |
| 1583 | "LLVMRemarks", |
| 1584 | "LLVMBitstreamReader", |
| 1585 | "LLVMBinaryFormat", |
| 1586 | "LLVMTargetParser", |
| 1587 | "LLVMSupport", |
| 1588 | "LLVMDemangle", |
| 1589 | }; |
| 1590 | const llvm_libs_m68k = [_][]const u8{ |
| 1591 | "LLVMM68kDisassembler", |
| 1592 | "LLVMM68kAsmParser", |
| 1593 | "LLVMM68kCodeGen", |
| 1594 | "LLVMM68kDesc", |
| 1595 | "LLVMM68kInfo", |
| 1596 | }; |
| 1597 | const llvm_libs_csky = [_][]const u8{ |
| 1598 | "LLVMCSKYDisassembler", |
| 1599 | "LLVMCSKYAsmParser", |
| 1600 | "LLVMCSKYCodeGen", |
| 1601 | "LLVMCSKYDesc", |
| 1602 | "LLVMCSKYInfo", |
| 1603 | }; |
| 1604 | const llvm_libs_arc = [_][]const u8{ |
| 1605 | "LLVMARCDisassembler", |
| 1606 | "LLVMARCCodeGen", |
| 1607 | "LLVMARCDesc", |
| 1608 | "LLVMARCInfo", |
| 1609 | }; |
| 1610 | const llvm_libs_xtensa = [_][]const u8{ |
| 1611 | "LLVMXtensaDisassembler", |
| 1612 | "LLVMXtensaAsmParser", |
| 1613 | "LLVMXtensaCodeGen", |
| 1614 | "LLVMXtensaDesc", |
| 1615 | "LLVMXtensaInfo", |
| 1616 | }; |
| 1617 | |
| 1618 | fn generateLangRef(b: *std.Build) !std.Build.LazyPath { |
| 1619 | const io = b.graph.io; |
| 1620 | const arena = b.graph.arena; |
| 1621 | |
| 1622 | const doctest_exe = b.addExecutable(.{ |
| 1623 | .name = "doctest", |
| 1624 | .root_module = b.createModule(.{ |
| 1625 | .root_source_file = b.path("tools/doctest.zig"), |
| 1626 | .target = b.graph.host, |
| 1627 | .optimize = .debug, |
| 1628 | }), |
| 1629 | }); |
| 1630 | |
| 1631 | const langref_path = try b.root.join(arena, "doc/langref"); |
| 1632 | |
| 1633 | var dir = langref_path.root_dir.handle.openDir(io, langref_path.sub_path, .{ .iterate = true }) catch |err| |
| 1634 | std.debug.panic("unable to open directory {f}: {t}", .{ langref_path, err }); |
| 1635 | defer dir.close(io); |
| 1636 | |
| 1637 | var wf = b.addWriteFiles(); |
| 1638 | b.step("test-docs", "Test code snippets from the docs").dependOn(&wf.step); |
| 1639 | |
| 1640 | var it = dir.iterateAssumeFirstIteration(); |
| 1641 | while (it.next(io) catch @panic("failed to read dir")) |entry| { |
| 1642 | if (entry.kind != .file) continue; |
| 1643 | if (std.mem.startsWith(u8, entry.name, ".")) continue; |
| 1644 | if (!std.mem.endsWith(u8, entry.name, ".zig")) continue; |
| 1645 | |
| 1646 | const out_basename = b.fmt("{s}.out", .{std.fs.path.stem(entry.name)}); |
| 1647 | const cmd = b.addRunArtifact(doctest_exe); |
| 1648 | |
| 1649 | cmd.addArg("--zig"); |
| 1650 | cmd.addFileArg(.zig_exe); |
| 1651 | |
| 1652 | cmd.addArg("--cache-root"); |
| 1653 | cmd.addDirectoryArg(.cache_root); |
| 1654 | |
| 1655 | cmd.addArg("--zig-lib-dir"); |
| 1656 | cmd.addDirectoryArg(.zig_lib); |
| 1657 | |
| 1658 | cmd.addArg("-i"); |
| 1659 | cmd.addFileArg(b.path(b.fmt("doc/langref/{s}", .{entry.name}))); |
| 1660 | |
| 1661 | cmd.addArg("-o"); |
| 1662 | _ = wf.addCopyFile(cmd.addOutputFileArg(out_basename), out_basename); |
| 1663 | } |
| 1664 | |
| 1665 | const docgen_exe = b.addExecutable(.{ |
| 1666 | .name = "docgen", |
| 1667 | .root_module = b.createModule(.{ |
| 1668 | .root_source_file = b.path("tools/docgen.zig"), |
| 1669 | .target = b.graph.host, |
| 1670 | .optimize = .debug, |
| 1671 | }), |
| 1672 | }); |
| 1673 | |
| 1674 | const docgen_cmd = b.addRunArtifact(docgen_exe); |
| 1675 | docgen_cmd.addArgs(&.{"--code-dir"}); |
| 1676 | docgen_cmd.addDirectoryArg(wf.getDirectory()); |
| 1677 | docgen_cmd.addArgs(&.{"--grammar"}); |
| 1678 | docgen_cmd.addFileArg(b.path("doc/langref/grammar.peg")); |
| 1679 | |
| 1680 | docgen_cmd.addFileArg(b.path("doc/langref.html.in")); |
| 1681 | return docgen_cmd.addOutputFileArg("langref.html"); |
| 1682 | } |
| 1683 | |
| 1684 | fn superHtmlCheck(b: *std.Build, html_file: std.Build.LazyPath) *std.Build.Step { |
| 1685 | const run_superhtml = b.addSystemCommand(&.{ |
| 1686 | "superhtml", "check", |
| 1687 | }); |
| 1688 | run_superhtml.addFileArg(html_file); |
| 1689 | run_superhtml.expectExitCode(0); |
| 1690 | return &run_superhtml.step; |
| 1691 | } |