Commit d11f42c2b2
Changed files (4)
src/clang_options_data.zig
@@ -2434,7 +2434,14 @@ flagpd1("emit-codegen-only"),
flagpd1("emit-header-module"),
flagpd1("emit-html"),
flagpd1("emit-interface-stubs"),
-flagpd1("emit-llvm"),
+.{
+ .name = "emit-llvm",
+ .syntax = .flag,
+ .zig_equivalent = .emit_llvm,
+ .pd1 = true,
+ .pd2 = false,
+ .psl = false,
+},
flagpd1("emit-llvm-bc"),
flagpd1("emit-llvm-only"),
flagpd1("emit-llvm-uselists"),
src/Compilation.zig
@@ -849,10 +849,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
if (options.use_llvm) |explicit|
break :blk explicit;
- // If we have no zig code to compile, no need for LLVM.
- if (options.main_pkg == null)
- break :blk false;
-
// If we are outputting .c code we must use Zig backend.
if (ofmt == .c)
break :blk false;
@@ -861,6 +857,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
if (options.emit_llvm_ir != null or options.emit_llvm_bc != null)
break :blk true;
+ // If we have no zig code to compile, no need for LLVM.
+ if (options.main_pkg == null)
+ break :blk false;
+
// The stage1 compiler depends on the stage1 C++ LLVM backend
// to compile zig code.
if (use_stage1)
@@ -876,9 +876,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
if (options.use_llvm == true) {
return error.ZigCompilerNotBuiltWithLLVMExtensions;
}
- if (options.machine_code_model != .default) {
- return error.MachineCodeModelNotSupportedWithoutLlvm;
- }
if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) {
return error.EmittingLlvmModuleRequiresUsingLlvmBackend;
}
@@ -1793,6 +1790,10 @@ pub fn update(self: *Compilation) !void {
}
}
+ // Flush takes care of -femit-bin, but we still have -femit-llvm-ir, -femit-llvm-bc, and
+ // -femit-asm to handle, in the case of C objects.
+ try self.emitOthers();
+
// If there are any errors, we anticipate the source files being loaded
// to report error messages. Otherwise we unload all source files to save memory.
// The ZIR needs to stay loaded in memory because (1) Decl objects contain references
@@ -1808,6 +1809,37 @@ pub fn update(self: *Compilation) !void {
}
}
+fn emitOthers(comp: *Compilation) !void {
+ if (comp.bin_file.options.output_mode != .Obj or comp.bin_file.options.module != null or
+ comp.c_object_table.count() == 0)
+ {
+ return;
+ }
+ const obj_path = comp.c_object_table.keys()[0].status.success.object_path;
+ const cwd = std.fs.cwd();
+ const ext = std.fs.path.extension(obj_path);
+ const basename = obj_path[0 .. obj_path.len - ext.len];
+ // This obj path always ends with the object file extension, but if we change the
+ // extension to .ll, .bc, or .s, then it will be the path to those things.
+ const outs = [_]struct {
+ emit: ?EmitLoc,
+ ext: []const u8,
+ }{
+ .{ .emit = comp.emit_asm, .ext = ".s" },
+ .{ .emit = comp.emit_llvm_ir, .ext = ".ll" },
+ .{ .emit = comp.emit_llvm_bc, .ext = ".bc" },
+ };
+ for (outs) |out| {
+ if (out.emit) |loc| {
+ if (loc.directory) |directory| {
+ const src_path = try std.fmt.allocPrint(comp.gpa, "{s}{s}", .{ basename, out.ext });
+ defer comp.gpa.free(src_path);
+ try cwd.copyFile(src_path, directory.handle, loc.basename, .{});
+ }
+ }
+ }
+}
+
/// Having the file open for writing is problematic as far as executing the
/// binary is concerned. This will remove the write flag, or close the file,
/// or whatever is needed so that it can be executed.
@@ -2764,6 +2796,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
defer man.deinit();
man.hash.add(comp.clang_preprocessor_mode);
+ man.hash.addOptionalEmitLoc(comp.emit_asm);
+ man.hash.addOptionalEmitLoc(comp.emit_llvm_ir);
+ man.hash.addOptionalEmitLoc(comp.emit_llvm_bc);
try man.hashCSource(c_object.src);
@@ -2787,16 +2822,29 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
comp.bin_file.options.root_name
else
c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len];
- const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{
- o_basename_noext,
- comp.bin_file.options.object_format.fileExt(comp.bin_file.options.target.cpu.arch),
- });
+ const o_ext = comp.bin_file.options.object_format.fileExt(comp.bin_file.options.target.cpu.arch);
const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {
var argv = std.ArrayList([]const u8).init(comp.gpa);
defer argv.deinit();
- // We can't know the digest until we do the C compiler invocation, so we need a temporary filename.
+ // In case we are doing passthrough mode, we need to detect -S and -emit-llvm.
+ const out_ext = e: {
+ if (!comp.clang_passthrough_mode)
+ break :e o_ext;
+ if (comp.emit_asm != null)
+ break :e ".s";
+ if (comp.emit_llvm_ir != null)
+ break :e ".ll";
+ if (comp.emit_llvm_bc != null)
+ break :e ".bc";
+
+ break :e o_ext;
+ };
+ const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, out_ext });
+
+ // We can't know the digest until we do the C compiler invocation,
+ // so we need a temporary filename.
const out_obj_path = try comp.tmpFilePath(arena, o_basename);
var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{});
defer zig_cache_tmp_dir.close();
@@ -2810,15 +2858,23 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path});
try comp.addCCArgs(arena, &argv, ext, out_dep_path);
- try argv.ensureCapacity(argv.items.len + 3);
+ try argv.ensureUnusedCapacity(6 + c_object.src.extra_flags.len);
switch (comp.clang_preprocessor_mode) {
.no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }),
.yes => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-E", "-o", out_obj_path }),
.stdout => argv.appendAssumeCapacity("-E"),
}
-
- try argv.append(c_object.src.src_path);
- try argv.appendSlice(c_object.src.extra_flags);
+ if (comp.clang_passthrough_mode) {
+ if (comp.emit_asm != null) {
+ argv.appendAssumeCapacity("-S");
+ } else if (comp.emit_llvm_ir != null) {
+ argv.appendSliceAssumeCapacity(&[_][]const u8{ "-emit-llvm", "-S" });
+ } else if (comp.emit_llvm_bc != null) {
+ argv.appendAssumeCapacity("-emit-llvm");
+ }
+ }
+ argv.appendAssumeCapacity(c_object.src.src_path);
+ argv.appendSliceAssumeCapacity(c_object.src.extra_flags);
if (comp.verbose_cc) {
dump_argv(argv.items);
@@ -2838,8 +2894,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
switch (term) {
.Exited => |code| {
if (code != 0) {
- // TODO https://github.com/ziglang/zig/issues/6342
- std.process.exit(1);
+ std.process.exit(code);
}
if (comp.clang_preprocessor_mode == .stdout)
std.process.exit(0);
@@ -2855,9 +2910,6 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
const stderr_reader = child.stderr.?.reader();
- // TODO https://github.com/ziglang/zig/issues/6343
- // Please uncomment and use stdout once this issue is fixed
- // const stdout = try stdout_reader.readAllAlloc(arena, std.math.maxInt(u32));
const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
const term = child.wait() catch |err| {
@@ -2907,6 +2959,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
break :blk digest;
};
+ const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, o_ext });
+
c_object.status = .{
.success = .{
.object_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{
src/main.zig
@@ -1151,6 +1151,7 @@ fn buildOutputType(
var is_shared_lib = false;
var linker_args = std.ArrayList([]const u8).init(arena);
var it = ClangArgIterator.init(arena, all_args);
+ var emit_llvm = false;
while (it.has_next) {
it.next() catch |err| {
fatal("unable to parse command line parameters: {s}", .{@errorName(err)});
@@ -1161,6 +1162,7 @@ fn buildOutputType(
.c => c_out_mode = .object, // -c
.asm_only => c_out_mode = .assembly, // -S
.preprocess_only => c_out_mode = .preprocessor, // -E
+ .emit_llvm => emit_llvm = true,
.other => {
try clang_argv.appendSlice(it.other_args);
},
@@ -1518,22 +1520,42 @@ fn buildOutputType(
output_mode = if (is_shared_lib) .Lib else .Exe;
emit_bin = if (out_path) |p| .{ .yes = p } else EmitBin.yes_a_out;
enable_cache = true;
+ if (emit_llvm) {
+ fatal("-emit-llvm cannot be used when linking", .{});
+ }
},
.object => {
output_mode = .Obj;
- if (out_path) |p| {
- emit_bin = .{ .yes = p };
+ if (emit_llvm) {
+ emit_bin = .no;
+ if (out_path) |p| {
+ emit_llvm_bc = .{ .yes = p };
+ } else {
+ emit_llvm_bc = .yes_default_path;
+ }
} else {
- emit_bin = .yes_default_path;
+ if (out_path) |p| {
+ emit_bin = .{ .yes = p };
+ } else {
+ emit_bin = .yes_default_path;
+ }
}
},
.assembly => {
output_mode = .Obj;
emit_bin = .no;
- if (out_path) |p| {
- emit_asm = .{ .yes = p };
+ if (emit_llvm) {
+ if (out_path) |p| {
+ emit_llvm_ir = .{ .yes = p };
+ } else {
+ emit_llvm_ir = .yes_default_path;
+ }
} else {
- emit_asm = .yes_default_path;
+ if (out_path) |p| {
+ emit_asm = .{ .yes = p };
+ } else {
+ emit_asm = .yes_default_path;
+ }
}
},
.preprocessor => {
@@ -3663,6 +3685,7 @@ pub const ClangArgIterator = struct {
no_red_zone,
strip,
exec_model,
+ emit_llvm,
};
const Args = struct {
tools/update_clang_options.zig
@@ -376,6 +376,10 @@ const known_options = [_]KnownOpt{
.name = "mexec-model",
.ident = "exec_model",
},
+ .{
+ .name = "emit-llvm",
+ .ident = "emit_llvm",
+ },
};
const blacklisted_options = [_][]const u8{};