Andrew Kelley 2a8fc1a18e stage2: caching system integration & Module/Compilation splitting
* update to the new cache hash API
 * std.Target defaultVersionRange moves to std.Target.Os.Tag
 * std.Target.Os gains getVersionRange which returns a tagged union
 * start the process of splitting Module into Compilation and "zig
   module".
   - The parts of Module having to do with only compiling zig code are
     extracted into ZigModule.zig.
   - Next step is to rename Module to Compilation.
   - After that rename ZigModule back to Module.
 * implement proper cache hash usage when compiling C objects, and
   properly manage the file lock of the build artifacts.
 * make versions optional to match recent changes to master branch.
 * proper cache hash integration for compiling zig code
 * proper cache hash integration for linking even when not compiling zig
   code.
 * ELF LLD linking integrates with the caching system. A comment from
   the source code:

   Here we want to determine whether we can save time by not invoking LLD when the
   output is unchanged. None of the linker options or the object files that are being
   linked are in the hash that namespaces the directory we are outputting to. Therefore,
   we must hash those now, and the resulting digest will form the "id" of the linking
   job we are about to perform.
   After a successful link, we store the id in the metadata of a symlink named "id.txt" in
   the artifact directory. So, now, we check if this symlink exists, and if it matches
   our digest. If so, we can skip linking. Otherwise, we proceed with invoking LLD.

 * implement disable_c_depfile option
 * add tracy to a few more functions
2020-09-13 19:29:07 -07:00

106 lines
3.1 KiB
Zig

const std = @import("std");
const mem = std.mem;
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const Module = @import("../ZigModule.zig");
const Compilation = @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: *Compilation.ErrorMsg = undefined,
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*File {
assert(options.object_format == .c);
if (options.use_llvm) return error.LLVMHasNoCBackend;
if (options.use_lld) return error.LLDHasNoCBackend;
const file = try options.directory.handle.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 Compilation.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, comp: *Compilation) !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;
}