diff --git a/README.md b/README.md index cc86bf6..925bec5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,9 @@ Turns your ELFs into DOLphins using the power of Zig (and CPU cycles). ## Usage -`elphin input.elf output.dol` +Binary: `elphin input.elf output.dol` + +You can embed elphin as part of a Zig build pipeline by following the example in `example-ci` ## License diff --git a/build.zig b/build.zig index 0957764..0532729 100644 --- a/build.zig +++ b/build.zig @@ -46,4 +46,4 @@ pub fn addModule(b: *std.Build) void { }); } -pub usingnamespace @import("src/lib.zig"); +pub const buildlib = @import("src/buildlib.zig"); diff --git a/example-ci/build.zig b/example-ci/build.zig new file mode 100644 index 0000000..05e082a --- /dev/null +++ b/example-ci/build.zig @@ -0,0 +1,11 @@ +const std = @import("std"); +const elphin = @import("elphin"); + +pub fn build(b: *std.Build) void { + const file = b.addInstallBinFile(.{ .path = "../testdata/example.elf" }, "lol.elf"); + + const convert = elphin.buildlib.convertFile(b, "lol.elf", .{}); + + b.getInstallStep().dependOn(&file.step); + b.getInstallStep().dependOn(&convert.step); +} diff --git a/example-ci/build.zig.zon b/example-ci/build.zig.zon new file mode 100644 index 0000000..5e52098 --- /dev/null +++ b/example-ci/build.zig.zon @@ -0,0 +1,12 @@ +.{ + .name = "example-ci", + .version = "0.0.0", + + .dependencies = .{ + .elphin = .{ .path = ".." }, + }, + + .paths = .{ + "", + }, +} diff --git a/src/buildlib.zig b/src/buildlib.zig new file mode 100644 index 0000000..41fa2be --- /dev/null +++ b/src/buildlib.zig @@ -0,0 +1,63 @@ +const std = @import("std"); +const lib = @import("lib.zig"); + +const Self = @This(); + +const ConvertFileOptions = struct { + installDir: std.Build.InstallDir = .bin, + filename: ?[]const u8 = null, +}; + +step: std.Build.Step, +path: []const u8, +options: ConvertFileOptions, + +pub fn convertFile(b: *std.Build, file: []const u8, options: ConvertFileOptions) *Self { + const convert = b.step("convert", "Converts the compiled .elf file into .dol"); + + const self = b.allocator.create(Self) catch @panic("OOM"); + self.* = .{ + .step = std.Build.Step.init(.{ + .id = .custom, + .name = b.fmt("Convert to DOL", .{}), + .owner = b, + .makeFn = make, + }), + .path = file, + .options = options, + }; + + convert.dependOn(&self.step); + + return self; +} + +fn make(step: *std.Build.Step, _: *std.Progress.Node) !void { + const self: *Self = @fieldParentPtr("step", step); + const b = step.owner; + + // Get input path + const inputPath = b.getInstallPath(self.options.installDir, self.path); + + // Read input + const input = try std.fs.cwd().openFile(inputPath, .{}); + defer input.close(); + + // Get output path or calculate it from the input + const destination = if (self.options.filename) |name| + b.getInstallPath(self.options.installDir, name) + else + calculateOutputName(b, inputPath); + + // Create output file + const output = try std.fs.cwd().createFile(destination, .{}); + defer output.close(); + + try lib.convert(input, output); +} + +fn calculateOutputName(b: *std.Build, path: []const u8) []const u8 { + const extIndex = std.mem.lastIndexOfScalar(u8, path, '.'); + const filenameWithoutExtension = if (extIndex) |index| path[0..index] else path; + return b.fmt("{s}.dol", .{filenameWithoutExtension}); +}