Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 40 additions & 14 deletions src/Module.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4865,14 +4865,31 @@ pub fn importFile(
};
}

pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*EmbedFile {
pub fn embedFile(mod: *Module, cur_file: *File, import_string: []const u8) !*EmbedFile {
const gpa = mod.gpa;

// The resolved path is used as the key in the table, to detect if
// a file refers to the same as another, despite different relative paths.
if (cur_file.pkg.table.get(import_string)) |pkg| {
const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
pkg.root_src_directory.path orelse ".", pkg.root_src_path,
});
var keep_resolved_path = false;
defer if (!keep_resolved_path) gpa.free(resolved_path);

const gop = try mod.embed_table.getOrPut(gpa, resolved_path);
errdefer assert(mod.embed_table.remove(resolved_path));
if (gop.found_existing) return gop.value_ptr.*;

const sub_file_path = try gpa.dupe(u8, pkg.root_src_path);
errdefer gpa.free(sub_file_path);

return newEmbedFile(mod, pkg, sub_file_path, resolved_path, &keep_resolved_path, gop);
}

// The resolved path is used as the key in the table, to detect if a file
// refers to the same as another, despite different relative paths.
const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse ".";
const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
cur_pkg_dir_path, cur_file.sub_file_path, "..", rel_file_path,
cur_pkg_dir_path, cur_file.sub_file_path, "..", import_string,
});
var keep_resolved_path = false;
defer if (!keep_resolved_path) gpa.free(resolved_path);
Expand All @@ -4881,9 +4898,6 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb
errdefer assert(mod.embed_table.remove(resolved_path));
if (gop.found_existing) return gop.value_ptr.*;

const new_file = try gpa.create(EmbedFile);
errdefer gpa.destroy(new_file);

const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path});
defer gpa.free(resolved_root_path);

Expand All @@ -4902,7 +4916,23 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb
};
errdefer gpa.free(sub_file_path);

var file = try cur_file.pkg.root_src_directory.handle.openFile(sub_file_path, .{});
return newEmbedFile(mod, cur_file.pkg, sub_file_path, resolved_path, &keep_resolved_path, gop);
}

fn newEmbedFile(
mod: *Module,
pkg: *Package,
sub_file_path: []const u8,
resolved_path: []const u8,
keep_resolved_path: *bool,
gop: std.StringHashMapUnmanaged(*EmbedFile).GetOrPutResult,
) !*EmbedFile {
const gpa = mod.gpa;

const new_file = try gpa.create(EmbedFile);
errdefer gpa.destroy(new_file);

var file = try pkg.root_src_directory.handle.openFile(sub_file_path, .{});
defer file.close();

const actual_stat = try file.stat();
Expand All @@ -4915,10 +4945,6 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb
const bytes = try file.readToEndAllocOptions(gpa, std.math.maxInt(u32), size_usize, 1, 0);
errdefer gpa.free(bytes);

log.debug("new embedFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, rel_file_path={s}", .{
resolved_root_path, resolved_path, sub_file_path, rel_file_path,
});

if (mod.comp.whole_cache_manifest) |whole_cache_manifest| {
const copied_resolved_path = try gpa.dupe(u8, resolved_path);
errdefer gpa.free(copied_resolved_path);
Expand All @@ -4927,13 +4953,13 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb
try whole_cache_manifest.addFilePostContents(copied_resolved_path, bytes, stat);
}

keep_resolved_path = true; // It's now owned by embed_table.
keep_resolved_path.* = true; // It's now owned by embed_table.
gop.value_ptr.* = new_file;
new_file.* = .{
.sub_file_path = sub_file_path,
.bytes = bytes,
.stat = stat,
.pkg = cur_file.pkg,
.pkg = pkg,
.owner_decl = undefined, // Set by Sema immediately after this function returns.
};
return new_file;
Expand Down
1 change: 1 addition & 0 deletions test/standalone.zig
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,5 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
cases.addBuildFile("test/standalone/issue_13030/build.zig", .{ .build_modes = true });
cases.addBuildFile("test/standalone/emit_asm_and_bin/build.zig", .{});
cases.addBuildFile("test/standalone/issue_12588/build.zig", .{});
cases.addBuildFile("test/standalone/embed_generated_file/build.zig", .{});
}
1 change: 1 addition & 0 deletions test/standalone/embed_generated_file/bootloader.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub export fn _start() void {}
28 changes: 28 additions & 0 deletions test/standalone/embed_generated_file/build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const std = @import("std");

pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

const bootloader = b.addExecutable(.{
.name = "bootloader",
.root_source_file = .{ .path = "bootloader.zig" },
.target = .{
.cpu_arch = .x86,
.os_tag = .freestanding,
},
.optimize = .ReleaseSmall,
});

const exe = b.addTest(.{
.root_source_file = .{ .path = "main.zig" },
.target = target,
.optimize = optimize,
});
exe.addAnonymousModule("bootloader.elf", .{
.source_file = bootloader.getOutputSource(),
});

const test_step = b.step("test", "Test the program");
test_step.dependOn(&exe.step);
}
8 changes: 8 additions & 0 deletions test/standalone/embed_generated_file/main.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const std = @import("std");
const blah = @embedFile("bootloader.elf");

test {
comptime {
std.debug.assert(std.mem.eql(u8, blah[1..][0..3], "ELF"));
}
}