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");...@@ -37,7 +37,7 @@ pub const FmtStep = @import("Build/FmtStep.zig");
37pub const InstallArtifactStep = @import("Build/InstallArtifactStep.zig");37pub const InstallArtifactStep = @import("Build/InstallArtifactStep.zig");
38pub const InstallDirStep = @import("Build/InstallDirStep.zig");38pub const InstallDirStep = @import("Build/InstallDirStep.zig");
39pub const InstallFileStep = @import("Build/InstallFileStep.zig");39pub const InstallFileStep = @import("Build/InstallFileStep.zig");
40pub const InstallRawStep = @import("Build/InstallRawStep.zig");40pub const ObjCopyStep = @import("Build/ObjCopyStep.zig");
41pub const CompileStep = @import("Build/CompileStep.zig");41pub const CompileStep = @import("Build/CompileStep.zig");
42pub const LogStep = @import("Build/LogStep.zig");42pub const LogStep = @import("Build/LogStep.zig");
43pub const OptionsStep = @import("Build/OptionsStep.zig");43pub const OptionsStep = @import("Build/OptionsStep.zig");
...@@ -1254,11 +1254,8 @@ pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const...@@ -1254,11 +1254,8 @@ pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const
1254 self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step);1254 self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step);
1255}1255}
12561256
1257/// Output format (BIN vs Intel HEX) determined by filename1257pub fn addObjCopy(b: *Build, source: FileSource, options: ObjCopyStep.Options) *ObjCopyStep {
1258pub fn installRaw(self: *Build, artifact: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {1258 return ObjCopyStep.create(b, source, options);
1259 const raw = self.addInstallRaw(artifact, dest_filename, options);
1260 self.getInstallStep().dependOn(&raw.step);
1261 return raw;
1262}1259}
12631260
1264///`dest_rel_path` is relative to install prefix path1261///`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...@@ -1280,10 +1277,6 @@ pub fn addInstallHeaderFile(b: *Build, src_path: []const u8, dest_rel_path: []co
1280 return b.addInstallFileWithDir(.{ .path = src_path }, .header, dest_rel_path);1277 return b.addInstallFileWithDir(.{ .path = src_path }, .header, dest_rel_path);
1281}1278}
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
1287pub fn addInstallFileWithDir(1280pub fn addInstallFileWithDir(
1288 self: *Build,1281 self: *Build,
1289 source: FileSource,1282 source: FileSource,
...@@ -1771,7 +1764,7 @@ test {...@@ -1771,7 +1764,7 @@ test {
1771 _ = InstallArtifactStep;1764 _ = InstallArtifactStep;
1772 _ = InstallDirStep;1765 _ = InstallDirStep;
1773 _ = InstallFileStep;1766 _ = InstallFileStep;
1774 _ = InstallRawStep;1767 _ = ObjCopyStep;
1775 _ = CompileStep;1768 _ = CompileStep;
1776 _ = LogStep;1769 _ = LogStep;
1777 _ = OptionsStep;1770 _ = OptionsStep;
lib/std/Build/CompileStep.zig+13-5
...@@ -21,7 +21,7 @@ const VcpkgRoot = std.Build.VcpkgRoot;...@@ -21,7 +21,7 @@ const VcpkgRoot = std.Build.VcpkgRoot;
21const InstallDir = std.Build.InstallDir;21const InstallDir = std.Build.InstallDir;
22const InstallArtifactStep = std.Build.InstallArtifactStep;22const InstallArtifactStep = std.Build.InstallArtifactStep;
23const GeneratedFile = std.Build.GeneratedFile;23const GeneratedFile = std.Build.GeneratedFile;
24const InstallRawStep = std.Build.InstallRawStep;24const ObjCopyStep = std.Build.ObjCopyStep;
25const EmulatableRunStep = std.Build.EmulatableRunStep;25const EmulatableRunStep = std.Build.EmulatableRunStep;
26const CheckObjectStep = std.Build.CheckObjectStep;26const CheckObjectStep = std.Build.CheckObjectStep;
27const RunStep = std.Build.RunStep;27const RunStep = std.Build.RunStep;
...@@ -432,10 +432,6 @@ pub fn install(self: *CompileStep) void {...@@ -432,10 +432,6 @@ pub fn install(self: *CompileStep) void {
432 self.builder.installArtifact(self);432 self.builder.installArtifact(self);
433}433}
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
439pub fn installHeader(a: *CompileStep, src_path: []const u8, dest_rel_path: []const u8) void {435pub fn installHeader(a: *CompileStep, src_path: []const u8, dest_rel_path: []const u8) void {
440 const install_file = a.builder.addInstallHeaderFile(src_path, dest_rel_path);436 const install_file = a.builder.addInstallHeaderFile(src_path, dest_rel_path);
441 a.builder.getInstallStep().dependOn(&install_file.step);437 a.builder.getInstallStep().dependOn(&install_file.step);
...@@ -506,6 +502,18 @@ pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void {...@@ -506,6 +502,18 @@ pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void {
506 a.installed_headers.appendSlice(l.installed_headers.items) catch @panic("OOM");502 a.installed_headers.appendSlice(l.installed_headers.items) catch @panic("OOM");
507}503}
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
509/// Deprecated: use `std.Build.addRunArtifact`517/// Deprecated: use `std.Build.addRunArtifact`
510/// This function will run in the context of the package that created the executable,518/// This function will run in the context of the package that created the executable,
511/// which is undesirable when running an executable provided by a dependency package.519/// 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 {...@@ -21,7 +21,7 @@ pub const Id = enum {
21 check_file,21 check_file,
22 check_object,22 check_object,
23 config_header,23 config_header,
24 install_raw,24 objcopy,
25 options,25 options,
26 custom,26 custom,
2727
...@@ -42,7 +42,7 @@ pub const Id = enum {...@@ -42,7 +42,7 @@ pub const Id = enum {
42 .check_file => Build.CheckFileStep,42 .check_file => Build.CheckFileStep,
43 .check_object => Build.CheckObjectStep,43 .check_object => Build.CheckObjectStep,
44 .config_header => Build.ConfigHeaderStep,44 .config_header => Build.ConfigHeaderStep,
45 .install_raw => Build.InstallRawStep,45 .objcopy => Build.ObjCopyStep,
46 .options => Build.OptionsStep,46 .options => Build.OptionsStep,
47 .custom => @compileError("no type available for custom step"),47 .custom => @compileError("no type available for custom step"),
48 };48 };
test/standalone/install_raw_hex/build.zig+10-5
...@@ -3,6 +3,9 @@ const std = @import("std");...@@ -3,6 +3,9 @@ const std = @import("std");
3const CheckFileStep = std.Build.CheckFileStep;3const CheckFileStep = std.Build.CheckFileStep;
44
5pub fn build(b: *std.Build) void {5pub fn build(b: *std.Build) void {
6 const test_step = b.step("test", "Test the program");
7 b.default_step.dependOn(test_step);
8
6 const target = .{9 const target = .{
7 .cpu_arch = .thumb,10 .cpu_arch = .thumb,
8 .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 },11 .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 },
...@@ -19,12 +22,14 @@ pub fn build(b: *std.Build) void {...@@ -19,12 +22,14 @@ pub fn build(b: *std.Build) void {
19 .optimize = optimize,22 .optimize = optimize,
20 });23 });
2124
22 const test_step = b.step("test", "Test the program");25 const hex_step = elf.addObjCopy(.{
23 b.default_step.dependOn(test_step);26 .basename = "hello.hex",
2427 });
25 const hex_step = b.addInstallRaw(elf, "hello.hex", .{});
26 test_step.dependOn(&hex_step.step);28 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 });
29 test_step.dependOn(&explicit_format_hex_step.step);34 test_step.dependOn(&explicit_format_hex_step.step);
30}35}