Andrew Kelley 4056bb92e6 stage2: more progress moving zig cc to stage2
* std.cache_hash exposes Hasher type
 * std.cache_hash makes hasher_init a global const
 * std.cache_hash supports cloning so that clones can share the same
   open manifest dir handle as well as fork from shared hasher state
 * start to populate the cache_hash for stage2 builds
 * remove a footgun from std.cache_hash add function
 * get rid of std.Target.ObjectFormat.unknown
 * rework stage2 logic for resolving output artifact names by adding
   object_format as an optional parameter to std.zig.binNameAlloc
 * support -Denable-llvm in stage2 tests
 * Module supports the use case when there are no .zig files
 * introduce c_object_table and failed_c_objects to Module
 * propagate many new kinds of data from CLI into Module and into
   linker.Options
 * introduce -fLLVM, -fLLD, -fClang and their -fno- counterparts.
   closes #6251.
   - add logic for choosing when to use LLD or zig's self-hosted linker
 * stub code for implementing invoking Clang to build C objects
 * add -femit-h, -femit-h=foo, and -fno-emit-h CLI options
2020-09-09 09:28:05 -07:00

105 lines
3.0 KiB
Zig

const std = @import("std");
const mem = std.mem;
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const Module = @import("../Module.zig");
const fs = std.fs;
const codegen = @import("../codegen/c.zig");
const link = @import("../link.zig");
const File = link.File;
const C = @This();
pub const base_tag: File.Tag = .c;
base: File,
header: std.ArrayList(u8),
constants: std.ArrayList(u8),
main: std.ArrayList(u8),
called: std.StringHashMap(void),
need_stddef: bool = false,
need_stdint: bool = false,
error_msg: *Module.ErrorMsg = undefined,
pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*File {
assert(options.object_format == .c);
if (options.use_llvm) return error.LLVM_HasNoCBackend;
if (options.use_lld) return error.LLD_HasNoCBackend;
const file = try dir.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) });
errdefer file.close();
var c_file = try allocator.create(C);
errdefer allocator.destroy(c_file);
c_file.* = C{
.base = .{
.tag = .c,
.options = options,
.file = file,
.allocator = allocator,
},
.main = std.ArrayList(u8).init(allocator),
.header = std.ArrayList(u8).init(allocator),
.constants = std.ArrayList(u8).init(allocator),
.called = std.StringHashMap(void).init(allocator),
};
return &c_file.base;
}
pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
self.error_msg = try Module.ErrorMsg.create(self.base.allocator, src, format, args);
return error.AnalysisFail;
}
pub fn deinit(self: *C) void {
self.main.deinit();
self.header.deinit();
self.constants.deinit();
self.called.deinit();
}
pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
codegen.generate(self, decl) catch |err| {
if (err == error.AnalysisFail) {
try module.failed_decls.put(module.gpa, decl, self.error_msg);
}
return err;
};
}
pub fn flush(self: *C, module: *Module) !void {
const writer = self.base.file.?.writer();
try writer.writeAll(@embedFile("cbe.h"));
var includes = false;
if (self.need_stddef) {
try writer.writeAll("#include <stddef.h>\n");
includes = true;
}
if (self.need_stdint) {
try writer.writeAll("#include <stdint.h>\n");
includes = true;
}
if (includes) {
try writer.writeByte('\n');
}
if (self.header.items.len > 0) {
try writer.print("{}\n", .{self.header.items});
}
if (self.constants.items.len > 0) {
try writer.print("{}\n", .{self.constants.items});
}
if (self.main.items.len > 1) {
const last_two = self.main.items[self.main.items.len - 2 ..];
if (std.mem.eql(u8, last_two, "\n\n")) {
self.main.items.len -= 1;
}
}
try writer.writeAll(self.main.items);
self.base.file.?.close();
self.base.file = null;
}