c4504e64ad
this fixes an issue where setting CC to `zig cc` could cause a recursive call and cause failures during linkage.
193 lines
7.2 KiB
Diff
193 lines
7.2 KiB
Diff
From 7c6f80f74395e546382c0400ef6db50c1b3e6439 Mon Sep 17 00:00:00 2001
|
|
From: Andrew Kelley <andrew@ziglang.org>
|
|
Date: Tue, 8 Jun 2021 12:48:48 -0700
|
|
Subject: [PATCH] native libc detection: respect spaces in CC env var
|
|
|
|
Zig has detection for when it is accidentally being called recursively
|
|
when trying to find the native libc installation. However it was not
|
|
working, resulting in a cryptic failure, because zig tried to execute
|
|
a command which had spaces in it rather than tokenizing it.
|
|
|
|
This improves the user experience of `zig cc` for systems that Zig
|
|
does not support cross-compiling for.
|
|
|
|
Closes #8960
|
|
|
|
Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
|
|
---
|
|
src/libc_installation.zig | 99 +++++++++++++++++++++++++++------------
|
|
1 file changed, 70 insertions(+), 29 deletions(-)
|
|
|
|
diff --git a/src/libc_installation.zig b/src/libc_installation.zig
|
|
index 2286b2c85..783f76b9b 100644
|
|
--- a/src/libc_installation.zig
|
|
+++ b/src/libc_installation.zig
|
|
@@ -237,26 +237,38 @@ pub const LibCInstallation = struct {
|
|
|
|
fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) FindError!void {
|
|
const allocator = args.allocator;
|
|
+
|
|
+ // Detect infinite loops.
|
|
+ var env_map = try std.process.getEnvMap(allocator);
|
|
+ defer env_map.deinit();
|
|
+ const skip_cc_env_var = if (env_map.get(inf_loop_env_key)) |phase| blk: {
|
|
+ if (std.mem.eql(u8, phase, "1")) {
|
|
+ try env_map.put(inf_loop_env_key, "2");
|
|
+ break :blk true;
|
|
+ } else {
|
|
+ return error.ZigIsTheCCompiler;
|
|
+ }
|
|
+ } else blk: {
|
|
+ try env_map.put(inf_loop_env_key, "1");
|
|
+ break :blk false;
|
|
+ };
|
|
+
|
|
const dev_null = if (is_windows) "nul" else "/dev/null";
|
|
- const cc_exe = std.os.getenvZ("CC") orelse default_cc_exe;
|
|
- const argv = [_][]const u8{
|
|
- cc_exe,
|
|
+
|
|
+ var argv = std.ArrayList([]const u8).init(allocator);
|
|
+ defer argv.deinit();
|
|
+
|
|
+ try appendCcExe(&argv, skip_cc_env_var);
|
|
+ try argv.appendSlice(&.{
|
|
"-E",
|
|
"-Wp,-v",
|
|
"-xc",
|
|
dev_null,
|
|
- };
|
|
- var env_map = try std.process.getEnvMap(allocator);
|
|
- defer env_map.deinit();
|
|
-
|
|
- // Detect infinite loops.
|
|
- const inf_loop_env_key = "ZIG_IS_DETECTING_LIBC_PATHS";
|
|
- if (env_map.get(inf_loop_env_key) != null) return error.ZigIsTheCCompiler;
|
|
- try env_map.put(inf_loop_env_key, "1");
|
|
+ });
|
|
|
|
const exec_res = std.ChildProcess.exec(.{
|
|
.allocator = allocator,
|
|
- .argv = &argv,
|
|
+ .argv = argv.items,
|
|
.max_output_bytes = 1024 * 1024,
|
|
.env_map = &env_map,
|
|
// Some C compilers, such as Clang, are known to rely on argv[0] to find the path
|
|
@@ -267,7 +279,7 @@ pub const LibCInstallation = struct {
|
|
}) catch |err| switch (err) {
|
|
error.OutOfMemory => return error.OutOfMemory,
|
|
else => {
|
|
- printVerboseInvocation(&argv, null, args.verbose, null);
|
|
+ printVerboseInvocation(argv.items, null, args.verbose, null);
|
|
return error.UnableToSpawnCCompiler;
|
|
},
|
|
};
|
|
@@ -277,11 +289,11 @@ pub const LibCInstallation = struct {
|
|
}
|
|
switch (exec_res.term) {
|
|
.Exited => |code| if (code != 0) {
|
|
- printVerboseInvocation(&argv, null, args.verbose, exec_res.stderr);
|
|
+ printVerboseInvocation(argv.items, null, args.verbose, exec_res.stderr);
|
|
return error.CCompilerExitCode;
|
|
},
|
|
else => {
|
|
- printVerboseInvocation(&argv, null, args.verbose, exec_res.stderr);
|
|
+ printVerboseInvocation(argv.items, null, args.verbose, exec_res.stderr);
|
|
return error.CCompilerCrashed;
|
|
},
|
|
}
|
|
@@ -540,8 +552,6 @@ pub const LibCInstallation = struct {
|
|
}
|
|
};
|
|
|
|
-const default_cc_exe = if (is_windows) "cc.exe" else "cc";
|
|
-
|
|
pub const CCPrintFileNameOptions = struct {
|
|
allocator: *Allocator,
|
|
search_basename: []const u8,
|
|
@@ -553,22 +563,33 @@ pub const CCPrintFileNameOptions = struct {
|
|
fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 {
|
|
const allocator = args.allocator;
|
|
|
|
- const cc_exe = std.os.getenvZ("CC") orelse default_cc_exe;
|
|
- const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={s}", .{args.search_basename});
|
|
- defer allocator.free(arg1);
|
|
- const argv = [_][]const u8{ cc_exe, arg1 };
|
|
-
|
|
+ // Detect infinite loops.
|
|
var env_map = try std.process.getEnvMap(allocator);
|
|
defer env_map.deinit();
|
|
+ const skip_cc_env_var = if (env_map.get(inf_loop_env_key)) |phase| blk: {
|
|
+ if (std.mem.eql(u8, phase, "1")) {
|
|
+ try env_map.put(inf_loop_env_key, "2");
|
|
+ break :blk true;
|
|
+ } else {
|
|
+ return error.ZigIsTheCCompiler;
|
|
+ }
|
|
+ } else blk: {
|
|
+ try env_map.put(inf_loop_env_key, "1");
|
|
+ break :blk false;
|
|
+ };
|
|
|
|
- // Detect infinite loops.
|
|
- const inf_loop_env_key = "ZIG_IS_DETECTING_LIBC_PATHS";
|
|
- if (env_map.get(inf_loop_env_key) != null) return error.ZigIsTheCCompiler;
|
|
- try env_map.put(inf_loop_env_key, "1");
|
|
+ var argv = std.ArrayList([]const u8).init(allocator);
|
|
+ defer argv.deinit();
|
|
+
|
|
+ const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={s}", .{args.search_basename});
|
|
+ defer allocator.free(arg1);
|
|
+
|
|
+ try appendCcExe(&argv, skip_cc_env_var);
|
|
+ try argv.append(arg1);
|
|
|
|
const exec_res = std.ChildProcess.exec(.{
|
|
.allocator = allocator,
|
|
- .argv = &argv,
|
|
+ .argv = argv.items,
|
|
.max_output_bytes = 1024 * 1024,
|
|
.env_map = &env_map,
|
|
// Some C compilers, such as Clang, are known to rely on argv[0] to find the path
|
|
@@ -586,11 +607,11 @@ fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 {
|
|
}
|
|
switch (exec_res.term) {
|
|
.Exited => |code| if (code != 0) {
|
|
- printVerboseInvocation(&argv, args.search_basename, args.verbose, exec_res.stderr);
|
|
+ printVerboseInvocation(argv.items, args.search_basename, args.verbose, exec_res.stderr);
|
|
return error.CCompilerExitCode;
|
|
},
|
|
else => {
|
|
- printVerboseInvocation(&argv, args.search_basename, args.verbose, exec_res.stderr);
|
|
+ printVerboseInvocation(argv.items, args.search_basename, args.verbose, exec_res.stderr);
|
|
return error.CCompilerCrashed;
|
|
},
|
|
}
|
|
@@ -659,3 +680,23 @@ fn fillSearch(search_buf: *[2]Search, sdk: *ZigWindowsSDK) []Search {
|
|
}
|
|
return search_buf[0..search_end];
|
|
}
|
|
+
|
|
+const inf_loop_env_key = "ZIG_IS_DETECTING_LIBC_PATHS";
|
|
+
|
|
+fn appendCcExe(args: *std.ArrayList([]const u8), skip_cc_env_var: bool) !void {
|
|
+ const default_cc_exe = if (is_windows) "cc.exe" else "cc";
|
|
+ try args.ensureUnusedCapacity(1);
|
|
+ if (skip_cc_env_var) {
|
|
+ args.appendAssumeCapacity(default_cc_exe);
|
|
+ return;
|
|
+ }
|
|
+ const cc_env_var = std.os.getenvZ("CC") orelse {
|
|
+ args.appendAssumeCapacity(default_cc_exe);
|
|
+ return;
|
|
+ };
|
|
+ // Respect space-separated flags to the C compiler.
|
|
+ var it = std.mem.tokenize(cc_env_var, " ");
|
|
+ while (it.next()) |arg| {
|
|
+ try args.append(arg);
|
|
+ }
|
|
+}
|
|
--
|
|
2.31.1
|
|
|