| author | |
| committer | |
| log | 26196be344e971c26ed044a39b68d0420cd94b90 |
| tree | 7c8c69a6876d50e872dc036e7dbd845ce564c70a |
| parent | 6398aabb87cc39ddbc4e8fd650545ffcc864f9a6 |
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 | 37 | pub const InstallArtifactStep = @import("Build/InstallArtifactStep.zig"); |
| 38 | 38 | pub const InstallDirStep = @import("Build/InstallDirStep.zig"); |
| 39 | 39 | pub const InstallFileStep = @import("Build/InstallFileStep.zig"); |
| 40 | pub const InstallRawStep = @import("Build/InstallRawStep.zig"); | |
| 40 | pub const ObjCopyStep = @import("Build/ObjCopyStep.zig"); | |
| 41 | 41 | pub const CompileStep = @import("Build/CompileStep.zig"); |
| 42 | 42 | pub const LogStep = @import("Build/LogStep.zig"); |
| 43 | 43 | pub const OptionsStep = @import("Build/OptionsStep.zig"); |
| ... | ... | @@ -1254,11 +1254,8 @@ pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const |
| 1254 | 1254 | self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step); |
| 1255 | 1255 | } |
| 1256 | 1256 | |
| 1257 | /// Output format (BIN vs Intel HEX) determined by filename | |
| 1258 | pub 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; | |
| 1257 | pub fn addObjCopy(b: *Build, source: FileSource, options: ObjCopyStep.Options) *ObjCopyStep { | |
| 1258 | return ObjCopyStep.create(b, source, options); | |
| 1262 | 1259 | } |
| 1263 | 1260 | |
| 1264 | 1261 | ///`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 | 1277 | return b.addInstallFileWithDir(.{ .path = src_path }, .header, dest_rel_path); |
| 1281 | 1278 | } |
| 1282 | 1279 | |
| 1283 | pub 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 | ||
| 1287 | 1280 | pub fn addInstallFileWithDir( |
| 1288 | 1281 | self: *Build, |
| 1289 | 1282 | source: FileSource, |
| ... | ... | @@ -1771,7 +1764,7 @@ test { |
| 1771 | 1764 | _ = InstallArtifactStep; |
| 1772 | 1765 | _ = InstallDirStep; |
| 1773 | 1766 | _ = InstallFileStep; |
| 1774 | _ = InstallRawStep; | |
| 1767 | _ = ObjCopyStep; | |
| 1775 | 1768 | _ = CompileStep; |
| 1776 | 1769 | _ = LogStep; |
| 1777 | 1770 | _ = OptionsStep; |
lib/std/Build/CompileStep.zig+13-5| ... | ... | @@ -21,7 +21,7 @@ const VcpkgRoot = std.Build.VcpkgRoot; |
| 21 | 21 | const InstallDir = std.Build.InstallDir; |
| 22 | 22 | const InstallArtifactStep = std.Build.InstallArtifactStep; |
| 23 | 23 | const GeneratedFile = std.Build.GeneratedFile; |
| 24 | const InstallRawStep = std.Build.InstallRawStep; | |
| 24 | const ObjCopyStep = std.Build.ObjCopyStep; | |
| 25 | 25 | const EmulatableRunStep = std.Build.EmulatableRunStep; |
| 26 | 26 | const CheckObjectStep = std.Build.CheckObjectStep; |
| 27 | 27 | const RunStep = std.Build.RunStep; |
| ... | ... | @@ -432,10 +432,6 @@ pub fn install(self: *CompileStep) void { |
| 432 | 432 | self.builder.installArtifact(self); |
| 433 | 433 | } |
| 434 | 434 | |
| 435 | pub fn installRaw(self: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep { | |
| 436 | return self.builder.installRaw(self, dest_filename, options); | |
| 437 | } | |
| 438 | ||
| 439 | 435 | pub fn installHeader(a: *CompileStep, src_path: []const u8, dest_rel_path: []const u8) void { |
| 440 | 436 | const install_file = a.builder.addInstallHeaderFile(src_path, dest_rel_path); |
| 441 | 437 | a.builder.getInstallStep().dependOn(&install_file.step); |
| ... | ... | @@ -506,6 +502,18 @@ pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void { |
| 506 | 502 | a.installed_headers.appendSlice(l.installed_headers.items) catch @panic("OOM"); |
| 507 | 503 | } |
| 508 | 504 | |
| 505 | pub 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 | 517 | /// Deprecated: use `std.Build.addRunArtifact` |
| 510 | 518 | /// This function will run in the context of the package that created the executable, |
| 511 | 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 | ||
| 4 | const std = @import("std"); | |
| 5 | const InstallRawStep = @This(); | |
| 6 | ||
| 7 | const Allocator = std.mem.Allocator; | |
| 8 | const ArenaAllocator = std.heap.ArenaAllocator; | |
| 9 | const ArrayListUnmanaged = std.ArrayListUnmanaged; | |
| 10 | const File = std.fs.File; | |
| 11 | const InstallDir = std.Build.InstallDir; | |
| 12 | const CompileStep = std.Build.CompileStep; | |
| 13 | const Step = std.Build.Step; | |
| 14 | const elf = std.elf; | |
| 15 | const fs = std.fs; | |
| 16 | const io = std.io; | |
| 17 | const sort = std.sort; | |
| 18 | ||
| 19 | pub const base_id = .install_raw; | |
| 20 | ||
| 21 | pub const RawFormat = enum { | |
| 22 | bin, | |
| 23 | hex, | |
| 24 | }; | |
| 25 | ||
| 26 | step: Step, | |
| 27 | builder: *std.Build, | |
| 28 | artifact: *CompileStep, | |
| 29 | dest_dir: InstallDir, | |
| 30 | dest_filename: []const u8, | |
| 31 | options: CreateOptions, | |
| 32 | output_file: std.Build.GeneratedFile, | |
| 33 | ||
| 34 | pub 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 | ||
| 41 | pub 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 | ||
| 68 | pub fn getOutputSource(self: *const InstallRawStep) std.Build.FileSource { | |
| 69 | return std.Build.FileSource{ .generated = &self.output_file }; | |
| 70 | } | |
| 71 | ||
| 72 | fn 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 | ||
| 108 | test { | |
| 109 | std.testing.refAllDecls(InstallRawStep); | |
| 110 | } |
lib/std/Build/ObjCopyStep.zig created+138| ... | ... | @@ -0,0 +1,138 @@ |
| 1 | const std = @import("std"); | |
| 2 | const ObjCopyStep = @This(); | |
| 3 | ||
| 4 | const Allocator = std.mem.Allocator; | |
| 5 | const ArenaAllocator = std.heap.ArenaAllocator; | |
| 6 | const ArrayListUnmanaged = std.ArrayListUnmanaged; | |
| 7 | const File = std.fs.File; | |
| 8 | const InstallDir = std.Build.InstallDir; | |
| 9 | const CompileStep = std.Build.CompileStep; | |
| 10 | const Step = std.Build.Step; | |
| 11 | const elf = std.elf; | |
| 12 | const fs = std.fs; | |
| 13 | const io = std.io; | |
| 14 | const sort = std.sort; | |
| 15 | ||
| 16 | pub const base_id: Step.Id = .objcopy; | |
| 17 | ||
| 18 | pub const RawFormat = enum { | |
| 19 | bin, | |
| 20 | hex, | |
| 21 | }; | |
| 22 | ||
| 23 | step: Step, | |
| 24 | builder: *std.Build, | |
| 25 | file_source: std.Build.FileSource, | |
| 26 | basename: []const u8, | |
| 27 | output_file: std.Build.GeneratedFile, | |
| 28 | ||
| 29 | format: ?RawFormat, | |
| 30 | only_section: ?[]const u8, | |
| 31 | pad_to: ?u64, | |
| 32 | ||
| 33 | pub 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 | ||
| 40 | pub 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 | ||
| 66 | pub fn getOutputSource(self: *const ObjCopyStep) std.Build.FileSource { | |
| 67 | return .{ .generated = &self.output_file }; | |
| 68 | } | |
| 69 | ||
| 70 | fn 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) | |
| 127 | fn 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 | ||
| 135 | fn 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 | 21 | check_file, |
| 22 | 22 | check_object, |
| 23 | 23 | config_header, |
| 24 | install_raw, | |
| 24 | objcopy, | |
| 25 | 25 | options, |
| 26 | 26 | custom, |
| 27 | 27 | |
| ... | ... | @@ -42,7 +42,7 @@ pub const Id = enum { |
| 42 | 42 | .check_file => Build.CheckFileStep, |
| 43 | 43 | .check_object => Build.CheckObjectStep, |
| 44 | 44 | .config_header => Build.ConfigHeaderStep, |
| 45 | .install_raw => Build.InstallRawStep, | |
| 45 | .objcopy => Build.ObjCopyStep, | |
| 46 | 46 | .options => Build.OptionsStep, |
| 47 | 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 | 3 | const CheckFileStep = std.Build.CheckFileStep; |
| 4 | 4 | |
| 5 | 5 | pub 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 | 9 | const target = .{ |
| 7 | 10 | .cpu_arch = .thumb, |
| 8 | 11 | .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 }, |
| ... | ... | @@ -19,12 +22,14 @@ pub fn build(b: *std.Build) void { |
| 19 | 22 | .optimize = optimize, |
| 20 | 23 | }); |
| 21 | 24 | |
| 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 | }); | |
| 26 | 28 | test_step.dependOn(&hex_step.step); |
| 27 | 29 | |
| 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 | 34 | test_step.dependOn(&explicit_format_hex_step.step); |
| 30 | 35 | } |