| 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 | 36 | |
| 37 | 37 | const docgen_exe = b.addExecutable(.{ |
| 38 | 38 | .name = "docgen", |
| 39 | .root_source_file = .{ .path = "doc/docgen.zig" }, | |
| 39 | .root_source_file = .{ .path = "tools/docgen.zig" }, | |
| 40 | 40 | .target = .{}, |
| 41 | 41 | .optimize = .Debug, |
| 42 | 42 | }); |
| ... | ... | @@ -45,9 +45,10 @@ pub fn build(b: *std.Build) !void { |
| 45 | 45 | const docgen_cmd = b.addRunArtifact(docgen_exe); |
| 46 | 46 | docgen_cmd.addArgs(&.{ "--zig", b.zig_exe }); |
| 47 | 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 | 52 | const langref_file = docgen_cmd.addOutputFileArg("langref.html"); |
| 52 | 53 | const install_langref = b.addInstallFileWithDir(langref_file, .prefix, "doc/langref.html"); |
| 53 | 54 | if (!skip_install_langref) { |
| ... | ... | @@ -57,9 +58,8 @@ pub fn build(b: *std.Build) !void { |
| 57 | 58 | const autodoc_test = b.addTest(.{ |
| 58 | 59 | .root_source_file = .{ .path = "lib/std/std.zig" }, |
| 59 | 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 | 63 | const install_std_docs = b.addInstallDirectory(.{ |
| 64 | 64 | .source_dir = autodoc_test.getEmittedDocs(), |
| 65 | 65 | .install_dir = .prefix, |
| ... | ... | @@ -88,8 +88,8 @@ pub fn build(b: *std.Build) !void { |
| 88 | 88 | .name = "check-case", |
| 89 | 89 | .root_source_file = .{ .path = "test/src/Cases.zig" }, |
| 90 | 90 | .optimize = optimize, |
| 91 | .main_pkg_path = .{ .path = "." }, | |
| 91 | 92 | }); |
| 92 | check_case_exe.main_pkg_path = "."; | |
| 93 | 93 | check_case_exe.stack_size = stack_size; |
| 94 | 94 | check_case_exe.single_threaded = single_threaded; |
| 95 | 95 | |
| ... | ... | @@ -196,10 +196,6 @@ pub fn build(b: *std.Build) !void { |
| 196 | 196 | exe.pie = pie; |
| 197 | 197 | exe.sanitize_thread = sanitize_thread; |
| 198 | 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 | 200 | exe.build_id = b.option( |
| 205 | 201 | std.Build.Step.Compile.BuildId, |
| ... | ... | @@ -208,7 +204,7 @@ pub fn build(b: *std.Build) !void { |
| 208 | 204 | ); |
| 209 | 205 | |
| 210 | 206 | if (!no_bin) { |
| 211 | const install_exe = b.addInstallArtifact(exe); | |
| 207 | const install_exe = b.addInstallArtifact(exe, .{}); | |
| 212 | 208 | if (flat) { |
| 213 | 209 | install_exe.dest_dir = .prefix; |
| 214 | 210 | } |
| ... | ... | @@ -352,10 +348,9 @@ pub fn build(b: *std.Build) !void { |
| 352 | 348 | exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation); |
| 353 | 349 | exe_options.addOption(bool, "value_tracing", value_tracing); |
| 354 | 350 | if (tracy) |tracy_path| { |
| 355 | const client_cpp = fs.path.join( | |
| 356 | b.allocator, | |
| 351 | const client_cpp = b.pathJoin( | |
| 357 | 352 | &[_][]const u8{ tracy_path, "public", "TracyClient.cpp" }, |
| 358 | ) catch unreachable; | |
| 353 | ); | |
| 359 | 354 | |
| 360 | 355 | // On mingw, we need to opt into windows 7+ to get some features required by tracy. |
| 361 | 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 | 358 | else |
| 364 | 359 | &[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" }; |
| 365 | 360 | |
| 366 | exe.addIncludePath(tracy_path); | |
| 367 | exe.addCSourceFile(client_cpp, tracy_c_flags); | |
| 361 | exe.addIncludePath(.{ .cwd_relative = tracy_path }); | |
| 362 | exe.addCSourceFile(.{ .file = .{ .cwd_relative = client_cpp }, .flags = tracy_c_flags }); | |
| 368 | 363 | if (!enable_llvm) { |
| 369 | 364 | exe.linkSystemLibraryName("c++"); |
| 370 | 365 | } |
| ... | ... | @@ -554,7 +549,7 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { |
| 554 | 549 | }); |
| 555 | 550 | run_opt.addArtifactArg(exe); |
| 556 | 551 | run_opt.addArg("-o"); |
| 557 | run_opt.addFileSourceArg(.{ .path = "stage1/zig1.wasm" }); | |
| 552 | run_opt.addFileArg(.{ .path = "stage1/zig1.wasm" }); | |
| 558 | 553 | |
| 559 | 554 | const copy_zig_h = b.addWriteFiles(); |
| 560 | 555 | copy_zig_h.addCopyFileToSource(.{ .path = "lib/zig.h" }, "stage1/zig.h"); |
| ... | ... | @@ -603,7 +598,7 @@ fn addCmakeCfgOptionsToExe( |
| 603 | 598 | // useful for package maintainers |
| 604 | 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 | 602 | cfg.cmake_binary_dir, |
| 608 | 603 | "zigcpp", |
| 609 | 604 | b.fmt("{s}{s}{s}", .{ |
| ... | ... | @@ -611,11 +606,11 @@ fn addCmakeCfgOptionsToExe( |
| 611 | 606 | "zigcpp", |
| 612 | 607 | cfg.cmake_static_library_suffix, |
| 613 | 608 | }), |
| 614 | }) catch unreachable); | |
| 609 | }) }); | |
| 615 | 610 | assert(cfg.lld_include_dir.len != 0); |
| 616 | exe.addIncludePath(cfg.lld_include_dir); | |
| 617 | exe.addIncludePath(cfg.llvm_include_dir); | |
| 618 | exe.addLibraryPath(cfg.llvm_lib_dir); | |
| 611 | exe.addIncludePath(.{ .cwd_relative = cfg.lld_include_dir }); | |
| 612 | exe.addIncludePath(.{ .cwd_relative = cfg.llvm_include_dir }); | |
| 613 | exe.addLibraryPath(.{ .cwd_relative = cfg.llvm_lib_dir }); | |
| 619 | 614 | addCMakeLibraryList(exe, cfg.clang_libraries); |
| 620 | 615 | addCMakeLibraryList(exe, cfg.lld_libraries); |
| 621 | 616 | addCMakeLibraryList(exe, cfg.llvm_libraries); |
| ... | ... | @@ -671,7 +666,7 @@ fn addCmakeCfgOptionsToExe( |
| 671 | 666 | } |
| 672 | 667 | |
| 673 | 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 | 727 | } |
| 733 | 728 | return error.RequiredLibraryNotFound; |
| 734 | 729 | } |
| 735 | exe.addObjectFile(path_unpadded); | |
| 730 | exe.addObjectFile(.{ .cwd_relative = path_unpadded }); | |
| 736 | 731 | |
| 737 | 732 | // TODO a way to integrate with system c++ include files here |
| 738 | 733 | // c++ -E -Wp,-v -xc++ /dev/null |
| ... | ... | @@ -752,7 +747,7 @@ fn addCMakeLibraryList(exe: *std.Build.Step.Compile, list: []const u8) void { |
| 752 | 747 | } else if (exe.target.isWindows() and mem.endsWith(u8, lib, ".lib") and !fs.path.isAbsolute(lib)) { |
| 753 | 748 | exe.linkSystemLibrary(lib[0 .. lib.len - ".lib".len]); |
| 754 | 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 | 188 | usageAndErr(builder, false, stderr_stream); |
| 189 | 189 | }; |
| 190 | 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 | 192 | std.debug.print("Expected argument after {s}\n\n", .{arg}); |
| 193 | 193 | usageAndErr(builder, false, stderr_stream); |
| 194 | }; | |
| 194 | } }; | |
| 195 | 195 | } else if (mem.eql(u8, arg, "--debug-log")) { |
| 196 | 196 | const next_arg = nextArg(args, &arg_idx) orelse { |
| 197 | 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 | 57 | pub const TranslateCStep = @import("Build/Step/TranslateC.zig"); |
| 58 | 58 | /// deprecated: use `Step.WriteFile`. |
| 59 | 59 | pub const WriteFileStep = @import("Build/Step/WriteFile.zig"); |
| 60 | /// deprecated: use `LazyPath`. | |
| 61 | pub const FileSource = LazyPath; | |
| 60 | 62 | |
| 61 | 63 | install_tls: TopLevelStep, |
| 62 | 64 | uninstall_tls: TopLevelStep, |
| ... | ... | @@ -93,8 +95,7 @@ build_root: Cache.Directory, |
| 93 | 95 | cache_root: Cache.Directory, |
| 94 | 96 | global_cache_root: Cache.Directory, |
| 95 | 97 | cache: *Cache, |
| 96 | /// If non-null, overrides the default zig lib dir. | |
| 97 | zig_lib_dir: ?[]const u8, | |
| 98 | zig_lib_dir: ?LazyPath, | |
| 98 | 99 | vcpkg_root: VcpkgRoot = .unattempted, |
| 99 | 100 | pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null, |
| 100 | 101 | args: ?[][]const u8 = null, |
| ... | ... | @@ -471,7 +472,7 @@ pub fn addOptions(self: *Build) *Step.Options { |
| 471 | 472 | |
| 472 | 473 | pub const ExecutableOptions = struct { |
| 473 | 474 | name: []const u8, |
| 474 | root_source_file: ?FileSource = null, | |
| 475 | root_source_file: ?LazyPath = null, | |
| 475 | 476 | version: ?std.SemanticVersion = null, |
| 476 | 477 | target: CrossTarget = .{}, |
| 477 | 478 | optimize: std.builtin.Mode = .Debug, |
| ... | ... | @@ -481,6 +482,8 @@ pub const ExecutableOptions = struct { |
| 481 | 482 | single_threaded: ?bool = null, |
| 482 | 483 | use_llvm: ?bool = null, |
| 483 | 484 | use_lld: ?bool = null, |
| 485 | zig_lib_dir: ?LazyPath = null, | |
| 486 | main_pkg_path: ?LazyPath = null, | |
| 484 | 487 | }; |
| 485 | 488 | |
| 486 | 489 | pub fn addExecutable(b: *Build, options: ExecutableOptions) *Step.Compile { |
| ... | ... | @@ -497,12 +500,14 @@ pub fn addExecutable(b: *Build, options: ExecutableOptions) *Step.Compile { |
| 497 | 500 | .single_threaded = options.single_threaded, |
| 498 | 501 | .use_llvm = options.use_llvm, |
| 499 | 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 | 508 | pub const ObjectOptions = struct { |
| 504 | 509 | name: []const u8, |
| 505 | root_source_file: ?FileSource = null, | |
| 510 | root_source_file: ?LazyPath = null, | |
| 506 | 511 | target: CrossTarget, |
| 507 | 512 | optimize: std.builtin.Mode, |
| 508 | 513 | max_rss: usize = 0, |
| ... | ... | @@ -510,6 +515,8 @@ pub const ObjectOptions = struct { |
| 510 | 515 | single_threaded: ?bool = null, |
| 511 | 516 | use_llvm: ?bool = null, |
| 512 | 517 | use_lld: ?bool = null, |
| 518 | zig_lib_dir: ?LazyPath = null, | |
| 519 | main_pkg_path: ?LazyPath = null, | |
| 513 | 520 | }; |
| 514 | 521 | |
| 515 | 522 | pub fn addObject(b: *Build, options: ObjectOptions) *Step.Compile { |
| ... | ... | @@ -524,12 +531,14 @@ pub fn addObject(b: *Build, options: ObjectOptions) *Step.Compile { |
| 524 | 531 | .single_threaded = options.single_threaded, |
| 525 | 532 | .use_llvm = options.use_llvm, |
| 526 | 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 | 539 | pub const SharedLibraryOptions = struct { |
| 531 | 540 | name: []const u8, |
| 532 | root_source_file: ?FileSource = null, | |
| 541 | root_source_file: ?LazyPath = null, | |
| 533 | 542 | version: ?std.SemanticVersion = null, |
| 534 | 543 | target: CrossTarget, |
| 535 | 544 | optimize: std.builtin.Mode, |
| ... | ... | @@ -538,6 +547,8 @@ pub const SharedLibraryOptions = struct { |
| 538 | 547 | single_threaded: ?bool = null, |
| 539 | 548 | use_llvm: ?bool = null, |
| 540 | 549 | use_lld: ?bool = null, |
| 550 | zig_lib_dir: ?LazyPath = null, | |
| 551 | main_pkg_path: ?LazyPath = null, | |
| 541 | 552 | }; |
| 542 | 553 | |
| 543 | 554 | pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *Step.Compile { |
| ... | ... | @@ -554,12 +565,14 @@ pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *Step.Compile |
| 554 | 565 | .single_threaded = options.single_threaded, |
| 555 | 566 | .use_llvm = options.use_llvm, |
| 556 | 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 | 573 | pub const StaticLibraryOptions = struct { |
| 561 | 574 | name: []const u8, |
| 562 | root_source_file: ?FileSource = null, | |
| 575 | root_source_file: ?LazyPath = null, | |
| 563 | 576 | target: CrossTarget, |
| 564 | 577 | optimize: std.builtin.Mode, |
| 565 | 578 | version: ?std.SemanticVersion = null, |
| ... | ... | @@ -568,6 +581,8 @@ pub const StaticLibraryOptions = struct { |
| 568 | 581 | single_threaded: ?bool = null, |
| 569 | 582 | use_llvm: ?bool = null, |
| 570 | 583 | use_lld: ?bool = null, |
| 584 | zig_lib_dir: ?LazyPath = null, | |
| 585 | main_pkg_path: ?LazyPath = null, | |
| 571 | 586 | }; |
| 572 | 587 | |
| 573 | 588 | pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *Step.Compile { |
| ... | ... | @@ -584,12 +599,14 @@ pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *Step.Compile |
| 584 | 599 | .single_threaded = options.single_threaded, |
| 585 | 600 | .use_llvm = options.use_llvm, |
| 586 | 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 | 607 | pub const TestOptions = struct { |
| 591 | 608 | name: []const u8 = "test", |
| 592 | root_source_file: FileSource, | |
| 609 | root_source_file: LazyPath, | |
| 593 | 610 | target: CrossTarget = .{}, |
| 594 | 611 | optimize: std.builtin.Mode = .Debug, |
| 595 | 612 | version: ?std.SemanticVersion = null, |
| ... | ... | @@ -600,6 +617,8 @@ pub const TestOptions = struct { |
| 600 | 617 | single_threaded: ?bool = null, |
| 601 | 618 | use_llvm: ?bool = null, |
| 602 | 619 | use_lld: ?bool = null, |
| 620 | zig_lib_dir: ?LazyPath = null, | |
| 621 | main_pkg_path: ?LazyPath = null, | |
| 603 | 622 | }; |
| 604 | 623 | |
| 605 | 624 | pub fn addTest(b: *Build, options: TestOptions) *Step.Compile { |
| ... | ... | @@ -616,15 +635,18 @@ pub fn addTest(b: *Build, options: TestOptions) *Step.Compile { |
| 616 | 635 | .single_threaded = options.single_threaded, |
| 617 | 636 | .use_llvm = options.use_llvm, |
| 618 | 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 | 643 | pub const AssemblyOptions = struct { |
| 623 | 644 | name: []const u8, |
| 624 | source_file: FileSource, | |
| 645 | source_file: LazyPath, | |
| 625 | 646 | target: CrossTarget, |
| 626 | 647 | optimize: std.builtin.Mode, |
| 627 | 648 | max_rss: usize = 0, |
| 649 | zig_lib_dir: ?LazyPath = null, | |
| 628 | 650 | }; |
| 629 | 651 | |
| 630 | 652 | pub fn addAssembly(b: *Build, options: AssemblyOptions) *Step.Compile { |
| ... | ... | @@ -635,8 +657,9 @@ pub fn addAssembly(b: *Build, options: AssemblyOptions) *Step.Compile { |
| 635 | 657 | .target = options.target, |
| 636 | 658 | .optimize = options.optimize, |
| 637 | 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 | 663 | return obj_step; |
| 641 | 664 | } |
| 642 | 665 | |
| ... | ... | @@ -655,7 +678,7 @@ pub const ModuleDependency = struct { |
| 655 | 678 | }; |
| 656 | 679 | |
| 657 | 680 | pub const CreateModuleOptions = struct { |
| 658 | source_file: FileSource, | |
| 681 | source_file: LazyPath, | |
| 659 | 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 | 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 | 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 { | |
| 1265 | return Step.InstallArtifact.create(self, artifact); | |
| 1290 | /// This merely creates the step; it does not add it to the dependencies of the | |
| 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 | 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 | 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 | 1320 | return Step.ObjCopy.create(b, source, options); |
| 1289 | 1321 | } |
| 1290 | 1322 | |
| 1291 | 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 | 1325 | return self.addInstallFileWithDir(source.dupe(self), .prefix, dest_rel_path); |
| 1294 | 1326 | } |
| 1295 | 1327 | |
| 1296 | 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 | 1330 | return self.addInstallFileWithDir(source.dupe(self), .bin, dest_rel_path); |
| 1299 | 1331 | } |
| 1300 | 1332 | |
| 1301 | 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 | 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 | 1341 | |
| 1310 | 1342 | pub fn addInstallFileWithDir( |
| 1311 | 1343 | self: *Build, |
| 1312 | source: FileSource, | |
| 1344 | source: LazyPath, | |
| 1313 | 1345 | install_dir: InstallDir, |
| 1314 | 1346 | dest_rel_path: []const u8, |
| 1315 | 1347 | ) *Step.InstallFile { |
| ... | ... | @@ -1322,12 +1354,13 @@ pub fn addInstallDirectory(self: *Build, options: InstallDirectoryOptions) *Step |
| 1322 | 1354 | |
| 1323 | 1355 | pub fn addCheckFile( |
| 1324 | 1356 | b: *Build, |
| 1325 | file_source: FileSource, | |
| 1357 | file_source: LazyPath, | |
| 1326 | 1358 | options: Step.CheckFile.Options, |
| 1327 | 1359 | ) *Step.CheckFile { |
| 1328 | 1360 | return Step.CheckFile.create(b, file_source, options); |
| 1329 | 1361 | } |
| 1330 | 1362 | |
| 1363 | /// deprecated: https://github.com/ziglang/zig/issues/14943 | |
| 1331 | 1364 | pub fn pushInstalledFile(self: *Build, dir: InstallDir, dest_rel_path: []const u8) void { |
| 1332 | 1365 | const file = InstalledFile{ |
| 1333 | 1366 | .dir = dir, |
| ... | ... | @@ -1357,6 +1390,11 @@ pub fn pathFromRoot(b: *Build, p: []const u8) []u8 { |
| 1357 | 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 | 1398 | pub fn pathJoin(self: *Build, paths: []const []const u8) []u8 { |
| 1361 | 1399 | return fs.path.join(self.allocator, paths) catch @panic("OOM"); |
| 1362 | 1400 | } |
| ... | ... | @@ -1608,7 +1646,7 @@ pub const Module = struct { |
| 1608 | 1646 | /// This could either be a generated file, in which case the module |
| 1609 | 1647 | /// contains exactly one file, or it could be a path to the root source |
| 1610 | 1648 | /// file of directory of files which constitute the module. |
| 1611 | source_file: FileSource, | |
| 1649 | source_file: LazyPath, | |
| 1612 | 1650 | dependencies: std.StringArrayHashMap(*Module), |
| 1613 | 1651 | }; |
| 1614 | 1652 | |
| ... | ... | @@ -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. | |
| 1634 | pub const FileSource = union(enum) { | |
| 1635 | /// A plain file path, relative to build root or absolute. | |
| 1671 | /// A reference to an existing or future path. | |
| 1672 | pub const LazyPath = union(enum) { | |
| 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 | 1676 | path: []const u8, |
| 1637 | 1677 | |
| 1638 | 1678 | /// A file that is generated by an interface. Those files usually are |
| 1639 | 1679 | /// not available until built by a build step. |
| 1640 | 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 | 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. | |
| 1644 | pub fn relative(path: []const u8) FileSource { | |
| 1691 | /// Asserts the parameter is not an absolute path. | |
| 1692 | pub fn relative(path: []const u8) LazyPath { | |
| 1645 | 1693 | std.debug.assert(!std.fs.path.isAbsolute(path)); |
| 1646 | return FileSource{ .path = path }; | |
| 1694 | return LazyPath{ .path = path }; | |
| 1647 | 1695 | } |
| 1648 | 1696 | |
| 1649 | 1697 | /// Returns a string that can be shown to represent the file source. |
| 1650 | 1698 | /// Either returns the path or `"generated"`. |
| 1651 | pub fn getDisplayName(self: FileSource) []const u8 { | |
| 1699 | pub fn getDisplayName(self: LazyPath) []const u8 { | |
| 1652 | 1700 | return switch (self) { |
| 1653 | .path => self.path, | |
| 1701 | .path, .cwd_relative => self.path, | |
| 1654 | 1702 | .generated => "generated", |
| 1655 | 1703 | }; |
| 1656 | 1704 | } |
| 1657 | 1705 | |
| 1658 | 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 | 1708 | switch (self) { |
| 1661 | .path => {}, | |
| 1709 | .path, .cwd_relative => {}, | |
| 1662 | 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. | |
| 1667 | pub fn getPath(self: FileSource, src_builder: *Build) []const u8 { | |
| 1714 | /// Returns an absolute path. | |
| 1715 | /// Intended to be used during the make phase only. | |
| 1716 | pub fn getPath(self: LazyPath, src_builder: *Build) []const u8 { | |
| 1668 | 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. | |
| 1672 | /// asking_step is only used for debugging purposes; it's the step being run that is asking for | |
| 1673 | /// the path. | |
| 1674 | pub fn getPath2(self: FileSource, src_builder: *Build, asking_step: ?*Step) []const u8 { | |
| 1720 | /// Returns an absolute path. | |
| 1721 | /// Intended to be used during the make phase only. | |
| 1722 | /// | |
| 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 | 1726 | switch (self) { |
| 1676 | 1727 | .path => |p| return src_builder.pathFromRoot(p), |
| 1728 | .cwd_relative => |p| return src_builder.pathFromCwd(p), | |
| 1677 | 1729 | .generated => |gen| return gen.path orelse { |
| 1678 | 1730 | std.debug.getStderrMutex().lock(); |
| 1679 | 1731 | const stderr = std.io.getStdErr(); |
| ... | ... | @@ -1684,16 +1736,17 @@ pub const FileSource = union(enum) { |
| 1684 | 1736 | } |
| 1685 | 1737 | |
| 1686 | 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 | 1740 | return switch (self) { |
| 1689 | 1741 | .path => |p| .{ .path = b.dupePath(p) }, |
| 1742 | .cwd_relative => |p| .{ .cwd_relative = b.dupePath(p) }, | |
| 1690 | 1743 | .generated => |gen| .{ .generated = gen }, |
| 1691 | 1744 | }; |
| 1692 | 1745 | } |
| 1693 | 1746 | }; |
| 1694 | 1747 | |
| 1695 | 1748 | /// In this function the stderr mutex has already been locked. |
| 1696 | fn dumpBadGetPathHelp( | |
| 1749 | pub fn dumpBadGetPathHelp( | |
| 1697 | 1750 | s: *Step, |
| 1698 | 1751 | stderr: fs.File, |
| 1699 | 1752 | src_builder: *Build, |
lib/std/Build/Step.zig+1-6| ... | ... | @@ -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; | |
| 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 | ); | |
| 426 | return result; | |
| 432 | 427 | } |
| 433 | 428 | |
| 434 | 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 | 11 | step: Step, |
| 12 | 12 | expected_matches: []const []const u8, |
| 13 | 13 | expected_exact: ?[]const u8, |
| 14 | source: std.Build.FileSource, | |
| 14 | source: std.Build.LazyPath, | |
| 15 | 15 | max_bytes: usize = 20 * 1024 * 1024, |
| 16 | 16 | |
| 17 | 17 | pub const base_id = .check_file; |
| ... | ... | @@ -23,7 +23,7 @@ pub const Options = struct { |
| 23 | 23 | |
| 24 | 24 | pub fn create( |
| 25 | 25 | owner: *std.Build, |
| 26 | source: std.Build.FileSource, | |
| 26 | source: std.Build.LazyPath, | |
| 27 | 27 | options: Options, |
| 28 | 28 | ) *CheckFile { |
| 29 | 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 | 15 | pub const base_id = .check_object; |
| 16 | 16 | |
| 17 | 17 | step: Step, |
| 18 | source: std.Build.FileSource, | |
| 18 | source: std.Build.LazyPath, | |
| 19 | 19 | max_bytes: usize = 20 * 1024 * 1024, |
| 20 | 20 | checks: std.ArrayList(Check), |
| 21 | 21 | obj_format: std.Target.ObjectFormat, |
| 22 | 22 | |
| 23 | 23 | pub fn create( |
| 24 | 24 | owner: *std.Build, |
| 25 | source: std.Build.FileSource, | |
| 25 | source: std.Build.LazyPath, | |
| 26 | 26 | obj_format: std.Target.ObjectFormat, |
| 27 | 27 | ) *CheckObject { |
| 28 | 28 | const gpa = owner.allocator; |
| ... | ... | @@ -44,7 +44,7 @@ pub fn create( |
| 44 | 44 | |
| 45 | 45 | const SearchPhrase = struct { |
| 46 | 46 | string: []const u8, |
| 47 | file_source: ?std.Build.FileSource = null, | |
| 47 | file_source: ?std.Build.LazyPath = null, | |
| 48 | 48 | |
| 49 | 49 | fn resolve(phrase: SearchPhrase, b: *std.Build, step: *Step) []const u8 { |
| 50 | 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 | 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 | 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 | 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 | 312 | assert(self.checks.items.len > 0); |
| 313 | 313 | const last = &self.checks.items[self.checks.items.len - 1]; |
| 314 | 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 | 321 | |
| 322 | 322 | /// Like `checkContains()` but takes an additional argument `FileSource` which will be |
| 323 | 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 | 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 | 11 | const Step = std.Build.Step; |
| 12 | 12 | const CrossTarget = std.zig.CrossTarget; |
| 13 | 13 | const NativeTargetInfo = std.zig.system.NativeTargetInfo; |
| 14 | const FileSource = std.Build.FileSource; | |
| 14 | const LazyPath = std.Build.LazyPath; | |
| 15 | 15 | const PkgConfigPkg = std.Build.PkgConfigPkg; |
| 16 | 16 | const PkgConfigError = std.Build.PkgConfigError; |
| 17 | 17 | const ExecError = std.Build.ExecError; |
| ... | ... | @@ -28,7 +28,7 @@ name: []const u8, |
| 28 | 28 | target: CrossTarget, |
| 29 | 29 | target_info: NativeTargetInfo, |
| 30 | 30 | optimize: std.builtin.Mode, |
| 31 | linker_script: ?FileSource = null, | |
| 31 | linker_script: ?LazyPath = null, | |
| 32 | 32 | version_script: ?[]const u8 = null, |
| 33 | 33 | out_filename: []const u8, |
| 34 | 34 | linkage: ?Linkage = null, |
| ... | ... | @@ -40,20 +40,12 @@ strip: ?bool, |
| 40 | 40 | unwind_tables: ?bool, |
| 41 | 41 | // keep in sync with src/link.zig:CompressDebugSections |
| 42 | 42 | compress_debug_sections: enum { none, zlib } = .none, |
| 43 | lib_paths: ArrayList(FileSource), | |
| 44 | rpaths: ArrayList(FileSource), | |
| 45 | framework_dirs: ArrayList(FileSource), | |
| 43 | lib_paths: ArrayList(LazyPath), | |
| 44 | rpaths: ArrayList(LazyPath), | |
| 45 | framework_dirs: ArrayList(LazyPath), | |
| 46 | 46 | frameworks: StringHashMap(FrameworkLinkInfo), |
| 47 | 47 | verbose_link: bool, |
| 48 | 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 | 49 | bundle_compiler_rt: ?bool = null, |
| 58 | 50 | single_threaded: ?bool, |
| 59 | 51 | stack_protector: ?bool = null, |
| ... | ... | @@ -74,8 +66,10 @@ max_memory: ?u64 = null, |
| 74 | 66 | shared_memory: bool = false, |
| 75 | 67 | global_base: ?u64 = null, |
| 76 | 68 | c_std: std.Build.CStd, |
| 77 | zig_lib_dir: ?[]const u8, | |
| 78 | main_pkg_path: ?[]const u8, | |
| 69 | /// Set via options; intended to be read-only after that. | |
| 70 | zig_lib_dir: ?LazyPath, | |
| 71 | /// Set via options; intended to be read-only after that. | |
| 72 | main_pkg_path: ?LazyPath, | |
| 79 | 73 | exec_cmd_args: ?[]const ?[]const u8, |
| 80 | 74 | filter: ?[]const u8, |
| 81 | 75 | test_evented_io: bool = false, |
| ... | ... | @@ -85,10 +79,8 @@ wasi_exec_model: ?std.builtin.WasiExecModel = null, |
| 85 | 79 | /// Symbols to be exported when compiling to wasm |
| 86 | 80 | export_symbol_names: []const []const u8 = &.{}, |
| 87 | 81 | |
| 88 | root_src: ?FileSource, | |
| 89 | out_h_filename: []const u8, | |
| 82 | root_src: ?LazyPath, | |
| 90 | 83 | out_lib_filename: []const u8, |
| 91 | out_pdb_filename: []const u8, | |
| 92 | 84 | modules: std.StringArrayHashMap(*Module), |
| 93 | 85 | |
| 94 | 86 | link_objects: ArrayList(LinkObject), |
| ... | ... | @@ -99,14 +91,12 @@ is_linking_libc: bool, |
| 99 | 91 | is_linking_libcpp: bool, |
| 100 | 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 | 94 | installed_path: ?[]const u8, |
| 105 | 95 | |
| 106 | 96 | /// Base address for an executable image. |
| 107 | 97 | image_base: ?u64 = null, |
| 108 | 98 | |
| 109 | libc_file: ?FileSource = null, | |
| 99 | libc_file: ?LazyPath = null, | |
| 110 | 100 | |
| 111 | 101 | valgrind_support: ?bool = null, |
| 112 | 102 | each_lib_rpath: ?bool = null, |
| ... | ... | @@ -210,35 +200,40 @@ use_lld: ?bool, |
| 210 | 200 | /// otherwise. |
| 211 | 201 | expect_errors: []const []const u8 = &.{}, |
| 212 | 202 | |
| 213 | output_path_source: GeneratedFile, | |
| 214 | output_lib_path_source: GeneratedFile, | |
| 215 | output_h_path_source: GeneratedFile, | |
| 216 | output_pdb_path_source: GeneratedFile, | |
| 217 | output_dirname_source: GeneratedFile, | |
| 203 | emit_directory: ?*GeneratedFile, | |
| 204 | ||
| 218 | 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 | 214 | pub const CSourceFiles = struct { |
| 215 | /// Relative to the build root. | |
| 221 | 216 | files: []const []const u8, |
| 222 | 217 | flags: []const []const u8, |
| 223 | 218 | }; |
| 224 | 219 | |
| 225 | 220 | pub const CSourceFile = struct { |
| 226 | source: FileSource, | |
| 227 | args: []const []const u8, | |
| 221 | file: LazyPath, | |
| 222 | flags: []const []const u8, | |
| 228 | 223 | |
| 229 | 224 | pub fn dupe(self: CSourceFile, b: *std.Build) CSourceFile { |
| 230 | 225 | return .{ |
| 231 | .source = self.source.dupe(b), | |
| 232 | .args = b.dupeStrings(self.args), | |
| 226 | .file = self.file.dupe(b), | |
| 227 | .flags = b.dupeStrings(self.flags), | |
| 233 | 228 | }; |
| 234 | 229 | } |
| 235 | 230 | }; |
| 236 | 231 | |
| 237 | 232 | pub const LinkObject = union(enum) { |
| 238 | static_path: FileSource, | |
| 233 | static_path: LazyPath, | |
| 239 | 234 | other_step: *Compile, |
| 240 | 235 | system_lib: SystemLib, |
| 241 | assembly_file: FileSource, | |
| 236 | assembly_file: LazyPath, | |
| 242 | 237 | c_source_file: *CSourceFile, |
| 243 | 238 | c_source_files: *CSourceFiles, |
| 244 | 239 | }; |
| ... | ... | @@ -265,15 +260,15 @@ const FrameworkLinkInfo = struct { |
| 265 | 260 | }; |
| 266 | 261 | |
| 267 | 262 | pub const IncludeDir = union(enum) { |
| 268 | raw_path: []const u8, | |
| 269 | raw_path_system: []const u8, | |
| 263 | path: LazyPath, | |
| 264 | path_system: LazyPath, | |
| 270 | 265 | other_step: *Compile, |
| 271 | 266 | config_header_step: *Step.ConfigHeader, |
| 272 | 267 | }; |
| 273 | 268 | |
| 274 | 269 | pub const Options = struct { |
| 275 | 270 | name: []const u8, |
| 276 | root_source_file: ?FileSource = null, | |
| 271 | root_source_file: ?LazyPath = null, | |
| 277 | 272 | target: CrossTarget, |
| 278 | 273 | optimize: std.builtin.Mode, |
| 279 | 274 | kind: Kind, |
| ... | ... | @@ -286,6 +281,8 @@ pub const Options = struct { |
| 286 | 281 | single_threaded: ?bool = null, |
| 287 | 282 | use_llvm: ?bool = null, |
| 288 | 283 | use_lld: ?bool = null, |
| 284 | zig_lib_dir: ?LazyPath = null, | |
| 285 | main_pkg_path: ?LazyPath = null, | |
| 289 | 286 | }; |
| 290 | 287 | |
| 291 | 288 | pub const BuildId = union(enum) { |
| ... | ... | @@ -373,25 +370,9 @@ pub const Kind = enum { |
| 373 | 370 | |
| 374 | 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 | 373 | pub fn create(owner: *std.Build, options: Options) *Compile { |
| 393 | 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 | 376 | if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) { |
| 396 | 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 | 434 | }), |
| 454 | 435 | .version = options.version, |
| 455 | 436 | .out_filename = out_filename, |
| 456 | .out_h_filename = owner.fmt("{s}.h", .{name}), | |
| 457 | 437 | .out_lib_filename = undefined, |
| 458 | .out_pdb_filename = owner.fmt("{s}.pdb", .{name}), | |
| 459 | 438 | .major_only_filename = null, |
| 460 | 439 | .name_only_filename = null, |
| 461 | 440 | .modules = std.StringArrayHashMap(*Module).init(owner.allocator), |
| 462 | 441 | .include_dirs = ArrayList(IncludeDir).init(owner.allocator), |
| 463 | 442 | .link_objects = ArrayList(LinkObject).init(owner.allocator), |
| 464 | 443 | .c_macros = ArrayList([]const u8).init(owner.allocator), |
| 465 | .lib_paths = ArrayList(FileSource).init(owner.allocator), | |
| 466 | .rpaths = ArrayList(FileSource).init(owner.allocator), | |
| 467 | .framework_dirs = ArrayList(FileSource).init(owner.allocator), | |
| 444 | .lib_paths = ArrayList(LazyPath).init(owner.allocator), | |
| 445 | .rpaths = ArrayList(LazyPath).init(owner.allocator), | |
| 446 | .framework_dirs = ArrayList(LazyPath).init(owner.allocator), | |
| 468 | 447 | .installed_headers = ArrayList(*Step).init(owner.allocator), |
| 469 | 448 | .c_std = std.Build.CStd.C99, |
| 470 | 449 | .zig_lib_dir = null, |
| ... | ... | @@ -476,16 +455,18 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 476 | 455 | .disable_sanitize_c = false, |
| 477 | 456 | .sanitize_thread = false, |
| 478 | 457 | .rdynamic = false, |
| 479 | .override_dest_dir = null, | |
| 480 | 458 | .installed_path = null, |
| 481 | 459 | .force_undefined_symbols = StringHashMap(void).init(owner.allocator), |
| 482 | 460 | |
| 483 | .output_path_source = GeneratedFile{ .step = &self.step }, | |
| 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 }, | |
| 461 | .emit_directory = null, | |
| 488 | 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 | 471 | .target_info = target_info, |
| 491 | 472 | |
| ... | ... | @@ -496,6 +477,16 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 496 | 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 | 490 | if (self.kind == .lib) { |
| 500 | 491 | if (self.linkage != null and self.linkage.? == .static) { |
| 501 | 492 | self.out_lib_filename = self.out_filename; |
| ... | ... | @@ -614,7 +605,7 @@ pub fn addObjCopy(cs: *Compile, options: Step.ObjCopy.Options) *Step.ObjCopy { |
| 614 | 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 | 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 | 617 | pub const install = @compileError("deprecated; use std.Build.installArtifact"); |
| 627 | 618 | |
| 628 | 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 | 627 | const b = self.step.owner; |
| 634 | 628 | self.linker_script = source.dupe(b); |
| 635 | 629 | source.addStepDependencies(&self.step); |
| ... | ... | @@ -690,12 +684,18 @@ pub fn isStaticLibrary(self: *Compile) bool { |
| 690 | 684 | } |
| 691 | 685 | |
| 692 | 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 | 689 | if (!self.target.isWindows() and !self.target.isUefi()) return false; |
| 694 | 690 | if (self.target.getObjectFormat() == .c) return false; |
| 695 | 691 | if (self.strip == true or (self.strip == null and self.optimize == .ReleaseSmall)) return false; |
| 696 | 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 | 699 | pub fn linkLibC(self: *Compile) void { |
| 700 | 700 | self.is_linking_libc = true; |
| 701 | 701 | } |
| ... | ... | @@ -935,19 +935,12 @@ pub fn addCSourceFiles(self: *Compile, files: []const []const u8, flags: []const |
| 935 | 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 { | |
| 939 | self.addCSourceFileSource(.{ | |
| 940 | .args = flags, | |
| 941 | .source = .{ .path = file }, | |
| 942 | }); | |
| 943 | } | |
| 944 | ||
| 945 | pub fn addCSourceFileSource(self: *Compile, source: CSourceFile) void { | |
| 938 | pub fn addCSourceFile(self: *Compile, source: CSourceFile) void { | |
| 946 | 939 | const b = self.step.owner; |
| 947 | 940 | const c_source_file = b.allocator.create(CSourceFile) catch @panic("OOM"); |
| 948 | 941 | c_source_file.* = source.dupe(b); |
| 949 | 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 | 946 | pub fn setVerboseLink(self: *Compile, value: bool) void { |
| ... | ... | @@ -958,80 +951,99 @@ pub fn setVerboseCC(self: *Compile, value: bool) void { |
| 958 | 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 | 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 { | |
| 967 | const b = self.step.owner; | |
| 968 | self.main_pkg_path = b.dupePath(dir_path); | |
| 959 | fn getEmittedFileGeneric(self: *Compile, output_file: *?*GeneratedFile) LazyPath { | |
| 960 | if (output_file.*) |g| { | |
| 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 { | |
| 972 | const b = self.step.owner; | |
| 973 | self.libc_file = if (libc_file) |f| f.dupe(b) else null; | |
| 970 | /// deprecated: use `getEmittedBinDirectory` | |
| 971 | pub const getOutputDirectorySource = getEmittedBinDirectory; | |
| 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 | 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 { | |
| 979 | return .{ .generated = &self.output_path_source }; | |
| 984 | pub fn getEmittedBin(self: *Compile) LazyPath { | |
| 985 | return self.getEmittedFileGeneric(&self.generated_bin); | |
| 980 | 986 | } |
| 981 | 987 | |
| 982 | pub fn getOutputDirectorySource(self: *Compile) FileSource { | |
| 983 | return .{ .generated = &self.output_dirname_source }; | |
| 984 | } | |
| 988 | /// deprecated: use `getEmittedImplib` | |
| 989 | pub const getOutputLibSource = getEmittedImplib; | |
| 985 | 990 | |
| 986 | /// Returns the generated import library. This function can only be called for libraries. | |
| 987 | pub fn getOutputLibSource(self: *Compile) FileSource { | |
| 991 | /// Returns the path to the generated import library. | |
| 992 | /// This function can only be called for libraries. | |
| 993 | pub fn getEmittedImplib(self: *Compile) LazyPath { | |
| 988 | 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. | |
| 993 | /// This function can only be called for libraries or object files which have `emit_h` set. | |
| 994 | pub fn getOutputHSource(self: *Compile) FileSource { | |
| 998 | /// deprecated: use `getEmittedH` | |
| 999 | pub const getOutputHSource = getEmittedH; | |
| 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 | 1004 | assert(self.kind != .exe and self.kind != .@"test"); |
| 996 | assert(self.emit_h); | |
| 997 | return .{ .generated = &self.output_h_path_source }; | |
| 1005 | return self.getEmittedFileGeneric(&self.generated_h); | |
| 998 | 1006 | } |
| 999 | 1007 | |
| 1000 | /// Returns the generated PDB file. This function can only be called for Windows and UEFI. | |
| 1001 | pub fn getOutputPdbSource(self: *Compile) FileSource { | |
| 1002 | // TODO: Is this right? Isn't PDB for *any* PE/COFF file? | |
| 1003 | assert(self.target.isWindows() or self.target.isUefi()); | |
| 1004 | return .{ .generated = &self.output_pdb_path_source }; | |
| 1008 | /// deprecated: use `getEmittedPdb`. | |
| 1009 | pub const getOutputPdbSource = getEmittedPdb; | |
| 1010 | ||
| 1011 | /// Returns the generated PDB file. | |
| 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 { | |
| 1008 | if (self.generated_docs) |g| return .{ .generated = g }; | |
| 1009 | const arena = self.step.owner.allocator; | |
| 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 }; | |
| 1019 | /// Returns the path to the generated documentation directory. | |
| 1020 | pub fn getEmittedDocs(self: *Compile) LazyPath { | |
| 1021 | return self.getEmittedFileGeneric(&self.generated_docs); | |
| 1014 | 1022 | } |
| 1015 | 1023 | |
| 1016 | pub fn addAssemblyFile(self: *Compile, path: []const u8) void { | |
| 1017 | const b = self.step.owner; | |
| 1018 | self.link_objects.append(.{ | |
| 1019 | .assembly_file = .{ .path = b.dupe(path) }, | |
| 1020 | }) catch @panic("OOM"); | |
| 1024 | /// Returns the path to the generated assembly code. | |
| 1025 | pub fn getEmittedAsm(self: *Compile) LazyPath { | |
| 1026 | return self.getEmittedFileGeneric(&self.generated_asm); | |
| 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 | 1040 | const b = self.step.owner; |
| 1025 | 1041 | const source_duped = source.dupe(b); |
| 1026 | 1042 | self.link_objects.append(.{ .assembly_file = source_duped }) catch @panic("OOM"); |
| 1027 | 1043 | source_duped.addStepDependencies(&self.step); |
| 1028 | 1044 | } |
| 1029 | 1045 | |
| 1030 | pub fn addObjectFile(self: *Compile, source_file: []const u8) void { | |
| 1031 | self.addObjectFileSource(.{ .path = source_file }); | |
| 1032 | } | |
| 1033 | ||
| 1034 | pub fn addObjectFileSource(self: *Compile, source: FileSource) void { | |
| 1046 | pub fn addObjectFile(self: *Compile, source: LazyPath) void { | |
| 1035 | 1047 | const b = self.step.owner; |
| 1036 | 1048 | self.link_objects.append(.{ .static_path = source.dupe(b) }) catch @panic("OOM"); |
| 1037 | 1049 | source.addStepDependencies(&self.step); |
| ... | ... | @@ -1042,14 +1054,16 @@ pub fn addObject(self: *Compile, obj: *Compile) void { |
| 1042 | 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 | 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 | 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 | 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 | 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 { | |
| 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 { | |
| 1074 | pub fn addLibraryPath(self: *Compile, directory_source: LazyPath) void { | |
| 1066 | 1075 | self.lib_paths.append(directory_source) catch @panic("OOM"); |
| 1067 | 1076 | directory_source.addStepDependencies(&self.step); |
| 1068 | 1077 | } |
| 1069 | 1078 | |
| 1070 | pub fn addRPath(self: *Compile, path: []const u8) 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 { | |
| 1079 | pub fn addRPath(self: *Compile, directory_source: LazyPath) void { | |
| 1076 | 1080 | self.rpaths.append(directory_source) catch @panic("OOM"); |
| 1077 | 1081 | directory_source.addStepDependencies(&self.step); |
| 1078 | 1082 | } |
| 1079 | 1083 | |
| 1080 | pub fn addFrameworkPath(self: *Compile, dir_path: []const u8) 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 { | |
| 1084 | pub fn addFrameworkPath(self: *Compile, directory_source: LazyPath) void { | |
| 1086 | 1085 | self.framework_dirs.append(directory_source) catch @panic("OOM"); |
| 1087 | 1086 | directory_source.addStepDependencies(&self.step); |
| 1088 | 1087 | } |
| ... | ... | @@ -1168,7 +1167,11 @@ pub fn setExecCmd(self: *Compile, args: []const ?[]const u8) void { |
| 1168 | 1167 | } |
| 1169 | 1168 | |
| 1170 | 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 | 1175 | self.link_objects.append(.{ .other_step = other }) catch @panic("OOM"); |
| 1173 | 1176 | self.include_dirs.append(.{ .other_step = other }) catch @panic("OOM"); |
| 1174 | 1177 | |
| ... | ... | @@ -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 | 1317 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1291 | 1318 | const b = step.owner; |
| 1292 | 1319 | const self = @fieldParentPtr(Compile, "step", step); |
| ... | ... | @@ -1364,7 +1391,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1364 | 1391 | .exe => @panic("Cannot link with an executable build artifact"), |
| 1365 | 1392 | .@"test" => @panic("Cannot link with a test"), |
| 1366 | 1393 | .obj => { |
| 1367 | try zig_args.append(other.getOutputSource().getPath(b)); | |
| 1394 | try zig_args.append(other.getEmittedBin().getPath(b)); | |
| 1368 | 1395 | }, |
| 1369 | 1396 | .lib => l: { |
| 1370 | 1397 | if (self.isStaticLibrary() and other.isStaticLibrary()) { |
| ... | ... | @@ -1372,7 +1399,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1372 | 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 | 1408 | try zig_args.append(full_path_lib); |
| 1377 | 1409 | |
| 1378 | 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 | 1464 | }, |
| 1433 | 1465 | |
| 1434 | 1466 | .c_source_file => |c_source_file| { |
| 1435 | if (c_source_file.args.len == 0) { | |
| 1467 | if (c_source_file.flags.len == 0) { | |
| 1436 | 1468 | if (prev_has_cflags) { |
| 1437 | 1469 | try zig_args.append("-cflags"); |
| 1438 | 1470 | try zig_args.append("--"); |
| ... | ... | @@ -1440,13 +1472,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1440 | 1472 | } |
| 1441 | 1473 | } else { |
| 1442 | 1474 | try zig_args.append("-cflags"); |
| 1443 | for (c_source_file.args) |arg| { | |
| 1475 | for (c_source_file.flags) |arg| { | |
| 1444 | 1476 | try zig_args.append(arg); |
| 1445 | 1477 | } |
| 1446 | 1478 | try zig_args.append("--"); |
| 1447 | 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 | 1484 | .c_source_files => |c_source_files| { |
| ... | ... | @@ -1515,14 +1547,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1515 | 1547 | if (b.verbose_cc or self.verbose_cc) try zig_args.append("--verbose-cc"); |
| 1516 | 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); | |
| 1519 | if (self.emit_bin.getArg(b, "emit-bin")) |arg| try zig_args.append(arg); | |
| 1550 | if (self.generated_asm != null) try zig_args.append("-femit-asm"); | |
| 1551 | if (self.generated_bin == null) try zig_args.append("-fno-emit-bin"); | |
| 1520 | 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); | |
| 1522 | if (self.emit_llvm_bc.getArg(b, "emit-llvm-bc")) |arg| try zig_args.append(arg); | |
| 1523 | if (self.emit_llvm_ir.getArg(b, "emit-llvm-ir")) |arg| try zig_args.append(arg); | |
| 1524 | ||
| 1525 | if (self.emit_h) try zig_args.append("-femit-h"); | |
| 1553 | if (self.generated_implib != null) try zig_args.append("-femit-implib"); | |
| 1554 | if (self.generated_llvm_bc != null) try zig_args.append("-femit-llvm-bc"); | |
| 1555 | if (self.generated_llvm_ir != null) try zig_args.append("-femit-llvm-ir"); | |
| 1556 | if (self.generated_h != null) try zig_args.append("-femit-h"); | |
| 1526 | 1557 | |
| 1527 | 1558 | try addFlag(&zig_args, "strip", self.strip); |
| 1528 | 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 | 1777 | |
| 1747 | 1778 | for (self.include_dirs.items) |include_dir| { |
| 1748 | 1779 | switch (include_dir) { |
| 1749 | .raw_path => |include_path| { | |
| 1780 | .path => |include_path| { | |
| 1750 | 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 | 1785 | if (b.sysroot != null) { |
| 1755 | 1786 | try zig_args.append("-iwithsysroot"); |
| 1756 | 1787 | } else { |
| 1757 | 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 | 1793 | const common_include_path = if (builtin.os.tag == .windows and b.sysroot != null and fs.path.isAbsolute(resolved_include_path)) blk: { |
| 1763 | 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 | 1805 | try zig_args.append(common_include_path); |
| 1775 | 1806 | }, |
| 1776 | 1807 | .other_step => |other| { |
| 1777 | if (other.emit_h) { | |
| 1778 | const h_path = other.getOutputHSource().getPath(b); | |
| 1808 | if (other.generated_h) |header| { | |
| 1779 | 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 | 1812 | if (other.installed_headers.items.len > 0) { |
| 1783 | 1813 | try zig_args.append("-I"); |
| ... | ... | @@ -1810,7 +1840,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1810 | 1840 | zig_args.appendAssumeCapacity("-rpath"); |
| 1811 | 1841 | |
| 1812 | 1842 | if (self.target_info.target.isDarwin()) switch (rpath) { |
| 1813 | .path => |path| { | |
| 1843 | .path, .cwd_relative => |path| { | |
| 1814 | 1844 | // On Darwin, we should not try to expand special runtime paths such as |
| 1815 | 1845 | // * @executable_path |
| 1816 | 1846 | // * @loader_path |
| ... | ... | @@ -1907,15 +1937,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1907 | 1937 | |
| 1908 | 1938 | if (self.zig_lib_dir) |dir| { |
| 1909 | 1939 | try zig_args.append("--zig-lib-dir"); |
| 1910 | try zig_args.append(b.pathFromRoot(dir)); | |
| 1911 | } else if (b.zig_lib_dir) |dir| { | |
| 1912 | try zig_args.append("--zig-lib-dir"); | |
| 1913 | try zig_args.append(dir); | |
| 1940 | try zig_args.append(dir.getPath(b)); | |
| 1914 | 1941 | } |
| 1915 | 1942 | |
| 1916 | 1943 | if (self.main_pkg_path) |dir| { |
| 1917 | 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 | 1948 | try addFlag(&zig_args, "PIC", self.force_pic); |
| ... | ... | @@ -2008,33 +2035,51 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 2008 | 2035 | if (maybe_output_bin_path) |output_bin_path| { |
| 2009 | 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( | |
| 2014 | &.{ output_dir, self.out_filename }, | |
| 2015 | ); | |
| 2042 | // -femit-bin[=path] (default) Output machine code | |
| 2043 | if (self.generated_bin) |bin| { | |
| 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) { | |
| 2018 | self.output_lib_path_source.path = b.pathJoin( | |
| 2019 | &.{ output_dir, self.out_lib_filename }, | |
| 2020 | ); | |
| 2049 | // output PDB if someone requested it | |
| 2050 | if (self.generated_pdb) |pdb| { | |
| 2051 | pdb.path = b.fmt("{s}{c}{s}.pdb", .{ output_dir, sep, self.name }); | |
| 2021 | 2052 | } |
| 2022 | 2053 | |
| 2023 | if (self.emit_h) { | |
| 2024 | self.output_h_path_source.path = b.pathJoin( | |
| 2025 | &.{ output_dir, self.out_h_filename }, | |
| 2026 | ); | |
| 2054 | // -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL | |
| 2055 | if (self.generated_implib) |implib| { | |
| 2056 | implib.path = b.fmt("{s}{c}{s}.lib", .{ output_dir, sep, self.name }); | |
| 2027 | 2057 | } |
| 2028 | 2058 | |
| 2029 | if (self.target.isWindows() or self.target.isUefi()) { | |
| 2030 | self.output_pdb_path_source.path = b.pathJoin( | |
| 2031 | &.{ output_dir, self.out_pdb_filename }, | |
| 2032 | ); | |
| 2059 | // -femit-h[=path] Generate a C header file (.h) | |
| 2060 | if (self.generated_h) |lp| { | |
| 2061 | lp.path = b.fmt("{s}{c}{s}.h", .{ output_dir, sep, self.name }); | |
| 2033 | 2062 | } |
| 2034 | 2063 | |
| 2064 | // -femit-docs[=path] Create a docs/ dir with html documentation | |
| 2035 | 2065 | if (self.generated_docs) |generated_docs| { |
| 2036 | 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 | 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 | 2087 | { |
| 2043 | 2088 | try doAtomicSymLinks( |
| 2044 | 2089 | step, |
| 2045 | self.getOutputSource().getPath(b), | |
| 2090 | self.getEmittedBin().getPath(b), | |
| 2046 | 2091 | self.major_only_filename.?, |
| 2047 | 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 | 6 | pub const Style = union(enum) { |
| 7 | 7 | /// The configure format supported by autotools. It uses `#undef foo` to |
| 8 | 8 | /// mark lines that can be substituted with different values. |
| 9 | autoconf: std.Build.FileSource, | |
| 9 | autoconf: std.Build.LazyPath, | |
| 10 | 10 | /// The configure format supported by CMake. It uses `@@FOO@@` and |
| 11 | 11 | /// `#cmakedefine` for template substitution. |
| 12 | cmake: std.Build.FileSource, | |
| 12 | cmake: std.Build.LazyPath, | |
| 13 | 13 | /// Instead of starting with an input file, start with nothing. |
| 14 | 14 | blank, |
| 15 | 15 | /// Start with nothing, like blank, and output a nasm .asm file. |
| 16 | 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 | 22 | switch (style) { |
| 20 | 23 | .autoconf, .cmake => |s| return s, |
| 21 | 24 | .blank, .nasm => return null, |
| ... | ... | @@ -54,7 +57,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { |
| 54 | 57 | |
| 55 | 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 | 61 | .path => |p| { |
| 59 | 62 | const basename = std.fs.path.basename(p); |
| 60 | 63 | if (std.mem.endsWith(u8, basename, ".h.in")) { |
| ... | ... | @@ -68,7 +71,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { |
| 68 | 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 | 75 | owner.fmt("configure {s} header {s} to {s}", .{ |
| 73 | 76 | @tagName(options.style), s.getDisplayName(), include_path, |
| 74 | 77 | }) |
| ... | ... | @@ -98,7 +101,10 @@ pub fn addValues(self: *ConfigHeader, values: anytype) void { |
| 98 | 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 | 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 | 3 | const InstallDir = std.Build.InstallDir; |
| 4 | 4 | const InstallArtifact = @This(); |
| 5 | 5 | const fs = std.fs; |
| 6 | ||
| 7 | pub const base_id = .install_artifact; | |
| 6 | const LazyPath = std.Build.LazyPath; | |
| 8 | 7 | |
| 9 | 8 | step: Step, |
| 10 | artifact: *Step.Compile, | |
| 11 | dest_dir: InstallDir, | |
| 9 | ||
| 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 | 17 | pdb_dir: ?InstallDir, |
| 18 | emitted_pdb: ?LazyPath, | |
| 19 | ||
| 13 | 20 | h_dir: ?InstallDir, |
| 14 | /// If non-null, adds additional path components relative to dest_dir, and | |
| 15 | /// overrides the basename of the Compile step. | |
| 16 | dest_sub_path: ?[]const u8, | |
| 21 | emitted_h: ?LazyPath, | |
| 22 | ||
| 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 | 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 | 66 | .step = Step.init(.{ |
| 22 | 67 | .id = base_id, |
| 23 | 68 | .name = owner.fmt("install {s}", .{artifact.name}), |
| 24 | 69 | .owner = owner, |
| 25 | 70 | .makeFn = make, |
| 26 | 71 | }), |
| 27 | .artifact = artifact, | |
| 28 | .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) { | |
| 29 | .obj => @panic("Cannot install a .obj build artifact."), | |
| 30 | .exe, .@"test" => InstallDir{ .bin = {} }, | |
| 31 | .lib => InstallDir{ .lib = {} }, | |
| 72 | .dest_dir = dest_dir, | |
| 73 | .pdb_dir = switch (options.pdb_dir) { | |
| 74 | .disabled => null, | |
| 75 | .default => if (artifact.producesPdbFile()) dest_dir else null, | |
| 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: { | |
| 34 | if (artifact.kind == .exe or artifact.kind == .@"test") { | |
| 35 | break :blk InstallDir{ .bin = {} }; | |
| 36 | } else { | |
| 37 | break :blk InstallDir{ .lib = {} }; | |
| 38 | } | |
| 88 | .implib_dir = switch (options.implib_dir) { | |
| 89 | .disabled => null, | |
| 90 | .default => if (artifact.producesImplib()) dest_dir else null, | |
| 91 | .override => |o| o, | |
| 92 | }, | |
| 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 | 100 | } else null, |
| 40 | .h_dir = if (artifact.kind == .lib and artifact.emit_h) .header else null, | |
| 41 | .dest_sub_path = null, | |
| 101 | ||
| 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 | 112 | self.step.dependOn(&artifact.step); |
| 44 | 113 | |
| 45 | owner.pushInstalledFile(self.dest_dir, artifact.out_filename); | |
| 46 | if (self.artifact.isDynamicLibrary()) { | |
| 47 | if (artifact.major_only_filename) |name| { | |
| 48 | owner.pushInstalledFile(.lib, name); | |
| 49 | } | |
| 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 | } | |
| 114 | if (self.dest_dir != null) self.emitted_bin = artifact.getEmittedBin(); | |
| 115 | if (self.pdb_dir != null) self.emitted_pdb = artifact.getEmittedPdb(); | |
| 116 | if (self.h_dir != null) self.emitted_h = artifact.getEmittedH(); | |
| 117 | if (self.implib_dir != null) self.emitted_implib = artifact.getEmittedImplib(); | |
| 118 | ||
| 63 | 119 | return self; |
| 64 | 120 | } |
| 65 | 121 | |
| 66 | 122 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 67 | 123 | _ = prog_node; |
| 68 | 124 | const self = @fieldParentPtr(InstallArtifact, "step", step); |
| 69 | const src_builder = self.artifact.step.owner; | |
| 70 | 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 | 126 | const cwd = fs.cwd(); |
| 75 | 127 | |
| 76 | 128 | var all_cached = true; |
| 77 | 129 | |
| 78 | { | |
| 79 | const full_src_path = self.artifact.getOutputSource().getPath(src_builder); | |
| 130 | if (self.dest_dir) |dest_dir| { | |
| 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 | 133 | const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_dest_path, .{}) catch |err| { |
| 81 | 134 | return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ |
| 82 | 135 | full_src_path, full_dest_path, @errorName(err), |
| 83 | 136 | }); |
| 84 | 137 | }; |
| 85 | 138 | all_cached = all_cached and p == .fresh; |
| 86 | } | |
| 87 | 139 | |
| 88 | if (self.artifact.isDynamicLibrary() and | |
| 89 | self.artifact.version != null and | |
| 90 | self.artifact.target.wantSharedLibSymLinks()) | |
| 91 | { | |
| 92 | try Step.Compile.doAtomicSymLinks(step, full_dest_path, self.artifact.major_only_filename.?, self.artifact.name_only_filename.?); | |
| 140 | if (self.dylib_symlinks) |dls| { | |
| 141 | try Step.Compile.doAtomicSymLinks(step, full_dest_path, dls.major_only_filename, dls.name_only_filename); | |
| 142 | } | |
| 143 | ||
| 144 | self.artifact.installed_path = full_dest_path; | |
| 93 | 145 | } |
| 94 | if (self.artifact.isDynamicLibrary() and | |
| 95 | self.artifact.target.isWindows() and | |
| 96 | self.artifact.emit_implib != .no_emit) | |
| 97 | { | |
| 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); | |
| 146 | ||
| 147 | if (self.implib_dir) |implib_dir| { | |
| 148 | const full_src_path = self.emitted_implib.?.getPath2(step.owner, step); | |
| 149 | const full_implib_path = dest_builder.getInstallPath(implib_dir, fs.path.basename(full_src_path)); | |
| 100 | 150 | const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_implib_path, .{}) catch |err| { |
| 101 | 151 | return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ |
| 102 | 152 | full_src_path, full_implib_path, @errorName(err), |
| ... | ... | @@ -104,9 +154,10 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 104 | 154 | }; |
| 105 | 155 | all_cached = all_cached and p == .fresh; |
| 106 | 156 | } |
| 157 | ||
| 107 | 158 | if (self.pdb_dir) |pdb_dir| { |
| 108 | const full_src_path = self.artifact.getOutputPdbSource().getPath(src_builder); | |
| 109 | const full_pdb_path = dest_builder.getInstallPath(pdb_dir, self.artifact.out_pdb_filename); | |
| 159 | const full_src_path = self.emitted_pdb.?.getPath2(step.owner, step); | |
| 160 | const full_pdb_path = dest_builder.getInstallPath(pdb_dir, fs.path.basename(full_src_path)); | |
| 110 | 161 | const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_pdb_path, .{}) catch |err| { |
| 111 | 162 | return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ |
| 112 | 163 | full_src_path, full_pdb_path, @errorName(err), |
| ... | ... | @@ -114,9 +165,10 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 114 | 165 | }; |
| 115 | 166 | all_cached = all_cached and p == .fresh; |
| 116 | 167 | } |
| 168 | ||
| 117 | 169 | if (self.h_dir) |h_dir| { |
| 118 | const full_src_path = self.artifact.getOutputHSource().getPath(src_builder); | |
| 119 | const full_h_path = dest_builder.getInstallPath(h_dir, self.artifact.out_h_filename); | |
| 170 | const full_src_path = self.emitted_h.?.getPath2(step.owner, step); | |
| 171 | const full_h_path = dest_builder.getInstallPath(h_dir, fs.path.basename(full_src_path)); | |
| 120 | 172 | const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_h_path, .{}) catch |err| { |
| 121 | 173 | return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ |
| 122 | 174 | full_src_path, full_h_path, @errorName(err), |
| ... | ... | @@ -124,6 +176,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 124 | 176 | }; |
| 125 | 177 | all_cached = all_cached and p == .fresh; |
| 126 | 178 | } |
| 127 | self.artifact.installed_path = full_dest_path; | |
| 179 | ||
| 128 | 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 | 2 | const mem = std.mem; |
| 3 | 3 | const fs = std.fs; |
| 4 | 4 | const Step = std.Build.Step; |
| 5 | const FileSource = std.Build.FileSource; | |
| 5 | const LazyPath = std.Build.LazyPath; | |
| 6 | 6 | const InstallDir = std.Build.InstallDir; |
| 7 | 7 | const InstallDirStep = @This(); |
| 8 | 8 | |
| ... | ... | @@ -15,7 +15,7 @@ dest_builder: *std.Build, |
| 15 | 15 | pub const base_id = .install_dir; |
| 16 | 16 | |
| 17 | 17 | pub const Options = struct { |
| 18 | source_dir: FileSource, | |
| 18 | source_dir: LazyPath, | |
| 19 | 19 | install_dir: InstallDir, |
| 20 | 20 | install_subdir: []const u8, |
| 21 | 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 | 1 | const std = @import("std"); |
| 2 | 2 | const Step = std.Build.Step; |
| 3 | const FileSource = std.Build.FileSource; | |
| 3 | const LazyPath = std.Build.LazyPath; | |
| 4 | 4 | const InstallDir = std.Build.InstallDir; |
| 5 | 5 | const InstallFile = @This(); |
| 6 | 6 | const assert = std.debug.assert; |
| ... | ... | @@ -8,7 +8,7 @@ const assert = std.debug.assert; |
| 8 | 8 | pub const base_id = .install_file; |
| 9 | 9 | |
| 10 | 10 | step: Step, |
| 11 | source: FileSource, | |
| 11 | source: LazyPath, | |
| 12 | 12 | dir: InstallDir, |
| 13 | 13 | dest_rel_path: []const u8, |
| 14 | 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 | 17 | |
| 18 | 18 | pub fn create( |
| 19 | 19 | owner: *std.Build, |
| 20 | source: FileSource, | |
| 20 | source: LazyPath, | |
| 21 | 21 | dir: InstallDir, |
| 22 | 22 | dest_rel_path: []const u8, |
| 23 | 23 | ) *InstallFile { |
lib/std/Build/Step/ObjCopy.zig+11-8| ... | ... | @@ -20,7 +20,7 @@ pub const RawFormat = enum { |
| 20 | 20 | }; |
| 21 | 21 | |
| 22 | 22 | step: Step, |
| 23 | file_source: std.Build.FileSource, | |
| 23 | input_file: std.Build.LazyPath, | |
| 24 | 24 | basename: []const u8, |
| 25 | 25 | output_file: std.Build.GeneratedFile, |
| 26 | 26 | |
| ... | ... | @@ -37,30 +37,33 @@ pub const Options = struct { |
| 37 | 37 | |
| 38 | 38 | pub fn create( |
| 39 | 39 | owner: *std.Build, |
| 40 | file_source: std.Build.FileSource, | |
| 40 | input_file: std.Build.LazyPath, | |
| 41 | 41 | options: Options, |
| 42 | 42 | ) *ObjCopy { |
| 43 | 43 | const self = owner.allocator.create(ObjCopy) catch @panic("OOM"); |
| 44 | 44 | self.* = ObjCopy{ |
| 45 | 45 | .step = Step.init(.{ |
| 46 | 46 | .id = base_id, |
| 47 | .name = owner.fmt("objcopy {s}", .{file_source.getDisplayName()}), | |
| 47 | .name = owner.fmt("objcopy {s}", .{input_file.getDisplayName()}), | |
| 48 | 48 | .owner = owner, |
| 49 | 49 | .makeFn = make, |
| 50 | 50 | }), |
| 51 | .file_source = file_source, | |
| 52 | .basename = options.basename orelse file_source.getDisplayName(), | |
| 51 | .input_file = input_file, | |
| 52 | .basename = options.basename orelse input_file.getDisplayName(), | |
| 53 | 53 | .output_file = std.Build.GeneratedFile{ .step = &self.step }, |
| 54 | 54 | |
| 55 | 55 | .format = options.format, |
| 56 | 56 | .only_section = options.only_section, |
| 57 | 57 | .pad_to = options.pad_to, |
| 58 | 58 | }; |
| 59 | file_source.addStepDependencies(&self.step); | |
| 59 | input_file.addStepDependencies(&self.step); | |
| 60 | 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 | 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 | 78 | // bytes when ObjCopy implementation is modified incompatibly. |
| 76 | 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 | 82 | _ = try man.addFile(full_src_path, null); |
| 80 | 83 | man.hash.addOptionalBytes(self.only_section); |
| 81 | 84 | man.hash.addOptional(self.pad_to); |
lib/std/Build/Step/Options.zig+24-35| ... | ... | @@ -3,7 +3,7 @@ const builtin = @import("builtin"); |
| 3 | 3 | const fs = std.fs; |
| 4 | 4 | const Step = std.Build.Step; |
| 5 | 5 | const GeneratedFile = std.Build.GeneratedFile; |
| 6 | const FileSource = std.Build.FileSource; | |
| 6 | const LazyPath = std.Build.LazyPath; | |
| 7 | 7 | |
| 8 | 8 | const Options = @This(); |
| 9 | 9 | |
| ... | ... | @@ -13,8 +13,7 @@ step: Step, |
| 13 | 13 | generated_file: GeneratedFile, |
| 14 | 14 | |
| 15 | 15 | contents: std.ArrayList(u8), |
| 16 | artifact_args: std.ArrayList(OptionArtifactArg), | |
| 17 | file_source_args: std.ArrayList(OptionFileSourceArg), | |
| 16 | args: std.ArrayList(Arg), | |
| 18 | 17 | |
| 19 | 18 | pub fn create(owner: *std.Build) *Options { |
| 20 | 19 | const self = owner.allocator.create(Options) catch @panic("OOM"); |
| ... | ... | @@ -27,8 +26,7 @@ pub fn create(owner: *std.Build) *Options { |
| 27 | 26 | }), |
| 28 | 27 | .generated_file = undefined, |
| 29 | 28 | .contents = std.ArrayList(u8).init(owner.allocator), |
| 30 | .artifact_args = std.ArrayList(OptionArtifactArg).init(owner.allocator), | |
| 31 | .file_source_args = std.ArrayList(OptionFileSourceArg).init(owner.allocator), | |
| 29 | .args = std.ArrayList(Arg).init(owner.allocator), | |
| 32 | 30 | }; |
| 33 | 31 | self.generated_file = .{ .step = &self.step }; |
| 34 | 32 | |
| ... | ... | @@ -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 | 172 | /// The value is the path in the cache dir. |
| 172 | 173 | /// Adds a dependency automatically. |
| 173 | pub fn addOptionFileSource( | |
| 174 | pub fn addOptionPath( | |
| 174 | 175 | self: *Options, |
| 175 | 176 | name: []const u8, |
| 176 | source: FileSource, | |
| 177 | path: LazyPath, | |
| 177 | 178 | ) void { |
| 178 | self.file_source_args.append(.{ | |
| 179 | .name = name, | |
| 180 | .source = source.dupe(self.step.owner), | |
| 179 | self.args.append(.{ | |
| 180 | .name = self.step.owner.dupe(name), | |
| 181 | .path = path.dupe(self.step.owner), | |
| 181 | 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 | /// Adds a dependency automatically. | |
| 186 | /// Deprecated: use `addOptionPath(options, name, artifact.getEmittedBin())` instead. | |
| 187 | 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"); | |
| 189 | self.step.dependOn(&artifact.step); | |
| 188 | return addOptionPath(self, name, artifact.getEmittedBin()); | |
| 190 | 189 | } |
| 191 | 190 | |
| 192 | 191 | pub fn createModule(self: *Options) *std.Build.Module { |
| 193 | 192 | return self.step.owner.createModule(.{ |
| 194 | .source_file = self.getSource(), | |
| 193 | .source_file = self.getOutput(), | |
| 195 | 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 | 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 | 209 | const b = step.owner; |
| 208 | 210 | const self = @fieldParentPtr(Options, "step", step); |
| 209 | 211 | |
| 210 | for (self.artifact_args.items) |item| { | |
| 212 | for (self.args.items) |item| { | |
| 211 | 213 | self.addOption( |
| 212 | 214 | []const u8, |
| 213 | 215 | item.name, |
| 214 | b.pathFromRoot(item.artifact.getOutputSource().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), | |
| 216 | item.path.getPath(b), | |
| 223 | 217 | ); |
| 224 | 218 | } |
| 225 | 219 | |
| ... | ... | @@ -229,7 +223,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 229 | 223 | var hash = b.cache.hash; |
| 230 | 224 | // Random bytes to make unique. Refresh this with new random bytes when |
| 231 | 225 | // implementation is modified in a non-backwards-compatible way. |
| 232 | hash.add(@as(u32, 0x38845ef8)); | |
| 226 | hash.add(@as(u32, 0xad95e922)); | |
| 233 | 227 | hash.addBytes(self.contents.items); |
| 234 | 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 | 288 | } |
| 295 | 289 | } |
| 296 | 290 | |
| 297 | const OptionArtifactArg = struct { | |
| 298 | name: []const u8, | |
| 299 | artifact: *Step.Compile, | |
| 300 | }; | |
| 301 | ||
| 302 | const OptionFileSourceArg = struct { | |
| 291 | const Arg = struct { | |
| 303 | 292 | name: []const u8, |
| 304 | source: FileSource, | |
| 293 | path: LazyPath, | |
| 305 | 294 | }; |
| 306 | 295 | |
| 307 | 296 | test Options { |
lib/std/Build/Step/Run.zig+46-34| ... | ... | @@ -82,7 +82,7 @@ has_side_effects: bool = false, |
| 82 | 82 | pub const StdIn = union(enum) { |
| 83 | 83 | none, |
| 84 | 84 | bytes: []const u8, |
| 85 | file_source: std.Build.FileSource, | |
| 85 | lazy_path: std.Build.LazyPath, | |
| 86 | 86 | }; |
| 87 | 87 | |
| 88 | 88 | pub const StdIo = union(enum) { |
| ... | ... | @@ -120,15 +120,15 @@ pub const StdIo = union(enum) { |
| 120 | 120 | |
| 121 | 121 | pub const Arg = union(enum) { |
| 122 | 122 | artifact: *Step.Compile, |
| 123 | file_source: PrefixedFileSource, | |
| 124 | directory_source: PrefixedFileSource, | |
| 123 | lazy_path: PrefixedLazyPath, | |
| 124 | directory_source: PrefixedLazyPath, | |
| 125 | 125 | bytes: []u8, |
| 126 | 126 | output: *Output, |
| 127 | 127 | }; |
| 128 | 128 | |
| 129 | pub const PrefixedFileSource = struct { | |
| 129 | pub const PrefixedLazyPath = struct { | |
| 130 | 130 | prefix: []const u8, |
| 131 | file_source: std.Build.FileSource, | |
| 131 | lazy_path: std.Build.LazyPath, | |
| 132 | 132 | }; |
| 133 | 133 | |
| 134 | 134 | pub const Output = struct { |
| ... | ... | @@ -164,14 +164,15 @@ pub fn enableTestRunnerMode(self: *Run) void { |
| 164 | 164 | } |
| 165 | 165 | |
| 166 | 166 | pub fn addArtifactArg(self: *Run, artifact: *Step.Compile) void { |
| 167 | const bin_file = artifact.getEmittedBin(); | |
| 168 | bin_file.addStepDependencies(&self.step); | |
| 167 | 169 | self.argv.append(Arg{ .artifact = artifact }) catch @panic("OOM"); |
| 168 | self.step.dependOn(&artifact.step); | |
| 169 | 170 | } |
| 170 | 171 | |
| 171 | 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 | 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 | 176 | return self.addPrefixedOutputFileArg("", basename); |
| 176 | 177 | } |
| 177 | 178 | |
| ... | ... | @@ -179,7 +180,7 @@ pub fn addPrefixedOutputFileArg( |
| 179 | 180 | self: *Run, |
| 180 | 181 | prefix: []const u8, |
| 181 | 182 | basename: []const u8, |
| 182 | ) std.Build.FileSource { | |
| 183 | ) std.Build.LazyPath { | |
| 183 | 184 | const b = self.step.owner; |
| 184 | 185 | |
| 185 | 186 | const output = b.allocator.create(Output) catch @panic("OOM"); |
| ... | ... | @@ -197,31 +198,43 @@ pub fn addPrefixedOutputFileArg( |
| 197 | 198 | return .{ .generated = &output.generated_file }; |
| 198 | 199 | } |
| 199 | 200 | |
| 200 | pub fn addFileSourceArg(self: *Run, file_source: std.Build.FileSource) void { | |
| 201 | self.addPrefixedFileSourceArg("", file_source); | |
| 201 | /// deprecated: use `addFileArg` | |
| 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 | 212 | const b = self.step.owner; |
| 206 | 213 | |
| 207 | const prefixed_file_source: PrefixedFileSource = .{ | |
| 214 | const prefixed_file_source: PrefixedLazyPath = .{ | |
| 208 | 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"); | |
| 212 | file_source.addStepDependencies(&self.step); | |
| 218 | self.argv.append(.{ .lazy_path = prefixed_file_source }) catch @panic("OOM"); | |
| 219 | lp.addStepDependencies(&self.step); | |
| 213 | 220 | } |
| 214 | 221 | |
| 215 | pub fn addDirectorySourceArg(self: *Run, directory_source: std.Build.FileSource) void { | |
| 216 | self.addPrefixedDirectorySourceArg("", directory_source); | |
| 222 | /// deprecated: use `addDirectoryArg` | |
| 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 | 233 | const b = self.step.owner; |
| 221 | 234 | |
| 222 | const prefixed_directory_source: PrefixedFileSource = .{ | |
| 235 | const prefixed_directory_source: PrefixedLazyPath = .{ | |
| 223 | 236 | .prefix = b.dupe(prefix), |
| 224 | .file_source = directory_source.dupe(b), | |
| 237 | .lazy_path = directory_source.dupe(b), | |
| 225 | 238 | }; |
| 226 | 239 | self.argv.append(.{ .directory_source = prefixed_directory_source }) catch @panic("OOM"); |
| 227 | 240 | directory_source.addStepDependencies(&self.step); |
| ... | ... | @@ -239,7 +252,7 @@ pub fn addArgs(self: *Run, args: []const []const u8) void { |
| 239 | 252 | |
| 240 | 253 | pub fn setStdIn(self: *Run, stdin: StdIn) void { |
| 241 | 254 | switch (stdin) { |
| 242 | .file_source => |file_source| file_source.addStepDependencies(&self.step), | |
| 255 | .lazy_path => |lazy_path| lazy_path.addStepDependencies(&self.step), | |
| 243 | 256 | .bytes, .none => {}, |
| 244 | 257 | } |
| 245 | 258 | self.stdin = stdin; |
| ... | ... | @@ -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 | 348 | assert(self.stdio != .inherit); |
| 336 | 349 | |
| 337 | 350 | if (self.captured_stderr) |output| return .{ .generated = &output.generated_file }; |
| ... | ... | @@ -346,7 +359,7 @@ pub fn captureStdErr(self: *Run) std.Build.FileSource { |
| 346 | 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 | 363 | assert(self.stdio != .inherit); |
| 351 | 364 | |
| 352 | 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 | 444 | try argv_list.append(bytes); |
| 432 | 445 | man.hash.addBytes(bytes); |
| 433 | 446 | }, |
| 434 | .file_source => |file| { | |
| 435 | const file_path = file.file_source.getPath(b); | |
| 447 | .lazy_path => |file| { | |
| 448 | const file_path = file.lazy_path.getPath(b); | |
| 436 | 449 | try argv_list.append(b.fmt("{s}{s}", .{ file.prefix, file_path })); |
| 437 | 450 | man.hash.addBytes(file.prefix); |
| 438 | 451 | _ = try man.addFile(file_path, null); |
| 439 | 452 | }, |
| 440 | 453 | .directory_source => |file| { |
| 441 | const file_path = file.file_source.getPath(b); | |
| 454 | const file_path = file.lazy_path.getPath(b); | |
| 442 | 455 | try argv_list.append(b.fmt("{s}{s}", .{ file.prefix, file_path })); |
| 443 | 456 | man.hash.addBytes(file.prefix); |
| 444 | 457 | man.hash.addBytes(file_path); |
| ... | ... | @@ -448,8 +461,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 448 | 461 | // On Windows we don't have rpaths so we have to add .dll search paths to PATH |
| 449 | 462 | self.addPathForDynLibs(artifact); |
| 450 | 463 | } |
| 451 | const file_path = artifact.installed_path orelse | |
| 452 | artifact.getOutputSource().getPath(b); | |
| 464 | const file_path = artifact.installed_path orelse artifact.generated_bin.?.path.?; // the path is guaranteed to be set | |
| 453 | 465 | |
| 454 | 466 | try argv_list.append(file_path); |
| 455 | 467 | |
| ... | ... | @@ -474,8 +486,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 474 | 486 | .bytes => |bytes| { |
| 475 | 487 | man.hash.addBytes(bytes); |
| 476 | 488 | }, |
| 477 | .file_source => |file_source| { | |
| 478 | const file_path = file_source.getPath(b); | |
| 489 | .lazy_path => |lazy_path| { | |
| 490 | const file_path = lazy_path.getPath(b); | |
| 479 | 491 | _ = try man.addFile(file_path, null); |
| 480 | 492 | }, |
| 481 | 493 | .none => {}, |
| ... | ... | @@ -1174,8 +1186,8 @@ fn evalGeneric(self: *Run, child: *std.process.Child) !StdIoResult { |
| 1174 | 1186 | child.stdin.?.close(); |
| 1175 | 1187 | child.stdin = null; |
| 1176 | 1188 | }, |
| 1177 | .file_source => |file_source| { | |
| 1178 | const path = file_source.getPath(self.step.owner); | |
| 1189 | .lazy_path => |lazy_path| { | |
| 1190 | const path = lazy_path.getPath(self.step.owner); | |
| 1179 | 1191 | const file = self.step.owner.build_root.handle.openFile(path, .{}) catch |err| { |
| 1180 | 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 | 1253 | switch (link_object) { |
| 1242 | 1254 | .other_step => |other| { |
| 1243 | 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 | 1257 | addPathForDynLibs(self, other); |
| 1246 | 1258 | } |
| 1247 | 1259 | }, |
lib/std/Build/Step/TranslateC.zig+10-6| ... | ... | @@ -9,7 +9,7 @@ const TranslateC = @This(); |
| 9 | 9 | pub const base_id = .translate_c; |
| 10 | 10 | |
| 11 | 11 | step: Step, |
| 12 | source: std.Build.FileSource, | |
| 12 | source: std.Build.LazyPath, | |
| 13 | 13 | include_dirs: std.ArrayList([]const u8), |
| 14 | 14 | c_macros: std.ArrayList([]const u8), |
| 15 | 15 | out_basename: []const u8, |
| ... | ... | @@ -18,7 +18,7 @@ optimize: std.builtin.OptimizeMode, |
| 18 | 18 | output_file: std.Build.GeneratedFile, |
| 19 | 19 | |
| 20 | 20 | pub const Options = struct { |
| 21 | source_file: std.Build.FileSource, | |
| 21 | source_file: std.Build.LazyPath, | |
| 22 | 22 | target: CrossTarget, |
| 23 | 23 | optimize: std.builtin.OptimizeMode, |
| 24 | 24 | }; |
| ... | ... | @@ -53,10 +53,14 @@ pub const AddExecutableOptions = struct { |
| 53 | 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 | 60 | /// Creates a step to build an executable from the translated source. |
| 57 | 61 | pub fn addExecutable(self: *TranslateC, options: AddExecutableOptions) *Step.Compile { |
| 58 | 62 | return self.step.owner.addExecutable(.{ |
| 59 | .root_source_file = .{ .generated = &self.output_file }, | |
| 63 | .root_source_file = self.getOutput(), | |
| 60 | 64 | .name = options.name orelse "translated_c", |
| 61 | 65 | .version = options.version, |
| 62 | 66 | .target = options.target orelse self.target, |
| ... | ... | @@ -70,7 +74,7 @@ pub fn addExecutable(self: *TranslateC, options: AddExecutableOptions) *Step.Com |
| 70 | 74 | /// `createModule` can be used instead to create a private module. |
| 71 | 75 | pub fn addModule(self: *TranslateC, name: []const u8) *std.Build.Module { |
| 72 | 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 | 87 | |
| 84 | 88 | module.* = .{ |
| 85 | 89 | .builder = b, |
| 86 | .source_file = .{ .generated = &self.output_file }, | |
| 90 | .source_file = self.getOutput(), | |
| 87 | 91 | .dependencies = std.StringArrayHashMap(*std.Build.Module).init(b.allocator), |
| 88 | 92 | }; |
| 89 | 93 | return module; |
| ... | ... | @@ -96,7 +100,7 @@ pub fn addIncludeDir(self: *TranslateC, include_dir: []const u8) void { |
| 96 | 100 | pub fn addCheckFile(self: *TranslateC, expected_matches: []const []const u8) *Step.CheckFile { |
| 97 | 101 | return Step.CheckFile.create( |
| 98 | 102 | self.step.owner, |
| 99 | .{ .generated = &self.output_file }, | |
| 103 | self.getOutput(), | |
| 100 | 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 | 28 | sub_path: []const u8, |
| 29 | 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 | 35 | return .{ .generated = &self.generated_file }; |
| 33 | 36 | } |
| 34 | 37 | }; |
| ... | ... | @@ -40,7 +43,7 @@ pub const OutputSourceFile = struct { |
| 40 | 43 | |
| 41 | 44 | pub const Contents = union(enum) { |
| 42 | 45 | bytes: []const u8, |
| 43 | copy: std.Build.FileSource, | |
| 46 | copy: std.Build.LazyPath, | |
| 44 | 47 | }; |
| 45 | 48 | |
| 46 | 49 | pub fn create(owner: *std.Build) *WriteFile { |
| ... | ... | @@ -59,7 +62,7 @@ pub fn create(owner: *std.Build) *WriteFile { |
| 59 | 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 | 66 | const b = wf.step.owner; |
| 64 | 67 | const gpa = b.allocator; |
| 65 | 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 | 73 | }; |
| 71 | 74 | wf.files.append(gpa, file) catch @panic("OOM"); |
| 72 | 75 | wf.maybeUpdateName(); |
| 73 | return file.getFileSource(); | |
| 76 | return file.getPath(); | |
| 74 | 77 | } |
| 75 | 78 | |
| 76 | 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 | 83 | /// include sub-directories, in which case this step will ensure the |
| 81 | 84 | /// required sub-path exists. |
| 82 | 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 | 87 | const b = wf.step.owner; |
| 85 | 88 | const gpa = b.allocator; |
| 86 | 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 | 96 | |
| 94 | 97 | wf.maybeUpdateName(); |
| 95 | 98 | source.addStepDependencies(&wf.step); |
| 96 | return file.getFileSource(); | |
| 99 | return file.getLazyPath(); | |
| 97 | 100 | } |
| 98 | 101 | |
| 99 | 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 | 104 | /// used as part of the normal build process, but as a utility occasionally |
| 102 | 105 | /// run by a developer with intent to modify source files and then commit |
| 103 | 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 | 108 | const b = wf.step.owner; |
| 106 | 109 | wf.output_source_files.append(b.allocator, .{ |
| 107 | 110 | .contents = .{ .copy = source }, |
| ... | ... | @@ -123,11 +126,13 @@ pub fn addBytesToSource(wf: *WriteFile, bytes: []const u8, sub_path: []const u8) |
| 123 | 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 | 134 | /// files from this `WriteFile`. |
| 130 | pub fn getDirectorySource(wf: *WriteFile) std.Build.FileSource { | |
| 135 | pub fn getDirectory(wf: *WriteFile) std.Build.LazyPath { | |
| 131 | 136 | return .{ .generated = &wf.generated_directory }; |
| 132 | 137 | } |
| 133 | 138 |
src/link.zig+4-2| ... | ... | @@ -966,6 +966,8 @@ pub const File = struct { |
| 966 | 966 | } |
| 967 | 967 | |
| 968 | 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 | 971 | const tracy = trace(@src()); |
| 970 | 972 | defer tracy.end(); |
| 971 | 973 | |
| ... | ... | @@ -973,8 +975,8 @@ pub const File = struct { |
| 973 | 975 | defer arena_allocator.deinit(); |
| 974 | 976 | const arena = arena_allocator.allocator(); |
| 975 | 977 | |
| 976 | const directory = base.options.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}); | |
| 978 | const directory = emit.directory; // Just an alias to make it shorter to type. | |
| 979 | const full_out_path = try directory.join(arena, &[_][]const u8{emit.sub_path}); | |
| 978 | 980 | const full_out_path_z = try arena.dupeZ(u8, full_out_path); |
| 979 | 981 | |
| 980 | 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 | 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 | 1457 | const gpa = self.base.allocator; |
| 1456 | 1458 | |
| 1457 | 1459 | const decl = mod.declPtr(decl_index); |
src/link/Elf.zig+2| ... | ... | @@ -2865,6 +2865,8 @@ pub fn updateDeclExports( |
| 2865 | 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 | 2870 | const tracy = trace(@src()); |
| 2869 | 2871 | defer tracy.end(); |
| 2870 | 2872 |
src/link/MachO.zig+2| ... | ... | @@ -2386,6 +2386,8 @@ pub fn updateDeclExports( |
| 2386 | 2386 | return llvm_object.updateDeclExports(mod, decl_index, exports); |
| 2387 | 2387 | } |
| 2388 | 2388 | |
| 2389 | if (self.base.options.emit == null) return; | |
| 2390 | ||
| 2389 | 2391 | const tracy = trace(@src()); |
| 2390 | 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 | 106 | if (build_options.skip_non_native) { |
| 107 | 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 | 111 | const tracy = trace(@src()); |
| 110 | 112 | defer tracy.end(); |
| 111 | 113 | |
| 112 | const outfile = comp.bin_file.options.emit.?; | |
| 113 | 114 | // We modify 'comp' before passing it to LLVM, but restore value afterwards. |
| 114 | 115 | // We tell LLVM to not try to build a .o, only an "assembly" file. |
| 115 | 116 | // This is required by the LLVM PTX backend. |
src/link/Wasm.zig+2| ... | ... | @@ -1712,6 +1712,8 @@ pub fn updateDeclExports( |
| 1712 | 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 | 1717 | const decl = mod.declPtr(decl_index); |
| 1716 | 1718 | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); |
| 1717 | 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 | 4 | const test_step = b.step("test", "Test"); |
| 5 | 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 | 8 | const exe = b.addExecutable(.{ |
| 9 | 9 | .name = t, |
| 10 | 10 | .root_source_file = .{ .path = "main.c" }, |
| ... | ... | @@ -13,6 +13,8 @@ pub fn build(b: *std.Build) void { |
| 13 | 13 | ) catch unreachable, |
| 14 | 14 | }); |
| 15 | 15 | exe.linkLibC(); |
| 16 | // TODO: actually test the output | |
| 17 | _ = exe.getEmittedBin(); | |
| 16 | 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 | .optimize = optimize, |
| 17 | 17 | .target = .{}, |
| 18 | 18 | }); |
| 19 | lib_a.addCSourceFile("a.c", &[_][]const u8{}); | |
| 20 | lib_a.addIncludePath("."); | |
| 19 | lib_a.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &[_][]const u8{} }); | |
| 20 | lib_a.addIncludePath(.{ .path = "." }); | |
| 21 | 21 | |
| 22 | 22 | const lib_b = b.addStaticLibrary(.{ |
| 23 | 23 | .name = "b", |
| 24 | 24 | .optimize = optimize, |
| 25 | 25 | .target = .{}, |
| 26 | 26 | }); |
| 27 | lib_b.addCSourceFile("b.c", &[_][]const u8{}); | |
| 28 | lib_b.addIncludePath("."); | |
| 27 | lib_b.addCSourceFile(.{ .file = .{ .path = "b.c" }, .flags = &[_][]const u8{} }); | |
| 28 | lib_b.addIncludePath(.{ .path = "." }); | |
| 29 | 29 | |
| 30 | 30 | const test_exe = b.addTest(.{ |
| 31 | 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 | 33 | }); |
| 34 | 34 | test_exe.linkLibrary(lib_a); |
| 35 | 35 | test_exe.linkLibrary(lib_b); |
| 36 | test_exe.addIncludePath("."); | |
| 36 | test_exe.addIncludePath(.{ .path = "." }); | |
| 37 | 37 | |
| 38 | 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 | 23 | .name = "test", |
| 24 | 24 | .optimize = optimize, |
| 25 | 25 | }); |
| 26 | exe.addSystemIncludePath(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/include" }) catch unreachable); | |
| 27 | exe.addIncludePath(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/include/c++/v1" }) catch unreachable); | |
| 28 | exe.addCSourceFile("test.cpp", &.{ | |
| 26 | exe.addSystemIncludePath(.{ .path = b.pathJoin(&.{ sdk.path, "/usr/include" }) }); | |
| 27 | exe.addIncludePath(.{ .path = b.pathJoin(&.{ sdk.path, "/usr/include/c++/v1" }) }); | |
| 28 | exe.addCSourceFile(.{ .file = .{ .path = "test.cpp" }, .flags = &.{ | |
| 29 | 29 | "-nostdlib++", |
| 30 | 30 | "-nostdinc++", |
| 31 | }); | |
| 32 | exe.addObjectFile(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/lib/libc++.tbd" }) catch unreachable); | |
| 31 | } }); | |
| 32 | exe.addObjectFile(.{ .path = b.pathJoin(&.{ sdk.path, "/usr/lib/libc++.tbd" }) }); | |
| 33 | 33 | |
| 34 | 34 | const run_cmd = b.addRunArtifact(exe); |
| 35 | 35 | run_cmd.expectStdErrEqual("x: 5\n"); |
test/link/macho/dead_strip/build.zig+1-1| ... | ... | @@ -52,7 +52,7 @@ fn createScenario( |
| 52 | 52 | .optimize = optimize, |
| 53 | 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 | 56 | exe.linkLibC(); |
| 57 | 57 | return exe; |
| 58 | 58 | } |
test/link/macho/dead_strip_dylibs/build.zig+1-1| ... | ... | @@ -53,7 +53,7 @@ fn createScenario( |
| 53 | 53 | .name = name, |
| 54 | 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 | 57 | exe.linkLibC(); |
| 58 | 58 | exe.linkFramework("Cocoa"); |
| 59 | 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 | 21 | .optimize = optimize, |
| 22 | 22 | .target = target, |
| 23 | 23 | }); |
| 24 | dylib.addCSourceFile("a.c", &.{}); | |
| 24 | dylib.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); | |
| 25 | 25 | dylib.linkLibC(); |
| 26 | 26 | |
| 27 | 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 | 39 | .optimize = optimize, |
| 40 | 40 | .target = target, |
| 41 | 41 | }); |
| 42 | exe.addCSourceFile("main.c", &.{}); | |
| 42 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); | |
| 43 | 43 | exe.linkSystemLibrary("a"); |
| 44 | exe.addLibraryPathDirectorySource(dylib.getOutputDirectorySource()); | |
| 45 | exe.addRPathDirectorySource(dylib.getOutputDirectorySource()); | |
| 44 | exe.addLibraryPath(dylib.getEmittedBinDirectory()); | |
| 45 | exe.addRPath(dylib.getEmittedBinDirectory()); | |
| 46 | 46 | exe.linkLibC(); |
| 47 | 47 | |
| 48 | 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 | 55 | |
| 56 | 56 | check_exe.checkStart(); |
| 57 | 57 | check_exe.checkExact("cmd RPATH"); |
| 58 | check_exe.checkExactFileSource("path", dylib.getOutputDirectorySource()); | |
| 58 | check_exe.checkExactPath("path", dylib.getOutputDirectorySource()); | |
| 59 | 59 | test_step.dependOn(&check_exe.step); |
| 60 | 60 | |
| 61 | 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 | 20 | .optimize = optimize, |
| 21 | 21 | .target = target, |
| 22 | 22 | }); |
| 23 | exe.addCSourceFile("main.c", &[0][]const u8{}); | |
| 24 | exe.addCSourceFile("empty.c", &[0][]const u8{}); | |
| 23 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &[0][]const u8{} }); | |
| 24 | exe.addCSourceFile(.{ .file = .{ .path = "empty.c" }, .flags = &[0][]const u8{} }); | |
| 25 | 25 | exe.linkLibC(); |
| 26 | 26 | |
| 27 | 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 | 18 | .optimize = optimize, |
| 19 | 19 | .target = .{ .os_tag = .macos }, |
| 20 | 20 | }); |
| 21 | exe.addCSourceFile("main.c", &.{}); | |
| 21 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); | |
| 22 | 22 | exe.linkLibC(); |
| 23 | 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 | 18 | .optimize = optimize, |
| 19 | 19 | .target = .{ .os_tag = .macos }, |
| 20 | 20 | }); |
| 21 | lib.addCSourceFile("main.c", &.{}); | |
| 21 | lib.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); | |
| 22 | 22 | lib.linkLibC(); |
| 23 | 23 | |
| 24 | 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 | 18 | .optimize = optimize, |
| 19 | 19 | .target = .{ .os_tag = .macos }, |
| 20 | 20 | }); |
| 21 | lib.addCSourceFile("bootstrap.c", &.{}); | |
| 21 | lib.addCSourceFile(.{ .file = .{ .path = "bootstrap.c" }, .flags = &.{} }); | |
| 22 | 22 | lib.linkLibC(); |
| 23 | 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 | 27 | .optimize = optimize, |
| 28 | 28 | .target = .{ .os_tag = .macos }, |
| 29 | 29 | }); |
| 30 | exe.addCSourceFile("main.c", &.{}); | |
| 30 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); | |
| 31 | 31 | exe.linkLibrary(lib); |
| 32 | 32 | exe.linkLibC(); |
| 33 | 33 | exe.entry_symbol_name = "_bootstrap"; |
test/link/macho/headerpad/build.zig+1-1| ... | ... | @@ -113,7 +113,7 @@ fn simpleExe( |
| 113 | 113 | .name = name, |
| 114 | 114 | .optimize = optimize, |
| 115 | 115 | }); |
| 116 | exe.addCSourceFile("main.c", &.{}); | |
| 116 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); | |
| 117 | 117 | exe.linkLibC(); |
| 118 | 118 | exe.linkFramework("CoreFoundation"); |
| 119 | 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 | 20 | .name = "test", |
| 21 | 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 | 24 | exe.linkLibC(); |
| 25 | 25 | exe.linkFrameworkNeeded("Cocoa"); |
| 26 | 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 | 21 | .optimize = optimize, |
| 22 | 22 | .target = target, |
| 23 | 23 | }); |
| 24 | dylib.addCSourceFile("a.c", &.{}); | |
| 24 | dylib.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); | |
| 25 | 25 | dylib.linkLibC(); |
| 26 | 26 | |
| 27 | 27 | // -dead_strip_dylibs |
| ... | ... | @@ -31,11 +31,11 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 31 | 31 | .optimize = optimize, |
| 32 | 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 | 35 | exe.linkLibC(); |
| 36 | 36 | exe.linkSystemLibraryNeeded("a"); |
| 37 | exe.addLibraryPathDirectorySource(dylib.getOutputDirectorySource()); | |
| 38 | exe.addRPathDirectorySource(dylib.getOutputDirectorySource()); | |
| 37 | exe.addLibraryPath(dylib.getEmittedBinDirectory()); | |
| 38 | exe.addRPath(dylib.getEmittedBinDirectory()); | |
| 39 | 39 | exe.dead_strip_dylibs = true; |
| 40 | 40 | |
| 41 | 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 | 18 | .name = "test", |
| 19 | 19 | .optimize = optimize, |
| 20 | 20 | }); |
| 21 | exe.addIncludePath("."); | |
| 22 | exe.addCSourceFile("Foo.m", &[0][]const u8{}); | |
| 23 | exe.addCSourceFile("test.m", &[0][]const u8{}); | |
| 21 | exe.addIncludePath(.{ .path = "." }); | |
| 22 | exe.addCSourceFile(.{ .file = .{ .path = "Foo.m" }, .flags = &[0][]const u8{} }); | |
| 23 | exe.addCSourceFile(.{ .file = .{ .path = "test.m" }, .flags = &[0][]const u8{} }); | |
| 24 | 24 | exe.linkLibC(); |
| 25 | 25 | // TODO when we figure out how to ship framework stubs for cross-compilation, |
| 26 | 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 | 19 | .optimize = optimize, |
| 20 | 20 | }); |
| 21 | 21 | b.default_step.dependOn(&exe.step); |
| 22 | exe.addIncludePath("."); | |
| 23 | exe.addCSourceFile("Foo.mm", &[0][]const u8{}); | |
| 24 | exe.addCSourceFile("test.mm", &[0][]const u8{}); | |
| 22 | exe.addIncludePath(.{ .path = "." }); | |
| 23 | exe.addCSourceFile(.{ .file = .{ .path = "Foo.mm" }, .flags = &[0][]const u8{} }); | |
| 24 | exe.addCSourceFile(.{ .file = .{ .path = "test.mm" }, .flags = &[0][]const u8{} }); | |
| 25 | 25 | exe.linkLibCpp(); |
| 26 | 26 | // TODO when we figure out how to ship framework stubs for cross-compilation, |
| 27 | 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 | 15 | .optimize = optimize, |
| 16 | 16 | .target = target, |
| 17 | 17 | }); |
| 18 | exe.addCSourceFile("main.c", &.{}); | |
| 18 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); | |
| 19 | 19 | exe.linkLibC(); |
| 20 | 20 | exe.pagezero_size = 0x4000; |
| 21 | 21 | |
| ... | ... | @@ -39,7 +39,7 @@ pub fn build(b: *std.Build) void { |
| 39 | 39 | .optimize = optimize, |
| 40 | 40 | .target = target, |
| 41 | 41 | }); |
| 42 | exe.addCSourceFile("main.c", &.{}); | |
| 42 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); | |
| 43 | 43 | exe.linkLibC(); |
| 44 | 44 | exe.pagezero_size = 0; |
| 45 | 45 |
test/link/macho/search_strategy/build.zig+6-12| ... | ... | @@ -55,11 +55,8 @@ fn createScenario( |
| 55 | 55 | .optimize = optimize, |
| 56 | 56 | .target = target, |
| 57 | 57 | }); |
| 58 | static.addCSourceFile("a.c", &.{}); | |
| 58 | static.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); | |
| 59 | 59 | static.linkLibC(); |
| 60 | static.override_dest_dir = std.Build.InstallDir{ | |
| 61 | .custom = "static", | |
| 62 | }; | |
| 63 | 60 | |
| 64 | 61 | const dylib = b.addSharedLibrary(.{ |
| 65 | 62 | .name = name, |
| ... | ... | @@ -67,22 +64,19 @@ fn createScenario( |
| 67 | 64 | .optimize = optimize, |
| 68 | 65 | .target = target, |
| 69 | 66 | }); |
| 70 | dylib.addCSourceFile("a.c", &.{}); | |
| 67 | dylib.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); | |
| 71 | 68 | dylib.linkLibC(); |
| 72 | dylib.override_dest_dir = std.Build.InstallDir{ | |
| 73 | .custom = "dynamic", | |
| 74 | }; | |
| 75 | 69 | |
| 76 | 70 | const exe = b.addExecutable(.{ |
| 77 | 71 | .name = name, |
| 78 | 72 | .optimize = optimize, |
| 79 | 73 | .target = target, |
| 80 | 74 | }); |
| 81 | exe.addCSourceFile("main.c", &.{}); | |
| 75 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); | |
| 82 | 76 | exe.linkSystemLibraryName(name); |
| 83 | 77 | exe.linkLibC(); |
| 84 | exe.addLibraryPathDirectorySource(static.getOutputDirectorySource()); | |
| 85 | exe.addLibraryPathDirectorySource(dylib.getOutputDirectorySource()); | |
| 86 | exe.addRPathDirectorySource(dylib.getOutputDirectorySource()); | |
| 78 | exe.addLibraryPath(static.getEmittedBinDirectory()); | |
| 79 | exe.addLibraryPath(dylib.getEmittedBinDirectory()); | |
| 80 | exe.addRPath(dylib.getEmittedBinDirectory()); | |
| 87 | 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 | 20 | .optimize = optimize, |
| 21 | 21 | .target = target, |
| 22 | 22 | }); |
| 23 | exe.addCSourceFile("main.c", &.{}); | |
| 23 | exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} }); | |
| 24 | 24 | exe.linkLibC(); |
| 25 | 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 | 23 | .optimize = optimize, |
| 24 | 24 | .target = target, |
| 25 | 25 | }); |
| 26 | lib.addCSourceFile("a.c", &.{}); | |
| 26 | lib.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); | |
| 27 | 27 | lib.linkLibC(); |
| 28 | 28 | |
| 29 | 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 | 43 | .optimize = optimize, |
| 44 | 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 | 47 | exe.linkSystemLibrary("a"); |
| 48 | exe.addLibraryPathDirectorySource(tbd_file.getDirectorySource()); | |
| 49 | exe.addRPathDirectorySource(lib.getOutputDirectorySource()); | |
| 48 | exe.addLibraryPath(tbd_file.getDirectory()); | |
| 49 | exe.addRPath(lib.getEmittedBinDirectory()); | |
| 50 | 50 | exe.linkLibC(); |
| 51 | 51 | |
| 52 | 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 | 21 | .optimize = optimize, |
| 22 | 22 | .target = target, |
| 23 | 23 | }); |
| 24 | lib.addCSourceFile("a.c", &.{}); | |
| 24 | lib.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); | |
| 25 | 25 | lib.linkLibC(); |
| 26 | 26 | |
| 27 | 27 | const test_exe = b.addTest(.{ |
test/link/macho/unwind_info/build.zig+1-1| ... | ... | @@ -75,7 +75,7 @@ fn createScenario( |
| 75 | 75 | .target = target, |
| 76 | 76 | }); |
| 77 | 77 | b.default_step.dependOn(&exe.step); |
| 78 | exe.addIncludePath("."); | |
| 78 | exe.addIncludePath(.{ .path = "." }); | |
| 79 | 79 | exe.addCSourceFiles(&[_][]const u8{ |
| 80 | 80 | "main.cpp", |
| 81 | 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 | 18 | .name = "test", |
| 19 | 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 | 22 | exe.linkLibC(); |
| 23 | 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 | 21 | .target = target, |
| 22 | 22 | .optimize = optimize, |
| 23 | 23 | }); |
| 24 | dylib.addCSourceFile("a.c", &.{}); | |
| 24 | dylib.addCSourceFile(.{ .file = .{ .path = "a.c" }, .flags = &.{} }); | |
| 25 | 25 | dylib.linkLibC(); |
| 26 | 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 | 30 | .target = target, |
| 31 | 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 | 34 | exe.linkLibC(); |
| 35 | 35 | exe.linkSystemLibraryWeak("a"); |
| 36 | exe.addLibraryPathDirectorySource(dylib.getOutputDirectorySource()); | |
| 37 | exe.addRPathDirectorySource(dylib.getOutputDirectorySource()); | |
| 36 | exe.addLibraryPath(dylib.getEmittedBinDirectory()); | |
| 37 | exe.addRPath(dylib.getEmittedBinDirectory()); | |
| 38 | 38 | |
| 39 | 39 | const check = exe.checkObject(); |
| 40 | 40 | check.checkStart(); |
test/link/static_libs_from_object_files/build.zig+6-6| ... | ... | @@ -2,7 +2,7 @@ const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | const Build = std.Build; |
| 5 | const FileSource = Build.FileSource; | |
| 5 | const LazyPath = Build.LazyPath; | |
| 6 | 6 | const Step = Build.Step; |
| 7 | 7 | const Run = Step.Run; |
| 8 | 8 | const WriteFile = Step.WriteFile; |
| ... | ... | @@ -14,7 +14,7 @@ pub fn build(b: *Build) void { |
| 14 | 14 | b.default_step = test_step; |
| 15 | 15 | |
| 16 | 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 | 18 | defer b.allocator.free(files); |
| 19 | 19 | { |
| 20 | 20 | for (files[0 .. nb_files - 1], 1..nb_files) |*file, i| { |
| ... | ... | @@ -47,7 +47,7 @@ pub fn build(b: *Build) void { |
| 47 | 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 | 51 | const flags = [_][]const u8{ |
| 52 | 52 | "-Wall", |
| 53 | 53 | "-std=c11", |
| ... | ... | @@ -63,7 +63,7 @@ fn add(b: *Build, test_step: *Step, files: []const std.Build.FileSource, optimiz |
| 63 | 63 | }); |
| 64 | 64 | |
| 65 | 65 | for (files) |file| { |
| 66 | exe.addCSourceFileSource(.{ .source = file, .args = &flags }); | |
| 66 | exe.addCSourceFile(.{ .file = file, .flags = &flags }); | |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | 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 | 88 | |
| 89 | 89 | for (files, 1..) |file, i| { |
| 90 | 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 | 94 | const exe = b.addExecutable(.{ |
| ... | ... | @@ -125,7 +125,7 @@ fn add(b: *Build, test_step: *Step, files: []const std.Build.FileSource, optimiz |
| 125 | 125 | .target = .{}, |
| 126 | 126 | .optimize = optimize, |
| 127 | 127 | }); |
| 128 | obj.addCSourceFileSource(.{ .source = file, .args = &flags }); | |
| 128 | obj.addCSourceFile(.{ .file = file, .flags = &flags }); | |
| 129 | 129 | |
| 130 | 130 | const lib = if (i & 1 == 0) lib_a else lib_b; |
| 131 | 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 | 19 | .optimize = optimize, |
| 20 | 20 | .target = .{ .cpu_arch = .wasm32, .os_tag = .wasi }, |
| 21 | 21 | }); |
| 22 | exe.addCSourceFile("foo.c", &.{}); | |
| 22 | exe.addCSourceFile(.{ .file = .{ .path = "foo.c" }, .flags = &.{} }); | |
| 23 | 23 | exe.use_llvm = false; |
| 24 | 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 | 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 | 18 | // Wasm library that doesn't have any features specified. This will |
| 19 | 19 | // infer its featureset from other linked object files. |
test/src/Cases.zig+3-5| ... | ... | @@ -518,12 +518,12 @@ pub fn lowerToBuildSteps( |
| 518 | 518 | } |
| 519 | 519 | |
| 520 | 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 | 522 | defer file_sources.deinit(); |
| 523 | 523 | for (update.files.items) |file| { |
| 524 | 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 | 528 | const artifact = if (case.is_test) b.addTest(.{ |
| 529 | 529 | .root_source_file = root_source_file, |
| ... | ... | @@ -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 | 554 | if (case.link_libc) artifact.linkLibC(); |
| 557 | 555 | |
| 558 | 556 | switch (case.backend) { |
| ... | ... | @@ -577,7 +575,7 @@ pub fn lowerToBuildSteps( |
| 577 | 575 | parent_step.dependOn(&artifact.step); |
| 578 | 576 | }, |
| 579 | 577 | .CompareObjectFile => |expected_output| { |
| 580 | const check = b.addCheckFile(artifact.getOutputSource(), .{ | |
| 578 | const check = b.addCheckFile(artifact.getEmittedBin(), .{ | |
| 581 | 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 | 99 | .target = .{}, |
| 100 | 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 | 104 | const run = b.addRunArtifact(exe); |
| 105 | 105 | run.setName(annotated_case_name); |
| ... | ... | @@ -119,7 +119,7 @@ pub fn addCase(self: *CompareOutput, case: TestCase) void { |
| 119 | 119 | |
| 120 | 120 | const exe = b.addExecutable(.{ |
| 121 | 121 | .name = "test", |
| 122 | .root_source_file = write_src.files.items[0].getFileSource(), | |
| 122 | .root_source_file = write_src.files.items[0].getPath(), | |
| 123 | 123 | .optimize = optimize, |
| 124 | 124 | .target = .{}, |
| 125 | 125 | }); |
| ... | ... | @@ -145,7 +145,7 @@ pub fn addCase(self: *CompareOutput, case: TestCase) void { |
| 145 | 145 | |
| 146 | 146 | const exe = b.addExecutable(.{ |
| 147 | 147 | .name = "test", |
| 148 | .root_source_file = write_src.files.items[0].getFileSource(), | |
| 148 | .root_source_file = write_src.files.items[0].getPath(), | |
| 149 | 149 | .target = .{}, |
| 150 | 150 | .optimize = .Debug, |
| 151 | 151 | }); |
test/src/StackTrace.zig+2-2| ... | ... | @@ -75,7 +75,7 @@ fn addExpect( |
| 75 | 75 | const write_src = b.addWriteFile("source.zig", source); |
| 76 | 76 | const exe = b.addExecutable(.{ |
| 77 | 77 | .name = "test", |
| 78 | .root_source_file = write_src.files.items[0].getFileSource(), | |
| 78 | .root_source_file = write_src.files.items[0].getPath(), | |
| 79 | 79 | .optimize = optimize_mode, |
| 80 | 80 | .target = .{}, |
| 81 | 81 | }); |
| ... | ... | @@ -88,7 +88,7 @@ fn addExpect( |
| 88 | 88 | |
| 89 | 89 | const check_run = b.addRunArtifact(self.check_exe); |
| 90 | 90 | check_run.setName(annotated_case_name); |
| 91 | check_run.addFileSourceArg(run.captureStdErr()); | |
| 91 | check_run.addFileArg(run.captureStdErr()); | |
| 92 | 92 | check_run.addArgs(&.{ |
| 93 | 93 | @tagName(optimize_mode), |
| 94 | 94 | }); |
test/src/run_translated_c.zig+1-1| ... | ... | @@ -85,7 +85,7 @@ pub const RunTranslatedCContext = struct { |
| 85 | 85 | _ = write_src.add(src_file.filename, src_file.source); |
| 86 | 86 | } |
| 87 | 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 | 89 | .target = .{}, |
| 90 | 90 | .optimize = .Debug, |
| 91 | 91 | }); |
test/src/translate_c.zig+1-1| ... | ... | @@ -108,7 +108,7 @@ pub const TranslateCContext = struct { |
| 108 | 108 | } |
| 109 | 109 | |
| 110 | 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 | 112 | .target = case.target, |
| 113 | 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 | 19 | .optimize = optimize, |
| 20 | 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 | 23 | exe_c.linkLibC(); |
| 24 | 24 | |
| 25 | 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 | 28 | .target = target, |
| 29 | 29 | }); |
| 30 | 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 | 32 | exe_cpp.linkLibCpp(); |
| 33 | 33 | |
| 34 | 34 | switch (target.getOsTag()) { |
test/standalone/coff_dwarf/build.zig+1-1| ... | ... | @@ -23,7 +23,7 @@ pub fn build(b: *std.Build) void { |
| 23 | 23 | .optimize = optimize, |
| 24 | 24 | .target = target, |
| 25 | 25 | }); |
| 26 | lib.addCSourceFile("shared_lib.c", &.{"-gdwarf"}); | |
| 26 | lib.addCSourceFile(.{ .file = .{ .path = "shared_lib.c" }, .flags = &.{"-gdwarf"} }); | |
| 27 | 27 | lib.linkLibC(); |
| 28 | 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 | 16 | .target = target, |
| 17 | 17 | }); |
| 18 | 18 | exe.linkLibC(); |
| 19 | exe.addCSourceFile("main.c", &.{}); | |
| 19 | exe.addCSourceFile(.{ | |
| 20 | .file = .{ .path = "main.c" }, | |
| 21 | .flags = &.{}, | |
| 22 | }); | |
| 20 | 23 | exe.link_gc_sections = false; |
| 21 | 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 | 19 | .optimize = .Debug, |
| 20 | 20 | }); |
| 21 | 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 | 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 | .root_source_file = .{ .path = "main.zig" }, |
| 9 | 9 | .optimize = b.standardOptimizeOption(.{}), |
| 10 | 10 | }); |
| 11 | main.emit_asm = .{ .emit_to = b.pathFromRoot("main.s") }; | |
| 12 | main.emit_bin = .{ .emit_to = b.pathFromRoot("main") }; | |
| 11 | // TODO: actually check these two artifacts for correctness | |
| 12 | _ = main.getEmittedBin(); | |
| 13 | _ = main.getEmittedAsm(); | |
| 13 | 14 | |
| 14 | 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 | 13 | .optimize = optimize, |
| 14 | 14 | .target = target, |
| 15 | 15 | }); |
| 16 | obj.emit_llvm_ir = .{ .emit_to = b.pathFromRoot("main.ll") }; | |
| 17 | obj.emit_llvm_bc = .{ .emit_to = b.pathFromRoot("main.bc") }; | |
| 18 | obj.emit_bin = .no_emit; | |
| 16 | _ = obj.getEmittedLlvmIr(); | |
| 17 | _ = obj.getEmittedLlvmBc(); | |
| 19 | 18 | b.default_step.dependOn(&obj.step); |
| 20 | 19 | |
| 21 | 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 | 14 | .optimize = optimize, |
| 15 | 15 | }); |
| 16 | 16 | |
| 17 | // TODO: actually check the output | |
| 18 | _ = obj.getEmittedBin(); | |
| 19 | ||
| 17 | 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 | 27 | exe.linkSystemLibrary("ntdll"); |
| 28 | 28 | exe.addObject(obj); |
| 29 | 29 | |
| 30 | // TODO: actually check the output | |
| 31 | _ = exe.getEmittedBin(); | |
| 32 | ||
| 30 | 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 | const test_artifact = b.addTest(.{ |
| 8 | 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 | 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 | 19 | .optimize = optimize, |
| 20 | 20 | .target = target, |
| 21 | 21 | }); |
| 22 | kernel.addObjectFile("./boot.S"); | |
| 23 | kernel.setLinkerScriptPath(.{ .path = "./linker.ld" }); | |
| 22 | kernel.addObjectFile(.{ .path = "./boot.S" }); | |
| 23 | kernel.setLinkerScript(.{ .path = "./linker.ld" }); | |
| 24 | 24 | b.installArtifact(kernel); |
| 25 | 25 | |
| 26 | 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 | 6 | |
| 7 | 7 | const test_exe = b.addTest(.{ |
| 8 | 8 | .root_source_file = .{ .path = "a/test.zig" }, |
| 9 | .main_pkg_path = .{ .path = "." }, | |
| 9 | 10 | }); |
| 10 | test_exe.setMainPkgPath("."); | |
| 11 | 11 | |
| 12 | 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 | 21 | .root_source_file = .{ .path = "main.zig" }, |
| 22 | 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 | 25 | exe.linkLibC(); |
| 26 | 26 | |
| 27 | 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 | 19 | .optimize = optimize, |
| 20 | 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 | 26 | exe.addObject(obj); |
| 24 | 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 | 19 | .target = target, |
| 20 | 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 | 26 | exe.linkLibrary(lib); |
| 24 | 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 | 74 | if (target.isWindows()) c_shared_lib.defineCMacro("LIB_API", "__declspec(dllexport)"); |
| 75 | 75 | |
| 76 | 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 | 81 | c_shared_lib.linkLibC(); |
| 79 | 82 | |
| 80 | 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 | 11 | .optimize = optimize, |
| 12 | 12 | .target = .{}, |
| 13 | 13 | }); |
| 14 | foo.addCSourceFile("foo.c", &[_][]const u8{}); | |
| 15 | foo.addIncludePath("."); | |
| 14 | foo.addCSourceFile(.{ .file = .{ .path = "foo.c" }, .flags = &[_][]const u8{} }); | |
| 15 | foo.addIncludePath(.{ .path = "." }); | |
| 16 | 16 | |
| 17 | 17 | const test_exe = b.addTest(.{ |
| 18 | 18 | .root_source_file = .{ .path = "foo.zig" }, |
| 19 | 19 | .optimize = optimize, |
| 20 | 20 | }); |
| 21 | 21 | test_exe.linkLibrary(foo); |
| 22 | test_exe.addIncludePath("."); | |
| 22 | test_exe.addIncludePath(.{ .path = "." }); | |
| 23 | 23 | |
| 24 | 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 | 14 | .target = target, |
| 15 | 15 | }); |
| 16 | 16 | main.strip = true; |
| 17 | ||
| 18 | // TODO: actually check the output | |
| 19 | _ = main.getEmittedBin(); | |
| 20 | ||
| 17 | 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 | 10 | .root_source_file = .{ .path = "main.zig" }, |
| 11 | 11 | .optimize = optimize, |
| 12 | 12 | }); |
| 13 | main.addIncludePath("."); | |
| 13 | main.addIncludePath(.{ .path = "." }); | |
| 14 | 14 | |
| 15 | 15 | test_step.dependOn(&b.addRunArtifact(main).step); |
| 16 | 16 | } |
test/tests.zig+14-9| ... | ... | @@ -588,6 +588,8 @@ pub fn addStandaloneTests( |
| 588 | 588 | }); |
| 589 | 589 | if (case.link_libc) exe.linkLibC(); |
| 590 | 590 | |
| 591 | _ = exe.getEmittedBin(); | |
| 592 | ||
| 591 | 593 | step.dependOn(&exe.step); |
| 592 | 594 | } |
| 593 | 595 | |
| ... | ... | @@ -759,7 +761,7 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 759 | 761 | "-fno-emit-bin", "-fno-emit-h", |
| 760 | 762 | "-fstrip", "-OReleaseFast", |
| 761 | 763 | }); |
| 762 | run.addFileSourceArg(writefile.files.items[0].getFileSource()); | |
| 764 | run.addFileArg(writefile.files.items[0].getPath()); | |
| 763 | 765 | const example_s = run.addPrefixedOutputFileArg("-femit-asm=", "example.s"); |
| 764 | 766 | |
| 765 | 767 | const checkfile = b.addCheckFile(example_s, .{ |
| ... | ... | @@ -1006,6 +1008,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 1006 | 1008 | .single_threaded = test_target.single_threaded, |
| 1007 | 1009 | .use_llvm = test_target.use_llvm, |
| 1008 | 1010 | .use_lld = test_target.use_lld, |
| 1011 | .zig_lib_dir = .{ .path = "lib" }, | |
| 1009 | 1012 | }); |
| 1010 | 1013 | const single_threaded_suffix = if (test_target.single_threaded == true) "-single" else ""; |
| 1011 | 1014 | const backend_suffix = if (test_target.use_llvm == true) |
| ... | ... | @@ -1017,8 +1020,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 1017 | 1020 | else |
| 1018 | 1021 | ""; |
| 1019 | 1022 | |
| 1020 | these_tests.overrideZigLibDir("lib"); | |
| 1021 | these_tests.addIncludePath("test"); | |
| 1023 | these_tests.addIncludePath(.{ .path = "test" }); | |
| 1022 | 1024 | |
| 1023 | 1025 | const qualified_name = b.fmt("{s}-{s}-{s}{s}{s}{s}", .{ |
| 1024 | 1026 | options.name, |
| ... | ... | @@ -1037,11 +1039,11 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 1037 | 1039 | .name = qualified_name, |
| 1038 | 1040 | .link_libc = test_target.link_libc, |
| 1039 | 1041 | .target = altered_target, |
| 1042 | .zig_lib_dir = .{ .path = "lib" }, | |
| 1040 | 1043 | }); |
| 1041 | compile_c.overrideZigLibDir("lib"); | |
| 1042 | compile_c.addCSourceFileSource(.{ | |
| 1043 | .source = these_tests.getOutputSource(), | |
| 1044 | .args = &.{ | |
| 1044 | compile_c.addCSourceFile(.{ | |
| 1045 | .file = these_tests.getEmittedBin(), | |
| 1046 | .flags = &.{ | |
| 1045 | 1047 | // TODO output -std=c89 compatible C code |
| 1046 | 1048 | "-std=c99", |
| 1047 | 1049 | "-pedantic", |
| ... | ... | @@ -1058,7 +1060,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 1058 | 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 | 1064 | if (test_target.target.getOsTag() == .windows) { |
| 1063 | 1065 | if (true) { |
| 1064 | 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 | 1133 | test_step.target_info.dynamic_linker.max_byte = null; |
| 1132 | 1134 | } |
| 1133 | 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 | 1141 | // This test is intentionally trying to check if the external ABI is |
| 1137 | 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 | } |