authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-24 16:02:01-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-24 23:48:03-05:00
log26196be344e971c26ed044a39b68d0420cd94b90
tree7c8c69a6876d50e872dc036e7dbd845ce564c70a
parent6398aabb87cc39ddbc4e8fd650545ffcc864f9a6

rename std.Build.InstallRawStep to ObjCopyStep

And make it not do any installation, only objcopying. We already have install steps for doing installation. This commit also makes ObjCopyStep properly integrate with caching.

6 files changed, 167 insertions(+), 133 deletions(-)

lib/std/Build.zig+4-11
......@@ -37,7 +37,7 @@ pub const FmtStep = @import("Build/FmtStep.zig");
3737pub const InstallArtifactStep = @import("Build/InstallArtifactStep.zig");
3838pub const InstallDirStep = @import("Build/InstallDirStep.zig");
3939pub const InstallFileStep = @import("Build/InstallFileStep.zig");
40pub const InstallRawStep = @import("Build/InstallRawStep.zig");
40pub const ObjCopyStep = @import("Build/ObjCopyStep.zig");
4141pub const CompileStep = @import("Build/CompileStep.zig");
4242pub const LogStep = @import("Build/LogStep.zig");
4343pub const OptionsStep = @import("Build/OptionsStep.zig");
......@@ -1254,11 +1254,8 @@ pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const
12541254 self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step);
12551255}
12561256
1257/// Output format (BIN vs Intel HEX) determined by filename
1258pub fn installRaw(self: *Build, artifact: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
1259 const raw = self.addInstallRaw(artifact, dest_filename, options);
1260 self.getInstallStep().dependOn(&raw.step);
1261 return raw;
1257pub fn addObjCopy(b: *Build, source: FileSource, options: ObjCopyStep.Options) *ObjCopyStep {
1258 return ObjCopyStep.create(b, source, options);
12621259}
12631260
12641261///`dest_rel_path` is relative to install prefix path
......@@ -1280,10 +1277,6 @@ pub fn addInstallHeaderFile(b: *Build, src_path: []const u8, dest_rel_path: []co
12801277 return b.addInstallFileWithDir(.{ .path = src_path }, .header, dest_rel_path);
12811278}
12821279
1283pub fn addInstallRaw(self: *Build, artifact: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
1284 return InstallRawStep.create(self, artifact, dest_filename, options);
1285}
1286
12871280pub fn addInstallFileWithDir(
12881281 self: *Build,
12891282 source: FileSource,
......@@ -1771,7 +1764,7 @@ test {
17711764 _ = InstallArtifactStep;
17721765 _ = InstallDirStep;
17731766 _ = InstallFileStep;
1774 _ = InstallRawStep;
1767 _ = ObjCopyStep;
17751768 _ = CompileStep;
17761769 _ = LogStep;
17771770 _ = OptionsStep;
lib/std/Build/CompileStep.zig+13-5
......@@ -21,7 +21,7 @@ const VcpkgRoot = std.Build.VcpkgRoot;
2121const InstallDir = std.Build.InstallDir;
2222const InstallArtifactStep = std.Build.InstallArtifactStep;
2323const GeneratedFile = std.Build.GeneratedFile;
24const InstallRawStep = std.Build.InstallRawStep;
24const ObjCopyStep = std.Build.ObjCopyStep;
2525const EmulatableRunStep = std.Build.EmulatableRunStep;
2626const CheckObjectStep = std.Build.CheckObjectStep;
2727const RunStep = std.Build.RunStep;
......@@ -432,10 +432,6 @@ pub fn install(self: *CompileStep) void {
432432 self.builder.installArtifact(self);
433433}
434434
435pub fn installRaw(self: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
436 return self.builder.installRaw(self, dest_filename, options);
437}
438
439435pub fn installHeader(a: *CompileStep, src_path: []const u8, dest_rel_path: []const u8) void {
440436 const install_file = a.builder.addInstallHeaderFile(src_path, dest_rel_path);
441437 a.builder.getInstallStep().dependOn(&install_file.step);
......@@ -506,6 +502,18 @@ pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void {
506502 a.installed_headers.appendSlice(l.installed_headers.items) catch @panic("OOM");
507503}
508504
505pub fn addObjCopy(cs: *CompileStep, options: ObjCopyStep.Options) *ObjCopyStep {
506 var copy = options;
507 if (copy.basename == null) {
508 if (options.format) |f| {
509 copy.basename = cs.builder.fmt("{s}.{s}", .{ cs.name, @tagName(f) });
510 } else {
511 copy.basename = cs.name;
512 }
513 }
514 return cs.builder.addObjCopy(cs.getOutputSource(), copy);
515}
516
509517/// Deprecated: use `std.Build.addRunArtifact`
510518/// This function will run in the context of the package that created the executable,
511519/// which is undesirable when running an executable provided by a dependency package.
lib/std/Build/InstallRawStep.zig deleted-110
......@@ -1,110 +0,0 @@
1//! TODO: Rename this to ObjCopyStep now that it invokes the `zig objcopy`
2//! subcommand rather than containing an implementation directly.
3
4const std = @import("std");
5const InstallRawStep = @This();
6
7const Allocator = std.mem.Allocator;
8const ArenaAllocator = std.heap.ArenaAllocator;
9const ArrayListUnmanaged = std.ArrayListUnmanaged;
10const File = std.fs.File;
11const InstallDir = std.Build.InstallDir;
12const CompileStep = std.Build.CompileStep;
13const Step = std.Build.Step;
14const elf = std.elf;
15const fs = std.fs;
16const io = std.io;
17const sort = std.sort;
18
19pub const base_id = .install_raw;
20
21pub const RawFormat = enum {
22 bin,
23 hex,
24};
25
26step: Step,
27builder: *std.Build,
28artifact: *CompileStep,
29dest_dir: InstallDir,
30dest_filename: []const u8,
31options: CreateOptions,
32output_file: std.Build.GeneratedFile,
33
34pub const CreateOptions = struct {
35 format: ?RawFormat = null,
36 dest_dir: ?InstallDir = null,
37 only_section: ?[]const u8 = null,
38 pad_to: ?u64 = null,
39};
40
41pub fn create(
42 builder: *std.Build,
43 artifact: *CompileStep,
44 dest_filename: []const u8,
45 options: CreateOptions,
46) *InstallRawStep {
47 const self = builder.allocator.create(InstallRawStep) catch @panic("OOM");
48 self.* = InstallRawStep{
49 .step = Step.init(.install_raw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make),
50 .builder = builder,
51 .artifact = artifact,
52 .dest_dir = if (options.dest_dir) |d| d else switch (artifact.kind) {
53 .obj => unreachable,
54 .@"test" => unreachable,
55 .exe, .test_exe => .bin,
56 .lib => unreachable,
57 },
58 .dest_filename = dest_filename,
59 .options = options,
60 .output_file = std.Build.GeneratedFile{ .step = &self.step },
61 };
62 self.step.dependOn(&artifact.step);
63
64 builder.pushInstalledFile(self.dest_dir, dest_filename);
65 return self;
66}
67
68pub fn getOutputSource(self: *const InstallRawStep) std.Build.FileSource {
69 return std.Build.FileSource{ .generated = &self.output_file };
70}
71
72fn make(step: *Step) !void {
73 const self = @fieldParentPtr(InstallRawStep, "step", step);
74 const b = self.builder;
75
76 if (self.artifact.target.getObjectFormat() != .elf) {
77 std.debug.print("InstallRawStep only works with ELF format.\n", .{});
78 return error.InvalidObjectFormat;
79 }
80
81 const full_src_path = self.artifact.getOutputSource().getPath(b);
82 const full_dest_path = b.getInstallPath(self.dest_dir, self.dest_filename);
83 self.output_file.path = full_dest_path;
84
85 try fs.cwd().makePath(b.getInstallPath(self.dest_dir, ""));
86
87 var argv_list = std.ArrayList([]const u8).init(b.allocator);
88 try argv_list.appendSlice(&.{ b.zig_exe, "objcopy" });
89
90 if (self.options.only_section) |only_section| {
91 try argv_list.appendSlice(&.{ "-j", only_section });
92 }
93 if (self.options.pad_to) |pad_to| {
94 try argv_list.appendSlice(&.{
95 "--pad-to",
96 b.fmt("{d}", .{pad_to}),
97 });
98 }
99 if (self.options.format) |format| switch (format) {
100 .bin => try argv_list.appendSlice(&.{ "-O", "binary" }),
101 .hex => try argv_list.appendSlice(&.{ "-O", "hex" }),
102 };
103
104 try argv_list.appendSlice(&.{ full_src_path, full_dest_path });
105 _ = try self.builder.execFromStep(argv_list.items, &self.step);
106}
107
108test {
109 std.testing.refAllDecls(InstallRawStep);
110}
lib/std/Build/ObjCopyStep.zig created+138
......@@ -0,0 +1,138 @@
1const std = @import("std");
2const ObjCopyStep = @This();
3
4const Allocator = std.mem.Allocator;
5const ArenaAllocator = std.heap.ArenaAllocator;
6const ArrayListUnmanaged = std.ArrayListUnmanaged;
7const File = std.fs.File;
8const InstallDir = std.Build.InstallDir;
9const CompileStep = std.Build.CompileStep;
10const Step = std.Build.Step;
11const elf = std.elf;
12const fs = std.fs;
13const io = std.io;
14const sort = std.sort;
15
16pub const base_id: Step.Id = .objcopy;
17
18pub const RawFormat = enum {
19 bin,
20 hex,
21};
22
23step: Step,
24builder: *std.Build,
25file_source: std.Build.FileSource,
26basename: []const u8,
27output_file: std.Build.GeneratedFile,
28
29format: ?RawFormat,
30only_section: ?[]const u8,
31pad_to: ?u64,
32
33pub const Options = struct {
34 basename: ?[]const u8 = null,
35 format: ?RawFormat = null,
36 only_section: ?[]const u8 = null,
37 pad_to: ?u64 = null,
38};
39
40pub fn create(
41 builder: *std.Build,
42 file_source: std.Build.FileSource,
43 options: Options,
44) *ObjCopyStep {
45 const self = builder.allocator.create(ObjCopyStep) catch @panic("OOM");
46 self.* = ObjCopyStep{
47 .step = Step.init(
48 base_id,
49 builder.fmt("objcopy {s}", .{file_source.getDisplayName()}),
50 builder.allocator,
51 make,
52 ),
53 .builder = builder,
54 .file_source = file_source,
55 .basename = options.basename orelse file_source.getDisplayName(),
56 .output_file = std.Build.GeneratedFile{ .step = &self.step },
57
58 .format = options.format,
59 .only_section = options.only_section,
60 .pad_to = options.pad_to,
61 };
62 file_source.addStepDependencies(&self.step);
63 return self;
64}
65
66pub fn getOutputSource(self: *const ObjCopyStep) std.Build.FileSource {
67 return .{ .generated = &self.output_file };
68}
69
70fn make(step: *Step) !void {
71 const self = @fieldParentPtr(ObjCopyStep, "step", step);
72 const b = self.builder;
73
74 var man = b.cache.obtain();
75 defer man.deinit();
76
77 // Random bytes to make ObjCopyStep unique. Refresh this with new random
78 // bytes when ObjCopyStep implementation is modified incompatibly.
79 man.hash.add(@as(u32, 0xe18b7baf));
80
81 const full_src_path = self.file_source.getPath(b);
82 _ = try man.addFile(full_src_path, null);
83 man.hash.addOptionalBytes(self.only_section);
84 man.hash.addOptional(self.pad_to);
85 man.hash.addOptional(self.format);
86
87 if (man.hit() catch |err| failWithCacheError(man, err)) {
88 // Cache hit, skip subprocess execution.
89 const digest = man.final();
90 self.output_file.path = try b.cache_root.join(b.allocator, &.{
91 "o", &digest, self.basename,
92 });
93 return;
94 }
95
96 const digest = man.final();
97 const full_dest_path = try b.cache_root.join(b.allocator, &.{ "o", &digest, self.basename });
98 const cache_path = "o" ++ fs.path.sep_str ++ digest;
99 b.cache_root.handle.makePath(cache_path) catch |err| {
100 std.debug.print("unable to make path {s}: {s}\n", .{ cache_path, @errorName(err) });
101 return err;
102 };
103
104 var argv = std.ArrayList([]const u8).init(b.allocator);
105 try argv.appendSlice(&.{ b.zig_exe, "objcopy" });
106
107 if (self.only_section) |only_section| {
108 try argv.appendSlice(&.{ "-j", only_section });
109 }
110 if (self.pad_to) |pad_to| {
111 try argv.appendSlice(&.{ "--pad-to", b.fmt("{d}", .{pad_to}) });
112 }
113 if (self.format) |format| switch (format) {
114 .bin => try argv.appendSlice(&.{ "-O", "binary" }),
115 .hex => try argv.appendSlice(&.{ "-O", "hex" }),
116 };
117
118 try argv.appendSlice(&.{ full_src_path, full_dest_path });
119 _ = try self.builder.execFromStep(argv.items, &self.step);
120
121 self.output_file.path = full_dest_path;
122 try man.writeManifest();
123}
124
125/// TODO consolidate this with the same function in RunStep?
126/// Also properly deal with concurrency (see open PR)
127fn failWithCacheError(man: std.Build.Cache.Manifest, err: anyerror) noreturn {
128 const i = man.failed_file_index orelse failWithSimpleError(err);
129 const pp = man.files.items[i].prefixed_path orelse failWithSimpleError(err);
130 const prefix = man.cache.prefixes()[pp.prefix].path orelse "";
131 std.debug.print("{s}: {s}/{s}\n", .{ @errorName(err), prefix, pp.sub_path });
132 std.process.exit(1);
133}
134
135fn failWithSimpleError(err: anyerror) noreturn {
136 std.debug.print("{s}\n", .{@errorName(err)});
137 std.process.exit(1);
138}
lib/std/Build/Step.zig+2-2
......@@ -21,7 +21,7 @@ pub const Id = enum {
2121 check_file,
2222 check_object,
2323 config_header,
24 install_raw,
24 objcopy,
2525 options,
2626 custom,
2727
......@@ -42,7 +42,7 @@ pub const Id = enum {
4242 .check_file => Build.CheckFileStep,
4343 .check_object => Build.CheckObjectStep,
4444 .config_header => Build.ConfigHeaderStep,
45 .install_raw => Build.InstallRawStep,
45 .objcopy => Build.ObjCopyStep,
4646 .options => Build.OptionsStep,
4747 .custom => @compileError("no type available for custom step"),
4848 };
test/standalone/install_raw_hex/build.zig+10-5
......@@ -3,6 +3,9 @@ const std = @import("std");
33const CheckFileStep = std.Build.CheckFileStep;
44
55pub fn build(b: *std.Build) void {
6 const test_step = b.step("test", "Test the program");
7 b.default_step.dependOn(test_step);
8
69 const target = .{
710 .cpu_arch = .thumb,
811 .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 },
......@@ -19,12 +22,14 @@ pub fn build(b: *std.Build) void {
1922 .optimize = optimize,
2023 });
2124
22 const test_step = b.step("test", "Test the program");
23 b.default_step.dependOn(test_step);
24
25 const hex_step = b.addInstallRaw(elf, "hello.hex", .{});
25 const hex_step = elf.addObjCopy(.{
26 .basename = "hello.hex",
27 });
2628 test_step.dependOn(&hex_step.step);
2729
28 const explicit_format_hex_step = b.addInstallRaw(elf, "hello.foo", .{ .format = .hex });
30 const explicit_format_hex_step = elf.addObjCopy(.{
31 .basename = "hello.foo",
32 .format = .hex,
33 });
2934 test_step.dependOn(&explicit_format_hex_step.step);
3035}