Skip to content

Commit 6036cd4

Browse files
author
Felix "xq" Queißner
committed
Starts to implement build.zig interface
1 parent d4d5516 commit 6036cd4

File tree

6 files changed

+311
-7
lines changed

6 files changed

+311
-7
lines changed

build.zig

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const std = @import("std");
2-
const builtin = @import("builtin");
2+
3+
pub const BuildInterface = @import("src/BuildInterface.zig");
34

45
pub fn build(b: *std.Build) void {
56
const target = b.standardTargetOptions(.{});
@@ -34,7 +35,7 @@ pub fn build(b: *std.Build) void {
3435
dim_mod.addImport("zfat", zfat_mod);
3536

3637
const dim_exe = b.addExecutable(.{
37-
.name = "dim",
38+
.name = "dimmer",
3839
.root_module = dim_mod,
3940
});
4041
b.installArtifact(dim_exe);

build.zig.zon

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
.{
2-
.name = .disk_image_step,
2+
.name = .dimmer,
33
.version = "2.0.0",
4-
.fingerprint = 0xdaabde74a06664f7,
4+
.fingerprint = 0x9947018c924eecb2,
55
.dependencies = .{
66
.zfat = .{
77
.url = "https://github.com/ZigEmbeddedGroup/zfat/archive/3ce06d43a4e04d387034dcae2f486b050701f321.tar.gz",

justfile

+8-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ default: install test
88
install:
99
{{zig}} build install
1010

11-
test: unit-test behaviour-tests
11+
test: unit-test behaviour-tests build-test
1212

1313
unit-test:
1414
{{zig}} build test
@@ -29,10 +29,15 @@ behaviour-tests: \
2929

3030
behaviour-test script: install
3131
@mkdir -p {{ join(out, parent_directory(script)) }}
32-
./zig-out/bin/dim --output {{ join(out, without_extension(script) + ".img") }} --script "{{script}}" --size 33M
33-
./zig-out/bin/dim --output {{ join(out, without_extension(script) + ".img") }} --deps-file {{ join(out, without_extension(script) + ".d") }} --script "{{script}}" --size 33M
32+
./zig-out/bin/dimmer --output {{ join(out, without_extension(script) + ".img") }} --script "{{script}}" --size 33M
33+
./zig-out/bin/dimmer --output {{ join(out, without_extension(script) + ".img") }} --deps-file {{ join(out, without_extension(script) + ".d") }} --script "{{script}}" --size 33M
3434

3535
# TODO(fqu): sfdisk --json .dim-out/tests/part/mbr/basic-single-part-unsized.img
3636

37+
38+
[working-directory: 'tests/zig-build-interface']
39+
build-test:
40+
{{zig}} build
41+
3742
fuzz:
3843
{{zig}} build install test --fuzz --port 35991

src/BuildInterface.zig

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
//!
2+
//! This file implements the Zig build system interface for Dimmer.
3+
//!
4+
//! It is included by it's build.zig
5+
//!
6+
const std = @import("std");
7+
8+
const Interface = @This();
9+
10+
builder: *std.Build,
11+
dimmer_exe: *std.Build.Step.Compile,
12+
13+
pub fn init(builder: *std.Build, dep: *std.Build.Dependency) Interface {
14+
return .{
15+
.builder = builder,
16+
.dimmer_exe = dep.artifact("dimmer"),
17+
};
18+
}
19+
20+
pub fn createDisk(dimmer: Interface, size: u64, content: Content) std.Build.LazyPath {
21+
const b = dimmer.builder;
22+
23+
const write_files = b.addWriteFiles();
24+
25+
const script_source, const variables = renderContent(write_files, b.allocator, content);
26+
27+
const script_file = write_files.add("image.dis", script_source);
28+
29+
const compile_script = b.addRunArtifact(dimmer.dimmer_exe);
30+
31+
_ = compile_script.addPrefixedDepFileOutputArg("--deps-file=", "image.d");
32+
33+
compile_script.addArg(b.fmt("--size={d}", .{size}));
34+
35+
compile_script.addPrefixedFileArg("--script=", script_file);
36+
37+
const result_file = compile_script.addPrefixedOutputFileArg("--output=", "disk.img");
38+
39+
{
40+
var iter = variables.iterator();
41+
while (iter.next()) |kvp| {
42+
const key = kvp.key_ptr.*;
43+
const value = kvp.value_ptr.*;
44+
45+
compile_script.addPrefixedFileArg(
46+
b.fmt("{s}=", .{key}),
47+
value,
48+
);
49+
}
50+
}
51+
52+
return result_file;
53+
}
54+
55+
fn renderContent(wfs: *std.Build.Step.WriteFile, allocator: std.mem.Allocator, content: Content) struct { []const u8, std.StringHashMap(std.Build.LazyPath) } {
56+
var code: std.ArrayList(u8) = .init(allocator);
57+
defer code.deinit();
58+
59+
var variables: std.StringHashMap(std.Build.LazyPath) = .init(allocator);
60+
61+
renderContentInner(
62+
wfs,
63+
code.writer(),
64+
&variables,
65+
content,
66+
) catch @panic("out of memory");
67+
68+
const source = std.mem.trim(
69+
u8,
70+
code.toOwnedSlice() catch @panic("out of memory"),
71+
" \r\n\t",
72+
);
73+
74+
return .{ source, variables };
75+
}
76+
77+
fn renderContentInner(
78+
wfs: *std.Build.Step.WriteFile,
79+
code: std.ArrayList(u8).Writer,
80+
vars: *std.StringHashMap(std.Build.LazyPath),
81+
content: Content,
82+
) !void {
83+
// Always insert some padding before and after:
84+
try code.writeAll(" ");
85+
errdefer code.writeAll(" ") catch {};
86+
87+
switch (content) {
88+
.empty => {
89+
try code.writeAll("empty");
90+
},
91+
92+
.fill => |data| {
93+
try code.print("fill 0x{X:0>2}", .{data});
94+
},
95+
96+
.paste_file => |data| {
97+
try code.writeAll("paste-file ");
98+
try renderLazyPath(wfs, code, vars, data);
99+
},
100+
101+
.mbr_part_table => |data| {
102+
_ = data;
103+
@panic("not supported yet!");
104+
},
105+
.vfat => |data| {
106+
_ = data;
107+
@panic("not supported yet!");
108+
},
109+
}
110+
}
111+
112+
fn renderLazyPath(
113+
wfs: *std.Build.Step.WriteFile,
114+
code: std.ArrayList(u8).Writer,
115+
vars: *std.StringHashMap(std.Build.LazyPath),
116+
path: std.Build.LazyPath,
117+
) !void {
118+
switch (path) {
119+
.cwd_relative,
120+
.dependency,
121+
.src_path,
122+
=> {
123+
// We can safely call getPath2 as we can fully resolve the path
124+
// already
125+
const full_path = path.getPath2(wfs.step.owner, &wfs.step);
126+
127+
std.debug.assert(std.fs.path.isAbsolute(full_path));
128+
129+
try code.writeAll(full_path);
130+
},
131+
132+
.generated => {
133+
// this means we can't emit the variable just verbatim, but we
134+
// actually have a build-time dependency
135+
const var_id = vars.count() + 1;
136+
const var_name = wfs.step.owner.fmt("PATH{}", .{var_id});
137+
138+
try vars.put(var_name, path);
139+
140+
try code.print("${s}", .{var_name});
141+
},
142+
}
143+
}
144+
145+
pub const Content = union(enum) {
146+
empty,
147+
fill: u8,
148+
paste_file: std.Build.LazyPath,
149+
mbr_part_table: MbrPartTable,
150+
vfat: FatFs,
151+
};
152+
153+
pub const MbrPartTable = struct {
154+
//
155+
};
156+
157+
pub const FatFs = struct {
158+
//
159+
};

tests/zig-build-interface/build.zig

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
const std = @import("std");
2+
const Dimmer = @import("dimmer").BuildInterface;
3+
4+
pub const KiB = 1024;
5+
pub const MiB = 1024 * KiB;
6+
pub const GiB = 1024 * MiB;
7+
8+
pub fn build(b: *std.Build) void {
9+
const dimmer_dep = b.dependency("dimmer", .{});
10+
11+
const dimmer: Dimmer = .init(b, dimmer_dep);
12+
13+
const install_step = b.getInstallStep();
14+
15+
installDebugDisk(dimmer, install_step, "empty.img", 50 * KiB, .empty);
16+
installDebugDisk(dimmer, install_step, "fill-0x00.img", 50 * KiB, .{ .fill = 0x00 });
17+
installDebugDisk(dimmer, install_step, "fill-0xAA.img", 50 * KiB, .{ .fill = 0xAA });
18+
installDebugDisk(dimmer, install_step, "fill-0xFF.img", 50 * KiB, .{ .fill = 0xFF });
19+
installDebugDisk(dimmer, install_step, "paste-file.img", 50 * KiB, .{ .paste_file = b.path("build.zig.zon") });
20+
21+
// installDebugDisk(dimmer, install_step, "empty-mbr.img", 50 * MiB, .{
22+
// .mbr_part_table = .{
23+
// .partitions = .{
24+
// null,
25+
// null,
26+
// null,
27+
// null,
28+
// },
29+
// },
30+
// });
31+
32+
// installDebugDisk(dimmer, install_step, "manual-offset-mbr.img", 50 * MiB, .{
33+
// .mbr_part_table = .{
34+
// .partitions = .{
35+
// &.{ .offset = 2048 + 0 * 10 * MiB, .size = 10 * MiB, .bootable = true, .type = .fat32_lba, .data = .empty },
36+
// &.{ .offset = 2048 + 1 * 10 * MiB, .size = 10 * MiB, .bootable = false, .type = .ntfs, .data = .empty },
37+
// &.{ .offset = 2048 + 2 * 10 * MiB, .size = 10 * MiB, .bootable = false, .type = .linux_swap, .data = .empty },
38+
// &.{ .offset = 2048 + 3 * 10 * MiB, .size = 10 * MiB, .bootable = false, .type = .linux_fs, .data = .empty },
39+
// },
40+
// },
41+
// });
42+
43+
// installDebugDisk(dimmer, install_step, "auto-offset-mbr.img", 50 * MiB, .{
44+
// .mbr_part_table = .{
45+
// .partitions = .{
46+
// &.{ .size = 7 * MiB, .bootable = true, .type = .fat32_lba, .data = .empty },
47+
// &.{ .size = 8 * MiB, .bootable = false, .type = .ntfs, .data = .empty },
48+
// &.{ .size = 9 * MiB, .bootable = false, .type = .linux_swap, .data = .empty },
49+
// &.{ .size = 10 * MiB, .bootable = false, .type = .linux_fs, .data = .empty },
50+
// },
51+
// },
52+
// });
53+
54+
// installDebugDisk(dimmer, install_step, "empty-fat32.img", 50 * MiB, .{
55+
// .vfat = .{
56+
// .format = .fat32,
57+
// .label = "EMPTY",
58+
// .items = &.{},
59+
// },
60+
// });
61+
62+
// installDebugDisk(dimmer, install_step, "initialized-fat32.img", 50 * MiB, .{
63+
// .vfat = .{
64+
// .format = .fat32,
65+
// .label = "ROOTFS",
66+
// .items = &.{
67+
// .{ .empty_dir = "boot/EFI/refind/icons" },
68+
// .{ .empty_dir = "/boot/EFI/nixos/.extra-files/" },
69+
// .{ .empty_dir = "Users/xq/" },
70+
// .{ .copy_dir = .{ .source = b.path("dummy/Windows"), .destination = "Windows" } },
71+
// .{ .copy_file = .{ .source = b.path("dummy/README.md"), .destination = "Users/xq/README.md" } },
72+
// },
73+
// },
74+
// });
75+
76+
// installDebugDisk(dimmer, install_step, "initialized-fat32-in-mbr-partitions.img", 100 * MiB, .{
77+
// .mbr = .{
78+
// .partitions = .{
79+
// &.{
80+
// .size = 90 * MiB,
81+
// .bootable = true,
82+
// .type = .fat32_lba,
83+
// .data = .{
84+
// .vfat = .{
85+
// .format = .fat32,
86+
// .label = "ROOTFS",
87+
// .items = &.{
88+
// .{ .empty_dir = "boot/EFI/refind/icons" },
89+
// .{ .empty_dir = "/boot/EFI/nixos/.extra-files/" },
90+
// .{ .empty_dir = "Users/xq/" },
91+
// .{ .copy_dir = .{ .source = b.path("dummy/Windows"), .destination = "Windows" } },
92+
// .{ .copy_file = .{ .source = b.path("dummy/README.md"), .destination = "Users/xq/README.md" } },
93+
// },
94+
// },
95+
// },
96+
// },
97+
// null,
98+
// null,
99+
// null,
100+
// },
101+
// },
102+
// });
103+
104+
// TODO: Implement GPT partition support
105+
// installDebugDisk(debug_step, "empty-gpt.img", 50 * MiB, .{
106+
// .gpt = .{
107+
// .partitions = &.{},
108+
// },
109+
// });
110+
}
111+
112+
fn installDebugDisk(
113+
dimmer: Dimmer,
114+
install_step: *std.Build.Step,
115+
name: []const u8,
116+
size: u64,
117+
content: Dimmer.Content,
118+
) void {
119+
const disk_file = dimmer.createDisk(size, content);
120+
121+
const install_disk = install_step.owner.addInstallFile(
122+
disk_file,
123+
name,
124+
);
125+
install_step.dependOn(&install_disk.step);
126+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.{
2+
.name = .dimmer_usage_demo,
3+
.fingerprint = 0x6a630b1cfa8384c,
4+
.version = "1.0.0",
5+
.dependencies = .{
6+
.dimmer = .{
7+
.path = "../..",
8+
},
9+
},
10+
.paths = .{
11+
".",
12+
},
13+
}

0 commit comments

Comments
 (0)