aboutsummaryrefslogtreecommitdiff
path: root/src/Compilation.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/Compilation.zig')
-rw-r--r--src/Compilation.zig93
1 files changed, 69 insertions, 24 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 23f67f5b37..11521e5a52 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -26,6 +26,8 @@ const Module = @import("Module.zig");
const Cache = @import("Cache.zig");
const stage1 = @import("stage1.zig");
const translate_c = @import("translate_c.zig");
+const c_codegen = @import("codegen/c.zig");
+const c_link = @import("link/C.zig");
const ThreadPool = @import("ThreadPool.zig");
const WaitGroup = @import("WaitGroup.zig");
@@ -126,12 +128,13 @@ test_filter: ?[]const u8,
test_name_prefix: ?[]const u8,
test_evented_io: bool,
-emit_h: ?EmitLoc,
emit_asm: ?EmitLoc,
emit_llvm_ir: ?EmitLoc,
emit_analysis: ?EmitLoc,
emit_docs: ?EmitLoc,
+c_header: ?c_link.Header,
+
pub const InnerError = Module.InnerError;
pub const CRTFile = struct {
@@ -895,10 +898,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
};
};
- if (!use_llvm and options.emit_h != null) {
- fatal("TODO implement support for -femit-h in the self-hosted backend", .{});
- }
-
var system_libs: std.StringArrayHashMapUnmanaged(void) = .{};
errdefer system_libs.deinit(gpa);
try system_libs.ensureCapacity(gpa, options.system_libs.len);
@@ -974,7 +973,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.local_cache_directory = options.local_cache_directory,
.global_cache_directory = options.global_cache_directory,
.bin_file = bin_file,
- .emit_h = options.emit_h,
+ .c_header = if (!use_llvm and options.emit_h != null) c_link.Header.init(gpa, options.emit_h) else null,
.emit_asm = options.emit_asm,
.emit_llvm_ir = options.emit_llvm_ir,
.emit_analysis = options.emit_analysis,
@@ -1185,6 +1184,10 @@ pub fn destroy(self: *Compilation) void {
}
self.failed_c_objects.deinit(gpa);
+ if (self.c_header) |*header| {
+ header.deinit();
+ }
+
self.cache_parent.manifest_dir.close();
if (self.owned_link_dir) |*dir| dir.close();
@@ -1286,6 +1289,20 @@ pub fn update(self: *Compilation) !void {
module.root_scope.unload(self.gpa);
}
}
+
+ // If we've chosen to emit a C header, flush the header to the disk.
+ if (self.c_header) |header| {
+ const header_path = header.emit_loc.?;
+ // If a directory has been provided, write the header there. Otherwise, just write it to the
+ // cache directory.
+ const header_dir = if (header_path.directory) |dir|
+ dir.handle
+ else
+ self.local_cache_directory.handle;
+ const header_file = try header_dir.createFile(header_path.basename, .{});
+ defer header_file.close();
+ try header.flush(header_file.writer());
+ }
}
/// Having the file open for writing is problematic as far as executing the
@@ -1385,6 +1402,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
var c_comp_progress_node = main_progress_node.start("Compile C Objects", self.c_source_files.len);
defer c_comp_progress_node.end();
+ var arena = std.heap.ArenaAllocator.init(self.gpa);
+ defer arena.deinit();
+
var wg = WaitGroup{};
defer wg.wait();
@@ -1432,22 +1452,44 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
assert(decl.typed_value.most_recent.typed_value.ty.hasCodeGenBits());
- self.bin_file.updateDecl(module, decl) catch |err| switch (err) {
- error.OutOfMemory => return error.OutOfMemory,
- error.AnalysisFail => {
- decl.analysis = .dependency_failure;
- },
- else => {
- try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1);
- module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
- module.gpa,
- decl.src(),
- "unable to codegen: {}",
- .{@errorName(err)},
- ));
- decl.analysis = .codegen_failure_retryable;
- },
+ self.bin_file.updateDecl(module, decl) catch |err| {
+ switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
+ error.AnalysisFail => {
+ decl.analysis = .dependency_failure;
+ },
+ else => {
+ try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1);
+ module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
+ module.gpa,
+ decl.src(),
+ "unable to codegen: {}",
+ .{@errorName(err)},
+ ));
+ decl.analysis = .codegen_failure_retryable;
+ },
+ }
+ return;
};
+
+ if (self.c_header) |*header| {
+ c_codegen.generateHeader(&arena, module, &header.*, decl) catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
+ error.AnalysisFail => {
+ decl.analysis = .dependency_failure;
+ },
+ else => {
+ try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1);
+ module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
+ module.gpa,
+ decl.src(),
+ "unable to generate C header: {}",
+ .{@errorName(err)},
+ ));
+ decl.analysis = .codegen_failure_retryable;
+ },
+ };
+ }
},
},
.analyze_decl => |decl| {
@@ -2913,7 +2955,10 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
man.hash.add(comp.bin_file.options.function_sections);
man.hash.add(comp.bin_file.options.is_test);
man.hash.add(comp.bin_file.options.emit != null);
- man.hash.addOptionalEmitLoc(comp.emit_h);
+ man.hash.add(comp.c_header != null);
+ if (comp.c_header) |header| {
+ man.hash.addEmitLoc(header.emit_loc.?);
+ }
man.hash.addOptionalEmitLoc(comp.emit_asm);
man.hash.addOptionalEmitLoc(comp.emit_llvm_ir);
man.hash.addOptionalEmitLoc(comp.emit_analysis);
@@ -3012,10 +3057,10 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
});
break :blk try directory.join(arena, &[_][]const u8{bin_basename});
} else "";
- if (comp.emit_h != null) {
+ if (comp.c_header != null) {
log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{});
}
- const emit_h_path = try stage1LocPath(arena, comp.emit_h, directory);
+ const emit_h_path = try stage1LocPath(arena, if (comp.c_header) |header| header.emit_loc else null, directory);
const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory);
const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory);
const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory);