diff options
| author | Cody Tapscott <topolarity@tapscott.me> | 2022-02-03 15:27:01 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-02-06 22:21:46 -0700 |
| commit | 5065830aa007c374c382be9e80ba924df6cecc78 (patch) | |
| tree | b8f8b3b601ded5d48cac007c52bd23592a62c206 /src/main.zig | |
| parent | 069dd01ce4ced3cb9664e4f1e09be753cb3ed476 (diff) | |
| download | zig-5065830aa007c374c382be9e80ba924df6cecc78.tar.gz zig-5065830aa007c374c382be9e80ba924df6cecc78.zip | |
Avoid depending on child process execution when not supported by host OS
In accordance with the requesting issue (#10750):
- `zig test` skips any tests that it cannot spawn, returning success
- `zig run` and `zig build` exit with failure, reporting the command the cannot be run
- `zig clang`, `zig ar`, etc. already punt directly to the appropriate clang/lld main(), even before this change
- Native `libc` Detection is not supported
Additionally, `exec()` and related Builder functions error at run-time, reporting the command that cannot be run
Diffstat (limited to 'src/main.zig')
| -rw-r--r-- | src/main.zig | 137 |
1 files changed, 82 insertions, 55 deletions
diff --git a/src/main.zig b/src/main.zig index bbdb948c90..d6688081f1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -221,7 +221,7 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi mem.eql(u8, cmd, "lib") or mem.eql(u8, cmd, "ar")) { - return punt_to_llvm_ar(arena, args); + return process.exit(try llvmArMain(arena, args)); } else if (mem.eql(u8, cmd, "cc")) { return buildOutputType(gpa, arena, args, .cc); } else if (mem.eql(u8, cmd, "c++")) { @@ -231,12 +231,12 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi } else if (mem.eql(u8, cmd, "clang") or mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as")) { - return punt_to_clang(arena, args); + return process.exit(try clangMain(arena, args)); } else if (mem.eql(u8, cmd, "ld.lld") or mem.eql(u8, cmd, "lld-link") or mem.eql(u8, cmd, "wasm-ld")) { - return punt_to_lld(arena, args); + return process.exit(try lldMain(arena, args)); } else if (mem.eql(u8, cmd, "build")) { return cmdBuild(gpa, arena, cmd_args); } else if (mem.eql(u8, cmd, "fmt")) { @@ -1347,7 +1347,7 @@ fn buildOutputType( .ignore => {}, .driver_punt => { // Never mind what we're doing, just pass the args directly. For example --help. - return punt_to_clang(arena, all_args); + return process.exit(try clangMain(arena, all_args)); }, .pic => want_pic = true, .no_pic => want_pic = false, @@ -1866,7 +1866,7 @@ fn buildOutputType( // An error message is generated when there is more than 1 C source file. if (c_source_files.items.len != 1) { // For example `zig cc` and no args should print the "no input files" message. - return punt_to_clang(arena, all_args); + return process.exit(try clangMain(arena, all_args)); } if (out_path) |p| { emit_bin = .{ .yes = p }; @@ -1882,7 +1882,7 @@ fn buildOutputType( { // For example `zig cc` and no args should print the "no input files" message. // There could be other reasons to punt to clang, for example, --help. - return punt_to_clang(arena, all_args); + return process.exit(try clangMain(arena, all_args)); } }, } @@ -2883,7 +2883,7 @@ fn runOrTest( try warnAboutForeignBinaries(gpa, arena, arg_mode, target_info, link_libc); const cmd = try argvCmd(arena, argv.items); fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd }); - } else { + } else if (std.process.can_spawn) { const child = try std.ChildProcess.init(argv.items, gpa); defer child.deinit(); @@ -2943,6 +2943,9 @@ fn runOrTest( }, else => unreachable, } + } else { + const cmd = try argvCmd(arena, argv.items); + fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd }); } } @@ -3553,29 +3556,35 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi break :argv child_argv.items; }; - const child = try std.ChildProcess.init(child_argv, gpa); - defer child.deinit(); - child.stdin_behavior = .Inherit; - child.stdout_behavior = .Inherit; - child.stderr_behavior = .Inherit; + if (std.process.can_spawn) { + const child = try std.ChildProcess.init(child_argv, gpa); + defer child.deinit(); + + child.stdin_behavior = .Inherit; + child.stdout_behavior = .Inherit; + child.stderr_behavior = .Inherit; - const term = try child.spawnAndWait(); - switch (term) { - .Exited => |code| { - if (code == 0) return cleanExit(); + const term = try child.spawnAndWait(); + switch (term) { + .Exited => |code| { + if (code == 0) return cleanExit(); - if (prominent_compile_errors) { - fatal("the build command failed with exit code {d}", .{code}); - } else { + if (prominent_compile_errors) { + fatal("the build command failed with exit code {d}", .{code}); + } else { + const cmd = try argvCmd(arena, child_argv); + fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd }); + } + }, + else => { const cmd = try argvCmd(arena, child_argv); - fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd }); - } - }, - else => { - const cmd = try argvCmd(arena, child_argv); - fatal("the following build command crashed:\n{s}", .{cmd}); - }, + fatal("the following build command crashed:\n{s}", .{cmd}); + }, + } + } else { + const cmd = try argvCmd(arena, child_argv); + fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd }); } } @@ -4080,51 +4089,69 @@ pub const info_zen = extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; extern "c" fn ZigLlvmAr_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; -/// TODO https://github.com/ziglang/zig/issues/3257 -fn punt_to_clang(arena: Allocator, args: []const []const u8) error{OutOfMemory} { - if (!build_options.have_llvm) - fatal("`zig cc` and `zig c++` unavailable: compiler built without LLVM extensions", .{}); - // Convert the args to the format Clang expects. - const argv = try arena.alloc(?[*:0]u8, args.len + 1); +fn argsCopyZ(alloc: Allocator, args: []const []const u8) ![:null]?[*:0]u8 { + var argv = try alloc.allocSentinel(?[*:0]u8, args.len, null); for (args) |arg, i| { - argv[i] = try arena.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation. + argv[i] = try alloc.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation. } - argv[args.len] = null; - const exit_code = ZigClang_main(@intCast(c_int, args.len), argv[0..args.len :null].ptr); - process.exit(@bitCast(u8, @truncate(i8, exit_code))); + return argv; +} + +pub fn clangMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 { + if (!build_options.have_llvm) + fatal("`zig cc` and `zig c++` unavailable: compiler built without LLVM extensions", .{}); + + var arena_instance = std.heap.ArenaAllocator.init(alloc); + defer arena_instance.deinit(); + const arena = arena_instance.allocator(); + + // Convert the args to the null-terminated format Clang expects. + const argv = try argsCopyZ(arena, args); + const exit_code = ZigClang_main(@intCast(c_int, argv.len), argv.ptr); + return @bitCast(u8, @truncate(i8, exit_code)); } -/// TODO https://github.com/ziglang/zig/issues/3257 -fn punt_to_llvm_ar(arena: Allocator, args: []const []const u8) error{OutOfMemory} { +pub fn llvmArMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 { if (!build_options.have_llvm) fatal("`zig ar`, `zig dlltool`, `zig ranlib', and `zig lib` unavailable: compiler built without LLVM extensions", .{}); + var arena_instance = std.heap.ArenaAllocator.init(alloc); + defer arena_instance.deinit(); + const arena = arena_instance.allocator(); + // Convert the args to the format llvm-ar expects. - // We subtract 1 to shave off the zig binary from args[0]. - const argv = try arena.allocSentinel(?[*:0]u8, args.len - 1, null); - for (args[1..]) |arg, i| { - // TODO If there was an argsAllocZ we could avoid this allocation. - argv[i] = try arena.dupeZ(u8, arg); - } - const argc = @intCast(c_int, argv.len); - const exit_code = ZigLlvmAr_main(argc, argv.ptr); - process.exit(@bitCast(u8, @truncate(i8, exit_code))); + // We intentionally shave off the zig binary at args[0]. + const argv = try argsCopyZ(arena, args[1..]); + const exit_code = ZigLlvmAr_main(@intCast(c_int, argv.len), argv.ptr); + return @bitCast(u8, @truncate(i8, exit_code)); } /// The first argument determines which backend is invoked. The options are: /// * `ld.lld` - ELF /// * `lld-link` - COFF /// * `wasm-ld` - WebAssembly -/// TODO https://github.com/ziglang/zig/issues/3257 -pub fn punt_to_lld(arena: Allocator, args: []const []const u8) error{OutOfMemory} { +pub fn lldMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 { if (!build_options.have_llvm) fatal("`zig {s}` unavailable: compiler built without LLVM extensions", .{args[0]}); - // Convert the args to the format LLD expects. - // We subtract 1 to shave off the zig binary from args[0]. - const argv = try arena.allocSentinel(?[*:0]const u8, args.len - 1, null); - for (args[1..]) |arg, i| { - argv[i] = try arena.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation. + + // Print a warning if lld is called multiple times in the same process, + // since it may misbehave + // https://github.com/ziglang/zig/issues/3825 + const CallCounter = struct { + var count: usize = 0; + }; + if (CallCounter.count == 1) { // Issue the warning on the first repeat call + warn("calling lldMain repeatedly within the same process can have side effects (https://github.com/ziglang/zig/issues/3825)", .{}); } + CallCounter.count += 1; + + var arena_instance = std.heap.ArenaAllocator.init(alloc); + defer arena_instance.deinit(); + const arena = arena_instance.allocator(); + + // Convert the args to the format llvm-ar expects. + // We intentionally shave off the zig binary at args[0]. + const argv = try argsCopyZ(arena, args[1..]); const exit_code = rc: { const llvm = @import("codegen/llvm/bindings.zig"); const argc = @intCast(c_int, argv.len); @@ -4138,7 +4165,7 @@ pub fn punt_to_lld(arena: Allocator, args: []const []const u8) error{OutOfMemory unreachable; } }; - process.exit(@bitCast(u8, @truncate(i8, exit_code))); + return @bitCast(u8, @truncate(i8, exit_code)); } const clang_args = @import("clang_options.zig").list; |
