Skip to content

Add a .rc -> .res compiler to the Zig compiler #17069

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Sep 22, 2023
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
65 changes: 65 additions & 0 deletions lib/std/Build/Step/Compile.zig
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ is_linking_libc: bool,
is_linking_libcpp: bool,
vcpkg_bin_path: ?[]const u8 = null,

// keep in sync with src/Compilation.zig:RcIncludes
/// Behavior of automatic detection of include directories when compiling .rc files.
/// any: Use MSVC if available, fall back to MinGW.
/// msvc: Use MSVC include paths (must be present on the system).
/// gnu: Use MinGW include paths (distributed with Zig).
/// none: Do not use any autodetected include paths.
rc_includes: enum { any, msvc, gnu, none } = .any,

installed_path: ?[]const u8,

/// Base address for an executable image.
Expand Down Expand Up @@ -221,13 +229,34 @@ pub const CSourceFile = struct {
}
};

pub const RcSourceFile = struct {
file: LazyPath,
/// Any option that rc.exe accepts will work here, with the exception of:
/// - `/fo`: The output filename is set by the build system
/// - Any MUI-related option
/// https://learn.microsoft.com/en-us/windows/win32/menurc/using-rc-the-rc-command-line-
///
/// Implicitly defined options:
/// /x (ignore the INCLUDE environment variable)
/// /D_DEBUG or /DNDEBUG depending on the optimization mode
flags: []const []const u8 = &.{},

pub fn dupe(self: RcSourceFile, b: *std.Build) RcSourceFile {
return .{
.file = self.file.dupe(b),
.flags = b.dupeStrings(self.flags),
};
}
};

pub const LinkObject = union(enum) {
static_path: LazyPath,
other_step: *Compile,
system_lib: SystemLib,
assembly_file: LazyPath,
c_source_file: *CSourceFile,
c_source_files: *CSourceFiles,
win32_resource_file: *RcSourceFile,
};

pub const SystemLib = struct {
Expand Down Expand Up @@ -910,6 +939,18 @@ pub fn addCSourceFile(self: *Compile, source: CSourceFile) void {
source.file.addStepDependencies(&self.step);
}

pub fn addWin32ResourceFile(self: *Compile, source: RcSourceFile) void {
// Only the PE/COFF format has a Resource Table, so for any other target
// the resource file is just ignored.
if (self.target.getObjectFormat() != .coff) return;

const b = self.step.owner;
const rc_source_file = b.allocator.create(RcSourceFile) catch @panic("OOM");
rc_source_file.* = source.dupe(b);
self.link_objects.append(.{ .win32_resource_file = rc_source_file }) catch @panic("OOM");
source.file.addStepDependencies(&self.step);
}

pub fn setVerboseLink(self: *Compile, value: bool) void {
self.verbose_link = value;
}
Expand Down Expand Up @@ -1358,6 +1399,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
try transitive_deps.add(self.link_objects.items);

var prev_has_cflags = false;
var prev_has_rcflags = false;
var prev_search_strategy: SystemLib.SearchStrategy = .paths_first;
var prev_preferred_link_mode: std.builtin.LinkMode = .Dynamic;

Expand Down Expand Up @@ -1500,6 +1542,24 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
try zig_args.append(b.pathFromRoot(file));
}
},

.win32_resource_file => |rc_source_file| {
if (rc_source_file.flags.len == 0) {
if (prev_has_rcflags) {
try zig_args.append("-rcflags");
try zig_args.append("--");
prev_has_rcflags = false;
}
} else {
try zig_args.append("-rcflags");
for (rc_source_file.flags) |arg| {
try zig_args.append(arg);
}
try zig_args.append("--");
prev_has_rcflags = true;
}
try zig_args.append(rc_source_file.file.getPath(b));
},
}
}

Expand Down Expand Up @@ -1897,6 +1957,11 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
}
}

if (self.rc_includes != .any) {
try zig_args.append("-rcincludes");
try zig_args.append(@tagName(self.rc_includes));
}

try addFlag(&zig_args, "valgrind", self.valgrind_support);
try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath);

Expand Down
22 changes: 20 additions & 2 deletions lib/std/zig/ErrorBundle.zig
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ pub const Wip = struct {
_ = try addExtra(wip, rt);
}

pub fn addBundle(wip: *Wip, other: ErrorBundle) !void {
pub fn addBundleAsNotes(wip: *Wip, other: ErrorBundle) !void {
const gpa = wip.gpa;

try wip.string_bytes.ensureUnusedCapacity(gpa, other.string_bytes.len);
Expand All @@ -436,6 +436,21 @@ pub const Wip = struct {
}
}

pub fn addBundleAsRoots(wip: *Wip, other: ErrorBundle) !void {
const gpa = wip.gpa;

try wip.string_bytes.ensureUnusedCapacity(gpa, other.string_bytes.len);
try wip.extra.ensureUnusedCapacity(gpa, other.extra.len);

const other_list = other.getMessages();

try wip.root_list.ensureUnusedCapacity(gpa, other_list.len);
for (other_list) |other_msg| {
// The ensureUnusedCapacity calls above guarantees this.
wip.root_list.appendAssumeCapacity(wip.addOtherMessage(other, other_msg) catch unreachable);
}
}

pub fn reserveNotes(wip: *Wip, notes_len: u32) !u32 {
try wip.extra.ensureUnusedCapacity(wip.gpa, notes_len +
notes_len * @typeInfo(ErrorBundle.ErrorMessage).Struct.fields.len);
Expand Down Expand Up @@ -474,7 +489,10 @@ pub const Wip = struct {
.span_start = other_sl.span_start,
.span_main = other_sl.span_main,
.span_end = other_sl.span_end,
.source_line = try wip.addString(other.nullTerminatedString(other_sl.source_line)),
.source_line = if (other_sl.source_line != 0)
try wip.addString(other.nullTerminatedString(other_sl.source_line))
else
0,
.reference_trace_len = other_sl.reference_trace_len,
});

Expand Down
Loading