mirror of
https://github.com/ziglang/zig.git
synced 2026-02-15 22:09:49 +00:00
stage2: don't create empty object files when no zig source
This commit is contained in:
parent
046dce9cef
commit
2627778b25
@ -1072,13 +1072,14 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void {
|
||||
break :blk digest;
|
||||
};
|
||||
|
||||
const full_object_path = if (comp.zig_cache_directory.path) |p|
|
||||
try std.fs.path.join(comp.gpa, &[_][]const u8{ p, "o", &digest, o_basename })
|
||||
const components = if (comp.zig_cache_directory.path) |p|
|
||||
&[_][]const u8{ p, "o", &digest, o_basename }
|
||||
else
|
||||
try std.fs.path.join(comp.gpa, &[_][]const u8{ "o", &digest, o_basename });
|
||||
&[_][]const u8{ "o", &digest, o_basename };
|
||||
|
||||
c_object.status = .{
|
||||
.success = .{
|
||||
.object_path = full_object_path,
|
||||
.object_path = try std.fs.path.join(comp.gpa, components),
|
||||
.lock = ch.toOwnedLock(),
|
||||
},
|
||||
};
|
||||
|
||||
@ -126,17 +126,29 @@ pub const File = struct {
|
||||
pub fn openPath(allocator: *Allocator, options: Options) !*File {
|
||||
const use_lld = build_options.have_llvm and options.use_lld; // comptime known false when !have_llvm
|
||||
const sub_path = if (use_lld) blk: {
|
||||
if (options.module == null) {
|
||||
// No point in opening a file, we would not write anything to it. Initialize with empty.
|
||||
return switch (options.object_format) {
|
||||
.coff, .pe => &(try Coff.createEmpty(allocator, options)).base,
|
||||
.elf => &(try Elf.createEmpty(allocator, options)).base,
|
||||
.macho => &(try MachO.createEmpty(allocator, options)).base,
|
||||
.wasm => &(try Wasm.createEmpty(allocator, options)).base,
|
||||
.c => unreachable, // Reported error earlier.
|
||||
.hex => return error.HexObjectFormatUnimplemented,
|
||||
.raw => return error.RawObjectFormatUnimplemented,
|
||||
};
|
||||
}
|
||||
// Open a temporary object file, not the final output file because we want to link with LLD.
|
||||
break :blk try std.fmt.allocPrint(allocator, "{}{}", .{ options.sub_path, options.target.oFileExt() });
|
||||
} else options.sub_path;
|
||||
errdefer if (use_lld) allocator.free(sub_path);
|
||||
|
||||
const file: *File = switch (options.object_format) {
|
||||
.coff, .pe => try Coff.openPath(allocator, sub_path, options),
|
||||
.elf => try Elf.openPath(allocator, sub_path, options),
|
||||
.macho => try MachO.openPath(allocator, sub_path, options),
|
||||
.wasm => try Wasm.openPath(allocator, sub_path, options),
|
||||
.c => try C.openPath(allocator, sub_path, options),
|
||||
.coff, .pe => &(try Coff.openPath(allocator, sub_path, options)).base,
|
||||
.elf => &(try Elf.openPath(allocator, sub_path, options)).base,
|
||||
.macho => &(try MachO.openPath(allocator, sub_path, options)).base,
|
||||
.wasm => &(try Wasm.openPath(allocator, sub_path, options)).base,
|
||||
.c => &(try C.openPath(allocator, sub_path, options)).base,
|
||||
.hex => return error.HexObjectFormatUnimplemented,
|
||||
.raw => return error.RawObjectFormatUnimplemented,
|
||||
};
|
||||
@ -216,19 +228,9 @@ pub const File = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(base: *File) void {
|
||||
switch (base.tag) {
|
||||
.coff => @fieldParentPtr(Coff, "base", base).deinit(),
|
||||
.elf => @fieldParentPtr(Elf, "base", base).deinit(),
|
||||
.macho => @fieldParentPtr(MachO, "base", base).deinit(),
|
||||
.c => @fieldParentPtr(C, "base", base).deinit(),
|
||||
.wasm => @fieldParentPtr(Wasm, "base", base).deinit(),
|
||||
}
|
||||
pub fn destroy(base: *File) void {
|
||||
if (base.file) |f| f.close();
|
||||
if (base.intermediary_basename) |sub_path| base.allocator.free(sub_path);
|
||||
}
|
||||
|
||||
pub fn destroy(base: *File) void {
|
||||
switch (base.tag) {
|
||||
.coff => {
|
||||
const parent = @fieldParentPtr(Coff, "base", base);
|
||||
|
||||
@ -23,7 +23,7 @@ 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 {
|
||||
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*C {
|
||||
assert(options.object_format == .c);
|
||||
|
||||
if (options.use_llvm) return error.LLVMHasNoCBackend;
|
||||
@ -48,7 +48,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
|
||||
.called = std.StringHashMap(void).init(allocator),
|
||||
};
|
||||
|
||||
return &c_file.base;
|
||||
return c_file;
|
||||
}
|
||||
|
||||
pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
|
||||
|
||||
@ -28,7 +28,7 @@ pub const base_tag: link.File.Tag = .coff;
|
||||
const msdos_stub = @embedFile("msdos-stub.bin");
|
||||
|
||||
base: link.File,
|
||||
ptr_width: enum { p32, p64 },
|
||||
ptr_width: PtrWidth,
|
||||
error_flags: link.File.ErrorFlags = .{},
|
||||
|
||||
text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{},
|
||||
@ -64,6 +64,8 @@ text_section_size_dirty: bool = false,
|
||||
/// and needs to be updated in the optional header.
|
||||
size_of_image_dirty: bool = false,
|
||||
|
||||
pub const PtrWidth = enum { p32, p64 };
|
||||
|
||||
pub const TextBlock = struct {
|
||||
/// Offset of the code relative to the start of the text section
|
||||
text_offset: u32,
|
||||
@ -111,7 +113,7 @@ pub const TextBlock = struct {
|
||||
|
||||
pub const SrcFn = void;
|
||||
|
||||
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*link.File {
|
||||
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Coff {
|
||||
assert(options.object_format == .coff);
|
||||
|
||||
if (options.use_llvm) return error.LLVM_BackendIsTODO_ForCoff; // TODO
|
||||
@ -124,66 +126,17 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
|
||||
});
|
||||
errdefer file.close();
|
||||
|
||||
var coff_file = try allocator.create(Coff);
|
||||
errdefer allocator.destroy(coff_file);
|
||||
const self = try createEmpty(allocator, options);
|
||||
errdefer self.base.destroy();
|
||||
|
||||
coff_file.* = openFile(allocator, file, options) catch |err| switch (err) {
|
||||
error.IncrFailed => try createFile(allocator, file, options),
|
||||
else => |e| return e,
|
||||
};
|
||||
self.base.file = file;
|
||||
|
||||
return &coff_file.base;
|
||||
}
|
||||
|
||||
/// Returns error.IncrFailed if incremental update could not be performed.
|
||||
fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !Coff {
|
||||
switch (options.output_mode) {
|
||||
.Exe => {},
|
||||
.Obj => return error.IncrFailed,
|
||||
.Lib => return error.IncrFailed,
|
||||
}
|
||||
var self: Coff = .{
|
||||
.base = .{
|
||||
.file = file,
|
||||
.tag = .coff,
|
||||
.options = options,
|
||||
.allocator = allocator,
|
||||
},
|
||||
.ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
|
||||
32 => .p32,
|
||||
64 => .p64,
|
||||
else => return error.UnsupportedELFArchitecture,
|
||||
},
|
||||
};
|
||||
errdefer self.deinit();
|
||||
|
||||
// TODO implement reading the PE/COFF file
|
||||
return error.IncrFailed;
|
||||
}
|
||||
|
||||
/// Truncates the existing file contents and overwrites the contents.
|
||||
/// Returns an error if `file` is not already open with +read +write +seek abilities.
|
||||
fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Coff {
|
||||
// TODO Write object specific relocations, COFF symbol table, then enable object file output.
|
||||
switch (options.output_mode) {
|
||||
.Exe => {},
|
||||
.Obj => return error.TODOImplementWritingObjFiles,
|
||||
.Lib => return error.TODOImplementWritingLibFiles,
|
||||
}
|
||||
var self: Coff = .{
|
||||
.base = .{
|
||||
.tag = .coff,
|
||||
.options = options,
|
||||
.allocator = allocator,
|
||||
.file = file,
|
||||
},
|
||||
.ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
|
||||
32 => .p32,
|
||||
64 => .p64,
|
||||
else => return error.UnsupportedCOFFArchitecture,
|
||||
},
|
||||
};
|
||||
errdefer self.deinit();
|
||||
|
||||
var coff_file_header_offset: u32 = 0;
|
||||
if (options.output_mode == .Exe) {
|
||||
@ -426,6 +379,25 @@ fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Coff
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Coff {
|
||||
const ptr_width: PtrWidth = switch (options.target.cpu.arch.ptrBitWidth()) {
|
||||
0...32 => .p32,
|
||||
33...64 => .p64,
|
||||
else => return error.UnsupportedCOFFArchitecture,
|
||||
};
|
||||
const self = try gpa.create(Coff);
|
||||
self.* = .{
|
||||
.base = .{
|
||||
.tag = .coff,
|
||||
.options = options,
|
||||
.allocator = gpa,
|
||||
.file = null,
|
||||
},
|
||||
.ptr_width = ptr_width,
|
||||
};
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn allocateDeclIndexes(self: *Coff, decl: *Module.Decl) !void {
|
||||
try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ pub const base_tag: File.Tag = .elf;
|
||||
|
||||
base: File,
|
||||
|
||||
ptr_width: enum { p32, p64 },
|
||||
ptr_width: PtrWidth,
|
||||
|
||||
/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
|
||||
/// Same order as in the file.
|
||||
@ -136,6 +136,8 @@ const alloc_den = 3;
|
||||
const minimum_text_block_size = 64;
|
||||
const min_text_capacity = minimum_text_block_size * alloc_num / alloc_den;
|
||||
|
||||
pub const PtrWidth = enum { p32, p64 };
|
||||
|
||||
pub const TextBlock = struct {
|
||||
/// Each decl always gets a local symbol with the fully qualified name.
|
||||
/// The vaddr and size are found here directly.
|
||||
@ -222,7 +224,7 @@ pub const SrcFn = struct {
|
||||
};
|
||||
};
|
||||
|
||||
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*File {
|
||||
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Elf {
|
||||
assert(options.object_format == .elf);
|
||||
|
||||
if (options.use_llvm) return error.LLVMBackendUnimplementedForELF; // TODO
|
||||
@ -234,31 +236,11 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
|
||||
});
|
||||
errdefer file.close();
|
||||
|
||||
var elf_file = try allocator.create(Elf);
|
||||
errdefer allocator.destroy(elf_file);
|
||||
const self = try createEmpty(allocator, options);
|
||||
errdefer self.base.destroy();
|
||||
|
||||
elf_file.* = try createFile(allocator, file, options);
|
||||
return &elf_file.base;
|
||||
}
|
||||
|
||||
/// Truncates the existing file contents and overwrites the contents.
|
||||
/// Returns an error if `file` is not already open with +read +write +seek abilities.
|
||||
fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Elf {
|
||||
var self: Elf = .{
|
||||
.base = .{
|
||||
.tag = .elf,
|
||||
.options = options,
|
||||
.allocator = allocator,
|
||||
.file = file,
|
||||
},
|
||||
.ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
|
||||
0 ... 32 => .p32,
|
||||
33 ... 64 => .p64,
|
||||
else => return error.UnsupportedELFArchitecture,
|
||||
},
|
||||
.shdr_table_dirty = true,
|
||||
};
|
||||
errdefer self.deinit();
|
||||
self.base.file = file;
|
||||
self.shdr_table_dirty = true;
|
||||
|
||||
// Index 0 is always a null symbol.
|
||||
try self.local_symbols.append(allocator, .{
|
||||
@ -289,6 +271,25 @@ fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Elf
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf {
|
||||
const ptr_width: PtrWidth = switch (options.target.cpu.arch.ptrBitWidth()) {
|
||||
0 ... 32 => .p32,
|
||||
33 ... 64 => .p64,
|
||||
else => return error.UnsupportedELFArchitecture,
|
||||
};
|
||||
const self = try gpa.create(Elf);
|
||||
self.* = .{
|
||||
.base = .{
|
||||
.tag = .elf,
|
||||
.options = options,
|
||||
.allocator = gpa,
|
||||
.file = null,
|
||||
},
|
||||
.ptr_width = ptr_width,
|
||||
};
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn releaseLock(self: *Elf) void {
|
||||
if (self.lock) |*lock| {
|
||||
lock.release();
|
||||
|
||||
@ -135,7 +135,7 @@ pub const SrcFn = struct {
|
||||
pub const empty = SrcFn{};
|
||||
};
|
||||
|
||||
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*File {
|
||||
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*MachO {
|
||||
assert(options.object_format == .macho);
|
||||
|
||||
if (options.use_llvm) return error.LLVM_BackendIsTODO_ForMachO; // TODO
|
||||
@ -148,64 +148,35 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
|
||||
});
|
||||
errdefer file.close();
|
||||
|
||||
var macho_file = try allocator.create(MachO);
|
||||
errdefer allocator.destroy(macho_file);
|
||||
const self = try createEmpty(allocator, options);
|
||||
errdefer self.base.destroy();
|
||||
|
||||
macho_file.* = openFile(allocator, file, options) catch |err| switch (err) {
|
||||
error.IncrFailed => try createFile(allocator, file, options),
|
||||
else => |e| return e,
|
||||
};
|
||||
self.base.file = file;
|
||||
|
||||
return &macho_file.base;
|
||||
}
|
||||
|
||||
/// Returns error.IncrFailed if incremental update could not be performed.
|
||||
fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO {
|
||||
switch (options.output_mode) {
|
||||
.Exe => {},
|
||||
.Obj => {},
|
||||
.Lib => return error.IncrFailed,
|
||||
}
|
||||
var self: MachO = .{
|
||||
.base = .{
|
||||
.file = file,
|
||||
.tag = .macho,
|
||||
.options = options,
|
||||
.allocator = allocator,
|
||||
},
|
||||
};
|
||||
errdefer self.deinit();
|
||||
|
||||
// TODO implement reading the macho file
|
||||
return error.IncrFailed;
|
||||
//try self.populateMissingMetadata();
|
||||
//return self;
|
||||
}
|
||||
|
||||
/// Truncates the existing file contents and overwrites the contents.
|
||||
/// Returns an error if `file` is not already open with +read +write +seek abilities.
|
||||
fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !MachO {
|
||||
switch (options.output_mode) {
|
||||
.Exe => {},
|
||||
.Obj => {},
|
||||
.Lib => return error.TODOImplementWritingLibFiles,
|
||||
}
|
||||
|
||||
var self: MachO = .{
|
||||
.base = .{
|
||||
.file = file,
|
||||
.tag = .macho,
|
||||
.options = options,
|
||||
.allocator = allocator,
|
||||
},
|
||||
};
|
||||
errdefer self.deinit();
|
||||
|
||||
try self.populateMissingMetadata();
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn createEmpty(gpa: *Allocator, options: link.Options) !*MachO {
|
||||
const self = try gpa.create(MachO);
|
||||
self.* = .{
|
||||
.base = .{
|
||||
.tag = .macho,
|
||||
.options = options,
|
||||
.allocator = gpa,
|
||||
.file = null,
|
||||
},
|
||||
};
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn flush(self: *MachO, comp: *Compilation) !void {
|
||||
switch (self.base.options.output_mode) {
|
||||
.Exe => {
|
||||
|
||||
@ -50,7 +50,7 @@ base: link.File,
|
||||
/// TODO: can/should we access some data structure in Module directly?
|
||||
funcs: std.ArrayListUnmanaged(*Module.Decl) = .{},
|
||||
|
||||
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*link.File {
|
||||
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Wasm {
|
||||
assert(options.object_format == .wasm);
|
||||
|
||||
if (options.use_llvm) return error.LLVM_BackendIsTODO_ForWasm; // TODO
|
||||
@ -60,21 +60,27 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
|
||||
const file = try options.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true });
|
||||
errdefer file.close();
|
||||
|
||||
const wasm = try allocator.create(Wasm);
|
||||
errdefer allocator.destroy(wasm);
|
||||
const wasm = try createEmpty(allocator, options);
|
||||
errdefer wasm.base.destroy();
|
||||
|
||||
wasm.base.file = file;
|
||||
|
||||
try file.writeAll(&(spec.magic ++ spec.version));
|
||||
|
||||
return wasm;
|
||||
}
|
||||
|
||||
pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Wasm {
|
||||
const wasm = try gpa.create(Wasm);
|
||||
wasm.* = .{
|
||||
.base = .{
|
||||
.tag = .wasm,
|
||||
.options = options,
|
||||
.file = file,
|
||||
.allocator = allocator,
|
||||
.file = null,
|
||||
.allocator = gpa,
|
||||
},
|
||||
};
|
||||
|
||||
return &wasm.base;
|
||||
return wasm;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Wasm) void {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user