Skip to content

Commit c21ee00

Browse files
committed
Add preliminary support for Windows .manifest files
An embedded manifest file is really just XML data embedded as a RT_MANIFEST resource (ID = 24). Typically, the Windows-only 'Manifest Tool' (`mt.exe`) is used to embed manifest files, and `mt.exe` also seems to perform some transformation of the manifest data before embedding, but in testing it doesn't seem like the transformations are necessary to get the intended result. So, to handle embedding manifest files, Zig now takes the following approach: - Generate a .rc file with the contents `1 24 "path-to-manifest.manifest"` - Compile that generated .rc file into a .res file - Link the .res file into the final binary This effectively achieves the same thing as `mt.exe` minus the validation/transformations of the XML data that it performs. How this is used: On the command line: ``` zig build-exe main.zig main.manifest ``` (on the command line, specifying a .manifest file when the target object format is not COFF is an error) or in build.zig: ``` const exe = b.addExecutable(.{ .name = "manifest-test", .root_source_file = .{ .path = "main.zig" }, .target = target, .optimize = optimize, }); exe.addWin32ManifestFile(.{ .path = "main.manifest" }); ``` (in build.zig, the manifest file is ignored if the target object format is not COFF) Note: Currently, only one manifest file can be specified per compilation. This is because the ID of the manifest resource is currently always 1. Specifying multiple manifests could be supported if a way for the user to specify an ID for each manifest is added (manifest IDs must be a u16). Closes #17406
1 parent 4df7f7c commit c21ee00

File tree

3 files changed

+207
-32
lines changed

3 files changed

+207
-32
lines changed

lib/std/Build/Step/Compile.zig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ pub const LinkObject = union(enum) {
257257
c_source_file: *CSourceFile,
258258
c_source_files: *CSourceFiles,
259259
win32_resource_file: *RcSourceFile,
260+
win32_manifest_file: LazyPath,
260261
};
261262

262263
pub const SystemLib = struct {
@@ -952,6 +953,17 @@ pub fn addWin32ResourceFile(self: *Compile, source: RcSourceFile) void {
952953
source.file.addStepDependencies(&self.step);
953954
}
954955

956+
pub fn addWin32ManifestFile(self: *Compile, source: LazyPath) void {
957+
// Only the PE/COFF format has a Resource Table which is where the manifest
958+
// gets embedded, so for any other target the manifest file is just ignored.
959+
if (self.target.getObjectFormat() != .coff) return;
960+
961+
const b = self.step.owner;
962+
const source_duped = source.dupe(b);
963+
self.link_objects.append(.{ .win32_manifest_file = source_duped }) catch @panic("OOM");
964+
source.addStepDependencies(&self.step);
965+
}
966+
955967
pub fn setVerboseLink(self: *Compile, value: bool) void {
956968
self.verbose_link = value;
957969
}
@@ -1567,6 +1579,10 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
15671579
}
15681580
try zig_args.append(rc_source_file.file.getPath(b));
15691581
},
1582+
1583+
.win32_manifest_file => |manifest_file| {
1584+
try zig_args.append(manifest_file.getPath(b));
1585+
},
15701586
}
15711587
}
15721588

0 commit comments

Comments
 (0)