authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-04 16:14:43-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-05 03:25:43-05:00
log11cc1c16fa36a7eb13cba1c43fb153ee6aca7b58
tree5c1ee30f000c278394a00f674aab25c0fff1c0c0
parentd4ce0fe7fea14bae889e03464980e5eca7a2ed1f

make `@embedFile` support module-mapped names the same way as `@import`

closes #14553

5 files changed, 78 insertions(+), 14 deletions(-)

src/Module.zig+40-14
...@@ -4865,14 +4865,31 @@ pub fn importFile(...@@ -4865,14 +4865,31 @@ pub fn importFile(
4865 };4865 };
4866}4866}
48674867
4868pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*EmbedFile {4868pub fn embedFile(mod: *Module, cur_file: *File, import_string: []const u8) !*EmbedFile {
4869 const gpa = mod.gpa;4869 const gpa = mod.gpa;
48704870
4871 // The resolved path is used as the key in the table, to detect if4871 if (cur_file.pkg.table.get(import_string)) |pkg| {
4872 // a file refers to the same as another, despite different relative paths.4872 const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
4873 pkg.root_src_directory.path orelse ".", pkg.root_src_path,
4874 });
4875 var keep_resolved_path = false;
4876 defer if (!keep_resolved_path) gpa.free(resolved_path);
4877
4878 const gop = try mod.embed_table.getOrPut(gpa, resolved_path);
4879 errdefer assert(mod.embed_table.remove(resolved_path));
4880 if (gop.found_existing) return gop.value_ptr.*;
4881
4882 const sub_file_path = try gpa.dupe(u8, pkg.root_src_path);
4883 errdefer gpa.free(sub_file_path);
4884
4885 return newEmbedFile(mod, pkg, sub_file_path, resolved_path, &keep_resolved_path, gop);
4886 }
4887
4888 // The resolved path is used as the key in the table, to detect if a file
4889 // refers to the same as another, despite different relative paths.
4873 const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse ".";4890 const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse ".";
4874 const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{4891 const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
4875 cur_pkg_dir_path, cur_file.sub_file_path, "..", rel_file_path,4892 cur_pkg_dir_path, cur_file.sub_file_path, "..", import_string,
4876 });4893 });
4877 var keep_resolved_path = false;4894 var keep_resolved_path = false;
4878 defer if (!keep_resolved_path) gpa.free(resolved_path);4895 defer if (!keep_resolved_path) gpa.free(resolved_path);
...@@ -4881,9 +4898,6 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb...@@ -4881,9 +4898,6 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb
4881 errdefer assert(mod.embed_table.remove(resolved_path));4898 errdefer assert(mod.embed_table.remove(resolved_path));
4882 if (gop.found_existing) return gop.value_ptr.*;4899 if (gop.found_existing) return gop.value_ptr.*;
48834900
4884 const new_file = try gpa.create(EmbedFile);
4885 errdefer gpa.destroy(new_file);
4886
4887 const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path});4901 const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path});
4888 defer gpa.free(resolved_root_path);4902 defer gpa.free(resolved_root_path);
48894903
...@@ -4902,7 +4916,23 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb...@@ -4902,7 +4916,23 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb
4902 };4916 };
4903 errdefer gpa.free(sub_file_path);4917 errdefer gpa.free(sub_file_path);
49044918
4905 var file = try cur_file.pkg.root_src_directory.handle.openFile(sub_file_path, .{});4919 return newEmbedFile(mod, cur_file.pkg, sub_file_path, resolved_path, &keep_resolved_path, gop);
4920}
4921
4922fn newEmbedFile(
4923 mod: *Module,
4924 pkg: *Package,
4925 sub_file_path: []const u8,
4926 resolved_path: []const u8,
4927 keep_resolved_path: *bool,
4928 gop: std.StringHashMapUnmanaged(*EmbedFile).GetOrPutResult,
4929) !*EmbedFile {
4930 const gpa = mod.gpa;
4931
4932 const new_file = try gpa.create(EmbedFile);
4933 errdefer gpa.destroy(new_file);
4934
4935 var file = try pkg.root_src_directory.handle.openFile(sub_file_path, .{});
4906 defer file.close();4936 defer file.close();
49074937
4908 const actual_stat = try file.stat();4938 const actual_stat = try file.stat();
...@@ -4915,10 +4945,6 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb...@@ -4915,10 +4945,6 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb
4915 const bytes = try file.readToEndAllocOptions(gpa, std.math.maxInt(u32), size_usize, 1, 0);4945 const bytes = try file.readToEndAllocOptions(gpa, std.math.maxInt(u32), size_usize, 1, 0);
4916 errdefer gpa.free(bytes);4946 errdefer gpa.free(bytes);
49174947
4918 log.debug("new embedFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, rel_file_path={s}", .{
4919 resolved_root_path, resolved_path, sub_file_path, rel_file_path,
4920 });
4921
4922 if (mod.comp.whole_cache_manifest) |whole_cache_manifest| {4948 if (mod.comp.whole_cache_manifest) |whole_cache_manifest| {
4923 const copied_resolved_path = try gpa.dupe(u8, resolved_path);4949 const copied_resolved_path = try gpa.dupe(u8, resolved_path);
4924 errdefer gpa.free(copied_resolved_path);4950 errdefer gpa.free(copied_resolved_path);
...@@ -4927,13 +4953,13 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb...@@ -4927,13 +4953,13 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb
4927 try whole_cache_manifest.addFilePostContents(copied_resolved_path, bytes, stat);4953 try whole_cache_manifest.addFilePostContents(copied_resolved_path, bytes, stat);
4928 }4954 }
49294955
4930 keep_resolved_path = true; // It's now owned by embed_table.4956 keep_resolved_path.* = true; // It's now owned by embed_table.
4931 gop.value_ptr.* = new_file;4957 gop.value_ptr.* = new_file;
4932 new_file.* = .{4958 new_file.* = .{
4933 .sub_file_path = sub_file_path,4959 .sub_file_path = sub_file_path,
4934 .bytes = bytes,4960 .bytes = bytes,
4935 .stat = stat,4961 .stat = stat,
4936 .pkg = cur_file.pkg,4962 .pkg = pkg,
4937 .owner_decl = undefined, // Set by Sema immediately after this function returns.4963 .owner_decl = undefined, // Set by Sema immediately after this function returns.
4938 };4964 };
4939 return new_file;4965 return new_file;
test/standalone.zig+1
...@@ -102,4 +102,5 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -102,4 +102,5 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
102 cases.addBuildFile("test/standalone/issue_13030/build.zig", .{ .build_modes = true });102 cases.addBuildFile("test/standalone/issue_13030/build.zig", .{ .build_modes = true });
103 cases.addBuildFile("test/standalone/emit_asm_and_bin/build.zig", .{});103 cases.addBuildFile("test/standalone/emit_asm_and_bin/build.zig", .{});
104 cases.addBuildFile("test/standalone/issue_12588/build.zig", .{});104 cases.addBuildFile("test/standalone/issue_12588/build.zig", .{});
105 cases.addBuildFile("test/standalone/embed_generated_file/build.zig", .{});
105}106}
test/standalone/embed_generated_file/bootloader.zig created+1
...@@ -0,0 +1 @@
1pub export fn _start() void {}
test/standalone/embed_generated_file/build.zig created+28
...@@ -0,0 +1,28 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const target = b.standardTargetOptions(.{});
5 const optimize = b.standardOptimizeOption(.{});
6
7 const bootloader = b.addExecutable(.{
8 .name = "bootloader",
9 .root_source_file = .{ .path = "bootloader.zig" },
10 .target = .{
11 .cpu_arch = .x86,
12 .os_tag = .freestanding,
13 },
14 .optimize = .ReleaseSmall,
15 });
16
17 const exe = b.addTest(.{
18 .root_source_file = .{ .path = "main.zig" },
19 .target = target,
20 .optimize = optimize,
21 });
22 exe.addAnonymousModule("bootloader.elf", .{
23 .source_file = bootloader.getOutputSource(),
24 });
25
26 const test_step = b.step("test", "Test the program");
27 test_step.dependOn(&exe.step);
28}
test/standalone/embed_generated_file/main.zig created+8
...@@ -0,0 +1,8 @@
1const std = @import("std");
2const blah = @embedFile("bootloader.elf");
3
4test {
5 comptime {
6 std.debug.assert(std.mem.eql(u8, blah[1..][0..3], "ELF"));
7 }
8}