diff options
Diffstat (limited to 'lib/std/Build')
| -rw-r--r-- | lib/std/Build/Module.zig | 15 | ||||
| -rw-r--r-- | lib/std/Build/Step/CheckObject.zig | 120 | ||||
| -rw-r--r-- | lib/std/Build/Step/Compile.zig | 41 | ||||
| -rw-r--r-- | lib/std/Build/Step/ConfigHeader.zig | 13 |
4 files changed, 117 insertions, 72 deletions
diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index 02386de430..d19f0a781e 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -451,7 +451,7 @@ pub fn linkFramework(m: *Module, name: []const u8, options: LinkFrameworkOptions pub const AddCSourceFilesOptions = struct { /// When provided, `files` are relative to `root` rather than the /// package that owns the `Compile` step. - root: LazyPath = .{ .path = "" }, + root: ?LazyPath = null, files: []const []const u8, flags: []const []const u8 = &.{}, }; @@ -472,7 +472,7 @@ pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void { const c_source_files = allocator.create(CSourceFiles) catch @panic("OOM"); c_source_files.* = .{ - .root = options.root, + .root = options.root orelse b.path(""), .files = b.dupeStrings(options.files), .flags = b.dupeStrings(options.flags), }; @@ -573,17 +573,6 @@ pub fn addLibraryPath(m: *Module, directory_path: LazyPath) void { pub fn addRPath(m: *Module, directory_path: LazyPath) void { const b = m.owner; - switch (directory_path) { - .path, .cwd_relative => |path| { - // TODO: remove this check after people upgrade and stop expecting it to work - if (std.mem.startsWith(u8, path, "@executable_path") or - std.mem.startsWith(u8, path, "@loader_path")) - { - @panic("this function is for adding directory paths. It does not support special rpaths. use addRPathSpecial for that."); - } - }, - else => {}, - } m.rpaths.append(b.allocator, .{ .lazy_path = directory_path.dupe(b) }) catch @panic("OOM"); addLazyPathDependenciesOnly(m, directory_path); } diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index c39a487649..f8f0fcd584 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -247,15 +247,27 @@ const ComputeCompareExpected = struct { const Check = struct { kind: Kind, + payload: Payload, + data: std.ArrayList(u8), actions: std.ArrayList(Action), fn create(allocator: Allocator, kind: Kind) Check { return .{ .kind = kind, + .payload = .{ .none = {} }, + .data = std.ArrayList(u8).init(allocator), .actions = std.ArrayList(Action).init(allocator), }; } + fn dumpSection(allocator: Allocator, name: [:0]const u8) Check { + var check = Check.create(allocator, .dump_section); + const off: u32 = @intCast(check.data.items.len); + check.data.writer().print("{s}\x00", .{name}) catch @panic("OOM"); + check.payload = .{ .dump_section = off }; + return check; + } + fn extract(self: *Check, phrase: SearchPhrase) void { self.actions.append(.{ .tag = .extract, @@ -305,6 +317,13 @@ const Check = struct { dyld_lazy_bind, exports, compute_compare, + dump_section, + }; + + const Payload = union { + none: void, + /// Null-delimited string in the 'data' buffer. + dump_section: u32, }; }; @@ -513,6 +532,11 @@ pub fn checkInArchiveSymtab(self: *CheckObject) void { self.checkExact(label); } +pub fn dumpSection(self: *CheckObject, name: [:0]const u8) void { + const new_check = Check.dumpSection(self.step.owner.allocator, name); + self.checks.append(new_check) catch @panic("OOM"); +} + /// Creates a new standalone, singular check which allows running simple binary operations /// on the extracted variables. It will then compare the reduced program with the value of /// the expected variable. @@ -564,13 +588,44 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { } const output = switch (self.obj_format) { - .macho => try MachODumper.parseAndDump(step, chk.kind, contents), - .elf => try ElfDumper.parseAndDump(step, chk.kind, contents), + .macho => try MachODumper.parseAndDump(step, chk, contents), + .elf => try ElfDumper.parseAndDump(step, chk, contents), .coff => return step.fail("TODO coff parser", .{}), - .wasm => try WasmDumper.parseAndDump(step, chk.kind, contents), + .wasm => try WasmDumper.parseAndDump(step, chk, contents), else => unreachable, }; + // Depending on whether we requested dumping section verbatim or not, + // we either format message string with escaped codes, or not to aid debugging + // the failed test. + const fmtMessageString = struct { + fn fmtMessageString(kind: Check.Kind, msg: []const u8) std.fmt.Formatter(formatMessageString) { + return .{ .data = .{ + .kind = kind, + .msg = msg, + } }; + } + + const Ctx = struct { + kind: Check.Kind, + msg: []const u8, + }; + + fn formatMessageString( + ctx: Ctx, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = unused_fmt_string; + _ = options; + switch (ctx.kind) { + .dump_section => try writer.print("{s}", .{std.fmt.fmtSliceEscapeLower(ctx.msg)}), + else => try writer.writeAll(ctx.msg), + } + } + }.fmtMessageString; + var it = mem.tokenizeAny(u8, output, "\r\n"); for (chk.actions.items) |act| { switch (act.tag) { @@ -585,7 +640,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { \\========= but parsed file does not contain it: ======= \\{s} \\====================================================== - , .{ act.phrase.resolve(b, step), output }); + , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) }); } }, @@ -600,7 +655,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { \\========= but parsed file does not contain it: ======= \\{s} \\====================================================== - , .{ act.phrase.resolve(b, step), output }); + , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) }); } }, @@ -614,7 +669,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { \\========= but parsed file does contain it: ======== \\{s} \\=================================================== - , .{ act.phrase.resolve(b, step), output }); + , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) }); } }, @@ -629,7 +684,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { \\========= but parsed file does not contain it: ======= \\{s} \\====================================================== - , .{ act.phrase.resolve(b, step), output }); + , .{ act.phrase.resolve(b, step), fmtMessageString(chk.kind, output) }); } }, @@ -660,7 +715,7 @@ const MachODumper = struct { } }; - fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 { + fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 { const gpa = step.owner.allocator; var stream = std.io.fixedBufferStream(bytes); const reader = stream.reader(); @@ -731,7 +786,7 @@ const MachODumper = struct { } } - switch (kind) { + switch (check.kind) { .headers => { try dumpHeader(hdr, writer); @@ -764,7 +819,7 @@ const MachODumper = struct { if (dyld_info_lc == null) return step.fail("no dyld info found", .{}); const lc = dyld_info_lc.?; - switch (kind) { + switch (check.kind) { .dyld_rebase => if (lc.rebase_size > 0) { const data = bytes[lc.rebase_off..][0..lc.rebase_size]; try writer.writeAll(dyld_rebase_label ++ "\n"); @@ -805,7 +860,7 @@ const MachODumper = struct { return step.fail("no exports data found", .{}); }, - else => return step.fail("invalid check kind for MachO file format: {s}", .{@tagName(kind)}), + else => return step.fail("invalid check kind for MachO file format: {s}", .{@tagName(check.kind)}), } return output.toOwnedSlice(); @@ -1633,14 +1688,14 @@ const ElfDumper = struct { const dynamic_section_label = "dynamic section"; const archive_symtab_label = "archive symbol table"; - fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 { - return parseAndDumpArchive(step, kind, bytes) catch |err| switch (err) { - error.InvalidArchiveMagicNumber => try parseAndDumpObject(step, kind, bytes), + fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 { + return parseAndDumpArchive(step, check, bytes) catch |err| switch (err) { + error.InvalidArchiveMagicNumber => try parseAndDumpObject(step, check, bytes), else => |e| return e, }; } - fn parseAndDumpArchive(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 { + fn parseAndDumpArchive(step: *Step, check: Check, bytes: []const u8) ![]const u8 { const gpa = step.owner.allocator; var stream = std.io.fixedBufferStream(bytes); const reader = stream.reader(); @@ -1702,13 +1757,13 @@ const ElfDumper = struct { var output = std.ArrayList(u8).init(gpa); const writer = output.writer(); - switch (kind) { + switch (check.kind) { .archive_symtab => if (ctx.symtab.items.len > 0) { try ctx.dumpSymtab(writer); } else return step.fail("no archive symbol table found", .{}), else => if (ctx.objects.items.len > 0) { - try ctx.dumpObjects(step, kind, writer); + try ctx.dumpObjects(step, check, writer); } else return step.fail("empty archive", .{}), } @@ -1785,10 +1840,10 @@ const ElfDumper = struct { } } - fn dumpObjects(ctx: ArchiveContext, step: *Step, kind: Check.Kind, writer: anytype) !void { + fn dumpObjects(ctx: ArchiveContext, step: *Step, check: Check, writer: anytype) !void { for (ctx.objects.items) |object| { try writer.print("object {s}\n", .{object.name}); - const output = try parseAndDumpObject(step, kind, ctx.data[object.off..][0..object.len]); + const output = try parseAndDumpObject(step, check, ctx.data[object.off..][0..object.len]); defer ctx.gpa.free(output); try writer.print("{s}\n", .{output}); } @@ -1806,7 +1861,7 @@ const ElfDumper = struct { }; }; - fn parseAndDumpObject(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 { + fn parseAndDumpObject(step: *Step, check: Check, bytes: []const u8) ![]const u8 { const gpa = step.owner.allocator; var stream = std.io.fixedBufferStream(bytes); const reader = stream.reader(); @@ -1859,7 +1914,7 @@ const ElfDumper = struct { var output = std.ArrayList(u8).init(gpa); const writer = output.writer(); - switch (kind) { + switch (check.kind) { .headers => { try ctx.dumpHeader(writer); try ctx.dumpShdrs(writer); @@ -1878,7 +1933,13 @@ const ElfDumper = struct { try ctx.dumpDynamicSection(shndx, writer); } else return step.fail("no .dynamic section found", .{}), - else => return step.fail("invalid check kind for ELF file format: {s}", .{@tagName(kind)}), + .dump_section => { + const name = mem.sliceTo(@as([*:0]const u8, @ptrCast(check.data.items.ptr + check.payload.dump_section)), 0); + const shndx = ctx.getSectionByName(name) orelse return step.fail("no '{s}' section found", .{name}); + try ctx.dumpSection(shndx, writer); + }, + + else => return step.fail("invalid check kind for ELF file format: {s}", .{@tagName(check.kind)}), } return output.toOwnedSlice(); @@ -2176,6 +2237,11 @@ const ElfDumper = struct { } } + fn dumpSection(ctx: ObjectContext, shndx: usize, writer: anytype) !void { + const data = ctx.getSectionContents(shndx); + try writer.print("{s}", .{data}); + } + inline fn getSectionName(ctx: ObjectContext, shndx: usize) []const u8 { const shdr = ctx.shdrs[shndx]; return getString(ctx.shstrtab, shdr.sh_name); @@ -2300,7 +2366,7 @@ const ElfDumper = struct { const WasmDumper = struct { const symtab_label = "symbols"; - fn parseAndDump(step: *Step, kind: Check.Kind, bytes: []const u8) ![]const u8 { + fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 { const gpa = step.owner.allocator; var fbs = std.io.fixedBufferStream(bytes); const reader = fbs.reader(); @@ -2317,7 +2383,7 @@ const WasmDumper = struct { errdefer output.deinit(); const writer = output.writer(); - switch (kind) { + switch (check.kind) { .headers => { while (reader.readByte()) |current_byte| { const section = std.meta.intToEnum(std.wasm.Section, current_byte) catch { @@ -2330,7 +2396,7 @@ const WasmDumper = struct { } else |_| {} // reached end of stream }, - else => return step.fail("invalid check kind for Wasm file format: {s}", .{@tagName(kind)}), + else => return step.fail("invalid check kind for Wasm file format: {s}", .{@tagName(check.kind)}), } return output.toOwnedSlice(); @@ -2364,7 +2430,7 @@ const WasmDumper = struct { => { const entries = try std.leb.readULEB128(u32, reader); try writer.print("\nentries {d}\n", .{entries}); - try dumpSection(step, section, data[fbs.pos..], entries, writer); + try parseSection(step, section, data[fbs.pos..], entries, writer); }, .custom => { const name_length = try std.leb.readULEB128(u32, reader); @@ -2393,7 +2459,7 @@ const WasmDumper = struct { } } - fn dumpSection(step: *Step, section: std.wasm.Section, data: []const u8, entries: u32, writer: anytype) !void { + fn parseSection(step: *Step, section: std.wasm.Section, data: []const u8, entries: u32, writer: anytype) !void { var fbs = std.io.fixedBufferStream(data); const reader = fbs.reader(); diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 4a5364176a..c36fd8c4ca 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -55,7 +55,7 @@ global_base: ?u64 = null, zig_lib_dir: ?LazyPath, exec_cmd_args: ?[]const ?[]const u8, filters: []const []const u8, -test_runner: ?[]const u8, +test_runner: ?LazyPath, test_server_mode: bool, wasi_exec_model: ?std.builtin.WasiExecModel = null, @@ -236,7 +236,7 @@ pub const Options = struct { version: ?std.SemanticVersion = null, max_rss: usize = 0, filters: []const []const u8 = &.{}, - test_runner: ?[]const u8 = null, + test_runner: ?LazyPath = null, use_llvm: ?bool = null, use_lld: ?bool = null, zig_lib_dir: ?LazyPath = null, @@ -264,20 +264,8 @@ pub const HeaderInstallation = union(enum) { dest_rel_path: []const u8, pub fn dupe(self: File, b: *std.Build) File { - // 'path' lazy paths are relative to the build root of some step, inferred from the step - // in which they are used. This means that we can't dupe such paths, because they may - // come from dependencies with their own build roots and duping the paths as is might - // cause the build script to search for the file relative to the wrong root. - // As a temporary workaround, we convert build root-relative paths to absolute paths. - // If/when the build-root relative paths are updated to encode which build root they are - // relative to, this workaround should be removed. - const duped_source: LazyPath = switch (self.source) { - .path => |root_rel| .{ .cwd_relative = b.pathFromRoot(root_rel) }, - else => self.source.dupe(b), - }; - return .{ - .source = duped_source, + .source = self.source.dupe(b), .dest_rel_path = b.dupePath(self.dest_rel_path), }; } @@ -305,20 +293,8 @@ pub const HeaderInstallation = union(enum) { }; pub fn dupe(self: Directory, b: *std.Build) Directory { - // 'path' lazy paths are relative to the build root of some step, inferred from the step - // in which they are used. This means that we can't dupe such paths, because they may - // come from dependencies with their own build roots and duping the paths as is might - // cause the build script to search for the file relative to the wrong root. - // As a temporary workaround, we convert build root-relative paths to absolute paths. - // If/when the build-root relative paths are updated to encode which build root they are - // relative to, this workaround should be removed. - const duped_source: LazyPath = switch (self.source) { - .path => |root_rel| .{ .cwd_relative = b.pathFromRoot(root_rel) }, - else => self.source.dupe(b), - }; - return .{ - .source = duped_source, + .source = self.source.dupe(b), .dest_rel_path = b.dupePath(self.dest_rel_path), .options = self.options.dupe(b), }; @@ -402,7 +378,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { .zig_lib_dir = null, .exec_cmd_args = null, .filters = options.filters, - .test_runner = options.test_runner, + .test_runner = null, .test_server_mode = options.test_runner == null, .rdynamic = false, .installed_path = null, @@ -429,6 +405,11 @@ pub fn create(owner: *std.Build, options: Options) *Compile { lp.addStepDependencies(&self.step); } + if (options.test_runner) |lp| { + self.test_runner = lp.dupe(self.step.owner); + lp.addStepDependencies(&self.step); + } + // Only the PE/COFF format has a Resource Table which is where the manifest // gets embedded, so for any other target the manifest file is just ignored. if (target.ofmt == .coff) { @@ -1402,7 +1383,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { if (self.test_runner) |test_runner| { try zig_args.append("--test-runner"); - try zig_args.append(b.pathFromRoot(test_runner)); + try zig_args.append(test_runner.getPath(b)); } for (b.debug_log_scopes) |log_scope| { diff --git a/lib/std/Build/Step/ConfigHeader.zig b/lib/std/Build/Step/ConfigHeader.zig index 46631cac24..e547f8082e 100644 --- a/lib/std/Build/Step/ConfigHeader.zig +++ b/lib/std/Build/Step/ConfigHeader.zig @@ -58,6 +58,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { if (options.style.getPath()) |s| default_include_path: { const sub_path = switch (s) { + .src_path => |sp| sp.sub_path, .path => |path| path, .generated, .generated_dirname => break :default_include_path, .cwd_relative => |sub_path| sub_path, @@ -192,13 +193,21 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { .autoconf => |file_source| { try output.appendSlice(c_generated_line); const src_path = file_source.getPath(b); - const contents = try std.fs.cwd().readFileAlloc(arena, src_path, self.max_bytes); + const contents = std.fs.cwd().readFileAlloc(arena, src_path, self.max_bytes) catch |err| { + return step.fail("unable to read autoconf input file '{s}': {s}", .{ + src_path, @errorName(err), + }); + }; try render_autoconf(step, contents, &output, self.values, src_path); }, .cmake => |file_source| { try output.appendSlice(c_generated_line); const src_path = file_source.getPath(b); - const contents = try std.fs.cwd().readFileAlloc(arena, src_path, self.max_bytes); + const contents = std.fs.cwd().readFileAlloc(arena, src_path, self.max_bytes) catch |err| { + return step.fail("unable to read cmake input file '{s}': {s}", .{ + src_path, @errorName(err), + }); + }; try render_cmake(step, contents, &output, self.values, src_path); }, .blank => { |
