| author | |
| committer | |
| log | 43b830415368ac4fb08bf5e154a222a38baf4a24 |
| tree | eaf6206e2038cbf7af17098162458b78cac91058 |
| parent | 235e6ac05df95e5dc2656cfb1a33d7b18c45a603 |
| parent | acbb6418c3899eb79aea98e7f5d3173298716377 |
| signature |
Build.zig rename orgy. Renames FileSource to LazyPath and others74 files changed, 3023 insertions(+), 2824 deletions(-)
build.zig+20-25| ... | @@ -36,7 +36,7 @@ pub fn build(b: *std.Build) !void { | ... | @@ -36,7 +36,7 @@ pub fn build(b: *std.Build) !void { |
| 36 | 36 | ||
| 37 | const docgen_exe = b.addExecutable(.{ | 37 | const docgen_exe = b.addExecutable(.{ |
| 38 | .name = "docgen", | 38 | .name = "docgen", |
| 39 | .root_source_file = .{ .path = "doc/docgen.zig" }, | 39 | .root_source_file = .{ .path = "tools/docgen.zig" }, |
| 40 | .target = .{}, | 40 | .target = .{}, |
| 41 | .optimize = .Debug, | 41 | .optimize = .Debug, |
| 42 | }); | 42 | }); |
| ... | @@ -45,9 +45,10 @@ pub fn build(b: *std.Build) !void { | ... | @@ -45,9 +45,10 @@ pub fn build(b: *std.Build) !void { |
| 45 | const docgen_cmd = b.addRunArtifact(docgen_exe); | 45 | const docgen_cmd = b.addRunArtifact(docgen_exe); |
| 46 | docgen_cmd.addArgs(&.{ "--zig", b.zig_exe }); | 46 | docgen_cmd.addArgs(&.{ "--zig", b.zig_exe }); |
| 47 | if (b.zig_lib_dir) |p| { | 47 | if (b.zig_lib_dir) |p| { |
| 48 | docgen_cmd.addArgs(&.{ "--zig-lib-dir", p }); | 48 | docgen_cmd.addArg("--zig-lib-dir"); |
| 49 | docgen_cmd.addDirectoryArg(p); | ||
| 49 | } | 50 | } |
| 50 | docgen_cmd.addFileSourceArg(.{ .path = "doc/langref.html.in" }); | 51 | docgen_cmd.addFileArg(.{ .path = "doc/langref.html.in" }); |
| 51 | const langref_file = docgen_cmd.addOutputFileArg("langref.html"); | 52 | const langref_file = docgen_cmd.addOutputFileArg("langref.html"); |
| 52 | const install_langref = b.addInstallFileWithDir(langref_file, .prefix, "doc/langref.html"); | 53 | const install_langref = b.addInstallFileWithDir(langref_file, .prefix, "doc/langref.html"); |
| 53 | if (!skip_install_langref) { | 54 | if (!skip_install_langref) { |
| ... | @@ -57,9 +58,8 @@ pub fn build(b: *std.Build) !void { | ... | @@ -57,9 +58,8 @@ pub fn build(b: *std.Build) !void { |
| 57 | const autodoc_test = b.addTest(.{ | 58 | const autodoc_test = b.addTest(.{ |
| 58 | .root_source_file = .{ .path = "lib/std/std.zig" }, | 59 | .root_source_file = .{ .path = "lib/std/std.zig" }, |
| 59 | .target = target, | 60 | .target = target, |
| 61 | .zig_lib_dir = .{ .path = "lib" }, | ||
| 60 | }); | 62 | }); |
| 61 | autodoc_test.overrideZigLibDir("lib"); | ||
| 62 | autodoc_test.emit_bin = .no_emit; // https://github.com/ziglang/zig/issues/16351 | ||
| 63 | const install_std_docs = b.addInstallDirectory(.{ | 63 | const install_std_docs = b.addInstallDirectory(.{ |
| 64 | .source_dir = autodoc_test.getEmittedDocs(), | 64 | .source_dir = autodoc_test.getEmittedDocs(), |
| 65 | .install_dir = .prefix, | 65 | .install_dir = .prefix, |
| ... | @@ -88,8 +88,8 @@ pub fn build(b: *std.Build) !void { | ... | @@ -88,8 +88,8 @@ pub fn build(b: *std.Build) !void { |
| 88 | .name = "check-case", | 88 | .name = "check-case", |
| 89 | .root_source_file = .{ .path = "test/src/Cases.zig" }, | 89 | .root_source_file = .{ .path = "test/src/Cases.zig" }, |
| 90 | .optimize = optimize, | 90 | .optimize = optimize, |
| 91 | .main_pkg_path = .{ .path = "." }, | ||
| 91 | }); | 92 | }); |
| 92 | check_case_exe.main_pkg_path = "."; | ||
| 93 | check_case_exe.stack_size = stack_size; | 93 | check_case_exe.stack_size = stack_size; |
| 94 | check_case_exe.single_threaded = single_threaded; | 94 | check_case_exe.single_threaded = single_threaded; |
| 95 | 95 | ||
| ... | @@ -196,10 +196,6 @@ pub fn build(b: *std.Build) !void { | ... | @@ -196,10 +196,6 @@ pub fn build(b: *std.Build) !void { |
| 196 | exe.pie = pie; | 196 | exe.pie = pie; |
| 197 | exe.sanitize_thread = sanitize_thread; | 197 | exe.sanitize_thread = sanitize_thread; |
| 198 | exe.entitlements = entitlements; | 198 | exe.entitlements = entitlements; |
| 199 | // TODO -femit-bin/-fno-emit-bin should be inferred by the build system | ||
| 200 | // based on whether or not the exe is run or installed. | ||
| 201 | // https://github.com/ziglang/zig/issues/16351 | ||
| 202 | if (no_bin) exe.emit_bin = .no_emit; | ||
| 203 | 199 | ||
| 204 | exe.build_id = b.option( | 200 | exe.build_id = b.option( |
| 205 | std.Build.Step.Compile.BuildId, | 201 | std.Build.Step.Compile.BuildId, |
| ... | @@ -208,7 +204,7 @@ pub fn build(b: *std.Build) !void { | ... | @@ -208,7 +204,7 @@ pub fn build(b: *std.Build) !void { |
| 208 | ); | 204 | ); |
| 209 | 205 | ||
| 210 | if (!no_bin) { | 206 | if (!no_bin) { |
| 211 | const install_exe = b.addInstallArtifact(exe); | 207 | const install_exe = b.addInstallArtifact(exe, .{}); |
| 212 | if (flat) { | 208 | if (flat) { |
| 213 | install_exe.dest_dir = .prefix; | 209 | install_exe.dest_dir = .prefix; |
| 214 | } | 210 | } |
| ... | @@ -352,10 +348,9 @@ pub fn build(b: *std.Build) !void { | ... | @@ -352,10 +348,9 @@ pub fn build(b: *std.Build) !void { |
| 352 | exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation); | 348 | exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation); |
| 353 | exe_options.addOption(bool, "value_tracing", value_tracing); | 349 | exe_options.addOption(bool, "value_tracing", value_tracing); |
| 354 | if (tracy) |tracy_path| { | 350 | if (tracy) |tracy_path| { |
| 355 | const client_cpp = fs.path.join( | 351 | const client_cpp = b.pathJoin( |
| 356 | b.allocator, | ||
| 357 | &[_][]const u8{ tracy_path, "public", "TracyClient.cpp" }, | 352 | &[_][]const u8{ tracy_path, "public", "TracyClient.cpp" }, |
| 358 | ) catch unreachable; | 353 | ); |
| 359 | 354 | ||
| 360 | // On mingw, we need to opt into windows 7+ to get some features required by tracy. | 355 | // On mingw, we need to opt into windows 7+ to get some features required by tracy. |
| 361 | const tracy_c_flags: []const []const u8 = if (target.isWindows() and target.getAbi() == .gnu) | 356 | const tracy_c_flags: []const []const u8 = if (target.isWindows() and target.getAbi() == .gnu) |
| ... | @@ -363,8 +358,8 @@ pub fn build(b: *std.Build) !void { | ... | @@ -363,8 +358,8 @@ pub fn build(b: *std.Build) !void { |
| 363 | else | 358 | else |
| 364 | &[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" }; | 359 | &[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" }; |
| 365 | 360 | ||
| 366 | exe.addIncludePath(tracy_path); | 361 | exe.addIncludePath(.{ .cwd_relative = tracy_path }); |
| 367 | exe.addCSourceFile(client_cpp, tracy_c_flags); | 362 | exe.addCSourceFile(.{ .file = .{ .cwd_relative = client_cpp }, .flags = tracy_c_flags }); |
| 368 | if (!enable_llvm) { | 363 | if (!enable_llvm) { |
| 369 | exe.linkSystemLibraryName("c++"); | 364 | exe.linkSystemLibraryName("c++"); |
| 370 | } | 365 | } |
| ... | @@ -554,7 +549,7 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { | ... | @@ -554,7 +549,7 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { |
| 554 | }); | 549 | }); |
| 555 | run_opt.addArtifactArg(exe); | 550 | run_opt.addArtifactArg(exe); |
| 556 | run_opt.addArg("-o"); | 551 | run_opt.addArg("-o"); |
| 557 | run_opt.addFileSourceArg(.{ .path = "stage1/zig1.wasm" }); | 552 | run_opt.addFileArg(.{ .path = "stage1/zig1.wasm" }); |
| 558 | 553 | ||
| 559 | const copy_zig_h = b.addWriteFiles(); | 554 | const copy_zig_h = b.addWriteFiles(); |
| 560 | copy_zig_h.addCopyFileToSource(.{ .path = "lib/zig.h" }, "stage1/zig.h"); | 555 | copy_zig_h.addCopyFileToSource(.{ .path = "lib/zig.h" }, "stage1/zig.h"); |
| ... | @@ -603,7 +598,7 @@ fn addCmakeCfgOptionsToExe( | ... | @@ -603,7 +598,7 @@ fn addCmakeCfgOptionsToExe( |
| 603 | // useful for package maintainers | 598 | // useful for package maintainers |
| 604 | exe.headerpad_max_install_names = true; | 599 | exe.headerpad_max_install_names = true; |
| 605 | } | 600 | } |
| 606 | exe.addObjectFile(fs.path.join(b.allocator, &[_][]const u8{ | 601 | exe.addObjectFile(.{ .cwd_relative = b.pathJoin(&[_][]const u8{ |
| 607 | cfg.cmake_binary_dir, | 602 | cfg.cmake_binary_dir, |
| 608 | "zigcpp", | 603 | "zigcpp", |
| 609 | b.fmt("{s}{s}{s}", .{ | 604 | b.fmt("{s}{s}{s}", .{ |
| ... | @@ -611,11 +606,11 @@ fn addCmakeCfgOptionsToExe( | ... | @@ -611,11 +606,11 @@ fn addCmakeCfgOptionsToExe( |
| 611 | "zigcpp", | 606 | "zigcpp", |
| 612 | cfg.cmake_static_library_suffix, | 607 | cfg.cmake_static_library_suffix, |
| 613 | }), | 608 | }), |
| 614 | }) catch unreachable); | 609 | }) }); |
| 615 | assert(cfg.lld_include_dir.len != 0); | 610 | assert(cfg.lld_include_dir.len != 0); |
| 616 | exe.addIncludePath(cfg.lld_include_dir); | 611 | exe.addIncludePath(.{ .cwd_relative = cfg.lld_include_dir }); |
| 617 | exe.addIncludePath(cfg.llvm_include_dir); | 612 | exe.addIncludePath(.{ .cwd_relative = cfg.llvm_include_dir }); |
| 618 | exe.addLibraryPath(cfg.llvm_lib_dir); | 613 | exe.addLibraryPath(.{ .cwd_relative = cfg.llvm_lib_dir }); |
| 619 | addCMakeLibraryList(exe, cfg.clang_libraries); | 614 | addCMakeLibraryList(exe, cfg.clang_libraries); |
| 620 | addCMakeLibraryList(exe, cfg.lld_libraries); | 615 | addCMakeLibraryList(exe, cfg.lld_libraries); |
| 621 | addCMakeLibraryList(exe, cfg.llvm_libraries); | 616 | addCMakeLibraryList(exe, cfg.llvm_libraries); |
| ... | @@ -671,7 +666,7 @@ fn addCmakeCfgOptionsToExe( | ... | @@ -671,7 +666,7 @@ fn addCmakeCfgOptionsToExe( |
| 671 | } | 666 | } |
| 672 | 667 | ||
| 673 | if (cfg.dia_guids_lib.len != 0) { | 668 | if (cfg.dia_guids_lib.len != 0) { |
| 674 | exe.addObjectFile(cfg.dia_guids_lib); | 669 | exe.addObjectFile(.{ .cwd_relative = cfg.dia_guids_lib }); |
| 675 | } | 670 | } |
| 676 | } | 671 | } |
| 677 | 672 | ||
| ... | @@ -732,7 +727,7 @@ fn addCxxKnownPath( | ... | @@ -732,7 +727,7 @@ fn addCxxKnownPath( |
| 732 | } | 727 | } |
| 733 | return error.RequiredLibraryNotFound; | 728 | return error.RequiredLibraryNotFound; |
| 734 | } | 729 | } |
| 735 | exe.addObjectFile(path_unpadded); | 730 | exe.addObjectFile(.{ .cwd_relative = path_unpadded }); |
| 736 | 731 | ||
| 737 | // TODO a way to integrate with system c++ include files here | 732 | // TODO a way to integrate with system c++ include files here |
| 738 | // c++ -E -Wp,-v -xc++ /dev/null | 733 | // c++ -E -Wp,-v -xc++ /dev/null |
| ... | @@ -752,7 +747,7 @@ fn addCMakeLibraryList(exe: *std.Build.Step.Compile, list: []const u8) void { | ... | @@ -752,7 +747,7 @@ fn addCMakeLibraryList(exe: *std.Build.Step.Compile, list: []const u8) void { |
| 752 | } else if (exe.target.isWindows() and mem.endsWith(u8, lib, ".lib") and !fs.path.isAbsolute(lib)) { | 747 | } else if (exe.target.isWindows() and mem.endsWith(u8, lib, ".lib") and !fs.path.isAbsolute(lib)) { |
| 753 | exe.linkSystemLibrary(lib[0 .. lib.len - ".lib".len]); | 748 | exe.linkSystemLibrary(lib[0 .. lib.len - ".lib".len]); |
| 754 | } else { | 749 | } else { |
| 755 | exe.addObjectFile(lib); | 750 | exe.addObjectFile(.{ .cwd_relative = lib }); |
| 756 | } | 751 | } |
| 757 | } | 752 | } |
| 758 | } | 753 | } |
doc/docgen.zig deleted-2276| ... | @@ -1,2276 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const io = std.io; | ||
| 4 | const fs = std.fs; | ||
| 5 | const process = std.process; | ||
| 6 | const ChildProcess = std.ChildProcess; | ||
| 7 | const Progress = std.Progress; | ||
| 8 | const print = std.debug.print; | ||
| 9 | const mem = std.mem; | ||
| 10 | const testing = std.testing; | ||
| 11 | const Allocator = std.mem.Allocator; | ||
| 12 | |||
| 13 | const max_doc_file_size = 10 * 1024 * 1024; | ||
| 14 | |||
| 15 | const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt(); | ||
| 16 | const obj_ext = builtin.object_format.fileExt(builtin.cpu.arch); | ||
| 17 | const tmp_dir_name = "docgen_tmp"; | ||
| 18 | const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext; | ||
| 19 | |||
| 20 | const usage = | ||
| 21 | \\Usage: docgen [--zig] [--skip-code-tests] input output" | ||
| 22 | \\ | ||
| 23 | \\ Generates an HTML document from a docgen template. | ||
| 24 | \\ | ||
| 25 | \\Options: | ||
| 26 | \\ -h, --help Print this help and exit | ||
| 27 | \\ --skip-code-tests Skip the doctests | ||
| 28 | \\ | ||
| 29 | ; | ||
| 30 | |||
| 31 | fn fatal(comptime format: []const u8, args: anytype) noreturn { | ||
| 32 | const stderr = io.getStdErr().writer(); | ||
| 33 | |||
| 34 | stderr.print("error: " ++ format ++ "\n", args) catch {}; | ||
| 35 | process.exit(1); | ||
| 36 | } | ||
| 37 | |||
| 38 | pub fn main() !void { | ||
| 39 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||
| 40 | defer arena.deinit(); | ||
| 41 | |||
| 42 | const allocator = arena.allocator(); | ||
| 43 | |||
| 44 | var args_it = try process.argsWithAllocator(allocator); | ||
| 45 | if (!args_it.skip()) @panic("expected self arg"); | ||
| 46 | |||
| 47 | var zig_exe: []const u8 = "zig"; | ||
| 48 | var opt_zig_lib_dir: ?[]const u8 = null; | ||
| 49 | var do_code_tests = true; | ||
| 50 | var files = [_][]const u8{ "", "" }; | ||
| 51 | |||
| 52 | var i: usize = 0; | ||
| 53 | while (args_it.next()) |arg| { | ||
| 54 | if (mem.startsWith(u8, arg, "-")) { | ||
| 55 | if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { | ||
| 56 | const stdout = io.getStdOut().writer(); | ||
| 57 | try stdout.writeAll(usage); | ||
| 58 | process.exit(0); | ||
| 59 | } else if (mem.eql(u8, arg, "--zig")) { | ||
| 60 | if (args_it.next()) |param| { | ||
| 61 | zig_exe = param; | ||
| 62 | } else { | ||
| 63 | fatal("expected parameter after --zig", .{}); | ||
| 64 | } | ||
| 65 | } else if (mem.eql(u8, arg, "--zig-lib-dir")) { | ||
| 66 | if (args_it.next()) |param| { | ||
| 67 | opt_zig_lib_dir = param; | ||
| 68 | } else { | ||
| 69 | fatal("expected parameter after --zig-lib-dir", .{}); | ||
| 70 | } | ||
| 71 | } else if (mem.eql(u8, arg, "--skip-code-tests")) { | ||
| 72 | do_code_tests = false; | ||
| 73 | } else { | ||
| 74 | fatal("unrecognized option: '{s}'", .{arg}); | ||
| 75 | } | ||
| 76 | } else { | ||
| 77 | if (i > 1) { | ||
| 78 | fatal("too many arguments", .{}); | ||
| 79 | } | ||
| 80 | files[i] = arg; | ||
| 81 | i += 1; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | if (i < 2) { | ||
| 85 | fatal("not enough arguments", .{}); | ||
| 86 | } | ||
| 87 | |||
| 88 | var in_file = try fs.cwd().openFile(files[0], .{ .mode = .read_only }); | ||
| 89 | defer in_file.close(); | ||
| 90 | |||
| 91 | var out_file = try fs.cwd().createFile(files[1], .{}); | ||
| 92 | defer out_file.close(); | ||
| 93 | |||
| 94 | const input_file_bytes = try in_file.reader().readAllAlloc(allocator, max_doc_file_size); | ||
| 95 | |||
| 96 | var buffered_writer = io.bufferedWriter(out_file.writer()); | ||
| 97 | |||
| 98 | var tokenizer = Tokenizer.init(files[0], input_file_bytes); | ||
| 99 | var toc = try genToc(allocator, &tokenizer); | ||
| 100 | |||
| 101 | try fs.cwd().makePath(tmp_dir_name); | ||
| 102 | defer fs.cwd().deleteTree(tmp_dir_name) catch {}; | ||
| 103 | |||
| 104 | try genHtml(allocator, &tokenizer, &toc, buffered_writer.writer(), zig_exe, opt_zig_lib_dir, do_code_tests); | ||
| 105 | try buffered_writer.flush(); | ||
| 106 | } | ||
| 107 | |||
| 108 | const Token = struct { | ||
| 109 | id: Id, | ||
| 110 | start: usize, | ||
| 111 | end: usize, | ||
| 112 | |||
| 113 | const Id = enum { | ||
| 114 | invalid, | ||
| 115 | content, | ||
| 116 | bracket_open, | ||
| 117 | tag_content, | ||
| 118 | separator, | ||
| 119 | bracket_close, | ||
| 120 | eof, | ||
| 121 | }; | ||
| 122 | }; | ||
| 123 | |||
| 124 | const Tokenizer = struct { | ||
| 125 | buffer: []const u8, | ||
| 126 | index: usize, | ||
| 127 | state: State, | ||
| 128 | source_file_name: []const u8, | ||
| 129 | code_node_count: usize, | ||
| 130 | |||
| 131 | const State = enum { | ||
| 132 | start, | ||
| 133 | l_bracket, | ||
| 134 | hash, | ||
| 135 | tag_name, | ||
| 136 | eof, | ||
| 137 | }; | ||
| 138 | |||
| 139 | fn init(source_file_name: []const u8, buffer: []const u8) Tokenizer { | ||
| 140 | return Tokenizer{ | ||
| 141 | .buffer = buffer, | ||
| 142 | .index = 0, | ||
| 143 | .state = .start, | ||
| 144 | .source_file_name = source_file_name, | ||
| 145 | .code_node_count = 0, | ||
| 146 | }; | ||
| 147 | } | ||
| 148 | |||
| 149 | fn next(self: *Tokenizer) Token { | ||
| 150 | var result = Token{ | ||
| 151 | .id = .eof, | ||
| 152 | .start = self.index, | ||
| 153 | .end = undefined, | ||
| 154 | }; | ||
| 155 | while (self.index < self.buffer.len) : (self.index += 1) { | ||
| 156 | const c = self.buffer[self.index]; | ||
| 157 | switch (self.state) { | ||
| 158 | .start => switch (c) { | ||
| 159 | '{' => { | ||
| 160 | self.state = .l_bracket; | ||
| 161 | }, | ||
| 162 | else => { | ||
| 163 | result.id = .content; | ||
| 164 | }, | ||
| 165 | }, | ||
| 166 | .l_bracket => switch (c) { | ||
| 167 | '#' => { | ||
| 168 | if (result.id != .eof) { | ||
| 169 | self.index -= 1; | ||
| 170 | self.state = .start; | ||
| 171 | break; | ||
| 172 | } else { | ||
| 173 | result.id = .bracket_open; | ||
| 174 | self.index += 1; | ||
| 175 | self.state = .tag_name; | ||
| 176 | break; | ||
| 177 | } | ||
| 178 | }, | ||
| 179 | else => { | ||
| 180 | result.id = .content; | ||
| 181 | self.state = .start; | ||
| 182 | }, | ||
| 183 | }, | ||
| 184 | .tag_name => switch (c) { | ||
| 185 | '|' => { | ||
| 186 | if (result.id != .eof) { | ||
| 187 | break; | ||
| 188 | } else { | ||
| 189 | result.id = .separator; | ||
| 190 | self.index += 1; | ||
| 191 | break; | ||
| 192 | } | ||
| 193 | }, | ||
| 194 | '#' => { | ||
| 195 | self.state = .hash; | ||
| 196 | }, | ||
| 197 | else => { | ||
| 198 | result.id = .tag_content; | ||
| 199 | }, | ||
| 200 | }, | ||
| 201 | .hash => switch (c) { | ||
| 202 | '}' => { | ||
| 203 | if (result.id != .eof) { | ||
| 204 | self.index -= 1; | ||
| 205 | self.state = .tag_name; | ||
| 206 | break; | ||
| 207 | } else { | ||
| 208 | result.id = .bracket_close; | ||
| 209 | self.index += 1; | ||
| 210 | self.state = .start; | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | }, | ||
| 214 | else => { | ||
| 215 | result.id = .tag_content; | ||
| 216 | self.state = .tag_name; | ||
| 217 | }, | ||
| 218 | }, | ||
| 219 | .eof => unreachable, | ||
| 220 | } | ||
| 221 | } else { | ||
| 222 | switch (self.state) { | ||
| 223 | .start, .l_bracket, .eof => {}, | ||
| 224 | else => { | ||
| 225 | result.id = .invalid; | ||
| 226 | }, | ||
| 227 | } | ||
| 228 | self.state = .eof; | ||
| 229 | } | ||
| 230 | result.end = self.index; | ||
| 231 | return result; | ||
| 232 | } | ||
| 233 | |||
| 234 | const Location = struct { | ||
| 235 | line: usize, | ||
| 236 | column: usize, | ||
| 237 | line_start: usize, | ||
| 238 | line_end: usize, | ||
| 239 | }; | ||
| 240 | |||
| 241 | fn getTokenLocation(self: *Tokenizer, token: Token) Location { | ||
| 242 | var loc = Location{ | ||
| 243 | .line = 0, | ||
| 244 | .column = 0, | ||
| 245 | .line_start = 0, | ||
| 246 | .line_end = 0, | ||
| 247 | }; | ||
| 248 | for (self.buffer, 0..) |c, i| { | ||
| 249 | if (i == token.start) { | ||
| 250 | loc.line_end = i; | ||
| 251 | while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {} | ||
| 252 | return loc; | ||
| 253 | } | ||
| 254 | if (c == '\n') { | ||
| 255 | loc.line += 1; | ||
| 256 | loc.column = 0; | ||
| 257 | loc.line_start = i + 1; | ||
| 258 | } else { | ||
| 259 | loc.column += 1; | ||
| 260 | } | ||
| 261 | } | ||
| 262 | return loc; | ||
| 263 | } | ||
| 264 | }; | ||
| 265 | |||
| 266 | fn parseError(tokenizer: *Tokenizer, token: Token, comptime fmt: []const u8, args: anytype) anyerror { | ||
| 267 | const loc = tokenizer.getTokenLocation(token); | ||
| 268 | const args_prefix = .{ tokenizer.source_file_name, loc.line + 1, loc.column + 1 }; | ||
| 269 | print("{s}:{d}:{d}: error: " ++ fmt ++ "\n", args_prefix ++ args); | ||
| 270 | if (loc.line_start <= loc.line_end) { | ||
| 271 | print("{s}\n", .{tokenizer.buffer[loc.line_start..loc.line_end]}); | ||
| 272 | { | ||
| 273 | var i: usize = 0; | ||
| 274 | while (i < loc.column) : (i += 1) { | ||
| 275 | print(" ", .{}); | ||
| 276 | } | ||
| 277 | } | ||
| 278 | { | ||
| 279 | const caret_count = @min(token.end, loc.line_end) - token.start; | ||
| 280 | var i: usize = 0; | ||
| 281 | while (i < caret_count) : (i += 1) { | ||
| 282 | print("~", .{}); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | print("\n", .{}); | ||
| 286 | } | ||
| 287 | return error.ParseError; | ||
| 288 | } | ||
| 289 | |||
| 290 | fn assertToken(tokenizer: *Tokenizer, token: Token, id: Token.Id) !void { | ||
| 291 | if (token.id != id) { | ||
| 292 | return parseError(tokenizer, token, "expected {s}, found {s}", .{ @tagName(id), @tagName(token.id) }); | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | fn eatToken(tokenizer: *Tokenizer, id: Token.Id) !Token { | ||
| 297 | const token = tokenizer.next(); | ||
| 298 | try assertToken(tokenizer, token, id); | ||
| 299 | return token; | ||
| 300 | } | ||
| 301 | |||
| 302 | const HeaderOpen = struct { | ||
| 303 | name: []const u8, | ||
| 304 | url: []const u8, | ||
| 305 | n: usize, | ||
| 306 | }; | ||
| 307 | |||
| 308 | const SeeAlsoItem = struct { | ||
| 309 | name: []const u8, | ||
| 310 | token: Token, | ||
| 311 | }; | ||
| 312 | |||
| 313 | const ExpectedOutcome = enum { | ||
| 314 | succeed, | ||
| 315 | fail, | ||
| 316 | build_fail, | ||
| 317 | }; | ||
| 318 | |||
| 319 | const Code = struct { | ||
| 320 | id: Id, | ||
| 321 | name: []const u8, | ||
| 322 | source_token: Token, | ||
| 323 | just_check_syntax: bool, | ||
| 324 | mode: std.builtin.Mode, | ||
| 325 | link_objects: []const []const u8, | ||
| 326 | target_str: ?[]const u8, | ||
| 327 | link_libc: bool, | ||
| 328 | link_mode: ?std.builtin.LinkMode, | ||
| 329 | disable_cache: bool, | ||
| 330 | verbose_cimport: bool, | ||
| 331 | additional_options: []const []const u8, | ||
| 332 | |||
| 333 | const Id = union(enum) { | ||
| 334 | @"test", | ||
| 335 | test_error: []const u8, | ||
| 336 | test_safety: []const u8, | ||
| 337 | exe: ExpectedOutcome, | ||
| 338 | obj: ?[]const u8, | ||
| 339 | lib, | ||
| 340 | }; | ||
| 341 | }; | ||
| 342 | |||
| 343 | const Link = struct { | ||
| 344 | url: []const u8, | ||
| 345 | name: []const u8, | ||
| 346 | token: Token, | ||
| 347 | }; | ||
| 348 | |||
| 349 | const SyntaxBlock = struct { | ||
| 350 | source_type: SourceType, | ||
| 351 | name: []const u8, | ||
| 352 | source_token: Token, | ||
| 353 | |||
| 354 | const SourceType = enum { | ||
| 355 | zig, | ||
| 356 | c, | ||
| 357 | peg, | ||
| 358 | javascript, | ||
| 359 | }; | ||
| 360 | }; | ||
| 361 | |||
| 362 | const Node = union(enum) { | ||
| 363 | Content: []const u8, | ||
| 364 | Nav, | ||
| 365 | Builtin: Token, | ||
| 366 | HeaderOpen: HeaderOpen, | ||
| 367 | SeeAlso: []const SeeAlsoItem, | ||
| 368 | Code: Code, | ||
| 369 | Link: Link, | ||
| 370 | InlineSyntax: Token, | ||
| 371 | Shell: Token, | ||
| 372 | SyntaxBlock: SyntaxBlock, | ||
| 373 | }; | ||
| 374 | |||
| 375 | const Toc = struct { | ||
| 376 | nodes: []Node, | ||
| 377 | toc: []u8, | ||
| 378 | urls: std.StringHashMap(Token), | ||
| 379 | }; | ||
| 380 | |||
| 381 | const Action = enum { | ||
| 382 | open, | ||
| 383 | close, | ||
| 384 | }; | ||
| 385 | |||
| 386 | fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc { | ||
| 387 | var urls = std.StringHashMap(Token).init(allocator); | ||
| 388 | errdefer urls.deinit(); | ||
| 389 | |||
| 390 | var header_stack_size: usize = 0; | ||
| 391 | var last_action: Action = .open; | ||
| 392 | var last_columns: ?u8 = null; | ||
| 393 | |||
| 394 | var toc_buf = std.ArrayList(u8).init(allocator); | ||
| 395 | defer toc_buf.deinit(); | ||
| 396 | |||
| 397 | var toc = toc_buf.writer(); | ||
| 398 | |||
| 399 | var nodes = std.ArrayList(Node).init(allocator); | ||
| 400 | defer nodes.deinit(); | ||
| 401 | |||
| 402 | try toc.writeByte('\n'); | ||
| 403 | |||
| 404 | while (true) { | ||
| 405 | const token = tokenizer.next(); | ||
| 406 | switch (token.id) { | ||
| 407 | .eof => { | ||
| 408 | if (header_stack_size != 0) { | ||
| 409 | return parseError(tokenizer, token, "unbalanced headers", .{}); | ||
| 410 | } | ||
| 411 | try toc.writeAll(" </ul>\n"); | ||
| 412 | break; | ||
| 413 | }, | ||
| 414 | .content => { | ||
| 415 | try nodes.append(Node{ .Content = tokenizer.buffer[token.start..token.end] }); | ||
| 416 | }, | ||
| 417 | .bracket_open => { | ||
| 418 | const tag_token = try eatToken(tokenizer, .tag_content); | ||
| 419 | const tag_name = tokenizer.buffer[tag_token.start..tag_token.end]; | ||
| 420 | |||
| 421 | if (mem.eql(u8, tag_name, "nav")) { | ||
| 422 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 423 | |||
| 424 | try nodes.append(Node.Nav); | ||
| 425 | } else if (mem.eql(u8, tag_name, "builtin")) { | ||
| 426 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 427 | try nodes.append(Node{ .Builtin = tag_token }); | ||
| 428 | } else if (mem.eql(u8, tag_name, "header_open")) { | ||
| 429 | _ = try eatToken(tokenizer, .separator); | ||
| 430 | const content_token = try eatToken(tokenizer, .tag_content); | ||
| 431 | const content = tokenizer.buffer[content_token.start..content_token.end]; | ||
| 432 | var columns: ?u8 = null; | ||
| 433 | while (true) { | ||
| 434 | const bracket_tok = tokenizer.next(); | ||
| 435 | switch (bracket_tok.id) { | ||
| 436 | .bracket_close => break, | ||
| 437 | .separator => continue, | ||
| 438 | .tag_content => { | ||
| 439 | const param = tokenizer.buffer[bracket_tok.start..bracket_tok.end]; | ||
| 440 | if (mem.eql(u8, param, "2col")) { | ||
| 441 | columns = 2; | ||
| 442 | } else { | ||
| 443 | return parseError( | ||
| 444 | tokenizer, | ||
| 445 | bracket_tok, | ||
| 446 | "unrecognized header_open param: {s}", | ||
| 447 | .{param}, | ||
| 448 | ); | ||
| 449 | } | ||
| 450 | }, | ||
| 451 | else => return parseError(tokenizer, bracket_tok, "invalid header_open token", .{}), | ||
| 452 | } | ||
| 453 | } | ||
| 454 | |||
| 455 | header_stack_size += 1; | ||
| 456 | |||
| 457 | const urlized = try urlize(allocator, content); | ||
| 458 | try nodes.append(Node{ | ||
| 459 | .HeaderOpen = HeaderOpen{ | ||
| 460 | .name = content, | ||
| 461 | .url = urlized, | ||
| 462 | .n = header_stack_size + 1, // highest-level section headers start at h2 | ||
| 463 | }, | ||
| 464 | }); | ||
| 465 | if (try urls.fetchPut(urlized, tag_token)) |kv| { | ||
| 466 | parseError(tokenizer, tag_token, "duplicate header url: #{s}", .{urlized}) catch {}; | ||
| 467 | parseError(tokenizer, kv.value, "other tag here", .{}) catch {}; | ||
| 468 | return error.ParseError; | ||
| 469 | } | ||
| 470 | if (last_action == .open) { | ||
| 471 | try toc.writeByte('\n'); | ||
| 472 | try toc.writeByteNTimes(' ', header_stack_size * 4); | ||
| 473 | if (last_columns) |n| { | ||
| 474 | try toc.print("<ul style=\"columns: {}\">\n", .{n}); | ||
| 475 | } else { | ||
| 476 | try toc.writeAll("<ul>\n"); | ||
| 477 | } | ||
| 478 | } else { | ||
| 479 | last_action = .open; | ||
| 480 | } | ||
| 481 | last_columns = columns; | ||
| 482 | try toc.writeByteNTimes(' ', 4 + header_stack_size * 4); | ||
| 483 | try toc.print("<li><a id=\"toc-{s}\" href=\"#{s}\">{s}</a>", .{ urlized, urlized, content }); | ||
| 484 | } else if (mem.eql(u8, tag_name, "header_close")) { | ||
| 485 | if (header_stack_size == 0) { | ||
| 486 | return parseError(tokenizer, tag_token, "unbalanced close header", .{}); | ||
| 487 | } | ||
| 488 | header_stack_size -= 1; | ||
| 489 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 490 | |||
| 491 | if (last_action == .close) { | ||
| 492 | try toc.writeByteNTimes(' ', 8 + header_stack_size * 4); | ||
| 493 | try toc.writeAll("</ul></li>\n"); | ||
| 494 | } else { | ||
| 495 | try toc.writeAll("</li>\n"); | ||
| 496 | last_action = .close; | ||
| 497 | } | ||
| 498 | } else if (mem.eql(u8, tag_name, "see_also")) { | ||
| 499 | var list = std.ArrayList(SeeAlsoItem).init(allocator); | ||
| 500 | errdefer list.deinit(); | ||
| 501 | |||
| 502 | while (true) { | ||
| 503 | const see_also_tok = tokenizer.next(); | ||
| 504 | switch (see_also_tok.id) { | ||
| 505 | .tag_content => { | ||
| 506 | const content = tokenizer.buffer[see_also_tok.start..see_also_tok.end]; | ||
| 507 | try list.append(SeeAlsoItem{ | ||
| 508 | .name = content, | ||
| 509 | .token = see_also_tok, | ||
| 510 | }); | ||
| 511 | }, | ||
| 512 | .separator => {}, | ||
| 513 | .bracket_close => { | ||
| 514 | try nodes.append(Node{ .SeeAlso = try list.toOwnedSlice() }); | ||
| 515 | break; | ||
| 516 | }, | ||
| 517 | else => return parseError(tokenizer, see_also_tok, "invalid see_also token", .{}), | ||
| 518 | } | ||
| 519 | } | ||
| 520 | } else if (mem.eql(u8, tag_name, "link")) { | ||
| 521 | _ = try eatToken(tokenizer, .separator); | ||
| 522 | const name_tok = try eatToken(tokenizer, .tag_content); | ||
| 523 | const name = tokenizer.buffer[name_tok.start..name_tok.end]; | ||
| 524 | |||
| 525 | const url_name = blk: { | ||
| 526 | const tok = tokenizer.next(); | ||
| 527 | switch (tok.id) { | ||
| 528 | .bracket_close => break :blk name, | ||
| 529 | .separator => { | ||
| 530 | const explicit_text = try eatToken(tokenizer, .tag_content); | ||
| 531 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 532 | break :blk tokenizer.buffer[explicit_text.start..explicit_text.end]; | ||
| 533 | }, | ||
| 534 | else => return parseError(tokenizer, tok, "invalid link token", .{}), | ||
| 535 | } | ||
| 536 | }; | ||
| 537 | |||
| 538 | try nodes.append(Node{ | ||
| 539 | .Link = Link{ | ||
| 540 | .url = try urlize(allocator, url_name), | ||
| 541 | .name = name, | ||
| 542 | .token = name_tok, | ||
| 543 | }, | ||
| 544 | }); | ||
| 545 | } else if (mem.eql(u8, tag_name, "code_begin")) { | ||
| 546 | _ = try eatToken(tokenizer, .separator); | ||
| 547 | const code_kind_tok = try eatToken(tokenizer, .tag_content); | ||
| 548 | _ = try eatToken(tokenizer, .separator); | ||
| 549 | const name_tok = try eatToken(tokenizer, .tag_content); | ||
| 550 | const name = tokenizer.buffer[name_tok.start..name_tok.end]; | ||
| 551 | var error_str: []const u8 = ""; | ||
| 552 | const maybe_sep = tokenizer.next(); | ||
| 553 | switch (maybe_sep.id) { | ||
| 554 | .separator => { | ||
| 555 | const error_tok = try eatToken(tokenizer, .tag_content); | ||
| 556 | error_str = tokenizer.buffer[error_tok.start..error_tok.end]; | ||
| 557 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 558 | }, | ||
| 559 | .bracket_close => {}, | ||
| 560 | else => return parseError(tokenizer, token, "invalid token", .{}), | ||
| 561 | } | ||
| 562 | const code_kind_str = tokenizer.buffer[code_kind_tok.start..code_kind_tok.end]; | ||
| 563 | var code_kind_id: Code.Id = undefined; | ||
| 564 | var just_check_syntax = false; | ||
| 565 | if (mem.eql(u8, code_kind_str, "exe")) { | ||
| 566 | code_kind_id = Code.Id{ .exe = .succeed }; | ||
| 567 | } else if (mem.eql(u8, code_kind_str, "exe_err")) { | ||
| 568 | code_kind_id = Code.Id{ .exe = .fail }; | ||
| 569 | } else if (mem.eql(u8, code_kind_str, "exe_build_err")) { | ||
| 570 | code_kind_id = Code.Id{ .exe = .build_fail }; | ||
| 571 | } else if (mem.eql(u8, code_kind_str, "test")) { | ||
| 572 | code_kind_id = .@"test"; | ||
| 573 | } else if (mem.eql(u8, code_kind_str, "test_err")) { | ||
| 574 | code_kind_id = Code.Id{ .test_error = error_str }; | ||
| 575 | } else if (mem.eql(u8, code_kind_str, "test_safety")) { | ||
| 576 | code_kind_id = Code.Id{ .test_safety = error_str }; | ||
| 577 | } else if (mem.eql(u8, code_kind_str, "obj")) { | ||
| 578 | code_kind_id = Code.Id{ .obj = null }; | ||
| 579 | } else if (mem.eql(u8, code_kind_str, "obj_err")) { | ||
| 580 | code_kind_id = Code.Id{ .obj = error_str }; | ||
| 581 | } else if (mem.eql(u8, code_kind_str, "lib")) { | ||
| 582 | code_kind_id = Code.Id.lib; | ||
| 583 | } else if (mem.eql(u8, code_kind_str, "syntax")) { | ||
| 584 | code_kind_id = Code.Id{ .obj = null }; | ||
| 585 | just_check_syntax = true; | ||
| 586 | } else { | ||
| 587 | return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {s}", .{code_kind_str}); | ||
| 588 | } | ||
| 589 | |||
| 590 | var mode: std.builtin.Mode = .Debug; | ||
| 591 | var link_objects = std.ArrayList([]const u8).init(allocator); | ||
| 592 | defer link_objects.deinit(); | ||
| 593 | var target_str: ?[]const u8 = null; | ||
| 594 | var link_libc = false; | ||
| 595 | var link_mode: ?std.builtin.LinkMode = null; | ||
| 596 | var disable_cache = false; | ||
| 597 | var verbose_cimport = false; | ||
| 598 | var additional_options = std.ArrayList([]const u8).init(allocator); | ||
| 599 | defer additional_options.deinit(); | ||
| 600 | |||
| 601 | const source_token = while (true) { | ||
| 602 | const content_tok = try eatToken(tokenizer, .content); | ||
| 603 | _ = try eatToken(tokenizer, .bracket_open); | ||
| 604 | const end_code_tag = try eatToken(tokenizer, .tag_content); | ||
| 605 | const end_tag_name = tokenizer.buffer[end_code_tag.start..end_code_tag.end]; | ||
| 606 | if (mem.eql(u8, end_tag_name, "code_release_fast")) { | ||
| 607 | mode = .ReleaseFast; | ||
| 608 | } else if (mem.eql(u8, end_tag_name, "code_release_safe")) { | ||
| 609 | mode = .ReleaseSafe; | ||
| 610 | } else if (mem.eql(u8, end_tag_name, "code_disable_cache")) { | ||
| 611 | disable_cache = true; | ||
| 612 | } else if (mem.eql(u8, end_tag_name, "code_verbose_cimport")) { | ||
| 613 | verbose_cimport = true; | ||
| 614 | } else if (mem.eql(u8, end_tag_name, "code_link_object")) { | ||
| 615 | _ = try eatToken(tokenizer, .separator); | ||
| 616 | const obj_tok = try eatToken(tokenizer, .tag_content); | ||
| 617 | try link_objects.append(tokenizer.buffer[obj_tok.start..obj_tok.end]); | ||
| 618 | } else if (mem.eql(u8, end_tag_name, "target_windows")) { | ||
| 619 | target_str = "x86_64-windows"; | ||
| 620 | } else if (mem.eql(u8, end_tag_name, "target_linux_x86_64")) { | ||
| 621 | target_str = "x86_64-linux"; | ||
| 622 | } else if (mem.eql(u8, end_tag_name, "target_linux_riscv64")) { | ||
| 623 | target_str = "riscv64-linux"; | ||
| 624 | } else if (mem.eql(u8, end_tag_name, "target_wasm")) { | ||
| 625 | target_str = "wasm32-freestanding"; | ||
| 626 | } else if (mem.eql(u8, end_tag_name, "target_wasi")) { | ||
| 627 | target_str = "wasm32-wasi"; | ||
| 628 | } else if (mem.eql(u8, end_tag_name, "link_libc")) { | ||
| 629 | link_libc = true; | ||
| 630 | } else if (mem.eql(u8, end_tag_name, "link_mode_dynamic")) { | ||
| 631 | link_mode = .Dynamic; | ||
| 632 | } else if (mem.eql(u8, end_tag_name, "additonal_option")) { | ||
| 633 | _ = try eatToken(tokenizer, .separator); | ||
| 634 | const option = try eatToken(tokenizer, .tag_content); | ||
| 635 | try additional_options.append(tokenizer.buffer[option.start..option.end]); | ||
| 636 | } else if (mem.eql(u8, end_tag_name, "code_end")) { | ||
| 637 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 638 | break content_tok; | ||
| 639 | } else { | ||
| 640 | return parseError( | ||
| 641 | tokenizer, | ||
| 642 | end_code_tag, | ||
| 643 | "invalid token inside code_begin: {s}", | ||
| 644 | .{end_tag_name}, | ||
| 645 | ); | ||
| 646 | } | ||
| 647 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 648 | } else unreachable; // TODO issue #707 | ||
| 649 | try nodes.append(Node{ | ||
| 650 | .Code = Code{ | ||
| 651 | .id = code_kind_id, | ||
| 652 | .name = name, | ||
| 653 | .source_token = source_token, | ||
| 654 | .just_check_syntax = just_check_syntax, | ||
| 655 | .mode = mode, | ||
| 656 | .link_objects = try link_objects.toOwnedSlice(), | ||
| 657 | .target_str = target_str, | ||
| 658 | .link_libc = link_libc, | ||
| 659 | .link_mode = link_mode, | ||
| 660 | .disable_cache = disable_cache, | ||
| 661 | .verbose_cimport = verbose_cimport, | ||
| 662 | .additional_options = try additional_options.toOwnedSlice(), | ||
| 663 | }, | ||
| 664 | }); | ||
| 665 | tokenizer.code_node_count += 1; | ||
| 666 | } else if (mem.eql(u8, tag_name, "syntax")) { | ||
| 667 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 668 | const content_tok = try eatToken(tokenizer, .content); | ||
| 669 | _ = try eatToken(tokenizer, .bracket_open); | ||
| 670 | const end_syntax_tag = try eatToken(tokenizer, .tag_content); | ||
| 671 | const end_tag_name = tokenizer.buffer[end_syntax_tag.start..end_syntax_tag.end]; | ||
| 672 | if (!mem.eql(u8, end_tag_name, "endsyntax")) { | ||
| 673 | return parseError( | ||
| 674 | tokenizer, | ||
| 675 | end_syntax_tag, | ||
| 676 | "invalid token inside syntax: {s}", | ||
| 677 | .{end_tag_name}, | ||
| 678 | ); | ||
| 679 | } | ||
| 680 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 681 | try nodes.append(Node{ .InlineSyntax = content_tok }); | ||
| 682 | } else if (mem.eql(u8, tag_name, "shell_samp")) { | ||
| 683 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 684 | const content_tok = try eatToken(tokenizer, .content); | ||
| 685 | _ = try eatToken(tokenizer, .bracket_open); | ||
| 686 | const end_syntax_tag = try eatToken(tokenizer, .tag_content); | ||
| 687 | const end_tag_name = tokenizer.buffer[end_syntax_tag.start..end_syntax_tag.end]; | ||
| 688 | if (!mem.eql(u8, end_tag_name, "end_shell_samp")) { | ||
| 689 | return parseError( | ||
| 690 | tokenizer, | ||
| 691 | end_syntax_tag, | ||
| 692 | "invalid token inside syntax: {s}", | ||
| 693 | .{end_tag_name}, | ||
| 694 | ); | ||
| 695 | } | ||
| 696 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 697 | try nodes.append(Node{ .Shell = content_tok }); | ||
| 698 | } else if (mem.eql(u8, tag_name, "syntax_block")) { | ||
| 699 | _ = try eatToken(tokenizer, .separator); | ||
| 700 | const source_type_tok = try eatToken(tokenizer, .tag_content); | ||
| 701 | var name: []const u8 = "sample_code"; | ||
| 702 | const maybe_sep = tokenizer.next(); | ||
| 703 | switch (maybe_sep.id) { | ||
| 704 | .separator => { | ||
| 705 | const name_tok = try eatToken(tokenizer, .tag_content); | ||
| 706 | name = tokenizer.buffer[name_tok.start..name_tok.end]; | ||
| 707 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 708 | }, | ||
| 709 | .bracket_close => {}, | ||
| 710 | else => return parseError(tokenizer, token, "invalid token", .{}), | ||
| 711 | } | ||
| 712 | const source_type_str = tokenizer.buffer[source_type_tok.start..source_type_tok.end]; | ||
| 713 | var source_type: SyntaxBlock.SourceType = undefined; | ||
| 714 | if (mem.eql(u8, source_type_str, "zig")) { | ||
| 715 | source_type = SyntaxBlock.SourceType.zig; | ||
| 716 | } else if (mem.eql(u8, source_type_str, "c")) { | ||
| 717 | source_type = SyntaxBlock.SourceType.c; | ||
| 718 | } else if (mem.eql(u8, source_type_str, "peg")) { | ||
| 719 | source_type = SyntaxBlock.SourceType.peg; | ||
| 720 | } else if (mem.eql(u8, source_type_str, "javascript")) { | ||
| 721 | source_type = SyntaxBlock.SourceType.javascript; | ||
| 722 | } else { | ||
| 723 | return parseError(tokenizer, source_type_tok, "unrecognized code kind: {s}", .{source_type_str}); | ||
| 724 | } | ||
| 725 | const source_token = while (true) { | ||
| 726 | const content_tok = try eatToken(tokenizer, .content); | ||
| 727 | _ = try eatToken(tokenizer, .bracket_open); | ||
| 728 | const end_code_tag = try eatToken(tokenizer, .tag_content); | ||
| 729 | const end_tag_name = tokenizer.buffer[end_code_tag.start..end_code_tag.end]; | ||
| 730 | if (mem.eql(u8, end_tag_name, "end_syntax_block")) { | ||
| 731 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 732 | break content_tok; | ||
| 733 | } else { | ||
| 734 | return parseError( | ||
| 735 | tokenizer, | ||
| 736 | end_code_tag, | ||
| 737 | "invalid token inside code_begin: {s}", | ||
| 738 | .{end_tag_name}, | ||
| 739 | ); | ||
| 740 | } | ||
| 741 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 742 | }; | ||
| 743 | try nodes.append(Node{ .SyntaxBlock = SyntaxBlock{ .source_type = source_type, .name = name, .source_token = source_token } }); | ||
| 744 | } else { | ||
| 745 | return parseError(tokenizer, tag_token, "unrecognized tag name: {s}", .{tag_name}); | ||
| 746 | } | ||
| 747 | }, | ||
| 748 | else => return parseError(tokenizer, token, "invalid token", .{}), | ||
| 749 | } | ||
| 750 | } | ||
| 751 | |||
| 752 | return Toc{ | ||
| 753 | .nodes = try nodes.toOwnedSlice(), | ||
| 754 | .toc = try toc_buf.toOwnedSlice(), | ||
| 755 | .urls = urls, | ||
| 756 | }; | ||
| 757 | } | ||
| 758 | |||
| 759 | fn urlize(allocator: Allocator, input: []const u8) ![]u8 { | ||
| 760 | var buf = std.ArrayList(u8).init(allocator); | ||
| 761 | defer buf.deinit(); | ||
| 762 | |||
| 763 | const out = buf.writer(); | ||
| 764 | for (input) |c| { | ||
| 765 | switch (c) { | ||
| 766 | 'a'...'z', 'A'...'Z', '_', '-', '0'...'9' => { | ||
| 767 | try out.writeByte(c); | ||
| 768 | }, | ||
| 769 | ' ' => { | ||
| 770 | try out.writeByte('-'); | ||
| 771 | }, | ||
| 772 | else => {}, | ||
| 773 | } | ||
| 774 | } | ||
| 775 | return try buf.toOwnedSlice(); | ||
| 776 | } | ||
| 777 | |||
| 778 | fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 { | ||
| 779 | var buf = std.ArrayList(u8).init(allocator); | ||
| 780 | defer buf.deinit(); | ||
| 781 | |||
| 782 | const out = buf.writer(); | ||
| 783 | try writeEscaped(out, input); | ||
| 784 | return try buf.toOwnedSlice(); | ||
| 785 | } | ||
| 786 | |||
| 787 | fn writeEscaped(out: anytype, input: []const u8) !void { | ||
| 788 | for (input) |c| { | ||
| 789 | try switch (c) { | ||
| 790 | '&' => out.writeAll("&amp;"), | ||
| 791 | '<' => out.writeAll("&lt;"), | ||
| 792 | '>' => out.writeAll("&gt;"), | ||
| 793 | '"' => out.writeAll("&quot;"), | ||
| 794 | else => out.writeByte(c), | ||
| 795 | }; | ||
| 796 | } | ||
| 797 | } | ||
| 798 | |||
| 799 | // Returns true if number is in slice. | ||
| 800 | fn in(slice: []const u8, number: u8) bool { | ||
| 801 | for (slice) |n| { | ||
| 802 | if (number == n) return true; | ||
| 803 | } | ||
| 804 | return false; | ||
| 805 | } | ||
| 806 | |||
| 807 | fn termColor(allocator: Allocator, input: []const u8) ![]u8 { | ||
| 808 | // The SRG sequences generates by the Zig compiler are in the format: | ||
| 809 | // ESC [ <foreground-color> ; <n> m | ||
| 810 | // or | ||
| 811 | // ESC [ <n> m | ||
| 812 | // | ||
| 813 | // where | ||
| 814 | // foreground-color is 31 (red), 32 (green), 36 (cyan) | ||
| 815 | // n is 0 (reset), 1 (bold), 2 (dim) | ||
| 816 | // | ||
| 817 | // Note that 37 (white) is currently not used by the compiler. | ||
| 818 | // | ||
| 819 | // See std.debug.TTY.Color. | ||
| 820 | const supported_sgr_colors = [_]u8{ 31, 32, 36 }; | ||
| 821 | const supported_sgr_numbers = [_]u8{ 0, 1, 2 }; | ||
| 822 | |||
| 823 | var buf = std.ArrayList(u8).init(allocator); | ||
| 824 | defer buf.deinit(); | ||
| 825 | |||
| 826 | var out = buf.writer(); | ||
| 827 | var sgr_param_start_index: usize = undefined; | ||
| 828 | var sgr_num: u8 = undefined; | ||
| 829 | var sgr_color: u8 = undefined; | ||
| 830 | var i: usize = 0; | ||
| 831 | var state: enum { | ||
| 832 | start, | ||
| 833 | escape, | ||
| 834 | lbracket, | ||
| 835 | number, | ||
| 836 | after_number, | ||
| 837 | arg, | ||
| 838 | arg_number, | ||
| 839 | expect_end, | ||
| 840 | } = .start; | ||
| 841 | var last_new_line: usize = 0; | ||
| 842 | var open_span_count: usize = 0; | ||
| 843 | while (i < input.len) : (i += 1) { | ||
| 844 | const c = input[i]; | ||
| 845 | switch (state) { | ||
| 846 | .start => switch (c) { | ||
| 847 | '\x1b' => state = .escape, | ||
| 848 | '\n' => { | ||
| 849 | try out.writeByte(c); | ||
| 850 | last_new_line = buf.items.len; | ||
| 851 | }, | ||
| 852 | else => try out.writeByte(c), | ||
| 853 | }, | ||
| 854 | .escape => switch (c) { | ||
| 855 | '[' => state = .lbracket, | ||
| 856 | else => return error.UnsupportedEscape, | ||
| 857 | }, | ||
| 858 | .lbracket => switch (c) { | ||
| 859 | '0'...'9' => { | ||
| 860 | sgr_param_start_index = i; | ||
| 861 | state = .number; | ||
| 862 | }, | ||
| 863 | else => return error.UnsupportedEscape, | ||
| 864 | }, | ||
| 865 | .number => switch (c) { | ||
| 866 | '0'...'9' => {}, | ||
| 867 | else => { | ||
| 868 | sgr_num = try std.fmt.parseInt(u8, input[sgr_param_start_index..i], 10); | ||
| 869 | sgr_color = 0; | ||
| 870 | state = .after_number; | ||
| 871 | i -= 1; | ||
| 872 | }, | ||
| 873 | }, | ||
| 874 | .after_number => switch (c) { | ||
| 875 | ';' => state = .arg, | ||
| 876 | 'D' => state = .start, | ||
| 877 | 'K' => { | ||
| 878 | buf.items.len = last_new_line; | ||
| 879 | state = .start; | ||
| 880 | }, | ||
| 881 | else => { | ||
| 882 | state = .expect_end; | ||
| 883 | i -= 1; | ||
| 884 | }, | ||
| 885 | }, | ||
| 886 | .arg => switch (c) { | ||
| 887 | '0'...'9' => { | ||
| 888 | sgr_param_start_index = i; | ||
| 889 | state = .arg_number; | ||
| 890 | }, | ||
| 891 | else => return error.UnsupportedEscape, | ||
| 892 | }, | ||
| 893 | .arg_number => switch (c) { | ||
| 894 | '0'...'9' => {}, | ||
| 895 | else => { | ||
| 896 | // Keep the sequence consistent, foreground color first. | ||
| 897 | // 32;1m is equivalent to 1;32m, but the latter will | ||
| 898 | // generate an incorrect HTML class without notice. | ||
| 899 | sgr_color = sgr_num; | ||
| 900 | if (!in(&supported_sgr_colors, sgr_color)) return error.UnsupportedForegroundColor; | ||
| 901 | |||
| 902 | sgr_num = try std.fmt.parseInt(u8, input[sgr_param_start_index..i], 10); | ||
| 903 | if (!in(&supported_sgr_numbers, sgr_num)) return error.UnsupportedNumber; | ||
| 904 | |||
| 905 | state = .expect_end; | ||
| 906 | i -= 1; | ||
| 907 | }, | ||
| 908 | }, | ||
| 909 | .expect_end => switch (c) { | ||
| 910 | 'm' => { | ||
| 911 | state = .start; | ||
| 912 | while (open_span_count != 0) : (open_span_count -= 1) { | ||
| 913 | try out.writeAll("</span>"); | ||
| 914 | } | ||
| 915 | if (sgr_num == 0) { | ||
| 916 | if (sgr_color != 0) return error.UnsupportedColor; | ||
| 917 | continue; | ||
| 918 | } | ||
| 919 | if (sgr_color != 0) { | ||
| 920 | try out.print("<span class=\"sgr-{d}_{d}m\">", .{ sgr_color, sgr_num }); | ||
| 921 | } else { | ||
| 922 | try out.print("<span class=\"sgr-{d}m\">", .{sgr_num}); | ||
| 923 | } | ||
| 924 | open_span_count += 1; | ||
| 925 | }, | ||
| 926 | else => return error.UnsupportedEscape, | ||
| 927 | }, | ||
| 928 | } | ||
| 929 | } | ||
| 930 | return try buf.toOwnedSlice(); | ||
| 931 | } | ||
| 932 | |||
| 933 | const builtin_types = [_][]const u8{ | ||
| 934 | "f16", "f32", "f64", "f80", "f128", | ||
| 935 | "c_longdouble", "c_short", "c_ushort", "c_int", "c_uint", | ||
| 936 | "c_long", "c_ulong", "c_longlong", "c_ulonglong", "c_char", | ||
| 937 | "anyopaque", "void", "bool", "isize", "usize", | ||
| 938 | "noreturn", "type", "anyerror", "comptime_int", "comptime_float", | ||
| 939 | }; | ||
| 940 | |||
| 941 | fn isType(name: []const u8) bool { | ||
| 942 | for (builtin_types) |t| { | ||
| 943 | if (mem.eql(u8, t, name)) | ||
| 944 | return true; | ||
| 945 | } | ||
| 946 | return false; | ||
| 947 | } | ||
| 948 | |||
| 949 | const start_line = "<span class=\"line\">"; | ||
| 950 | const end_line = "</span>"; | ||
| 951 | |||
| 952 | fn writeEscapedLines(out: anytype, text: []const u8) !void { | ||
| 953 | for (text) |char| { | ||
| 954 | if (char == '\n') { | ||
| 955 | try out.writeAll(end_line); | ||
| 956 | try out.writeAll("\n"); | ||
| 957 | try out.writeAll(start_line); | ||
| 958 | } else { | ||
| 959 | try writeEscaped(out, &[_]u8{char}); | ||
| 960 | } | ||
| 961 | } | ||
| 962 | } | ||
| 963 | |||
| 964 | fn tokenizeAndPrintRaw( | ||
| 965 | allocator: Allocator, | ||
| 966 | docgen_tokenizer: *Tokenizer, | ||
| 967 | out: anytype, | ||
| 968 | source_token: Token, | ||
| 969 | raw_src: []const u8, | ||
| 970 | ) !void { | ||
| 971 | const src_non_terminated = mem.trim(u8, raw_src, " \n"); | ||
| 972 | const src = try allocator.dupeZ(u8, src_non_terminated); | ||
| 973 | |||
| 974 | try out.writeAll("<code>" ++ start_line); | ||
| 975 | var tokenizer = std.zig.Tokenizer.init(src); | ||
| 976 | var index: usize = 0; | ||
| 977 | var next_tok_is_fn = false; | ||
| 978 | while (true) { | ||
| 979 | const prev_tok_was_fn = next_tok_is_fn; | ||
| 980 | next_tok_is_fn = false; | ||
| 981 | |||
| 982 | const token = tokenizer.next(); | ||
| 983 | if (mem.indexOf(u8, src[index..token.loc.start], "//")) |comment_start_off| { | ||
| 984 | // render one comment | ||
| 985 | const comment_start = index + comment_start_off; | ||
| 986 | const comment_end_off = mem.indexOf(u8, src[comment_start..token.loc.start], "\n"); | ||
| 987 | const comment_end = if (comment_end_off) |o| comment_start + o else token.loc.start; | ||
| 988 | |||
| 989 | try writeEscapedLines(out, src[index..comment_start]); | ||
| 990 | try out.writeAll("<span class=\"tok-comment\">"); | ||
| 991 | try writeEscaped(out, src[comment_start..comment_end]); | ||
| 992 | try out.writeAll("</span>"); | ||
| 993 | index = comment_end; | ||
| 994 | tokenizer.index = index; | ||
| 995 | continue; | ||
| 996 | } | ||
| 997 | |||
| 998 | try writeEscapedLines(out, src[index..token.loc.start]); | ||
| 999 | switch (token.tag) { | ||
| 1000 | .eof => break, | ||
| 1001 | |||
| 1002 | .keyword_addrspace, | ||
| 1003 | .keyword_align, | ||
| 1004 | .keyword_and, | ||
| 1005 | .keyword_asm, | ||
| 1006 | .keyword_async, | ||
| 1007 | .keyword_await, | ||
| 1008 | .keyword_break, | ||
| 1009 | .keyword_catch, | ||
| 1010 | .keyword_comptime, | ||
| 1011 | .keyword_const, | ||
| 1012 | .keyword_continue, | ||
| 1013 | .keyword_defer, | ||
| 1014 | .keyword_else, | ||
| 1015 | .keyword_enum, | ||
| 1016 | .keyword_errdefer, | ||
| 1017 | .keyword_error, | ||
| 1018 | .keyword_export, | ||
| 1019 | .keyword_extern, | ||
| 1020 | .keyword_for, | ||
| 1021 | .keyword_if, | ||
| 1022 | .keyword_inline, | ||
| 1023 | .keyword_noalias, | ||
| 1024 | .keyword_noinline, | ||
| 1025 | .keyword_nosuspend, | ||
| 1026 | .keyword_opaque, | ||
| 1027 | .keyword_or, | ||
| 1028 | .keyword_orelse, | ||
| 1029 | .keyword_packed, | ||
| 1030 | .keyword_anyframe, | ||
| 1031 | .keyword_pub, | ||
| 1032 | .keyword_resume, | ||
| 1033 | .keyword_return, | ||
| 1034 | .keyword_linksection, | ||
| 1035 | .keyword_callconv, | ||
| 1036 | .keyword_struct, | ||
| 1037 | .keyword_suspend, | ||
| 1038 | .keyword_switch, | ||
| 1039 | .keyword_test, | ||
| 1040 | .keyword_threadlocal, | ||
| 1041 | .keyword_try, | ||
| 1042 | .keyword_union, | ||
| 1043 | .keyword_unreachable, | ||
| 1044 | .keyword_usingnamespace, | ||
| 1045 | .keyword_var, | ||
| 1046 | .keyword_volatile, | ||
| 1047 | .keyword_allowzero, | ||
| 1048 | .keyword_while, | ||
| 1049 | .keyword_anytype, | ||
| 1050 | => { | ||
| 1051 | try out.writeAll("<span class=\"tok-kw\">"); | ||
| 1052 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1053 | try out.writeAll("</span>"); | ||
| 1054 | }, | ||
| 1055 | |||
| 1056 | .keyword_fn => { | ||
| 1057 | try out.writeAll("<span class=\"tok-kw\">"); | ||
| 1058 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1059 | try out.writeAll("</span>"); | ||
| 1060 | next_tok_is_fn = true; | ||
| 1061 | }, | ||
| 1062 | |||
| 1063 | .string_literal, | ||
| 1064 | .char_literal, | ||
| 1065 | => { | ||
| 1066 | try out.writeAll("<span class=\"tok-str\">"); | ||
| 1067 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1068 | try out.writeAll("</span>"); | ||
| 1069 | }, | ||
| 1070 | |||
| 1071 | .multiline_string_literal_line => { | ||
| 1072 | if (src[token.loc.end - 1] == '\n') { | ||
| 1073 | try out.writeAll("<span class=\"tok-str\">"); | ||
| 1074 | try writeEscaped(out, src[token.loc.start .. token.loc.end - 1]); | ||
| 1075 | try out.writeAll("</span>" ++ end_line ++ "\n" ++ start_line); | ||
| 1076 | } else { | ||
| 1077 | try out.writeAll("<span class=\"tok-str\">"); | ||
| 1078 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1079 | try out.writeAll("</span>"); | ||
| 1080 | } | ||
| 1081 | }, | ||
| 1082 | |||
| 1083 | .builtin => { | ||
| 1084 | try out.writeAll("<span class=\"tok-builtin\">"); | ||
| 1085 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1086 | try out.writeAll("</span>"); | ||
| 1087 | }, | ||
| 1088 | |||
| 1089 | .doc_comment, | ||
| 1090 | .container_doc_comment, | ||
| 1091 | => { | ||
| 1092 | try out.writeAll("<span class=\"tok-comment\">"); | ||
| 1093 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1094 | try out.writeAll("</span>"); | ||
| 1095 | }, | ||
| 1096 | |||
| 1097 | .identifier => { | ||
| 1098 | const tok_bytes = src[token.loc.start..token.loc.end]; | ||
| 1099 | if (mem.eql(u8, tok_bytes, "undefined") or | ||
| 1100 | mem.eql(u8, tok_bytes, "null") or | ||
| 1101 | mem.eql(u8, tok_bytes, "true") or | ||
| 1102 | mem.eql(u8, tok_bytes, "false")) | ||
| 1103 | { | ||
| 1104 | try out.writeAll("<span class=\"tok-null\">"); | ||
| 1105 | try writeEscaped(out, tok_bytes); | ||
| 1106 | try out.writeAll("</span>"); | ||
| 1107 | } else if (prev_tok_was_fn) { | ||
| 1108 | try out.writeAll("<span class=\"tok-fn\">"); | ||
| 1109 | try writeEscaped(out, tok_bytes); | ||
| 1110 | try out.writeAll("</span>"); | ||
| 1111 | } else { | ||
| 1112 | const is_int = blk: { | ||
| 1113 | if (src[token.loc.start] != 'i' and src[token.loc.start] != 'u') | ||
| 1114 | break :blk false; | ||
| 1115 | var i = token.loc.start + 1; | ||
| 1116 | if (i == token.loc.end) | ||
| 1117 | break :blk false; | ||
| 1118 | while (i != token.loc.end) : (i += 1) { | ||
| 1119 | if (src[i] < '0' or src[i] > '9') | ||
| 1120 | break :blk false; | ||
| 1121 | } | ||
| 1122 | break :blk true; | ||
| 1123 | }; | ||
| 1124 | if (is_int or isType(tok_bytes)) { | ||
| 1125 | try out.writeAll("<span class=\"tok-type\">"); | ||
| 1126 | try writeEscaped(out, tok_bytes); | ||
| 1127 | try out.writeAll("</span>"); | ||
| 1128 | } else { | ||
| 1129 | try writeEscaped(out, tok_bytes); | ||
| 1130 | } | ||
| 1131 | } | ||
| 1132 | }, | ||
| 1133 | |||
| 1134 | .number_literal => { | ||
| 1135 | try out.writeAll("<span class=\"tok-number\">"); | ||
| 1136 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1137 | try out.writeAll("</span>"); | ||
| 1138 | }, | ||
| 1139 | |||
| 1140 | .bang, | ||
| 1141 | .pipe, | ||
| 1142 | .pipe_pipe, | ||
| 1143 | .pipe_equal, | ||
| 1144 | .equal, | ||
| 1145 | .equal_equal, | ||
| 1146 | .equal_angle_bracket_right, | ||
| 1147 | .bang_equal, | ||
| 1148 | .l_paren, | ||
| 1149 | .r_paren, | ||
| 1150 | .semicolon, | ||
| 1151 | .percent, | ||
| 1152 | .percent_equal, | ||
| 1153 | .l_brace, | ||
| 1154 | .r_brace, | ||
| 1155 | .l_bracket, | ||
| 1156 | .r_bracket, | ||
| 1157 | .period, | ||
| 1158 | .period_asterisk, | ||
| 1159 | .ellipsis2, | ||
| 1160 | .ellipsis3, | ||
| 1161 | .caret, | ||
| 1162 | .caret_equal, | ||
| 1163 | .plus, | ||
| 1164 | .plus_plus, | ||
| 1165 | .plus_equal, | ||
| 1166 | .plus_percent, | ||
| 1167 | .plus_percent_equal, | ||
| 1168 | .plus_pipe, | ||
| 1169 | .plus_pipe_equal, | ||
| 1170 | .minus, | ||
| 1171 | .minus_equal, | ||
| 1172 | .minus_percent, | ||
| 1173 | .minus_percent_equal, | ||
| 1174 | .minus_pipe, | ||
| 1175 | .minus_pipe_equal, | ||
| 1176 | .asterisk, | ||
| 1177 | .asterisk_equal, | ||
| 1178 | .asterisk_asterisk, | ||
| 1179 | .asterisk_percent, | ||
| 1180 | .asterisk_percent_equal, | ||
| 1181 | .asterisk_pipe, | ||
| 1182 | .asterisk_pipe_equal, | ||
| 1183 | .arrow, | ||
| 1184 | .colon, | ||
| 1185 | .slash, | ||
| 1186 | .slash_equal, | ||
| 1187 | .comma, | ||
| 1188 | .ampersand, | ||
| 1189 | .ampersand_equal, | ||
| 1190 | .question_mark, | ||
| 1191 | .angle_bracket_left, | ||
| 1192 | .angle_bracket_left_equal, | ||
| 1193 | .angle_bracket_angle_bracket_left, | ||
| 1194 | .angle_bracket_angle_bracket_left_equal, | ||
| 1195 | .angle_bracket_angle_bracket_left_pipe, | ||
| 1196 | .angle_bracket_angle_bracket_left_pipe_equal, | ||
| 1197 | .angle_bracket_right, | ||
| 1198 | .angle_bracket_right_equal, | ||
| 1199 | .angle_bracket_angle_bracket_right, | ||
| 1200 | .angle_bracket_angle_bracket_right_equal, | ||
| 1201 | .tilde, | ||
| 1202 | => try writeEscaped(out, src[token.loc.start..token.loc.end]), | ||
| 1203 | |||
| 1204 | .invalid, .invalid_periodasterisks => return parseError( | ||
| 1205 | docgen_tokenizer, | ||
| 1206 | source_token, | ||
| 1207 | "syntax error", | ||
| 1208 | .{}, | ||
| 1209 | ), | ||
| 1210 | } | ||
| 1211 | index = token.loc.end; | ||
| 1212 | } | ||
| 1213 | try out.writeAll(end_line ++ "</code>"); | ||
| 1214 | } | ||
| 1215 | |||
| 1216 | fn tokenizeAndPrint( | ||
| 1217 | allocator: Allocator, | ||
| 1218 | docgen_tokenizer: *Tokenizer, | ||
| 1219 | out: anytype, | ||
| 1220 | source_token: Token, | ||
| 1221 | ) !void { | ||
| 1222 | const raw_src = docgen_tokenizer.buffer[source_token.start..source_token.end]; | ||
| 1223 | return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: anytype, syntax_block: SyntaxBlock) !void { | ||
| 1227 | const source_type = @tagName(syntax_block.source_type); | ||
| 1228 | |||
| 1229 | try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{ source_type, syntax_block.name }); | ||
| 1230 | switch (syntax_block.source_type) { | ||
| 1231 | .zig => try tokenizeAndPrint(allocator, docgen_tokenizer, out, syntax_block.source_token), | ||
| 1232 | else => { | ||
| 1233 | const raw_source = docgen_tokenizer.buffer[syntax_block.source_token.start..syntax_block.source_token.end]; | ||
| 1234 | const trimmed_raw_source = mem.trim(u8, raw_source, " \n"); | ||
| 1235 | |||
| 1236 | try out.writeAll("<code>" ++ start_line); | ||
| 1237 | try writeEscapedLines(out, trimmed_raw_source); | ||
| 1238 | try out.writeAll(end_line ++ "</code>"); | ||
| 1239 | }, | ||
| 1240 | } | ||
| 1241 | try out.writeAll("</pre></figure>"); | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | fn printShell(out: anytype, shell_content: []const u8, escape: bool) !void { | ||
| 1245 | const trimmed_shell_content = mem.trim(u8, shell_content, " \n"); | ||
| 1246 | try out.writeAll("<figure><figcaption class=\"shell-cap\">Shell</figcaption><pre><samp>"); | ||
| 1247 | var cmd_cont: bool = false; | ||
| 1248 | var iter = std.mem.splitScalar(u8, trimmed_shell_content, '\n'); | ||
| 1249 | while (iter.next()) |orig_line| { | ||
| 1250 | const line = mem.trimRight(u8, orig_line, " "); | ||
| 1251 | if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] != '\\') { | ||
| 1252 | try out.writeAll("$ <kbd>"); | ||
| 1253 | const s = std.mem.trimLeft(u8, line[1..], " "); | ||
| 1254 | if (escape) { | ||
| 1255 | try writeEscaped(out, s); | ||
| 1256 | } else { | ||
| 1257 | try out.writeAll(s); | ||
| 1258 | } | ||
| 1259 | try out.writeAll("</kbd>" ++ "\n"); | ||
| 1260 | } else if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] == '\\') { | ||
| 1261 | try out.writeAll("$ <kbd>"); | ||
| 1262 | const s = std.mem.trimLeft(u8, line[1..], " "); | ||
| 1263 | if (escape) { | ||
| 1264 | try writeEscaped(out, s); | ||
| 1265 | } else { | ||
| 1266 | try out.writeAll(s); | ||
| 1267 | } | ||
| 1268 | try out.writeAll("\n"); | ||
| 1269 | cmd_cont = true; | ||
| 1270 | } else if (line.len > 0 and line[line.len - 1] != '\\' and cmd_cont) { | ||
| 1271 | if (escape) { | ||
| 1272 | try writeEscaped(out, line); | ||
| 1273 | } else { | ||
| 1274 | try out.writeAll(line); | ||
| 1275 | } | ||
| 1276 | try out.writeAll("</kbd>" ++ "\n"); | ||
| 1277 | cmd_cont = false; | ||
| 1278 | } else { | ||
| 1279 | if (escape) { | ||
| 1280 | try writeEscaped(out, line); | ||
| 1281 | } else { | ||
| 1282 | try out.writeAll(line); | ||
| 1283 | } | ||
| 1284 | try out.writeAll("\n"); | ||
| 1285 | } | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | try out.writeAll("</samp></pre></figure>"); | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | // Override this to skip to later tests | ||
| 1292 | const debug_start_line = 0; | ||
| 1293 | |||
| 1294 | fn genHtml( | ||
| 1295 | allocator: Allocator, | ||
| 1296 | tokenizer: *Tokenizer, | ||
| 1297 | toc: *Toc, | ||
| 1298 | out: anytype, | ||
| 1299 | zig_exe: []const u8, | ||
| 1300 | opt_zig_lib_dir: ?[]const u8, | ||
| 1301 | do_code_tests: bool, | ||
| 1302 | ) !void { | ||
| 1303 | var progress = Progress{ .dont_print_on_dumb = true }; | ||
| 1304 | const root_node = progress.start("Generating docgen examples", toc.nodes.len); | ||
| 1305 | defer root_node.end(); | ||
| 1306 | |||
| 1307 | var env_map = try process.getEnvMap(allocator); | ||
| 1308 | try env_map.put("YES_COLOR", "1"); | ||
| 1309 | |||
| 1310 | const host = try std.zig.system.NativeTargetInfo.detect(.{}); | ||
| 1311 | const builtin_code = try getBuiltinCode(allocator, &env_map, zig_exe, opt_zig_lib_dir); | ||
| 1312 | |||
| 1313 | for (toc.nodes) |node| { | ||
| 1314 | defer root_node.completeOne(); | ||
| 1315 | switch (node) { | ||
| 1316 | .Content => |data| { | ||
| 1317 | try out.writeAll(data); | ||
| 1318 | }, | ||
| 1319 | .Link => |info| { | ||
| 1320 | if (!toc.urls.contains(info.url)) { | ||
| 1321 | return parseError(tokenizer, info.token, "url not found: {s}", .{info.url}); | ||
| 1322 | } | ||
| 1323 | try out.print("<a href=\"#{s}\">{s}</a>", .{ info.url, info.name }); | ||
| 1324 | }, | ||
| 1325 | .Nav => { | ||
| 1326 | try out.writeAll(toc.toc); | ||
| 1327 | }, | ||
| 1328 | .Builtin => |tok| { | ||
| 1329 | try out.writeAll("<figure><figcaption class=\"zig-cap\"><cite>@import(\"builtin\")</cite></figcaption><pre>"); | ||
| 1330 | try tokenizeAndPrintRaw(allocator, tokenizer, out, tok, builtin_code); | ||
| 1331 | try out.writeAll("</pre></figure>"); | ||
| 1332 | }, | ||
| 1333 | .HeaderOpen => |info| { | ||
| 1334 | try out.print( | ||
| 1335 | "<h{d} id=\"{s}\"><a href=\"#toc-{s}\">{s}</a> <a class=\"hdr\" href=\"#{s}\">§</a></h{d}>\n", | ||
| 1336 | .{ info.n, info.url, info.url, info.name, info.url, info.n }, | ||
| 1337 | ); | ||
| 1338 | }, | ||
| 1339 | .SeeAlso => |items| { | ||
| 1340 | try out.writeAll("<p>See also:</p><ul>\n"); | ||
| 1341 | for (items) |item| { | ||
| 1342 | const url = try urlize(allocator, item.name); | ||
| 1343 | if (!toc.urls.contains(url)) { | ||
| 1344 | return parseError(tokenizer, item.token, "url not found: {s}", .{url}); | ||
| 1345 | } | ||
| 1346 | try out.print("<li><a href=\"#{s}\">{s}</a></li>\n", .{ url, item.name }); | ||
| 1347 | } | ||
| 1348 | try out.writeAll("</ul>\n"); | ||
| 1349 | }, | ||
| 1350 | .InlineSyntax => |content_tok| { | ||
| 1351 | try tokenizeAndPrint(allocator, tokenizer, out, content_tok); | ||
| 1352 | }, | ||
| 1353 | .Shell => |content_tok| { | ||
| 1354 | const raw_shell_content = tokenizer.buffer[content_tok.start..content_tok.end]; | ||
| 1355 | try printShell(out, raw_shell_content, true); | ||
| 1356 | }, | ||
| 1357 | .SyntaxBlock => |syntax_block| { | ||
| 1358 | try printSourceBlock(allocator, tokenizer, out, syntax_block); | ||
| 1359 | }, | ||
| 1360 | .Code => |code| { | ||
| 1361 | const name_plus_ext = try std.fmt.allocPrint(allocator, "{s}.zig", .{code.name}); | ||
| 1362 | const syntax_block = SyntaxBlock{ | ||
| 1363 | .source_type = .zig, | ||
| 1364 | .name = name_plus_ext, | ||
| 1365 | .source_token = code.source_token, | ||
| 1366 | }; | ||
| 1367 | |||
| 1368 | try printSourceBlock(allocator, tokenizer, out, syntax_block); | ||
| 1369 | |||
| 1370 | if (!do_code_tests) { | ||
| 1371 | continue; | ||
| 1372 | } | ||
| 1373 | |||
| 1374 | if (debug_start_line > 0) { | ||
| 1375 | const loc = tokenizer.getTokenLocation(code.source_token); | ||
| 1376 | if (debug_start_line > loc.line) { | ||
| 1377 | continue; | ||
| 1378 | } | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end]; | ||
| 1382 | const trimmed_raw_source = mem.trim(u8, raw_source, " \n"); | ||
| 1383 | const tmp_source_file_name = try fs.path.join( | ||
| 1384 | allocator, | ||
| 1385 | &[_][]const u8{ tmp_dir_name, name_plus_ext }, | ||
| 1386 | ); | ||
| 1387 | try fs.cwd().writeFile(tmp_source_file_name, trimmed_raw_source); | ||
| 1388 | |||
| 1389 | var shell_buffer = std.ArrayList(u8).init(allocator); | ||
| 1390 | defer shell_buffer.deinit(); | ||
| 1391 | var shell_out = shell_buffer.writer(); | ||
| 1392 | |||
| 1393 | switch (code.id) { | ||
| 1394 | .exe => |expected_outcome| code_block: { | ||
| 1395 | var build_args = std.ArrayList([]const u8).init(allocator); | ||
| 1396 | defer build_args.deinit(); | ||
| 1397 | try build_args.appendSlice(&[_][]const u8{ | ||
| 1398 | zig_exe, "build-exe", | ||
| 1399 | "--name", code.name, | ||
| 1400 | "--color", "on", | ||
| 1401 | name_plus_ext, | ||
| 1402 | }); | ||
| 1403 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1404 | try build_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir }); | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | try shell_out.print("$ zig build-exe {s} ", .{name_plus_ext}); | ||
| 1408 | |||
| 1409 | switch (code.mode) { | ||
| 1410 | .Debug => {}, | ||
| 1411 | else => { | ||
| 1412 | try build_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) }); | ||
| 1413 | try shell_out.print("-O {s} ", .{@tagName(code.mode)}); | ||
| 1414 | }, | ||
| 1415 | } | ||
| 1416 | for (code.link_objects) |link_object| { | ||
| 1417 | const name_with_ext = try std.fmt.allocPrint(allocator, "{s}{s}", .{ link_object, obj_ext }); | ||
| 1418 | try build_args.append(name_with_ext); | ||
| 1419 | try shell_out.print("{s} ", .{name_with_ext}); | ||
| 1420 | } | ||
| 1421 | if (code.link_libc) { | ||
| 1422 | try build_args.append("-lc"); | ||
| 1423 | try shell_out.print("-lc ", .{}); | ||
| 1424 | } | ||
| 1425 | const target = try std.zig.CrossTarget.parse(.{ | ||
| 1426 | .arch_os_abi = code.target_str orelse "native", | ||
| 1427 | }); | ||
| 1428 | if (code.target_str) |triple| { | ||
| 1429 | try build_args.appendSlice(&[_][]const u8{ "-target", triple }); | ||
| 1430 | try shell_out.print("-target {s} ", .{triple}); | ||
| 1431 | } | ||
| 1432 | if (code.verbose_cimport) { | ||
| 1433 | try build_args.append("--verbose-cimport"); | ||
| 1434 | try shell_out.print("--verbose-cimport ", .{}); | ||
| 1435 | } | ||
| 1436 | for (code.additional_options) |option| { | ||
| 1437 | try build_args.append(option); | ||
| 1438 | try shell_out.print("{s} ", .{option}); | ||
| 1439 | } | ||
| 1440 | |||
| 1441 | try shell_out.print("\n", .{}); | ||
| 1442 | |||
| 1443 | if (expected_outcome == .build_fail) { | ||
| 1444 | const result = try ChildProcess.exec(.{ | ||
| 1445 | .allocator = allocator, | ||
| 1446 | .argv = build_args.items, | ||
| 1447 | .cwd = tmp_dir_name, | ||
| 1448 | .env_map = &env_map, | ||
| 1449 | .max_output_bytes = max_doc_file_size, | ||
| 1450 | }); | ||
| 1451 | switch (result.term) { | ||
| 1452 | .Exited => |exit_code| { | ||
| 1453 | if (exit_code == 0) { | ||
| 1454 | progress.log("", .{}); | ||
| 1455 | print("{s}\nThe following command incorrectly succeeded:\n", .{result.stderr}); | ||
| 1456 | dumpArgs(build_args.items); | ||
| 1457 | return parseError(tokenizer, code.source_token, "example incorrectly compiled", .{}); | ||
| 1458 | } | ||
| 1459 | }, | ||
| 1460 | else => { | ||
| 1461 | progress.log("", .{}); | ||
| 1462 | print("{s}\nThe following command crashed:\n", .{result.stderr}); | ||
| 1463 | dumpArgs(build_args.items); | ||
| 1464 | return parseError(tokenizer, code.source_token, "example compile crashed", .{}); | ||
| 1465 | }, | ||
| 1466 | } | ||
| 1467 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1468 | const colored_stderr = try termColor(allocator, escaped_stderr); | ||
| 1469 | try shell_out.writeAll(colored_stderr); | ||
| 1470 | break :code_block; | ||
| 1471 | } | ||
| 1472 | const exec_result = exec(allocator, &env_map, tmp_dir_name, build_args.items) catch | ||
| 1473 | return parseError(tokenizer, code.source_token, "example failed to compile", .{}); | ||
| 1474 | |||
| 1475 | if (code.verbose_cimport) { | ||
| 1476 | const escaped_build_stderr = try escapeHtml(allocator, exec_result.stderr); | ||
| 1477 | try shell_out.writeAll(escaped_build_stderr); | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | if (code.target_str) |triple| { | ||
| 1481 | if (mem.startsWith(u8, triple, "wasm32") or | ||
| 1482 | mem.startsWith(u8, triple, "riscv64-linux") or | ||
| 1483 | (mem.startsWith(u8, triple, "x86_64-linux") and | ||
| 1484 | builtin.os.tag != .linux or builtin.cpu.arch != .x86_64)) | ||
| 1485 | { | ||
| 1486 | // skip execution | ||
| 1487 | break :code_block; | ||
| 1488 | } | ||
| 1489 | } | ||
| 1490 | |||
| 1491 | const path_to_exe = try std.fmt.allocPrint(allocator, "./{s}{s}", .{ | ||
| 1492 | code.name, | ||
| 1493 | target.exeFileExt(), | ||
| 1494 | }); | ||
| 1495 | const run_args = &[_][]const u8{path_to_exe}; | ||
| 1496 | |||
| 1497 | var exited_with_signal = false; | ||
| 1498 | |||
| 1499 | const result = if (expected_outcome == .fail) blk: { | ||
| 1500 | const result = try ChildProcess.exec(.{ | ||
| 1501 | .allocator = allocator, | ||
| 1502 | .argv = run_args, | ||
| 1503 | .env_map = &env_map, | ||
| 1504 | .cwd = tmp_dir_name, | ||
| 1505 | .max_output_bytes = max_doc_file_size, | ||
| 1506 | }); | ||
| 1507 | switch (result.term) { | ||
| 1508 | .Exited => |exit_code| { | ||
| 1509 | if (exit_code == 0) { | ||
| 1510 | progress.log("", .{}); | ||
| 1511 | print("{s}\nThe following command incorrectly succeeded:\n", .{result.stderr}); | ||
| 1512 | dumpArgs(run_args); | ||
| 1513 | return parseError(tokenizer, code.source_token, "example incorrectly compiled", .{}); | ||
| 1514 | } | ||
| 1515 | }, | ||
| 1516 | .Signal => exited_with_signal = true, | ||
| 1517 | else => {}, | ||
| 1518 | } | ||
| 1519 | break :blk result; | ||
| 1520 | } else blk: { | ||
| 1521 | break :blk exec(allocator, &env_map, tmp_dir_name, run_args) catch return parseError(tokenizer, code.source_token, "example crashed", .{}); | ||
| 1522 | }; | ||
| 1523 | |||
| 1524 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1525 | const escaped_stdout = try escapeHtml(allocator, result.stdout); | ||
| 1526 | |||
| 1527 | const colored_stderr = try termColor(allocator, escaped_stderr); | ||
| 1528 | const colored_stdout = try termColor(allocator, escaped_stdout); | ||
| 1529 | |||
| 1530 | try shell_out.print("$ ./{s}\n{s}{s}", .{ code.name, colored_stdout, colored_stderr }); | ||
| 1531 | if (exited_with_signal) { | ||
| 1532 | try shell_out.print("(process terminated by signal)", .{}); | ||
| 1533 | } | ||
| 1534 | try shell_out.writeAll("\n"); | ||
| 1535 | }, | ||
| 1536 | .@"test" => { | ||
| 1537 | var test_args = std.ArrayList([]const u8).init(allocator); | ||
| 1538 | defer test_args.deinit(); | ||
| 1539 | |||
| 1540 | try test_args.appendSlice(&[_][]const u8{ | ||
| 1541 | zig_exe, "test", | ||
| 1542 | tmp_source_file_name, | ||
| 1543 | }); | ||
| 1544 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1545 | try test_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir }); | ||
| 1546 | } | ||
| 1547 | try shell_out.print("$ zig test {s}.zig ", .{code.name}); | ||
| 1548 | |||
| 1549 | switch (code.mode) { | ||
| 1550 | .Debug => {}, | ||
| 1551 | else => { | ||
| 1552 | try test_args.appendSlice(&[_][]const u8{ | ||
| 1553 | "-O", @tagName(code.mode), | ||
| 1554 | }); | ||
| 1555 | try shell_out.print("-O {s} ", .{@tagName(code.mode)}); | ||
| 1556 | }, | ||
| 1557 | } | ||
| 1558 | if (code.link_libc) { | ||
| 1559 | try test_args.append("-lc"); | ||
| 1560 | try shell_out.print("-lc ", .{}); | ||
| 1561 | } | ||
| 1562 | if (code.target_str) |triple| { | ||
| 1563 | try test_args.appendSlice(&[_][]const u8{ "-target", triple }); | ||
| 1564 | try shell_out.print("-target {s} ", .{triple}); | ||
| 1565 | |||
| 1566 | const cross_target = try std.zig.CrossTarget.parse(.{ | ||
| 1567 | .arch_os_abi = triple, | ||
| 1568 | }); | ||
| 1569 | const target_info = try std.zig.system.NativeTargetInfo.detect( | ||
| 1570 | cross_target, | ||
| 1571 | ); | ||
| 1572 | switch (host.getExternalExecutor(target_info, .{ | ||
| 1573 | .link_libc = code.link_libc, | ||
| 1574 | })) { | ||
| 1575 | .native => {}, | ||
| 1576 | else => { | ||
| 1577 | try test_args.appendSlice(&[_][]const u8{"--test-no-exec"}); | ||
| 1578 | try shell_out.writeAll("--test-no-exec"); | ||
| 1579 | }, | ||
| 1580 | } | ||
| 1581 | } | ||
| 1582 | const result = exec(allocator, &env_map, null, test_args.items) catch | ||
| 1583 | return parseError(tokenizer, code.source_token, "test failed", .{}); | ||
| 1584 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1585 | const escaped_stdout = try escapeHtml(allocator, result.stdout); | ||
| 1586 | try shell_out.print("\n{s}{s}\n", .{ escaped_stderr, escaped_stdout }); | ||
| 1587 | }, | ||
| 1588 | .test_error => |error_match| { | ||
| 1589 | var test_args = std.ArrayList([]const u8).init(allocator); | ||
| 1590 | defer test_args.deinit(); | ||
| 1591 | |||
| 1592 | try test_args.appendSlice(&[_][]const u8{ | ||
| 1593 | zig_exe, "test", | ||
| 1594 | "--color", "on", | ||
| 1595 | tmp_source_file_name, | ||
| 1596 | }); | ||
| 1597 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1598 | try test_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir }); | ||
| 1599 | } | ||
| 1600 | try shell_out.print("$ zig test {s}.zig ", .{code.name}); | ||
| 1601 | |||
| 1602 | switch (code.mode) { | ||
| 1603 | .Debug => {}, | ||
| 1604 | else => { | ||
| 1605 | try test_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) }); | ||
| 1606 | try shell_out.print("-O {s} ", .{@tagName(code.mode)}); | ||
| 1607 | }, | ||
| 1608 | } | ||
| 1609 | if (code.link_libc) { | ||
| 1610 | try test_args.append("-lc"); | ||
| 1611 | try shell_out.print("-lc ", .{}); | ||
| 1612 | } | ||
| 1613 | const result = try ChildProcess.exec(.{ | ||
| 1614 | .allocator = allocator, | ||
| 1615 | .argv = test_args.items, | ||
| 1616 | .env_map = &env_map, | ||
| 1617 | .max_output_bytes = max_doc_file_size, | ||
| 1618 | }); | ||
| 1619 | switch (result.term) { | ||
| 1620 | .Exited => |exit_code| { | ||
| 1621 | if (exit_code == 0) { | ||
| 1622 | progress.log("", .{}); | ||
| 1623 | print("{s}\nThe following command incorrectly succeeded:\n", .{result.stderr}); | ||
| 1624 | dumpArgs(test_args.items); | ||
| 1625 | return parseError(tokenizer, code.source_token, "example incorrectly compiled", .{}); | ||
| 1626 | } | ||
| 1627 | }, | ||
| 1628 | else => { | ||
| 1629 | progress.log("", .{}); | ||
| 1630 | print("{s}\nThe following command crashed:\n", .{result.stderr}); | ||
| 1631 | dumpArgs(test_args.items); | ||
| 1632 | return parseError(tokenizer, code.source_token, "example compile crashed", .{}); | ||
| 1633 | }, | ||
| 1634 | } | ||
| 1635 | if (mem.indexOf(u8, result.stderr, error_match) == null) { | ||
| 1636 | progress.log("", .{}); | ||
| 1637 | print("{s}\nExpected to find '{s}' in stderr\n", .{ result.stderr, error_match }); | ||
| 1638 | return parseError(tokenizer, code.source_token, "example did not have expected compile error", .{}); | ||
| 1639 | } | ||
| 1640 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1641 | const colored_stderr = try termColor(allocator, escaped_stderr); | ||
| 1642 | try shell_out.print("\n{s}\n", .{colored_stderr}); | ||
| 1643 | }, | ||
| 1644 | .test_safety => |error_match| { | ||
| 1645 | var test_args = std.ArrayList([]const u8).init(allocator); | ||
| 1646 | defer test_args.deinit(); | ||
| 1647 | |||
| 1648 | try test_args.appendSlice(&[_][]const u8{ | ||
| 1649 | zig_exe, "test", | ||
| 1650 | tmp_source_file_name, | ||
| 1651 | }); | ||
| 1652 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1653 | try test_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir }); | ||
| 1654 | } | ||
| 1655 | var mode_arg: []const u8 = ""; | ||
| 1656 | switch (code.mode) { | ||
| 1657 | .Debug => {}, | ||
| 1658 | .ReleaseSafe => { | ||
| 1659 | try test_args.append("-OReleaseSafe"); | ||
| 1660 | mode_arg = "-OReleaseSafe"; | ||
| 1661 | }, | ||
| 1662 | .ReleaseFast => { | ||
| 1663 | try test_args.append("-OReleaseFast"); | ||
| 1664 | mode_arg = "-OReleaseFast"; | ||
| 1665 | }, | ||
| 1666 | .ReleaseSmall => { | ||
| 1667 | try test_args.append("-OReleaseSmall"); | ||
| 1668 | mode_arg = "-OReleaseSmall"; | ||
| 1669 | }, | ||
| 1670 | } | ||
| 1671 | |||
| 1672 | const result = try ChildProcess.exec(.{ | ||
| 1673 | .allocator = allocator, | ||
| 1674 | .argv = test_args.items, | ||
| 1675 | .env_map = &env_map, | ||
| 1676 | .max_output_bytes = max_doc_file_size, | ||
| 1677 | }); | ||
| 1678 | switch (result.term) { | ||
| 1679 | .Exited => |exit_code| { | ||
| 1680 | if (exit_code == 0) { | ||
| 1681 | progress.log("", .{}); | ||
| 1682 | print("{s}\nThe following command incorrectly succeeded:\n", .{result.stderr}); | ||
| 1683 | dumpArgs(test_args.items); | ||
| 1684 | return parseError(tokenizer, code.source_token, "example test incorrectly succeeded", .{}); | ||
| 1685 | } | ||
| 1686 | }, | ||
| 1687 | else => { | ||
| 1688 | progress.log("", .{}); | ||
| 1689 | print("{s}\nThe following command crashed:\n", .{result.stderr}); | ||
| 1690 | dumpArgs(test_args.items); | ||
| 1691 | return parseError(tokenizer, code.source_token, "example compile crashed", .{}); | ||
| 1692 | }, | ||
| 1693 | } | ||
| 1694 | if (mem.indexOf(u8, result.stderr, error_match) == null) { | ||
| 1695 | progress.log("", .{}); | ||
| 1696 | print("{s}\nExpected to find '{s}' in stderr\n", .{ result.stderr, error_match }); | ||
| 1697 | return parseError(tokenizer, code.source_token, "example did not have expected runtime safety error message", .{}); | ||
| 1698 | } | ||
| 1699 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1700 | const colored_stderr = try termColor(allocator, escaped_stderr); | ||
| 1701 | try shell_out.print("$ zig test {s}.zig {s}\n{s}\n", .{ | ||
| 1702 | code.name, | ||
| 1703 | mode_arg, | ||
| 1704 | colored_stderr, | ||
| 1705 | }); | ||
| 1706 | }, | ||
| 1707 | .obj => |maybe_error_match| { | ||
| 1708 | const name_plus_obj_ext = try std.fmt.allocPrint(allocator, "{s}{s}", .{ code.name, obj_ext }); | ||
| 1709 | var build_args = std.ArrayList([]const u8).init(allocator); | ||
| 1710 | defer build_args.deinit(); | ||
| 1711 | |||
| 1712 | try build_args.appendSlice(&[_][]const u8{ | ||
| 1713 | zig_exe, "build-obj", | ||
| 1714 | "--color", "on", | ||
| 1715 | "--name", code.name, | ||
| 1716 | tmp_source_file_name, | ||
| 1717 | try std.fmt.allocPrint(allocator, "-femit-bin={s}{c}{s}", .{ | ||
| 1718 | tmp_dir_name, fs.path.sep, name_plus_obj_ext, | ||
| 1719 | }), | ||
| 1720 | }); | ||
| 1721 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1722 | try build_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir }); | ||
| 1723 | } | ||
| 1724 | |||
| 1725 | try shell_out.print("$ zig build-obj {s}.zig ", .{code.name}); | ||
| 1726 | |||
| 1727 | switch (code.mode) { | ||
| 1728 | .Debug => {}, | ||
| 1729 | else => { | ||
| 1730 | try build_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) }); | ||
| 1731 | try shell_out.print("-O {s} ", .{@tagName(code.mode)}); | ||
| 1732 | }, | ||
| 1733 | } | ||
| 1734 | |||
| 1735 | if (code.target_str) |triple| { | ||
| 1736 | try build_args.appendSlice(&[_][]const u8{ "-target", triple }); | ||
| 1737 | try shell_out.print("-target {s} ", .{triple}); | ||
| 1738 | } | ||
| 1739 | for (code.additional_options) |option| { | ||
| 1740 | try build_args.append(option); | ||
| 1741 | try shell_out.print("{s} ", .{option}); | ||
| 1742 | } | ||
| 1743 | |||
| 1744 | if (maybe_error_match) |error_match| { | ||
| 1745 | const result = try ChildProcess.exec(.{ | ||
| 1746 | .allocator = allocator, | ||
| 1747 | .argv = build_args.items, | ||
| 1748 | .env_map = &env_map, | ||
| 1749 | .max_output_bytes = max_doc_file_size, | ||
| 1750 | }); | ||
| 1751 | switch (result.term) { | ||
| 1752 | .Exited => |exit_code| { | ||
| 1753 | if (exit_code == 0) { | ||
| 1754 | progress.log("", .{}); | ||
| 1755 | print("{s}\nThe following command incorrectly succeeded:\n", .{result.stderr}); | ||
| 1756 | dumpArgs(build_args.items); | ||
| 1757 | return parseError(tokenizer, code.source_token, "example build incorrectly succeeded", .{}); | ||
| 1758 | } | ||
| 1759 | }, | ||
| 1760 | else => { | ||
| 1761 | progress.log("", .{}); | ||
| 1762 | print("{s}\nThe following command crashed:\n", .{result.stderr}); | ||
| 1763 | dumpArgs(build_args.items); | ||
| 1764 | return parseError(tokenizer, code.source_token, "example compile crashed", .{}); | ||
| 1765 | }, | ||
| 1766 | } | ||
| 1767 | if (mem.indexOf(u8, result.stderr, error_match) == null) { | ||
| 1768 | progress.log("", .{}); | ||
| 1769 | print("{s}\nExpected to find '{s}' in stderr\n", .{ result.stderr, error_match }); | ||
| 1770 | return parseError(tokenizer, code.source_token, "example did not have expected compile error message", .{}); | ||
| 1771 | } | ||
| 1772 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1773 | const colored_stderr = try termColor(allocator, escaped_stderr); | ||
| 1774 | try shell_out.print("\n{s} ", .{colored_stderr}); | ||
| 1775 | } else { | ||
| 1776 | _ = exec(allocator, &env_map, null, build_args.items) catch return parseError(tokenizer, code.source_token, "example failed to compile", .{}); | ||
| 1777 | } | ||
| 1778 | try shell_out.writeAll("\n"); | ||
| 1779 | }, | ||
| 1780 | .lib => { | ||
| 1781 | const bin_basename = try std.zig.binNameAlloc(allocator, .{ | ||
| 1782 | .root_name = code.name, | ||
| 1783 | .target = builtin.target, | ||
| 1784 | .output_mode = .Lib, | ||
| 1785 | }); | ||
| 1786 | |||
| 1787 | var test_args = std.ArrayList([]const u8).init(allocator); | ||
| 1788 | defer test_args.deinit(); | ||
| 1789 | |||
| 1790 | try test_args.appendSlice(&[_][]const u8{ | ||
| 1791 | zig_exe, "build-lib", | ||
| 1792 | tmp_source_file_name, | ||
| 1793 | try std.fmt.allocPrint(allocator, "-femit-bin={s}{s}{s}", .{ | ||
| 1794 | tmp_dir_name, fs.path.sep_str, bin_basename, | ||
| 1795 | }), | ||
| 1796 | }); | ||
| 1797 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1798 | try test_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir }); | ||
| 1799 | } | ||
| 1800 | try shell_out.print("$ zig build-lib {s}.zig ", .{code.name}); | ||
| 1801 | |||
| 1802 | switch (code.mode) { | ||
| 1803 | .Debug => {}, | ||
| 1804 | else => { | ||
| 1805 | try test_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) }); | ||
| 1806 | try shell_out.print("-O {s} ", .{@tagName(code.mode)}); | ||
| 1807 | }, | ||
| 1808 | } | ||
| 1809 | if (code.target_str) |triple| { | ||
| 1810 | try test_args.appendSlice(&[_][]const u8{ "-target", triple }); | ||
| 1811 | try shell_out.print("-target {s} ", .{triple}); | ||
| 1812 | } | ||
| 1813 | if (code.link_mode) |link_mode| { | ||
| 1814 | switch (link_mode) { | ||
| 1815 | .Static => { | ||
| 1816 | try test_args.append("-static"); | ||
| 1817 | try shell_out.print("-static ", .{}); | ||
| 1818 | }, | ||
| 1819 | .Dynamic => { | ||
| 1820 | try test_args.append("-dynamic"); | ||
| 1821 | try shell_out.print("-dynamic ", .{}); | ||
| 1822 | }, | ||
| 1823 | } | ||
| 1824 | } | ||
| 1825 | for (code.additional_options) |option| { | ||
| 1826 | try test_args.append(option); | ||
| 1827 | try shell_out.print("{s} ", .{option}); | ||
| 1828 | } | ||
| 1829 | const result = exec(allocator, &env_map, null, test_args.items) catch return parseError(tokenizer, code.source_token, "test failed", .{}); | ||
| 1830 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1831 | const escaped_stdout = try escapeHtml(allocator, result.stdout); | ||
| 1832 | try shell_out.print("\n{s}{s}\n", .{ escaped_stderr, escaped_stdout }); | ||
| 1833 | }, | ||
| 1834 | } | ||
| 1835 | |||
| 1836 | if (!code.just_check_syntax) { | ||
| 1837 | try printShell(out, shell_buffer.items, false); | ||
| 1838 | } | ||
| 1839 | }, | ||
| 1840 | } | ||
| 1841 | } | ||
| 1842 | } | ||
| 1843 | |||
| 1844 | fn exec( | ||
| 1845 | allocator: Allocator, | ||
| 1846 | env_map: *process.EnvMap, | ||
| 1847 | cwd: ?[]const u8, | ||
| 1848 | args: []const []const u8, | ||
| 1849 | ) !ChildProcess.ExecResult { | ||
| 1850 | const result = try ChildProcess.exec(.{ | ||
| 1851 | .allocator = allocator, | ||
| 1852 | .argv = args, | ||
| 1853 | .env_map = env_map, | ||
| 1854 | .cwd = cwd, | ||
| 1855 | .max_output_bytes = max_doc_file_size, | ||
| 1856 | }); | ||
| 1857 | switch (result.term) { | ||
| 1858 | .Exited => |exit_code| { | ||
| 1859 | if (exit_code != 0) { | ||
| 1860 | print("{s}\nThe following command exited with code {}:\n", .{ result.stderr, exit_code }); | ||
| 1861 | dumpArgs(args); | ||
| 1862 | return error.ChildExitError; | ||
| 1863 | } | ||
| 1864 | }, | ||
| 1865 | else => { | ||
| 1866 | print("{s}\nThe following command crashed:\n", .{result.stderr}); | ||
| 1867 | dumpArgs(args); | ||
| 1868 | return error.ChildCrashed; | ||
| 1869 | }, | ||
| 1870 | } | ||
| 1871 | return result; | ||
| 1872 | } | ||
| 1873 | |||
| 1874 | fn getBuiltinCode( | ||
| 1875 | allocator: Allocator, | ||
| 1876 | env_map: *process.EnvMap, | ||
| 1877 | zig_exe: []const u8, | ||
| 1878 | opt_zig_lib_dir: ?[]const u8, | ||
| 1879 | ) ![]const u8 { | ||
| 1880 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1881 | const result = try exec(allocator, env_map, null, &.{ | ||
| 1882 | zig_exe, "build-obj", "--show-builtin", "--zig-lib-dir", zig_lib_dir, | ||
| 1883 | }); | ||
| 1884 | return result.stdout; | ||
| 1885 | } else { | ||
| 1886 | const result = try exec(allocator, env_map, null, &.{ | ||
| 1887 | zig_exe, "build-obj", "--show-builtin", | ||
| 1888 | }); | ||
| 1889 | return result.stdout; | ||
| 1890 | } | ||
| 1891 | } | ||
| 1892 | |||
| 1893 | fn dumpArgs(args: []const []const u8) void { | ||
| 1894 | for (args) |arg| | ||
| 1895 | print("{s} ", .{arg}) | ||
| 1896 | else | ||
| 1897 | print("\n", .{}); | ||
| 1898 | } | ||
| 1899 | |||
| 1900 | test "term supported colors" { | ||
| 1901 | const test_allocator = testing.allocator; | ||
| 1902 | |||
| 1903 | { | ||
| 1904 | const input = "A\x1b[31;1mred\x1b[0mB"; | ||
| 1905 | const expect = "A<span class=\"sgr-31_1m\">red</span>B"; | ||
| 1906 | |||
| 1907 | const result = try termColor(test_allocator, input); | ||
| 1908 | defer test_allocator.free(result); | ||
| 1909 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1910 | } | ||
| 1911 | |||
| 1912 | { | ||
| 1913 | const input = "A\x1b[32;1mgreen\x1b[0mB"; | ||
| 1914 | const expect = "A<span class=\"sgr-32_1m\">green</span>B"; | ||
| 1915 | |||
| 1916 | const result = try termColor(test_allocator, input); | ||
| 1917 | defer test_allocator.free(result); | ||
| 1918 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1919 | } | ||
| 1920 | |||
| 1921 | { | ||
| 1922 | const input = "A\x1b[36;1mcyan\x1b[0mB"; | ||
| 1923 | const expect = "A<span class=\"sgr-36_1m\">cyan</span>B"; | ||
| 1924 | |||
| 1925 | const result = try termColor(test_allocator, input); | ||
| 1926 | defer test_allocator.free(result); | ||
| 1927 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1928 | } | ||
| 1929 | |||
| 1930 | { | ||
| 1931 | const input = "A\x1b[1mbold\x1b[0mB"; | ||
| 1932 | const expect = "A<span class=\"sgr-1m\">bold</span>B"; | ||
| 1933 | |||
| 1934 | const result = try termColor(test_allocator, input); | ||
| 1935 | defer test_allocator.free(result); | ||
| 1936 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1937 | } | ||
| 1938 | |||
| 1939 | { | ||
| 1940 | const input = "A\x1b[2mdim\x1b[0mB"; | ||
| 1941 | const expect = "A<span class=\"sgr-2m\">dim</span>B"; | ||
| 1942 | |||
| 1943 | const result = try termColor(test_allocator, input); | ||
| 1944 | defer test_allocator.free(result); | ||
| 1945 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1946 | } | ||
| 1947 | } | ||
| 1948 | |||
| 1949 | test "term output from zig" { | ||
| 1950 | // Use data generated by https://github.com/perillo/zig-tty-test-data, | ||
| 1951 | // with zig version 0.11.0-dev.1898+36d47dd19. | ||
| 1952 | const test_allocator = testing.allocator; | ||
| 1953 | |||
| 1954 | { | ||
| 1955 | // 1.1-with-build-progress.out | ||
| 1956 | const input = "Semantic Analysis [1324] \x1b[25D\x1b[0KLLVM Emit Object... \x1b[20D\x1b[0KLLVM Emit Object... \x1b[20D\x1b[0KLLD Link... \x1b[12D\x1b[0K"; | ||
| 1957 | const expect = ""; | ||
| 1958 | |||
| 1959 | const result = try termColor(test_allocator, input); | ||
| 1960 | defer test_allocator.free(result); | ||
| 1961 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1962 | } | ||
| 1963 | |||
| 1964 | { | ||
| 1965 | // 2.1-with-reference-traces.out | ||
| 1966 | const input = "\x1b[1msrc/2.1-with-reference-traces.zig:3:7: \x1b[31;1merror: \x1b[0m\x1b[1mcannot assign to constant\n\x1b[0m x += 1;\n \x1b[32;1m~~^~~~\n\x1b[0m\x1b[0m\x1b[2mreferenced by:\n main: src/2.1-with-reference-traces.zig:7:5\n callMain: /usr/local/lib/zig/lib/std/start.zig:607:17\n remaining reference traces hidden; use '-freference-trace' to see all reference traces\n\n\x1b[0m"; | ||
| 1967 | const expect = | ||
| 1968 | \\<span class="sgr-1m">src/2.1-with-reference-traces.zig:3:7: </span><span class="sgr-31_1m">error: </span><span class="sgr-1m">cannot assign to constant | ||
| 1969 | \\</span> x += 1; | ||
| 1970 | \\ <span class="sgr-32_1m">~~^~~~ | ||
| 1971 | \\</span><span class="sgr-2m">referenced by: | ||
| 1972 | \\ main: src/2.1-with-reference-traces.zig:7:5 | ||
| 1973 | \\ callMain: /usr/local/lib/zig/lib/std/start.zig:607:17 | ||
| 1974 | \\ remaining reference traces hidden; use '-freference-trace' to see all reference traces | ||
| 1975 | \\ | ||
| 1976 | \\</span> | ||
| 1977 | ; | ||
| 1978 | |||
| 1979 | const result = try termColor(test_allocator, input); | ||
| 1980 | defer test_allocator.free(result); | ||
| 1981 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1982 | } | ||
| 1983 | |||
| 1984 | { | ||
| 1985 | // 2.2-without-reference-traces.out | ||
| 1986 | const input = "\x1b[1m/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:128:29: \x1b[31;1merror: \x1b[0m\x1b[1minvalid type given to fixedBufferStream\n\x1b[0m else => @compileError(\"invalid type given to fixedBufferStream\"),\n \x1b[32;1m^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\x1b[0m\x1b[1m/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:116:66: \x1b[36;1mnote: \x1b[0m\x1b[1mcalled from here\n\x1b[0mpub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) {\n; \x1b[32;1m~~~~~^~~~~~~~~~~~~~~~~\n\x1b[0m"; | ||
| 1987 | const expect = | ||
| 1988 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:128:29: </span><span class="sgr-31_1m">error: </span><span class="sgr-1m">invalid type given to fixedBufferStream | ||
| 1989 | \\</span> else => @compileError("invalid type given to fixedBufferStream"), | ||
| 1990 | \\ <span class="sgr-32_1m">^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 1991 | \\</span><span class="sgr-1m">/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:116:66: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">called from here | ||
| 1992 | \\</span>pub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) { | ||
| 1993 | \\; <span class="sgr-32_1m">~~~~~^~~~~~~~~~~~~~~~~ | ||
| 1994 | \\</span> | ||
| 1995 | ; | ||
| 1996 | |||
| 1997 | const result = try termColor(test_allocator, input); | ||
| 1998 | defer test_allocator.free(result); | ||
| 1999 | try testing.expectEqualSlices(u8, expect, result); | ||
| 2000 | } | ||
| 2001 | |||
| 2002 | { | ||
| 2003 | // 2.3-with-notes.out | ||
| 2004 | const input = "\x1b[1msrc/2.3-with-notes.zig:6:9: \x1b[31;1merror: \x1b[0m\x1b[1mexpected type '*2.3-with-notes.Derp', found '*2.3-with-notes.Wat'\n\x1b[0m bar(w);\n \x1b[32;1m^\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:6:9: \x1b[36;1mnote: \x1b[0m\x1b[1mpointer type child '2.3-with-notes.Wat' cannot cast into pointer type child '2.3-with-notes.Derp'\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:2:13: \x1b[36;1mnote: \x1b[0m\x1b[1mopaque declared here\n\x1b[0mconst Wat = opaque {};\n \x1b[32;1m^~~~~~~~~\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:1:14: \x1b[36;1mnote: \x1b[0m\x1b[1mopaque declared here\n\x1b[0mconst Derp = opaque {};\n \x1b[32;1m^~~~~~~~~\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:4:18: \x1b[36;1mnote: \x1b[0m\x1b[1mparameter type declared here\n\x1b[0mextern fn bar(d: *Derp) void;\n \x1b[32;1m^~~~~\n\x1b[0m\x1b[0m\x1b[2mreferenced by:\n main: src/2.3-with-notes.zig:10:5\n callMain: /usr/local/lib/zig/lib/std/start.zig:607:17\n remaining reference traces hidden; use '-freference-trace' to see all reference traces\n\n\x1b[0m"; | ||
| 2005 | const expect = | ||
| 2006 | \\<span class="sgr-1m">src/2.3-with-notes.zig:6:9: </span><span class="sgr-31_1m">error: </span><span class="sgr-1m">expected type '*2.3-with-notes.Derp', found '*2.3-with-notes.Wat' | ||
| 2007 | \\</span> bar(w); | ||
| 2008 | \\ <span class="sgr-32_1m">^ | ||
| 2009 | \\</span><span class="sgr-1m">src/2.3-with-notes.zig:6:9: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">pointer type child '2.3-with-notes.Wat' cannot cast into pointer type child '2.3-with-notes.Derp' | ||
| 2010 | \\</span><span class="sgr-1m">src/2.3-with-notes.zig:2:13: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">opaque declared here | ||
| 2011 | \\</span>const Wat = opaque {}; | ||
| 2012 | \\ <span class="sgr-32_1m">^~~~~~~~~ | ||
| 2013 | \\</span><span class="sgr-1m">src/2.3-with-notes.zig:1:14: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">opaque declared here | ||
| 2014 | \\</span>const Derp = opaque {}; | ||
| 2015 | \\ <span class="sgr-32_1m">^~~~~~~~~ | ||
| 2016 | \\</span><span class="sgr-1m">src/2.3-with-notes.zig:4:18: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">parameter type declared here | ||
| 2017 | \\</span>extern fn bar(d: *Derp) void; | ||
| 2018 | \\ <span class="sgr-32_1m">^~~~~ | ||
| 2019 | \\</span><span class="sgr-2m">referenced by: | ||
| 2020 | \\ main: src/2.3-with-notes.zig:10:5 | ||
| 2021 | \\ callMain: /usr/local/lib/zig/lib/std/start.zig:607:17 | ||
| 2022 | \\ remaining reference traces hidden; use '-freference-trace' to see all reference traces | ||
| 2023 | \\ | ||
| 2024 | \\</span> | ||
| 2025 | ; | ||
| 2026 | |||
| 2027 | const result = try termColor(test_allocator, input); | ||
| 2028 | defer test_allocator.free(result); | ||
| 2029 | try testing.expectEqualSlices(u8, expect, result); | ||
| 2030 | } | ||
| 2031 | |||
| 2032 | { | ||
| 2033 | // 3.1-with-error-return-traces.out | ||
| 2034 | |||
| 2035 | const input = "error: Error\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:5:5\x1b[0m: \x1b[2m0x20b008 in callee (3.1-with-error-return-traces)\x1b[0m\n return error.Error;\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:9:5\x1b[0m: \x1b[2m0x20b113 in caller (3.1-with-error-return-traces)\x1b[0m\n try callee();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:13:5\x1b[0m: \x1b[2m0x20b153 in main (3.1-with-error-return-traces)\x1b[0m\n try caller();\n \x1b[32;1m^\x1b[0m\n"; | ||
| 2036 | const expect = | ||
| 2037 | \\error: Error | ||
| 2038 | \\<span class="sgr-1m">/home/zig/src/3.1-with-error-return-traces.zig:5:5</span>: <span class="sgr-2m">0x20b008 in callee (3.1-with-error-return-traces)</span> | ||
| 2039 | \\ return error.Error; | ||
| 2040 | \\ <span class="sgr-32_1m">^</span> | ||
| 2041 | \\<span class="sgr-1m">/home/zig/src/3.1-with-error-return-traces.zig:9:5</span>: <span class="sgr-2m">0x20b113 in caller (3.1-with-error-return-traces)</span> | ||
| 2042 | \\ try callee(); | ||
| 2043 | \\ <span class="sgr-32_1m">^</span> | ||
| 2044 | \\<span class="sgr-1m">/home/zig/src/3.1-with-error-return-traces.zig:13:5</span>: <span class="sgr-2m">0x20b153 in main (3.1-with-error-return-traces)</span> | ||
| 2045 | \\ try caller(); | ||
| 2046 | \\ <span class="sgr-32_1m">^</span> | ||
| 2047 | \\ | ||
| 2048 | ; | ||
| 2049 | |||
| 2050 | const result = try termColor(test_allocator, input); | ||
| 2051 | defer test_allocator.free(result); | ||
| 2052 | try testing.expectEqualSlices(u8, expect, result); | ||
| 2053 | } | ||
| 2054 | |||
| 2055 | { | ||
| 2056 | // 3.2-with-stack-trace.out | ||
| 2057 | const input = "\x1b[1m/usr/local/lib/zig/lib/std/debug.zig:561:19\x1b[0m: \x1b[2m0x22a107 in writeCurrentStackTrace__anon_5898 (3.2-with-stack-trace)\x1b[0m\n while (it.next()) |return_address| {\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/debug.zig:157:80\x1b[0m: \x1b[2m0x20bb23 in dumpCurrentStackTrace (3.2-with-stack-trace)\x1b[0m\n writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(io.getStdErr()), start_addr) catch |err| {\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.2-with-stack-trace.zig:5:36\x1b[0m: \x1b[2m0x20d3b2 in foo (3.2-with-stack-trace)\x1b[0m\n std.debug.dumpCurrentStackTrace(null);\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.2-with-stack-trace.zig:9:8\x1b[0m: \x1b[2m0x20b458 in main (3.2-with-stack-trace)\x1b[0m\n foo();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/start.zig:607:22\x1b[0m: \x1b[2m0x20a965 in posixCallMainAndExit (3.2-with-stack-trace)\x1b[0m\n root.main();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/start.zig:376:5\x1b[0m: \x1b[2m0x20a411 in _start (3.2-with-stack-trace)\x1b[0m\n @call(.never_inline, posixCallMainAndExit, .{});\n \x1b[32;1m^\x1b[0m\n"; | ||
| 2058 | const expect = | ||
| 2059 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/debug.zig:561:19</span>: <span class="sgr-2m">0x22a107 in writeCurrentStackTrace__anon_5898 (3.2-with-stack-trace)</span> | ||
| 2060 | \\ while (it.next()) |return_address| { | ||
| 2061 | \\ <span class="sgr-32_1m">^</span> | ||
| 2062 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/debug.zig:157:80</span>: <span class="sgr-2m">0x20bb23 in dumpCurrentStackTrace (3.2-with-stack-trace)</span> | ||
| 2063 | \\ writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(io.getStdErr()), start_addr) catch |err| { | ||
| 2064 | \\ <span class="sgr-32_1m">^</span> | ||
| 2065 | \\<span class="sgr-1m">/home/zig/src/3.2-with-stack-trace.zig:5:36</span>: <span class="sgr-2m">0x20d3b2 in foo (3.2-with-stack-trace)</span> | ||
| 2066 | \\ std.debug.dumpCurrentStackTrace(null); | ||
| 2067 | \\ <span class="sgr-32_1m">^</span> | ||
| 2068 | \\<span class="sgr-1m">/home/zig/src/3.2-with-stack-trace.zig:9:8</span>: <span class="sgr-2m">0x20b458 in main (3.2-with-stack-trace)</span> | ||
| 2069 | \\ foo(); | ||
| 2070 | \\ <span class="sgr-32_1m">^</span> | ||
| 2071 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/start.zig:607:22</span>: <span class="sgr-2m">0x20a965 in posixCallMainAndExit (3.2-with-stack-trace)</span> | ||
| 2072 | \\ root.main(); | ||
| 2073 | \\ <span class="sgr-32_1m">^</span> | ||
| 2074 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/start.zig:376:5</span>: <span class="sgr-2m">0x20a411 in _start (3.2-with-stack-trace)</span> | ||
| 2075 | \\ @call(.never_inline, posixCallMainAndExit, .{}); | ||
| 2076 | \\ <span class="sgr-32_1m">^</span> | ||
| 2077 | \\ | ||
| 2078 | ; | ||
| 2079 | |||
| 2080 | const result = try termColor(test_allocator, input); | ||
| 2081 | defer test_allocator.free(result); | ||
| 2082 | try testing.expectEqualSlices(u8, expect, result); | ||
| 2083 | } | ||
| 2084 | } | ||
| 2085 | |||
| 2086 | test "printShell" { | ||
| 2087 | const test_allocator = std.testing.allocator; | ||
| 2088 | |||
| 2089 | { | ||
| 2090 | const shell_out = | ||
| 2091 | \\$ zig build test.zig | ||
| 2092 | ; | ||
| 2093 | const expected = | ||
| 2094 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> | ||
| 2095 | \\</samp></pre></figure> | ||
| 2096 | ; | ||
| 2097 | |||
| 2098 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2099 | defer buffer.deinit(); | ||
| 2100 | |||
| 2101 | try printShell(buffer.writer(), shell_out, false); | ||
| 2102 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2103 | } | ||
| 2104 | { | ||
| 2105 | const shell_out = | ||
| 2106 | \\$ zig build test.zig | ||
| 2107 | \\build output | ||
| 2108 | ; | ||
| 2109 | const expected = | ||
| 2110 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> | ||
| 2111 | \\build output | ||
| 2112 | \\</samp></pre></figure> | ||
| 2113 | ; | ||
| 2114 | |||
| 2115 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2116 | defer buffer.deinit(); | ||
| 2117 | |||
| 2118 | try printShell(buffer.writer(), shell_out, false); | ||
| 2119 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2120 | } | ||
| 2121 | { | ||
| 2122 | const shell_out = | ||
| 2123 | \\$ zig build test.zig | ||
| 2124 | \\build output | ||
| 2125 | \\$ ./test | ||
| 2126 | ; | ||
| 2127 | const expected = | ||
| 2128 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> | ||
| 2129 | \\build output | ||
| 2130 | \\$ <kbd>./test</kbd> | ||
| 2131 | \\</samp></pre></figure> | ||
| 2132 | ; | ||
| 2133 | |||
| 2134 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2135 | defer buffer.deinit(); | ||
| 2136 | |||
| 2137 | try printShell(buffer.writer(), shell_out, false); | ||
| 2138 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2139 | } | ||
| 2140 | { | ||
| 2141 | const shell_out = | ||
| 2142 | \\$ zig build test.zig | ||
| 2143 | \\ | ||
| 2144 | \\$ ./test | ||
| 2145 | \\output | ||
| 2146 | ; | ||
| 2147 | const expected = | ||
| 2148 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> | ||
| 2149 | \\ | ||
| 2150 | \\$ <kbd>./test</kbd> | ||
| 2151 | \\output | ||
| 2152 | \\</samp></pre></figure> | ||
| 2153 | ; | ||
| 2154 | |||
| 2155 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2156 | defer buffer.deinit(); | ||
| 2157 | |||
| 2158 | try printShell(buffer.writer(), shell_out, false); | ||
| 2159 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2160 | } | ||
| 2161 | { | ||
| 2162 | const shell_out = | ||
| 2163 | \\$ zig build test.zig | ||
| 2164 | \\$ ./test | ||
| 2165 | \\output | ||
| 2166 | ; | ||
| 2167 | const expected = | ||
| 2168 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> | ||
| 2169 | \\$ <kbd>./test</kbd> | ||
| 2170 | \\output | ||
| 2171 | \\</samp></pre></figure> | ||
| 2172 | ; | ||
| 2173 | |||
| 2174 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2175 | defer buffer.deinit(); | ||
| 2176 | |||
| 2177 | try printShell(buffer.writer(), shell_out, false); | ||
| 2178 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2179 | } | ||
| 2180 | { | ||
| 2181 | const shell_out = | ||
| 2182 | \\$ zig build test.zig \ | ||
| 2183 | \\ --build-option | ||
| 2184 | \\build output | ||
| 2185 | \\$ ./test | ||
| 2186 | \\output | ||
| 2187 | ; | ||
| 2188 | const expected = | ||
| 2189 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig \ | ||
| 2190 | \\ --build-option</kbd> | ||
| 2191 | \\build output | ||
| 2192 | \\$ <kbd>./test</kbd> | ||
| 2193 | \\output | ||
| 2194 | \\</samp></pre></figure> | ||
| 2195 | ; | ||
| 2196 | |||
| 2197 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2198 | defer buffer.deinit(); | ||
| 2199 | |||
| 2200 | try printShell(buffer.writer(), shell_out, false); | ||
| 2201 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2202 | } | ||
| 2203 | { | ||
| 2204 | // intentional space after "--build-option1 \" | ||
| 2205 | const shell_out = | ||
| 2206 | \\$ zig build test.zig \ | ||
| 2207 | \\ --build-option1 \ | ||
| 2208 | \\ --build-option2 | ||
| 2209 | \\$ ./test | ||
| 2210 | ; | ||
| 2211 | const expected = | ||
| 2212 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig \ | ||
| 2213 | \\ --build-option1 \ | ||
| 2214 | \\ --build-option2</kbd> | ||
| 2215 | \\$ <kbd>./test</kbd> | ||
| 2216 | \\</samp></pre></figure> | ||
| 2217 | ; | ||
| 2218 | |||
| 2219 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2220 | defer buffer.deinit(); | ||
| 2221 | |||
| 2222 | try printShell(buffer.writer(), shell_out, false); | ||
| 2223 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2224 | } | ||
| 2225 | { | ||
| 2226 | const shell_out = | ||
| 2227 | \\$ zig build test.zig \ | ||
| 2228 | \\$ ./test | ||
| 2229 | ; | ||
| 2230 | const expected = | ||
| 2231 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig \ | ||
| 2232 | \\$ ./test</kbd> | ||
| 2233 | \\</samp></pre></figure> | ||
| 2234 | ; | ||
| 2235 | |||
| 2236 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2237 | defer buffer.deinit(); | ||
| 2238 | |||
| 2239 | try printShell(buffer.writer(), shell_out, false); | ||
| 2240 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2241 | } | ||
| 2242 | { | ||
| 2243 | const shell_out = | ||
| 2244 | \\$ zig build test.zig | ||
| 2245 | \\$ ./test | ||
| 2246 | \\$1 | ||
| 2247 | ; | ||
| 2248 | const expected = | ||
| 2249 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> | ||
| 2250 | \\$ <kbd>./test</kbd> | ||
| 2251 | \\$1 | ||
| 2252 | \\</samp></pre></figure> | ||
| 2253 | ; | ||
| 2254 | |||
| 2255 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2256 | defer buffer.deinit(); | ||
| 2257 | |||
| 2258 | try printShell(buffer.writer(), shell_out, false); | ||
| 2259 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2260 | } | ||
| 2261 | { | ||
| 2262 | const shell_out = | ||
| 2263 | \\$zig build test.zig | ||
| 2264 | ; | ||
| 2265 | const expected = | ||
| 2266 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$zig build test.zig | ||
| 2267 | \\</samp></pre></figure> | ||
| 2268 | ; | ||
| 2269 | |||
| 2270 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2271 | defer buffer.deinit(); | ||
| 2272 | |||
| 2273 | try printShell(buffer.writer(), shell_out, false); | ||
| 2274 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2275 | } | ||
| 2276 | } | ||
lib/build_runner.zig+2-2| ... | @@ -188,10 +188,10 @@ pub fn main() !void { | ... | @@ -188,10 +188,10 @@ pub fn main() !void { |
| 188 | usageAndErr(builder, false, stderr_stream); | 188 | usageAndErr(builder, false, stderr_stream); |
| 189 | }; | 189 | }; |
| 190 | } else if (mem.eql(u8, arg, "--zig-lib-dir")) { | 190 | } else if (mem.eql(u8, arg, "--zig-lib-dir")) { |
| 191 | builder.zig_lib_dir = nextArg(args, &arg_idx) orelse { | 191 | builder.zig_lib_dir = .{ .cwd_relative = nextArg(args, &arg_idx) orelse { |
| 192 | std.debug.print("Expected argument after {s}\n\n", .{arg}); | 192 | std.debug.print("Expected argument after {s}\n\n", .{arg}); |
| 193 | usageAndErr(builder, false, stderr_stream); | 193 | usageAndErr(builder, false, stderr_stream); |
| 194 | }; | 194 | } }; |
| 195 | } else if (mem.eql(u8, arg, "--debug-log")) { | 195 | } else if (mem.eql(u8, arg, "--debug-log")) { |
| 196 | const next_arg = nextArg(args, &arg_idx) orelse { | 196 | const next_arg = nextArg(args, &arg_idx) orelse { |
| 197 | std.debug.print("Expected argument after {s}\n\n", .{arg}); | 197 | std.debug.print("Expected argument after {s}\n\n", .{arg}); |
lib/std/Build.zig+91-38| ... | @@ -57,6 +57,8 @@ pub const RunStep = @import("Build/Step/Run.zig"); | ... | @@ -57,6 +57,8 @@ pub const RunStep = @import("Build/Step/Run.zig"); |
| 57 | pub const TranslateCStep = @import("Build/Step/TranslateC.zig"); | 57 | pub const TranslateCStep = @import("Build/Step/TranslateC.zig"); |
| 58 | /// deprecated: use `Step.WriteFile`. | 58 | /// deprecated: use `Step.WriteFile`. |
| 59 | pub const WriteFileStep = @import("Build/Step/WriteFile.zig"); | 59 | pub const WriteFileStep = @import("Build/Step/WriteFile.zig"); |
| 60 | /// deprecated: use `LazyPath`. | ||
| 61 | pub const FileSource = LazyPath; | ||
| 60 | 62 | ||
| 61 | install_tls: TopLevelStep, | 63 | install_tls: TopLevelStep, |
| 62 | uninstall_tls: TopLevelStep, | 64 | uninstall_tls: TopLevelStep, |
| ... | @@ -93,8 +95,7 @@ build_root: Cache.Directory, | ... | @@ -93,8 +95,7 @@ build_root: Cache.Directory, |
| 93 | cache_root: Cache.Directory, | 95 | cache_root: Cache.Directory, |
| 94 | global_cache_root: Cache.Directory, | 96 | global_cache_root: Cache.Directory, |
| 95 | cache: *Cache, | 97 | cache: *Cache, |
| 96 | /// If non-null, overrides the default zig lib dir. | 98 | zig_lib_dir: ?LazyPath, |
| 97 | zig_lib_dir: ?[]const u8, | ||
| 98 | vcpkg_root: VcpkgRoot = .unattempted, | 99 | vcpkg_root: VcpkgRoot = .unattempted, |
| 99 | pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null, | 100 | pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null, |
| 100 | args: ?[][]const u8 = null, | 101 | args: ?[][]const u8 = null, |
| ... | @@ -471,7 +472,7 @@ pub fn addOptions(self: *Build) *Step.Options { | ... | @@ -471,7 +472,7 @@ pub fn addOptions(self: *Build) *Step.Options { |
| 471 | 472 | ||
| 472 | pub const ExecutableOptions = struct { | 473 | pub const ExecutableOptions = struct { |
| 473 | name: []const u8, | 474 | name: []const u8, |
| 474 | root_source_file: ?FileSource = null, | 475 | root_source_file: ?LazyPath = null, |
| 475 | version: ?std.SemanticVersion = null, | 476 | version: ?std.SemanticVersion = null, |
| 476 | target: CrossTarget = .{}, | 477 | target: CrossTarget = .{}, |
| 477 | optimize: std.builtin.Mode = .Debug, | 478 | optimize: std.builtin.Mode = .Debug, |
| ... | @@ -481,6 +482,8 @@ pub const ExecutableOptions = struct { | ... | @@ -481,6 +482,8 @@ pub const ExecutableOptions = struct { |
| 481 | single_threaded: ?bool = null, | 482 | single_threaded: ?bool = null, |
| 482 | use_llvm: ?bool = null, | 483 | use_llvm: ?bool = null, |
| 483 | use_lld: ?bool = null, | 484 | use_lld: ?bool = null, |
| 485 | zig_lib_dir: ?LazyPath = null, | ||
| 486 | main_pkg_path: ?LazyPath = null, | ||
| 484 | }; | 487 | }; |
| 485 | 488 | ||
| 486 | pub fn addExecutable(b: *Build, options: ExecutableOptions) *Step.Compile { | 489 | pub fn addExecutable(b: *Build, options: ExecutableOptions) *Step.Compile { |
| ... | @@ -497,12 +500,14 @@ pub fn addExecutable(b: *Build, options: ExecutableOptions) *Step.Compile { | ... | @@ -497,12 +500,14 @@ pub fn addExecutable(b: *Build, options: ExecutableOptions) *Step.Compile { |
| 497 | .single_threaded = options.single_threaded, | 500 | .single_threaded = options.single_threaded, |
| 498 | .use_llvm = options.use_llvm, | 501 | .use_llvm = options.use_llvm, |
| 499 | .use_lld = options.use_lld, | 502 | .use_lld = options.use_lld, |
| 503 | .zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir, | ||
| 504 | .main_pkg_path = options.main_pkg_path, | ||
| 500 | }); | 505 | }); |
| 501 | } | 506 | } |
| 502 | 507 | ||
| 503 | pub const ObjectOptions = struct { | 508 | pub const ObjectOptions = struct { |
| 504 | name: []const u8, | 509 | name: []const u8, |
| 505 | root_source_file: ?FileSource = null, | 510 | root_source_file: ?LazyPath = null, |
| 506 | target: CrossTarget, | 511 | target: CrossTarget, |
| 507 | optimize: std.builtin.Mode, | 512 | optimize: std.builtin.Mode, |
| 508 | max_rss: usize = 0, | 513 | max_rss: usize = 0, |
| ... | @@ -510,6 +515,8 @@ pub const ObjectOptions = struct { | ... | @@ -510,6 +515,8 @@ pub const ObjectOptions = struct { |
| 510 | single_threaded: ?bool = null, | 515 | single_threaded: ?bool = null, |
| 511 | use_llvm: ?bool = null, | 516 | use_llvm: ?bool = null, |
| 512 | use_lld: ?bool = null, | 517 | use_lld: ?bool = null, |
| 518 | zig_lib_dir: ?LazyPath = null, | ||
| 519 | main_pkg_path: ?LazyPath = null, | ||
| 513 | }; | 520 | }; |
| 514 | 521 | ||
| 515 | pub fn addObject(b: *Build, options: ObjectOptions) *Step.Compile { | 522 | pub fn addObject(b: *Build, options: ObjectOptions) *Step.Compile { |
| ... | @@ -524,12 +531,14 @@ pub fn addObject(b: *Build, options: ObjectOptions) *Step.Compile { | ... | @@ -524,12 +531,14 @@ pub fn addObject(b: *Build, options: ObjectOptions) *Step.Compile { |
| 524 | .single_threaded = options.single_threaded, | 531 | .single_threaded = options.single_threaded, |
| 525 | .use_llvm = options.use_llvm, | 532 | .use_llvm = options.use_llvm, |
| 526 | .use_lld = options.use_lld, | 533 | .use_lld = options.use_lld, |
| 534 | .zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir, | ||
| 535 | .main_pkg_path = options.main_pkg_path, | ||
| 527 | }); | 536 | }); |
| 528 | } | 537 | } |
| 529 | 538 | ||
| 530 | pub const SharedLibraryOptions = struct { | 539 | pub const SharedLibraryOptions = struct { |
| 531 | name: []const u8, | 540 | name: []const u8, |
| 532 | root_source_file: ?FileSource = null, | 541 | root_source_file: ?LazyPath = null, |
| 533 | version: ?std.SemanticVersion = null, | 542 | version: ?std.SemanticVersion = null, |
| 534 | target: CrossTarget, | 543 | target: CrossTarget, |
| 535 | optimize: std.builtin.Mode, | 544 | optimize: std.builtin.Mode, |
| ... | @@ -538,6 +547,8 @@ pub const SharedLibraryOptions = struct { | ... | @@ -538,6 +547,8 @@ pub const SharedLibraryOptions = struct { |
| 538 | single_threaded: ?bool = null, | 547 | single_threaded: ?bool = null, |
| 539 | use_llvm: ?bool = null, | 548 | use_llvm: ?bool = null, |
| 540 | use_lld: ?bool = null, | 549 | use_lld: ?bool = null, |
| 550 | zig_lib_dir: ?LazyPath = null, | ||
| 551 | main_pkg_path: ?LazyPath = null, | ||
| 541 | }; | 552 | }; |
| 542 | 553 | ||
| 543 | pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *Step.Compile { | 554 | pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *Step.Compile { |
| ... | @@ -554,12 +565,14 @@ pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *Step.Compile | ... | @@ -554,12 +565,14 @@ pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *Step.Compile |
| 554 | .single_threaded = options.single_threaded, | 565 | .single_threaded = options.single_threaded, |
| 555 | .use_llvm = options.use_llvm, | 566 | .use_llvm = options.use_llvm, |
| 556 | .use_lld = options.use_lld, | 567 | .use_lld = options.use_lld, |
| 568 | .zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir, | ||
| 569 | .main_pkg_path = options.main_pkg_path, | ||
| 557 | }); | 570 | }); |
| 558 | } | 571 | } |
| 559 | 572 | ||
| 560 | pub const StaticLibraryOptions = struct { | 573 | pub const StaticLibraryOptions = struct { |
| 561 | name: []const u8, | 574 | name: []const u8, |
| 562 | root_source_file: ?FileSource = null, | 575 | root_source_file: ?LazyPath = null, |
| 563 | target: CrossTarget, | 576 | target: CrossTarget, |
| 564 | optimize: std.builtin.Mode, | 577 | optimize: std.builtin.Mode, |
| 565 | version: ?std.SemanticVersion = null, | 578 | version: ?std.SemanticVersion = null, |
| ... | @@ -568,6 +581,8 @@ pub const StaticLibraryOptions = struct { | ... | @@ -568,6 +581,8 @@ pub const StaticLibraryOptions = struct { |
| 568 | single_threaded: ?bool = null, | 581 | single_threaded: ?bool = null, |
| 569 | use_llvm: ?bool = null, | 582 | use_llvm: ?bool = null, |
| 570 | use_lld: ?bool = null, | 583 | use_lld: ?bool = null, |
| 584 | zig_lib_dir: ?LazyPath = null, | ||
| 585 | main_pkg_path: ?LazyPath = null, | ||
| 571 | }; | 586 | }; |
| 572 | 587 | ||
| 573 | pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *Step.Compile { | 588 | pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *Step.Compile { |
| ... | @@ -584,12 +599,14 @@ pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *Step.Compile | ... | @@ -584,12 +599,14 @@ pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *Step.Compile |
| 584 | .single_threaded = options.single_threaded, | 599 | .single_threaded = options.single_threaded, |
| 585 | .use_llvm = options.use_llvm, | 600 | .use_llvm = options.use_llvm, |
| 586 | .use_lld = options.use_lld, | 601 | .use_lld = options.use_lld, |
| 602 | .zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir, | ||
| 603 | .main_pkg_path = options.main_pkg_path, | ||
| 587 | }); | 604 | }); |
| 588 | } | 605 | } |
| 589 | 606 | ||
| 590 | pub const TestOptions = struct { | 607 | pub const TestOptions = struct { |
| 591 | name: []const u8 = "test", | 608 | name: []const u8 = "test", |
| 592 | root_source_file: FileSource, | 609 | root_source_file: LazyPath, |
| 593 | target: CrossTarget = .{}, | 610 | target: CrossTarget = .{}, |
| 594 | optimize: std.builtin.Mode = .Debug, | 611 | optimize: std.builtin.Mode = .Debug, |
| 595 | version: ?std.SemanticVersion = null, | 612 | version: ?std.SemanticVersion = null, |
| ... | @@ -600,6 +617,8 @@ pub const TestOptions = struct { | ... | @@ -600,6 +617,8 @@ pub const TestOptions = struct { |
| 600 | single_threaded: ?bool = null, | 617 | single_threaded: ?bool = null, |
| 601 | use_llvm: ?bool = null, | 618 | use_llvm: ?bool = null, |
| 602 | use_lld: ?bool = null, | 619 | use_lld: ?bool = null, |
| 620 | zig_lib_dir: ?LazyPath = null, | ||
| 621 | main_pkg_path: ?LazyPath = null, | ||
| 603 | }; | 622 | }; |
| 604 | 623 | ||
| 605 | pub fn addTest(b: *Build, options: TestOptions) *Step.Compile { | 624 | pub fn addTest(b: *Build, options: TestOptions) *Step.Compile { |
| ... | @@ -616,15 +635,18 @@ pub fn addTest(b: *Build, options: TestOptions) *Step.Compile { | ... | @@ -616,15 +635,18 @@ pub fn addTest(b: *Build, options: TestOptions) *Step.Compile { |
| 616 | .single_threaded = options.single_threaded, | 635 | .single_threaded = options.single_threaded, |
| 617 | .use_llvm = options.use_llvm, | 636 | .use_llvm = options.use_llvm, |
| 618 | .use_lld = options.use_lld, | 637 | .use_lld = options.use_lld, |
| 638 | .zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir, | ||
| 639 | .main_pkg_path = options.main_pkg_path, | ||
| 619 | }); | 640 | }); |
| 620 | } | 641 | } |
| 621 | 642 | ||
| 622 | pub const AssemblyOptions = struct { | 643 | pub const AssemblyOptions = struct { |
| 623 | name: []const u8, | 644 | name: []const u8, |
| 624 | source_file: FileSource, | 645 | source_file: LazyPath, |
| 625 | target: CrossTarget, | 646 | target: CrossTarget, |
| 626 | optimize: std.builtin.Mode, | 647 | optimize: std.builtin.Mode, |
| 627 | max_rss: usize = 0, | 648 | max_rss: usize = 0, |
| 649 | zig_lib_dir: ?LazyPath = null, | ||
| 628 | }; | 650 | }; |
| 629 | 651 | ||
| 630 | pub fn addAssembly(b: *Build, options: AssemblyOptions) *Step.Compile { | 652 | pub fn addAssembly(b: *Build, options: AssemblyOptions) *Step.Compile { |
| ... | @@ -635,8 +657,9 @@ pub fn addAssembly(b: *Build, options: AssemblyOptions) *Step.Compile { | ... | @@ -635,8 +657,9 @@ pub fn addAssembly(b: *Build, options: AssemblyOptions) *Step.Compile { |
| 635 | .target = options.target, | 657 | .target = options.target, |
| 636 | .optimize = options.optimize, | 658 | .optimize = options.optimize, |
| 637 | .max_rss = options.max_rss, | 659 | .max_rss = options.max_rss, |
| 660 | .zig_lib_dir = options.zig_lib_dir orelse b.zig_lib_dir, | ||
| 638 | }); | 661 | }); |
| 639 | obj_step.addAssemblyFileSource(options.source_file.dupe(b)); | 662 | obj_step.addAssemblyLazyPath(options.source_file.dupe(b)); |
| 640 | return obj_step; | 663 | return obj_step; |
| 641 | } | 664 | } |
| 642 | 665 | ||
| ... | @@ -655,7 +678,7 @@ pub const ModuleDependency = struct { | ... | @@ -655,7 +678,7 @@ pub const ModuleDependency = struct { |
| 655 | }; | 678 | }; |
| 656 | 679 | ||
| 657 | pub const CreateModuleOptions = struct { | 680 | pub const CreateModuleOptions = struct { |
| 658 | source_file: FileSource, | 681 | source_file: LazyPath, |
| 659 | dependencies: []const ModuleDependency = &.{}, | 682 | dependencies: []const ModuleDependency = &.{}, |
| 660 | }; | 683 | }; |
| 661 | 684 | ||
| ... | @@ -1257,12 +1280,21 @@ fn printCmd(ally: Allocator, cwd: ?[]const u8, argv: []const []const u8) void { | ... | @@ -1257,12 +1280,21 @@ fn printCmd(ally: Allocator, cwd: ?[]const u8, argv: []const []const u8) void { |
| 1257 | std.debug.print("{s}\n", .{text}); | 1280 | std.debug.print("{s}\n", .{text}); |
| 1258 | } | 1281 | } |
| 1259 | 1282 | ||
| 1283 | /// This creates the install step and adds it to the dependencies of the | ||
| 1284 | /// top-level install step, using all the default options. | ||
| 1285 | /// See `addInstallArtifact` for a more flexible function. | ||
| 1260 | pub fn installArtifact(self: *Build, artifact: *Step.Compile) void { | 1286 | pub fn installArtifact(self: *Build, artifact: *Step.Compile) void { |
| 1261 | self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step); | 1287 | self.getInstallStep().dependOn(&self.addInstallArtifact(artifact, .{}).step); |
| 1262 | } | 1288 | } |
| 1263 | 1289 | ||
| 1264 | pub fn addInstallArtifact(self: *Build, artifact: *Step.Compile) *Step.InstallArtifact { | 1290 | /// This merely creates the step; it does not add it to the dependencies of the |
| 1265 | return Step.InstallArtifact.create(self, artifact); | 1291 | /// top-level install step. |
| 1292 | pub fn addInstallArtifact( | ||
| 1293 | self: *Build, | ||
| 1294 | artifact: *Step.Compile, | ||
| 1295 | options: Step.InstallArtifact.Options, | ||
| 1296 | ) *Step.InstallArtifact { | ||
| 1297 | return Step.InstallArtifact.create(self, artifact, options); | ||
| 1266 | } | 1298 | } |
| 1267 | 1299 | ||
| 1268 | ///`dest_rel_path` is relative to prefix path | 1300 | ///`dest_rel_path` is relative to prefix path |
| ... | @@ -1284,22 +1316,22 @@ pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const | ... | @@ -1284,22 +1316,22 @@ pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const |
| 1284 | self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step); | 1316 | self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step); |
| 1285 | } | 1317 | } |
| 1286 | 1318 | ||
| 1287 | pub fn addObjCopy(b: *Build, source: FileSource, options: Step.ObjCopy.Options) *Step.ObjCopy { | 1319 | pub fn addObjCopy(b: *Build, source: LazyPath, options: Step.ObjCopy.Options) *Step.ObjCopy { |
| 1288 | return Step.ObjCopy.create(b, source, options); | 1320 | return Step.ObjCopy.create(b, source, options); |
| 1289 | } | 1321 | } |
| 1290 | 1322 | ||
| 1291 | ///`dest_rel_path` is relative to install prefix path | 1323 | ///`dest_rel_path` is relative to install prefix path |
| 1292 | pub fn addInstallFile(self: *Build, source: FileSource, dest_rel_path: []const u8) *Step.InstallFile { | 1324 | pub fn addInstallFile(self: *Build, source: LazyPath, dest_rel_path: []const u8) *Step.InstallFile { |
| 1293 | return self.addInstallFileWithDir(source.dupe(self), .prefix, dest_rel_path); | 1325 | return self.addInstallFileWithDir(source.dupe(self), .prefix, dest_rel_path); |
| 1294 | } | 1326 | } |
| 1295 | 1327 | ||
| 1296 | ///`dest_rel_path` is relative to bin path | 1328 | ///`dest_rel_path` is relative to bin path |
| 1297 | pub fn addInstallBinFile(self: *Build, source: FileSource, dest_rel_path: []const u8) *Step.InstallFile { | 1329 | pub fn addInstallBinFile(self: *Build, source: LazyPath, dest_rel_path: []const u8) *Step.InstallFile { |
| 1298 | return self.addInstallFileWithDir(source.dupe(self), .bin, dest_rel_path); | 1330 | return self.addInstallFileWithDir(source.dupe(self), .bin, dest_rel_path); |
| 1299 | } | 1331 | } |
| 1300 | 1332 | ||
| 1301 | ///`dest_rel_path` is relative to lib path | 1333 | ///`dest_rel_path` is relative to lib path |
| 1302 | pub fn addInstallLibFile(self: *Build, source: FileSource, dest_rel_path: []const u8) *Step.InstallFile { | 1334 | pub fn addInstallLibFile(self: *Build, source: LazyPath, dest_rel_path: []const u8) *Step.InstallFile { |
| 1303 | return self.addInstallFileWithDir(source.dupe(self), .lib, dest_rel_path); | 1335 | return self.addInstallFileWithDir(source.dupe(self), .lib, dest_rel_path); |
| 1304 | } | 1336 | } |
| 1305 | 1337 | ||
| ... | @@ -1309,7 +1341,7 @@ pub fn addInstallHeaderFile(b: *Build, src_path: []const u8, dest_rel_path: []co | ... | @@ -1309,7 +1341,7 @@ pub fn addInstallHeaderFile(b: *Build, src_path: []const u8, dest_rel_path: []co |
| 1309 | 1341 | ||
| 1310 | pub fn addInstallFileWithDir( | 1342 | pub fn addInstallFileWithDir( |
| 1311 | self: *Build, | 1343 | self: *Build, |
| 1312 | source: FileSource, | 1344 | source: LazyPath, |
| 1313 | install_dir: InstallDir, | 1345 | install_dir: InstallDir, |
| 1314 | dest_rel_path: []const u8, | 1346 | dest_rel_path: []const u8, |
| 1315 | ) *Step.InstallFile { | 1347 | ) *Step.InstallFile { |
| ... | @@ -1322,12 +1354,13 @@ pub fn addInstallDirectory(self: *Build, options: InstallDirectoryOptions) *Step | ... | @@ -1322,12 +1354,13 @@ pub fn addInstallDirectory(self: *Build, options: InstallDirectoryOptions) *Step |
| 1322 | 1354 | ||
| 1323 | pub fn addCheckFile( | 1355 | pub fn addCheckFile( |
| 1324 | b: *Build, | 1356 | b: *Build, |
| 1325 | file_source: FileSource, | 1357 | file_source: LazyPath, |
| 1326 | options: Step.CheckFile.Options, | 1358 | options: Step.CheckFile.Options, |
| 1327 | ) *Step.CheckFile { | 1359 | ) *Step.CheckFile { |
| 1328 | return Step.CheckFile.create(b, file_source, options); | 1360 | return Step.CheckFile.create(b, file_source, options); |
| 1329 | } | 1361 | } |
| 1330 | 1362 | ||
| 1363 | /// deprecated: https://github.com/ziglang/zig/issues/14943 | ||
| 1331 | pub fn pushInstalledFile(self: *Build, dir: InstallDir, dest_rel_path: []const u8) void { | 1364 | pub fn pushInstalledFile(self: *Build, dir: InstallDir, dest_rel_path: []const u8) void { |
| 1332 | const file = InstalledFile{ | 1365 | const file = InstalledFile{ |
| 1333 | .dir = dir, | 1366 | .dir = dir, |
| ... | @@ -1357,6 +1390,11 @@ pub fn pathFromRoot(b: *Build, p: []const u8) []u8 { | ... | @@ -1357,6 +1390,11 @@ pub fn pathFromRoot(b: *Build, p: []const u8) []u8 { |
| 1357 | return fs.path.resolve(b.allocator, &.{ b.build_root.path orelse ".", p }) catch @panic("OOM"); | 1390 | return fs.path.resolve(b.allocator, &.{ b.build_root.path orelse ".", p }) catch @panic("OOM"); |
| 1358 | } | 1391 | } |
| 1359 | 1392 | ||
| 1393 | fn pathFromCwd(b: *Build, p: []const u8) []u8 { | ||
| 1394 | const cwd = process.getCwdAlloc(b.allocator) catch @panic("OOM"); | ||
| 1395 | return fs.path.resolve(b.allocator, &.{ cwd, p }) catch @panic("OOM"); | ||
| 1396 | } | ||
| 1397 | |||
| 1360 | pub fn pathJoin(self: *Build, paths: []const []const u8) []u8 { | 1398 | pub fn pathJoin(self: *Build, paths: []const []const u8) []u8 { |
| 1361 | return fs.path.join(self.allocator, paths) catch @panic("OOM"); | 1399 | return fs.path.join(self.allocator, paths) catch @panic("OOM"); |
| 1362 | } | 1400 | } |
| ... | @@ -1608,7 +1646,7 @@ pub const Module = struct { | ... | @@ -1608,7 +1646,7 @@ pub const Module = struct { |
| 1608 | /// This could either be a generated file, in which case the module | 1646 | /// This could either be a generated file, in which case the module |
| 1609 | /// contains exactly one file, or it could be a path to the root source | 1647 | /// contains exactly one file, or it could be a path to the root source |
| 1610 | /// file of directory of files which constitute the module. | 1648 | /// file of directory of files which constitute the module. |
| 1611 | source_file: FileSource, | 1649 | source_file: LazyPath, |
| 1612 | dependencies: std.StringArrayHashMap(*Module), | 1650 | dependencies: std.StringArrayHashMap(*Module), |
| 1613 | }; | 1651 | }; |
| 1614 | 1652 | ||
| ... | @@ -1630,50 +1668,64 @@ pub const GeneratedFile = struct { | ... | @@ -1630,50 +1668,64 @@ pub const GeneratedFile = struct { |
| 1630 | } | 1668 | } |
| 1631 | }; | 1669 | }; |
| 1632 | 1670 | ||
| 1633 | /// A file source is a reference to an existing or future file. | 1671 | /// A reference to an existing or future path. |
| 1634 | pub const FileSource = union(enum) { | 1672 | pub const LazyPath = union(enum) { |
| 1635 | /// A plain file path, relative to build root or absolute. | 1673 | /// A source file path relative to build root. |
| 1674 | /// This should not be an absolute path, but in an older iteration of the zig build | ||
| 1675 | /// system API, it was allowed to be absolute. Absolute paths should use `cwd_relative`. | ||
| 1636 | path: []const u8, | 1676 | path: []const u8, |
| 1637 | 1677 | ||
| 1638 | /// A file that is generated by an interface. Those files usually are | 1678 | /// A file that is generated by an interface. Those files usually are |
| 1639 | /// not available until built by a build step. | 1679 | /// not available until built by a build step. |
| 1640 | generated: *const GeneratedFile, | 1680 | generated: *const GeneratedFile, |
| 1641 | 1681 | ||
| 1682 | /// An absolute path or a path relative to the current working directory of | ||
| 1683 | /// the build runner process. | ||
| 1684 | /// This is uncommon but used for system environment paths such as `--zig-lib-dir` which | ||
| 1685 | /// ignore the file system path of build.zig and instead are relative to the directory from | ||
| 1686 | /// which `zig build` was invoked. | ||
| 1687 | /// Use of this tag indicates a dependency on the host system. | ||
| 1688 | cwd_relative: []const u8, | ||
| 1689 | |||
| 1642 | /// Returns a new file source that will have a relative path to the build root guaranteed. | 1690 | /// Returns a new file source that will have a relative path to the build root guaranteed. |
| 1643 | /// This should be preferred over setting `.path` directly as it documents that the files are in the project directory. | 1691 | /// Asserts the parameter is not an absolute path. |
| 1644 | pub fn relative(path: []const u8) FileSource { | 1692 | pub fn relative(path: []const u8) LazyPath { |
| 1645 | std.debug.assert(!std.fs.path.isAbsolute(path)); | 1693 | std.debug.assert(!std.fs.path.isAbsolute(path)); |
| 1646 | return FileSource{ .path = path }; | 1694 | return LazyPath{ .path = path }; |
| 1647 | } | 1695 | } |
| 1648 | 1696 | ||
| 1649 | /// Returns a string that can be shown to represent the file source. | 1697 | /// Returns a string that can be shown to represent the file source. |
| 1650 | /// Either returns the path or `"generated"`. | 1698 | /// Either returns the path or `"generated"`. |
| 1651 | pub fn getDisplayName(self: FileSource) []const u8 { | 1699 | pub fn getDisplayName(self: LazyPath) []const u8 { |
| 1652 | return switch (self) { | 1700 | return switch (self) { |
| 1653 | .path => self.path, | 1701 | .path, .cwd_relative => self.path, |
| 1654 | .generated => "generated", | 1702 | .generated => "generated", |
| 1655 | }; | 1703 | }; |
| 1656 | } | 1704 | } |
| 1657 | 1705 | ||
| 1658 | /// Adds dependencies this file source implies to the given step. | 1706 | /// Adds dependencies this file source implies to the given step. |
| 1659 | pub fn addStepDependencies(self: FileSource, other_step: *Step) void { | 1707 | pub fn addStepDependencies(self: LazyPath, other_step: *Step) void { |
| 1660 | switch (self) { | 1708 | switch (self) { |
| 1661 | .path => {}, | 1709 | .path, .cwd_relative => {}, |
| 1662 | .generated => |gen| other_step.dependOn(gen.step), | 1710 | .generated => |gen| other_step.dependOn(gen.step), |
| 1663 | } | 1711 | } |
| 1664 | } | 1712 | } |
| 1665 | 1713 | ||
| 1666 | /// Should only be called during make(), returns a path relative to the build root or absolute. | 1714 | /// Returns an absolute path. |
| 1667 | pub fn getPath(self: FileSource, src_builder: *Build) []const u8 { | 1715 | /// Intended to be used during the make phase only. |
| 1716 | pub fn getPath(self: LazyPath, src_builder: *Build) []const u8 { | ||
| 1668 | return getPath2(self, src_builder, null); | 1717 | return getPath2(self, src_builder, null); |
| 1669 | } | 1718 | } |
| 1670 | 1719 | ||
| 1671 | /// Should only be called during make(), returns a path relative to the build root or absolute. | 1720 | /// Returns an absolute path. |
| 1672 | /// asking_step is only used for debugging purposes; it's the step being run that is asking for | 1721 | /// Intended to be used during the make phase only. |
| 1673 | /// the path. | 1722 | /// |
| 1674 | pub fn getPath2(self: FileSource, src_builder: *Build, asking_step: ?*Step) []const u8 { | 1723 | /// `asking_step` is only used for debugging purposes; it's the step being |
| 1724 | /// run that is asking for the path. | ||
| 1725 | pub fn getPath2(self: LazyPath, src_builder: *Build, asking_step: ?*Step) []const u8 { | ||
| 1675 | switch (self) { | 1726 | switch (self) { |
| 1676 | .path => |p| return src_builder.pathFromRoot(p), | 1727 | .path => |p| return src_builder.pathFromRoot(p), |
| 1728 | .cwd_relative => |p| return src_builder.pathFromCwd(p), | ||
| 1677 | .generated => |gen| return gen.path orelse { | 1729 | .generated => |gen| return gen.path orelse { |
| 1678 | std.debug.getStderrMutex().lock(); | 1730 | std.debug.getStderrMutex().lock(); |
| 1679 | const stderr = std.io.getStdErr(); | 1731 | const stderr = std.io.getStdErr(); |
| ... | @@ -1684,16 +1736,17 @@ pub const FileSource = union(enum) { | ... | @@ -1684,16 +1736,17 @@ pub const FileSource = union(enum) { |
| 1684 | } | 1736 | } |
| 1685 | 1737 | ||
| 1686 | /// Duplicates the file source for a given builder. | 1738 | /// Duplicates the file source for a given builder. |
| 1687 | pub fn dupe(self: FileSource, b: *Build) FileSource { | 1739 | pub fn dupe(self: LazyPath, b: *Build) LazyPath { |
| 1688 | return switch (self) { | 1740 | return switch (self) { |
| 1689 | .path => |p| .{ .path = b.dupePath(p) }, | 1741 | .path => |p| .{ .path = b.dupePath(p) }, |
| 1742 | .cwd_relative => |p| .{ .cwd_relative = b.dupePath(p) }, | ||
| 1690 | .generated => |gen| .{ .generated = gen }, | 1743 | .generated => |gen| .{ .generated = gen }, |
| 1691 | }; | 1744 | }; |
| 1692 | } | 1745 | } |
| 1693 | }; | 1746 | }; |
| 1694 | 1747 | ||
| 1695 | /// In this function the stderr mutex has already been locked. | 1748 | /// In this function the stderr mutex has already been locked. |
| 1696 | fn dumpBadGetPathHelp( | 1749 | pub fn dumpBadGetPathHelp( |
| 1697 | s: *Step, | 1750 | s: *Step, |
| 1698 | stderr: fs.File, | 1751 | stderr: fs.File, |
| 1699 | src_builder: *Build, | 1752 | src_builder: *Build, |
lib/std/Build/Step.zig+1-6| ... | @@ -423,12 +423,7 @@ pub fn evalZigProcess( | ... | @@ -423,12 +423,7 @@ pub fn evalZigProcess( |
| 423 | }); | 423 | }); |
| 424 | } | 424 | } |
| 425 | 425 | ||
| 426 | if (s.cast(Compile)) |compile| if (compile.emit_bin == .no_emit) return result; | 426 | return result; |
| 427 | |||
| 428 | return result orelse return s.fail( | ||
| 429 | "the following command failed to communicate the compilation result:\n{s}", | ||
| 430 | .{try allocPrintCmd(arena, null, argv)}, | ||
| 431 | ); | ||
| 432 | } | 427 | } |
| 433 | 428 | ||
| 434 | fn sendMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag) !void { | 429 | fn sendMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag) !void { |
lib/std/Build/Step/CheckFile.zig+2-2| ... | @@ -11,7 +11,7 @@ const mem = std.mem; | ... | @@ -11,7 +11,7 @@ const mem = std.mem; |
| 11 | step: Step, | 11 | step: Step, |
| 12 | expected_matches: []const []const u8, | 12 | expected_matches: []const []const u8, |
| 13 | expected_exact: ?[]const u8, | 13 | expected_exact: ?[]const u8, |
| 14 | source: std.Build.FileSource, | 14 | source: std.Build.LazyPath, |
| 15 | max_bytes: usize = 20 * 1024 * 1024, | 15 | max_bytes: usize = 20 * 1024 * 1024, |
| 16 | 16 | ||
| 17 | pub const base_id = .check_file; | 17 | pub const base_id = .check_file; |
| ... | @@ -23,7 +23,7 @@ pub const Options = struct { | ... | @@ -23,7 +23,7 @@ pub const Options = struct { |
| 23 | 23 | ||
| 24 | pub fn create( | 24 | pub fn create( |
| 25 | owner: *std.Build, | 25 | owner: *std.Build, |
| 26 | source: std.Build.FileSource, | 26 | source: std.Build.LazyPath, |
| 27 | options: Options, | 27 | options: Options, |
| 28 | ) *CheckFile { | 28 | ) *CheckFile { |
| 29 | const self = owner.allocator.create(CheckFile) catch @panic("OOM"); | 29 | const self = owner.allocator.create(CheckFile) catch @panic("OOM"); |
lib/std/Build/Step/CheckObject.zig+7-7| ... | @@ -15,14 +15,14 @@ const Step = std.Build.Step; | ... | @@ -15,14 +15,14 @@ const Step = std.Build.Step; |
| 15 | pub const base_id = .check_object; | 15 | pub const base_id = .check_object; |
| 16 | 16 | ||
| 17 | step: Step, | 17 | step: Step, |
| 18 | source: std.Build.FileSource, | 18 | source: std.Build.LazyPath, |
| 19 | max_bytes: usize = 20 * 1024 * 1024, | 19 | max_bytes: usize = 20 * 1024 * 1024, |
| 20 | checks: std.ArrayList(Check), | 20 | checks: std.ArrayList(Check), |
| 21 | obj_format: std.Target.ObjectFormat, | 21 | obj_format: std.Target.ObjectFormat, |
| 22 | 22 | ||
| 23 | pub fn create( | 23 | pub fn create( |
| 24 | owner: *std.Build, | 24 | owner: *std.Build, |
| 25 | source: std.Build.FileSource, | 25 | source: std.Build.LazyPath, |
| 26 | obj_format: std.Target.ObjectFormat, | 26 | obj_format: std.Target.ObjectFormat, |
| 27 | ) *CheckObject { | 27 | ) *CheckObject { |
| 28 | const gpa = owner.allocator; | 28 | const gpa = owner.allocator; |
| ... | @@ -44,7 +44,7 @@ pub fn create( | ... | @@ -44,7 +44,7 @@ pub fn create( |
| 44 | 44 | ||
| 45 | const SearchPhrase = struct { | 45 | const SearchPhrase = struct { |
| 46 | string: []const u8, | 46 | string: []const u8, |
| 47 | file_source: ?std.Build.FileSource = null, | 47 | file_source: ?std.Build.LazyPath = null, |
| 48 | 48 | ||
| 49 | fn resolve(phrase: SearchPhrase, b: *std.Build, step: *Step) []const u8 { | 49 | fn resolve(phrase: SearchPhrase, b: *std.Build, step: *Step) []const u8 { |
| 50 | const file_source = phrase.file_source orelse return phrase.string; | 50 | const file_source = phrase.file_source orelse return phrase.string; |
| ... | @@ -302,13 +302,13 @@ pub fn checkExact(self: *CheckObject, phrase: []const u8) void { | ... | @@ -302,13 +302,13 @@ pub fn checkExact(self: *CheckObject, phrase: []const u8) void { |
| 302 | self.checkExactInner(phrase, null); | 302 | self.checkExactInner(phrase, null); |
| 303 | } | 303 | } |
| 304 | 304 | ||
| 305 | /// Like `checkExact()` but takes an additional argument `FileSource` which will be | 305 | /// Like `checkExact()` but takes an additional argument `LazyPath` which will be |
| 306 | /// resolved to a full search query in `make()`. | 306 | /// resolved to a full search query in `make()`. |
| 307 | pub fn checkExactFileSource(self: *CheckObject, phrase: []const u8, file_source: std.Build.FileSource) void { | 307 | pub fn checkExactPath(self: *CheckObject, phrase: []const u8, file_source: std.Build.LazyPath) void { |
| 308 | self.checkExactInner(phrase, file_source); | 308 | self.checkExactInner(phrase, file_source); |
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | fn checkExactInner(self: *CheckObject, phrase: []const u8, file_source: ?std.Build.FileSource) void { | 311 | fn checkExactInner(self: *CheckObject, phrase: []const u8, file_source: ?std.Build.LazyPath) void { |
| 312 | assert(self.checks.items.len > 0); | 312 | assert(self.checks.items.len > 0); |
| 313 | const last = &self.checks.items[self.checks.items.len - 1]; | 313 | const last = &self.checks.items[self.checks.items.len - 1]; |
| 314 | last.exact(.{ .string = self.step.owner.dupe(phrase), .file_source = file_source }); | 314 | last.exact(.{ .string = self.step.owner.dupe(phrase), .file_source = file_source }); |
| ... | @@ -321,7 +321,7 @@ pub fn checkContains(self: *CheckObject, phrase: []const u8) void { | ... | @@ -321,7 +321,7 @@ pub fn checkContains(self: *CheckObject, phrase: []const u8) void { |
| 321 | 321 | ||
| 322 | /// Like `checkContains()` but takes an additional argument `FileSource` which will be | 322 | /// Like `checkContains()` but takes an additional argument `FileSource` which will be |
| 323 | /// resolved to a full search query in `make()`. | 323 | /// resolved to a full search query in `make()`. |
| 324 | pub fn checkContainsFileSource(self: *CheckObject, phrase: []const u8, file_source: std.Build.FileSource) void { | 324 | pub fn checkContainsPath(self: *CheckObject, phrase: []const u8, file_source: std.Build.LazyPath) void { |
| 325 | self.checkContainsInner(phrase, file_source); | 325 | self.checkContainsInner(phrase, file_source); |
| 326 | } | 326 | } |
| 327 | 327 |
lib/std/Build/Step/Compile.zig+230-185| ... | @@ -11,7 +11,7 @@ const Allocator = mem.Allocator; | ... | @@ -11,7 +11,7 @@ const Allocator = mem.Allocator; |
| 11 | const Step = std.Build.Step; | 11 | const Step = std.Build.Step; |
| 12 | const CrossTarget = std.zig.CrossTarget; | 12 | const CrossTarget = std.zig.CrossTarget; |
| 13 | const NativeTargetInfo = std.zig.system.NativeTargetInfo; | 13 | const NativeTargetInfo = std.zig.system.NativeTargetInfo; |
| 14 | const FileSource = std.Build.FileSource; | 14 | const LazyPath = std.Build.LazyPath; |
| 15 | const PkgConfigPkg = std.Build.PkgConfigPkg; | 15 | const PkgConfigPkg = std.Build.PkgConfigPkg; |
| 16 | const PkgConfigError = std.Build.PkgConfigError; | 16 | const PkgConfigError = std.Build.PkgConfigError; |
| 17 | const ExecError = std.Build.ExecError; | 17 | const ExecError = std.Build.ExecError; |
| ... | @@ -28,7 +28,7 @@ name: []const u8, | ... | @@ -28,7 +28,7 @@ name: []const u8, |
| 28 | target: CrossTarget, | 28 | target: CrossTarget, |
| 29 | target_info: NativeTargetInfo, | 29 | target_info: NativeTargetInfo, |
| 30 | optimize: std.builtin.Mode, | 30 | optimize: std.builtin.Mode, |
| 31 | linker_script: ?FileSource = null, | 31 | linker_script: ?LazyPath = null, |
| 32 | version_script: ?[]const u8 = null, | 32 | version_script: ?[]const u8 = null, |
| 33 | out_filename: []const u8, | 33 | out_filename: []const u8, |
| 34 | linkage: ?Linkage = null, | 34 | linkage: ?Linkage = null, |
| ... | @@ -40,20 +40,12 @@ strip: ?bool, | ... | @@ -40,20 +40,12 @@ strip: ?bool, |
| 40 | unwind_tables: ?bool, | 40 | unwind_tables: ?bool, |
| 41 | // keep in sync with src/link.zig:CompressDebugSections | 41 | // keep in sync with src/link.zig:CompressDebugSections |
| 42 | compress_debug_sections: enum { none, zlib } = .none, | 42 | compress_debug_sections: enum { none, zlib } = .none, |
| 43 | lib_paths: ArrayList(FileSource), | 43 | lib_paths: ArrayList(LazyPath), |
| 44 | rpaths: ArrayList(FileSource), | 44 | rpaths: ArrayList(LazyPath), |
| 45 | framework_dirs: ArrayList(FileSource), | 45 | framework_dirs: ArrayList(LazyPath), |
| 46 | frameworks: StringHashMap(FrameworkLinkInfo), | 46 | frameworks: StringHashMap(FrameworkLinkInfo), |
| 47 | verbose_link: bool, | 47 | verbose_link: bool, |
| 48 | verbose_cc: bool, | 48 | verbose_cc: bool, |
| 49 | emit_asm: EmitOption = .default, | ||
| 50 | emit_bin: EmitOption = .default, | ||
| 51 | emit_implib: EmitOption = .default, | ||
| 52 | emit_llvm_bc: EmitOption = .default, | ||
| 53 | emit_llvm_ir: EmitOption = .default, | ||
| 54 | // Lots of things depend on emit_h having a consistent path, | ||
| 55 | // so it is not an EmitOption for now. | ||
| 56 | emit_h: bool = false, | ||
| 57 | bundle_compiler_rt: ?bool = null, | 49 | bundle_compiler_rt: ?bool = null, |
| 58 | single_threaded: ?bool, | 50 | single_threaded: ?bool, |
| 59 | stack_protector: ?bool = null, | 51 | stack_protector: ?bool = null, |
| ... | @@ -74,8 +66,10 @@ max_memory: ?u64 = null, | ... | @@ -74,8 +66,10 @@ max_memory: ?u64 = null, |
| 74 | shared_memory: bool = false, | 66 | shared_memory: bool = false, |
| 75 | global_base: ?u64 = null, | 67 | global_base: ?u64 = null, |
| 76 | c_std: std.Build.CStd, | 68 | c_std: std.Build.CStd, |
| 77 | zig_lib_dir: ?[]const u8, | 69 | /// Set via options; intended to be read-only after that. |
| 78 | main_pkg_path: ?[]const u8, | 70 | zig_lib_dir: ?LazyPath, |
| 71 | /// Set via options; intended to be read-only after that. | ||
| 72 | main_pkg_path: ?LazyPath, | ||
| 79 | exec_cmd_args: ?[]const ?[]const u8, | 73 | exec_cmd_args: ?[]const ?[]const u8, |
| 80 | filter: ?[]const u8, | 74 | filter: ?[]const u8, |
| 81 | test_evented_io: bool = false, | 75 | test_evented_io: bool = false, |
| ... | @@ -85,10 +79,8 @@ wasi_exec_model: ?std.builtin.WasiExecModel = null, | ... | @@ -85,10 +79,8 @@ wasi_exec_model: ?std.builtin.WasiExecModel = null, |
| 85 | /// Symbols to be exported when compiling to wasm | 79 | /// Symbols to be exported when compiling to wasm |
| 86 | export_symbol_names: []const []const u8 = &.{}, | 80 | export_symbol_names: []const []const u8 = &.{}, |
| 87 | 81 | ||
| 88 | root_src: ?FileSource, | 82 | root_src: ?LazyPath, |
| 89 | out_h_filename: []const u8, | ||
| 90 | out_lib_filename: []const u8, | 83 | out_lib_filename: []const u8, |
| 91 | out_pdb_filename: []const u8, | ||
| 92 | modules: std.StringArrayHashMap(*Module), | 84 | modules: std.StringArrayHashMap(*Module), |
| 93 | 85 | ||
| 94 | link_objects: ArrayList(LinkObject), | 86 | link_objects: ArrayList(LinkObject), |
| ... | @@ -99,14 +91,12 @@ is_linking_libc: bool, | ... | @@ -99,14 +91,12 @@ is_linking_libc: bool, |
| 99 | is_linking_libcpp: bool, | 91 | is_linking_libcpp: bool, |
| 100 | vcpkg_bin_path: ?[]const u8 = null, | 92 | vcpkg_bin_path: ?[]const u8 = null, |
| 101 | 93 | ||
| 102 | /// This may be set in order to override the default install directory | ||
| 103 | override_dest_dir: ?InstallDir, | ||
| 104 | installed_path: ?[]const u8, | 94 | installed_path: ?[]const u8, |
| 105 | 95 | ||
| 106 | /// Base address for an executable image. | 96 | /// Base address for an executable image. |
| 107 | image_base: ?u64 = null, | 97 | image_base: ?u64 = null, |
| 108 | 98 | ||
| 109 | libc_file: ?FileSource = null, | 99 | libc_file: ?LazyPath = null, |
| 110 | 100 | ||
| 111 | valgrind_support: ?bool = null, | 101 | valgrind_support: ?bool = null, |
| 112 | each_lib_rpath: ?bool = null, | 102 | each_lib_rpath: ?bool = null, |
| ... | @@ -210,35 +200,40 @@ use_lld: ?bool, | ... | @@ -210,35 +200,40 @@ use_lld: ?bool, |
| 210 | /// otherwise. | 200 | /// otherwise. |
| 211 | expect_errors: []const []const u8 = &.{}, | 201 | expect_errors: []const []const u8 = &.{}, |
| 212 | 202 | ||
| 213 | output_path_source: GeneratedFile, | 203 | emit_directory: ?*GeneratedFile, |
| 214 | output_lib_path_source: GeneratedFile, | 204 | |
| 215 | output_h_path_source: GeneratedFile, | ||
| 216 | output_pdb_path_source: GeneratedFile, | ||
| 217 | output_dirname_source: GeneratedFile, | ||
| 218 | generated_docs: ?*GeneratedFile, | 205 | generated_docs: ?*GeneratedFile, |
| 206 | generated_asm: ?*GeneratedFile, | ||
| 207 | generated_bin: ?*GeneratedFile, | ||
| 208 | generated_pdb: ?*GeneratedFile, | ||
| 209 | generated_implib: ?*GeneratedFile, | ||
| 210 | generated_llvm_bc: ?*GeneratedFile, | ||
| 211 | generated_llvm_ir: ?*GeneratedFile, | ||
| 212 | generated_h: ?*GeneratedFile, | ||
| 219 | 213 | ||
| 220 | pub const CSourceFiles = struct { | 214 | pub const CSourceFiles = struct { |
| 215 | /// Relative to the build root. | ||
| 221 | files: []const []const u8, | 216 | files: []const []const u8, |
| 222 | flags: []const []const u8, | 217 | flags: []const []const u8, |
| 223 | }; | 218 | }; |
| 224 | 219 | ||
| 225 | pub const CSourceFile = struct { | 220 | pub const CSourceFile = struct { |
| 226 | source: FileSource, | 221 | file: LazyPath, |
| 227 | args: []const []const u8, | 222 | flags: []const []const u8, |
| 228 | 223 | ||
| 229 | pub fn dupe(self: CSourceFile, b: *std.Build) CSourceFile { | 224 | pub fn dupe(self: CSourceFile, b: *std.Build) CSourceFile { |
| 230 | return .{ | 225 | return .{ |
| 231 | .source = self.source.dupe(b), | 226 | .file = self.file.dupe(b), |
| 232 | .args = b.dupeStrings(self.args), | 227 | .flags = b.dupeStrings(self.flags), |
| 233 | }; | 228 | }; |
| 234 | } | 229 | } |
| 235 | }; | 230 | }; |
| 236 | 231 | ||
| 237 | pub const LinkObject = union(enum) { | 232 | pub const LinkObject = union(enum) { |
| 238 | static_path: FileSource, | 233 | static_path: LazyPath, |
| 239 | other_step: *Compile, | 234 | other_step: *Compile, |
| 240 | system_lib: SystemLib, | 235 | system_lib: SystemLib, |
| 241 | assembly_file: FileSource, | 236 | assembly_file: LazyPath, |
| 242 | c_source_file: *CSourceFile, | 237 | c_source_file: *CSourceFile, |
| 243 | c_source_files: *CSourceFiles, | 238 | c_source_files: *CSourceFiles, |
| 244 | }; | 239 | }; |
| ... | @@ -265,15 +260,15 @@ const FrameworkLinkInfo = struct { | ... | @@ -265,15 +260,15 @@ const FrameworkLinkInfo = struct { |
| 265 | }; | 260 | }; |
| 266 | 261 | ||
| 267 | pub const IncludeDir = union(enum) { | 262 | pub const IncludeDir = union(enum) { |
| 268 | raw_path: []const u8, | 263 | path: LazyPath, |
| 269 | raw_path_system: []const u8, | 264 | path_system: LazyPath, |
| 270 | other_step: *Compile, | 265 | other_step: *Compile, |
| 271 | config_header_step: *Step.ConfigHeader, | 266 | config_header_step: *Step.ConfigHeader, |
| 272 | }; | 267 | }; |
| 273 | 268 | ||
| 274 | pub const Options = struct { | 269 | pub const Options = struct { |
| 275 | name: []const u8, | 270 | name: []const u8, |
| 276 | root_source_file: ?FileSource = null, | 271 | root_source_file: ?LazyPath = null, |
| 277 | target: CrossTarget, | 272 | target: CrossTarget, |
| 278 | optimize: std.builtin.Mode, | 273 | optimize: std.builtin.Mode, |
| 279 | kind: Kind, | 274 | kind: Kind, |
| ... | @@ -286,6 +281,8 @@ pub const Options = struct { | ... | @@ -286,6 +281,8 @@ pub const Options = struct { |
| 286 | single_threaded: ?bool = null, | 281 | single_threaded: ?bool = null, |
| 287 | use_llvm: ?bool = null, | 282 | use_llvm: ?bool = null, |
| 288 | use_lld: ?bool = null, | 283 | use_lld: ?bool = null, |
| 284 | zig_lib_dir: ?LazyPath = null, | ||
| 285 | main_pkg_path: ?LazyPath = null, | ||
| 289 | }; | 286 | }; |
| 290 | 287 | ||
| 291 | pub const BuildId = union(enum) { | 288 | pub const BuildId = union(enum) { |
| ... | @@ -373,25 +370,9 @@ pub const Kind = enum { | ... | @@ -373,25 +370,9 @@ pub const Kind = enum { |
| 373 | 370 | ||
| 374 | pub const Linkage = enum { dynamic, static }; | 371 | pub const Linkage = enum { dynamic, static }; |
| 375 | 372 | ||
| 376 | pub const EmitOption = union(enum) { | ||
| 377 | default: void, | ||
| 378 | no_emit: void, | ||
| 379 | emit: void, | ||
| 380 | emit_to: []const u8, | ||
| 381 | |||
| 382 | fn getArg(self: @This(), b: *std.Build, arg_name: []const u8) ?[]const u8 { | ||
| 383 | return switch (self) { | ||
| 384 | .no_emit => b.fmt("-fno-{s}", .{arg_name}), | ||
| 385 | .default => null, | ||
| 386 | .emit => b.fmt("-f{s}", .{arg_name}), | ||
| 387 | .emit_to => |path| b.fmt("-f{s}={s}", .{ arg_name, path }), | ||
| 388 | }; | ||
| 389 | } | ||
| 390 | }; | ||
| 391 | |||
| 392 | pub fn create(owner: *std.Build, options: Options) *Compile { | 373 | pub fn create(owner: *std.Build, options: Options) *Compile { |
| 393 | const name = owner.dupe(options.name); | 374 | const name = owner.dupe(options.name); |
| 394 | const root_src: ?FileSource = if (options.root_source_file) |rsrc| rsrc.dupe(owner) else null; | 375 | const root_src: ?LazyPath = if (options.root_source_file) |rsrc| rsrc.dupe(owner) else null; |
| 395 | if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) { | 376 | if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) { |
| 396 | panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name}); | 377 | panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name}); |
| 397 | } | 378 | } |
| ... | @@ -453,18 +434,16 @@ pub fn create(owner: *std.Build, options: Options) *Compile { | ... | @@ -453,18 +434,16 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 453 | }), | 434 | }), |
| 454 | .version = options.version, | 435 | .version = options.version, |
| 455 | .out_filename = out_filename, | 436 | .out_filename = out_filename, |
| 456 | .out_h_filename = owner.fmt("{s}.h", .{name}), | ||
| 457 | .out_lib_filename = undefined, | 437 | .out_lib_filename = undefined, |
| 458 | .out_pdb_filename = owner.fmt("{s}.pdb", .{name}), | ||
| 459 | .major_only_filename = null, | 438 | .major_only_filename = null, |
| 460 | .name_only_filename = null, | 439 | .name_only_filename = null, |
| 461 | .modules = std.StringArrayHashMap(*Module).init(owner.allocator), | 440 | .modules = std.StringArrayHashMap(*Module).init(owner.allocator), |
| 462 | .include_dirs = ArrayList(IncludeDir).init(owner.allocator), | 441 | .include_dirs = ArrayList(IncludeDir).init(owner.allocator), |
| 463 | .link_objects = ArrayList(LinkObject).init(owner.allocator), | 442 | .link_objects = ArrayList(LinkObject).init(owner.allocator), |
| 464 | .c_macros = ArrayList([]const u8).init(owner.allocator), | 443 | .c_macros = ArrayList([]const u8).init(owner.allocator), |
| 465 | .lib_paths = ArrayList(FileSource).init(owner.allocator), | 444 | .lib_paths = ArrayList(LazyPath).init(owner.allocator), |
| 466 | .rpaths = ArrayList(FileSource).init(owner.allocator), | 445 | .rpaths = ArrayList(LazyPath).init(owner.allocator), |
| 467 | .framework_dirs = ArrayList(FileSource).init(owner.allocator), | 446 | .framework_dirs = ArrayList(LazyPath).init(owner.allocator), |
| 468 | .installed_headers = ArrayList(*Step).init(owner.allocator), | 447 | .installed_headers = ArrayList(*Step).init(owner.allocator), |
| 469 | .c_std = std.Build.CStd.C99, | 448 | .c_std = std.Build.CStd.C99, |
| 470 | .zig_lib_dir = null, | 449 | .zig_lib_dir = null, |
| ... | @@ -476,16 +455,18 @@ pub fn create(owner: *std.Build, options: Options) *Compile { | ... | @@ -476,16 +455,18 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 476 | .disable_sanitize_c = false, | 455 | .disable_sanitize_c = false, |
| 477 | .sanitize_thread = false, | 456 | .sanitize_thread = false, |
| 478 | .rdynamic = false, | 457 | .rdynamic = false, |
| 479 | .override_dest_dir = null, | ||
| 480 | .installed_path = null, | 458 | .installed_path = null, |
| 481 | .force_undefined_symbols = StringHashMap(void).init(owner.allocator), | 459 | .force_undefined_symbols = StringHashMap(void).init(owner.allocator), |
| 482 | 460 | ||
| 483 | .output_path_source = GeneratedFile{ .step = &self.step }, | 461 | .emit_directory = null, |
| 484 | .output_lib_path_source = GeneratedFile{ .step = &self.step }, | ||
| 485 | .output_h_path_source = GeneratedFile{ .step = &self.step }, | ||
| 486 | .output_pdb_path_source = GeneratedFile{ .step = &self.step }, | ||
| 487 | .output_dirname_source = GeneratedFile{ .step = &self.step }, | ||
| 488 | .generated_docs = null, | 462 | .generated_docs = null, |
| 463 | .generated_asm = null, | ||
| 464 | .generated_bin = null, | ||
| 465 | .generated_pdb = null, | ||
| 466 | .generated_implib = null, | ||
| 467 | .generated_llvm_bc = null, | ||
| 468 | .generated_llvm_ir = null, | ||
| 469 | .generated_h = null, | ||
| 489 | 470 | ||
| 490 | .target_info = target_info, | 471 | .target_info = target_info, |
| 491 | 472 | ||
| ... | @@ -496,6 +477,16 @@ pub fn create(owner: *std.Build, options: Options) *Compile { | ... | @@ -496,6 +477,16 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 496 | .use_lld = options.use_lld, | 477 | .use_lld = options.use_lld, |
| 497 | }; | 478 | }; |
| 498 | 479 | ||
| 480 | if (options.zig_lib_dir) |lp| { | ||
| 481 | self.zig_lib_dir = lp.dupe(self.step.owner); | ||
| 482 | lp.addStepDependencies(&self.step); | ||
| 483 | } | ||
| 484 | |||
| 485 | if (options.main_pkg_path) |lp| { | ||
| 486 | self.main_pkg_path = lp.dupe(self.step.owner); | ||
| 487 | lp.addStepDependencies(&self.step); | ||
| 488 | } | ||
| 489 | |||
| 499 | if (self.kind == .lib) { | 490 | if (self.kind == .lib) { |
| 500 | if (self.linkage != null and self.linkage.? == .static) { | 491 | if (self.linkage != null and self.linkage.? == .static) { |
| 501 | self.out_lib_filename = self.out_filename; | 492 | self.out_lib_filename = self.out_filename; |
| ... | @@ -614,7 +605,7 @@ pub fn addObjCopy(cs: *Compile, options: Step.ObjCopy.Options) *Step.ObjCopy { | ... | @@ -614,7 +605,7 @@ pub fn addObjCopy(cs: *Compile, options: Step.ObjCopy.Options) *Step.ObjCopy { |
| 614 | copy.basename = cs.name; | 605 | copy.basename = cs.name; |
| 615 | } | 606 | } |
| 616 | } | 607 | } |
| 617 | return b.addObjCopy(cs.getOutputSource(), copy); | 608 | return b.addObjCopy(cs.getEmittedBin(), copy); |
| 618 | } | 609 | } |
| 619 | 610 | ||
| 620 | /// This function would run in the context of the package that created the executable, | 611 | /// This function would run in the context of the package that created the executable, |
| ... | @@ -626,10 +617,13 @@ pub const run = @compileError("deprecated; use std.Build.addRunArtifact"); | ... | @@ -626,10 +617,13 @@ pub const run = @compileError("deprecated; use std.Build.addRunArtifact"); |
| 626 | pub const install = @compileError("deprecated; use std.Build.installArtifact"); | 617 | pub const install = @compileError("deprecated; use std.Build.installArtifact"); |
| 627 | 618 | ||
| 628 | pub fn checkObject(self: *Compile) *Step.CheckObject { | 619 | pub fn checkObject(self: *Compile) *Step.CheckObject { |
| 629 | return Step.CheckObject.create(self.step.owner, self.getOutputSource(), self.target_info.target.ofmt); | 620 | return Step.CheckObject.create(self.step.owner, self.getEmittedBin(), self.target_info.target.ofmt); |
| 630 | } | 621 | } |
| 631 | 622 | ||
| 632 | pub fn setLinkerScriptPath(self: *Compile, source: FileSource) void { | 623 | /// deprecated: use `setLinkerScript` |
| 624 | pub const setLinkerScriptPath = setLinkerScript; | ||
| 625 | |||
| 626 | pub fn setLinkerScript(self: *Compile, source: LazyPath) void { | ||
| 633 | const b = self.step.owner; | 627 | const b = self.step.owner; |
| 634 | self.linker_script = source.dupe(b); | 628 | self.linker_script = source.dupe(b); |
| 635 | source.addStepDependencies(&self.step); | 629 | source.addStepDependencies(&self.step); |
| ... | @@ -690,12 +684,18 @@ pub fn isStaticLibrary(self: *Compile) bool { | ... | @@ -690,12 +684,18 @@ pub fn isStaticLibrary(self: *Compile) bool { |
| 690 | } | 684 | } |
| 691 | 685 | ||
| 692 | pub fn producesPdbFile(self: *Compile) bool { | 686 | pub fn producesPdbFile(self: *Compile) bool { |
| 687 | // TODO: Is this right? Isn't PDB for *any* PE/COFF file? | ||
| 688 | // TODO: just share this logic with the compiler, silly! | ||
| 693 | if (!self.target.isWindows() and !self.target.isUefi()) return false; | 689 | if (!self.target.isWindows() and !self.target.isUefi()) return false; |
| 694 | if (self.target.getObjectFormat() == .c) return false; | 690 | if (self.target.getObjectFormat() == .c) return false; |
| 695 | if (self.strip == true or (self.strip == null and self.optimize == .ReleaseSmall)) return false; | 691 | if (self.strip == true or (self.strip == null and self.optimize == .ReleaseSmall)) return false; |
| 696 | return self.isDynamicLibrary() or self.kind == .exe or self.kind == .@"test"; | 692 | return self.isDynamicLibrary() or self.kind == .exe or self.kind == .@"test"; |
| 697 | } | 693 | } |
| 698 | 694 | ||
| 695 | pub fn producesImplib(self: *Compile) bool { | ||
| 696 | return self.isDynamicLibrary() and self.target.isWindows(); | ||
| 697 | } | ||
| 698 | |||
| 699 | pub fn linkLibC(self: *Compile) void { | 699 | pub fn linkLibC(self: *Compile) void { |
| 700 | self.is_linking_libc = true; | 700 | self.is_linking_libc = true; |
| 701 | } | 701 | } |
| ... | @@ -935,19 +935,12 @@ pub fn addCSourceFiles(self: *Compile, files: []const []const u8, flags: []const | ... | @@ -935,19 +935,12 @@ pub fn addCSourceFiles(self: *Compile, files: []const []const u8, flags: []const |
| 935 | self.link_objects.append(.{ .c_source_files = c_source_files }) catch @panic("OOM"); | 935 | self.link_objects.append(.{ .c_source_files = c_source_files }) catch @panic("OOM"); |
| 936 | } | 936 | } |
| 937 | 937 | ||
| 938 | pub fn addCSourceFile(self: *Compile, file: []const u8, flags: []const []const u8) void { | 938 | pub fn addCSourceFile(self: *Compile, source: CSourceFile) void { |
| 939 | self.addCSourceFileSource(.{ | ||
| 940 | .args = flags, | ||
| 941 | .source = .{ .path = file }, | ||
| 942 | }); | ||
| 943 | } | ||
| 944 | |||
| 945 | pub fn addCSourceFileSource(self: *Compile, source: CSourceFile) void { | ||
| 946 | const b = self.step.owner; | 939 | const b = self.step.owner; |
| 947 | const c_source_file = b.allocator.create(CSourceFile) catch @panic("OOM"); | 940 | const c_source_file = b.allocator.create(CSourceFile) catch @panic("OOM"); |
| 948 | c_source_file.* = source.dupe(b); | 941 | c_source_file.* = source.dupe(b); |
| 949 | self.link_objects.append(.{ .c_source_file = c_source_file }) catch @panic("OOM"); | 942 | self.link_objects.append(.{ .c_source_file = c_source_file }) catch @panic("OOM"); |
| 950 | source.source.addStepDependencies(&self.step); | 943 | source.file.addStepDependencies(&self.step); |
| 951 | } | 944 | } |
| 952 | 945 | ||
| 953 | pub fn setVerboseLink(self: *Compile, value: bool) void { | 946 | pub fn setVerboseLink(self: *Compile, value: bool) void { |
| ... | @@ -958,80 +951,99 @@ pub fn setVerboseCC(self: *Compile, value: bool) void { | ... | @@ -958,80 +951,99 @@ pub fn setVerboseCC(self: *Compile, value: bool) void { |
| 958 | self.verbose_cc = value; | 951 | self.verbose_cc = value; |
| 959 | } | 952 | } |
| 960 | 953 | ||
| 961 | pub fn overrideZigLibDir(self: *Compile, dir_path: []const u8) void { | 954 | pub fn setLibCFile(self: *Compile, libc_file: ?LazyPath) void { |
| 962 | const b = self.step.owner; | 955 | const b = self.step.owner; |
| 963 | self.zig_lib_dir = b.dupePath(dir_path); | 956 | self.libc_file = if (libc_file) |f| f.dupe(b) else null; |
| 964 | } | 957 | } |
| 965 | 958 | ||
| 966 | pub fn setMainPkgPath(self: *Compile, dir_path: []const u8) void { | 959 | fn getEmittedFileGeneric(self: *Compile, output_file: *?*GeneratedFile) LazyPath { |
| 967 | const b = self.step.owner; | 960 | if (output_file.*) |g| { |
| 968 | self.main_pkg_path = b.dupePath(dir_path); | 961 | return .{ .generated = g }; |
| 962 | } | ||
| 963 | const arena = self.step.owner.allocator; | ||
| 964 | const generated_file = arena.create(GeneratedFile) catch @panic("OOM"); | ||
| 965 | generated_file.* = .{ .step = &self.step }; | ||
| 966 | output_file.* = generated_file; | ||
| 967 | return .{ .generated = generated_file }; | ||
| 969 | } | 968 | } |
| 970 | 969 | ||
| 971 | pub fn setLibCFile(self: *Compile, libc_file: ?FileSource) void { | 970 | /// deprecated: use `getEmittedBinDirectory` |
| 972 | const b = self.step.owner; | 971 | pub const getOutputDirectorySource = getEmittedBinDirectory; |
| 973 | self.libc_file = if (libc_file) |f| f.dupe(b) else null; | 972 | |
| 973 | /// Returns the path to the directory that contains the emitted binary file. | ||
| 974 | pub fn getEmittedBinDirectory(self: *Compile) LazyPath { | ||
| 975 | _ = self.getEmittedBin(); | ||
| 976 | return self.getEmittedFileGeneric(&self.emit_directory); | ||
| 974 | } | 977 | } |
| 975 | 978 | ||
| 976 | /// Returns the generated executable, library or object file. | 979 | /// deprecated: use `getEmittedBin` |
| 980 | pub const getOutputSource = getEmittedBin; | ||
| 981 | |||
| 982 | /// Returns the path to the generated executable, library or object file. | ||
| 977 | /// To run an executable built with zig build, use `run`, or create an install step and invoke it. | 983 | /// To run an executable built with zig build, use `run`, or create an install step and invoke it. |
| 978 | pub fn getOutputSource(self: *Compile) FileSource { | 984 | pub fn getEmittedBin(self: *Compile) LazyPath { |
| 979 | return .{ .generated = &self.output_path_source }; | 985 | return self.getEmittedFileGeneric(&self.generated_bin); |
| 980 | } | 986 | } |
| 981 | 987 | ||
| 982 | pub fn getOutputDirectorySource(self: *Compile) FileSource { | 988 | /// deprecated: use `getEmittedImplib` |
| 983 | return .{ .generated = &self.output_dirname_source }; | 989 | pub const getOutputLibSource = getEmittedImplib; |
| 984 | } | ||
| 985 | 990 | ||
| 986 | /// Returns the generated import library. This function can only be called for libraries. | 991 | /// Returns the path to the generated import library. |
| 987 | pub fn getOutputLibSource(self: *Compile) FileSource { | 992 | /// This function can only be called for libraries. |
| 993 | pub fn getEmittedImplib(self: *Compile) LazyPath { | ||
| 988 | assert(self.kind == .lib); | 994 | assert(self.kind == .lib); |
| 989 | return .{ .generated = &self.output_lib_path_source }; | 995 | return self.getEmittedFileGeneric(&self.generated_implib); |
| 990 | } | 996 | } |
| 991 | 997 | ||
| 992 | /// Returns the generated header file. | 998 | /// deprecated: use `getEmittedH` |
| 993 | /// This function can only be called for libraries or object files which have `emit_h` set. | 999 | pub const getOutputHSource = getEmittedH; |
| 994 | pub fn getOutputHSource(self: *Compile) FileSource { | 1000 | |
| 1001 | /// Returns the path to the generated header file. | ||
| 1002 | /// This function can only be called for libraries or objects. | ||
| 1003 | pub fn getEmittedH(self: *Compile) LazyPath { | ||
| 995 | assert(self.kind != .exe and self.kind != .@"test"); | 1004 | assert(self.kind != .exe and self.kind != .@"test"); |
| 996 | assert(self.emit_h); | 1005 | return self.getEmittedFileGeneric(&self.generated_h); |
| 997 | return .{ .generated = &self.output_h_path_source }; | ||
| 998 | } | 1006 | } |
| 999 | 1007 | ||
| 1000 | /// Returns the generated PDB file. This function can only be called for Windows and UEFI. | 1008 | /// deprecated: use `getEmittedPdb`. |
| 1001 | pub fn getOutputPdbSource(self: *Compile) FileSource { | 1009 | pub const getOutputPdbSource = getEmittedPdb; |
| 1002 | // TODO: Is this right? Isn't PDB for *any* PE/COFF file? | 1010 | |
| 1003 | assert(self.target.isWindows() or self.target.isUefi()); | 1011 | /// Returns the generated PDB file. |
| 1004 | return .{ .generated = &self.output_pdb_path_source }; | 1012 | /// If the compilation does not produce a PDB file, this causes a FileNotFound error |
| 1013 | /// at build time. | ||
| 1014 | pub fn getEmittedPdb(self: *Compile) LazyPath { | ||
| 1015 | _ = self.getEmittedBin(); | ||
| 1016 | return self.getEmittedFileGeneric(&self.generated_pdb); | ||
| 1005 | } | 1017 | } |
| 1006 | 1018 | ||
| 1007 | pub fn getEmittedDocs(self: *Compile) FileSource { | 1019 | /// Returns the path to the generated documentation directory. |
| 1008 | if (self.generated_docs) |g| return .{ .generated = g }; | 1020 | pub fn getEmittedDocs(self: *Compile) LazyPath { |
| 1009 | const arena = self.step.owner.allocator; | 1021 | return self.getEmittedFileGeneric(&self.generated_docs); |
| 1010 | const generated_file = arena.create(GeneratedFile) catch @panic("OOM"); | ||
| 1011 | generated_file.* = .{ .step = &self.step }; | ||
| 1012 | self.generated_docs = generated_file; | ||
| 1013 | return .{ .generated = generated_file }; | ||
| 1014 | } | 1022 | } |
| 1015 | 1023 | ||
| 1016 | pub fn addAssemblyFile(self: *Compile, path: []const u8) void { | 1024 | /// Returns the path to the generated assembly code. |
| 1017 | const b = self.step.owner; | 1025 | pub fn getEmittedAsm(self: *Compile) LazyPath { |
| 1018 | self.link_objects.append(.{ | 1026 | return self.getEmittedFileGeneric(&self.generated_asm); |
| 1019 | .assembly_file = .{ .path = b.dupe(path) }, | ||
| 1020 | }) catch @panic("OOM"); | ||
| 1021 | } | 1027 | } |
| 1022 | 1028 | ||
| 1023 | pub fn addAssemblyFileSource(self: *Compile, source: FileSource) void { | 1029 | /// Returns the path to the generated LLVM IR. |
| 1030 | pub fn getEmittedLlvmIr(self: *Compile) LazyPath { | ||
| 1031 | return self.getEmittedFileGeneric(&self.generated_llvm_ir); | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | /// Returns the path to the generated LLVM BC. | ||
| 1035 | pub fn getEmittedLlvmBc(self: *Compile) LazyPath { | ||
| 1036 | return self.getEmittedFileGeneric(&self.generated_llvm_bc); | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | pub fn addAssemblyFile(self: *Compile, source: LazyPath) void { | ||
| 1024 | const b = self.step.owner; | 1040 | const b = self.step.owner; |
| 1025 | const source_duped = source.dupe(b); | 1041 | const source_duped = source.dupe(b); |
| 1026 | self.link_objects.append(.{ .assembly_file = source_duped }) catch @panic("OOM"); | 1042 | self.link_objects.append(.{ .assembly_file = source_duped }) catch @panic("OOM"); |
| 1027 | source_duped.addStepDependencies(&self.step); | 1043 | source_duped.addStepDependencies(&self.step); |
| 1028 | } | 1044 | } |
| 1029 | 1045 | ||
| 1030 | pub fn addObjectFile(self: *Compile, source_file: []const u8) void { | 1046 | pub fn addObjectFile(self: *Compile, source: LazyPath) void { |
| 1031 | self.addObjectFileSource(.{ .path = source_file }); | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | pub fn addObjectFileSource(self: *Compile, source: FileSource) void { | ||
| 1035 | const b = self.step.owner; | 1047 | const b = self.step.owner; |
| 1036 | self.link_objects.append(.{ .static_path = source.dupe(b) }) catch @panic("OOM"); | 1048 | self.link_objects.append(.{ .static_path = source.dupe(b) }) catch @panic("OOM"); |
| 1037 | source.addStepDependencies(&self.step); | 1049 | source.addStepDependencies(&self.step); |
| ... | @@ -1042,14 +1054,16 @@ pub fn addObject(self: *Compile, obj: *Compile) void { | ... | @@ -1042,14 +1054,16 @@ pub fn addObject(self: *Compile, obj: *Compile) void { |
| 1042 | self.linkLibraryOrObject(obj); | 1054 | self.linkLibraryOrObject(obj); |
| 1043 | } | 1055 | } |
| 1044 | 1056 | ||
| 1045 | pub fn addSystemIncludePath(self: *Compile, path: []const u8) void { | 1057 | pub fn addSystemIncludePath(self: *Compile, path: LazyPath) void { |
| 1046 | const b = self.step.owner; | 1058 | const b = self.step.owner; |
| 1047 | self.include_dirs.append(IncludeDir{ .raw_path_system = b.dupe(path) }) catch @panic("OOM"); | 1059 | self.include_dirs.append(IncludeDir{ .path_system = path.dupe(b) }) catch @panic("OOM"); |
| 1060 | path.addStepDependencies(&self.step); | ||
| 1048 | } | 1061 | } |
| 1049 | 1062 | ||
| 1050 | pub fn addIncludePath(self: *Compile, path: []const u8) void { | 1063 | pub fn addIncludePath(self: *Compile, path: LazyPath) void { |
| 1051 | const b = self.step.owner; | 1064 | const b = self.step.owner; |
| 1052 | self.include_dirs.append(IncludeDir{ .raw_path = b.dupe(path) }) catch @panic("OOM"); | 1065 | self.include_dirs.append(IncludeDir{ .path = path.dupe(b) }) catch @panic("OOM"); |
| 1066 | path.addStepDependencies(&self.step); | ||
| 1053 | } | 1067 | } |
| 1054 | 1068 | ||
| 1055 | pub fn addConfigHeader(self: *Compile, config_header: *Step.ConfigHeader) void { | 1069 | pub fn addConfigHeader(self: *Compile, config_header: *Step.ConfigHeader) void { |
| ... | @@ -1057,32 +1071,17 @@ pub fn addConfigHeader(self: *Compile, config_header: *Step.ConfigHeader) void { | ... | @@ -1057,32 +1071,17 @@ pub fn addConfigHeader(self: *Compile, config_header: *Step.ConfigHeader) void { |
| 1057 | self.include_dirs.append(.{ .config_header_step = config_header }) catch @panic("OOM"); | 1071 | self.include_dirs.append(.{ .config_header_step = config_header }) catch @panic("OOM"); |
| 1058 | } | 1072 | } |
| 1059 | 1073 | ||
| 1060 | pub fn addLibraryPath(self: *Compile, path: []const u8) void { | 1074 | pub fn addLibraryPath(self: *Compile, directory_source: LazyPath) void { |
| 1061 | const b = self.step.owner; | ||
| 1062 | self.lib_paths.append(.{ .path = b.dupe(path) }) catch @panic("OOM"); | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | pub fn addLibraryPathDirectorySource(self: *Compile, directory_source: FileSource) void { | ||
| 1066 | self.lib_paths.append(directory_source) catch @panic("OOM"); | 1075 | self.lib_paths.append(directory_source) catch @panic("OOM"); |
| 1067 | directory_source.addStepDependencies(&self.step); | 1076 | directory_source.addStepDependencies(&self.step); |
| 1068 | } | 1077 | } |
| 1069 | 1078 | ||
| 1070 | pub fn addRPath(self: *Compile, path: []const u8) void { | 1079 | pub fn addRPath(self: *Compile, directory_source: LazyPath) void { |
| 1071 | const b = self.step.owner; | ||
| 1072 | self.rpaths.append(.{ .path = b.dupe(path) }) catch @panic("OOM"); | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | pub fn addRPathDirectorySource(self: *Compile, directory_source: FileSource) void { | ||
| 1076 | self.rpaths.append(directory_source) catch @panic("OOM"); | 1080 | self.rpaths.append(directory_source) catch @panic("OOM"); |
| 1077 | directory_source.addStepDependencies(&self.step); | 1081 | directory_source.addStepDependencies(&self.step); |
| 1078 | } | 1082 | } |
| 1079 | 1083 | ||
| 1080 | pub fn addFrameworkPath(self: *Compile, dir_path: []const u8) void { | 1084 | pub fn addFrameworkPath(self: *Compile, directory_source: LazyPath) void { |
| 1081 | const b = self.step.owner; | ||
| 1082 | self.framework_dirs.append(.{ .path = b.dupe(dir_path) }) catch @panic("OOM"); | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | pub fn addFrameworkPathDirectorySource(self: *Compile, directory_source: FileSource) void { | ||
| 1086 | self.framework_dirs.append(directory_source) catch @panic("OOM"); | 1085 | self.framework_dirs.append(directory_source) catch @panic("OOM"); |
| 1087 | directory_source.addStepDependencies(&self.step); | 1086 | directory_source.addStepDependencies(&self.step); |
| 1088 | } | 1087 | } |
| ... | @@ -1168,7 +1167,11 @@ pub fn setExecCmd(self: *Compile, args: []const ?[]const u8) void { | ... | @@ -1168,7 +1167,11 @@ pub fn setExecCmd(self: *Compile, args: []const ?[]const u8) void { |
| 1168 | } | 1167 | } |
| 1169 | 1168 | ||
| 1170 | fn linkLibraryOrObject(self: *Compile, other: *Compile) void { | 1169 | fn linkLibraryOrObject(self: *Compile, other: *Compile) void { |
| 1171 | self.step.dependOn(&other.step); | 1170 | other.getEmittedBin().addStepDependencies(&self.step); |
| 1171 | if (other.target.isWindows() and other.isDynamicLibrary()) { | ||
| 1172 | other.getEmittedImplib().addStepDependencies(&self.step); | ||
| 1173 | } | ||
| 1174 | |||
| 1172 | self.link_objects.append(.{ .other_step = other }) catch @panic("OOM"); | 1175 | self.link_objects.append(.{ .other_step = other }) catch @panic("OOM"); |
| 1173 | self.include_dirs.append(.{ .other_step = other }) catch @panic("OOM"); | 1176 | self.include_dirs.append(.{ .other_step = other }) catch @panic("OOM"); |
| 1174 | 1177 | ||
| ... | @@ -1287,6 +1290,30 @@ fn constructDepString( | ... | @@ -1287,6 +1290,30 @@ fn constructDepString( |
| 1287 | } | 1290 | } |
| 1288 | } | 1291 | } |
| 1289 | 1292 | ||
| 1293 | fn getGeneratedFilePath(self: *Compile, comptime tag_name: []const u8, asking_step: ?*Step) []const u8 { | ||
| 1294 | const maybe_path: ?*GeneratedFile = @field(self, tag_name); | ||
| 1295 | |||
| 1296 | const generated_file = maybe_path orelse { | ||
| 1297 | std.debug.getStderrMutex().lock(); | ||
| 1298 | const stderr = std.io.getStdErr(); | ||
| 1299 | |||
| 1300 | std.Build.dumpBadGetPathHelp(&self.step, stderr, self.step.owner, asking_step) catch {}; | ||
| 1301 | |||
| 1302 | @panic("missing emit option for " ++ tag_name); | ||
| 1303 | }; | ||
| 1304 | |||
| 1305 | const path = generated_file.path orelse { | ||
| 1306 | std.debug.getStderrMutex().lock(); | ||
| 1307 | const stderr = std.io.getStdErr(); | ||
| 1308 | |||
| 1309 | std.Build.dumpBadGetPathHelp(&self.step, stderr, self.step.owner, asking_step) catch {}; | ||
| 1310 | |||
| 1311 | @panic(tag_name ++ " is null. Is there a missing step dependency?"); | ||
| 1312 | }; | ||
| 1313 | |||
| 1314 | return path; | ||
| 1315 | } | ||
| 1316 | |||
| 1290 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 1317 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1291 | const b = step.owner; | 1318 | const b = step.owner; |
| 1292 | const self = @fieldParentPtr(Compile, "step", step); | 1319 | const self = @fieldParentPtr(Compile, "step", step); |
| ... | @@ -1364,7 +1391,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -1364,7 +1391,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1364 | .exe => @panic("Cannot link with an executable build artifact"), | 1391 | .exe => @panic("Cannot link with an executable build artifact"), |
| 1365 | .@"test" => @panic("Cannot link with a test"), | 1392 | .@"test" => @panic("Cannot link with a test"), |
| 1366 | .obj => { | 1393 | .obj => { |
| 1367 | try zig_args.append(other.getOutputSource().getPath(b)); | 1394 | try zig_args.append(other.getEmittedBin().getPath(b)); |
| 1368 | }, | 1395 | }, |
| 1369 | .lib => l: { | 1396 | .lib => l: { |
| 1370 | if (self.isStaticLibrary() and other.isStaticLibrary()) { | 1397 | if (self.isStaticLibrary() and other.isStaticLibrary()) { |
| ... | @@ -1372,7 +1399,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -1372,7 +1399,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1372 | break :l; | 1399 | break :l; |
| 1373 | } | 1400 | } |
| 1374 | 1401 | ||
| 1375 | const full_path_lib = other.getOutputLibSource().getPath(b); | 1402 | // For DLLs, we gotta link against the implib. For |
| 1403 | // everything else, we directly link against the library file. | ||
| 1404 | const full_path_lib = if (other.producesImplib()) | ||
| 1405 | other.getGeneratedFilePath("generated_implib", &self.step) | ||
| 1406 | else | ||
| 1407 | other.getGeneratedFilePath("generated_bin", &self.step); | ||
| 1376 | try zig_args.append(full_path_lib); | 1408 | try zig_args.append(full_path_lib); |
| 1377 | 1409 | ||
| 1378 | if (other.linkage == Linkage.dynamic and !self.target.isWindows()) { | 1410 | if (other.linkage == Linkage.dynamic and !self.target.isWindows()) { |
| ... | @@ -1432,7 +1464,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -1432,7 +1464,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1432 | }, | 1464 | }, |
| 1433 | 1465 | ||
| 1434 | .c_source_file => |c_source_file| { | 1466 | .c_source_file => |c_source_file| { |
| 1435 | if (c_source_file.args.len == 0) { | 1467 | if (c_source_file.flags.len == 0) { |
| 1436 | if (prev_has_cflags) { | 1468 | if (prev_has_cflags) { |
| 1437 | try zig_args.append("-cflags"); | 1469 | try zig_args.append("-cflags"); |
| 1438 | try zig_args.append("--"); | 1470 | try zig_args.append("--"); |
| ... | @@ -1440,13 +1472,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -1440,13 +1472,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1440 | } | 1472 | } |
| 1441 | } else { | 1473 | } else { |
| 1442 | try zig_args.append("-cflags"); | 1474 | try zig_args.append("-cflags"); |
| 1443 | for (c_source_file.args) |arg| { | 1475 | for (c_source_file.flags) |arg| { |
| 1444 | try zig_args.append(arg); | 1476 | try zig_args.append(arg); |
| 1445 | } | 1477 | } |
| 1446 | try zig_args.append("--"); | 1478 | try zig_args.append("--"); |
| 1447 | prev_has_cflags = true; | 1479 | prev_has_cflags = true; |
| 1448 | } | 1480 | } |
| 1449 | try zig_args.append(c_source_file.source.getPath(b)); | 1481 | try zig_args.append(c_source_file.file.getPath(b)); |
| 1450 | }, | 1482 | }, |
| 1451 | 1483 | ||
| 1452 | .c_source_files => |c_source_files| { | 1484 | .c_source_files => |c_source_files| { |
| ... | @@ -1515,14 +1547,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -1515,14 +1547,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1515 | if (b.verbose_cc or self.verbose_cc) try zig_args.append("--verbose-cc"); | 1547 | if (b.verbose_cc or self.verbose_cc) try zig_args.append("--verbose-cc"); |
| 1516 | if (b.verbose_llvm_cpu_features) try zig_args.append("--verbose-llvm-cpu-features"); | 1548 | if (b.verbose_llvm_cpu_features) try zig_args.append("--verbose-llvm-cpu-features"); |
| 1517 | 1549 | ||
| 1518 | if (self.emit_asm.getArg(b, "emit-asm")) |arg| try zig_args.append(arg); | 1550 | if (self.generated_asm != null) try zig_args.append("-femit-asm"); |
| 1519 | if (self.emit_bin.getArg(b, "emit-bin")) |arg| try zig_args.append(arg); | 1551 | if (self.generated_bin == null) try zig_args.append("-fno-emit-bin"); |
| 1520 | if (self.generated_docs != null) try zig_args.append("-femit-docs"); | 1552 | if (self.generated_docs != null) try zig_args.append("-femit-docs"); |
| 1521 | if (self.emit_implib.getArg(b, "emit-implib")) |arg| try zig_args.append(arg); | 1553 | if (self.generated_implib != null) try zig_args.append("-femit-implib"); |
| 1522 | if (self.emit_llvm_bc.getArg(b, "emit-llvm-bc")) |arg| try zig_args.append(arg); | 1554 | if (self.generated_llvm_bc != null) try zig_args.append("-femit-llvm-bc"); |
| 1523 | if (self.emit_llvm_ir.getArg(b, "emit-llvm-ir")) |arg| try zig_args.append(arg); | 1555 | if (self.generated_llvm_ir != null) try zig_args.append("-femit-llvm-ir"); |
| 1524 | 1556 | if (self.generated_h != null) try zig_args.append("-femit-h"); | |
| 1525 | if (self.emit_h) try zig_args.append("-femit-h"); | ||
| 1526 | 1557 | ||
| 1527 | try addFlag(&zig_args, "strip", self.strip); | 1558 | try addFlag(&zig_args, "strip", self.strip); |
| 1528 | try addFlag(&zig_args, "unwind-tables", self.unwind_tables); | 1559 | try addFlag(&zig_args, "unwind-tables", self.unwind_tables); |
| ... | @@ -1746,18 +1777,18 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -1746,18 +1777,18 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1746 | 1777 | ||
| 1747 | for (self.include_dirs.items) |include_dir| { | 1778 | for (self.include_dirs.items) |include_dir| { |
| 1748 | switch (include_dir) { | 1779 | switch (include_dir) { |
| 1749 | .raw_path => |include_path| { | 1780 | .path => |include_path| { |
| 1750 | try zig_args.append("-I"); | 1781 | try zig_args.append("-I"); |
| 1751 | try zig_args.append(b.pathFromRoot(include_path)); | 1782 | try zig_args.append(include_path.getPath(b)); |
| 1752 | }, | 1783 | }, |
| 1753 | .raw_path_system => |include_path| { | 1784 | .path_system => |include_path| { |
| 1754 | if (b.sysroot != null) { | 1785 | if (b.sysroot != null) { |
| 1755 | try zig_args.append("-iwithsysroot"); | 1786 | try zig_args.append("-iwithsysroot"); |
| 1756 | } else { | 1787 | } else { |
| 1757 | try zig_args.append("-isystem"); | 1788 | try zig_args.append("-isystem"); |
| 1758 | } | 1789 | } |
| 1759 | 1790 | ||
| 1760 | const resolved_include_path = b.pathFromRoot(include_path); | 1791 | const resolved_include_path = include_path.getPath(b); |
| 1761 | 1792 | ||
| 1762 | const common_include_path = if (builtin.os.tag == .windows and b.sysroot != null and fs.path.isAbsolute(resolved_include_path)) blk: { | 1793 | const common_include_path = if (builtin.os.tag == .windows and b.sysroot != null and fs.path.isAbsolute(resolved_include_path)) blk: { |
| 1763 | // We need to check for disk designator and strip it out from dir path so | 1794 | // We need to check for disk designator and strip it out from dir path so |
| ... | @@ -1774,10 +1805,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -1774,10 +1805,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1774 | try zig_args.append(common_include_path); | 1805 | try zig_args.append(common_include_path); |
| 1775 | }, | 1806 | }, |
| 1776 | .other_step => |other| { | 1807 | .other_step => |other| { |
| 1777 | if (other.emit_h) { | 1808 | if (other.generated_h) |header| { |
| 1778 | const h_path = other.getOutputHSource().getPath(b); | ||
| 1779 | try zig_args.append("-isystem"); | 1809 | try zig_args.append("-isystem"); |
| 1780 | try zig_args.append(fs.path.dirname(h_path).?); | 1810 | try zig_args.append(fs.path.dirname(header.path.?).?); |
| 1781 | } | 1811 | } |
| 1782 | if (other.installed_headers.items.len > 0) { | 1812 | if (other.installed_headers.items.len > 0) { |
| 1783 | try zig_args.append("-I"); | 1813 | try zig_args.append("-I"); |
| ... | @@ -1810,7 +1840,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -1810,7 +1840,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1810 | zig_args.appendAssumeCapacity("-rpath"); | 1840 | zig_args.appendAssumeCapacity("-rpath"); |
| 1811 | 1841 | ||
| 1812 | if (self.target_info.target.isDarwin()) switch (rpath) { | 1842 | if (self.target_info.target.isDarwin()) switch (rpath) { |
| 1813 | .path => |path| { | 1843 | .path, .cwd_relative => |path| { |
| 1814 | // On Darwin, we should not try to expand special runtime paths such as | 1844 | // On Darwin, we should not try to expand special runtime paths such as |
| 1815 | // * @executable_path | 1845 | // * @executable_path |
| 1816 | // * @loader_path | 1846 | // * @loader_path |
| ... | @@ -1907,15 +1937,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -1907,15 +1937,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1907 | 1937 | ||
| 1908 | if (self.zig_lib_dir) |dir| { | 1938 | if (self.zig_lib_dir) |dir| { |
| 1909 | try zig_args.append("--zig-lib-dir"); | 1939 | try zig_args.append("--zig-lib-dir"); |
| 1910 | try zig_args.append(b.pathFromRoot(dir)); | 1940 | try zig_args.append(dir.getPath(b)); |
| 1911 | } else if (b.zig_lib_dir) |dir| { | ||
| 1912 | try zig_args.append("--zig-lib-dir"); | ||
| 1913 | try zig_args.append(dir); | ||
| 1914 | } | 1941 | } |
| 1915 | 1942 | ||
| 1916 | if (self.main_pkg_path) |dir| { | 1943 | if (self.main_pkg_path) |dir| { |
| 1917 | try zig_args.append("--main-pkg-path"); | 1944 | try zig_args.append("--main-pkg-path"); |
| 1918 | try zig_args.append(b.pathFromRoot(dir)); | 1945 | try zig_args.append(dir.getPath(b)); |
| 1919 | } | 1946 | } |
| 1920 | 1947 | ||
| 1921 | try addFlag(&zig_args, "PIC", self.force_pic); | 1948 | try addFlag(&zig_args, "PIC", self.force_pic); |
| ... | @@ -2008,33 +2035,51 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -2008,33 +2035,51 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 2008 | if (maybe_output_bin_path) |output_bin_path| { | 2035 | if (maybe_output_bin_path) |output_bin_path| { |
| 2009 | const output_dir = fs.path.dirname(output_bin_path).?; | 2036 | const output_dir = fs.path.dirname(output_bin_path).?; |
| 2010 | 2037 | ||
| 2011 | self.output_dirname_source.path = output_dir; | 2038 | if (self.emit_directory) |lp| { |
| 2039 | lp.path = output_dir; | ||
| 2040 | } | ||
| 2012 | 2041 | ||
| 2013 | self.output_path_source.path = b.pathJoin( | 2042 | // -femit-bin[=path] (default) Output machine code |
| 2014 | &.{ output_dir, self.out_filename }, | 2043 | if (self.generated_bin) |bin| { |
| 2015 | ); | 2044 | bin.path = b.pathJoin(&.{ output_dir, self.out_filename }); |
| 2045 | } | ||
| 2046 | |||
| 2047 | const sep = std.fs.path.sep; | ||
| 2016 | 2048 | ||
| 2017 | if (self.kind == .lib) { | 2049 | // output PDB if someone requested it |
| 2018 | self.output_lib_path_source.path = b.pathJoin( | 2050 | if (self.generated_pdb) |pdb| { |
| 2019 | &.{ output_dir, self.out_lib_filename }, | 2051 | pdb.path = b.fmt("{s}{c}{s}.pdb", .{ output_dir, sep, self.name }); |
| 2020 | ); | ||
| 2021 | } | 2052 | } |
| 2022 | 2053 | ||
| 2023 | if (self.emit_h) { | 2054 | // -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL |
| 2024 | self.output_h_path_source.path = b.pathJoin( | 2055 | if (self.generated_implib) |implib| { |
| 2025 | &.{ output_dir, self.out_h_filename }, | 2056 | implib.path = b.fmt("{s}{c}{s}.lib", .{ output_dir, sep, self.name }); |
| 2026 | ); | ||
| 2027 | } | 2057 | } |
| 2028 | 2058 | ||
| 2029 | if (self.target.isWindows() or self.target.isUefi()) { | 2059 | // -femit-h[=path] Generate a C header file (.h) |
| 2030 | self.output_pdb_path_source.path = b.pathJoin( | 2060 | if (self.generated_h) |lp| { |
| 2031 | &.{ output_dir, self.out_pdb_filename }, | 2061 | lp.path = b.fmt("{s}{c}{s}.h", .{ output_dir, sep, self.name }); |
| 2032 | ); | ||
| 2033 | } | 2062 | } |
| 2034 | 2063 | ||
| 2064 | // -femit-docs[=path] Create a docs/ dir with html documentation | ||
| 2035 | if (self.generated_docs) |generated_docs| { | 2065 | if (self.generated_docs) |generated_docs| { |
| 2036 | generated_docs.path = b.pathJoin(&.{ output_dir, "docs" }); | 2066 | generated_docs.path = b.pathJoin(&.{ output_dir, "docs" }); |
| 2037 | } | 2067 | } |
| 2068 | |||
| 2069 | // -femit-asm[=path] Output .s (assembly code) | ||
| 2070 | if (self.generated_asm) |lp| { | ||
| 2071 | lp.path = b.fmt("{s}{c}{s}.s", .{ output_dir, sep, self.name }); | ||
| 2072 | } | ||
| 2073 | |||
| 2074 | // -femit-llvm-ir[=path] Produce a .ll file with optimized LLVM IR (requires LLVM extensions) | ||
| 2075 | if (self.generated_llvm_ir) |lp| { | ||
| 2076 | lp.path = b.fmt("{s}{c}{s}.ll", .{ output_dir, sep, self.name }); | ||
| 2077 | } | ||
| 2078 | |||
| 2079 | // -femit-llvm-bc[=path] Produce an optimized LLVM module as a .bc file (requires LLVM extensions) | ||
| 2080 | if (self.generated_llvm_bc) |lp| { | ||
| 2081 | lp.path = b.fmt("{s}{c}{s}.bc", .{ output_dir, sep, self.name }); | ||
| 2082 | } | ||
| 2038 | } | 2083 | } |
| 2039 | 2084 | ||
| 2040 | if (self.kind == .lib and self.linkage != null and self.linkage.? == .dynamic and | 2085 | if (self.kind == .lib and self.linkage != null and self.linkage.? == .dynamic and |
| ... | @@ -2042,7 +2087,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -2042,7 +2087,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 2042 | { | 2087 | { |
| 2043 | try doAtomicSymLinks( | 2088 | try doAtomicSymLinks( |
| 2044 | step, | 2089 | step, |
| 2045 | self.getOutputSource().getPath(b), | 2090 | self.getEmittedBin().getPath(b), |
| 2046 | self.major_only_filename.?, | 2091 | self.major_only_filename.?, |
| 2047 | self.name_only_filename.?, | 2092 | self.name_only_filename.?, |
| 2048 | ); | 2093 | ); |
lib/std/Build/Step/ConfigHeader.zig+12-6| ... | @@ -6,16 +6,19 @@ const Allocator = std.mem.Allocator; | ... | @@ -6,16 +6,19 @@ const Allocator = std.mem.Allocator; |
| 6 | pub const Style = union(enum) { | 6 | pub const Style = union(enum) { |
| 7 | /// The configure format supported by autotools. It uses `#undef foo` to | 7 | /// The configure format supported by autotools. It uses `#undef foo` to |
| 8 | /// mark lines that can be substituted with different values. | 8 | /// mark lines that can be substituted with different values. |
| 9 | autoconf: std.Build.FileSource, | 9 | autoconf: std.Build.LazyPath, |
| 10 | /// The configure format supported by CMake. It uses `@@FOO@@` and | 10 | /// The configure format supported by CMake. It uses `@@FOO@@` and |
| 11 | /// `#cmakedefine` for template substitution. | 11 | /// `#cmakedefine` for template substitution. |
| 12 | cmake: std.Build.FileSource, | 12 | cmake: std.Build.LazyPath, |
| 13 | /// Instead of starting with an input file, start with nothing. | 13 | /// Instead of starting with an input file, start with nothing. |
| 14 | blank, | 14 | blank, |
| 15 | /// Start with nothing, like blank, and output a nasm .asm file. | 15 | /// Start with nothing, like blank, and output a nasm .asm file. |
| 16 | nasm, | 16 | nasm, |
| 17 | 17 | ||
| 18 | pub fn getFileSource(style: Style) ?std.Build.FileSource { | 18 | /// deprecated: use `getPath` |
| 19 | pub const getFileSource = getPath; | ||
| 20 | |||
| 21 | pub fn getPath(style: Style) ?std.Build.LazyPath { | ||
| 19 | switch (style) { | 22 | switch (style) { |
| 20 | .autoconf, .cmake => |s| return s, | 23 | .autoconf, .cmake => |s| return s, |
| 21 | .blank, .nasm => return null, | 24 | .blank, .nasm => return null, |
| ... | @@ -54,7 +57,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { | ... | @@ -54,7 +57,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { |
| 54 | 57 | ||
| 55 | var include_path: []const u8 = "config.h"; | 58 | var include_path: []const u8 = "config.h"; |
| 56 | 59 | ||
| 57 | if (options.style.getFileSource()) |s| switch (s) { | 60 | if (options.style.getPath()) |s| switch (s) { |
| 58 | .path => |p| { | 61 | .path => |p| { |
| 59 | const basename = std.fs.path.basename(p); | 62 | const basename = std.fs.path.basename(p); |
| 60 | if (std.mem.endsWith(u8, basename, ".h.in")) { | 63 | if (std.mem.endsWith(u8, basename, ".h.in")) { |
| ... | @@ -68,7 +71,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { | ... | @@ -68,7 +71,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { |
| 68 | include_path = p; | 71 | include_path = p; |
| 69 | } | 72 | } |
| 70 | 73 | ||
| 71 | const name = if (options.style.getFileSource()) |s| | 74 | const name = if (options.style.getPath()) |s| |
| 72 | owner.fmt("configure {s} header {s} to {s}", .{ | 75 | owner.fmt("configure {s} header {s} to {s}", .{ |
| 73 | @tagName(options.style), s.getDisplayName(), include_path, | 76 | @tagName(options.style), s.getDisplayName(), include_path, |
| 74 | }) | 77 | }) |
| ... | @@ -98,7 +101,10 @@ pub fn addValues(self: *ConfigHeader, values: anytype) void { | ... | @@ -98,7 +101,10 @@ pub fn addValues(self: *ConfigHeader, values: anytype) void { |
| 98 | return addValuesInner(self, values) catch @panic("OOM"); | 101 | return addValuesInner(self, values) catch @panic("OOM"); |
| 99 | } | 102 | } |
| 100 | 103 | ||
| 101 | pub fn getFileSource(self: *ConfigHeader) std.Build.FileSource { | 104 | /// deprecated: use `getOutput` |
| 105 | pub const getFileSource = getOutput; | ||
| 106 | |||
| 107 | pub fn getOutput(self: *ConfigHeader) std.Build.LazyPath { | ||
| 102 | return .{ .generated = &self.output_file }; | 108 | return .{ .generated = &self.output_file }; |
| 103 | } | 109 | } |
| 104 | 110 |
lib/std/Build/Step/InstallArtifact.zig+115-63| ... | @@ -3,100 +3,150 @@ const Step = std.Build.Step; | ... | @@ -3,100 +3,150 @@ const Step = std.Build.Step; |
| 3 | const InstallDir = std.Build.InstallDir; | 3 | const InstallDir = std.Build.InstallDir; |
| 4 | const InstallArtifact = @This(); | 4 | const InstallArtifact = @This(); |
| 5 | const fs = std.fs; | 5 | const fs = std.fs; |
| 6 | 6 | const LazyPath = std.Build.LazyPath; | |
| 7 | pub const base_id = .install_artifact; | ||
| 8 | 7 | ||
| 9 | step: Step, | 8 | step: Step, |
| 10 | artifact: *Step.Compile, | 9 | |
| 11 | dest_dir: InstallDir, | 10 | dest_dir: ?InstallDir, |
| 11 | dest_sub_path: []const u8, | ||
| 12 | emitted_bin: ?LazyPath, | ||
| 13 | |||
| 14 | implib_dir: ?InstallDir, | ||
| 15 | emitted_implib: ?LazyPath, | ||
| 16 | |||
| 12 | pdb_dir: ?InstallDir, | 17 | pdb_dir: ?InstallDir, |
| 18 | emitted_pdb: ?LazyPath, | ||
| 19 | |||
| 13 | h_dir: ?InstallDir, | 20 | h_dir: ?InstallDir, |
| 14 | /// If non-null, adds additional path components relative to dest_dir, and | 21 | emitted_h: ?LazyPath, |
| 15 | /// overrides the basename of the Compile step. | 22 | |
| 16 | dest_sub_path: ?[]const u8, | 23 | dylib_symlinks: ?DylibSymlinkInfo, |
| 24 | |||
| 25 | artifact: *Step.Compile, | ||
| 26 | |||
| 27 | const DylibSymlinkInfo = struct { | ||
| 28 | major_only_filename: []const u8, | ||
| 29 | name_only_filename: []const u8, | ||
| 30 | }; | ||
| 31 | |||
| 32 | pub const base_id = .install_artifact; | ||
| 17 | 33 | ||
| 18 | pub fn create(owner: *std.Build, artifact: *Step.Compile) *InstallArtifact { | 34 | pub const Options = struct { |
| 35 | /// Which installation directory to put the main output file into. | ||
| 36 | dest_dir: Dir = .default, | ||
| 37 | pdb_dir: Dir = .default, | ||
| 38 | h_dir: Dir = .default, | ||
| 39 | implib_dir: Dir = .default, | ||
| 40 | |||
| 41 | /// Whether to install symlinks along with dynamic libraries. | ||
| 42 | dylib_symlinks: ?bool = null, | ||
| 43 | /// If non-null, adds additional path components relative to bin dir, and | ||
| 44 | /// overrides the basename of the Compile step for installation purposes. | ||
| 45 | dest_sub_path: ?[]const u8 = null, | ||
| 46 | |||
| 47 | pub const Dir = union(enum) { | ||
| 48 | disabled, | ||
| 49 | default, | ||
| 50 | override: InstallDir, | ||
| 51 | }; | ||
| 52 | }; | ||
| 53 | |||
| 54 | pub fn create(owner: *std.Build, artifact: *Step.Compile, options: Options) *InstallArtifact { | ||
| 19 | const self = owner.allocator.create(InstallArtifact) catch @panic("OOM"); | 55 | const self = owner.allocator.create(InstallArtifact) catch @panic("OOM"); |
| 20 | self.* = InstallArtifact{ | 56 | const dest_dir: ?InstallDir = switch (options.dest_dir) { |
| 57 | .disabled => null, | ||
| 58 | .default => switch (artifact.kind) { | ||
| 59 | .obj => @panic("object files have no standard installation procedure"), | ||
| 60 | .exe, .@"test" => InstallDir{ .bin = {} }, | ||
| 61 | .lib => InstallDir{ .lib = {} }, | ||
| 62 | }, | ||
| 63 | .override => |o| o, | ||
| 64 | }; | ||
| 65 | self.* = .{ | ||
| 21 | .step = Step.init(.{ | 66 | .step = Step.init(.{ |
| 22 | .id = base_id, | 67 | .id = base_id, |
| 23 | .name = owner.fmt("install {s}", .{artifact.name}), | 68 | .name = owner.fmt("install {s}", .{artifact.name}), |
| 24 | .owner = owner, | 69 | .owner = owner, |
| 25 | .makeFn = make, | 70 | .makeFn = make, |
| 26 | }), | 71 | }), |
| 27 | .artifact = artifact, | 72 | .dest_dir = dest_dir, |
| 28 | .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) { | 73 | .pdb_dir = switch (options.pdb_dir) { |
| 29 | .obj => @panic("Cannot install a .obj build artifact."), | 74 | .disabled => null, |
| 30 | .exe, .@"test" => InstallDir{ .bin = {} }, | 75 | .default => if (artifact.producesPdbFile()) dest_dir else null, |
| 31 | .lib => InstallDir{ .lib = {} }, | 76 | .override => |o| o, |
| 77 | }, | ||
| 78 | .h_dir = switch (options.h_dir) { | ||
| 79 | .disabled => null, | ||
| 80 | // https://github.com/ziglang/zig/issues/9698 | ||
| 81 | .default => null, | ||
| 82 | //.default => switch (artifact.kind) { | ||
| 83 | // .lib => .header, | ||
| 84 | // else => null, | ||
| 85 | //}, | ||
| 86 | .override => |o| o, | ||
| 32 | }, | 87 | }, |
| 33 | .pdb_dir = if (artifact.producesPdbFile()) blk: { | 88 | .implib_dir = switch (options.implib_dir) { |
| 34 | if (artifact.kind == .exe or artifact.kind == .@"test") { | 89 | .disabled => null, |
| 35 | break :blk InstallDir{ .bin = {} }; | 90 | .default => if (artifact.producesImplib()) dest_dir else null, |
| 36 | } else { | 91 | .override => |o| o, |
| 37 | break :blk InstallDir{ .lib = {} }; | 92 | }, |
| 38 | } | 93 | |
| 94 | .dylib_symlinks = if (options.dylib_symlinks orelse (dest_dir != null and | ||
| 95 | artifact.isDynamicLibrary() and | ||
| 96 | artifact.version != null and | ||
| 97 | artifact.target.wantSharedLibSymLinks())) .{ | ||
| 98 | .major_only_filename = artifact.major_only_filename.?, | ||
| 99 | .name_only_filename = artifact.name_only_filename.?, | ||
| 39 | } else null, | 100 | } else null, |
| 40 | .h_dir = if (artifact.kind == .lib and artifact.emit_h) .header else null, | 101 | |
| 41 | .dest_sub_path = null, | 102 | .dest_sub_path = options.dest_sub_path orelse artifact.out_filename, |
| 103 | |||
| 104 | .emitted_bin = null, | ||
| 105 | .emitted_pdb = null, | ||
| 106 | .emitted_h = null, | ||
| 107 | .emitted_implib = null, | ||
| 108 | |||
| 109 | .artifact = artifact, | ||
| 42 | }; | 110 | }; |
| 111 | |||
| 43 | self.step.dependOn(&artifact.step); | 112 | self.step.dependOn(&artifact.step); |
| 44 | 113 | ||
| 45 | owner.pushInstalledFile(self.dest_dir, artifact.out_filename); | 114 | if (self.dest_dir != null) self.emitted_bin = artifact.getEmittedBin(); |
| 46 | if (self.artifact.isDynamicLibrary()) { | 115 | if (self.pdb_dir != null) self.emitted_pdb = artifact.getEmittedPdb(); |
| 47 | if (artifact.major_only_filename) |name| { | 116 | if (self.h_dir != null) self.emitted_h = artifact.getEmittedH(); |
| 48 | owner.pushInstalledFile(.lib, name); | 117 | if (self.implib_dir != null) self.emitted_implib = artifact.getEmittedImplib(); |
| 49 | } | 118 | |
| 50 | if (artifact.name_only_filename) |name| { | ||
| 51 | owner.pushInstalledFile(.lib, name); | ||
| 52 | } | ||
| 53 | if (self.artifact.target.isWindows()) { | ||
| 54 | owner.pushInstalledFile(.lib, artifact.out_lib_filename); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | if (self.pdb_dir) |pdb_dir| { | ||
| 58 | owner.pushInstalledFile(pdb_dir, artifact.out_pdb_filename); | ||
| 59 | } | ||
| 60 | if (self.h_dir) |h_dir| { | ||
| 61 | owner.pushInstalledFile(h_dir, artifact.out_h_filename); | ||
| 62 | } | ||
| 63 | return self; | 119 | return self; |
| 64 | } | 120 | } |
| 65 | 121 | ||
| 66 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 122 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 67 | _ = prog_node; | 123 | _ = prog_node; |
| 68 | const self = @fieldParentPtr(InstallArtifact, "step", step); | 124 | const self = @fieldParentPtr(InstallArtifact, "step", step); |
| 69 | const src_builder = self.artifact.step.owner; | ||
| 70 | const dest_builder = step.owner; | 125 | const dest_builder = step.owner; |
| 71 | |||
| 72 | const dest_sub_path = if (self.dest_sub_path) |sub_path| sub_path else self.artifact.out_filename; | ||
| 73 | const full_dest_path = dest_builder.getInstallPath(self.dest_dir, dest_sub_path); | ||
| 74 | const cwd = fs.cwd(); | 126 | const cwd = fs.cwd(); |
| 75 | 127 | ||
| 76 | var all_cached = true; | 128 | var all_cached = true; |
| 77 | 129 | ||
| 78 | { | 130 | if (self.dest_dir) |dest_dir| { |
| 79 | const full_src_path = self.artifact.getOutputSource().getPath(src_builder); | 131 | const full_dest_path = dest_builder.getInstallPath(dest_dir, self.dest_sub_path); |
| 132 | const full_src_path = self.emitted_bin.?.getPath2(step.owner, step); | ||
| 80 | const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_dest_path, .{}) catch |err| { | 133 | const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_dest_path, .{}) catch |err| { |
| 81 | return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ | 134 | return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ |
| 82 | full_src_path, full_dest_path, @errorName(err), | 135 | full_src_path, full_dest_path, @errorName(err), |
| 83 | }); | 136 | }); |
| 84 | }; | 137 | }; |
| 85 | all_cached = all_cached and p == .fresh; | 138 | all_cached = all_cached and p == .fresh; |
| 86 | } | ||
| 87 | 139 | ||
| 88 | if (self.artifact.isDynamicLibrary() and | 140 | if (self.dylib_symlinks) |dls| { |
| 89 | self.artifact.version != null and | 141 | try Step.Compile.doAtomicSymLinks(step, full_dest_path, dls.major_only_filename, dls.name_only_filename); |
| 90 | self.artifact.target.wantSharedLibSymLinks()) | 142 | } |
| 91 | { | 143 | |
| 92 | try Step.Compile.doAtomicSymLinks(step, full_dest_path, self.artifact.major_only_filename.?, self.artifact.name_only_filename.?); | 144 | self.artifact.installed_path = full_dest_path; |
| 93 | } | 145 | } |
| 94 | if (self.artifact.isDynamicLibrary() and | 146 | |
| 95 | self.artifact.target.isWindows() and | 147 | if (self.implib_dir) |implib_dir| { |
| 96 | self.artifact.emit_implib != .no_emit) | 148 | const full_src_path = self.emitted_implib.?.getPath2(step.owner, step); |
| 97 | { | 149 | const full_implib_path = dest_builder.getInstallPath(implib_dir, fs.path.basename(full_src_path)); |
| 98 | const full_src_path = self.artifact.getOutputLibSource().getPath(src_builder); | ||
| 99 | const full_implib_path = dest_builder.getInstallPath(self.dest_dir, self.artifact.out_lib_filename); | ||
| 100 | const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_implib_path, .{}) catch |err| { | 150 | const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_implib_path, .{}) catch |err| { |
| 101 | return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ | 151 | return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ |
| 102 | full_src_path, full_implib_path, @errorName(err), | 152 | full_src_path, full_implib_path, @errorName(err), |
| ... | @@ -104,9 +154,10 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -104,9 +154,10 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 104 | }; | 154 | }; |
| 105 | all_cached = all_cached and p == .fresh; | 155 | all_cached = all_cached and p == .fresh; |
| 106 | } | 156 | } |
| 157 | |||
| 107 | if (self.pdb_dir) |pdb_dir| { | 158 | if (self.pdb_dir) |pdb_dir| { |
| 108 | const full_src_path = self.artifact.getOutputPdbSource().getPath(src_builder); | 159 | const full_src_path = self.emitted_pdb.?.getPath2(step.owner, step); |
| 109 | const full_pdb_path = dest_builder.getInstallPath(pdb_dir, self.artifact.out_pdb_filename); | 160 | const full_pdb_path = dest_builder.getInstallPath(pdb_dir, fs.path.basename(full_src_path)); |
| 110 | const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_pdb_path, .{}) catch |err| { | 161 | const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_pdb_path, .{}) catch |err| { |
| 111 | return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ | 162 | return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ |
| 112 | full_src_path, full_pdb_path, @errorName(err), | 163 | full_src_path, full_pdb_path, @errorName(err), |
| ... | @@ -114,9 +165,10 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -114,9 +165,10 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 114 | }; | 165 | }; |
| 115 | all_cached = all_cached and p == .fresh; | 166 | all_cached = all_cached and p == .fresh; |
| 116 | } | 167 | } |
| 168 | |||
| 117 | if (self.h_dir) |h_dir| { | 169 | if (self.h_dir) |h_dir| { |
| 118 | const full_src_path = self.artifact.getOutputHSource().getPath(src_builder); | 170 | const full_src_path = self.emitted_h.?.getPath2(step.owner, step); |
| 119 | const full_h_path = dest_builder.getInstallPath(h_dir, self.artifact.out_h_filename); | 171 | const full_h_path = dest_builder.getInstallPath(h_dir, fs.path.basename(full_src_path)); |
| 120 | const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_h_path, .{}) catch |err| { | 172 | const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_h_path, .{}) catch |err| { |
| 121 | return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ | 173 | return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ |
| 122 | full_src_path, full_h_path, @errorName(err), | 174 | full_src_path, full_h_path, @errorName(err), |
| ... | @@ -124,6 +176,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -124,6 +176,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 124 | }; | 176 | }; |
| 125 | all_cached = all_cached and p == .fresh; | 177 | all_cached = all_cached and p == .fresh; |
| 126 | } | 178 | } |
| 127 | self.artifact.installed_path = full_dest_path; | 179 | |
| 128 | step.result_cached = all_cached; | 180 | step.result_cached = all_cached; |
| 129 | } | 181 | } |
lib/std/Build/Step/InstallDir.zig+2-2| ... | @@ -2,7 +2,7 @@ const std = @import("std"); | ... | @@ -2,7 +2,7 @@ const std = @import("std"); |
| 2 | const mem = std.mem; | 2 | const mem = std.mem; |
| 3 | const fs = std.fs; | 3 | const fs = std.fs; |
| 4 | const Step = std.Build.Step; | 4 | const Step = std.Build.Step; |
| 5 | const FileSource = std.Build.FileSource; | 5 | const LazyPath = std.Build.LazyPath; |
| 6 | const InstallDir = std.Build.InstallDir; | 6 | const InstallDir = std.Build.InstallDir; |
| 7 | const InstallDirStep = @This(); | 7 | const InstallDirStep = @This(); |
| 8 | 8 | ||
| ... | @@ -15,7 +15,7 @@ dest_builder: *std.Build, | ... | @@ -15,7 +15,7 @@ dest_builder: *std.Build, |
| 15 | pub const base_id = .install_dir; | 15 | pub const base_id = .install_dir; |
| 16 | 16 | ||
| 17 | pub const Options = struct { | 17 | pub const Options = struct { |
| 18 | source_dir: FileSource, | 18 | source_dir: LazyPath, |
| 19 | install_dir: InstallDir, | 19 | install_dir: InstallDir, |
| 20 | install_subdir: []const u8, | 20 | install_subdir: []const u8, |
| 21 | /// File paths which end in any of these suffixes will be excluded | 21 | /// File paths which end in any of these suffixes will be excluded |
lib/std/Build/Step/InstallFile.zig+3-3| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const Step = std.Build.Step; | 2 | const Step = std.Build.Step; |
| 3 | const FileSource = std.Build.FileSource; | 3 | const LazyPath = std.Build.LazyPath; |
| 4 | const InstallDir = std.Build.InstallDir; | 4 | const InstallDir = std.Build.InstallDir; |
| 5 | const InstallFile = @This(); | 5 | const InstallFile = @This(); |
| 6 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| ... | @@ -8,7 +8,7 @@ const assert = std.debug.assert; | ... | @@ -8,7 +8,7 @@ const assert = std.debug.assert; |
| 8 | pub const base_id = .install_file; | 8 | pub const base_id = .install_file; |
| 9 | 9 | ||
| 10 | step: Step, | 10 | step: Step, |
| 11 | source: FileSource, | 11 | source: LazyPath, |
| 12 | dir: InstallDir, | 12 | dir: InstallDir, |
| 13 | dest_rel_path: []const u8, | 13 | dest_rel_path: []const u8, |
| 14 | /// This is used by the build system when a file being installed comes from one | 14 | /// This is used by the build system when a file being installed comes from one |
| ... | @@ -17,7 +17,7 @@ dest_builder: *std.Build, | ... | @@ -17,7 +17,7 @@ dest_builder: *std.Build, |
| 17 | 17 | ||
| 18 | pub fn create( | 18 | pub fn create( |
| 19 | owner: *std.Build, | 19 | owner: *std.Build, |
| 20 | source: FileSource, | 20 | source: LazyPath, |
| 21 | dir: InstallDir, | 21 | dir: InstallDir, |
| 22 | dest_rel_path: []const u8, | 22 | dest_rel_path: []const u8, |
| 23 | ) *InstallFile { | 23 | ) *InstallFile { |
lib/std/Build/Step/ObjCopy.zig+11-8| ... | @@ -20,7 +20,7 @@ pub const RawFormat = enum { | ... | @@ -20,7 +20,7 @@ pub const RawFormat = enum { |
| 20 | }; | 20 | }; |
| 21 | 21 | ||
| 22 | step: Step, | 22 | step: Step, |
| 23 | file_source: std.Build.FileSource, | 23 | input_file: std.Build.LazyPath, |
| 24 | basename: []const u8, | 24 | basename: []const u8, |
| 25 | output_file: std.Build.GeneratedFile, | 25 | output_file: std.Build.GeneratedFile, |
| 26 | 26 | ||
| ... | @@ -37,30 +37,33 @@ pub const Options = struct { | ... | @@ -37,30 +37,33 @@ pub const Options = struct { |
| 37 | 37 | ||
| 38 | pub fn create( | 38 | pub fn create( |
| 39 | owner: *std.Build, | 39 | owner: *std.Build, |
| 40 | file_source: std.Build.FileSource, | 40 | input_file: std.Build.LazyPath, |
| 41 | options: Options, | 41 | options: Options, |
| 42 | ) *ObjCopy { | 42 | ) *ObjCopy { |
| 43 | const self = owner.allocator.create(ObjCopy) catch @panic("OOM"); | 43 | const self = owner.allocator.create(ObjCopy) catch @panic("OOM"); |
| 44 | self.* = ObjCopy{ | 44 | self.* = ObjCopy{ |
| 45 | .step = Step.init(.{ | 45 | .step = Step.init(.{ |
| 46 | .id = base_id, | 46 | .id = base_id, |
| 47 | .name = owner.fmt("objcopy {s}", .{file_source.getDisplayName()}), | 47 | .name = owner.fmt("objcopy {s}", .{input_file.getDisplayName()}), |
| 48 | .owner = owner, | 48 | .owner = owner, |
| 49 | .makeFn = make, | 49 | .makeFn = make, |
| 50 | }), | 50 | }), |
| 51 | .file_source = file_source, | 51 | .input_file = input_file, |
| 52 | .basename = options.basename orelse file_source.getDisplayName(), | 52 | .basename = options.basename orelse input_file.getDisplayName(), |
| 53 | .output_file = std.Build.GeneratedFile{ .step = &self.step }, | 53 | .output_file = std.Build.GeneratedFile{ .step = &self.step }, |
| 54 | 54 | ||
| 55 | .format = options.format, | 55 | .format = options.format, |
| 56 | .only_section = options.only_section, | 56 | .only_section = options.only_section, |
| 57 | .pad_to = options.pad_to, | 57 | .pad_to = options.pad_to, |
| 58 | }; | 58 | }; |
| 59 | file_source.addStepDependencies(&self.step); | 59 | input_file.addStepDependencies(&self.step); |
| 60 | return self; | 60 | return self; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | pub fn getOutputSource(self: *const ObjCopy) std.Build.FileSource { | 63 | /// deprecated: use getOutput |
| 64 | pub const getOutputSource = getOutput; | ||
| 65 | |||
| 66 | pub fn getOutput(self: *const ObjCopy) std.Build.LazyPath { | ||
| 64 | return .{ .generated = &self.output_file }; | 67 | return .{ .generated = &self.output_file }; |
| 65 | } | 68 | } |
| 66 | 69 | ||
| ... | @@ -75,7 +78,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -75,7 +78,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 75 | // bytes when ObjCopy implementation is modified incompatibly. | 78 | // bytes when ObjCopy implementation is modified incompatibly. |
| 76 | man.hash.add(@as(u32, 0xe18b7baf)); | 79 | man.hash.add(@as(u32, 0xe18b7baf)); |
| 77 | 80 | ||
| 78 | const full_src_path = self.file_source.getPath(b); | 81 | const full_src_path = self.input_file.getPath(b); |
| 79 | _ = try man.addFile(full_src_path, null); | 82 | _ = try man.addFile(full_src_path, null); |
| 80 | man.hash.addOptionalBytes(self.only_section); | 83 | man.hash.addOptionalBytes(self.only_section); |
| 81 | man.hash.addOptional(self.pad_to); | 84 | man.hash.addOptional(self.pad_to); |
lib/std/Build/Step/Options.zig+24-35| ... | @@ -3,7 +3,7 @@ const builtin = @import("builtin"); | ... | @@ -3,7 +3,7 @@ const builtin = @import("builtin"); |
| 3 | const fs = std.fs; | 3 | const fs = std.fs; |
| 4 | const Step = std.Build.Step; | 4 | const Step = std.Build.Step; |
| 5 | const GeneratedFile = std.Build.GeneratedFile; | 5 | const GeneratedFile = std.Build.GeneratedFile; |
| 6 | const FileSource = std.Build.FileSource; | 6 | const LazyPath = std.Build.LazyPath; |
| 7 | 7 | ||
| 8 | const Options = @This(); | 8 | const Options = @This(); |
| 9 | 9 | ||
| ... | @@ -13,8 +13,7 @@ step: Step, | ... | @@ -13,8 +13,7 @@ step: Step, |
| 13 | generated_file: GeneratedFile, | 13 | generated_file: GeneratedFile, |
| 14 | 14 | ||
| 15 | contents: std.ArrayList(u8), | 15 | contents: std.ArrayList(u8), |
| 16 | artifact_args: std.ArrayList(OptionArtifactArg), | 16 | args: std.ArrayList(Arg), |
| 17 | file_source_args: std.ArrayList(OptionFileSourceArg), | ||
| 18 | 17 | ||
| 19 | pub fn create(owner: *std.Build) *Options { | 18 | pub fn create(owner: *std.Build) *Options { |
| 20 | const self = owner.allocator.create(Options) catch @panic("OOM"); | 19 | const self = owner.allocator.create(Options) catch @panic("OOM"); |
| ... | @@ -27,8 +26,7 @@ pub fn create(owner: *std.Build) *Options { | ... | @@ -27,8 +26,7 @@ pub fn create(owner: *std.Build) *Options { |
| 27 | }), | 26 | }), |
| 28 | .generated_file = undefined, | 27 | .generated_file = undefined, |
| 29 | .contents = std.ArrayList(u8).init(owner.allocator), | 28 | .contents = std.ArrayList(u8).init(owner.allocator), |
| 30 | .artifact_args = std.ArrayList(OptionArtifactArg).init(owner.allocator), | 29 | .args = std.ArrayList(Arg).init(owner.allocator), |
| 31 | .file_source_args = std.ArrayList(OptionFileSourceArg).init(owner.allocator), | ||
| 32 | }; | 30 | }; |
| 33 | self.generated_file = .{ .step = &self.step }; | 31 | self.generated_file = .{ .step = &self.step }; |
| 34 | 32 | ||
| ... | @@ -168,35 +166,39 @@ fn printLiteral(out: anytype, val: anytype, indent: u8) !void { | ... | @@ -168,35 +166,39 @@ fn printLiteral(out: anytype, val: anytype, indent: u8) !void { |
| 168 | } | 166 | } |
| 169 | } | 167 | } |
| 170 | 168 | ||
| 169 | /// deprecated: use `addOptionPath` | ||
| 170 | pub const addOptionFileSource = addOptionPath; | ||
| 171 | |||
| 171 | /// The value is the path in the cache dir. | 172 | /// The value is the path in the cache dir. |
| 172 | /// Adds a dependency automatically. | 173 | /// Adds a dependency automatically. |
| 173 | pub fn addOptionFileSource( | 174 | pub fn addOptionPath( |
| 174 | self: *Options, | 175 | self: *Options, |
| 175 | name: []const u8, | 176 | name: []const u8, |
| 176 | source: FileSource, | 177 | path: LazyPath, |
| 177 | ) void { | 178 | ) void { |
| 178 | self.file_source_args.append(.{ | 179 | self.args.append(.{ |
| 179 | .name = name, | 180 | .name = self.step.owner.dupe(name), |
| 180 | .source = source.dupe(self.step.owner), | 181 | .path = path.dupe(self.step.owner), |
| 181 | }) catch @panic("OOM"); | 182 | }) catch @panic("OOM"); |
| 182 | source.addStepDependencies(&self.step); | 183 | path.addStepDependencies(&self.step); |
| 183 | } | 184 | } |
| 184 | 185 | ||
| 185 | /// The value is the path in the cache dir. | 186 | /// Deprecated: use `addOptionPath(options, name, artifact.getEmittedBin())` instead. |
| 186 | /// Adds a dependency automatically. | ||
| 187 | pub fn addOptionArtifact(self: *Options, name: []const u8, artifact: *Step.Compile) void { | 187 | pub fn addOptionArtifact(self: *Options, name: []const u8, artifact: *Step.Compile) void { |
| 188 | self.artifact_args.append(.{ .name = self.step.owner.dupe(name), .artifact = artifact }) catch @panic("OOM"); | 188 | return addOptionPath(self, name, artifact.getEmittedBin()); |
| 189 | self.step.dependOn(&artifact.step); | ||
| 190 | } | 189 | } |
| 191 | 190 | ||
| 192 | pub fn createModule(self: *Options) *std.Build.Module { | 191 | pub fn createModule(self: *Options) *std.Build.Module { |
| 193 | return self.step.owner.createModule(.{ | 192 | return self.step.owner.createModule(.{ |
| 194 | .source_file = self.getSource(), | 193 | .source_file = self.getOutput(), |
| 195 | .dependencies = &.{}, | 194 | .dependencies = &.{}, |
| 196 | }); | 195 | }); |
| 197 | } | 196 | } |
| 198 | 197 | ||
| 199 | pub fn getSource(self: *Options) FileSource { | 198 | /// deprecated: use `getOutput` |
| 199 | pub const getSource = getOutput; | ||
| 200 | |||
| 201 | pub fn getOutput(self: *Options) LazyPath { | ||
| 200 | return .{ .generated = &self.generated_file }; | 202 | return .{ .generated = &self.generated_file }; |
| 201 | } | 203 | } |
| 202 | 204 | ||
| ... | @@ -207,19 +209,11 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -207,19 +209,11 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 207 | const b = step.owner; | 209 | const b = step.owner; |
| 208 | const self = @fieldParentPtr(Options, "step", step); | 210 | const self = @fieldParentPtr(Options, "step", step); |
| 209 | 211 | ||
| 210 | for (self.artifact_args.items) |item| { | 212 | for (self.args.items) |item| { |
| 211 | self.addOption( | 213 | self.addOption( |
| 212 | []const u8, | 214 | []const u8, |
| 213 | item.name, | 215 | item.name, |
| 214 | b.pathFromRoot(item.artifact.getOutputSource().getPath(b)), | 216 | item.path.getPath(b), |
| 215 | ); | ||
| 216 | } | ||
| 217 | |||
| 218 | for (self.file_source_args.items) |item| { | ||
| 219 | self.addOption( | ||
| 220 | []const u8, | ||
| 221 | item.name, | ||
| 222 | item.source.getPath(b), | ||
| 223 | ); | 217 | ); |
| 224 | } | 218 | } |
| 225 | 219 | ||
| ... | @@ -229,7 +223,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -229,7 +223,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 229 | var hash = b.cache.hash; | 223 | var hash = b.cache.hash; |
| 230 | // Random bytes to make unique. Refresh this with new random bytes when | 224 | // Random bytes to make unique. Refresh this with new random bytes when |
| 231 | // implementation is modified in a non-backwards-compatible way. | 225 | // implementation is modified in a non-backwards-compatible way. |
| 232 | hash.add(@as(u32, 0x38845ef8)); | 226 | hash.add(@as(u32, 0xad95e922)); |
| 233 | hash.addBytes(self.contents.items); | 227 | hash.addBytes(self.contents.items); |
| 234 | const sub_path = "c" ++ fs.path.sep_str ++ hash.final() ++ fs.path.sep_str ++ basename; | 228 | const sub_path = "c" ++ fs.path.sep_str ++ hash.final() ++ fs.path.sep_str ++ basename; |
| 235 | 229 | ||
| ... | @@ -294,14 +288,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -294,14 +288,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 294 | } | 288 | } |
| 295 | } | 289 | } |
| 296 | 290 | ||
| 297 | const OptionArtifactArg = struct { | 291 | const Arg = struct { |
| 298 | name: []const u8, | ||
| 299 | artifact: *Step.Compile, | ||
| 300 | }; | ||
| 301 | |||
| 302 | const OptionFileSourceArg = struct { | ||
| 303 | name: []const u8, | 292 | name: []const u8, |
| 304 | source: FileSource, | 293 | path: LazyPath, |
| 305 | }; | 294 | }; |
| 306 | 295 | ||
| 307 | test Options { | 296 | test Options { |
lib/std/Build/Step/Run.zig+46-34| ... | @@ -82,7 +82,7 @@ has_side_effects: bool = false, | ... | @@ -82,7 +82,7 @@ has_side_effects: bool = false, |
| 82 | pub const StdIn = union(enum) { | 82 | pub const StdIn = union(enum) { |
| 83 | none, | 83 | none, |
| 84 | bytes: []const u8, | 84 | bytes: []const u8, |
| 85 | file_source: std.Build.FileSource, | 85 | lazy_path: std.Build.LazyPath, |
| 86 | }; | 86 | }; |
| 87 | 87 | ||
| 88 | pub const StdIo = union(enum) { | 88 | pub const StdIo = union(enum) { |
| ... | @@ -120,15 +120,15 @@ pub const StdIo = union(enum) { | ... | @@ -120,15 +120,15 @@ pub const StdIo = union(enum) { |
| 120 | 120 | ||
| 121 | pub const Arg = union(enum) { | 121 | pub const Arg = union(enum) { |
| 122 | artifact: *Step.Compile, | 122 | artifact: *Step.Compile, |
| 123 | file_source: PrefixedFileSource, | 123 | lazy_path: PrefixedLazyPath, |
| 124 | directory_source: PrefixedFileSource, | 124 | directory_source: PrefixedLazyPath, |
| 125 | bytes: []u8, | 125 | bytes: []u8, |
| 126 | output: *Output, | 126 | output: *Output, |
| 127 | }; | 127 | }; |
| 128 | 128 | ||
| 129 | pub const PrefixedFileSource = struct { | 129 | pub const PrefixedLazyPath = struct { |
| 130 | prefix: []const u8, | 130 | prefix: []const u8, |
| 131 | file_source: std.Build.FileSource, | 131 | lazy_path: std.Build.LazyPath, |
| 132 | }; | 132 | }; |
| 133 | 133 | ||
| 134 | pub const Output = struct { | 134 | pub const Output = struct { |
| ... | @@ -164,14 +164,15 @@ pub fn enableTestRunnerMode(self: *Run) void { | ... | @@ -164,14 +164,15 @@ pub fn enableTestRunnerMode(self: *Run) void { |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | pub fn addArtifactArg(self: *Run, artifact: *Step.Compile) void { | 166 | pub fn addArtifactArg(self: *Run, artifact: *Step.Compile) void { |
| 167 | const bin_file = artifact.getEmittedBin(); | ||
| 168 | bin_file.addStepDependencies(&self.step); | ||
| 167 | self.argv.append(Arg{ .artifact = artifact }) catch @panic("OOM"); | 169 | self.argv.append(Arg{ .artifact = artifact }) catch @panic("OOM"); |
| 168 | self.step.dependOn(&artifact.step); | ||
| 169 | } | 170 | } |
| 170 | 171 | ||
| 171 | /// This provides file path as a command line argument to the command being | 172 | /// This provides file path as a command line argument to the command being |
| 172 | /// run, and returns a FileSource which can be used as inputs to other APIs | 173 | /// run, and returns a LazyPath which can be used as inputs to other APIs |
| 173 | /// throughout the build system. | 174 | /// throughout the build system. |
| 174 | pub fn addOutputFileArg(self: *Run, basename: []const u8) std.Build.FileSource { | 175 | pub fn addOutputFileArg(self: *Run, basename: []const u8) std.Build.LazyPath { |
| 175 | return self.addPrefixedOutputFileArg("", basename); | 176 | return self.addPrefixedOutputFileArg("", basename); |
| 176 | } | 177 | } |
| 177 | 178 | ||
| ... | @@ -179,7 +180,7 @@ pub fn addPrefixedOutputFileArg( | ... | @@ -179,7 +180,7 @@ pub fn addPrefixedOutputFileArg( |
| 179 | self: *Run, | 180 | self: *Run, |
| 180 | prefix: []const u8, | 181 | prefix: []const u8, |
| 181 | basename: []const u8, | 182 | basename: []const u8, |
| 182 | ) std.Build.FileSource { | 183 | ) std.Build.LazyPath { |
| 183 | const b = self.step.owner; | 184 | const b = self.step.owner; |
| 184 | 185 | ||
| 185 | const output = b.allocator.create(Output) catch @panic("OOM"); | 186 | const output = b.allocator.create(Output) catch @panic("OOM"); |
| ... | @@ -197,31 +198,43 @@ pub fn addPrefixedOutputFileArg( | ... | @@ -197,31 +198,43 @@ pub fn addPrefixedOutputFileArg( |
| 197 | return .{ .generated = &output.generated_file }; | 198 | return .{ .generated = &output.generated_file }; |
| 198 | } | 199 | } |
| 199 | 200 | ||
| 200 | pub fn addFileSourceArg(self: *Run, file_source: std.Build.FileSource) void { | 201 | /// deprecated: use `addFileArg` |
| 201 | self.addPrefixedFileSourceArg("", file_source); | 202 | pub const addFileSourceArg = addFileArg; |
| 203 | |||
| 204 | pub fn addFileArg(self: *Run, lp: std.Build.LazyPath) void { | ||
| 205 | self.addPrefixedFileArg("", lp); | ||
| 202 | } | 206 | } |
| 203 | 207 | ||
| 204 | pub fn addPrefixedFileSourceArg(self: *Run, prefix: []const u8, file_source: std.Build.FileSource) void { | 208 | // deprecated: use `addPrefixedFileArg` |
| 209 | pub const addPrefixedFileSourceArg = addPrefixedFileArg; | ||
| 210 | |||
| 211 | pub fn addPrefixedFileArg(self: *Run, prefix: []const u8, lp: std.Build.LazyPath) void { | ||
| 205 | const b = self.step.owner; | 212 | const b = self.step.owner; |
| 206 | 213 | ||
| 207 | const prefixed_file_source: PrefixedFileSource = .{ | 214 | const prefixed_file_source: PrefixedLazyPath = .{ |
| 208 | .prefix = b.dupe(prefix), | 215 | .prefix = b.dupe(prefix), |
| 209 | .file_source = file_source.dupe(b), | 216 | .lazy_path = lp.dupe(b), |
| 210 | }; | 217 | }; |
| 211 | self.argv.append(.{ .file_source = prefixed_file_source }) catch @panic("OOM"); | 218 | self.argv.append(.{ .lazy_path = prefixed_file_source }) catch @panic("OOM"); |
| 212 | file_source.addStepDependencies(&self.step); | 219 | lp.addStepDependencies(&self.step); |
| 213 | } | 220 | } |
| 214 | 221 | ||
| 215 | pub fn addDirectorySourceArg(self: *Run, directory_source: std.Build.FileSource) void { | 222 | /// deprecated: use `addDirectoryArg` |
| 216 | self.addPrefixedDirectorySourceArg("", directory_source); | 223 | pub const addDirectorySourceArg = addDirectoryArg; |
| 224 | |||
| 225 | pub fn addDirectoryArg(self: *Run, directory_source: std.Build.LazyPath) void { | ||
| 226 | self.addPrefixedDirectoryArg("", directory_source); | ||
| 217 | } | 227 | } |
| 218 | 228 | ||
| 219 | pub fn addPrefixedDirectorySourceArg(self: *Run, prefix: []const u8, directory_source: std.Build.FileSource) void { | 229 | // deprecated: use `addPrefixedDirectoryArg` |
| 230 | pub const addPrefixedDirectorySourceArg = addPrefixedDirectoryArg; | ||
| 231 | |||
| 232 | pub fn addPrefixedDirectoryArg(self: *Run, prefix: []const u8, directory_source: std.Build.LazyPath) void { | ||
| 220 | const b = self.step.owner; | 233 | const b = self.step.owner; |
| 221 | 234 | ||
| 222 | const prefixed_directory_source: PrefixedFileSource = .{ | 235 | const prefixed_directory_source: PrefixedLazyPath = .{ |
| 223 | .prefix = b.dupe(prefix), | 236 | .prefix = b.dupe(prefix), |
| 224 | .file_source = directory_source.dupe(b), | 237 | .lazy_path = directory_source.dupe(b), |
| 225 | }; | 238 | }; |
| 226 | self.argv.append(.{ .directory_source = prefixed_directory_source }) catch @panic("OOM"); | 239 | self.argv.append(.{ .directory_source = prefixed_directory_source }) catch @panic("OOM"); |
| 227 | directory_source.addStepDependencies(&self.step); | 240 | directory_source.addStepDependencies(&self.step); |
| ... | @@ -239,7 +252,7 @@ pub fn addArgs(self: *Run, args: []const []const u8) void { | ... | @@ -239,7 +252,7 @@ pub fn addArgs(self: *Run, args: []const []const u8) void { |
| 239 | 252 | ||
| 240 | pub fn setStdIn(self: *Run, stdin: StdIn) void { | 253 | pub fn setStdIn(self: *Run, stdin: StdIn) void { |
| 241 | switch (stdin) { | 254 | switch (stdin) { |
| 242 | .file_source => |file_source| file_source.addStepDependencies(&self.step), | 255 | .lazy_path => |lazy_path| lazy_path.addStepDependencies(&self.step), |
| 243 | .bytes, .none => {}, | 256 | .bytes, .none => {}, |
| 244 | } | 257 | } |
| 245 | self.stdin = stdin; | 258 | self.stdin = stdin; |
| ... | @@ -331,7 +344,7 @@ pub fn addCheck(self: *Run, new_check: StdIo.Check) void { | ... | @@ -331,7 +344,7 @@ pub fn addCheck(self: *Run, new_check: StdIo.Check) void { |
| 331 | } | 344 | } |
| 332 | } | 345 | } |
| 333 | 346 | ||
| 334 | pub fn captureStdErr(self: *Run) std.Build.FileSource { | 347 | pub fn captureStdErr(self: *Run) std.Build.LazyPath { |
| 335 | assert(self.stdio != .inherit); | 348 | assert(self.stdio != .inherit); |
| 336 | 349 | ||
| 337 | if (self.captured_stderr) |output| return .{ .generated = &output.generated_file }; | 350 | if (self.captured_stderr) |output| return .{ .generated = &output.generated_file }; |
| ... | @@ -346,7 +359,7 @@ pub fn captureStdErr(self: *Run) std.Build.FileSource { | ... | @@ -346,7 +359,7 @@ pub fn captureStdErr(self: *Run) std.Build.FileSource { |
| 346 | return .{ .generated = &output.generated_file }; | 359 | return .{ .generated = &output.generated_file }; |
| 347 | } | 360 | } |
| 348 | 361 | ||
| 349 | pub fn captureStdOut(self: *Run) std.Build.FileSource { | 362 | pub fn captureStdOut(self: *Run) std.Build.LazyPath { |
| 350 | assert(self.stdio != .inherit); | 363 | assert(self.stdio != .inherit); |
| 351 | 364 | ||
| 352 | if (self.captured_stdout) |output| return .{ .generated = &output.generated_file }; | 365 | if (self.captured_stdout) |output| return .{ .generated = &output.generated_file }; |
| ... | @@ -431,14 +444,14 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -431,14 +444,14 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 431 | try argv_list.append(bytes); | 444 | try argv_list.append(bytes); |
| 432 | man.hash.addBytes(bytes); | 445 | man.hash.addBytes(bytes); |
| 433 | }, | 446 | }, |
| 434 | .file_source => |file| { | 447 | .lazy_path => |file| { |
| 435 | const file_path = file.file_source.getPath(b); | 448 | const file_path = file.lazy_path.getPath(b); |
| 436 | try argv_list.append(b.fmt("{s}{s}", .{ file.prefix, file_path })); | 449 | try argv_list.append(b.fmt("{s}{s}", .{ file.prefix, file_path })); |
| 437 | man.hash.addBytes(file.prefix); | 450 | man.hash.addBytes(file.prefix); |
| 438 | _ = try man.addFile(file_path, null); | 451 | _ = try man.addFile(file_path, null); |
| 439 | }, | 452 | }, |
| 440 | .directory_source => |file| { | 453 | .directory_source => |file| { |
| 441 | const file_path = file.file_source.getPath(b); | 454 | const file_path = file.lazy_path.getPath(b); |
| 442 | try argv_list.append(b.fmt("{s}{s}", .{ file.prefix, file_path })); | 455 | try argv_list.append(b.fmt("{s}{s}", .{ file.prefix, file_path })); |
| 443 | man.hash.addBytes(file.prefix); | 456 | man.hash.addBytes(file.prefix); |
| 444 | man.hash.addBytes(file_path); | 457 | man.hash.addBytes(file_path); |
| ... | @@ -448,8 +461,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -448,8 +461,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 448 | // On Windows we don't have rpaths so we have to add .dll search paths to PATH | 461 | // On Windows we don't have rpaths so we have to add .dll search paths to PATH |
| 449 | self.addPathForDynLibs(artifact); | 462 | self.addPathForDynLibs(artifact); |
| 450 | } | 463 | } |
| 451 | const file_path = artifact.installed_path orelse | 464 | const file_path = artifact.installed_path orelse artifact.generated_bin.?.path.?; // the path is guaranteed to be set |
| 452 | artifact.getOutputSource().getPath(b); | ||
| 453 | 465 | ||
| 454 | try argv_list.append(file_path); | 466 | try argv_list.append(file_path); |
| 455 | 467 | ||
| ... | @@ -474,8 +486,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -474,8 +486,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 474 | .bytes => |bytes| { | 486 | .bytes => |bytes| { |
| 475 | man.hash.addBytes(bytes); | 487 | man.hash.addBytes(bytes); |
| 476 | }, | 488 | }, |
| 477 | .file_source => |file_source| { | 489 | .lazy_path => |lazy_path| { |
| 478 | const file_path = file_source.getPath(b); | 490 | const file_path = lazy_path.getPath(b); |
| 479 | _ = try man.addFile(file_path, null); | 491 | _ = try man.addFile(file_path, null); |
| 480 | }, | 492 | }, |
| 481 | .none => {}, | 493 | .none => {}, |
| ... | @@ -1174,8 +1186,8 @@ fn evalGeneric(self: *Run, child: *std.process.Child) !StdIoResult { | ... | @@ -1174,8 +1186,8 @@ fn evalGeneric(self: *Run, child: *std.process.Child) !StdIoResult { |
| 1174 | child.stdin.?.close(); | 1186 | child.stdin.?.close(); |
| 1175 | child.stdin = null; | 1187 | child.stdin = null; |
| 1176 | }, | 1188 | }, |
| 1177 | .file_source => |file_source| { | 1189 | .lazy_path => |lazy_path| { |
| 1178 | const path = file_source.getPath(self.step.owner); | 1190 | const path = lazy_path.getPath(self.step.owner); |
| 1179 | const file = self.step.owner.build_root.handle.openFile(path, .{}) catch |err| { | 1191 | const file = self.step.owner.build_root.handle.openFile(path, .{}) catch |err| { |
| 1180 | return self.step.fail("unable to open stdin file: {s}", .{@errorName(err)}); | 1192 | return self.step.fail("unable to open stdin file: {s}", .{@errorName(err)}); |
| 1181 | }; | 1193 | }; |
| ... | @@ -1241,7 +1253,7 @@ fn addPathForDynLibs(self: *Run, artifact: *Step.Compile) void { | ... | @@ -1241,7 +1253,7 @@ fn addPathForDynLibs(self: *Run, artifact: *Step.Compile) void { |
| 1241 | switch (link_object) { | 1253 | switch (link_object) { |
| 1242 | .other_step => |other| { | 1254 | .other_step => |other| { |
| 1243 | if (other.target.isWindows() and other.isDynamicLibrary()) { | 1255 | if (other.target.isWindows() and other.isDynamicLibrary()) { |
| 1244 | addPathDir(self, fs.path.dirname(other.getOutputSource().getPath(b)).?); | 1256 | addPathDir(self, fs.path.dirname(other.getEmittedBin().getPath(b)).?); |
| 1245 | addPathForDynLibs(self, other); | 1257 | addPathForDynLibs(self, other); |
| 1246 | } | 1258 | } |
| 1247 | }, | 1259 | }, |
lib/std/Build/Step/TranslateC.zig+10-6| ... | @@ -9,7 +9,7 @@ const TranslateC = @This(); | ... | @@ -9,7 +9,7 @@ const TranslateC = @This(); |
| 9 | pub const base_id = .translate_c; | 9 | pub const base_id = .translate_c; |
| 10 | 10 | ||
| 11 | step: Step, | 11 | step: Step, |
| 12 | source: std.Build.FileSource, | 12 | source: std.Build.LazyPath, |
| 13 | include_dirs: std.ArrayList([]const u8), | 13 | include_dirs: std.ArrayList([]const u8), |
| 14 | c_macros: std.ArrayList([]const u8), | 14 | c_macros: std.ArrayList([]const u8), |
| 15 | out_basename: []const u8, | 15 | out_basename: []const u8, |
| ... | @@ -18,7 +18,7 @@ optimize: std.builtin.OptimizeMode, | ... | @@ -18,7 +18,7 @@ optimize: std.builtin.OptimizeMode, |
| 18 | output_file: std.Build.GeneratedFile, | 18 | output_file: std.Build.GeneratedFile, |
| 19 | 19 | ||
| 20 | pub const Options = struct { | 20 | pub const Options = struct { |
| 21 | source_file: std.Build.FileSource, | 21 | source_file: std.Build.LazyPath, |
| 22 | target: CrossTarget, | 22 | target: CrossTarget, |
| 23 | optimize: std.builtin.OptimizeMode, | 23 | optimize: std.builtin.OptimizeMode, |
| 24 | }; | 24 | }; |
| ... | @@ -53,10 +53,14 @@ pub const AddExecutableOptions = struct { | ... | @@ -53,10 +53,14 @@ pub const AddExecutableOptions = struct { |
| 53 | linkage: ?Step.Compile.Linkage = null, | 53 | linkage: ?Step.Compile.Linkage = null, |
| 54 | }; | 54 | }; |
| 55 | 55 | ||
| 56 | pub fn getOutput(self: *TranslateC) std.Build.LazyPath { | ||
| 57 | return .{ .generated = &self.output_file }; | ||
| 58 | } | ||
| 59 | |||
| 56 | /// Creates a step to build an executable from the translated source. | 60 | /// Creates a step to build an executable from the translated source. |
| 57 | pub fn addExecutable(self: *TranslateC, options: AddExecutableOptions) *Step.Compile { | 61 | pub fn addExecutable(self: *TranslateC, options: AddExecutableOptions) *Step.Compile { |
| 58 | return self.step.owner.addExecutable(.{ | 62 | return self.step.owner.addExecutable(.{ |
| 59 | .root_source_file = .{ .generated = &self.output_file }, | 63 | .root_source_file = self.getOutput(), |
| 60 | .name = options.name orelse "translated_c", | 64 | .name = options.name orelse "translated_c", |
| 61 | .version = options.version, | 65 | .version = options.version, |
| 62 | .target = options.target orelse self.target, | 66 | .target = options.target orelse self.target, |
| ... | @@ -70,7 +74,7 @@ pub fn addExecutable(self: *TranslateC, options: AddExecutableOptions) *Step.Com | ... | @@ -70,7 +74,7 @@ pub fn addExecutable(self: *TranslateC, options: AddExecutableOptions) *Step.Com |
| 70 | /// `createModule` can be used instead to create a private module. | 74 | /// `createModule` can be used instead to create a private module. |
| 71 | pub fn addModule(self: *TranslateC, name: []const u8) *std.Build.Module { | 75 | pub fn addModule(self: *TranslateC, name: []const u8) *std.Build.Module { |
| 72 | return self.step.owner.addModule(name, .{ | 76 | return self.step.owner.addModule(name, .{ |
| 73 | .source_file = .{ .generated = &self.output_file }, | 77 | .source_file = self.getOutput(), |
| 74 | }); | 78 | }); |
| 75 | } | 79 | } |
| 76 | 80 | ||
| ... | @@ -83,7 +87,7 @@ pub fn createModule(self: *TranslateC) *std.Build.Module { | ... | @@ -83,7 +87,7 @@ pub fn createModule(self: *TranslateC) *std.Build.Module { |
| 83 | 87 | ||
| 84 | module.* = .{ | 88 | module.* = .{ |
| 85 | .builder = b, | 89 | .builder = b, |
| 86 | .source_file = .{ .generated = &self.output_file }, | 90 | .source_file = self.getOutput(), |
| 87 | .dependencies = std.StringArrayHashMap(*std.Build.Module).init(b.allocator), | 91 | .dependencies = std.StringArrayHashMap(*std.Build.Module).init(b.allocator), |
| 88 | }; | 92 | }; |
| 89 | return module; | 93 | return module; |
| ... | @@ -96,7 +100,7 @@ pub fn addIncludeDir(self: *TranslateC, include_dir: []const u8) void { | ... | @@ -96,7 +100,7 @@ pub fn addIncludeDir(self: *TranslateC, include_dir: []const u8) void { |
| 96 | pub fn addCheckFile(self: *TranslateC, expected_matches: []const []const u8) *Step.CheckFile { | 100 | pub fn addCheckFile(self: *TranslateC, expected_matches: []const []const u8) *Step.CheckFile { |
| 97 | return Step.CheckFile.create( | 101 | return Step.CheckFile.create( |
| 98 | self.step.owner, | 102 | self.step.owner, |
| 99 | .{ .generated = &self.output_file }, | 103 | self.getOutput(), |
| 100 | .{ .expected_matches = expected_matches }, | 104 | .{ .expected_matches = expected_matches }, |
| 101 | ); | 105 | ); |
| 102 | } | 106 | } |
lib/std/Build/Step/WriteFile.zig+15-10| ... | @@ -28,7 +28,10 @@ pub const File = struct { | ... | @@ -28,7 +28,10 @@ pub const File = struct { |
| 28 | sub_path: []const u8, | 28 | sub_path: []const u8, |
| 29 | contents: Contents, | 29 | contents: Contents, |
| 30 | 30 | ||
| 31 | pub fn getFileSource(self: *File) std.Build.FileSource { | 31 | /// deprecated: use `getPath` |
| 32 | pub const getFileSource = getPath; | ||
| 33 | |||
| 34 | pub fn getPath(self: *File) std.Build.LazyPath { | ||
| 32 | return .{ .generated = &self.generated_file }; | 35 | return .{ .generated = &self.generated_file }; |
| 33 | } | 36 | } |
| 34 | }; | 37 | }; |
| ... | @@ -40,7 +43,7 @@ pub const OutputSourceFile = struct { | ... | @@ -40,7 +43,7 @@ pub const OutputSourceFile = struct { |
| 40 | 43 | ||
| 41 | pub const Contents = union(enum) { | 44 | pub const Contents = union(enum) { |
| 42 | bytes: []const u8, | 45 | bytes: []const u8, |
| 43 | copy: std.Build.FileSource, | 46 | copy: std.Build.LazyPath, |
| 44 | }; | 47 | }; |
| 45 | 48 | ||
| 46 | pub fn create(owner: *std.Build) *WriteFile { | 49 | pub fn create(owner: *std.Build) *WriteFile { |
| ... | @@ -59,7 +62,7 @@ pub fn create(owner: *std.Build) *WriteFile { | ... | @@ -59,7 +62,7 @@ pub fn create(owner: *std.Build) *WriteFile { |
| 59 | return wf; | 62 | return wf; |
| 60 | } | 63 | } |
| 61 | 64 | ||
| 62 | pub fn add(wf: *WriteFile, sub_path: []const u8, bytes: []const u8) std.Build.FileSource { | 65 | pub fn add(wf: *WriteFile, sub_path: []const u8, bytes: []const u8) std.Build.LazyPath { |
| 63 | const b = wf.step.owner; | 66 | const b = wf.step.owner; |
| 64 | const gpa = b.allocator; | 67 | const gpa = b.allocator; |
| 65 | const file = gpa.create(File) catch @panic("OOM"); | 68 | const file = gpa.create(File) catch @panic("OOM"); |
| ... | @@ -70,7 +73,7 @@ pub fn add(wf: *WriteFile, sub_path: []const u8, bytes: []const u8) std.Build.Fi | ... | @@ -70,7 +73,7 @@ pub fn add(wf: *WriteFile, sub_path: []const u8, bytes: []const u8) std.Build.Fi |
| 70 | }; | 73 | }; |
| 71 | wf.files.append(gpa, file) catch @panic("OOM"); | 74 | wf.files.append(gpa, file) catch @panic("OOM"); |
| 72 | wf.maybeUpdateName(); | 75 | wf.maybeUpdateName(); |
| 73 | return file.getFileSource(); | 76 | return file.getPath(); |
| 74 | } | 77 | } |
| 75 | 78 | ||
| 76 | /// Place the file into the generated directory within the local cache, | 79 | /// Place the file into the generated directory within the local cache, |
| ... | @@ -80,7 +83,7 @@ pub fn add(wf: *WriteFile, sub_path: []const u8, bytes: []const u8) std.Build.Fi | ... | @@ -80,7 +83,7 @@ pub fn add(wf: *WriteFile, sub_path: []const u8, bytes: []const u8) std.Build.Fi |
| 80 | /// include sub-directories, in which case this step will ensure the | 83 | /// include sub-directories, in which case this step will ensure the |
| 81 | /// required sub-path exists. | 84 | /// required sub-path exists. |
| 82 | /// This is the option expected to be used most commonly with `addCopyFile`. | 85 | /// This is the option expected to be used most commonly with `addCopyFile`. |
| 83 | pub fn addCopyFile(wf: *WriteFile, source: std.Build.FileSource, sub_path: []const u8) std.Build.FileSource { | 86 | pub fn addCopyFile(wf: *WriteFile, source: std.Build.LazyPath, sub_path: []const u8) std.Build.LazyPath { |
| 84 | const b = wf.step.owner; | 87 | const b = wf.step.owner; |
| 85 | const gpa = b.allocator; | 88 | const gpa = b.allocator; |
| 86 | const file = gpa.create(File) catch @panic("OOM"); | 89 | const file = gpa.create(File) catch @panic("OOM"); |
| ... | @@ -93,7 +96,7 @@ pub fn addCopyFile(wf: *WriteFile, source: std.Build.FileSource, sub_path: []con | ... | @@ -93,7 +96,7 @@ pub fn addCopyFile(wf: *WriteFile, source: std.Build.FileSource, sub_path: []con |
| 93 | 96 | ||
| 94 | wf.maybeUpdateName(); | 97 | wf.maybeUpdateName(); |
| 95 | source.addStepDependencies(&wf.step); | 98 | source.addStepDependencies(&wf.step); |
| 96 | return file.getFileSource(); | 99 | return file.getLazyPath(); |
| 97 | } | 100 | } |
| 98 | 101 | ||
| 99 | /// A path relative to the package root. | 102 | /// A path relative to the package root. |
| ... | @@ -101,7 +104,7 @@ pub fn addCopyFile(wf: *WriteFile, source: std.Build.FileSource, sub_path: []con | ... | @@ -101,7 +104,7 @@ pub fn addCopyFile(wf: *WriteFile, source: std.Build.FileSource, sub_path: []con |
| 101 | /// used as part of the normal build process, but as a utility occasionally | 104 | /// used as part of the normal build process, but as a utility occasionally |
| 102 | /// run by a developer with intent to modify source files and then commit | 105 | /// run by a developer with intent to modify source files and then commit |
| 103 | /// those changes to version control. | 106 | /// those changes to version control. |
| 104 | pub fn addCopyFileToSource(wf: *WriteFile, source: std.Build.FileSource, sub_path: []const u8) void { | 107 | pub fn addCopyFileToSource(wf: *WriteFile, source: std.Build.LazyPath, sub_path: []const u8) void { |
| 105 | const b = wf.step.owner; | 108 | const b = wf.step.owner; |
| 106 | wf.output_source_files.append(b.allocator, .{ | 109 | wf.output_source_files.append(b.allocator, .{ |
| 107 | .contents = .{ .copy = source }, | 110 | .contents = .{ .copy = source }, |
| ... | @@ -123,11 +126,13 @@ pub fn addBytesToSource(wf: *WriteFile, bytes: []const u8, sub_path: []const u8) | ... | @@ -123,11 +126,13 @@ pub fn addBytesToSource(wf: *WriteFile, bytes: []const u8, sub_path: []const u8) |
| 123 | }) catch @panic("OOM"); | 126 | }) catch @panic("OOM"); |
| 124 | } | 127 | } |
| 125 | 128 | ||
| 126 | pub const getFileSource = @compileError("Deprecated; use the return value from add()/addCopyFile(), or use files[i].getFileSource()"); | 129 | pub const getFileSource = @compileError("Deprecated; use the return value from add()/addCopyFile(), or use files[i].getPath()"); |
| 130 | |||
| 131 | pub const getDirectorySource = getDirectory; | ||
| 127 | 132 | ||
| 128 | /// Returns a `FileSource` representing the base directory that contains all the | 133 | /// Returns a `LazyPath` representing the base directory that contains all the |
| 129 | /// files from this `WriteFile`. | 134 | /// files from this `WriteFile`. |
| 130 | pub fn getDirectorySource(wf: *WriteFile) std.Build.FileSource { | 135 | pub fn getDirectory(wf: *WriteFile) std.Build.LazyPath { |
| 131 | return .{ .generated = &wf.generated_directory }; | 136 | return .{ .generated = &wf.generated_directory }; |
| 132 | } | 137 | } |
| 133 | 138 |
src/link.zig+4-2| ... | @@ -966,6 +966,8 @@ pub const File = struct { | ... | @@ -966,6 +966,8 @@ pub const File = struct { |
| 966 | } | 966 | } |
| 967 | 967 | ||
| 968 | pub fn linkAsArchive(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) FlushError!void { | 968 | pub fn linkAsArchive(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) FlushError!void { |
| 969 | const emit = base.options.emit orelse return; | ||
| 970 | |||
| 969 | const tracy = trace(@src()); | 971 | const tracy = trace(@src()); |
| 970 | defer tracy.end(); | 972 | defer tracy.end(); |
| 971 | 973 | ||
| ... | @@ -973,8 +975,8 @@ pub const File = struct { | ... | @@ -973,8 +975,8 @@ pub const File = struct { |
| 973 | defer arena_allocator.deinit(); | 975 | defer arena_allocator.deinit(); |
| 974 | const arena = arena_allocator.allocator(); | 976 | const arena = arena_allocator.allocator(); |
| 975 | 977 | ||
| 976 | const directory = base.options.emit.?.directory; // Just an alias to make it shorter to type. | 978 | const directory = emit.directory; // Just an alias to make it shorter to type. |
| 977 | const full_out_path = try directory.join(arena, &[_][]const u8{base.options.emit.?.sub_path}); | 979 | const full_out_path = try directory.join(arena, &[_][]const u8{emit.sub_path}); |
| 978 | const full_out_path_z = try arena.dupeZ(u8, full_out_path); | 980 | const full_out_path_z = try arena.dupeZ(u8, full_out_path); |
| 979 | 981 | ||
| 980 | // If there is no Zig code to compile, then we should skip flushing the output file | 982 | // If there is no Zig code to compile, then we should skip flushing the output file |
src/link/Coff.zig+2| ... | @@ -1452,6 +1452,8 @@ pub fn updateDeclExports( | ... | @@ -1452,6 +1452,8 @@ pub fn updateDeclExports( |
| 1452 | if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports); | 1452 | if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports); |
| 1453 | } | 1453 | } |
| 1454 | 1454 | ||
| 1455 | if (self.base.options.emit == null) return; | ||
| 1456 | |||
| 1455 | const gpa = self.base.allocator; | 1457 | const gpa = self.base.allocator; |
| 1456 | 1458 | ||
| 1457 | const decl = mod.declPtr(decl_index); | 1459 | const decl = mod.declPtr(decl_index); |
src/link/Elf.zig+2| ... | @@ -2865,6 +2865,8 @@ pub fn updateDeclExports( | ... | @@ -2865,6 +2865,8 @@ pub fn updateDeclExports( |
| 2865 | if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports); | 2865 | if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports); |
| 2866 | } | 2866 | } |
| 2867 | 2867 | ||
| 2868 | if (self.base.options.emit == null) return; | ||
| 2869 | |||
| 2868 | const tracy = trace(@src()); | 2870 | const tracy = trace(@src()); |
| 2869 | defer tracy.end(); | 2871 | defer tracy.end(); |
| 2870 | 2872 |
src/link/MachO.zig+2| ... | @@ -2386,6 +2386,8 @@ pub fn updateDeclExports( | ... | @@ -2386,6 +2386,8 @@ pub fn updateDeclExports( |
| 2386 | return llvm_object.updateDeclExports(mod, decl_index, exports); | 2386 | return llvm_object.updateDeclExports(mod, decl_index, exports); |
| 2387 | } | 2387 | } |
| 2388 | 2388 | ||
| 2389 | if (self.base.options.emit == null) return; | ||
| 2390 | |||
| 2389 | const tracy = trace(@src()); | 2391 | const tracy = trace(@src()); |
| 2390 | defer tracy.end(); | 2392 | defer tracy.end(); |
| 2391 | 2393 |
src/link/NvPtx.zig+2-1| ... | @@ -106,10 +106,11 @@ pub fn flushModule(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -106,10 +106,11 @@ pub fn flushModule(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.No |
| 106 | if (build_options.skip_non_native) { | 106 | if (build_options.skip_non_native) { |
| 107 | @panic("Attempted to compile for architecture that was disabled by build configuration"); | 107 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 108 | } | 108 | } |
| 109 | const outfile = comp.bin_file.options.emit orelse return; | ||
| 110 | |||
| 109 | const tracy = trace(@src()); | 111 | const tracy = trace(@src()); |
| 110 | defer tracy.end(); | 112 | defer tracy.end(); |
| 111 | 113 | ||
| 112 | const outfile = comp.bin_file.options.emit.?; | ||
| 113 | // We modify 'comp' before passing it to LLVM, but restore value afterwards. | 114 | // We modify 'comp' before passing it to LLVM, but restore value afterwards. |
| 114 | // We tell LLVM to not try to build a .o, only an "assembly" file. | 115 | // We tell LLVM to not try to build a .o, only an "assembly" file. |
| 115 | // This is required by the LLVM PTX backend. | 116 | // This is required by the LLVM PTX backend. |
src/link/Wasm.zig+2| ... | @@ -1712,6 +1712,8 @@ pub fn updateDeclExports( | ... | @@ -1712,6 +1712,8 @@ pub fn updateDeclExports( |
| 1712 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports); | 1712 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports); |
| 1713 | } | 1713 | } |
| 1714 | 1714 | ||
| 1715 | if (wasm.base.options.emit == null) return; | ||
| 1716 | |||
| 1715 | const decl = mod.declPtr(decl_index); | 1717 | const decl = mod.declPtr(decl_index); |
| 1716 | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); | 1718 | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); |
| 1717 | const atom = wasm.getAtom(atom_index); | 1719 | const atom = wasm.getAtom(atom_index); |
test/link/glibc_compat/build.zig+3-1| ... | @@ -4,7 +4,7 @@ pub fn build(b: *std.Build) void { | ... | @@ -4,7 +4,7 @@ pub fn build(b: *std.Build) void { |
| 4 | const test_step = b.step("test", "Test"); | 4 | const test_step = b.step("test", "Test"); |
| 5 | b.default_step = test_step; | 5 | b.default_step = test_step; |
| 6 | 6 | ||
| 7 | inline for (.{ "aarch64-linux-gnu.2.27", "aarch64-linux-gnu.2.34" }) |t| { | 7 | for ([_][]const u8{ "aarch64-linux-gnu.2.27", "aarch64-linux-gnu.2.34" }) |t| { |
| 8 | const exe = b.addExecutable(.{ | 8 | const exe = b.addExecutable(.{ |
| 9 | .name = t, | 9 | .name = t, |
| 10 | .root_source_file = .{ .path = "main.c" }, | 10 | .root_source_file = .{ .path = "main.c" }, |
| ... | @@ -13,6 +13,8 @@ pub fn build(b: *std.Build) void { | ... | @@ -13,6 +13,8 @@ pub fn build(b: *std.Build) void { |
| 13 | ) catch unreachable, | 13 | ) catch unreachable, |
| 14 | }); | 14 | }); |
| 15 | exe.linkLibC(); | 15 | exe.linkLibC(); |
| 16 | // TODO: actually test the output | ||
| 17 | _ = exe.getEmittedBin(); | ||
| 16 | test_step.dependOn(&exe.step); | 18 | test_step.dependOn(&exe.step); |
| 17 | } | 19 | } |
| 18 | } | 20 | } |
test/link/interdependent_static_c_libs/build.zig+5-5| ... | @@ -16,16 +16,16 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -16,16 +16,16 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 16 | .optimize = optimize, | 16 | .optimize = optimize, |
| 17 | .target = .{}, | 17 | .target = .{}, |
| 18 | }); | 18 | }); |
| 19 | lib_a.addCSourceFile("a.c", &[_][]const u8{}); | 19 | lib_a.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &[_][]const u8{} }); |
| 20 | lib_a.addIncludePath("."); | 20 | lib_a.addIncludePath(.{ .path = "." }); |
| 21 | 21 | ||
| 22 | const lib_b = b.addStaticLibrary(.{ | 22 | const lib_b = b.addStaticLibrary(.{ |
| 23 | .name = "b", | 23 | .name = "b", |
| 24 | .optimize = optimize, | 24 | .optimize = optimize, |
| 25 | .target = .{}, | 25 | .target = .{}, |
| 26 | }); | 26 | }); |
| 27 | lib_b.addCSourceFile("b.c", &[_][]const u8{}); | 27 | lib_b.addCSourceFile(.{ .file = .{ .path = "b.c" }, .flags = &[_][]const u8{} }); |
| 28 | lib_b.addIncludePath("."); | 28 | lib_b.addIncludePath(.{ .path = "." }); |
| 29 | 29 | ||
| 30 | const test_exe = b.addTest(.{ | 30 | const test_exe = b.addTest(.{ |
| 31 | .root_source_file = .{ .path = "main.zig" }, | 31 | .root_source_file = .{ .path = "main.zig" }, |
| ... | @@ -33,7 +33,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -33,7 +33,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 33 | }); | 33 | }); |
| 34 | test_exe.linkLibrary(lib_a); | 34 | test_exe.linkLibrary(lib_a); |
| 35 | test_exe.linkLibrary(lib_b); | 35 | test_exe.linkLibrary(lib_b); |
| 36 | test_exe.addIncludePath("."); | 36 | test_exe.addIncludePath(.{ .path = "." }); |
| 37 | 37 | ||
| 38 | test_step.dependOn(&b.addRunArtifact(test_exe).step); | 38 | test_step.dependOn(&b.addRunArtifact(test_exe).step); |
| 39 | } | 39 | } |
test/link/macho/bugs/13056/build.zig+5-5| ... | @@ -23,13 +23,13 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -23,13 +23,13 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 23 | .name = "test", | 23 | .name = "test", |
| 24 | .optimize = optimize, | 24 | .optimize = optimize, |
| 25 | }); | 25 | }); |
| 26 | exe.addSystemIncludePath(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/include" }) catch unreachable); | 26 | exe.addSystemIncludePath(.{ .path = b.pathJoin(&.{ sdk.path, "/usr/include" }) }); |
| 27 | exe.addIncludePath(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/include/c++/v1" }) catch unreachable); | 27 | exe.addIncludePath(.{ .path = b.pathJoin(&.{ sdk.path, "/usr/include/c++/v1" }) }); |
| 28 | exe.addCSourceFile("test.cpp", &.{ | 28 | exe.addCSourceFile(.{ .file = .{ .path = "test.cpp" }, .flags = &.{ |
| 29 | "-nostdlib++", | 29 | "-nostdlib++", |
| 30 | "-nostdinc++", | 30 | "-nostdinc++", |
| 31 | }); | 31 | } }); |
| 32 | exe.addObjectFile(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/lib/libc++.tbd" }) catch unreachable); | 32 | exe.addObjectFile(.{ .path = b.pathJoin(&.{ sdk.path, "/usr/lib/libc++.tbd" }) }); |
| 33 | 33 | ||
| 34 | const run_cmd = b.addRunArtifact(exe); | 34 | const run_cmd = b.addRunArtifact(exe); |
| 35 | run_cmd.expectStdErrEqual("x: 5\n"); | 35 | run_cmd.expectStdErrEqual("x: 5\n"); |
test/link/macho/dead_strip/build.zig+1-1| ... | @@ -52,7 +52,7 @@ fn createScenario( | ... | @@ -52,7 +52,7 @@ fn createScenario( |
| 52 | .optimize = optimize, | 52 | .optimize = optimize, |
| 53 | .target = target, | 53 | .target = target, |
| 54 | }); | 54 | }); |
| 55 | exe.addCSourceFile("main.c", &[0][]const u8{}); | 55 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &[0][]const u8{} }); |
| 56 | exe.linkLibC(); | 56 | exe.linkLibC(); |
| 57 | return exe; | 57 | return exe; |
| 58 | } | 58 | } |
test/link/macho/dead_strip_dylibs/build.zig+1-1| ... | @@ -53,7 +53,7 @@ fn createScenario( | ... | @@ -53,7 +53,7 @@ fn createScenario( |
| 53 | .name = name, | 53 | .name = name, |
| 54 | .optimize = optimize, | 54 | .optimize = optimize, |
| 55 | }); | 55 | }); |
| 56 | exe.addCSourceFile("main.c", &[0][]const u8{}); | 56 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &[0][]const u8{} }); |
| 57 | exe.linkLibC(); | 57 | exe.linkLibC(); |
| 58 | exe.linkFramework("Cocoa"); | 58 | exe.linkFramework("Cocoa"); |
| 59 | return exe; | 59 | return exe; |
test/link/macho/dylib/build.zig+5-5| ... | @@ -21,7 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -21,7 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 21 | .optimize = optimize, | 21 | .optimize = optimize, |
| 22 | .target = target, | 22 | .target = target, |
| 23 | }); | 23 | }); |
| 24 | dylib.addCSourceFile("a.c", &.{}); | 24 | dylib.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); |
| 25 | dylib.linkLibC(); | 25 | dylib.linkLibC(); |
| 26 | 26 | ||
| 27 | const check_dylib = dylib.checkObject(); | 27 | const check_dylib = dylib.checkObject(); |
| ... | @@ -39,10 +39,10 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -39,10 +39,10 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 39 | .optimize = optimize, | 39 | .optimize = optimize, |
| 40 | .target = target, | 40 | .target = target, |
| 41 | }); | 41 | }); |
| 42 | exe.addCSourceFile("main.c", &.{}); | 42 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); |
| 43 | exe.linkSystemLibrary("a"); | 43 | exe.linkSystemLibrary("a"); |
| 44 | exe.addLibraryPathDirectorySource(dylib.getOutputDirectorySource()); | 44 | exe.addLibraryPath(dylib.getEmittedBinDirectory()); |
| 45 | exe.addRPathDirectorySource(dylib.getOutputDirectorySource()); | 45 | exe.addRPath(dylib.getEmittedBinDirectory()); |
| 46 | exe.linkLibC(); | 46 | exe.linkLibC(); |
| 47 | 47 | ||
| 48 | const check_exe = exe.checkObject(); | 48 | const check_exe = exe.checkObject(); |
| ... | @@ -55,7 +55,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -55,7 +55,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 55 | 55 | ||
| 56 | check_exe.checkStart(); | 56 | check_exe.checkStart(); |
| 57 | check_exe.checkExact("cmd RPATH"); | 57 | check_exe.checkExact("cmd RPATH"); |
| 58 | check_exe.checkExactFileSource("path", dylib.getOutputDirectorySource()); | 58 | check_exe.checkExactPath("path", dylib.getOutputDirectorySource()); |
| 59 | test_step.dependOn(&check_exe.step); | 59 | test_step.dependOn(&check_exe.step); |
| 60 | 60 | ||
| 61 | const run = b.addRunArtifact(exe); | 61 | const run = b.addRunArtifact(exe); |
test/link/macho/empty/build.zig+2-2| ... | @@ -20,8 +20,8 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -20,8 +20,8 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 20 | .optimize = optimize, | 20 | .optimize = optimize, |
| 21 | .target = target, | 21 | .target = target, |
| 22 | }); | 22 | }); |
| 23 | exe.addCSourceFile("main.c", &[0][]const u8{}); | 23 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &[0][]const u8{} }); |
| 24 | exe.addCSourceFile("empty.c", &[0][]const u8{}); | 24 | exe.addCSourceFile(.{ .file = .{ .path = "empty.c" }, .flags = &[0][]const u8{} }); |
| 25 | exe.linkLibC(); | 25 | exe.linkLibC(); |
| 26 | 26 | ||
| 27 | const run_cmd = b.addRunArtifact(exe); | 27 | const run_cmd = b.addRunArtifact(exe); |
test/link/macho/entry/build.zig+1-1| ... | @@ -18,7 +18,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -18,7 +18,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 18 | .optimize = optimize, | 18 | .optimize = optimize, |
| 19 | .target = .{ .os_tag = .macos }, | 19 | .target = .{ .os_tag = .macos }, |
| 20 | }); | 20 | }); |
| 21 | exe.addCSourceFile("main.c", &.{}); | 21 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); |
| 22 | exe.linkLibC(); | 22 | exe.linkLibC(); |
| 23 | exe.entry_symbol_name = "_non_main"; | 23 | exe.entry_symbol_name = "_non_main"; |
| 24 | 24 |
test/link/macho/entry_in_archive/build.zig+1-1| ... | @@ -18,7 +18,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -18,7 +18,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 18 | .optimize = optimize, | 18 | .optimize = optimize, |
| 19 | .target = .{ .os_tag = .macos }, | 19 | .target = .{ .os_tag = .macos }, |
| 20 | }); | 20 | }); |
| 21 | lib.addCSourceFile("main.c", &.{}); | 21 | lib.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); |
| 22 | lib.linkLibC(); | 22 | lib.linkLibC(); |
| 23 | 23 | ||
| 24 | const exe = b.addExecutable(.{ | 24 | const exe = b.addExecutable(.{ |
test/link/macho/entry_in_dylib/build.zig+2-2| ... | @@ -18,7 +18,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -18,7 +18,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 18 | .optimize = optimize, | 18 | .optimize = optimize, |
| 19 | .target = .{ .os_tag = .macos }, | 19 | .target = .{ .os_tag = .macos }, |
| 20 | }); | 20 | }); |
| 21 | lib.addCSourceFile("bootstrap.c", &.{}); | 21 | lib.addCSourceFile(.{ .file = .{ .path = "bootstrap.c" }, .flags = &.{} }); |
| 22 | lib.linkLibC(); | 22 | lib.linkLibC(); |
| 23 | lib.linker_allow_shlib_undefined = true; | 23 | lib.linker_allow_shlib_undefined = true; |
| 24 | 24 | ||
| ... | @@ -27,7 +27,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -27,7 +27,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 27 | .optimize = optimize, | 27 | .optimize = optimize, |
| 28 | .target = .{ .os_tag = .macos }, | 28 | .target = .{ .os_tag = .macos }, |
| 29 | }); | 29 | }); |
| 30 | exe.addCSourceFile("main.c", &.{}); | 30 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); |
| 31 | exe.linkLibrary(lib); | 31 | exe.linkLibrary(lib); |
| 32 | exe.linkLibC(); | 32 | exe.linkLibC(); |
| 33 | exe.entry_symbol_name = "_bootstrap"; | 33 | exe.entry_symbol_name = "_bootstrap"; |
test/link/macho/headerpad/build.zig+1-1| ... | @@ -113,7 +113,7 @@ fn simpleExe( | ... | @@ -113,7 +113,7 @@ fn simpleExe( |
| 113 | .name = name, | 113 | .name = name, |
| 114 | .optimize = optimize, | 114 | .optimize = optimize, |
| 115 | }); | 115 | }); |
| 116 | exe.addCSourceFile("main.c", &.{}); | 116 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); |
| 117 | exe.linkLibC(); | 117 | exe.linkLibC(); |
| 118 | exe.linkFramework("CoreFoundation"); | 118 | exe.linkFramework("CoreFoundation"); |
| 119 | exe.linkFramework("Foundation"); | 119 | exe.linkFramework("Foundation"); |
test/link/macho/needed_framework/build.zig+1-1| ... | @@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 20 | .name = "test", | 20 | .name = "test", |
| 21 | .optimize = optimize, | 21 | .optimize = optimize, |
| 22 | }); | 22 | }); |
| 23 | exe.addCSourceFile("main.c", &[0][]const u8{}); | 23 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &[0][]const u8{} }); |
| 24 | exe.linkLibC(); | 24 | exe.linkLibC(); |
| 25 | exe.linkFrameworkNeeded("Cocoa"); | 25 | exe.linkFrameworkNeeded("Cocoa"); |
| 26 | exe.dead_strip_dylibs = true; | 26 | exe.dead_strip_dylibs = true; |
test/link/macho/needed_library/build.zig+4-4| ... | @@ -21,7 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -21,7 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 21 | .optimize = optimize, | 21 | .optimize = optimize, |
| 22 | .target = target, | 22 | .target = target, |
| 23 | }); | 23 | }); |
| 24 | dylib.addCSourceFile("a.c", &.{}); | 24 | dylib.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); |
| 25 | dylib.linkLibC(); | 25 | dylib.linkLibC(); |
| 26 | 26 | ||
| 27 | // -dead_strip_dylibs | 27 | // -dead_strip_dylibs |
| ... | @@ -31,11 +31,11 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -31,11 +31,11 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 31 | .optimize = optimize, | 31 | .optimize = optimize, |
| 32 | .target = target, | 32 | .target = target, |
| 33 | }); | 33 | }); |
| 34 | exe.addCSourceFile("main.c", &[0][]const u8{}); | 34 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &[0][]const u8{} }); |
| 35 | exe.linkLibC(); | 35 | exe.linkLibC(); |
| 36 | exe.linkSystemLibraryNeeded("a"); | 36 | exe.linkSystemLibraryNeeded("a"); |
| 37 | exe.addLibraryPathDirectorySource(dylib.getOutputDirectorySource()); | 37 | exe.addLibraryPath(dylib.getEmittedBinDirectory()); |
| 38 | exe.addRPathDirectorySource(dylib.getOutputDirectorySource()); | 38 | exe.addRPath(dylib.getEmittedBinDirectory()); |
| 39 | exe.dead_strip_dylibs = true; | 39 | exe.dead_strip_dylibs = true; |
| 40 | 40 | ||
| 41 | const check = exe.checkObject(); | 41 | const check = exe.checkObject(); |
test/link/macho/objc/build.zig+3-3| ... | @@ -18,9 +18,9 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -18,9 +18,9 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 18 | .name = "test", | 18 | .name = "test", |
| 19 | .optimize = optimize, | 19 | .optimize = optimize, |
| 20 | }); | 20 | }); |
| 21 | exe.addIncludePath("."); | 21 | exe.addIncludePath(.{ .path = "." }); |
| 22 | exe.addCSourceFile("Foo.m", &[0][]const u8{}); | 22 | exe.addCSourceFile(.{ .file = .{ .path = "Foo.m" }, .flags = &[0][]const u8{} }); |
| 23 | exe.addCSourceFile("test.m", &[0][]const u8{}); | 23 | exe.addCSourceFile(.{ .file = .{ .path = "test.m" }, .flags = &[0][]const u8{} }); |
| 24 | exe.linkLibC(); | 24 | exe.linkLibC(); |
| 25 | // TODO when we figure out how to ship framework stubs for cross-compilation, | 25 | // TODO when we figure out how to ship framework stubs for cross-compilation, |
| 26 | // populate paths to the sysroot here. | 26 | // populate paths to the sysroot here. |
test/link/macho/objcpp/build.zig+3-3| ... | @@ -19,9 +19,9 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -19,9 +19,9 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 19 | .optimize = optimize, | 19 | .optimize = optimize, |
| 20 | }); | 20 | }); |
| 21 | b.default_step.dependOn(&exe.step); | 21 | b.default_step.dependOn(&exe.step); |
| 22 | exe.addIncludePath("."); | 22 | exe.addIncludePath(.{ .path = "." }); |
| 23 | exe.addCSourceFile("Foo.mm", &[0][]const u8{}); | 23 | exe.addCSourceFile(.{ .file = .{ .path = "Foo.mm" }, .flags = &[0][]const u8{} }); |
| 24 | exe.addCSourceFile("test.mm", &[0][]const u8{}); | 24 | exe.addCSourceFile(.{ .file = .{ .path = "test.mm" }, .flags = &[0][]const u8{} }); |
| 25 | exe.linkLibCpp(); | 25 | exe.linkLibCpp(); |
| 26 | // TODO when we figure out how to ship framework stubs for cross-compilation, | 26 | // TODO when we figure out how to ship framework stubs for cross-compilation, |
| 27 | // populate paths to the sysroot here. | 27 | // populate paths to the sysroot here. |
test/link/macho/pagezero/build.zig+2-2| ... | @@ -15,7 +15,7 @@ pub fn build(b: *std.Build) void { | ... | @@ -15,7 +15,7 @@ pub fn build(b: *std.Build) void { |
| 15 | .optimize = optimize, | 15 | .optimize = optimize, |
| 16 | .target = target, | 16 | .target = target, |
| 17 | }); | 17 | }); |
| 18 | exe.addCSourceFile("main.c", &.{}); | 18 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); |
| 19 | exe.linkLibC(); | 19 | exe.linkLibC(); |
| 20 | exe.pagezero_size = 0x4000; | 20 | exe.pagezero_size = 0x4000; |
| 21 | 21 | ||
| ... | @@ -39,7 +39,7 @@ pub fn build(b: *std.Build) void { | ... | @@ -39,7 +39,7 @@ pub fn build(b: *std.Build) void { |
| 39 | .optimize = optimize, | 39 | .optimize = optimize, |
| 40 | .target = target, | 40 | .target = target, |
| 41 | }); | 41 | }); |
| 42 | exe.addCSourceFile("main.c", &.{}); | 42 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); |
| 43 | exe.linkLibC(); | 43 | exe.linkLibC(); |
| 44 | exe.pagezero_size = 0; | 44 | exe.pagezero_size = 0; |
| 45 | 45 |
test/link/macho/search_strategy/build.zig+6-12| ... | @@ -55,11 +55,8 @@ fn createScenario( | ... | @@ -55,11 +55,8 @@ fn createScenario( |
| 55 | .optimize = optimize, | 55 | .optimize = optimize, |
| 56 | .target = target, | 56 | .target = target, |
| 57 | }); | 57 | }); |
| 58 | static.addCSourceFile("a.c", &.{}); | 58 | static.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); |
| 59 | static.linkLibC(); | 59 | static.linkLibC(); |
| 60 | static.override_dest_dir = std.Build.InstallDir{ | ||
| 61 | .custom = "static", | ||
| 62 | }; | ||
| 63 | 60 | ||
| 64 | const dylib = b.addSharedLibrary(.{ | 61 | const dylib = b.addSharedLibrary(.{ |
| 65 | .name = name, | 62 | .name = name, |
| ... | @@ -67,22 +64,19 @@ fn createScenario( | ... | @@ -67,22 +64,19 @@ fn createScenario( |
| 67 | .optimize = optimize, | 64 | .optimize = optimize, |
| 68 | .target = target, | 65 | .target = target, |
| 69 | }); | 66 | }); |
| 70 | dylib.addCSourceFile("a.c", &.{}); | 67 | dylib.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); |
| 71 | dylib.linkLibC(); | 68 | dylib.linkLibC(); |
| 72 | dylib.override_dest_dir = std.Build.InstallDir{ | ||
| 73 | .custom = "dynamic", | ||
| 74 | }; | ||
| 75 | 69 | ||
| 76 | const exe = b.addExecutable(.{ | 70 | const exe = b.addExecutable(.{ |
| 77 | .name = name, | 71 | .name = name, |
| 78 | .optimize = optimize, | 72 | .optimize = optimize, |
| 79 | .target = target, | 73 | .target = target, |
| 80 | }); | 74 | }); |
| 81 | exe.addCSourceFile("main.c", &.{}); | 75 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); |
| 82 | exe.linkSystemLibraryName(name); | 76 | exe.linkSystemLibraryName(name); |
| 83 | exe.linkLibC(); | 77 | exe.linkLibC(); |
| 84 | exe.addLibraryPathDirectorySource(static.getOutputDirectorySource()); | 78 | exe.addLibraryPath(static.getEmittedBinDirectory()); |
| 85 | exe.addLibraryPathDirectorySource(dylib.getOutputDirectorySource()); | 79 | exe.addLibraryPath(dylib.getEmittedBinDirectory()); |
| 86 | exe.addRPathDirectorySource(dylib.getOutputDirectorySource()); | 80 | exe.addRPath(dylib.getEmittedBinDirectory()); |
| 87 | return exe; | 81 | return exe; |
| 88 | } | 82 | } |
test/link/macho/stack_size/build.zig+1-1| ... | @@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 20 | .optimize = optimize, | 20 | .optimize = optimize, |
| 21 | .target = target, | 21 | .target = target, |
| 22 | }); | 22 | }); |
| 23 | exe.addCSourceFile("main.c", &.{}); | 23 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); |
| 24 | exe.linkLibC(); | 24 | exe.linkLibC(); |
| 25 | exe.stack_size = 0x100000000; | 25 | exe.stack_size = 0x100000000; |
| 26 | 26 |
test/link/macho/tbdv3/build.zig+4-4| ... | @@ -23,7 +23,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -23,7 +23,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 23 | .optimize = optimize, | 23 | .optimize = optimize, |
| 24 | .target = target, | 24 | .target = target, |
| 25 | }); | 25 | }); |
| 26 | lib.addCSourceFile("a.c", &.{}); | 26 | lib.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); |
| 27 | lib.linkLibC(); | 27 | lib.linkLibC(); |
| 28 | 28 | ||
| 29 | const tbd_file = b.addWriteFile("liba.tbd", | 29 | const tbd_file = b.addWriteFile("liba.tbd", |
| ... | @@ -43,10 +43,10 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -43,10 +43,10 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 43 | .optimize = optimize, | 43 | .optimize = optimize, |
| 44 | .target = target, | 44 | .target = target, |
| 45 | }); | 45 | }); |
| 46 | exe.addCSourceFile("main.c", &[0][]const u8{}); | 46 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &[0][]const u8{} }); |
| 47 | exe.linkSystemLibrary("a"); | 47 | exe.linkSystemLibrary("a"); |
| 48 | exe.addLibraryPathDirectorySource(tbd_file.getDirectorySource()); | 48 | exe.addLibraryPath(tbd_file.getDirectory()); |
| 49 | exe.addRPathDirectorySource(lib.getOutputDirectorySource()); | 49 | exe.addRPath(lib.getEmittedBinDirectory()); |
| 50 | exe.linkLibC(); | 50 | exe.linkLibC(); |
| 51 | 51 | ||
| 52 | const run = b.addRunArtifact(exe); | 52 | const run = b.addRunArtifact(exe); |
test/link/macho/tls/build.zig+1-1| ... | @@ -21,7 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -21,7 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 21 | .optimize = optimize, | 21 | .optimize = optimize, |
| 22 | .target = target, | 22 | .target = target, |
| 23 | }); | 23 | }); |
| 24 | lib.addCSourceFile("a.c", &.{}); | 24 | lib.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); |
| 25 | lib.linkLibC(); | 25 | lib.linkLibC(); |
| 26 | 26 | ||
| 27 | const test_exe = b.addTest(.{ | 27 | const test_exe = b.addTest(.{ |
test/link/macho/unwind_info/build.zig+1-1| ... | @@ -75,7 +75,7 @@ fn createScenario( | ... | @@ -75,7 +75,7 @@ fn createScenario( |
| 75 | .target = target, | 75 | .target = target, |
| 76 | }); | 76 | }); |
| 77 | b.default_step.dependOn(&exe.step); | 77 | b.default_step.dependOn(&exe.step); |
| 78 | exe.addIncludePath("."); | 78 | exe.addIncludePath(.{ .path = "." }); |
| 79 | exe.addCSourceFiles(&[_][]const u8{ | 79 | exe.addCSourceFiles(&[_][]const u8{ |
| 80 | "main.cpp", | 80 | "main.cpp", |
| 81 | "simple_string.cpp", | 81 | "simple_string.cpp", |
test/link/macho/weak_framework/build.zig+1-1| ... | @@ -18,7 +18,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -18,7 +18,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 18 | .name = "test", | 18 | .name = "test", |
| 19 | .optimize = optimize, | 19 | .optimize = optimize, |
| 20 | }); | 20 | }); |
| 21 | exe.addCSourceFile("main.c", &[0][]const u8{}); | 21 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &[0][]const u8{} }); |
| 22 | exe.linkLibC(); | 22 | exe.linkLibC(); |
| 23 | exe.linkFrameworkWeak("Cocoa"); | 23 | exe.linkFrameworkWeak("Cocoa"); |
| 24 | 24 |
test/link/macho/weak_library/build.zig+4-4| ... | @@ -21,7 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -21,7 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 21 | .target = target, | 21 | .target = target, |
| 22 | .optimize = optimize, | 22 | .optimize = optimize, |
| 23 | }); | 23 | }); |
| 24 | dylib.addCSourceFile("a.c", &.{}); | 24 | dylib.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); |
| 25 | dylib.linkLibC(); | 25 | dylib.linkLibC(); |
| 26 | b.installArtifact(dylib); | 26 | b.installArtifact(dylib); |
| 27 | 27 | ||
| ... | @@ -30,11 +30,11 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -30,11 +30,11 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 30 | .target = target, | 30 | .target = target, |
| 31 | .optimize = optimize, | 31 | .optimize = optimize, |
| 32 | }); | 32 | }); |
| 33 | exe.addCSourceFile("main.c", &[0][]const u8{}); | 33 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &[0][]const u8{} }); |
| 34 | exe.linkLibC(); | 34 | exe.linkLibC(); |
| 35 | exe.linkSystemLibraryWeak("a"); | 35 | exe.linkSystemLibraryWeak("a"); |
| 36 | exe.addLibraryPathDirectorySource(dylib.getOutputDirectorySource()); | 36 | exe.addLibraryPath(dylib.getEmittedBinDirectory()); |
| 37 | exe.addRPathDirectorySource(dylib.getOutputDirectorySource()); | 37 | exe.addRPath(dylib.getEmittedBinDirectory()); |
| 38 | 38 | ||
| 39 | const check = exe.checkObject(); | 39 | const check = exe.checkObject(); |
| 40 | check.checkStart(); | 40 | check.checkStart(); |
test/link/static_libs_from_object_files/build.zig+6-6| ... | @@ -2,7 +2,7 @@ const std = @import("std"); | ... | @@ -2,7 +2,7 @@ const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | 3 | ||
| 4 | const Build = std.Build; | 4 | const Build = std.Build; |
| 5 | const FileSource = Build.FileSource; | 5 | const LazyPath = Build.LazyPath; |
| 6 | const Step = Build.Step; | 6 | const Step = Build.Step; |
| 7 | const Run = Step.Run; | 7 | const Run = Step.Run; |
| 8 | const WriteFile = Step.WriteFile; | 8 | const WriteFile = Step.WriteFile; |
| ... | @@ -14,7 +14,7 @@ pub fn build(b: *Build) void { | ... | @@ -14,7 +14,7 @@ pub fn build(b: *Build) void { |
| 14 | b.default_step = test_step; | 14 | b.default_step = test_step; |
| 15 | 15 | ||
| 16 | // generate c files | 16 | // generate c files |
| 17 | const files = b.allocator.alloc(std.Build.FileSource, nb_files) catch unreachable; | 17 | const files = b.allocator.alloc(LazyPath, nb_files) catch unreachable; |
| 18 | defer b.allocator.free(files); | 18 | defer b.allocator.free(files); |
| 19 | { | 19 | { |
| 20 | for (files[0 .. nb_files - 1], 1..nb_files) |*file, i| { | 20 | for (files[0 .. nb_files - 1], 1..nb_files) |*file, i| { |
| ... | @@ -47,7 +47,7 @@ pub fn build(b: *Build) void { | ... | @@ -47,7 +47,7 @@ pub fn build(b: *Build) void { |
| 47 | add(b, test_step, files, .ReleaseFast); | 47 | add(b, test_step, files, .ReleaseFast); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | fn add(b: *Build, test_step: *Step, files: []const std.Build.FileSource, optimize: std.builtin.OptimizeMode) void { | 50 | fn add(b: *Build, test_step: *Step, files: []const LazyPath, optimize: std.builtin.OptimizeMode) void { |
| 51 | const flags = [_][]const u8{ | 51 | const flags = [_][]const u8{ |
| 52 | "-Wall", | 52 | "-Wall", |
| 53 | "-std=c11", | 53 | "-std=c11", |
| ... | @@ -63,7 +63,7 @@ fn add(b: *Build, test_step: *Step, files: []const std.Build.FileSource, optimiz | ... | @@ -63,7 +63,7 @@ fn add(b: *Build, test_step: *Step, files: []const std.Build.FileSource, optimiz |
| 63 | }); | 63 | }); |
| 64 | 64 | ||
| 65 | for (files) |file| { | 65 | for (files) |file| { |
| 66 | exe.addCSourceFileSource(.{ .source = file, .args = &flags }); | 66 | exe.addCSourceFile(.{ .file = file, .flags = &flags }); |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | const run_cmd = b.addRunArtifact(exe); | 69 | const run_cmd = b.addRunArtifact(exe); |
| ... | @@ -88,7 +88,7 @@ fn add(b: *Build, test_step: *Step, files: []const std.Build.FileSource, optimiz | ... | @@ -88,7 +88,7 @@ fn add(b: *Build, test_step: *Step, files: []const std.Build.FileSource, optimiz |
| 88 | 88 | ||
| 89 | for (files, 1..) |file, i| { | 89 | for (files, 1..) |file, i| { |
| 90 | const lib = if (i & 1 == 0) lib_a else lib_b; | 90 | const lib = if (i & 1 == 0) lib_a else lib_b; |
| 91 | lib.addCSourceFileSource(.{ .source = file, .args = &flags }); | 91 | lib.addCSourceFile(.{ .file = file, .flags = &flags }); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | const exe = b.addExecutable(.{ | 94 | const exe = b.addExecutable(.{ |
| ... | @@ -125,7 +125,7 @@ fn add(b: *Build, test_step: *Step, files: []const std.Build.FileSource, optimiz | ... | @@ -125,7 +125,7 @@ fn add(b: *Build, test_step: *Step, files: []const std.Build.FileSource, optimiz |
| 125 | .target = .{}, | 125 | .target = .{}, |
| 126 | .optimize = optimize, | 126 | .optimize = optimize, |
| 127 | }); | 127 | }); |
| 128 | obj.addCSourceFileSource(.{ .source = file, .args = &flags }); | 128 | obj.addCSourceFile(.{ .file = file, .flags = &flags }); |
| 129 | 129 | ||
| 130 | const lib = if (i & 1 == 0) lib_a else lib_b; | 130 | const lib = if (i & 1 == 0) lib_a else lib_b; |
| 131 | lib.addObject(obj); | 131 | lib.addObject(obj); |
test/link/wasm/extern/build.zig+1-1| ... | @@ -19,7 +19,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -19,7 +19,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 19 | .optimize = optimize, | 19 | .optimize = optimize, |
| 20 | .target = .{ .cpu_arch = .wasm32, .os_tag = .wasi }, | 20 | .target = .{ .cpu_arch = .wasm32, .os_tag = .wasi }, |
| 21 | }); | 21 | }); |
| 22 | exe.addCSourceFile("foo.c", &.{}); | 22 | exe.addCSourceFile(.{ .file = .{ .path = "foo.c" }, .flags = &.{} }); |
| 23 | exe.use_llvm = false; | 23 | exe.use_llvm = false; |
| 24 | exe.use_lld = false; | 24 | exe.use_lld = false; |
| 25 | 25 |
test/link/wasm/infer-features/build.zig+1-1| ... | @@ -13,7 +13,7 @@ pub fn build(b: *std.Build) void { | ... | @@ -13,7 +13,7 @@ pub fn build(b: *std.Build) void { |
| 13 | .os_tag = .freestanding, | 13 | .os_tag = .freestanding, |
| 14 | }, | 14 | }, |
| 15 | }); | 15 | }); |
| 16 | c_obj.addCSourceFile("foo.c", &.{}); | 16 | c_obj.addCSourceFile(.{ .file = .{ .path = "foo.c" }, .flags = &.{} }); |
| 17 | 17 | ||
| 18 | // Wasm library that doesn't have any features specified. This will | 18 | // Wasm library that doesn't have any features specified. This will |
| 19 | // infer its featureset from other linked object files. | 19 | // infer its featureset from other linked object files. |
test/src/Cases.zig+3-5| ... | @@ -518,12 +518,12 @@ pub fn lowerToBuildSteps( | ... | @@ -518,12 +518,12 @@ pub fn lowerToBuildSteps( |
| 518 | } | 518 | } |
| 519 | 519 | ||
| 520 | const writefiles = b.addWriteFiles(); | 520 | const writefiles = b.addWriteFiles(); |
| 521 | var file_sources = std.StringHashMap(std.Build.FileSource).init(b.allocator); | 521 | var file_sources = std.StringHashMap(std.Build.LazyPath).init(b.allocator); |
| 522 | defer file_sources.deinit(); | 522 | defer file_sources.deinit(); |
| 523 | for (update.files.items) |file| { | 523 | for (update.files.items) |file| { |
| 524 | file_sources.put(file.path, writefiles.add(file.path, file.src)) catch @panic("OOM"); | 524 | file_sources.put(file.path, writefiles.add(file.path, file.src)) catch @panic("OOM"); |
| 525 | } | 525 | } |
| 526 | const root_source_file = writefiles.files.items[0].getFileSource(); | 526 | const root_source_file = writefiles.files.items[0].getPath(); |
| 527 | 527 | ||
| 528 | const artifact = if (case.is_test) b.addTest(.{ | 528 | const artifact = if (case.is_test) b.addTest(.{ |
| 529 | .root_source_file = root_source_file, | 529 | .root_source_file = root_source_file, |
| ... | @@ -551,8 +551,6 @@ pub fn lowerToBuildSteps( | ... | @@ -551,8 +551,6 @@ pub fn lowerToBuildSteps( |
| 551 | }), | 551 | }), |
| 552 | }; | 552 | }; |
| 553 | 553 | ||
| 554 | artifact.emit_bin = if (case.emit_bin) .default else .no_emit; | ||
| 555 | |||
| 556 | if (case.link_libc) artifact.linkLibC(); | 554 | if (case.link_libc) artifact.linkLibC(); |
| 557 | 555 | ||
| 558 | switch (case.backend) { | 556 | switch (case.backend) { |
| ... | @@ -577,7 +575,7 @@ pub fn lowerToBuildSteps( | ... | @@ -577,7 +575,7 @@ pub fn lowerToBuildSteps( |
| 577 | parent_step.dependOn(&artifact.step); | 575 | parent_step.dependOn(&artifact.step); |
| 578 | }, | 576 | }, |
| 579 | .CompareObjectFile => |expected_output| { | 577 | .CompareObjectFile => |expected_output| { |
| 580 | const check = b.addCheckFile(artifact.getOutputSource(), .{ | 578 | const check = b.addCheckFile(artifact.getEmittedBin(), .{ |
| 581 | .expected_exact = expected_output, | 579 | .expected_exact = expected_output, |
| 582 | }); | 580 | }); |
| 583 | 581 |
test/src/CompareOutput.zig+3-3| ... | @@ -99,7 +99,7 @@ pub fn addCase(self: *CompareOutput, case: TestCase) void { | ... | @@ -99,7 +99,7 @@ pub fn addCase(self: *CompareOutput, case: TestCase) void { |
| 99 | .target = .{}, | 99 | .target = .{}, |
| 100 | .optimize = .Debug, | 100 | .optimize = .Debug, |
| 101 | }); | 101 | }); |
| 102 | exe.addAssemblyFileSource(write_src.files.items[0].getFileSource()); | 102 | exe.addAssemblyFile(write_src.files.items[0].getPath()); |
| 103 | 103 | ||
| 104 | const run = b.addRunArtifact(exe); | 104 | const run = b.addRunArtifact(exe); |
| 105 | run.setName(annotated_case_name); | 105 | run.setName(annotated_case_name); |
| ... | @@ -119,7 +119,7 @@ pub fn addCase(self: *CompareOutput, case: TestCase) void { | ... | @@ -119,7 +119,7 @@ pub fn addCase(self: *CompareOutput, case: TestCase) void { |
| 119 | 119 | ||
| 120 | const exe = b.addExecutable(.{ | 120 | const exe = b.addExecutable(.{ |
| 121 | .name = "test", | 121 | .name = "test", |
| 122 | .root_source_file = write_src.files.items[0].getFileSource(), | 122 | .root_source_file = write_src.files.items[0].getPath(), |
| 123 | .optimize = optimize, | 123 | .optimize = optimize, |
| 124 | .target = .{}, | 124 | .target = .{}, |
| 125 | }); | 125 | }); |
| ... | @@ -145,7 +145,7 @@ pub fn addCase(self: *CompareOutput, case: TestCase) void { | ... | @@ -145,7 +145,7 @@ pub fn addCase(self: *CompareOutput, case: TestCase) void { |
| 145 | 145 | ||
| 146 | const exe = b.addExecutable(.{ | 146 | const exe = b.addExecutable(.{ |
| 147 | .name = "test", | 147 | .name = "test", |
| 148 | .root_source_file = write_src.files.items[0].getFileSource(), | 148 | .root_source_file = write_src.files.items[0].getPath(), |
| 149 | .target = .{}, | 149 | .target = .{}, |
| 150 | .optimize = .Debug, | 150 | .optimize = .Debug, |
| 151 | }); | 151 | }); |
test/src/StackTrace.zig+2-2| ... | @@ -75,7 +75,7 @@ fn addExpect( | ... | @@ -75,7 +75,7 @@ fn addExpect( |
| 75 | const write_src = b.addWriteFile("source.zig", source); | 75 | const write_src = b.addWriteFile("source.zig", source); |
| 76 | const exe = b.addExecutable(.{ | 76 | const exe = b.addExecutable(.{ |
| 77 | .name = "test", | 77 | .name = "test", |
| 78 | .root_source_file = write_src.files.items[0].getFileSource(), | 78 | .root_source_file = write_src.files.items[0].getPath(), |
| 79 | .optimize = optimize_mode, | 79 | .optimize = optimize_mode, |
| 80 | .target = .{}, | 80 | .target = .{}, |
| 81 | }); | 81 | }); |
| ... | @@ -88,7 +88,7 @@ fn addExpect( | ... | @@ -88,7 +88,7 @@ fn addExpect( |
| 88 | 88 | ||
| 89 | const check_run = b.addRunArtifact(self.check_exe); | 89 | const check_run = b.addRunArtifact(self.check_exe); |
| 90 | check_run.setName(annotated_case_name); | 90 | check_run.setName(annotated_case_name); |
| 91 | check_run.addFileSourceArg(run.captureStdErr()); | 91 | check_run.addFileArg(run.captureStdErr()); |
| 92 | check_run.addArgs(&.{ | 92 | check_run.addArgs(&.{ |
| 93 | @tagName(optimize_mode), | 93 | @tagName(optimize_mode), |
| 94 | }); | 94 | }); |
test/src/run_translated_c.zig+1-1| ... | @@ -85,7 +85,7 @@ pub const RunTranslatedCContext = struct { | ... | @@ -85,7 +85,7 @@ pub const RunTranslatedCContext = struct { |
| 85 | _ = write_src.add(src_file.filename, src_file.source); | 85 | _ = write_src.add(src_file.filename, src_file.source); |
| 86 | } | 86 | } |
| 87 | const translate_c = b.addTranslateC(.{ | 87 | const translate_c = b.addTranslateC(.{ |
| 88 | .source_file = write_src.files.items[0].getFileSource(), | 88 | .source_file = write_src.files.items[0].getPath(), |
| 89 | .target = .{}, | 89 | .target = .{}, |
| 90 | .optimize = .Debug, | 90 | .optimize = .Debug, |
| 91 | }); | 91 | }); |
test/src/translate_c.zig+1-1| ... | @@ -108,7 +108,7 @@ pub const TranslateCContext = struct { | ... | @@ -108,7 +108,7 @@ pub const TranslateCContext = struct { |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | const translate_c = b.addTranslateC(.{ | 110 | const translate_c = b.addTranslateC(.{ |
| 111 | .source_file = write_src.files.items[0].getFileSource(), | 111 | .source_file = write_src.files.items[0].getPath(), |
| 112 | .target = case.target, | 112 | .target = case.target, |
| 113 | .optimize = .Debug, | 113 | .optimize = .Debug, |
| 114 | }); | 114 | }); |
test/standalone/c_compiler/build.zig+2-2| ... | @@ -19,7 +19,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -19,7 +19,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 19 | .optimize = optimize, | 19 | .optimize = optimize, |
| 20 | .target = target, | 20 | .target = target, |
| 21 | }); | 21 | }); |
| 22 | exe_c.addCSourceFile("test.c", &[0][]const u8{}); | 22 | exe_c.addCSourceFile(.{ .file = .{ .path = "test.c" }, .flags = &[0][]const u8{} }); |
| 23 | exe_c.linkLibC(); | 23 | exe_c.linkLibC(); |
| 24 | 24 | ||
| 25 | const exe_cpp = b.addExecutable(.{ | 25 | const exe_cpp = b.addExecutable(.{ |
| ... | @@ -28,7 +28,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -28,7 +28,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 28 | .target = target, | 28 | .target = target, |
| 29 | }); | 29 | }); |
| 30 | b.default_step.dependOn(&exe_cpp.step); | 30 | b.default_step.dependOn(&exe_cpp.step); |
| 31 | exe_cpp.addCSourceFile("test.cpp", &[0][]const u8{}); | 31 | exe_cpp.addCSourceFile(.{ .file = .{ .path = "test.cpp" }, .flags = &[0][]const u8{} }); |
| 32 | exe_cpp.linkLibCpp(); | 32 | exe_cpp.linkLibCpp(); |
| 33 | 33 | ||
| 34 | switch (target.getOsTag()) { | 34 | switch (target.getOsTag()) { |
test/standalone/coff_dwarf/build.zig+1-1| ... | @@ -23,7 +23,7 @@ pub fn build(b: *std.Build) void { | ... | @@ -23,7 +23,7 @@ pub fn build(b: *std.Build) void { |
| 23 | .optimize = optimize, | 23 | .optimize = optimize, |
| 24 | .target = target, | 24 | .target = target, |
| 25 | }); | 25 | }); |
| 26 | lib.addCSourceFile("shared_lib.c", &.{"-gdwarf"}); | 26 | lib.addCSourceFile(.{ .file = .{ .path = "shared_lib.c" }, .flags = &.{"-gdwarf"} }); |
| 27 | lib.linkLibC(); | 27 | lib.linkLibC(); |
| 28 | exe.linkLibrary(lib); | 28 | exe.linkLibrary(lib); |
| 29 | 29 |
test/standalone/compiler_rt_panic/build.zig+4-1| ... | @@ -16,7 +16,10 @@ pub fn build(b: *std.Build) void { | ... | @@ -16,7 +16,10 @@ pub fn build(b: *std.Build) void { |
| 16 | .target = target, | 16 | .target = target, |
| 17 | }); | 17 | }); |
| 18 | exe.linkLibC(); | 18 | exe.linkLibC(); |
| 19 | exe.addCSourceFile("main.c", &.{}); | 19 | exe.addCSourceFile(.{ |
| 20 | .file = .{ .path = "main.c" }, | ||
| 21 | .flags = &.{}, | ||
| 22 | }); | ||
| 20 | exe.link_gc_sections = false; | 23 | exe.link_gc_sections = false; |
| 21 | exe.bundle_compiler_rt = true; | 24 | exe.bundle_compiler_rt = true; |
| 22 | 25 |
test/standalone/embed_generated_file/build.zig+4-1| ... | @@ -19,8 +19,11 @@ pub fn build(b: *std.Build) void { | ... | @@ -19,8 +19,11 @@ pub fn build(b: *std.Build) void { |
| 19 | .optimize = .Debug, | 19 | .optimize = .Debug, |
| 20 | }); | 20 | }); |
| 21 | exe.addAnonymousModule("bootloader.elf", .{ | 21 | exe.addAnonymousModule("bootloader.elf", .{ |
| 22 | .source_file = bootloader.getOutputSource(), | 22 | .source_file = bootloader.getEmittedBin(), |
| 23 | }); | 23 | }); |
| 24 | 24 | ||
| 25 | // TODO: actually check the output | ||
| 26 | _ = exe.getEmittedBin(); | ||
| 27 | |||
| 25 | test_step.dependOn(&exe.step); | 28 | test_step.dependOn(&exe.step); |
| 26 | } | 29 | } |
test/standalone/emit_asm_and_bin/build.zig+3-2| ... | @@ -8,8 +8,9 @@ pub fn build(b: *std.Build) void { | ... | @@ -8,8 +8,9 @@ pub fn build(b: *std.Build) void { |
| 8 | .root_source_file = .{ .path = "main.zig" }, | 8 | .root_source_file = .{ .path = "main.zig" }, |
| 9 | .optimize = b.standardOptimizeOption(.{}), | 9 | .optimize = b.standardOptimizeOption(.{}), |
| 10 | }); | 10 | }); |
| 11 | main.emit_asm = .{ .emit_to = b.pathFromRoot("main.s") }; | 11 | // TODO: actually check these two artifacts for correctness |
| 12 | main.emit_bin = .{ .emit_to = b.pathFromRoot("main") }; | 12 | _ = main.getEmittedBin(); |
| 13 | _ = main.getEmittedAsm(); | ||
| 13 | 14 | ||
| 14 | test_step.dependOn(&b.addRunArtifact(main).step); | 15 | test_step.dependOn(&b.addRunArtifact(main).step); |
| 15 | } | 16 | } |
test/standalone/issue_12588/build.zig+2-3| ... | @@ -13,9 +13,8 @@ pub fn build(b: *std.Build) void { | ... | @@ -13,9 +13,8 @@ pub fn build(b: *std.Build) void { |
| 13 | .optimize = optimize, | 13 | .optimize = optimize, |
| 14 | .target = target, | 14 | .target = target, |
| 15 | }); | 15 | }); |
| 16 | obj.emit_llvm_ir = .{ .emit_to = b.pathFromRoot("main.ll") }; | 16 | _ = obj.getEmittedLlvmIr(); |
| 17 | obj.emit_llvm_bc = .{ .emit_to = b.pathFromRoot("main.bc") }; | 17 | _ = obj.getEmittedLlvmBc(); |
| 18 | obj.emit_bin = .no_emit; | ||
| 19 | b.default_step.dependOn(&obj.step); | 18 | b.default_step.dependOn(&obj.step); |
| 20 | 19 | ||
| 21 | test_step.dependOn(&obj.step); | 20 | test_step.dependOn(&obj.step); |
test/standalone/issue_339/build.zig+3| ... | @@ -14,5 +14,8 @@ pub fn build(b: *std.Build) void { | ... | @@ -14,5 +14,8 @@ pub fn build(b: *std.Build) void { |
| 14 | .optimize = optimize, | 14 | .optimize = optimize, |
| 15 | }); | 15 | }); |
| 16 | 16 | ||
| 17 | // TODO: actually check the output | ||
| 18 | _ = obj.getEmittedBin(); | ||
| 19 | |||
| 17 | test_step.dependOn(&obj.step); | 20 | test_step.dependOn(&obj.step); |
| 18 | } | 21 | } |
test/standalone/issue_5825/build.zig+3| ... | @@ -27,5 +27,8 @@ pub fn build(b: *std.Build) void { | ... | @@ -27,5 +27,8 @@ pub fn build(b: *std.Build) void { |
| 27 | exe.linkSystemLibrary("ntdll"); | 27 | exe.linkSystemLibrary("ntdll"); |
| 28 | exe.addObject(obj); | 28 | exe.addObject(obj); |
| 29 | 29 | ||
| 30 | // TODO: actually check the output | ||
| 31 | _ = exe.getEmittedBin(); | ||
| 32 | |||
| 30 | test_step.dependOn(&exe.step); | 33 | test_step.dependOn(&exe.step); |
| 31 | } | 34 | } |
test/standalone/issue_794/build.zig+4-1| ... | @@ -7,7 +7,10 @@ pub fn build(b: *std.Build) void { | ... | @@ -7,7 +7,10 @@ pub fn build(b: *std.Build) void { |
| 7 | const test_artifact = b.addTest(.{ | 7 | const test_artifact = b.addTest(.{ |
| 8 | .root_source_file = .{ .path = "main.zig" }, | 8 | .root_source_file = .{ .path = "main.zig" }, |
| 9 | }); | 9 | }); |
| 10 | test_artifact.addIncludePath("a_directory"); | 10 | test_artifact.addIncludePath(.{ .path = "a_directory" }); |
| 11 | |||
| 12 | // TODO: actually check the output | ||
| 13 | _ = test_artifact.getEmittedBin(); | ||
| 11 | 14 | ||
| 12 | test_step.dependOn(&test_artifact.step); | 15 | test_step.dependOn(&test_artifact.step); |
| 13 | } | 16 | } |
test/standalone/issue_8550/build.zig+2-2| ... | @@ -19,8 +19,8 @@ pub fn build(b: *std.Build) !void { | ... | @@ -19,8 +19,8 @@ pub fn build(b: *std.Build) !void { |
| 19 | .optimize = optimize, | 19 | .optimize = optimize, |
| 20 | .target = target, | 20 | .target = target, |
| 21 | }); | 21 | }); |
| 22 | kernel.addObjectFile("./boot.S"); | 22 | kernel.addObjectFile(.{ .path = "./boot.S" }); |
| 23 | kernel.setLinkerScriptPath(.{ .path = "./linker.ld" }); | 23 | kernel.setLinkerScript(.{ .path = "./linker.ld" }); |
| 24 | b.installArtifact(kernel); | 24 | b.installArtifact(kernel); |
| 25 | 25 | ||
| 26 | test_step.dependOn(&kernel.step); | 26 | test_step.dependOn(&kernel.step); |
test/standalone/main_pkg_path/build.zig+1-1| ... | @@ -6,8 +6,8 @@ pub fn build(b: *std.Build) void { | ... | @@ -6,8 +6,8 @@ pub fn build(b: *std.Build) void { |
| 6 | 6 | ||
| 7 | const test_exe = b.addTest(.{ | 7 | const test_exe = b.addTest(.{ |
| 8 | .root_source_file = .{ .path = "a/test.zig" }, | 8 | .root_source_file = .{ .path = "a/test.zig" }, |
| 9 | .main_pkg_path = .{ .path = "." }, | ||
| 9 | }); | 10 | }); |
| 10 | test_exe.setMainPkgPath("."); | ||
| 11 | 11 | ||
| 12 | test_step.dependOn(&b.addRunArtifact(test_exe).step); | 12 | test_step.dependOn(&b.addRunArtifact(test_exe).step); |
| 13 | } | 13 | } |
test/standalone/mix_c_files/build.zig+1-1| ... | @@ -21,7 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -21,7 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 21 | .root_source_file = .{ .path = "main.zig" }, | 21 | .root_source_file = .{ .path = "main.zig" }, |
| 22 | .optimize = optimize, | 22 | .optimize = optimize, |
| 23 | }); | 23 | }); |
| 24 | exe.addCSourceFile("test.c", &[_][]const u8{"-std=c11"}); | 24 | exe.addCSourceFile(.{ .file = .{ .path = "test.c" }, .flags = &[_][]const u8{"-std=c11"} }); |
| 25 | exe.linkLibC(); | 25 | exe.linkLibC(); |
| 26 | 26 | ||
| 27 | const run_cmd = b.addRunArtifact(exe); | 27 | const run_cmd = b.addRunArtifact(exe); |
test/standalone/mix_o_files/build.zig+4-1| ... | @@ -19,7 +19,10 @@ pub fn build(b: *std.Build) void { | ... | @@ -19,7 +19,10 @@ pub fn build(b: *std.Build) void { |
| 19 | .optimize = optimize, | 19 | .optimize = optimize, |
| 20 | .target = target, | 20 | .target = target, |
| 21 | }); | 21 | }); |
| 22 | exe.addCSourceFile("test.c", &[_][]const u8{"-std=c99"}); | 22 | exe.addCSourceFile(.{ |
| 23 | .file = .{ .path = "test.c" }, | ||
| 24 | .flags = &[_][]const u8{"-std=c99"}, | ||
| 25 | }); | ||
| 23 | exe.addObject(obj); | 26 | exe.addObject(obj); |
| 24 | exe.linkSystemLibrary("c"); | 27 | exe.linkSystemLibrary("c"); |
| 25 | 28 |
test/standalone/shared_library/build.zig+4-1| ... | @@ -19,7 +19,10 @@ pub fn build(b: *std.Build) void { | ... | @@ -19,7 +19,10 @@ pub fn build(b: *std.Build) void { |
| 19 | .target = target, | 19 | .target = target, |
| 20 | .optimize = optimize, | 20 | .optimize = optimize, |
| 21 | }); | 21 | }); |
| 22 | exe.addCSourceFile("test.c", &[_][]const u8{"-std=c99"}); | 22 | exe.addCSourceFile(.{ |
| 23 | .file = .{ .path = "test.c" }, | ||
| 24 | .flags = &[_][]const u8{"-std=c99"}, | ||
| 25 | }); | ||
| 23 | exe.linkLibrary(lib); | 26 | exe.linkLibrary(lib); |
| 24 | exe.linkSystemLibrary("c"); | 27 | exe.linkSystemLibrary("c"); |
| 25 | 28 |
test/standalone/stack_iterator/build.zig+4-1| ... | @@ -74,7 +74,10 @@ pub fn build(b: *std.Build) void { | ... | @@ -74,7 +74,10 @@ pub fn build(b: *std.Build) void { |
| 74 | if (target.isWindows()) c_shared_lib.defineCMacro("LIB_API", "__declspec(dllexport)"); | 74 | if (target.isWindows()) c_shared_lib.defineCMacro("LIB_API", "__declspec(dllexport)"); |
| 75 | 75 | ||
| 76 | c_shared_lib.strip = false; | 76 | c_shared_lib.strip = false; |
| 77 | c_shared_lib.addCSourceFile("shared_lib.c", &.{"-fomit-frame-pointer"}); | 77 | c_shared_lib.addCSourceFile(.{ |
| 78 | .file = .{ .path = "shared_lib.c" }, | ||
| 79 | .flags = &.{"-fomit-frame-pointer"}, | ||
| 80 | }); | ||
| 78 | c_shared_lib.linkLibC(); | 81 | c_shared_lib.linkLibC(); |
| 79 | 82 | ||
| 80 | const exe = b.addExecutable(.{ | 83 | const exe = b.addExecutable(.{ |
test/standalone/static_c_lib/build.zig+3-3| ... | @@ -11,15 +11,15 @@ pub fn build(b: *std.Build) void { | ... | @@ -11,15 +11,15 @@ pub fn build(b: *std.Build) void { |
| 11 | .optimize = optimize, | 11 | .optimize = optimize, |
| 12 | .target = .{}, | 12 | .target = .{}, |
| 13 | }); | 13 | }); |
| 14 | foo.addCSourceFile("foo.c", &[_][]const u8{}); | 14 | foo.addCSourceFile(.{ .file = .{ .path = "foo.c" }, .flags = &[_][]const u8{} }); |
| 15 | foo.addIncludePath("."); | 15 | foo.addIncludePath(.{ .path = "." }); |
| 16 | 16 | ||
| 17 | const test_exe = b.addTest(.{ | 17 | const test_exe = b.addTest(.{ |
| 18 | .root_source_file = .{ .path = "foo.zig" }, | 18 | .root_source_file = .{ .path = "foo.zig" }, |
| 19 | .optimize = optimize, | 19 | .optimize = optimize, |
| 20 | }); | 20 | }); |
| 21 | test_exe.linkLibrary(foo); | 21 | test_exe.linkLibrary(foo); |
| 22 | test_exe.addIncludePath("."); | 22 | test_exe.addIncludePath(.{ .path = "." }); |
| 23 | 23 | ||
| 24 | test_step.dependOn(&b.addRunArtifact(test_exe).step); | 24 | test_step.dependOn(&b.addRunArtifact(test_exe).step); |
| 25 | } | 25 | } |
test/standalone/strip_empty_loop/build.zig+4| ... | @@ -14,5 +14,9 @@ pub fn build(b: *std.Build) void { | ... | @@ -14,5 +14,9 @@ pub fn build(b: *std.Build) void { |
| 14 | .target = target, | 14 | .target = target, |
| 15 | }); | 15 | }); |
| 16 | main.strip = true; | 16 | main.strip = true; |
| 17 | |||
| 18 | // TODO: actually check the output | ||
| 19 | _ = main.getEmittedBin(); | ||
| 20 | |||
| 17 | test_step.dependOn(&main.step); | 21 | test_step.dependOn(&main.step); |
| 18 | } | 22 | } |
test/standalone/use_alias/build.zig+1-1| ... | @@ -10,7 +10,7 @@ pub fn build(b: *std.Build) void { | ... | @@ -10,7 +10,7 @@ pub fn build(b: *std.Build) void { |
| 10 | .root_source_file = .{ .path = "main.zig" }, | 10 | .root_source_file = .{ .path = "main.zig" }, |
| 11 | .optimize = optimize, | 11 | .optimize = optimize, |
| 12 | }); | 12 | }); |
| 13 | main.addIncludePath("."); | 13 | main.addIncludePath(.{ .path = "." }); |
| 14 | 14 | ||
| 15 | test_step.dependOn(&b.addRunArtifact(main).step); | 15 | test_step.dependOn(&b.addRunArtifact(main).step); |
| 16 | } | 16 | } |
test/tests.zig+14-9| ... | @@ -588,6 +588,8 @@ pub fn addStandaloneTests( | ... | @@ -588,6 +588,8 @@ pub fn addStandaloneTests( |
| 588 | }); | 588 | }); |
| 589 | if (case.link_libc) exe.linkLibC(); | 589 | if (case.link_libc) exe.linkLibC(); |
| 590 | 590 | ||
| 591 | _ = exe.getEmittedBin(); | ||
| 592 | |||
| 591 | step.dependOn(&exe.step); | 593 | step.dependOn(&exe.step); |
| 592 | } | 594 | } |
| 593 | 595 | ||
| ... | @@ -759,7 +761,7 @@ pub fn addCliTests(b: *std.Build) *Step { | ... | @@ -759,7 +761,7 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 759 | "-fno-emit-bin", "-fno-emit-h", | 761 | "-fno-emit-bin", "-fno-emit-h", |
| 760 | "-fstrip", "-OReleaseFast", | 762 | "-fstrip", "-OReleaseFast", |
| 761 | }); | 763 | }); |
| 762 | run.addFileSourceArg(writefile.files.items[0].getFileSource()); | 764 | run.addFileArg(writefile.files.items[0].getPath()); |
| 763 | const example_s = run.addPrefixedOutputFileArg("-femit-asm=", "example.s"); | 765 | const example_s = run.addPrefixedOutputFileArg("-femit-asm=", "example.s"); |
| 764 | 766 | ||
| 765 | const checkfile = b.addCheckFile(example_s, .{ | 767 | const checkfile = b.addCheckFile(example_s, .{ |
| ... | @@ -1006,6 +1008,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { | ... | @@ -1006,6 +1008,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 1006 | .single_threaded = test_target.single_threaded, | 1008 | .single_threaded = test_target.single_threaded, |
| 1007 | .use_llvm = test_target.use_llvm, | 1009 | .use_llvm = test_target.use_llvm, |
| 1008 | .use_lld = test_target.use_lld, | 1010 | .use_lld = test_target.use_lld, |
| 1011 | .zig_lib_dir = .{ .path = "lib" }, | ||
| 1009 | }); | 1012 | }); |
| 1010 | const single_threaded_suffix = if (test_target.single_threaded == true) "-single" else ""; | 1013 | const single_threaded_suffix = if (test_target.single_threaded == true) "-single" else ""; |
| 1011 | const backend_suffix = if (test_target.use_llvm == true) | 1014 | const backend_suffix = if (test_target.use_llvm == true) |
| ... | @@ -1017,8 +1020,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { | ... | @@ -1017,8 +1020,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 1017 | else | 1020 | else |
| 1018 | ""; | 1021 | ""; |
| 1019 | 1022 | ||
| 1020 | these_tests.overrideZigLibDir("lib"); | 1023 | these_tests.addIncludePath(.{ .path = "test" }); |
| 1021 | these_tests.addIncludePath("test"); | ||
| 1022 | 1024 | ||
| 1023 | const qualified_name = b.fmt("{s}-{s}-{s}{s}{s}{s}", .{ | 1025 | const qualified_name = b.fmt("{s}-{s}-{s}{s}{s}{s}", .{ |
| 1024 | options.name, | 1026 | options.name, |
| ... | @@ -1037,11 +1039,11 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { | ... | @@ -1037,11 +1039,11 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 1037 | .name = qualified_name, | 1039 | .name = qualified_name, |
| 1038 | .link_libc = test_target.link_libc, | 1040 | .link_libc = test_target.link_libc, |
| 1039 | .target = altered_target, | 1041 | .target = altered_target, |
| 1042 | .zig_lib_dir = .{ .path = "lib" }, | ||
| 1040 | }); | 1043 | }); |
| 1041 | compile_c.overrideZigLibDir("lib"); | 1044 | compile_c.addCSourceFile(.{ |
| 1042 | compile_c.addCSourceFileSource(.{ | 1045 | .file = these_tests.getEmittedBin(), |
| 1043 | .source = these_tests.getOutputSource(), | 1046 | .flags = &.{ |
| 1044 | .args = &.{ | ||
| 1045 | // TODO output -std=c89 compatible C code | 1047 | // TODO output -std=c89 compatible C code |
| 1046 | "-std=c99", | 1048 | "-std=c99", |
| 1047 | "-pedantic", | 1049 | "-pedantic", |
| ... | @@ -1058,7 +1060,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { | ... | @@ -1058,7 +1060,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 1058 | "-Wno-absolute-value", | 1060 | "-Wno-absolute-value", |
| 1059 | }, | 1061 | }, |
| 1060 | }); | 1062 | }); |
| 1061 | compile_c.addIncludePath("lib"); // for zig.h | 1063 | compile_c.addIncludePath(.{ .path = "lib" }); // for zig.h |
| 1062 | if (test_target.target.getOsTag() == .windows) { | 1064 | if (test_target.target.getOsTag() == .windows) { |
| 1063 | if (true) { | 1065 | if (true) { |
| 1064 | // Unfortunately this requires about 8G of RAM for clang to compile | 1066 | // Unfortunately this requires about 8G of RAM for clang to compile |
| ... | @@ -1131,7 +1133,10 @@ pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *S | ... | @@ -1131,7 +1133,10 @@ pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *S |
| 1131 | test_step.target_info.dynamic_linker.max_byte = null; | 1133 | test_step.target_info.dynamic_linker.max_byte = null; |
| 1132 | } | 1134 | } |
| 1133 | test_step.linkLibC(); | 1135 | test_step.linkLibC(); |
| 1134 | test_step.addCSourceFile("test/c_abi/cfuncs.c", &.{"-std=c99"}); | 1136 | test_step.addCSourceFile(.{ |
| 1137 | .file = .{ .path = "test/c_abi/cfuncs.c" }, | ||
| 1138 | .flags = &.{"-std=c99"}, | ||
| 1139 | }); | ||
| 1135 | 1140 | ||
| 1136 | // This test is intentionally trying to check if the external ABI is | 1141 | // This test is intentionally trying to check if the external ABI is |
| 1137 | // done properly. LTO would be a hindrance to this. | 1142 | // done properly. LTO would be a hindrance to this. |
tools/docgen.zig created+2278| ... | @@ -0,0 +1,2278 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const io = std.io; | ||
| 4 | const fs = std.fs; | ||
| 5 | const process = std.process; | ||
| 6 | const ChildProcess = std.ChildProcess; | ||
| 7 | const Progress = std.Progress; | ||
| 8 | const print = std.debug.print; | ||
| 9 | const mem = std.mem; | ||
| 10 | const testing = std.testing; | ||
| 11 | const Allocator = std.mem.Allocator; | ||
| 12 | |||
| 13 | const max_doc_file_size = 10 * 1024 * 1024; | ||
| 14 | |||
| 15 | const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt(); | ||
| 16 | const obj_ext = builtin.object_format.fileExt(builtin.cpu.arch); | ||
| 17 | const tmp_dir_name = "docgen_tmp"; | ||
| 18 | const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext; | ||
| 19 | |||
| 20 | const usage = | ||
| 21 | \\Usage: docgen [--zig] [--skip-code-tests] input output" | ||
| 22 | \\ | ||
| 23 | \\ Generates an HTML document from a docgen template. | ||
| 24 | \\ | ||
| 25 | \\Options: | ||
| 26 | \\ -h, --help Print this help and exit | ||
| 27 | \\ --skip-code-tests Skip the doctests | ||
| 28 | \\ | ||
| 29 | ; | ||
| 30 | |||
| 31 | fn fatal(comptime format: []const u8, args: anytype) noreturn { | ||
| 32 | const stderr = io.getStdErr().writer(); | ||
| 33 | |||
| 34 | stderr.print("error: " ++ format ++ "\n", args) catch {}; | ||
| 35 | process.exit(1); | ||
| 36 | } | ||
| 37 | |||
| 38 | pub fn main() !void { | ||
| 39 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||
| 40 | defer arena.deinit(); | ||
| 41 | |||
| 42 | const allocator = arena.allocator(); | ||
| 43 | |||
| 44 | var args_it = try process.argsWithAllocator(allocator); | ||
| 45 | if (!args_it.skip()) @panic("expected self arg"); | ||
| 46 | |||
| 47 | var zig_exe: []const u8 = "zig"; | ||
| 48 | var opt_zig_lib_dir: ?[]const u8 = null; | ||
| 49 | var do_code_tests = true; | ||
| 50 | var files = [_][]const u8{ "", "" }; | ||
| 51 | |||
| 52 | var i: usize = 0; | ||
| 53 | while (args_it.next()) |arg| { | ||
| 54 | if (mem.startsWith(u8, arg, "-")) { | ||
| 55 | if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { | ||
| 56 | const stdout = io.getStdOut().writer(); | ||
| 57 | try stdout.writeAll(usage); | ||
| 58 | process.exit(0); | ||
| 59 | } else if (mem.eql(u8, arg, "--zig")) { | ||
| 60 | if (args_it.next()) |param| { | ||
| 61 | zig_exe = param; | ||
| 62 | } else { | ||
| 63 | fatal("expected parameter after --zig", .{}); | ||
| 64 | } | ||
| 65 | } else if (mem.eql(u8, arg, "--zig-lib-dir")) { | ||
| 66 | if (args_it.next()) |param| { | ||
| 67 | // Convert relative to absolute because this will be passed | ||
| 68 | // to a child process with a different cwd. | ||
| 69 | opt_zig_lib_dir = try fs.realpathAlloc(allocator, param); | ||
| 70 | } else { | ||
| 71 | fatal("expected parameter after --zig-lib-dir", .{}); | ||
| 72 | } | ||
| 73 | } else if (mem.eql(u8, arg, "--skip-code-tests")) { | ||
| 74 | do_code_tests = false; | ||
| 75 | } else { | ||
| 76 | fatal("unrecognized option: '{s}'", .{arg}); | ||
| 77 | } | ||
| 78 | } else { | ||
| 79 | if (i > 1) { | ||
| 80 | fatal("too many arguments", .{}); | ||
| 81 | } | ||
| 82 | files[i] = arg; | ||
| 83 | i += 1; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | if (i < 2) { | ||
| 87 | fatal("not enough arguments", .{}); | ||
| 88 | } | ||
| 89 | |||
| 90 | var in_file = try fs.cwd().openFile(files[0], .{ .mode = .read_only }); | ||
| 91 | defer in_file.close(); | ||
| 92 | |||
| 93 | var out_file = try fs.cwd().createFile(files[1], .{}); | ||
| 94 | defer out_file.close(); | ||
| 95 | |||
| 96 | const input_file_bytes = try in_file.reader().readAllAlloc(allocator, max_doc_file_size); | ||
| 97 | |||
| 98 | var buffered_writer = io.bufferedWriter(out_file.writer()); | ||
| 99 | |||
| 100 | var tokenizer = Tokenizer.init(files[0], input_file_bytes); | ||
| 101 | var toc = try genToc(allocator, &tokenizer); | ||
| 102 | |||
| 103 | try fs.cwd().makePath(tmp_dir_name); | ||
| 104 | defer fs.cwd().deleteTree(tmp_dir_name) catch {}; | ||
| 105 | |||
| 106 | try genHtml(allocator, &tokenizer, &toc, buffered_writer.writer(), zig_exe, opt_zig_lib_dir, do_code_tests); | ||
| 107 | try buffered_writer.flush(); | ||
| 108 | } | ||
| 109 | |||
| 110 | const Token = struct { | ||
| 111 | id: Id, | ||
| 112 | start: usize, | ||
| 113 | end: usize, | ||
| 114 | |||
| 115 | const Id = enum { | ||
| 116 | invalid, | ||
| 117 | content, | ||
| 118 | bracket_open, | ||
| 119 | tag_content, | ||
| 120 | separator, | ||
| 121 | bracket_close, | ||
| 122 | eof, | ||
| 123 | }; | ||
| 124 | }; | ||
| 125 | |||
| 126 | const Tokenizer = struct { | ||
| 127 | buffer: []const u8, | ||
| 128 | index: usize, | ||
| 129 | state: State, | ||
| 130 | source_file_name: []const u8, | ||
| 131 | code_node_count: usize, | ||
| 132 | |||
| 133 | const State = enum { | ||
| 134 | start, | ||
| 135 | l_bracket, | ||
| 136 | hash, | ||
| 137 | tag_name, | ||
| 138 | eof, | ||
| 139 | }; | ||
| 140 | |||
| 141 | fn init(source_file_name: []const u8, buffer: []const u8) Tokenizer { | ||
| 142 | return Tokenizer{ | ||
| 143 | .buffer = buffer, | ||
| 144 | .index = 0, | ||
| 145 | .state = .start, | ||
| 146 | .source_file_name = source_file_name, | ||
| 147 | .code_node_count = 0, | ||
| 148 | }; | ||
| 149 | } | ||
| 150 | |||
| 151 | fn next(self: *Tokenizer) Token { | ||
| 152 | var result = Token{ | ||
| 153 | .id = .eof, | ||
| 154 | .start = self.index, | ||
| 155 | .end = undefined, | ||
| 156 | }; | ||
| 157 | while (self.index < self.buffer.len) : (self.index += 1) { | ||
| 158 | const c = self.buffer[self.index]; | ||
| 159 | switch (self.state) { | ||
| 160 | .start => switch (c) { | ||
| 161 | '{' => { | ||
| 162 | self.state = .l_bracket; | ||
| 163 | }, | ||
| 164 | else => { | ||
| 165 | result.id = .content; | ||
| 166 | }, | ||
| 167 | }, | ||
| 168 | .l_bracket => switch (c) { | ||
| 169 | '#' => { | ||
| 170 | if (result.id != .eof) { | ||
| 171 | self.index -= 1; | ||
| 172 | self.state = .start; | ||
| 173 | break; | ||
| 174 | } else { | ||
| 175 | result.id = .bracket_open; | ||
| 176 | self.index += 1; | ||
| 177 | self.state = .tag_name; | ||
| 178 | break; | ||
| 179 | } | ||
| 180 | }, | ||
| 181 | else => { | ||
| 182 | result.id = .content; | ||
| 183 | self.state = .start; | ||
| 184 | }, | ||
| 185 | }, | ||
| 186 | .tag_name => switch (c) { | ||
| 187 | '|' => { | ||
| 188 | if (result.id != .eof) { | ||
| 189 | break; | ||
| 190 | } else { | ||
| 191 | result.id = .separator; | ||
| 192 | self.index += 1; | ||
| 193 | break; | ||
| 194 | } | ||
| 195 | }, | ||
| 196 | '#' => { | ||
| 197 | self.state = .hash; | ||
| 198 | }, | ||
| 199 | else => { | ||
| 200 | result.id = .tag_content; | ||
| 201 | }, | ||
| 202 | }, | ||
| 203 | .hash => switch (c) { | ||
| 204 | '}' => { | ||
| 205 | if (result.id != .eof) { | ||
| 206 | self.index -= 1; | ||
| 207 | self.state = .tag_name; | ||
| 208 | break; | ||
| 209 | } else { | ||
| 210 | result.id = .bracket_close; | ||
| 211 | self.index += 1; | ||
| 212 | self.state = .start; | ||
| 213 | break; | ||
| 214 | } | ||
| 215 | }, | ||
| 216 | else => { | ||
| 217 | result.id = .tag_content; | ||
| 218 | self.state = .tag_name; | ||
| 219 | }, | ||
| 220 | }, | ||
| 221 | .eof => unreachable, | ||
| 222 | } | ||
| 223 | } else { | ||
| 224 | switch (self.state) { | ||
| 225 | .start, .l_bracket, .eof => {}, | ||
| 226 | else => { | ||
| 227 | result.id = .invalid; | ||
| 228 | }, | ||
| 229 | } | ||
| 230 | self.state = .eof; | ||
| 231 | } | ||
| 232 | result.end = self.index; | ||
| 233 | return result; | ||
| 234 | } | ||
| 235 | |||
| 236 | const Location = struct { | ||
| 237 | line: usize, | ||
| 238 | column: usize, | ||
| 239 | line_start: usize, | ||
| 240 | line_end: usize, | ||
| 241 | }; | ||
| 242 | |||
| 243 | fn getTokenLocation(self: *Tokenizer, token: Token) Location { | ||
| 244 | var loc = Location{ | ||
| 245 | .line = 0, | ||
| 246 | .column = 0, | ||
| 247 | .line_start = 0, | ||
| 248 | .line_end = 0, | ||
| 249 | }; | ||
| 250 | for (self.buffer, 0..) |c, i| { | ||
| 251 | if (i == token.start) { | ||
| 252 | loc.line_end = i; | ||
| 253 | while (loc.line_end < self.buffer.len and self.buffer[loc.line_end] != '\n') : (loc.line_end += 1) {} | ||
| 254 | return loc; | ||
| 255 | } | ||
| 256 | if (c == '\n') { | ||
| 257 | loc.line += 1; | ||
| 258 | loc.column = 0; | ||
| 259 | loc.line_start = i + 1; | ||
| 260 | } else { | ||
| 261 | loc.column += 1; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | return loc; | ||
| 265 | } | ||
| 266 | }; | ||
| 267 | |||
| 268 | fn parseError(tokenizer: *Tokenizer, token: Token, comptime fmt: []const u8, args: anytype) anyerror { | ||
| 269 | const loc = tokenizer.getTokenLocation(token); | ||
| 270 | const args_prefix = .{ tokenizer.source_file_name, loc.line + 1, loc.column + 1 }; | ||
| 271 | print("{s}:{d}:{d}: error: " ++ fmt ++ "\n", args_prefix ++ args); | ||
| 272 | if (loc.line_start <= loc.line_end) { | ||
| 273 | print("{s}\n", .{tokenizer.buffer[loc.line_start..loc.line_end]}); | ||
| 274 | { | ||
| 275 | var i: usize = 0; | ||
| 276 | while (i < loc.column) : (i += 1) { | ||
| 277 | print(" ", .{}); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | { | ||
| 281 | const caret_count = @min(token.end, loc.line_end) - token.start; | ||
| 282 | var i: usize = 0; | ||
| 283 | while (i < caret_count) : (i += 1) { | ||
| 284 | print("~", .{}); | ||
| 285 | } | ||
| 286 | } | ||
| 287 | print("\n", .{}); | ||
| 288 | } | ||
| 289 | return error.ParseError; | ||
| 290 | } | ||
| 291 | |||
| 292 | fn assertToken(tokenizer: *Tokenizer, token: Token, id: Token.Id) !void { | ||
| 293 | if (token.id != id) { | ||
| 294 | return parseError(tokenizer, token, "expected {s}, found {s}", .{ @tagName(id), @tagName(token.id) }); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | fn eatToken(tokenizer: *Tokenizer, id: Token.Id) !Token { | ||
| 299 | const token = tokenizer.next(); | ||
| 300 | try assertToken(tokenizer, token, id); | ||
| 301 | return token; | ||
| 302 | } | ||
| 303 | |||
| 304 | const HeaderOpen = struct { | ||
| 305 | name: []const u8, | ||
| 306 | url: []const u8, | ||
| 307 | n: usize, | ||
| 308 | }; | ||
| 309 | |||
| 310 | const SeeAlsoItem = struct { | ||
| 311 | name: []const u8, | ||
| 312 | token: Token, | ||
| 313 | }; | ||
| 314 | |||
| 315 | const ExpectedOutcome = enum { | ||
| 316 | succeed, | ||
| 317 | fail, | ||
| 318 | build_fail, | ||
| 319 | }; | ||
| 320 | |||
| 321 | const Code = struct { | ||
| 322 | id: Id, | ||
| 323 | name: []const u8, | ||
| 324 | source_token: Token, | ||
| 325 | just_check_syntax: bool, | ||
| 326 | mode: std.builtin.Mode, | ||
| 327 | link_objects: []const []const u8, | ||
| 328 | target_str: ?[]const u8, | ||
| 329 | link_libc: bool, | ||
| 330 | link_mode: ?std.builtin.LinkMode, | ||
| 331 | disable_cache: bool, | ||
| 332 | verbose_cimport: bool, | ||
| 333 | additional_options: []const []const u8, | ||
| 334 | |||
| 335 | const Id = union(enum) { | ||
| 336 | @"test", | ||
| 337 | test_error: []const u8, | ||
| 338 | test_safety: []const u8, | ||
| 339 | exe: ExpectedOutcome, | ||
| 340 | obj: ?[]const u8, | ||
| 341 | lib, | ||
| 342 | }; | ||
| 343 | }; | ||
| 344 | |||
| 345 | const Link = struct { | ||
| 346 | url: []const u8, | ||
| 347 | name: []const u8, | ||
| 348 | token: Token, | ||
| 349 | }; | ||
| 350 | |||
| 351 | const SyntaxBlock = struct { | ||
| 352 | source_type: SourceType, | ||
| 353 | name: []const u8, | ||
| 354 | source_token: Token, | ||
| 355 | |||
| 356 | const SourceType = enum { | ||
| 357 | zig, | ||
| 358 | c, | ||
| 359 | peg, | ||
| 360 | javascript, | ||
| 361 | }; | ||
| 362 | }; | ||
| 363 | |||
| 364 | const Node = union(enum) { | ||
| 365 | Content: []const u8, | ||
| 366 | Nav, | ||
| 367 | Builtin: Token, | ||
| 368 | HeaderOpen: HeaderOpen, | ||
| 369 | SeeAlso: []const SeeAlsoItem, | ||
| 370 | Code: Code, | ||
| 371 | Link: Link, | ||
| 372 | InlineSyntax: Token, | ||
| 373 | Shell: Token, | ||
| 374 | SyntaxBlock: SyntaxBlock, | ||
| 375 | }; | ||
| 376 | |||
| 377 | const Toc = struct { | ||
| 378 | nodes: []Node, | ||
| 379 | toc: []u8, | ||
| 380 | urls: std.StringHashMap(Token), | ||
| 381 | }; | ||
| 382 | |||
| 383 | const Action = enum { | ||
| 384 | open, | ||
| 385 | close, | ||
| 386 | }; | ||
| 387 | |||
| 388 | fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc { | ||
| 389 | var urls = std.StringHashMap(Token).init(allocator); | ||
| 390 | errdefer urls.deinit(); | ||
| 391 | |||
| 392 | var header_stack_size: usize = 0; | ||
| 393 | var last_action: Action = .open; | ||
| 394 | var last_columns: ?u8 = null; | ||
| 395 | |||
| 396 | var toc_buf = std.ArrayList(u8).init(allocator); | ||
| 397 | defer toc_buf.deinit(); | ||
| 398 | |||
| 399 | var toc = toc_buf.writer(); | ||
| 400 | |||
| 401 | var nodes = std.ArrayList(Node).init(allocator); | ||
| 402 | defer nodes.deinit(); | ||
| 403 | |||
| 404 | try toc.writeByte('\n'); | ||
| 405 | |||
| 406 | while (true) { | ||
| 407 | const token = tokenizer.next(); | ||
| 408 | switch (token.id) { | ||
| 409 | .eof => { | ||
| 410 | if (header_stack_size != 0) { | ||
| 411 | return parseError(tokenizer, token, "unbalanced headers", .{}); | ||
| 412 | } | ||
| 413 | try toc.writeAll(" </ul>\n"); | ||
| 414 | break; | ||
| 415 | }, | ||
| 416 | .content => { | ||
| 417 | try nodes.append(Node{ .Content = tokenizer.buffer[token.start..token.end] }); | ||
| 418 | }, | ||
| 419 | .bracket_open => { | ||
| 420 | const tag_token = try eatToken(tokenizer, .tag_content); | ||
| 421 | const tag_name = tokenizer.buffer[tag_token.start..tag_token.end]; | ||
| 422 | |||
| 423 | if (mem.eql(u8, tag_name, "nav")) { | ||
| 424 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 425 | |||
| 426 | try nodes.append(Node.Nav); | ||
| 427 | } else if (mem.eql(u8, tag_name, "builtin")) { | ||
| 428 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 429 | try nodes.append(Node{ .Builtin = tag_token }); | ||
| 430 | } else if (mem.eql(u8, tag_name, "header_open")) { | ||
| 431 | _ = try eatToken(tokenizer, .separator); | ||
| 432 | const content_token = try eatToken(tokenizer, .tag_content); | ||
| 433 | const content = tokenizer.buffer[content_token.start..content_token.end]; | ||
| 434 | var columns: ?u8 = null; | ||
| 435 | while (true) { | ||
| 436 | const bracket_tok = tokenizer.next(); | ||
| 437 | switch (bracket_tok.id) { | ||
| 438 | .bracket_close => break, | ||
| 439 | .separator => continue, | ||
| 440 | .tag_content => { | ||
| 441 | const param = tokenizer.buffer[bracket_tok.start..bracket_tok.end]; | ||
| 442 | if (mem.eql(u8, param, "2col")) { | ||
| 443 | columns = 2; | ||
| 444 | } else { | ||
| 445 | return parseError( | ||
| 446 | tokenizer, | ||
| 447 | bracket_tok, | ||
| 448 | "unrecognized header_open param: {s}", | ||
| 449 | .{param}, | ||
| 450 | ); | ||
| 451 | } | ||
| 452 | }, | ||
| 453 | else => return parseError(tokenizer, bracket_tok, "invalid header_open token", .{}), | ||
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | header_stack_size += 1; | ||
| 458 | |||
| 459 | const urlized = try urlize(allocator, content); | ||
| 460 | try nodes.append(Node{ | ||
| 461 | .HeaderOpen = HeaderOpen{ | ||
| 462 | .name = content, | ||
| 463 | .url = urlized, | ||
| 464 | .n = header_stack_size + 1, // highest-level section headers start at h2 | ||
| 465 | }, | ||
| 466 | }); | ||
| 467 | if (try urls.fetchPut(urlized, tag_token)) |kv| { | ||
| 468 | parseError(tokenizer, tag_token, "duplicate header url: #{s}", .{urlized}) catch {}; | ||
| 469 | parseError(tokenizer, kv.value, "other tag here", .{}) catch {}; | ||
| 470 | return error.ParseError; | ||
| 471 | } | ||
| 472 | if (last_action == .open) { | ||
| 473 | try toc.writeByte('\n'); | ||
| 474 | try toc.writeByteNTimes(' ', header_stack_size * 4); | ||
| 475 | if (last_columns) |n| { | ||
| 476 | try toc.print("<ul style=\"columns: {}\">\n", .{n}); | ||
| 477 | } else { | ||
| 478 | try toc.writeAll("<ul>\n"); | ||
| 479 | } | ||
| 480 | } else { | ||
| 481 | last_action = .open; | ||
| 482 | } | ||
| 483 | last_columns = columns; | ||
| 484 | try toc.writeByteNTimes(' ', 4 + header_stack_size * 4); | ||
| 485 | try toc.print("<li><a id=\"toc-{s}\" href=\"#{s}\">{s}</a>", .{ urlized, urlized, content }); | ||
| 486 | } else if (mem.eql(u8, tag_name, "header_close")) { | ||
| 487 | if (header_stack_size == 0) { | ||
| 488 | return parseError(tokenizer, tag_token, "unbalanced close header", .{}); | ||
| 489 | } | ||
| 490 | header_stack_size -= 1; | ||
| 491 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 492 | |||
| 493 | if (last_action == .close) { | ||
| 494 | try toc.writeByteNTimes(' ', 8 + header_stack_size * 4); | ||
| 495 | try toc.writeAll("</ul></li>\n"); | ||
| 496 | } else { | ||
| 497 | try toc.writeAll("</li>\n"); | ||
| 498 | last_action = .close; | ||
| 499 | } | ||
| 500 | } else if (mem.eql(u8, tag_name, "see_also")) { | ||
| 501 | var list = std.ArrayList(SeeAlsoItem).init(allocator); | ||
| 502 | errdefer list.deinit(); | ||
| 503 | |||
| 504 | while (true) { | ||
| 505 | const see_also_tok = tokenizer.next(); | ||
| 506 | switch (see_also_tok.id) { | ||
| 507 | .tag_content => { | ||
| 508 | const content = tokenizer.buffer[see_also_tok.start..see_also_tok.end]; | ||
| 509 | try list.append(SeeAlsoItem{ | ||
| 510 | .name = content, | ||
| 511 | .token = see_also_tok, | ||
| 512 | }); | ||
| 513 | }, | ||
| 514 | .separator => {}, | ||
| 515 | .bracket_close => { | ||
| 516 | try nodes.append(Node{ .SeeAlso = try list.toOwnedSlice() }); | ||
| 517 | break; | ||
| 518 | }, | ||
| 519 | else => return parseError(tokenizer, see_also_tok, "invalid see_also token", .{}), | ||
| 520 | } | ||
| 521 | } | ||
| 522 | } else if (mem.eql(u8, tag_name, "link")) { | ||
| 523 | _ = try eatToken(tokenizer, .separator); | ||
| 524 | const name_tok = try eatToken(tokenizer, .tag_content); | ||
| 525 | const name = tokenizer.buffer[name_tok.start..name_tok.end]; | ||
| 526 | |||
| 527 | const url_name = blk: { | ||
| 528 | const tok = tokenizer.next(); | ||
| 529 | switch (tok.id) { | ||
| 530 | .bracket_close => break :blk name, | ||
| 531 | .separator => { | ||
| 532 | const explicit_text = try eatToken(tokenizer, .tag_content); | ||
| 533 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 534 | break :blk tokenizer.buffer[explicit_text.start..explicit_text.end]; | ||
| 535 | }, | ||
| 536 | else => return parseError(tokenizer, tok, "invalid link token", .{}), | ||
| 537 | } | ||
| 538 | }; | ||
| 539 | |||
| 540 | try nodes.append(Node{ | ||
| 541 | .Link = Link{ | ||
| 542 | .url = try urlize(allocator, url_name), | ||
| 543 | .name = name, | ||
| 544 | .token = name_tok, | ||
| 545 | }, | ||
| 546 | }); | ||
| 547 | } else if (mem.eql(u8, tag_name, "code_begin")) { | ||
| 548 | _ = try eatToken(tokenizer, .separator); | ||
| 549 | const code_kind_tok = try eatToken(tokenizer, .tag_content); | ||
| 550 | _ = try eatToken(tokenizer, .separator); | ||
| 551 | const name_tok = try eatToken(tokenizer, .tag_content); | ||
| 552 | const name = tokenizer.buffer[name_tok.start..name_tok.end]; | ||
| 553 | var error_str: []const u8 = ""; | ||
| 554 | const maybe_sep = tokenizer.next(); | ||
| 555 | switch (maybe_sep.id) { | ||
| 556 | .separator => { | ||
| 557 | const error_tok = try eatToken(tokenizer, .tag_content); | ||
| 558 | error_str = tokenizer.buffer[error_tok.start..error_tok.end]; | ||
| 559 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 560 | }, | ||
| 561 | .bracket_close => {}, | ||
| 562 | else => return parseError(tokenizer, token, "invalid token", .{}), | ||
| 563 | } | ||
| 564 | const code_kind_str = tokenizer.buffer[code_kind_tok.start..code_kind_tok.end]; | ||
| 565 | var code_kind_id: Code.Id = undefined; | ||
| 566 | var just_check_syntax = false; | ||
| 567 | if (mem.eql(u8, code_kind_str, "exe")) { | ||
| 568 | code_kind_id = Code.Id{ .exe = .succeed }; | ||
| 569 | } else if (mem.eql(u8, code_kind_str, "exe_err")) { | ||
| 570 | code_kind_id = Code.Id{ .exe = .fail }; | ||
| 571 | } else if (mem.eql(u8, code_kind_str, "exe_build_err")) { | ||
| 572 | code_kind_id = Code.Id{ .exe = .build_fail }; | ||
| 573 | } else if (mem.eql(u8, code_kind_str, "test")) { | ||
| 574 | code_kind_id = .@"test"; | ||
| 575 | } else if (mem.eql(u8, code_kind_str, "test_err")) { | ||
| 576 | code_kind_id = Code.Id{ .test_error = error_str }; | ||
| 577 | } else if (mem.eql(u8, code_kind_str, "test_safety")) { | ||
| 578 | code_kind_id = Code.Id{ .test_safety = error_str }; | ||
| 579 | } else if (mem.eql(u8, code_kind_str, "obj")) { | ||
| 580 | code_kind_id = Code.Id{ .obj = null }; | ||
| 581 | } else if (mem.eql(u8, code_kind_str, "obj_err")) { | ||
| 582 | code_kind_id = Code.Id{ .obj = error_str }; | ||
| 583 | } else if (mem.eql(u8, code_kind_str, "lib")) { | ||
| 584 | code_kind_id = Code.Id.lib; | ||
| 585 | } else if (mem.eql(u8, code_kind_str, "syntax")) { | ||
| 586 | code_kind_id = Code.Id{ .obj = null }; | ||
| 587 | just_check_syntax = true; | ||
| 588 | } else { | ||
| 589 | return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {s}", .{code_kind_str}); | ||
| 590 | } | ||
| 591 | |||
| 592 | var mode: std.builtin.Mode = .Debug; | ||
| 593 | var link_objects = std.ArrayList([]const u8).init(allocator); | ||
| 594 | defer link_objects.deinit(); | ||
| 595 | var target_str: ?[]const u8 = null; | ||
| 596 | var link_libc = false; | ||
| 597 | var link_mode: ?std.builtin.LinkMode = null; | ||
| 598 | var disable_cache = false; | ||
| 599 | var verbose_cimport = false; | ||
| 600 | var additional_options = std.ArrayList([]const u8).init(allocator); | ||
| 601 | defer additional_options.deinit(); | ||
| 602 | |||
| 603 | const source_token = while (true) { | ||
| 604 | const content_tok = try eatToken(tokenizer, .content); | ||
| 605 | _ = try eatToken(tokenizer, .bracket_open); | ||
| 606 | const end_code_tag = try eatToken(tokenizer, .tag_content); | ||
| 607 | const end_tag_name = tokenizer.buffer[end_code_tag.start..end_code_tag.end]; | ||
| 608 | if (mem.eql(u8, end_tag_name, "code_release_fast")) { | ||
| 609 | mode = .ReleaseFast; | ||
| 610 | } else if (mem.eql(u8, end_tag_name, "code_release_safe")) { | ||
| 611 | mode = .ReleaseSafe; | ||
| 612 | } else if (mem.eql(u8, end_tag_name, "code_disable_cache")) { | ||
| 613 | disable_cache = true; | ||
| 614 | } else if (mem.eql(u8, end_tag_name, "code_verbose_cimport")) { | ||
| 615 | verbose_cimport = true; | ||
| 616 | } else if (mem.eql(u8, end_tag_name, "code_link_object")) { | ||
| 617 | _ = try eatToken(tokenizer, .separator); | ||
| 618 | const obj_tok = try eatToken(tokenizer, .tag_content); | ||
| 619 | try link_objects.append(tokenizer.buffer[obj_tok.start..obj_tok.end]); | ||
| 620 | } else if (mem.eql(u8, end_tag_name, "target_windows")) { | ||
| 621 | target_str = "x86_64-windows"; | ||
| 622 | } else if (mem.eql(u8, end_tag_name, "target_linux_x86_64")) { | ||
| 623 | target_str = "x86_64-linux"; | ||
| 624 | } else if (mem.eql(u8, end_tag_name, "target_linux_riscv64")) { | ||
| 625 | target_str = "riscv64-linux"; | ||
| 626 | } else if (mem.eql(u8, end_tag_name, "target_wasm")) { | ||
| 627 | target_str = "wasm32-freestanding"; | ||
| 628 | } else if (mem.eql(u8, end_tag_name, "target_wasi")) { | ||
| 629 | target_str = "wasm32-wasi"; | ||
| 630 | } else if (mem.eql(u8, end_tag_name, "link_libc")) { | ||
| 631 | link_libc = true; | ||
| 632 | } else if (mem.eql(u8, end_tag_name, "link_mode_dynamic")) { | ||
| 633 | link_mode = .Dynamic; | ||
| 634 | } else if (mem.eql(u8, end_tag_name, "additonal_option")) { | ||
| 635 | _ = try eatToken(tokenizer, .separator); | ||
| 636 | const option = try eatToken(tokenizer, .tag_content); | ||
| 637 | try additional_options.append(tokenizer.buffer[option.start..option.end]); | ||
| 638 | } else if (mem.eql(u8, end_tag_name, "code_end")) { | ||
| 639 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 640 | break content_tok; | ||
| 641 | } else { | ||
| 642 | return parseError( | ||
| 643 | tokenizer, | ||
| 644 | end_code_tag, | ||
| 645 | "invalid token inside code_begin: {s}", | ||
| 646 | .{end_tag_name}, | ||
| 647 | ); | ||
| 648 | } | ||
| 649 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 650 | } else unreachable; // TODO issue #707 | ||
| 651 | try nodes.append(Node{ | ||
| 652 | .Code = Code{ | ||
| 653 | .id = code_kind_id, | ||
| 654 | .name = name, | ||
| 655 | .source_token = source_token, | ||
| 656 | .just_check_syntax = just_check_syntax, | ||
| 657 | .mode = mode, | ||
| 658 | .link_objects = try link_objects.toOwnedSlice(), | ||
| 659 | .target_str = target_str, | ||
| 660 | .link_libc = link_libc, | ||
| 661 | .link_mode = link_mode, | ||
| 662 | .disable_cache = disable_cache, | ||
| 663 | .verbose_cimport = verbose_cimport, | ||
| 664 | .additional_options = try additional_options.toOwnedSlice(), | ||
| 665 | }, | ||
| 666 | }); | ||
| 667 | tokenizer.code_node_count += 1; | ||
| 668 | } else if (mem.eql(u8, tag_name, "syntax")) { | ||
| 669 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 670 | const content_tok = try eatToken(tokenizer, .content); | ||
| 671 | _ = try eatToken(tokenizer, .bracket_open); | ||
| 672 | const end_syntax_tag = try eatToken(tokenizer, .tag_content); | ||
| 673 | const end_tag_name = tokenizer.buffer[end_syntax_tag.start..end_syntax_tag.end]; | ||
| 674 | if (!mem.eql(u8, end_tag_name, "endsyntax")) { | ||
| 675 | return parseError( | ||
| 676 | tokenizer, | ||
| 677 | end_syntax_tag, | ||
| 678 | "invalid token inside syntax: {s}", | ||
| 679 | .{end_tag_name}, | ||
| 680 | ); | ||
| 681 | } | ||
| 682 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 683 | try nodes.append(Node{ .InlineSyntax = content_tok }); | ||
| 684 | } else if (mem.eql(u8, tag_name, "shell_samp")) { | ||
| 685 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 686 | const content_tok = try eatToken(tokenizer, .content); | ||
| 687 | _ = try eatToken(tokenizer, .bracket_open); | ||
| 688 | const end_syntax_tag = try eatToken(tokenizer, .tag_content); | ||
| 689 | const end_tag_name = tokenizer.buffer[end_syntax_tag.start..end_syntax_tag.end]; | ||
| 690 | if (!mem.eql(u8, end_tag_name, "end_shell_samp")) { | ||
| 691 | return parseError( | ||
| 692 | tokenizer, | ||
| 693 | end_syntax_tag, | ||
| 694 | "invalid token inside syntax: {s}", | ||
| 695 | .{end_tag_name}, | ||
| 696 | ); | ||
| 697 | } | ||
| 698 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 699 | try nodes.append(Node{ .Shell = content_tok }); | ||
| 700 | } else if (mem.eql(u8, tag_name, "syntax_block")) { | ||
| 701 | _ = try eatToken(tokenizer, .separator); | ||
| 702 | const source_type_tok = try eatToken(tokenizer, .tag_content); | ||
| 703 | var name: []const u8 = "sample_code"; | ||
| 704 | const maybe_sep = tokenizer.next(); | ||
| 705 | switch (maybe_sep.id) { | ||
| 706 | .separator => { | ||
| 707 | const name_tok = try eatToken(tokenizer, .tag_content); | ||
| 708 | name = tokenizer.buffer[name_tok.start..name_tok.end]; | ||
| 709 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 710 | }, | ||
| 711 | .bracket_close => {}, | ||
| 712 | else => return parseError(tokenizer, token, "invalid token", .{}), | ||
| 713 | } | ||
| 714 | const source_type_str = tokenizer.buffer[source_type_tok.start..source_type_tok.end]; | ||
| 715 | var source_type: SyntaxBlock.SourceType = undefined; | ||
| 716 | if (mem.eql(u8, source_type_str, "zig")) { | ||
| 717 | source_type = SyntaxBlock.SourceType.zig; | ||
| 718 | } else if (mem.eql(u8, source_type_str, "c")) { | ||
| 719 | source_type = SyntaxBlock.SourceType.c; | ||
| 720 | } else if (mem.eql(u8, source_type_str, "peg")) { | ||
| 721 | source_type = SyntaxBlock.SourceType.peg; | ||
| 722 | } else if (mem.eql(u8, source_type_str, "javascript")) { | ||
| 723 | source_type = SyntaxBlock.SourceType.javascript; | ||
| 724 | } else { | ||
| 725 | return parseError(tokenizer, source_type_tok, "unrecognized code kind: {s}", .{source_type_str}); | ||
| 726 | } | ||
| 727 | const source_token = while (true) { | ||
| 728 | const content_tok = try eatToken(tokenizer, .content); | ||
| 729 | _ = try eatToken(tokenizer, .bracket_open); | ||
| 730 | const end_code_tag = try eatToken(tokenizer, .tag_content); | ||
| 731 | const end_tag_name = tokenizer.buffer[end_code_tag.start..end_code_tag.end]; | ||
| 732 | if (mem.eql(u8, end_tag_name, "end_syntax_block")) { | ||
| 733 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 734 | break content_tok; | ||
| 735 | } else { | ||
| 736 | return parseError( | ||
| 737 | tokenizer, | ||
| 738 | end_code_tag, | ||
| 739 | "invalid token inside code_begin: {s}", | ||
| 740 | .{end_tag_name}, | ||
| 741 | ); | ||
| 742 | } | ||
| 743 | _ = try eatToken(tokenizer, .bracket_close); | ||
| 744 | }; | ||
| 745 | try nodes.append(Node{ .SyntaxBlock = SyntaxBlock{ .source_type = source_type, .name = name, .source_token = source_token } }); | ||
| 746 | } else { | ||
| 747 | return parseError(tokenizer, tag_token, "unrecognized tag name: {s}", .{tag_name}); | ||
| 748 | } | ||
| 749 | }, | ||
| 750 | else => return parseError(tokenizer, token, "invalid token", .{}), | ||
| 751 | } | ||
| 752 | } | ||
| 753 | |||
| 754 | return Toc{ | ||
| 755 | .nodes = try nodes.toOwnedSlice(), | ||
| 756 | .toc = try toc_buf.toOwnedSlice(), | ||
| 757 | .urls = urls, | ||
| 758 | }; | ||
| 759 | } | ||
| 760 | |||
| 761 | fn urlize(allocator: Allocator, input: []const u8) ![]u8 { | ||
| 762 | var buf = std.ArrayList(u8).init(allocator); | ||
| 763 | defer buf.deinit(); | ||
| 764 | |||
| 765 | const out = buf.writer(); | ||
| 766 | for (input) |c| { | ||
| 767 | switch (c) { | ||
| 768 | 'a'...'z', 'A'...'Z', '_', '-', '0'...'9' => { | ||
| 769 | try out.writeByte(c); | ||
| 770 | }, | ||
| 771 | ' ' => { | ||
| 772 | try out.writeByte('-'); | ||
| 773 | }, | ||
| 774 | else => {}, | ||
| 775 | } | ||
| 776 | } | ||
| 777 | return try buf.toOwnedSlice(); | ||
| 778 | } | ||
| 779 | |||
| 780 | fn escapeHtml(allocator: Allocator, input: []const u8) ![]u8 { | ||
| 781 | var buf = std.ArrayList(u8).init(allocator); | ||
| 782 | defer buf.deinit(); | ||
| 783 | |||
| 784 | const out = buf.writer(); | ||
| 785 | try writeEscaped(out, input); | ||
| 786 | return try buf.toOwnedSlice(); | ||
| 787 | } | ||
| 788 | |||
| 789 | fn writeEscaped(out: anytype, input: []const u8) !void { | ||
| 790 | for (input) |c| { | ||
| 791 | try switch (c) { | ||
| 792 | '&' => out.writeAll("&amp;"), | ||
| 793 | '<' => out.writeAll("&lt;"), | ||
| 794 | '>' => out.writeAll("&gt;"), | ||
| 795 | '"' => out.writeAll("&quot;"), | ||
| 796 | else => out.writeByte(c), | ||
| 797 | }; | ||
| 798 | } | ||
| 799 | } | ||
| 800 | |||
| 801 | // Returns true if number is in slice. | ||
| 802 | fn in(slice: []const u8, number: u8) bool { | ||
| 803 | for (slice) |n| { | ||
| 804 | if (number == n) return true; | ||
| 805 | } | ||
| 806 | return false; | ||
| 807 | } | ||
| 808 | |||
| 809 | fn termColor(allocator: Allocator, input: []const u8) ![]u8 { | ||
| 810 | // The SRG sequences generates by the Zig compiler are in the format: | ||
| 811 | // ESC [ <foreground-color> ; <n> m | ||
| 812 | // or | ||
| 813 | // ESC [ <n> m | ||
| 814 | // | ||
| 815 | // where | ||
| 816 | // foreground-color is 31 (red), 32 (green), 36 (cyan) | ||
| 817 | // n is 0 (reset), 1 (bold), 2 (dim) | ||
| 818 | // | ||
| 819 | // Note that 37 (white) is currently not used by the compiler. | ||
| 820 | // | ||
| 821 | // See std.debug.TTY.Color. | ||
| 822 | const supported_sgr_colors = [_]u8{ 31, 32, 36 }; | ||
| 823 | const supported_sgr_numbers = [_]u8{ 0, 1, 2 }; | ||
| 824 | |||
| 825 | var buf = std.ArrayList(u8).init(allocator); | ||
| 826 | defer buf.deinit(); | ||
| 827 | |||
| 828 | var out = buf.writer(); | ||
| 829 | var sgr_param_start_index: usize = undefined; | ||
| 830 | var sgr_num: u8 = undefined; | ||
| 831 | var sgr_color: u8 = undefined; | ||
| 832 | var i: usize = 0; | ||
| 833 | var state: enum { | ||
| 834 | start, | ||
| 835 | escape, | ||
| 836 | lbracket, | ||
| 837 | number, | ||
| 838 | after_number, | ||
| 839 | arg, | ||
| 840 | arg_number, | ||
| 841 | expect_end, | ||
| 842 | } = .start; | ||
| 843 | var last_new_line: usize = 0; | ||
| 844 | var open_span_count: usize = 0; | ||
| 845 | while (i < input.len) : (i += 1) { | ||
| 846 | const c = input[i]; | ||
| 847 | switch (state) { | ||
| 848 | .start => switch (c) { | ||
| 849 | '\x1b' => state = .escape, | ||
| 850 | '\n' => { | ||
| 851 | try out.writeByte(c); | ||
| 852 | last_new_line = buf.items.len; | ||
| 853 | }, | ||
| 854 | else => try out.writeByte(c), | ||
| 855 | }, | ||
| 856 | .escape => switch (c) { | ||
| 857 | '[' => state = .lbracket, | ||
| 858 | else => return error.UnsupportedEscape, | ||
| 859 | }, | ||
| 860 | .lbracket => switch (c) { | ||
| 861 | '0'...'9' => { | ||
| 862 | sgr_param_start_index = i; | ||
| 863 | state = .number; | ||
| 864 | }, | ||
| 865 | else => return error.UnsupportedEscape, | ||
| 866 | }, | ||
| 867 | .number => switch (c) { | ||
| 868 | '0'...'9' => {}, | ||
| 869 | else => { | ||
| 870 | sgr_num = try std.fmt.parseInt(u8, input[sgr_param_start_index..i], 10); | ||
| 871 | sgr_color = 0; | ||
| 872 | state = .after_number; | ||
| 873 | i -= 1; | ||
| 874 | }, | ||
| 875 | }, | ||
| 876 | .after_number => switch (c) { | ||
| 877 | ';' => state = .arg, | ||
| 878 | 'D' => state = .start, | ||
| 879 | 'K' => { | ||
| 880 | buf.items.len = last_new_line; | ||
| 881 | state = .start; | ||
| 882 | }, | ||
| 883 | else => { | ||
| 884 | state = .expect_end; | ||
| 885 | i -= 1; | ||
| 886 | }, | ||
| 887 | }, | ||
| 888 | .arg => switch (c) { | ||
| 889 | '0'...'9' => { | ||
| 890 | sgr_param_start_index = i; | ||
| 891 | state = .arg_number; | ||
| 892 | }, | ||
| 893 | else => return error.UnsupportedEscape, | ||
| 894 | }, | ||
| 895 | .arg_number => switch (c) { | ||
| 896 | '0'...'9' => {}, | ||
| 897 | else => { | ||
| 898 | // Keep the sequence consistent, foreground color first. | ||
| 899 | // 32;1m is equivalent to 1;32m, but the latter will | ||
| 900 | // generate an incorrect HTML class without notice. | ||
| 901 | sgr_color = sgr_num; | ||
| 902 | if (!in(&supported_sgr_colors, sgr_color)) return error.UnsupportedForegroundColor; | ||
| 903 | |||
| 904 | sgr_num = try std.fmt.parseInt(u8, input[sgr_param_start_index..i], 10); | ||
| 905 | if (!in(&supported_sgr_numbers, sgr_num)) return error.UnsupportedNumber; | ||
| 906 | |||
| 907 | state = .expect_end; | ||
| 908 | i -= 1; | ||
| 909 | }, | ||
| 910 | }, | ||
| 911 | .expect_end => switch (c) { | ||
| 912 | 'm' => { | ||
| 913 | state = .start; | ||
| 914 | while (open_span_count != 0) : (open_span_count -= 1) { | ||
| 915 | try out.writeAll("</span>"); | ||
| 916 | } | ||
| 917 | if (sgr_num == 0) { | ||
| 918 | if (sgr_color != 0) return error.UnsupportedColor; | ||
| 919 | continue; | ||
| 920 | } | ||
| 921 | if (sgr_color != 0) { | ||
| 922 | try out.print("<span class=\"sgr-{d}_{d}m\">", .{ sgr_color, sgr_num }); | ||
| 923 | } else { | ||
| 924 | try out.print("<span class=\"sgr-{d}m\">", .{sgr_num}); | ||
| 925 | } | ||
| 926 | open_span_count += 1; | ||
| 927 | }, | ||
| 928 | else => return error.UnsupportedEscape, | ||
| 929 | }, | ||
| 930 | } | ||
| 931 | } | ||
| 932 | return try buf.toOwnedSlice(); | ||
| 933 | } | ||
| 934 | |||
| 935 | const builtin_types = [_][]const u8{ | ||
| 936 | "f16", "f32", "f64", "f80", "f128", | ||
| 937 | "c_longdouble", "c_short", "c_ushort", "c_int", "c_uint", | ||
| 938 | "c_long", "c_ulong", "c_longlong", "c_ulonglong", "c_char", | ||
| 939 | "anyopaque", "void", "bool", "isize", "usize", | ||
| 940 | "noreturn", "type", "anyerror", "comptime_int", "comptime_float", | ||
| 941 | }; | ||
| 942 | |||
| 943 | fn isType(name: []const u8) bool { | ||
| 944 | for (builtin_types) |t| { | ||
| 945 | if (mem.eql(u8, t, name)) | ||
| 946 | return true; | ||
| 947 | } | ||
| 948 | return false; | ||
| 949 | } | ||
| 950 | |||
| 951 | const start_line = "<span class=\"line\">"; | ||
| 952 | const end_line = "</span>"; | ||
| 953 | |||
| 954 | fn writeEscapedLines(out: anytype, text: []const u8) !void { | ||
| 955 | for (text) |char| { | ||
| 956 | if (char == '\n') { | ||
| 957 | try out.writeAll(end_line); | ||
| 958 | try out.writeAll("\n"); | ||
| 959 | try out.writeAll(start_line); | ||
| 960 | } else { | ||
| 961 | try writeEscaped(out, &[_]u8{char}); | ||
| 962 | } | ||
| 963 | } | ||
| 964 | } | ||
| 965 | |||
| 966 | fn tokenizeAndPrintRaw( | ||
| 967 | allocator: Allocator, | ||
| 968 | docgen_tokenizer: *Tokenizer, | ||
| 969 | out: anytype, | ||
| 970 | source_token: Token, | ||
| 971 | raw_src: []const u8, | ||
| 972 | ) !void { | ||
| 973 | const src_non_terminated = mem.trim(u8, raw_src, " \n"); | ||
| 974 | const src = try allocator.dupeZ(u8, src_non_terminated); | ||
| 975 | |||
| 976 | try out.writeAll("<code>" ++ start_line); | ||
| 977 | var tokenizer = std.zig.Tokenizer.init(src); | ||
| 978 | var index: usize = 0; | ||
| 979 | var next_tok_is_fn = false; | ||
| 980 | while (true) { | ||
| 981 | const prev_tok_was_fn = next_tok_is_fn; | ||
| 982 | next_tok_is_fn = false; | ||
| 983 | |||
| 984 | const token = tokenizer.next(); | ||
| 985 | if (mem.indexOf(u8, src[index..token.loc.start], "//")) |comment_start_off| { | ||
| 986 | // render one comment | ||
| 987 | const comment_start = index + comment_start_off; | ||
| 988 | const comment_end_off = mem.indexOf(u8, src[comment_start..token.loc.start], "\n"); | ||
| 989 | const comment_end = if (comment_end_off) |o| comment_start + o else token.loc.start; | ||
| 990 | |||
| 991 | try writeEscapedLines(out, src[index..comment_start]); | ||
| 992 | try out.writeAll("<span class=\"tok-comment\">"); | ||
| 993 | try writeEscaped(out, src[comment_start..comment_end]); | ||
| 994 | try out.writeAll("</span>"); | ||
| 995 | index = comment_end; | ||
| 996 | tokenizer.index = index; | ||
| 997 | continue; | ||
| 998 | } | ||
| 999 | |||
| 1000 | try writeEscapedLines(out, src[index..token.loc.start]); | ||
| 1001 | switch (token.tag) { | ||
| 1002 | .eof => break, | ||
| 1003 | |||
| 1004 | .keyword_addrspace, | ||
| 1005 | .keyword_align, | ||
| 1006 | .keyword_and, | ||
| 1007 | .keyword_asm, | ||
| 1008 | .keyword_async, | ||
| 1009 | .keyword_await, | ||
| 1010 | .keyword_break, | ||
| 1011 | .keyword_catch, | ||
| 1012 | .keyword_comptime, | ||
| 1013 | .keyword_const, | ||
| 1014 | .keyword_continue, | ||
| 1015 | .keyword_defer, | ||
| 1016 | .keyword_else, | ||
| 1017 | .keyword_enum, | ||
| 1018 | .keyword_errdefer, | ||
| 1019 | .keyword_error, | ||
| 1020 | .keyword_export, | ||
| 1021 | .keyword_extern, | ||
| 1022 | .keyword_for, | ||
| 1023 | .keyword_if, | ||
| 1024 | .keyword_inline, | ||
| 1025 | .keyword_noalias, | ||
| 1026 | .keyword_noinline, | ||
| 1027 | .keyword_nosuspend, | ||
| 1028 | .keyword_opaque, | ||
| 1029 | .keyword_or, | ||
| 1030 | .keyword_orelse, | ||
| 1031 | .keyword_packed, | ||
| 1032 | .keyword_anyframe, | ||
| 1033 | .keyword_pub, | ||
| 1034 | .keyword_resume, | ||
| 1035 | .keyword_return, | ||
| 1036 | .keyword_linksection, | ||
| 1037 | .keyword_callconv, | ||
| 1038 | .keyword_struct, | ||
| 1039 | .keyword_suspend, | ||
| 1040 | .keyword_switch, | ||
| 1041 | .keyword_test, | ||
| 1042 | .keyword_threadlocal, | ||
| 1043 | .keyword_try, | ||
| 1044 | .keyword_union, | ||
| 1045 | .keyword_unreachable, | ||
| 1046 | .keyword_usingnamespace, | ||
| 1047 | .keyword_var, | ||
| 1048 | .keyword_volatile, | ||
| 1049 | .keyword_allowzero, | ||
| 1050 | .keyword_while, | ||
| 1051 | .keyword_anytype, | ||
| 1052 | => { | ||
| 1053 | try out.writeAll("<span class=\"tok-kw\">"); | ||
| 1054 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1055 | try out.writeAll("</span>"); | ||
| 1056 | }, | ||
| 1057 | |||
| 1058 | .keyword_fn => { | ||
| 1059 | try out.writeAll("<span class=\"tok-kw\">"); | ||
| 1060 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1061 | try out.writeAll("</span>"); | ||
| 1062 | next_tok_is_fn = true; | ||
| 1063 | }, | ||
| 1064 | |||
| 1065 | .string_literal, | ||
| 1066 | .char_literal, | ||
| 1067 | => { | ||
| 1068 | try out.writeAll("<span class=\"tok-str\">"); | ||
| 1069 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1070 | try out.writeAll("</span>"); | ||
| 1071 | }, | ||
| 1072 | |||
| 1073 | .multiline_string_literal_line => { | ||
| 1074 | if (src[token.loc.end - 1] == '\n') { | ||
| 1075 | try out.writeAll("<span class=\"tok-str\">"); | ||
| 1076 | try writeEscaped(out, src[token.loc.start .. token.loc.end - 1]); | ||
| 1077 | try out.writeAll("</span>" ++ end_line ++ "\n" ++ start_line); | ||
| 1078 | } else { | ||
| 1079 | try out.writeAll("<span class=\"tok-str\">"); | ||
| 1080 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1081 | try out.writeAll("</span>"); | ||
| 1082 | } | ||
| 1083 | }, | ||
| 1084 | |||
| 1085 | .builtin => { | ||
| 1086 | try out.writeAll("<span class=\"tok-builtin\">"); | ||
| 1087 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1088 | try out.writeAll("</span>"); | ||
| 1089 | }, | ||
| 1090 | |||
| 1091 | .doc_comment, | ||
| 1092 | .container_doc_comment, | ||
| 1093 | => { | ||
| 1094 | try out.writeAll("<span class=\"tok-comment\">"); | ||
| 1095 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1096 | try out.writeAll("</span>"); | ||
| 1097 | }, | ||
| 1098 | |||
| 1099 | .identifier => { | ||
| 1100 | const tok_bytes = src[token.loc.start..token.loc.end]; | ||
| 1101 | if (mem.eql(u8, tok_bytes, "undefined") or | ||
| 1102 | mem.eql(u8, tok_bytes, "null") or | ||
| 1103 | mem.eql(u8, tok_bytes, "true") or | ||
| 1104 | mem.eql(u8, tok_bytes, "false")) | ||
| 1105 | { | ||
| 1106 | try out.writeAll("<span class=\"tok-null\">"); | ||
| 1107 | try writeEscaped(out, tok_bytes); | ||
| 1108 | try out.writeAll("</span>"); | ||
| 1109 | } else if (prev_tok_was_fn) { | ||
| 1110 | try out.writeAll("<span class=\"tok-fn\">"); | ||
| 1111 | try writeEscaped(out, tok_bytes); | ||
| 1112 | try out.writeAll("</span>"); | ||
| 1113 | } else { | ||
| 1114 | const is_int = blk: { | ||
| 1115 | if (src[token.loc.start] != 'i' and src[token.loc.start] != 'u') | ||
| 1116 | break :blk false; | ||
| 1117 | var i = token.loc.start + 1; | ||
| 1118 | if (i == token.loc.end) | ||
| 1119 | break :blk false; | ||
| 1120 | while (i != token.loc.end) : (i += 1) { | ||
| 1121 | if (src[i] < '0' or src[i] > '9') | ||
| 1122 | break :blk false; | ||
| 1123 | } | ||
| 1124 | break :blk true; | ||
| 1125 | }; | ||
| 1126 | if (is_int or isType(tok_bytes)) { | ||
| 1127 | try out.writeAll("<span class=\"tok-type\">"); | ||
| 1128 | try writeEscaped(out, tok_bytes); | ||
| 1129 | try out.writeAll("</span>"); | ||
| 1130 | } else { | ||
| 1131 | try writeEscaped(out, tok_bytes); | ||
| 1132 | } | ||
| 1133 | } | ||
| 1134 | }, | ||
| 1135 | |||
| 1136 | .number_literal => { | ||
| 1137 | try out.writeAll("<span class=\"tok-number\">"); | ||
| 1138 | try writeEscaped(out, src[token.loc.start..token.loc.end]); | ||
| 1139 | try out.writeAll("</span>"); | ||
| 1140 | }, | ||
| 1141 | |||
| 1142 | .bang, | ||
| 1143 | .pipe, | ||
| 1144 | .pipe_pipe, | ||
| 1145 | .pipe_equal, | ||
| 1146 | .equal, | ||
| 1147 | .equal_equal, | ||
| 1148 | .equal_angle_bracket_right, | ||
| 1149 | .bang_equal, | ||
| 1150 | .l_paren, | ||
| 1151 | .r_paren, | ||
| 1152 | .semicolon, | ||
| 1153 | .percent, | ||
| 1154 | .percent_equal, | ||
| 1155 | .l_brace, | ||
| 1156 | .r_brace, | ||
| 1157 | .l_bracket, | ||
| 1158 | .r_bracket, | ||
| 1159 | .period, | ||
| 1160 | .period_asterisk, | ||
| 1161 | .ellipsis2, | ||
| 1162 | .ellipsis3, | ||
| 1163 | .caret, | ||
| 1164 | .caret_equal, | ||
| 1165 | .plus, | ||
| 1166 | .plus_plus, | ||
| 1167 | .plus_equal, | ||
| 1168 | .plus_percent, | ||
| 1169 | .plus_percent_equal, | ||
| 1170 | .plus_pipe, | ||
| 1171 | .plus_pipe_equal, | ||
| 1172 | .minus, | ||
| 1173 | .minus_equal, | ||
| 1174 | .minus_percent, | ||
| 1175 | .minus_percent_equal, | ||
| 1176 | .minus_pipe, | ||
| 1177 | .minus_pipe_equal, | ||
| 1178 | .asterisk, | ||
| 1179 | .asterisk_equal, | ||
| 1180 | .asterisk_asterisk, | ||
| 1181 | .asterisk_percent, | ||
| 1182 | .asterisk_percent_equal, | ||
| 1183 | .asterisk_pipe, | ||
| 1184 | .asterisk_pipe_equal, | ||
| 1185 | .arrow, | ||
| 1186 | .colon, | ||
| 1187 | .slash, | ||
| 1188 | .slash_equal, | ||
| 1189 | .comma, | ||
| 1190 | .ampersand, | ||
| 1191 | .ampersand_equal, | ||
| 1192 | .question_mark, | ||
| 1193 | .angle_bracket_left, | ||
| 1194 | .angle_bracket_left_equal, | ||
| 1195 | .angle_bracket_angle_bracket_left, | ||
| 1196 | .angle_bracket_angle_bracket_left_equal, | ||
| 1197 | .angle_bracket_angle_bracket_left_pipe, | ||
| 1198 | .angle_bracket_angle_bracket_left_pipe_equal, | ||
| 1199 | .angle_bracket_right, | ||
| 1200 | .angle_bracket_right_equal, | ||
| 1201 | .angle_bracket_angle_bracket_right, | ||
| 1202 | .angle_bracket_angle_bracket_right_equal, | ||
| 1203 | .tilde, | ||
| 1204 | => try writeEscaped(out, src[token.loc.start..token.loc.end]), | ||
| 1205 | |||
| 1206 | .invalid, .invalid_periodasterisks => return parseError( | ||
| 1207 | docgen_tokenizer, | ||
| 1208 | source_token, | ||
| 1209 | "syntax error", | ||
| 1210 | .{}, | ||
| 1211 | ), | ||
| 1212 | } | ||
| 1213 | index = token.loc.end; | ||
| 1214 | } | ||
| 1215 | try out.writeAll(end_line ++ "</code>"); | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | fn tokenizeAndPrint( | ||
| 1219 | allocator: Allocator, | ||
| 1220 | docgen_tokenizer: *Tokenizer, | ||
| 1221 | out: anytype, | ||
| 1222 | source_token: Token, | ||
| 1223 | ) !void { | ||
| 1224 | const raw_src = docgen_tokenizer.buffer[source_token.start..source_token.end]; | ||
| 1225 | return tokenizeAndPrintRaw(allocator, docgen_tokenizer, out, source_token, raw_src); | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | fn printSourceBlock(allocator: Allocator, docgen_tokenizer: *Tokenizer, out: anytype, syntax_block: SyntaxBlock) !void { | ||
| 1229 | const source_type = @tagName(syntax_block.source_type); | ||
| 1230 | |||
| 1231 | try out.print("<figure><figcaption class=\"{s}-cap\"><cite class=\"file\">{s}</cite></figcaption><pre>", .{ source_type, syntax_block.name }); | ||
| 1232 | switch (syntax_block.source_type) { | ||
| 1233 | .zig => try tokenizeAndPrint(allocator, docgen_tokenizer, out, syntax_block.source_token), | ||
| 1234 | else => { | ||
| 1235 | const raw_source = docgen_tokenizer.buffer[syntax_block.source_token.start..syntax_block.source_token.end]; | ||
| 1236 | const trimmed_raw_source = mem.trim(u8, raw_source, " \n"); | ||
| 1237 | |||
| 1238 | try out.writeAll("<code>" ++ start_line); | ||
| 1239 | try writeEscapedLines(out, trimmed_raw_source); | ||
| 1240 | try out.writeAll(end_line ++ "</code>"); | ||
| 1241 | }, | ||
| 1242 | } | ||
| 1243 | try out.writeAll("</pre></figure>"); | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | fn printShell(out: anytype, shell_content: []const u8, escape: bool) !void { | ||
| 1247 | const trimmed_shell_content = mem.trim(u8, shell_content, " \n"); | ||
| 1248 | try out.writeAll("<figure><figcaption class=\"shell-cap\">Shell</figcaption><pre><samp>"); | ||
| 1249 | var cmd_cont: bool = false; | ||
| 1250 | var iter = std.mem.splitScalar(u8, trimmed_shell_content, '\n'); | ||
| 1251 | while (iter.next()) |orig_line| { | ||
| 1252 | const line = mem.trimRight(u8, orig_line, " "); | ||
| 1253 | if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] != '\\') { | ||
| 1254 | try out.writeAll("$ <kbd>"); | ||
| 1255 | const s = std.mem.trimLeft(u8, line[1..], " "); | ||
| 1256 | if (escape) { | ||
| 1257 | try writeEscaped(out, s); | ||
| 1258 | } else { | ||
| 1259 | try out.writeAll(s); | ||
| 1260 | } | ||
| 1261 | try out.writeAll("</kbd>" ++ "\n"); | ||
| 1262 | } else if (!cmd_cont and line.len > 1 and mem.eql(u8, line[0..2], "$ ") and line[line.len - 1] == '\\') { | ||
| 1263 | try out.writeAll("$ <kbd>"); | ||
| 1264 | const s = std.mem.trimLeft(u8, line[1..], " "); | ||
| 1265 | if (escape) { | ||
| 1266 | try writeEscaped(out, s); | ||
| 1267 | } else { | ||
| 1268 | try out.writeAll(s); | ||
| 1269 | } | ||
| 1270 | try out.writeAll("\n"); | ||
| 1271 | cmd_cont = true; | ||
| 1272 | } else if (line.len > 0 and line[line.len - 1] != '\\' and cmd_cont) { | ||
| 1273 | if (escape) { | ||
| 1274 | try writeEscaped(out, line); | ||
| 1275 | } else { | ||
| 1276 | try out.writeAll(line); | ||
| 1277 | } | ||
| 1278 | try out.writeAll("</kbd>" ++ "\n"); | ||
| 1279 | cmd_cont = false; | ||
| 1280 | } else { | ||
| 1281 | if (escape) { | ||
| 1282 | try writeEscaped(out, line); | ||
| 1283 | } else { | ||
| 1284 | try out.writeAll(line); | ||
| 1285 | } | ||
| 1286 | try out.writeAll("\n"); | ||
| 1287 | } | ||
| 1288 | } | ||
| 1289 | |||
| 1290 | try out.writeAll("</samp></pre></figure>"); | ||
| 1291 | } | ||
| 1292 | |||
| 1293 | // Override this to skip to later tests | ||
| 1294 | const debug_start_line = 0; | ||
| 1295 | |||
| 1296 | fn genHtml( | ||
| 1297 | allocator: Allocator, | ||
| 1298 | tokenizer: *Tokenizer, | ||
| 1299 | toc: *Toc, | ||
| 1300 | out: anytype, | ||
| 1301 | zig_exe: []const u8, | ||
| 1302 | opt_zig_lib_dir: ?[]const u8, | ||
| 1303 | do_code_tests: bool, | ||
| 1304 | ) !void { | ||
| 1305 | var progress = Progress{ .dont_print_on_dumb = true }; | ||
| 1306 | const root_node = progress.start("Generating docgen examples", toc.nodes.len); | ||
| 1307 | defer root_node.end(); | ||
| 1308 | |||
| 1309 | var env_map = try process.getEnvMap(allocator); | ||
| 1310 | try env_map.put("YES_COLOR", "1"); | ||
| 1311 | |||
| 1312 | const host = try std.zig.system.NativeTargetInfo.detect(.{}); | ||
| 1313 | const builtin_code = try getBuiltinCode(allocator, &env_map, zig_exe, opt_zig_lib_dir); | ||
| 1314 | |||
| 1315 | for (toc.nodes) |node| { | ||
| 1316 | defer root_node.completeOne(); | ||
| 1317 | switch (node) { | ||
| 1318 | .Content => |data| { | ||
| 1319 | try out.writeAll(data); | ||
| 1320 | }, | ||
| 1321 | .Link => |info| { | ||
| 1322 | if (!toc.urls.contains(info.url)) { | ||
| 1323 | return parseError(tokenizer, info.token, "url not found: {s}", .{info.url}); | ||
| 1324 | } | ||
| 1325 | try out.print("<a href=\"#{s}\">{s}</a>", .{ info.url, info.name }); | ||
| 1326 | }, | ||
| 1327 | .Nav => { | ||
| 1328 | try out.writeAll(toc.toc); | ||
| 1329 | }, | ||
| 1330 | .Builtin => |tok| { | ||
| 1331 | try out.writeAll("<figure><figcaption class=\"zig-cap\"><cite>@import(\"builtin\")</cite></figcaption><pre>"); | ||
| 1332 | try tokenizeAndPrintRaw(allocator, tokenizer, out, tok, builtin_code); | ||
| 1333 | try out.writeAll("</pre></figure>"); | ||
| 1334 | }, | ||
| 1335 | .HeaderOpen => |info| { | ||
| 1336 | try out.print( | ||
| 1337 | "<h{d} id=\"{s}\"><a href=\"#toc-{s}\">{s}</a> <a class=\"hdr\" href=\"#{s}\">§</a></h{d}>\n", | ||
| 1338 | .{ info.n, info.url, info.url, info.name, info.url, info.n }, | ||
| 1339 | ); | ||
| 1340 | }, | ||
| 1341 | .SeeAlso => |items| { | ||
| 1342 | try out.writeAll("<p>See also:</p><ul>\n"); | ||
| 1343 | for (items) |item| { | ||
| 1344 | const url = try urlize(allocator, item.name); | ||
| 1345 | if (!toc.urls.contains(url)) { | ||
| 1346 | return parseError(tokenizer, item.token, "url not found: {s}", .{url}); | ||
| 1347 | } | ||
| 1348 | try out.print("<li><a href=\"#{s}\">{s}</a></li>\n", .{ url, item.name }); | ||
| 1349 | } | ||
| 1350 | try out.writeAll("</ul>\n"); | ||
| 1351 | }, | ||
| 1352 | .InlineSyntax => |content_tok| { | ||
| 1353 | try tokenizeAndPrint(allocator, tokenizer, out, content_tok); | ||
| 1354 | }, | ||
| 1355 | .Shell => |content_tok| { | ||
| 1356 | const raw_shell_content = tokenizer.buffer[content_tok.start..content_tok.end]; | ||
| 1357 | try printShell(out, raw_shell_content, true); | ||
| 1358 | }, | ||
| 1359 | .SyntaxBlock => |syntax_block| { | ||
| 1360 | try printSourceBlock(allocator, tokenizer, out, syntax_block); | ||
| 1361 | }, | ||
| 1362 | .Code => |code| { | ||
| 1363 | const name_plus_ext = try std.fmt.allocPrint(allocator, "{s}.zig", .{code.name}); | ||
| 1364 | const syntax_block = SyntaxBlock{ | ||
| 1365 | .source_type = .zig, | ||
| 1366 | .name = name_plus_ext, | ||
| 1367 | .source_token = code.source_token, | ||
| 1368 | }; | ||
| 1369 | |||
| 1370 | try printSourceBlock(allocator, tokenizer, out, syntax_block); | ||
| 1371 | |||
| 1372 | if (!do_code_tests) { | ||
| 1373 | continue; | ||
| 1374 | } | ||
| 1375 | |||
| 1376 | if (debug_start_line > 0) { | ||
| 1377 | const loc = tokenizer.getTokenLocation(code.source_token); | ||
| 1378 | if (debug_start_line > loc.line) { | ||
| 1379 | continue; | ||
| 1380 | } | ||
| 1381 | } | ||
| 1382 | |||
| 1383 | const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end]; | ||
| 1384 | const trimmed_raw_source = mem.trim(u8, raw_source, " \n"); | ||
| 1385 | const tmp_source_file_name = try fs.path.join( | ||
| 1386 | allocator, | ||
| 1387 | &[_][]const u8{ tmp_dir_name, name_plus_ext }, | ||
| 1388 | ); | ||
| 1389 | try fs.cwd().writeFile(tmp_source_file_name, trimmed_raw_source); | ||
| 1390 | |||
| 1391 | var shell_buffer = std.ArrayList(u8).init(allocator); | ||
| 1392 | defer shell_buffer.deinit(); | ||
| 1393 | var shell_out = shell_buffer.writer(); | ||
| 1394 | |||
| 1395 | switch (code.id) { | ||
| 1396 | .exe => |expected_outcome| code_block: { | ||
| 1397 | var build_args = std.ArrayList([]const u8).init(allocator); | ||
| 1398 | defer build_args.deinit(); | ||
| 1399 | try build_args.appendSlice(&[_][]const u8{ | ||
| 1400 | zig_exe, "build-exe", | ||
| 1401 | "--name", code.name, | ||
| 1402 | "--color", "on", | ||
| 1403 | name_plus_ext, | ||
| 1404 | }); | ||
| 1405 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1406 | try build_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir }); | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | try shell_out.print("$ zig build-exe {s} ", .{name_plus_ext}); | ||
| 1410 | |||
| 1411 | switch (code.mode) { | ||
| 1412 | .Debug => {}, | ||
| 1413 | else => { | ||
| 1414 | try build_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) }); | ||
| 1415 | try shell_out.print("-O {s} ", .{@tagName(code.mode)}); | ||
| 1416 | }, | ||
| 1417 | } | ||
| 1418 | for (code.link_objects) |link_object| { | ||
| 1419 | const name_with_ext = try std.fmt.allocPrint(allocator, "{s}{s}", .{ link_object, obj_ext }); | ||
| 1420 | try build_args.append(name_with_ext); | ||
| 1421 | try shell_out.print("{s} ", .{name_with_ext}); | ||
| 1422 | } | ||
| 1423 | if (code.link_libc) { | ||
| 1424 | try build_args.append("-lc"); | ||
| 1425 | try shell_out.print("-lc ", .{}); | ||
| 1426 | } | ||
| 1427 | const target = try std.zig.CrossTarget.parse(.{ | ||
| 1428 | .arch_os_abi = code.target_str orelse "native", | ||
| 1429 | }); | ||
| 1430 | if (code.target_str) |triple| { | ||
| 1431 | try build_args.appendSlice(&[_][]const u8{ "-target", triple }); | ||
| 1432 | try shell_out.print("-target {s} ", .{triple}); | ||
| 1433 | } | ||
| 1434 | if (code.verbose_cimport) { | ||
| 1435 | try build_args.append("--verbose-cimport"); | ||
| 1436 | try shell_out.print("--verbose-cimport ", .{}); | ||
| 1437 | } | ||
| 1438 | for (code.additional_options) |option| { | ||
| 1439 | try build_args.append(option); | ||
| 1440 | try shell_out.print("{s} ", .{option}); | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | try shell_out.print("\n", .{}); | ||
| 1444 | |||
| 1445 | if (expected_outcome == .build_fail) { | ||
| 1446 | const result = try ChildProcess.exec(.{ | ||
| 1447 | .allocator = allocator, | ||
| 1448 | .argv = build_args.items, | ||
| 1449 | .cwd = tmp_dir_name, | ||
| 1450 | .env_map = &env_map, | ||
| 1451 | .max_output_bytes = max_doc_file_size, | ||
| 1452 | }); | ||
| 1453 | switch (result.term) { | ||
| 1454 | .Exited => |exit_code| { | ||
| 1455 | if (exit_code == 0) { | ||
| 1456 | progress.log("", .{}); | ||
| 1457 | print("{s}\nThe following command incorrectly succeeded:\n", .{result.stderr}); | ||
| 1458 | dumpArgs(build_args.items); | ||
| 1459 | return parseError(tokenizer, code.source_token, "example incorrectly compiled", .{}); | ||
| 1460 | } | ||
| 1461 | }, | ||
| 1462 | else => { | ||
| 1463 | progress.log("", .{}); | ||
| 1464 | print("{s}\nThe following command crashed:\n", .{result.stderr}); | ||
| 1465 | dumpArgs(build_args.items); | ||
| 1466 | return parseError(tokenizer, code.source_token, "example compile crashed", .{}); | ||
| 1467 | }, | ||
| 1468 | } | ||
| 1469 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1470 | const colored_stderr = try termColor(allocator, escaped_stderr); | ||
| 1471 | try shell_out.writeAll(colored_stderr); | ||
| 1472 | break :code_block; | ||
| 1473 | } | ||
| 1474 | const exec_result = exec(allocator, &env_map, tmp_dir_name, build_args.items) catch | ||
| 1475 | return parseError(tokenizer, code.source_token, "example failed to compile", .{}); | ||
| 1476 | |||
| 1477 | if (code.verbose_cimport) { | ||
| 1478 | const escaped_build_stderr = try escapeHtml(allocator, exec_result.stderr); | ||
| 1479 | try shell_out.writeAll(escaped_build_stderr); | ||
| 1480 | } | ||
| 1481 | |||
| 1482 | if (code.target_str) |triple| { | ||
| 1483 | if (mem.startsWith(u8, triple, "wasm32") or | ||
| 1484 | mem.startsWith(u8, triple, "riscv64-linux") or | ||
| 1485 | (mem.startsWith(u8, triple, "x86_64-linux") and | ||
| 1486 | builtin.os.tag != .linux or builtin.cpu.arch != .x86_64)) | ||
| 1487 | { | ||
| 1488 | // skip execution | ||
| 1489 | break :code_block; | ||
| 1490 | } | ||
| 1491 | } | ||
| 1492 | |||
| 1493 | const path_to_exe = try std.fmt.allocPrint(allocator, "./{s}{s}", .{ | ||
| 1494 | code.name, | ||
| 1495 | target.exeFileExt(), | ||
| 1496 | }); | ||
| 1497 | const run_args = &[_][]const u8{path_to_exe}; | ||
| 1498 | |||
| 1499 | var exited_with_signal = false; | ||
| 1500 | |||
| 1501 | const result = if (expected_outcome == .fail) blk: { | ||
| 1502 | const result = try ChildProcess.exec(.{ | ||
| 1503 | .allocator = allocator, | ||
| 1504 | .argv = run_args, | ||
| 1505 | .env_map = &env_map, | ||
| 1506 | .cwd = tmp_dir_name, | ||
| 1507 | .max_output_bytes = max_doc_file_size, | ||
| 1508 | }); | ||
| 1509 | switch (result.term) { | ||
| 1510 | .Exited => |exit_code| { | ||
| 1511 | if (exit_code == 0) { | ||
| 1512 | progress.log("", .{}); | ||
| 1513 | print("{s}\nThe following command incorrectly succeeded:\n", .{result.stderr}); | ||
| 1514 | dumpArgs(run_args); | ||
| 1515 | return parseError(tokenizer, code.source_token, "example incorrectly compiled", .{}); | ||
| 1516 | } | ||
| 1517 | }, | ||
| 1518 | .Signal => exited_with_signal = true, | ||
| 1519 | else => {}, | ||
| 1520 | } | ||
| 1521 | break :blk result; | ||
| 1522 | } else blk: { | ||
| 1523 | break :blk exec(allocator, &env_map, tmp_dir_name, run_args) catch return parseError(tokenizer, code.source_token, "example crashed", .{}); | ||
| 1524 | }; | ||
| 1525 | |||
| 1526 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1527 | const escaped_stdout = try escapeHtml(allocator, result.stdout); | ||
| 1528 | |||
| 1529 | const colored_stderr = try termColor(allocator, escaped_stderr); | ||
| 1530 | const colored_stdout = try termColor(allocator, escaped_stdout); | ||
| 1531 | |||
| 1532 | try shell_out.print("$ ./{s}\n{s}{s}", .{ code.name, colored_stdout, colored_stderr }); | ||
| 1533 | if (exited_with_signal) { | ||
| 1534 | try shell_out.print("(process terminated by signal)", .{}); | ||
| 1535 | } | ||
| 1536 | try shell_out.writeAll("\n"); | ||
| 1537 | }, | ||
| 1538 | .@"test" => { | ||
| 1539 | var test_args = std.ArrayList([]const u8).init(allocator); | ||
| 1540 | defer test_args.deinit(); | ||
| 1541 | |||
| 1542 | try test_args.appendSlice(&[_][]const u8{ | ||
| 1543 | zig_exe, "test", | ||
| 1544 | tmp_source_file_name, | ||
| 1545 | }); | ||
| 1546 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1547 | try test_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir }); | ||
| 1548 | } | ||
| 1549 | try shell_out.print("$ zig test {s}.zig ", .{code.name}); | ||
| 1550 | |||
| 1551 | switch (code.mode) { | ||
| 1552 | .Debug => {}, | ||
| 1553 | else => { | ||
| 1554 | try test_args.appendSlice(&[_][]const u8{ | ||
| 1555 | "-O", @tagName(code.mode), | ||
| 1556 | }); | ||
| 1557 | try shell_out.print("-O {s} ", .{@tagName(code.mode)}); | ||
| 1558 | }, | ||
| 1559 | } | ||
| 1560 | if (code.link_libc) { | ||
| 1561 | try test_args.append("-lc"); | ||
| 1562 | try shell_out.print("-lc ", .{}); | ||
| 1563 | } | ||
| 1564 | if (code.target_str) |triple| { | ||
| 1565 | try test_args.appendSlice(&[_][]const u8{ "-target", triple }); | ||
| 1566 | try shell_out.print("-target {s} ", .{triple}); | ||
| 1567 | |||
| 1568 | const cross_target = try std.zig.CrossTarget.parse(.{ | ||
| 1569 | .arch_os_abi = triple, | ||
| 1570 | }); | ||
| 1571 | const target_info = try std.zig.system.NativeTargetInfo.detect( | ||
| 1572 | cross_target, | ||
| 1573 | ); | ||
| 1574 | switch (host.getExternalExecutor(target_info, .{ | ||
| 1575 | .link_libc = code.link_libc, | ||
| 1576 | })) { | ||
| 1577 | .native => {}, | ||
| 1578 | else => { | ||
| 1579 | try test_args.appendSlice(&[_][]const u8{"--test-no-exec"}); | ||
| 1580 | try shell_out.writeAll("--test-no-exec"); | ||
| 1581 | }, | ||
| 1582 | } | ||
| 1583 | } | ||
| 1584 | const result = exec(allocator, &env_map, null, test_args.items) catch | ||
| 1585 | return parseError(tokenizer, code.source_token, "test failed", .{}); | ||
| 1586 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1587 | const escaped_stdout = try escapeHtml(allocator, result.stdout); | ||
| 1588 | try shell_out.print("\n{s}{s}\n", .{ escaped_stderr, escaped_stdout }); | ||
| 1589 | }, | ||
| 1590 | .test_error => |error_match| { | ||
| 1591 | var test_args = std.ArrayList([]const u8).init(allocator); | ||
| 1592 | defer test_args.deinit(); | ||
| 1593 | |||
| 1594 | try test_args.appendSlice(&[_][]const u8{ | ||
| 1595 | zig_exe, "test", | ||
| 1596 | "--color", "on", | ||
| 1597 | tmp_source_file_name, | ||
| 1598 | }); | ||
| 1599 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1600 | try test_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir }); | ||
| 1601 | } | ||
| 1602 | try shell_out.print("$ zig test {s}.zig ", .{code.name}); | ||
| 1603 | |||
| 1604 | switch (code.mode) { | ||
| 1605 | .Debug => {}, | ||
| 1606 | else => { | ||
| 1607 | try test_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) }); | ||
| 1608 | try shell_out.print("-O {s} ", .{@tagName(code.mode)}); | ||
| 1609 | }, | ||
| 1610 | } | ||
| 1611 | if (code.link_libc) { | ||
| 1612 | try test_args.append("-lc"); | ||
| 1613 | try shell_out.print("-lc ", .{}); | ||
| 1614 | } | ||
| 1615 | const result = try ChildProcess.exec(.{ | ||
| 1616 | .allocator = allocator, | ||
| 1617 | .argv = test_args.items, | ||
| 1618 | .env_map = &env_map, | ||
| 1619 | .max_output_bytes = max_doc_file_size, | ||
| 1620 | }); | ||
| 1621 | switch (result.term) { | ||
| 1622 | .Exited => |exit_code| { | ||
| 1623 | if (exit_code == 0) { | ||
| 1624 | progress.log("", .{}); | ||
| 1625 | print("{s}\nThe following command incorrectly succeeded:\n", .{result.stderr}); | ||
| 1626 | dumpArgs(test_args.items); | ||
| 1627 | return parseError(tokenizer, code.source_token, "example incorrectly compiled", .{}); | ||
| 1628 | } | ||
| 1629 | }, | ||
| 1630 | else => { | ||
| 1631 | progress.log("", .{}); | ||
| 1632 | print("{s}\nThe following command crashed:\n", .{result.stderr}); | ||
| 1633 | dumpArgs(test_args.items); | ||
| 1634 | return parseError(tokenizer, code.source_token, "example compile crashed", .{}); | ||
| 1635 | }, | ||
| 1636 | } | ||
| 1637 | if (mem.indexOf(u8, result.stderr, error_match) == null) { | ||
| 1638 | progress.log("", .{}); | ||
| 1639 | print("{s}\nExpected to find '{s}' in stderr\n", .{ result.stderr, error_match }); | ||
| 1640 | return parseError(tokenizer, code.source_token, "example did not have expected compile error", .{}); | ||
| 1641 | } | ||
| 1642 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1643 | const colored_stderr = try termColor(allocator, escaped_stderr); | ||
| 1644 | try shell_out.print("\n{s}\n", .{colored_stderr}); | ||
| 1645 | }, | ||
| 1646 | .test_safety => |error_match| { | ||
| 1647 | var test_args = std.ArrayList([]const u8).init(allocator); | ||
| 1648 | defer test_args.deinit(); | ||
| 1649 | |||
| 1650 | try test_args.appendSlice(&[_][]const u8{ | ||
| 1651 | zig_exe, "test", | ||
| 1652 | tmp_source_file_name, | ||
| 1653 | }); | ||
| 1654 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1655 | try test_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir }); | ||
| 1656 | } | ||
| 1657 | var mode_arg: []const u8 = ""; | ||
| 1658 | switch (code.mode) { | ||
| 1659 | .Debug => {}, | ||
| 1660 | .ReleaseSafe => { | ||
| 1661 | try test_args.append("-OReleaseSafe"); | ||
| 1662 | mode_arg = "-OReleaseSafe"; | ||
| 1663 | }, | ||
| 1664 | .ReleaseFast => { | ||
| 1665 | try test_args.append("-OReleaseFast"); | ||
| 1666 | mode_arg = "-OReleaseFast"; | ||
| 1667 | }, | ||
| 1668 | .ReleaseSmall => { | ||
| 1669 | try test_args.append("-OReleaseSmall"); | ||
| 1670 | mode_arg = "-OReleaseSmall"; | ||
| 1671 | }, | ||
| 1672 | } | ||
| 1673 | |||
| 1674 | const result = try ChildProcess.exec(.{ | ||
| 1675 | .allocator = allocator, | ||
| 1676 | .argv = test_args.items, | ||
| 1677 | .env_map = &env_map, | ||
| 1678 | .max_output_bytes = max_doc_file_size, | ||
| 1679 | }); | ||
| 1680 | switch (result.term) { | ||
| 1681 | .Exited => |exit_code| { | ||
| 1682 | if (exit_code == 0) { | ||
| 1683 | progress.log("", .{}); | ||
| 1684 | print("{s}\nThe following command incorrectly succeeded:\n", .{result.stderr}); | ||
| 1685 | dumpArgs(test_args.items); | ||
| 1686 | return parseError(tokenizer, code.source_token, "example test incorrectly succeeded", .{}); | ||
| 1687 | } | ||
| 1688 | }, | ||
| 1689 | else => { | ||
| 1690 | progress.log("", .{}); | ||
| 1691 | print("{s}\nThe following command crashed:\n", .{result.stderr}); | ||
| 1692 | dumpArgs(test_args.items); | ||
| 1693 | return parseError(tokenizer, code.source_token, "example compile crashed", .{}); | ||
| 1694 | }, | ||
| 1695 | } | ||
| 1696 | if (mem.indexOf(u8, result.stderr, error_match) == null) { | ||
| 1697 | progress.log("", .{}); | ||
| 1698 | print("{s}\nExpected to find '{s}' in stderr\n", .{ result.stderr, error_match }); | ||
| 1699 | return parseError(tokenizer, code.source_token, "example did not have expected runtime safety error message", .{}); | ||
| 1700 | } | ||
| 1701 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1702 | const colored_stderr = try termColor(allocator, escaped_stderr); | ||
| 1703 | try shell_out.print("$ zig test {s}.zig {s}\n{s}\n", .{ | ||
| 1704 | code.name, | ||
| 1705 | mode_arg, | ||
| 1706 | colored_stderr, | ||
| 1707 | }); | ||
| 1708 | }, | ||
| 1709 | .obj => |maybe_error_match| { | ||
| 1710 | const name_plus_obj_ext = try std.fmt.allocPrint(allocator, "{s}{s}", .{ code.name, obj_ext }); | ||
| 1711 | var build_args = std.ArrayList([]const u8).init(allocator); | ||
| 1712 | defer build_args.deinit(); | ||
| 1713 | |||
| 1714 | try build_args.appendSlice(&[_][]const u8{ | ||
| 1715 | zig_exe, "build-obj", | ||
| 1716 | "--color", "on", | ||
| 1717 | "--name", code.name, | ||
| 1718 | tmp_source_file_name, | ||
| 1719 | try std.fmt.allocPrint(allocator, "-femit-bin={s}{c}{s}", .{ | ||
| 1720 | tmp_dir_name, fs.path.sep, name_plus_obj_ext, | ||
| 1721 | }), | ||
| 1722 | }); | ||
| 1723 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1724 | try build_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir }); | ||
| 1725 | } | ||
| 1726 | |||
| 1727 | try shell_out.print("$ zig build-obj {s}.zig ", .{code.name}); | ||
| 1728 | |||
| 1729 | switch (code.mode) { | ||
| 1730 | .Debug => {}, | ||
| 1731 | else => { | ||
| 1732 | try build_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) }); | ||
| 1733 | try shell_out.print("-O {s} ", .{@tagName(code.mode)}); | ||
| 1734 | }, | ||
| 1735 | } | ||
| 1736 | |||
| 1737 | if (code.target_str) |triple| { | ||
| 1738 | try build_args.appendSlice(&[_][]const u8{ "-target", triple }); | ||
| 1739 | try shell_out.print("-target {s} ", .{triple}); | ||
| 1740 | } | ||
| 1741 | for (code.additional_options) |option| { | ||
| 1742 | try build_args.append(option); | ||
| 1743 | try shell_out.print("{s} ", .{option}); | ||
| 1744 | } | ||
| 1745 | |||
| 1746 | if (maybe_error_match) |error_match| { | ||
| 1747 | const result = try ChildProcess.exec(.{ | ||
| 1748 | .allocator = allocator, | ||
| 1749 | .argv = build_args.items, | ||
| 1750 | .env_map = &env_map, | ||
| 1751 | .max_output_bytes = max_doc_file_size, | ||
| 1752 | }); | ||
| 1753 | switch (result.term) { | ||
| 1754 | .Exited => |exit_code| { | ||
| 1755 | if (exit_code == 0) { | ||
| 1756 | progress.log("", .{}); | ||
| 1757 | print("{s}\nThe following command incorrectly succeeded:\n", .{result.stderr}); | ||
| 1758 | dumpArgs(build_args.items); | ||
| 1759 | return parseError(tokenizer, code.source_token, "example build incorrectly succeeded", .{}); | ||
| 1760 | } | ||
| 1761 | }, | ||
| 1762 | else => { | ||
| 1763 | progress.log("", .{}); | ||
| 1764 | print("{s}\nThe following command crashed:\n", .{result.stderr}); | ||
| 1765 | dumpArgs(build_args.items); | ||
| 1766 | return parseError(tokenizer, code.source_token, "example compile crashed", .{}); | ||
| 1767 | }, | ||
| 1768 | } | ||
| 1769 | if (mem.indexOf(u8, result.stderr, error_match) == null) { | ||
| 1770 | progress.log("", .{}); | ||
| 1771 | print("{s}\nExpected to find '{s}' in stderr\n", .{ result.stderr, error_match }); | ||
| 1772 | return parseError(tokenizer, code.source_token, "example did not have expected compile error message", .{}); | ||
| 1773 | } | ||
| 1774 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1775 | const colored_stderr = try termColor(allocator, escaped_stderr); | ||
| 1776 | try shell_out.print("\n{s} ", .{colored_stderr}); | ||
| 1777 | } else { | ||
| 1778 | _ = exec(allocator, &env_map, null, build_args.items) catch return parseError(tokenizer, code.source_token, "example failed to compile", .{}); | ||
| 1779 | } | ||
| 1780 | try shell_out.writeAll("\n"); | ||
| 1781 | }, | ||
| 1782 | .lib => { | ||
| 1783 | const bin_basename = try std.zig.binNameAlloc(allocator, .{ | ||
| 1784 | .root_name = code.name, | ||
| 1785 | .target = builtin.target, | ||
| 1786 | .output_mode = .Lib, | ||
| 1787 | }); | ||
| 1788 | |||
| 1789 | var test_args = std.ArrayList([]const u8).init(allocator); | ||
| 1790 | defer test_args.deinit(); | ||
| 1791 | |||
| 1792 | try test_args.appendSlice(&[_][]const u8{ | ||
| 1793 | zig_exe, "build-lib", | ||
| 1794 | tmp_source_file_name, | ||
| 1795 | try std.fmt.allocPrint(allocator, "-femit-bin={s}{s}{s}", .{ | ||
| 1796 | tmp_dir_name, fs.path.sep_str, bin_basename, | ||
| 1797 | }), | ||
| 1798 | }); | ||
| 1799 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1800 | try test_args.appendSlice(&.{ "--zig-lib-dir", zig_lib_dir }); | ||
| 1801 | } | ||
| 1802 | try shell_out.print("$ zig build-lib {s}.zig ", .{code.name}); | ||
| 1803 | |||
| 1804 | switch (code.mode) { | ||
| 1805 | .Debug => {}, | ||
| 1806 | else => { | ||
| 1807 | try test_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) }); | ||
| 1808 | try shell_out.print("-O {s} ", .{@tagName(code.mode)}); | ||
| 1809 | }, | ||
| 1810 | } | ||
| 1811 | if (code.target_str) |triple| { | ||
| 1812 | try test_args.appendSlice(&[_][]const u8{ "-target", triple }); | ||
| 1813 | try shell_out.print("-target {s} ", .{triple}); | ||
| 1814 | } | ||
| 1815 | if (code.link_mode) |link_mode| { | ||
| 1816 | switch (link_mode) { | ||
| 1817 | .Static => { | ||
| 1818 | try test_args.append("-static"); | ||
| 1819 | try shell_out.print("-static ", .{}); | ||
| 1820 | }, | ||
| 1821 | .Dynamic => { | ||
| 1822 | try test_args.append("-dynamic"); | ||
| 1823 | try shell_out.print("-dynamic ", .{}); | ||
| 1824 | }, | ||
| 1825 | } | ||
| 1826 | } | ||
| 1827 | for (code.additional_options) |option| { | ||
| 1828 | try test_args.append(option); | ||
| 1829 | try shell_out.print("{s} ", .{option}); | ||
| 1830 | } | ||
| 1831 | const result = exec(allocator, &env_map, null, test_args.items) catch return parseError(tokenizer, code.source_token, "test failed", .{}); | ||
| 1832 | const escaped_stderr = try escapeHtml(allocator, result.stderr); | ||
| 1833 | const escaped_stdout = try escapeHtml(allocator, result.stdout); | ||
| 1834 | try shell_out.print("\n{s}{s}\n", .{ escaped_stderr, escaped_stdout }); | ||
| 1835 | }, | ||
| 1836 | } | ||
| 1837 | |||
| 1838 | if (!code.just_check_syntax) { | ||
| 1839 | try printShell(out, shell_buffer.items, false); | ||
| 1840 | } | ||
| 1841 | }, | ||
| 1842 | } | ||
| 1843 | } | ||
| 1844 | } | ||
| 1845 | |||
| 1846 | fn exec( | ||
| 1847 | allocator: Allocator, | ||
| 1848 | env_map: *process.EnvMap, | ||
| 1849 | cwd: ?[]const u8, | ||
| 1850 | args: []const []const u8, | ||
| 1851 | ) !ChildProcess.ExecResult { | ||
| 1852 | const result = try ChildProcess.exec(.{ | ||
| 1853 | .allocator = allocator, | ||
| 1854 | .argv = args, | ||
| 1855 | .env_map = env_map, | ||
| 1856 | .cwd = cwd, | ||
| 1857 | .max_output_bytes = max_doc_file_size, | ||
| 1858 | }); | ||
| 1859 | switch (result.term) { | ||
| 1860 | .Exited => |exit_code| { | ||
| 1861 | if (exit_code != 0) { | ||
| 1862 | print("{s}\nThe following command exited with code {}:\n", .{ result.stderr, exit_code }); | ||
| 1863 | dumpArgs(args); | ||
| 1864 | return error.ChildExitError; | ||
| 1865 | } | ||
| 1866 | }, | ||
| 1867 | else => { | ||
| 1868 | print("{s}\nThe following command crashed:\n", .{result.stderr}); | ||
| 1869 | dumpArgs(args); | ||
| 1870 | return error.ChildCrashed; | ||
| 1871 | }, | ||
| 1872 | } | ||
| 1873 | return result; | ||
| 1874 | } | ||
| 1875 | |||
| 1876 | fn getBuiltinCode( | ||
| 1877 | allocator: Allocator, | ||
| 1878 | env_map: *process.EnvMap, | ||
| 1879 | zig_exe: []const u8, | ||
| 1880 | opt_zig_lib_dir: ?[]const u8, | ||
| 1881 | ) ![]const u8 { | ||
| 1882 | if (opt_zig_lib_dir) |zig_lib_dir| { | ||
| 1883 | const result = try exec(allocator, env_map, null, &.{ | ||
| 1884 | zig_exe, "build-obj", "--show-builtin", "--zig-lib-dir", zig_lib_dir, | ||
| 1885 | }); | ||
| 1886 | return result.stdout; | ||
| 1887 | } else { | ||
| 1888 | const result = try exec(allocator, env_map, null, &.{ | ||
| 1889 | zig_exe, "build-obj", "--show-builtin", | ||
| 1890 | }); | ||
| 1891 | return result.stdout; | ||
| 1892 | } | ||
| 1893 | } | ||
| 1894 | |||
| 1895 | fn dumpArgs(args: []const []const u8) void { | ||
| 1896 | for (args) |arg| | ||
| 1897 | print("{s} ", .{arg}) | ||
| 1898 | else | ||
| 1899 | print("\n", .{}); | ||
| 1900 | } | ||
| 1901 | |||
| 1902 | test "term supported colors" { | ||
| 1903 | const test_allocator = testing.allocator; | ||
| 1904 | |||
| 1905 | { | ||
| 1906 | const input = "A\x1b[31;1mred\x1b[0mB"; | ||
| 1907 | const expect = "A<span class=\"sgr-31_1m\">red</span>B"; | ||
| 1908 | |||
| 1909 | const result = try termColor(test_allocator, input); | ||
| 1910 | defer test_allocator.free(result); | ||
| 1911 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1912 | } | ||
| 1913 | |||
| 1914 | { | ||
| 1915 | const input = "A\x1b[32;1mgreen\x1b[0mB"; | ||
| 1916 | const expect = "A<span class=\"sgr-32_1m\">green</span>B"; | ||
| 1917 | |||
| 1918 | const result = try termColor(test_allocator, input); | ||
| 1919 | defer test_allocator.free(result); | ||
| 1920 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1921 | } | ||
| 1922 | |||
| 1923 | { | ||
| 1924 | const input = "A\x1b[36;1mcyan\x1b[0mB"; | ||
| 1925 | const expect = "A<span class=\"sgr-36_1m\">cyan</span>B"; | ||
| 1926 | |||
| 1927 | const result = try termColor(test_allocator, input); | ||
| 1928 | defer test_allocator.free(result); | ||
| 1929 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1930 | } | ||
| 1931 | |||
| 1932 | { | ||
| 1933 | const input = "A\x1b[1mbold\x1b[0mB"; | ||
| 1934 | const expect = "A<span class=\"sgr-1m\">bold</span>B"; | ||
| 1935 | |||
| 1936 | const result = try termColor(test_allocator, input); | ||
| 1937 | defer test_allocator.free(result); | ||
| 1938 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1939 | } | ||
| 1940 | |||
| 1941 | { | ||
| 1942 | const input = "A\x1b[2mdim\x1b[0mB"; | ||
| 1943 | const expect = "A<span class=\"sgr-2m\">dim</span>B"; | ||
| 1944 | |||
| 1945 | const result = try termColor(test_allocator, input); | ||
| 1946 | defer test_allocator.free(result); | ||
| 1947 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1948 | } | ||
| 1949 | } | ||
| 1950 | |||
| 1951 | test "term output from zig" { | ||
| 1952 | // Use data generated by https://github.com/perillo/zig-tty-test-data, | ||
| 1953 | // with zig version 0.11.0-dev.1898+36d47dd19. | ||
| 1954 | const test_allocator = testing.allocator; | ||
| 1955 | |||
| 1956 | { | ||
| 1957 | // 1.1-with-build-progress.out | ||
| 1958 | const input = "Semantic Analysis [1324] \x1b[25D\x1b[0KLLVM Emit Object... \x1b[20D\x1b[0KLLVM Emit Object... \x1b[20D\x1b[0KLLD Link... \x1b[12D\x1b[0K"; | ||
| 1959 | const expect = ""; | ||
| 1960 | |||
| 1961 | const result = try termColor(test_allocator, input); | ||
| 1962 | defer test_allocator.free(result); | ||
| 1963 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1964 | } | ||
| 1965 | |||
| 1966 | { | ||
| 1967 | // 2.1-with-reference-traces.out | ||
| 1968 | const input = "\x1b[1msrc/2.1-with-reference-traces.zig:3:7: \x1b[31;1merror: \x1b[0m\x1b[1mcannot assign to constant\n\x1b[0m x += 1;\n \x1b[32;1m~~^~~~\n\x1b[0m\x1b[0m\x1b[2mreferenced by:\n main: src/2.1-with-reference-traces.zig:7:5\n callMain: /usr/local/lib/zig/lib/std/start.zig:607:17\n remaining reference traces hidden; use '-freference-trace' to see all reference traces\n\n\x1b[0m"; | ||
| 1969 | const expect = | ||
| 1970 | \\<span class="sgr-1m">src/2.1-with-reference-traces.zig:3:7: </span><span class="sgr-31_1m">error: </span><span class="sgr-1m">cannot assign to constant | ||
| 1971 | \\</span> x += 1; | ||
| 1972 | \\ <span class="sgr-32_1m">~~^~~~ | ||
| 1973 | \\</span><span class="sgr-2m">referenced by: | ||
| 1974 | \\ main: src/2.1-with-reference-traces.zig:7:5 | ||
| 1975 | \\ callMain: /usr/local/lib/zig/lib/std/start.zig:607:17 | ||
| 1976 | \\ remaining reference traces hidden; use '-freference-trace' to see all reference traces | ||
| 1977 | \\ | ||
| 1978 | \\</span> | ||
| 1979 | ; | ||
| 1980 | |||
| 1981 | const result = try termColor(test_allocator, input); | ||
| 1982 | defer test_allocator.free(result); | ||
| 1983 | try testing.expectEqualSlices(u8, expect, result); | ||
| 1984 | } | ||
| 1985 | |||
| 1986 | { | ||
| 1987 | // 2.2-without-reference-traces.out | ||
| 1988 | const input = "\x1b[1m/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:128:29: \x1b[31;1merror: \x1b[0m\x1b[1minvalid type given to fixedBufferStream\n\x1b[0m else => @compileError(\"invalid type given to fixedBufferStream\"),\n \x1b[32;1m^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\x1b[0m\x1b[1m/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:116:66: \x1b[36;1mnote: \x1b[0m\x1b[1mcalled from here\n\x1b[0mpub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) {\n; \x1b[32;1m~~~~~^~~~~~~~~~~~~~~~~\n\x1b[0m"; | ||
| 1989 | const expect = | ||
| 1990 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:128:29: </span><span class="sgr-31_1m">error: </span><span class="sgr-1m">invalid type given to fixedBufferStream | ||
| 1991 | \\</span> else => @compileError("invalid type given to fixedBufferStream"), | ||
| 1992 | \\ <span class="sgr-32_1m">^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 1993 | \\</span><span class="sgr-1m">/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:116:66: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">called from here | ||
| 1994 | \\</span>pub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) { | ||
| 1995 | \\; <span class="sgr-32_1m">~~~~~^~~~~~~~~~~~~~~~~ | ||
| 1996 | \\</span> | ||
| 1997 | ; | ||
| 1998 | |||
| 1999 | const result = try termColor(test_allocator, input); | ||
| 2000 | defer test_allocator.free(result); | ||
| 2001 | try testing.expectEqualSlices(u8, expect, result); | ||
| 2002 | } | ||
| 2003 | |||
| 2004 | { | ||
| 2005 | // 2.3-with-notes.out | ||
| 2006 | const input = "\x1b[1msrc/2.3-with-notes.zig:6:9: \x1b[31;1merror: \x1b[0m\x1b[1mexpected type '*2.3-with-notes.Derp', found '*2.3-with-notes.Wat'\n\x1b[0m bar(w);\n \x1b[32;1m^\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:6:9: \x1b[36;1mnote: \x1b[0m\x1b[1mpointer type child '2.3-with-notes.Wat' cannot cast into pointer type child '2.3-with-notes.Derp'\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:2:13: \x1b[36;1mnote: \x1b[0m\x1b[1mopaque declared here\n\x1b[0mconst Wat = opaque {};\n \x1b[32;1m^~~~~~~~~\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:1:14: \x1b[36;1mnote: \x1b[0m\x1b[1mopaque declared here\n\x1b[0mconst Derp = opaque {};\n \x1b[32;1m^~~~~~~~~\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:4:18: \x1b[36;1mnote: \x1b[0m\x1b[1mparameter type declared here\n\x1b[0mextern fn bar(d: *Derp) void;\n \x1b[32;1m^~~~~\n\x1b[0m\x1b[0m\x1b[2mreferenced by:\n main: src/2.3-with-notes.zig:10:5\n callMain: /usr/local/lib/zig/lib/std/start.zig:607:17\n remaining reference traces hidden; use '-freference-trace' to see all reference traces\n\n\x1b[0m"; | ||
| 2007 | const expect = | ||
| 2008 | \\<span class="sgr-1m">src/2.3-with-notes.zig:6:9: </span><span class="sgr-31_1m">error: </span><span class="sgr-1m">expected type '*2.3-with-notes.Derp', found '*2.3-with-notes.Wat' | ||
| 2009 | \\</span> bar(w); | ||
| 2010 | \\ <span class="sgr-32_1m">^ | ||
| 2011 | \\</span><span class="sgr-1m">src/2.3-with-notes.zig:6:9: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">pointer type child '2.3-with-notes.Wat' cannot cast into pointer type child '2.3-with-notes.Derp' | ||
| 2012 | \\</span><span class="sgr-1m">src/2.3-with-notes.zig:2:13: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">opaque declared here | ||
| 2013 | \\</span>const Wat = opaque {}; | ||
| 2014 | \\ <span class="sgr-32_1m">^~~~~~~~~ | ||
| 2015 | \\</span><span class="sgr-1m">src/2.3-with-notes.zig:1:14: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">opaque declared here | ||
| 2016 | \\</span>const Derp = opaque {}; | ||
| 2017 | \\ <span class="sgr-32_1m">^~~~~~~~~ | ||
| 2018 | \\</span><span class="sgr-1m">src/2.3-with-notes.zig:4:18: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">parameter type declared here | ||
| 2019 | \\</span>extern fn bar(d: *Derp) void; | ||
| 2020 | \\ <span class="sgr-32_1m">^~~~~ | ||
| 2021 | \\</span><span class="sgr-2m">referenced by: | ||
| 2022 | \\ main: src/2.3-with-notes.zig:10:5 | ||
| 2023 | \\ callMain: /usr/local/lib/zig/lib/std/start.zig:607:17 | ||
| 2024 | \\ remaining reference traces hidden; use '-freference-trace' to see all reference traces | ||
| 2025 | \\ | ||
| 2026 | \\</span> | ||
| 2027 | ; | ||
| 2028 | |||
| 2029 | const result = try termColor(test_allocator, input); | ||
| 2030 | defer test_allocator.free(result); | ||
| 2031 | try testing.expectEqualSlices(u8, expect, result); | ||
| 2032 | } | ||
| 2033 | |||
| 2034 | { | ||
| 2035 | // 3.1-with-error-return-traces.out | ||
| 2036 | |||
| 2037 | const input = "error: Error\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:5:5\x1b[0m: \x1b[2m0x20b008 in callee (3.1-with-error-return-traces)\x1b[0m\n return error.Error;\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:9:5\x1b[0m: \x1b[2m0x20b113 in caller (3.1-with-error-return-traces)\x1b[0m\n try callee();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:13:5\x1b[0m: \x1b[2m0x20b153 in main (3.1-with-error-return-traces)\x1b[0m\n try caller();\n \x1b[32;1m^\x1b[0m\n"; | ||
| 2038 | const expect = | ||
| 2039 | \\error: Error | ||
| 2040 | \\<span class="sgr-1m">/home/zig/src/3.1-with-error-return-traces.zig:5:5</span>: <span class="sgr-2m">0x20b008 in callee (3.1-with-error-return-traces)</span> | ||
| 2041 | \\ return error.Error; | ||
| 2042 | \\ <span class="sgr-32_1m">^</span> | ||
| 2043 | \\<span class="sgr-1m">/home/zig/src/3.1-with-error-return-traces.zig:9:5</span>: <span class="sgr-2m">0x20b113 in caller (3.1-with-error-return-traces)</span> | ||
| 2044 | \\ try callee(); | ||
| 2045 | \\ <span class="sgr-32_1m">^</span> | ||
| 2046 | \\<span class="sgr-1m">/home/zig/src/3.1-with-error-return-traces.zig:13:5</span>: <span class="sgr-2m">0x20b153 in main (3.1-with-error-return-traces)</span> | ||
| 2047 | \\ try caller(); | ||
| 2048 | \\ <span class="sgr-32_1m">^</span> | ||
| 2049 | \\ | ||
| 2050 | ; | ||
| 2051 | |||
| 2052 | const result = try termColor(test_allocator, input); | ||
| 2053 | defer test_allocator.free(result); | ||
| 2054 | try testing.expectEqualSlices(u8, expect, result); | ||
| 2055 | } | ||
| 2056 | |||
| 2057 | { | ||
| 2058 | // 3.2-with-stack-trace.out | ||
| 2059 | const input = "\x1b[1m/usr/local/lib/zig/lib/std/debug.zig:561:19\x1b[0m: \x1b[2m0x22a107 in writeCurrentStackTrace__anon_5898 (3.2-with-stack-trace)\x1b[0m\n while (it.next()) |return_address| {\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/debug.zig:157:80\x1b[0m: \x1b[2m0x20bb23 in dumpCurrentStackTrace (3.2-with-stack-trace)\x1b[0m\n writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(io.getStdErr()), start_addr) catch |err| {\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.2-with-stack-trace.zig:5:36\x1b[0m: \x1b[2m0x20d3b2 in foo (3.2-with-stack-trace)\x1b[0m\n std.debug.dumpCurrentStackTrace(null);\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.2-with-stack-trace.zig:9:8\x1b[0m: \x1b[2m0x20b458 in main (3.2-with-stack-trace)\x1b[0m\n foo();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/start.zig:607:22\x1b[0m: \x1b[2m0x20a965 in posixCallMainAndExit (3.2-with-stack-trace)\x1b[0m\n root.main();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/start.zig:376:5\x1b[0m: \x1b[2m0x20a411 in _start (3.2-with-stack-trace)\x1b[0m\n @call(.never_inline, posixCallMainAndExit, .{});\n \x1b[32;1m^\x1b[0m\n"; | ||
| 2060 | const expect = | ||
| 2061 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/debug.zig:561:19</span>: <span class="sgr-2m">0x22a107 in writeCurrentStackTrace__anon_5898 (3.2-with-stack-trace)</span> | ||
| 2062 | \\ while (it.next()) |return_address| { | ||
| 2063 | \\ <span class="sgr-32_1m">^</span> | ||
| 2064 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/debug.zig:157:80</span>: <span class="sgr-2m">0x20bb23 in dumpCurrentStackTrace (3.2-with-stack-trace)</span> | ||
| 2065 | \\ writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(io.getStdErr()), start_addr) catch |err| { | ||
| 2066 | \\ <span class="sgr-32_1m">^</span> | ||
| 2067 | \\<span class="sgr-1m">/home/zig/src/3.2-with-stack-trace.zig:5:36</span>: <span class="sgr-2m">0x20d3b2 in foo (3.2-with-stack-trace)</span> | ||
| 2068 | \\ std.debug.dumpCurrentStackTrace(null); | ||
| 2069 | \\ <span class="sgr-32_1m">^</span> | ||
| 2070 | \\<span class="sgr-1m">/home/zig/src/3.2-with-stack-trace.zig:9:8</span>: <span class="sgr-2m">0x20b458 in main (3.2-with-stack-trace)</span> | ||
| 2071 | \\ foo(); | ||
| 2072 | \\ <span class="sgr-32_1m">^</span> | ||
| 2073 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/start.zig:607:22</span>: <span class="sgr-2m">0x20a965 in posixCallMainAndExit (3.2-with-stack-trace)</span> | ||
| 2074 | \\ root.main(); | ||
| 2075 | \\ <span class="sgr-32_1m">^</span> | ||
| 2076 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/start.zig:376:5</span>: <span class="sgr-2m">0x20a411 in _start (3.2-with-stack-trace)</span> | ||
| 2077 | \\ @call(.never_inline, posixCallMainAndExit, .{}); | ||
| 2078 | \\ <span class="sgr-32_1m">^</span> | ||
| 2079 | \\ | ||
| 2080 | ; | ||
| 2081 | |||
| 2082 | const result = try termColor(test_allocator, input); | ||
| 2083 | defer test_allocator.free(result); | ||
| 2084 | try testing.expectEqualSlices(u8, expect, result); | ||
| 2085 | } | ||
| 2086 | } | ||
| 2087 | |||
| 2088 | test "printShell" { | ||
| 2089 | const test_allocator = std.testing.allocator; | ||
| 2090 | |||
| 2091 | { | ||
| 2092 | const shell_out = | ||
| 2093 | \\$ zig build test.zig | ||
| 2094 | ; | ||
| 2095 | const expected = | ||
| 2096 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> | ||
| 2097 | \\</samp></pre></figure> | ||
| 2098 | ; | ||
| 2099 | |||
| 2100 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2101 | defer buffer.deinit(); | ||
| 2102 | |||
| 2103 | try printShell(buffer.writer(), shell_out, false); | ||
| 2104 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2105 | } | ||
| 2106 | { | ||
| 2107 | const shell_out = | ||
| 2108 | \\$ zig build test.zig | ||
| 2109 | \\build output | ||
| 2110 | ; | ||
| 2111 | const expected = | ||
| 2112 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> | ||
| 2113 | \\build output | ||
| 2114 | \\</samp></pre></figure> | ||
| 2115 | ; | ||
| 2116 | |||
| 2117 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2118 | defer buffer.deinit(); | ||
| 2119 | |||
| 2120 | try printShell(buffer.writer(), shell_out, false); | ||
| 2121 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2122 | } | ||
| 2123 | { | ||
| 2124 | const shell_out = | ||
| 2125 | \\$ zig build test.zig | ||
| 2126 | \\build output | ||
| 2127 | \\$ ./test | ||
| 2128 | ; | ||
| 2129 | const expected = | ||
| 2130 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> | ||
| 2131 | \\build output | ||
| 2132 | \\$ <kbd>./test</kbd> | ||
| 2133 | \\</samp></pre></figure> | ||
| 2134 | ; | ||
| 2135 | |||
| 2136 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2137 | defer buffer.deinit(); | ||
| 2138 | |||
| 2139 | try printShell(buffer.writer(), shell_out, false); | ||
| 2140 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2141 | } | ||
| 2142 | { | ||
| 2143 | const shell_out = | ||
| 2144 | \\$ zig build test.zig | ||
| 2145 | \\ | ||
| 2146 | \\$ ./test | ||
| 2147 | \\output | ||
| 2148 | ; | ||
| 2149 | const expected = | ||
| 2150 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> | ||
| 2151 | \\ | ||
| 2152 | \\$ <kbd>./test</kbd> | ||
| 2153 | \\output | ||
| 2154 | \\</samp></pre></figure> | ||
| 2155 | ; | ||
| 2156 | |||
| 2157 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2158 | defer buffer.deinit(); | ||
| 2159 | |||
| 2160 | try printShell(buffer.writer(), shell_out, false); | ||
| 2161 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2162 | } | ||
| 2163 | { | ||
| 2164 | const shell_out = | ||
| 2165 | \\$ zig build test.zig | ||
| 2166 | \\$ ./test | ||
| 2167 | \\output | ||
| 2168 | ; | ||
| 2169 | const expected = | ||
| 2170 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> | ||
| 2171 | \\$ <kbd>./test</kbd> | ||
| 2172 | \\output | ||
| 2173 | \\</samp></pre></figure> | ||
| 2174 | ; | ||
| 2175 | |||
| 2176 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2177 | defer buffer.deinit(); | ||
| 2178 | |||
| 2179 | try printShell(buffer.writer(), shell_out, false); | ||
| 2180 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2181 | } | ||
| 2182 | { | ||
| 2183 | const shell_out = | ||
| 2184 | \\$ zig build test.zig \ | ||
| 2185 | \\ --build-option | ||
| 2186 | \\build output | ||
| 2187 | \\$ ./test | ||
| 2188 | \\output | ||
| 2189 | ; | ||
| 2190 | const expected = | ||
| 2191 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig \ | ||
| 2192 | \\ --build-option</kbd> | ||
| 2193 | \\build output | ||
| 2194 | \\$ <kbd>./test</kbd> | ||
| 2195 | \\output | ||
| 2196 | \\</samp></pre></figure> | ||
| 2197 | ; | ||
| 2198 | |||
| 2199 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2200 | defer buffer.deinit(); | ||
| 2201 | |||
| 2202 | try printShell(buffer.writer(), shell_out, false); | ||
| 2203 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2204 | } | ||
| 2205 | { | ||
| 2206 | // intentional space after "--build-option1 \" | ||
| 2207 | const shell_out = | ||
| 2208 | \\$ zig build test.zig \ | ||
| 2209 | \\ --build-option1 \ | ||
| 2210 | \\ --build-option2 | ||
| 2211 | \\$ ./test | ||
| 2212 | ; | ||
| 2213 | const expected = | ||
| 2214 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig \ | ||
| 2215 | \\ --build-option1 \ | ||
| 2216 | \\ --build-option2</kbd> | ||
| 2217 | \\$ <kbd>./test</kbd> | ||
| 2218 | \\</samp></pre></figure> | ||
| 2219 | ; | ||
| 2220 | |||
| 2221 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2222 | defer buffer.deinit(); | ||
| 2223 | |||
| 2224 | try printShell(buffer.writer(), shell_out, false); | ||
| 2225 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2226 | } | ||
| 2227 | { | ||
| 2228 | const shell_out = | ||
| 2229 | \\$ zig build test.zig \ | ||
| 2230 | \\$ ./test | ||
| 2231 | ; | ||
| 2232 | const expected = | ||
| 2233 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig \ | ||
| 2234 | \\$ ./test</kbd> | ||
| 2235 | \\</samp></pre></figure> | ||
| 2236 | ; | ||
| 2237 | |||
| 2238 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2239 | defer buffer.deinit(); | ||
| 2240 | |||
| 2241 | try printShell(buffer.writer(), shell_out, false); | ||
| 2242 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2243 | } | ||
| 2244 | { | ||
| 2245 | const shell_out = | ||
| 2246 | \\$ zig build test.zig | ||
| 2247 | \\$ ./test | ||
| 2248 | \\$1 | ||
| 2249 | ; | ||
| 2250 | const expected = | ||
| 2251 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$ <kbd>zig build test.zig</kbd> | ||
| 2252 | \\$ <kbd>./test</kbd> | ||
| 2253 | \\$1 | ||
| 2254 | \\</samp></pre></figure> | ||
| 2255 | ; | ||
| 2256 | |||
| 2257 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2258 | defer buffer.deinit(); | ||
| 2259 | |||
| 2260 | try printShell(buffer.writer(), shell_out, false); | ||
| 2261 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2262 | } | ||
| 2263 | { | ||
| 2264 | const shell_out = | ||
| 2265 | \\$zig build test.zig | ||
| 2266 | ; | ||
| 2267 | const expected = | ||
| 2268 | \\<figure><figcaption class="shell-cap">Shell</figcaption><pre><samp>$zig build test.zig | ||
| 2269 | \\</samp></pre></figure> | ||
| 2270 | ; | ||
| 2271 | |||
| 2272 | var buffer = std.ArrayList(u8).init(test_allocator); | ||
| 2273 | defer buffer.deinit(); | ||
| 2274 | |||
| 2275 | try printShell(buffer.writer(), shell_out, false); | ||
| 2276 | try testing.expectEqualSlices(u8, expected, buffer.items); | ||
| 2277 | } | ||
| 2278 | } | ||