Commit 0168ed7bf1
Changed files (3)
lib
std
Build
Step
lib/std/Build/Step/Compile.zig
@@ -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.
@@ -1949,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);
src/Compilation.zig
@@ -243,6 +243,17 @@ pub const RcSourceFile = struct {
extra_flags: []const []const u8 = &.{},
};
+pub const RcIncludes = enum {
+ /// Use MSVC if available, fall back to MinGW.
+ any,
+ /// Use MSVC include paths (MSVC install + Windows SDK, must be present on the system).
+ msvc,
+ /// Use MinGW include paths (distributed with Zig).
+ gnu,
+ /// Do not use any autodetected include paths.
+ none,
+};
+
const Job = union(enum) {
/// Write the constant value for a Decl to the output file.
codegen_decl: Module.Decl.Index,
@@ -568,6 +579,7 @@ pub const InitOptions = struct {
symbol_wrap_set: std.StringArrayHashMapUnmanaged(void) = .{},
c_source_files: []const CSourceFile = &[0]CSourceFile{},
rc_source_files: []const RcSourceFile = &[0]RcSourceFile{},
+ rc_includes: RcIncludes = .any,
link_objects: []LinkObject = &[0]LinkObject{},
framework_dirs: []const []const u8 = &[0][]const u8{},
frameworks: []const Framework = &.{},
@@ -1001,16 +1013,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
options.libc_installation,
);
- const rc_dirs = try detectLibCIncludeDirs(
+ const rc_dirs = try detectWin32ResourceIncludeDirs(
arena,
- options.zig_lib_directory.path.?,
- options.target,
- options.is_native_abi,
- // Set "link libc" to true here whenever there are rc files to compile, since
- // the .rc preprocessor will need to know the libc include dirs even if we
- // are not linking libc
- options.rc_source_files.len > 0,
- options.libc_installation,
+ options,
);
const sysroot = options.sysroot orelse libc_dirs.sysroot;
@@ -2450,6 +2455,8 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
man.hash.addListOfBytes(key.src.extra_flags);
}
+ man.hash.addListOfBytes(comp.rc_include_dir_list);
+
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_asm);
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir);
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_bc);
@@ -5156,6 +5163,67 @@ fn failCObjWithOwnedErrorMsg(
return error.AnalysisFail;
}
+/// The include directories used when preprocessing .rc files are separate from the
+/// target. Which include directories are used is determined by `options.rc_includes`.
+///
+/// Note: It should be okay that the include directories used when compiling .rc
+/// files differ from the include directories used when compiling the main
+/// binary, since the .res format is not dependent on anything ABI-related. The
+/// only relevant differences would be things like `#define` constants being
+/// different in the MinGW headers vs the MSVC headers, but any such
+/// differences would likely be a MinGW bug.
+fn detectWin32ResourceIncludeDirs(arena: Allocator, options: InitOptions) !LibCDirs {
+ // Set the includes to .none here when there are no rc files to compile
+ var includes = if (options.rc_source_files.len > 0) options.rc_includes else .none;
+ if (builtin.target.os.tag != .windows) {
+ switch (includes) {
+ // MSVC can't be found when the host isn't Windows, so short-circuit.
+ .msvc => return error.WindowsSdkNotFound,
+ // Skip straight to gnu since we won't be able to detect MSVC on non-Windows hosts.
+ .any => includes = .gnu,
+ .none, .gnu => {},
+ }
+ }
+ while (true) {
+ switch (includes) {
+ .any, .msvc => return detectLibCIncludeDirs(
+ arena,
+ options.zig_lib_directory.path.?,
+ .{
+ .cpu = options.target.cpu,
+ .os = options.target.os,
+ .abi = .msvc,
+ .ofmt = options.target.ofmt,
+ },
+ options.is_native_abi,
+ // The .rc preprocessor will need to know the libc include dirs even if we
+ // are not linking libc, so force 'link_libc' to true
+ true,
+ options.libc_installation,
+ ) catch |err| {
+ if (includes == .any) {
+ // fall back to mingw
+ includes = .gnu;
+ continue;
+ }
+ return err;
+ },
+ .gnu => return detectLibCFromBuilding(arena, options.zig_lib_directory.path.?, .{
+ .cpu = options.target.cpu,
+ .os = options.target.os,
+ .abi = .gnu,
+ .ofmt = options.target.ofmt,
+ }),
+ .none => return LibCDirs{
+ .libc_include_dir_list = &[0][]u8{},
+ .libc_installation = null,
+ .libc_framework_dir_list = &.{},
+ .sysroot = null,
+ },
+ }
+ }
+}
+
fn failWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, comptime format: []const u8, args: anytype) SemaError {
@setCold(true);
var bundle: ErrorBundle.Wip = undefined;
src/main.zig
@@ -473,6 +473,11 @@ const usage_build_generic =
\\ --libc [file] Provide a file which specifies libc paths
\\ -cflags [flags] -- Set extra flags for the next positional C source files
\\ -rcflags [flags] -- Set extra flags for the next positional .rc source files
+ \\ -rcincludes=[type] Set the type of includes to use when compiling .rc source files
+ \\ any (default) Use msvc if available, fall back to gnu
+ \\ 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
\\
\\Link Options:
\\ -l[lib], --library [lib] Link against system library (only if actually used)
@@ -927,6 +932,7 @@ fn buildOutputType(
var symbol_wrap_set: std.StringArrayHashMapUnmanaged(void) = .{};
var c_source_files = std.ArrayList(Compilation.CSourceFile).init(arena);
var rc_source_files = std.ArrayList(Compilation.RcSourceFile).init(arena);
+ var rc_includes: Compilation.RcIncludes = .any;
var res_files = std.ArrayList(Compilation.LinkObject).init(arena);
var link_objects = std.ArrayList(Compilation.LinkObject).init(arena);
var framework_dirs = std.ArrayList([]const u8).init(arena);
@@ -1046,6 +1052,10 @@ fn buildOutputType(
if (mem.eql(u8, next_arg, "--")) break;
try extra_cflags.append(next_arg);
}
+ } else if (mem.eql(u8, arg, "-rcincludes")) {
+ rc_includes = parseRcIncludes(args_iter.nextOrFatal());
+ } else if (mem.startsWith(u8, arg, "-rcincludes=")) {
+ rc_includes = parseRcIncludes(arg["-rcincludes=".len..]);
} else if (mem.eql(u8, arg, "-rcflags")) {
extra_rcflags.shrinkRetainingCapacity(0);
while (true) {
@@ -3369,6 +3379,7 @@ fn buildOutputType(
.symbol_wrap_set = symbol_wrap_set,
.c_source_files = c_source_files.items,
.rc_source_files = rc_source_files.items,
+ .rc_includes = rc_includes,
.link_objects = link_objects.items,
.framework_dirs = framework_dirs.items,
.frameworks = resolved_frameworks.items,
@@ -6532,3 +6543,8 @@ fn accessFrameworkPath(
return false;
}
+
+fn parseRcIncludes(arg: []const u8) Compilation.RcIncludes {
+ return std.meta.stringToEnum(Compilation.RcIncludes, arg) orelse
+ fatal("unsupported rc includes type: '{s}'", .{arg});
+}