Commit 0789e91eeb
Changed files (22)
src/codegen/llvm.zig
@@ -3083,9 +3083,7 @@ pub const Object = struct {
if (comp.unwind_tables) {
try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder);
}
- if (comp.bin_file.options.skip_linker_dependencies or
- comp.bin_file.options.no_builtin)
- {
+ if (comp.skip_linker_dependencies or comp.bin_file.options.no_builtin) {
// The intent here is for compiler-rt and libc functions to not generate
// infinite recursion. For example, if we are compiling the memcpy function,
// and llvm detects that the body is equivalent to memcpy, it may replace the
src/Compilation/Config.zig
@@ -335,7 +335,7 @@ pub fn resolve(options: Options) !Config {
break :b .Static;
};
- const import_memory = options.import_memory orelse false;
+ const import_memory = options.import_memory orelse (options.output_mode == .Obj);
const export_memory = b: {
if (link_mode == .Dynamic) {
if (options.export_memory == true) return error.ExportMemoryAndDynamicIncompatible;
src/link/Coff/lld.zig
@@ -48,7 +48,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
const is_lib = self.base.comp.config.output_mode == .Lib;
const is_dyn_lib = self.base.comp.config.link_mode == .Dynamic and is_lib;
const is_exe_or_dyn_lib = is_dyn_lib or self.base.comp.config.output_mode == .Exe;
- const link_in_crt = self.base.options.link_libc and is_exe_or_dyn_lib;
+ const link_in_crt = comp.config.link_libc and is_exe_or_dyn_lib;
const target = self.base.comp.root_mod.resolved_target.result;
const optimize_mode = self.base.comp.root_mod.optimize_mode;
@@ -56,17 +56,17 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
const id_symlink_basename = "lld.id";
var man: Cache.Manifest = undefined;
- defer if (!self.base.options.disable_lld_caching) man.deinit();
+ defer if (!self.base.disable_lld_caching) man.deinit();
var digest: [Cache.hex_digest_len]u8 = undefined;
- if (!self.base.options.disable_lld_caching) {
+ if (!self.base.disable_lld_caching) {
man = comp.cache_parent.obtain();
self.base.releaseLock();
comptime assert(Compilation.link_hash_implementation_version == 10);
- for (self.base.options.objects) |obj| {
+ for (comp.objects) |obj| {
_ = try man.addFile(obj.path, null);
man.hash.add(obj.must_link);
}
@@ -79,12 +79,12 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
}
}
try man.addOptionalFile(module_obj_path);
- man.hash.addOptionalBytes(self.base.options.entry);
+ man.hash.addOptionalBytes(comp.config.entry);
man.hash.add(self.base.stack_size);
man.hash.addOptional(self.image_base);
- man.hash.addListOfBytes(self.base.options.lib_dirs);
- man.hash.add(self.base.options.skip_linker_dependencies);
- if (self.base.options.link_libc) {
+ man.hash.addListOfBytes(self.lib_dirs);
+ man.hash.add(comp.skip_linker_dependencies);
+ if (comp.config.link_libc) {
man.hash.add(self.base.comp.libc_installation != null);
if (self.base.comp.libc_installation) |libc_installation| {
man.hash.addBytes(libc_installation.crt_dir.?);
@@ -95,18 +95,18 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
}
}
try link.hashAddSystemLibs(&man, self.base.comp.system_libs);
- man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys());
- man.hash.addOptional(self.base.options.subsystem);
- man.hash.add(self.base.options.is_test);
- man.hash.add(self.base.options.tsaware);
- man.hash.add(self.base.options.nxcompat);
- man.hash.add(self.base.options.dynamicbase);
+ man.hash.addListOfBytes(self.base.force_undefined_symbols.keys());
+ man.hash.addOptional(self.subsystem);
+ man.hash.add(comp.config.is_test);
+ man.hash.add(self.tsaware);
+ man.hash.add(self.nxcompat);
+ man.hash.add(self.dynamicbase);
man.hash.addOptional(self.base.allow_shlib_undefined);
// strip does not need to go into the linker hash because it is part of the hash namespace
- man.hash.addOptional(self.base.options.major_subsystem_version);
- man.hash.addOptional(self.base.options.minor_subsystem_version);
- man.hash.addOptional(self.base.options.version);
- try man.addOptionalFile(self.base.options.module_definition_file);
+ man.hash.addOptional(self.major_subsystem_version);
+ man.hash.addOptional(self.minor_subsystem_version);
+ man.hash.addOptional(comp.version);
+ try man.addOptionalFile(self.module_definition_file);
// We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
_ = try man.hit();
@@ -141,8 +141,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
// here. TODO: think carefully about how we can avoid this redundant operation when doing
// build-obj. See also the corresponding TODO in linkAsArchive.
const the_object_path = blk: {
- if (self.base.options.objects.len != 0)
- break :blk self.base.options.objects[0].path;
+ if (comp.objects.len != 0)
+ break :blk comp.objects[0].path;
if (comp.c_object_table.count() != 0)
break :blk comp.c_object_table.keys()[0].status.success.object_path;
@@ -171,21 +171,21 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
try argv.append("-ERRORLIMIT:0");
try argv.append("-NOLOGO");
- if (!self.base.options.strip) {
+ if (self.base.debug_format != .strip) {
try argv.append("-DEBUG");
const out_ext = std.fs.path.extension(full_out_path);
- const out_pdb = self.base.options.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{
+ const out_pdb = self.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{
full_out_path[0 .. full_out_path.len - out_ext.len],
});
try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb}));
try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb}));
}
- if (self.base.options.version) |version| {
+ if (comp.version) |version| {
try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor }));
}
- if (self.base.options.lto) {
+ if (comp.config.lto) {
switch (optimize_mode) {
.Debug => {},
.ReleaseSmall => try argv.append("-OPT:lldlto=2"),
@@ -209,7 +209,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
}
}
- for (self.base.options.force_undefined_symbols.keys()) |symbol| {
+ for (self.base.force_undefined_symbols.keys()) |symbol| {
try argv.append(try allocPrint(arena, "-INCLUDE:{s}", .{symbol}));
}
@@ -217,17 +217,17 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
try argv.append("-DLL");
}
- if (self.base.options.entry) |entry| {
+ if (comp.config.entry) |entry| {
try argv.append(try allocPrint(arena, "-ENTRY:{s}", .{entry}));
}
- if (self.base.options.tsaware) {
+ if (self.tsaware) {
try argv.append("-tsaware");
}
- if (self.base.options.nxcompat) {
+ if (self.nxcompat) {
try argv.append("-nxcompat");
}
- if (!self.base.options.dynamicbase) {
+ if (!self.dynamicbase) {
try argv.append("-dynamicbase:NO");
}
if (self.base.allow_shlib_undefined) {
@@ -236,12 +236,12 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path}));
- if (self.base.options.implib_emit) |emit| {
+ if (self.implib_emit) |emit| {
const implib_out_path = try emit.directory.join(arena, &[_][]const u8{emit.sub_path});
try argv.append(try allocPrint(arena, "-IMPLIB:{s}", .{implib_out_path}));
}
- if (self.base.options.link_libc) {
+ if (comp.config.link_libc) {
if (self.base.comp.libc_installation) |libc_installation| {
try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.crt_dir.?}));
@@ -252,12 +252,12 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
}
}
- for (self.base.options.lib_dirs) |lib_dir| {
+ for (self.lib_dirs) |lib_dir| {
try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{lib_dir}));
}
- try argv.ensureUnusedCapacity(self.base.options.objects.len);
- for (self.base.options.objects) |obj| {
+ try argv.ensureUnusedCapacity(comp.objects.len);
+ for (comp.objects) |obj| {
if (obj.must_link) {
argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{s}", .{obj.path}));
} else {
@@ -279,18 +279,18 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
try argv.append(p);
}
- if (self.base.options.module_definition_file) |def| {
+ if (self.module_definition_file) |def| {
try argv.append(try allocPrint(arena, "-DEF:{s}", .{def}));
}
const resolved_subsystem: ?std.Target.SubSystem = blk: {
- if (self.base.options.subsystem) |explicit| break :blk explicit;
+ if (self.subsystem) |explicit| break :blk explicit;
switch (target.os.tag) {
.windows => {
if (self.base.comp.module) |module| {
if (module.stage1_flags.have_dllmain_crt_startup or is_dyn_lib)
break :blk null;
- if (module.stage1_flags.have_c_main or self.base.options.is_test or
+ if (module.stage1_flags.have_c_main or comp.config.is_test or
module.stage1_flags.have_winmain_crt_startup or
module.stage1_flags.have_wwinmain_crt_startup)
{
@@ -310,8 +310,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
const mode: Mode = mode: {
if (resolved_subsystem) |subsystem| {
const subsystem_suffix = ss: {
- if (self.base.options.major_subsystem_version) |major| {
- if (self.base.options.minor_subsystem_version) |minor| {
+ if (self.major_subsystem_version) |major| {
+ if (self.minor_subsystem_version) |minor| {
break :ss try allocPrint(arena, ",{d}.{d}", .{ major, minor });
} else {
break :ss try allocPrint(arena, ",{d}", .{major});
@@ -447,7 +447,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
}
} else {
try argv.append("-NODEFAULTLIB");
- if (!is_lib and self.base.options.entry == null) {
+ if (!is_lib and comp.config.entry == null) {
if (self.base.comp.module) |module| {
if (module.stage1_flags.have_winmain_crt_startup) {
try argv.append("-ENTRY:WinMainCRTStartup");
@@ -463,18 +463,18 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
}
// libc++ dep
- if (self.base.options.link_libcpp) {
+ if (comp.config.link_libcpp) {
try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
try argv.append(comp.libcxx_static_lib.?.full_object_path);
}
// libunwind dep
- if (self.base.options.link_libunwind) {
+ if (comp.config.link_libunwind) {
try argv.append(comp.libunwind_static_lib.?.full_object_path);
}
- if (is_exe_or_dyn_lib and !self.base.options.skip_linker_dependencies) {
- if (!self.base.options.link_libc) {
+ if (is_exe_or_dyn_lib and !comp.skip_linker_dependencies) {
+ if (!comp.config.link_libc) {
if (comp.libc_static_lib) |lib| {
try argv.append(lib.full_object_path);
}
@@ -492,13 +492,13 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
argv.appendAssumeCapacity(crt_file.full_object_path);
continue;
}
- if (try findLib(arena, lib_basename, self.base.options.lib_dirs)) |full_path| {
+ if (try findLib(arena, lib_basename, self.lib_dirs)) |full_path| {
argv.appendAssumeCapacity(full_path);
continue;
}
if (target.abi.isGnu()) {
const fallback_name = try allocPrint(arena, "lib{s}.dll.a", .{key});
- if (try findLib(arena, fallback_name, self.base.options.lib_dirs)) |full_path| {
+ if (try findLib(arena, fallback_name, self.lib_dirs)) |full_path| {
argv.appendAssumeCapacity(full_path);
continue;
}
@@ -582,7 +582,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
}
}
- if (!self.base.options.disable_lld_caching) {
+ if (!self.base.disable_lld_caching) {
// Update the file with the digest. If it fails we can continue; it only
// means that the next invocation will have an unnecessary cache miss.
Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
src/link/Elf/Atom.zig
@@ -543,7 +543,7 @@ fn scanReloc(
try self.reportPicError(symbol, rel, elf_file),
.copyrel => {
- if (elf_file.base.options.z_nocopyreloc) {
+ if (elf_file.z_nocopyreloc) {
if (symbol.isAbs(elf_file))
try self.reportNoPicError(symbol, rel, elf_file)
else
@@ -553,9 +553,9 @@ fn scanReloc(
},
.dyn_copyrel => {
- if (is_writeable or elf_file.base.options.z_nocopyreloc) {
+ if (is_writeable or elf_file.z_nocopyreloc) {
if (!is_writeable) {
- if (elf_file.base.options.z_notext) {
+ if (elf_file.z_notext) {
elf_file.has_text_reloc = true;
} else {
try self.reportTextRelocError(symbol, rel, elf_file);
@@ -587,7 +587,7 @@ fn scanReloc(
.dynrel, .baserel, .ifunc => {
if (!is_writeable) {
- if (elf_file.base.options.z_notext) {
+ if (elf_file.z_notext) {
elf_file.has_text_reloc = true;
} else {
try self.reportTextRelocError(symbol, rel, elf_file);
@@ -657,11 +657,12 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction {
}
fn outputType(elf_file: *Elf) u2 {
+ const comp = elf_file.base.comp;
assert(!elf_file.isRelocatable());
return switch (elf_file.base.comp.config.output_mode) {
.Obj => unreachable,
.Lib => 0,
- .Exe => if (elf_file.base.options.pie) 1 else 2,
+ .Exe => if (comp.config.pie) 1 else 2,
};
}
@@ -979,7 +980,7 @@ fn resolveDynAbsReloc(
=> try writer.writeInt(i32, @as(i32, @truncate(S + A)), .little),
.dyn_copyrel => {
- if (is_writeable or elf_file.base.options.z_nocopyreloc) {
+ if (is_writeable or elf_file.z_nocopyreloc) {
elf_file.addRelaDynAssumeCapacity(.{
.offset = P,
.sym = target.extra(elf_file).?.dynamic,
src/link/Elf/Object.zig
@@ -299,7 +299,7 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool {
if (mem.startsWith(u8, name, ".note")) break :blk true;
if (mem.startsWith(u8, name, ".comment")) break :blk true;
if (mem.startsWith(u8, name, ".llvm_addrsig")) break :blk true;
- if (elf_file.base.options.strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and
+ if (elf_file.base.debug_format == .strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and
mem.startsWith(u8, name, ".debug")) break :blk true;
break :blk false;
};
src/link/Elf/synthetic_sections.zig
@@ -32,7 +32,7 @@ pub const DynamicSection = struct {
fn getFlags(dt: DynamicSection, elf_file: *Elf) ?u64 {
_ = dt;
var flags: u64 = 0;
- if (elf_file.base.options.z_now) {
+ if (elf_file.z_now) {
flags |= elf.DF_BIND_NOW;
}
for (elf_file.got.entries.items) |entry| switch (entry.tag) {
@@ -49,15 +49,16 @@ pub const DynamicSection = struct {
}
fn getFlags1(dt: DynamicSection, elf_file: *Elf) ?u64 {
+ const comp = elf_file.base.comp;
_ = dt;
var flags_1: u64 = 0;
- if (elf_file.base.options.z_now) {
+ if (elf_file.z_now) {
flags_1 |= elf.DF_1_NOW;
}
- if (elf_file.isExe() and elf_file.base.options.pie) {
+ if (elf_file.isExe() and comp.config.pie) {
flags_1 |= elf.DF_1_PIE;
}
- // if (elf_file.base.options.z_nodlopen) {
+ // if (elf_file.z_nodlopen) {
// flags_1 |= elf.DF_1_NOOPEN;
// }
return if (flags_1 > 0) flags_1 else null;
@@ -246,12 +247,13 @@ pub const ZigGotSection = struct {
}
pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index {
+ const comp = elf_file.base.comp;
const index = try zig_got.allocateEntry(elf_file.base.allocator);
const entry = &zig_got.entries.items[index];
entry.* = sym_index;
const symbol = elf_file.symbol(sym_index);
symbol.flags.has_zig_got = true;
- if (elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) {
+ if (elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) {
zig_got.flags.needs_rela = true;
}
if (symbol.extra(elf_file)) |extra| {
@@ -478,6 +480,7 @@ pub const GotSection = struct {
}
pub fn addGotSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index {
+ const comp = elf_file.base.comp;
const index = try got.allocateEntry(elf_file.base.allocator);
const entry = &got.entries.items[index];
entry.tag = .got;
@@ -485,7 +488,7 @@ pub const GotSection = struct {
const symbol = elf_file.symbol(sym_index);
symbol.flags.has_got = true;
if (symbol.flags.import or symbol.isIFunc(elf_file) or
- ((elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) and !symbol.isAbs(elf_file)))
+ ((elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) and !symbol.isAbs(elf_file)))
{
got.flags.needs_rela = true;
}
@@ -561,6 +564,7 @@ pub const GotSection = struct {
}
pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void {
+ const comp = elf_file.base.comp;
const is_dyn_lib = elf_file.isDynLib();
const apply_relocs = true; // TODO add user option for this
@@ -576,7 +580,7 @@ pub const GotSection = struct {
if (symbol.?.flags.import) break :blk 0;
if (symbol.?.isIFunc(elf_file))
break :blk if (apply_relocs) value else 0;
- if ((elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) and
+ if ((elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) and
!symbol.?.isAbs(elf_file))
{
break :blk if (apply_relocs) value else 0;
@@ -623,6 +627,7 @@ pub const GotSection = struct {
}
pub fn addRela(got: GotSection, elf_file: *Elf) !void {
+ const comp = elf_file.base.comp;
const is_dyn_lib = elf_file.isDynLib();
try elf_file.rela_dyn.ensureUnusedCapacity(elf_file.base.allocator, got.numRela(elf_file));
@@ -652,7 +657,7 @@ pub const GotSection = struct {
});
continue;
}
- if ((elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) and
+ if ((elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) and
!symbol.?.isAbs(elf_file))
{
elf_file.addRelaDynAssumeCapacity(.{
@@ -725,6 +730,7 @@ pub const GotSection = struct {
}
pub fn numRela(got: GotSection, elf_file: *Elf) usize {
+ const comp = elf_file.base.comp;
const is_dyn_lib = elf_file.isDynLib();
var num: usize = 0;
for (got.entries.items) |entry| {
@@ -734,7 +740,7 @@ pub const GotSection = struct {
};
switch (entry.tag) {
.got => if (symbol.?.flags.import or symbol.?.isIFunc(elf_file) or
- ((elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) and
+ ((elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) and
!symbol.?.isAbs(elf_file)))
{
num += 1;
src/link/Elf/ZigObject.zig
@@ -97,7 +97,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
symbol_ptr.esym_index = esym_index;
if (elf_file.base.debug_format != .strip) {
- self.dwarf = Dwarf.init(gpa, &elf_file.base, .dwarf32);
+ self.dwarf = Dwarf.init(&elf_file.base, .dwarf32);
}
}
src/link/MachO/dead_strip.zig
@@ -60,7 +60,7 @@ fn collectRoots(macho_file: *MachO, roots: *AtomTable) !void {
}
// Add all symbols force-defined by the user.
- for (macho_file.base.options.force_undefined_symbols.keys()) |sym_name| {
+ for (macho_file.base.force_undefined_symbols.keys()) |sym_name| {
const global_index = macho_file.resolver.get(sym_name).?;
const global = macho_file.globals.items[global_index];
const sym = macho_file.getSymbol(global);
src/link/MachO/DebugSymbols.zig
@@ -198,10 +198,10 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64
}
pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
+ const comp = macho_file.base.comp;
// TODO This linker code currently assumes there is only 1 compilation unit
// and it corresponds to the Zig source code.
- const options = macho_file.base.options;
- const module = options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
+ const zcu = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented;
for (self.relocs.items) |*reloc| {
const sym = switch (reloc.type) {
@@ -245,7 +245,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
const text_section = macho_file.sections.items(.header)[macho_file.text_section_index.?];
const low_pc = text_section.addr;
const high_pc = text_section.addr + text_section.size;
- try self.dwarf.writeDbgInfoHeader(module, low_pc, high_pc);
+ try self.dwarf.writeDbgInfoHeader(zcu, low_pc, high_pc);
self.debug_info_header_dirty = false;
}
@@ -572,6 +572,5 @@ const trace = @import("../../tracy.zig").trace;
const Allocator = mem.Allocator;
const Dwarf = @import("../Dwarf.zig");
const MachO = @import("../MachO.zig");
-const Module = @import("../../Module.zig");
const StringTable = @import("../StringTable.zig");
const Type = @import("../../type.zig").Type;
src/link/MachO/load_commands.zig
@@ -1,6 +1,3 @@
-/// Default implicit entrypoint symbol name.
-pub const default_entry_point: []const u8 = "_main";
-
/// Default path to dyld.
pub const default_dyld_path: [*:0]const u8 = "/usr/lib/dyld";
@@ -17,7 +14,9 @@ const CalcLCsSizeCtx = struct {
wants_function_starts: bool = true,
};
-fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx, assume_max_path_len: bool) !u32 {
+fn calcLCsSize(m: *MachO, ctx: CalcLCsSizeCtx, assume_max_path_len: bool) !u32 {
+ const comp = m.base.comp;
+ const gpa = comp.gpa;
var has_text_segment: bool = false;
var sizeofcmds: u64 = 0;
for (ctx.segments) |seg| {
@@ -46,15 +45,15 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx
false,
);
// LC_MAIN
- if (options.output_mode == .Exe) {
+ if (comp.config.output_mode == .Exe) {
sizeofcmds += @sizeOf(macho.entry_point_command);
}
// LC_ID_DYLIB
- if (options.output_mode == .Lib and options.link_mode == .Dynamic) {
+ if (comp.config.output_mode == .Lib and comp.config.link_mode == .Dynamic) {
sizeofcmds += blk: {
- const emit = options.emit.?;
- const install_name = options.install_name orelse try emit.directory.join(gpa, &.{emit.sub_path});
- defer if (options.install_name == null) gpa.free(install_name);
+ const emit = m.base.emit;
+ const install_name = m.install_name orelse try emit.directory.join(gpa, &.{emit.sub_path});
+ defer if (m.install_name == null) gpa.free(install_name);
break :blk calcInstallNameLen(
@sizeOf(macho.dylib_command),
install_name,
@@ -64,7 +63,7 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx
}
// LC_RPATH
{
- var it = RpathIterator.init(gpa, options.rpath_list);
+ var it = RpathIterator.init(gpa, m.rpath_list);
defer it.deinit();
while (try it.next()) |rpath| {
sizeofcmds += calcInstallNameLen(
@@ -78,7 +77,8 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx
sizeofcmds += @sizeOf(macho.source_version_command);
// LC_BUILD_VERSION or LC_VERSION_MIN_ or nothing
{
- const platform = Platform.fromTarget(options.target);
+ const target = comp.root_mod.resolved_target.result;
+ const platform = Platform.fromTarget(target);
if (platform.isBuildVersionCompatible()) {
// LC_BUILD_VERSION
sizeofcmds += @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
@@ -100,19 +100,19 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx
);
}
// LC_CODE_SIGNATURE
- if (MachO.requiresCodeSignature(options)) {
+ if (m.requiresCodeSignature()) {
sizeofcmds += @sizeOf(macho.linkedit_data_command);
}
- return @as(u32, @intCast(sizeofcmds));
+ return @intCast(sizeofcmds);
}
-pub fn calcMinHeaderPad(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx) !u64 {
- var padding: u32 = (try calcLCsSize(gpa, options, ctx, false)) + (options.headerpad_size orelse 0);
+pub fn calcMinHeaderPad(m: *MachO, ctx: CalcLCsSizeCtx) !u64 {
+ var padding: u32 = (try calcLCsSize(m, ctx, false)) + m.headerpad_size;
log.debug("minimum requested headerpad size 0x{x}", .{padding + @sizeOf(macho.mach_header_64)});
- if (options.headerpad_max_install_names) {
- const min_headerpad_size: u32 = try calcLCsSize(gpa, options, ctx, true);
+ if (m.headerpad_max_install_names) {
+ const min_headerpad_size: u32 = try calcLCsSize(m, ctx, true);
log.debug("headerpad_max_install_names minimum headerpad size 0x{x}", .{
min_headerpad_size + @sizeOf(macho.mach_header_64),
});
src/link/MachO/zld.zig
@@ -499,7 +499,7 @@ pub fn linkWithZld(
}
// Write code signature padding if required
- var codesig: ?CodeSignature = if (MachO.requiresCodeSignature(&macho_file.base.options)) blk: {
+ var codesig: ?CodeSignature = if (macho_file.requiresCodeSignature()) blk: {
// Preallocate space for the code signature.
// We need to do this at this stage so that we have the load commands with proper values
// written out to the file.
@@ -547,12 +547,12 @@ pub fn linkWithZld(
});
},
.Lib => if (link_mode == .Dynamic) {
- try load_commands.writeDylibIdLC(gpa, &macho_file.base.options, lc_writer);
+ try load_commands.writeDylibIdLC(macho_file, lc_writer);
},
else => {},
}
- try load_commands.writeRpathLCs(gpa, &macho_file.base.options, lc_writer);
+ try load_commands.writeRpathLCs(macho_file, lc_writer);
try lc_writer.writeStruct(macho.source_version_command{
.version = 0,
});
@@ -1072,11 +1072,10 @@ fn calcSectionSizes(macho_file: *MachO) !void {
}
fn allocateSegments(macho_file: *MachO) !void {
- const gpa = macho_file.base.allocator;
for (macho_file.segments.items, 0..) |*segment, segment_index| {
const is_text_segment = mem.eql(u8, segment.segName(), "__TEXT");
const base_size = if (is_text_segment)
- try load_commands.calcMinHeaderPad(gpa, &macho_file.base.options, .{
+ try load_commands.calcMinHeaderPad(macho_file, .{
.segments = macho_file.segments.items,
.dylibs = macho_file.dylibs.items,
.referenced_dylibs = macho_file.referenced_dylibs.keys(),
src/link/Dwarf.zig
@@ -1022,16 +1022,18 @@ const min_nop_size = 2;
/// actual_capacity + (actual_capacity / ideal_factor)
const ideal_factor = 3;
-pub fn init(allocator: Allocator, bin_file: *File, format: Format) Dwarf {
- const target = &bin_file.options.target;
+pub fn init(lf: *File, format: Format) Dwarf {
+ const comp = lf.comp;
+ const gpa = comp.gpa;
+ const target = comp.root_mod.resolved_target.result;
const ptr_width: PtrWidth = switch (target.ptrBitWidth()) {
0...32 => .p32,
33...64 => .p64,
else => unreachable,
};
return .{
- .allocator = allocator,
- .bin_file = bin_file,
+ .allocator = gpa,
+ .bin_file = lf,
.format = format,
.ptr_width = ptr_width,
.dbg_line_header = switch (target.cpu.arch) {
src/link/Elf.zig
@@ -1,5 +1,6 @@
base: link.File,
image_base: u64,
+rdynamic: bool,
ptr_width: PtrWidth,
@@ -358,19 +359,21 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf {
.debug_format = options.debug_format orelse .{ .dwarf = .@"32" },
.function_sections = options.function_sections,
.data_sections = options.data_sections,
-
- .image_base = b: {
- if (is_dyn_lib) break :b 0;
- if (output_mode == .Exe and comp.config.pie) return 0;
- return options.image_base orelse switch (ptr_width) {
- .p32 => 0x1000,
- .p64 => 0x1000000,
- };
- },
},
.ptr_width = ptr_width,
.page_size = page_size,
.default_sym_version = default_sym_version,
+
+ .image_base = b: {
+ if (is_dyn_lib) break :b 0;
+ if (output_mode == .Exe and comp.config.pie) break :b 0;
+ break :b options.image_base orelse switch (ptr_width) {
+ .p32 => 0x1000,
+ .p64 => 0x1000000,
+ };
+ },
+
+ .rdynamic = options.rdynamic,
};
if (use_llvm and comp.config.have_zcu) {
self.llvm_object = try LlvmObject.create(arena, options);
@@ -1006,7 +1009,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
break :blk path;
}
} else null;
- const gc_sections = self.base.gc_sections;
// --verbose-link
if (self.base.comp.verbose_link) try self.dumpArgv(comp);
@@ -1047,14 +1049,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
var rpath_table = std.StringArrayHashMap(void).init(gpa);
defer rpath_table.deinit();
- for (self.base.options.rpath_list) |rpath| {
+ for (self.base.rpath_list) |rpath| {
_ = try rpath_table.put(rpath, {});
}
- if (self.base.options.each_lib_rpath) {
+ if (self.each_lib_rpath) {
var test_path = std.ArrayList(u8).init(gpa);
defer test_path.deinit();
- for (self.base.options.lib_dirs) |lib_dir_path| {
+ for (self.lib_dirs) |lib_dir_path| {
for (self.base.comp.system_libs.keys()) |link_lib| {
if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic)))
continue;
@@ -1076,9 +1078,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
}
// libc
- if (!self.base.options.skip_linker_dependencies and
- !self.base.options.link_libc)
- {
+ if (!comp.skip_linker_dependencies and !comp.config.link_libc) {
if (comp.libc_static_lib) |lib| {
try positionals.append(.{ .path = lib.full_object_path });
}
@@ -1263,10 +1263,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
self.entry_index = if (entry) |name| self.globalByName(name) else null;
}
- if (gc_sections) {
+ if (self.base.gc_sections) {
try gc.gcAtoms(self);
- if (self.base.options.print_gc_sections) {
+ if (self.base.print_gc_sections) {
try gc.dumpPrunedAtoms(self);
}
}
@@ -1347,13 +1347,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
}
pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
- const gpa = self.base.comp.gpa;
+ const gpa = comp.gpa;
var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
defer positionals.deinit();
- try positionals.ensureUnusedCapacity(self.base.options.objects.len);
- positionals.appendSliceAssumeCapacity(self.base.options.objects);
+ try positionals.ensureUnusedCapacity(comp.objects.len);
+ positionals.appendSliceAssumeCapacity(comp.objects);
// This is a set of object files emitted by clang in a single `build-exe` invocation.
// For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
@@ -1495,8 +1495,8 @@ pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8)
var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
defer positionals.deinit();
- try positionals.ensureUnusedCapacity(self.base.options.objects.len);
- positionals.appendSliceAssumeCapacity(self.base.options.objects);
+ try positionals.ensureUnusedCapacity(comp.objects.len);
+ positionals.appendSliceAssumeCapacity(comp.objects);
// This is a set of object files emitted by clang in a single `build-exe` invocation.
// For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
@@ -1606,7 +1606,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
try argv.append(full_out_path);
if (self.base.isRelocatable()) {
- for (self.base.options.objects) |obj| {
+ for (comp.objects) |obj| {
try argv.append(obj.path);
}
@@ -1626,28 +1626,28 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
}
if (self.base.isDynLib()) {
- if (self.base.options.soname) |name| {
+ if (self.soname) |name| {
try argv.append("-soname");
try argv.append(name);
}
}
- if (self.base.options.entry) |entry| {
+ if (comp.config.entry) |entry| {
try argv.append("--entry");
try argv.append(entry);
}
- for (self.base.options.rpath_list) |rpath| {
+ for (self.base.rpath_list) |rpath| {
try argv.append("-rpath");
try argv.append(rpath);
}
- if (self.base.options.each_lib_rpath) {
- for (self.base.options.lib_dirs) |lib_dir_path| {
+ if (self.each_lib_rpath) {
+ for (self.lib_dirs) |lib_dir_path| {
try argv.append("-rpath");
try argv.append(lib_dir_path);
}
- for (self.base.options.objects) |obj| {
+ for (comp.objects) |obj| {
if (Compilation.classifyFileExt(obj.path) == .shared_library) {
const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue;
if (obj.loption) continue;
@@ -1669,29 +1669,29 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
try argv.append("--gc-sections");
}
- if (self.base.options.print_gc_sections) {
+ if (self.base.print_gc_sections) {
try argv.append("--print-gc-sections");
}
- if (self.base.options.eh_frame_hdr) {
+ if (self.eh_frame_hdr) {
try argv.append("--eh-frame-hdr");
}
- if (self.base.options.rdynamic) {
+ if (self.rdynamic) {
try argv.append("--export-dynamic");
}
- if (self.base.options.z_notext) {
+ if (self.z_notext) {
try argv.append("-z");
try argv.append("notext");
}
- if (self.base.options.z_nocopyreloc) {
+ if (self.z_nocopyreloc) {
try argv.append("-z");
try argv.append("nocopyreloc");
}
- if (self.base.options.z_now) {
+ if (self.z_now) {
try argv.append("-z");
try argv.append("now");
}
@@ -1702,11 +1702,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
try argv.append("-shared");
}
- if (self.base.options.pie and self.base.isExe()) {
+ if (comp.config.pie and self.base.isExe()) {
try argv.append("-pie");
}
- if (self.base.options.strip) {
+ if (self.base.debug_format == .strip) {
try argv.append("-s");
}
@@ -1715,12 +1715,12 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
if (csu.crti) |v| try argv.append(v);
if (csu.crtbegin) |v| try argv.append(v);
- for (self.base.options.lib_dirs) |lib_dir| {
+ for (self.lib_dirs) |lib_dir| {
try argv.append("-L");
try argv.append(lib_dir);
}
- if (self.base.options.link_libc) {
+ if (comp.config.link_libc) {
if (self.base.comp.libc_installation) |libc_installation| {
try argv.append("-L");
try argv.append(libc_installation.crt_dir.?);
@@ -1728,7 +1728,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
}
var whole_archive = false;
- for (self.base.options.objects) |obj| {
+ for (comp.objects) |obj| {
if (obj.must_link and !whole_archive) {
try argv.append("-whole-archive");
whole_archive = true;
@@ -1756,15 +1756,12 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
try argv.append(p);
}
- // TSAN
- if (self.base.options.tsan) {
+ if (comp.config.any_sanitize_thread) {
try argv.append(comp.tsan_static_lib.?.full_object_path);
}
// libc
- if (!self.base.options.skip_linker_dependencies and
- !self.base.options.link_libc)
- {
+ if (!comp.skip_linker_dependencies and !comp.config.link_libc) {
if (comp.libc_static_lib) |lib| {
try argv.append(lib.full_object_path);
}
@@ -1799,18 +1796,18 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
}
// libc++ dep
- if (self.base.options.link_libcpp) {
+ if (comp.config.link_libcpp) {
try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
try argv.append(comp.libcxx_static_lib.?.full_object_path);
}
// libunwind dep
- if (self.base.options.link_libunwind) {
+ if (comp.config.link_libunwind) {
try argv.append(comp.libunwind_static_lib.?.full_object_path);
}
// libc dep
- if (self.base.options.link_libc) {
+ if (comp.config.link_libc) {
if (self.base.comp.libc_installation != null) {
const needs_grouping = link_mode == .Static;
if (needs_grouping) try argv.append("--start-group");
@@ -1963,8 +1960,6 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
defer script.deinit(gpa);
try script.parse(data, self);
- const lib_dirs = self.base.options.lib_dirs;
-
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
@@ -1981,7 +1976,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
// TODO I think technically we should re-use the mechanism used by the frontend here.
// Maybe we should hoist search-strategy all the way here?
- for (lib_dirs) |lib_dir| {
+ for (self.lib_dirs) |lib_dir| {
if (!self.isStatic()) {
if (try self.accessLibPath(&test_path, &checked_paths, lib_dir, lib_name, .Dynamic))
break :success;
@@ -1998,7 +1993,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
} else |_| {}
try checked_paths.append(try gpa.dupe(u8, scr_obj.path));
- for (lib_dirs) |lib_dir| {
+ for (self.lib_dirs) |lib_dir| {
if (try self.accessLibPath(&test_path, &checked_paths, lib_dir, scr_obj.path, null))
break :success;
}
@@ -2338,7 +2333,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
const link_mode = self.base.comp.config.link_mode;
const is_dyn_lib = link_mode == .Dynamic and is_lib;
const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe;
- const have_dynamic_linker = self.base.options.link_libc and
+ const have_dynamic_linker = comp.config.link_libc and
link_mode == .Dynamic and is_exe_or_dyn_lib;
const target = self.base.comp.root_mod.resolved_target.result;
const compiler_rt_path: ?[]const u8 = blk: {
@@ -2358,11 +2353,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
const id_symlink_basename = "lld.id";
var man: Cache.Manifest = undefined;
- defer if (!self.base.options.disable_lld_caching) man.deinit();
+ defer if (!self.base.disable_lld_caching) man.deinit();
var digest: [Cache.hex_digest_len]u8 = undefined;
- if (!self.base.options.disable_lld_caching) {
+ if (!self.base.disable_lld_caching) {
man = comp.cache_parent.obtain();
// We are about to obtain this lock, so here we give other processes a chance first.
@@ -2370,9 +2365,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
comptime assert(Compilation.link_hash_implementation_version == 10);
- try man.addOptionalFile(self.base.options.linker_script);
- try man.addOptionalFile(self.base.options.version_script);
- for (self.base.options.objects) |obj| {
+ try man.addOptionalFile(self.linker_script);
+ try man.addOptionalFile(self.version_script);
+ for (comp.objects) |obj| {
_ = try man.addFile(obj.path, null);
man.hash.add(obj.must_link);
man.hash.add(obj.loption);
@@ -2385,34 +2380,34 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
// We can skip hashing libc and libc++ components that we are in charge of building from Zig
// installation sources because they are always a product of the compiler version + target information.
- man.hash.addOptionalBytes(self.base.options.entry);
+ man.hash.addOptionalBytes(comp.config.entry);
man.hash.addOptional(self.image_base);
man.hash.add(self.base.gc_sections);
- man.hash.addOptional(self.base.options.sort_section);
- man.hash.add(self.base.options.eh_frame_hdr);
- man.hash.add(self.base.options.emit_relocs);
- man.hash.add(self.base.options.rdynamic);
- man.hash.addListOfBytes(self.base.options.lib_dirs);
- man.hash.addListOfBytes(self.base.options.rpath_list);
- man.hash.add(self.base.options.each_lib_rpath);
+ man.hash.addOptional(self.sort_section);
+ man.hash.add(self.eh_frame_hdr);
+ man.hash.add(self.emit_relocs);
+ man.hash.add(self.rdynamic);
+ man.hash.addListOfBytes(self.lib_dirs);
+ man.hash.addListOfBytes(self.base.rpath_list);
+ man.hash.add(self.each_lib_rpath);
if (output_mode == .Exe) {
man.hash.add(self.base.stack_size);
man.hash.add(self.base.build_id);
}
- man.hash.addListOfBytes(self.base.options.symbol_wrap_set.keys());
- man.hash.add(self.base.options.skip_linker_dependencies);
- man.hash.add(self.base.options.z_nodelete);
- man.hash.add(self.base.options.z_notext);
- man.hash.add(self.base.options.z_defs);
- man.hash.add(self.base.options.z_origin);
- man.hash.add(self.base.options.z_nocopyreloc);
- man.hash.add(self.base.options.z_now);
- man.hash.add(self.base.options.z_relro);
- man.hash.add(self.base.options.z_common_page_size orelse 0);
- man.hash.add(self.base.options.z_max_page_size orelse 0);
- man.hash.add(self.base.options.hash_style);
+ man.hash.addListOfBytes(self.symbol_wrap_set.keys());
+ man.hash.add(comp.skip_linker_dependencies);
+ man.hash.add(self.z_nodelete);
+ man.hash.add(self.z_notext);
+ man.hash.add(self.z_defs);
+ man.hash.add(self.z_origin);
+ man.hash.add(self.z_nocopyreloc);
+ man.hash.add(self.z_now);
+ man.hash.add(self.z_relro);
+ man.hash.add(self.z_common_page_size orelse 0);
+ man.hash.add(self.z_max_page_size orelse 0);
+ man.hash.add(self.hash_style);
// strip does not need to go into the linker hash because it is part of the hash namespace
- if (self.base.options.link_libc) {
+ if (comp.config.link_libc) {
man.hash.add(self.base.comp.libc_installation != null);
if (self.base.comp.libc_installation) |libc_installation| {
man.hash.addBytes(libc_installation.crt_dir.?);
@@ -2421,16 +2416,16 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
man.hash.addOptionalBytes(target.dynamic_linker.get());
}
}
- man.hash.addOptionalBytes(self.base.options.soname);
- man.hash.addOptional(self.base.options.version);
+ man.hash.addOptionalBytes(self.soname);
+ man.hash.addOptional(comp.version);
try link.hashAddSystemLibs(&man, self.base.comp.system_libs);
- man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys());
+ man.hash.addListOfBytes(self.base.force_undefined_symbols.keys());
man.hash.add(self.base.allow_shlib_undefined);
- man.hash.add(self.base.options.bind_global_refs_locally);
- man.hash.add(self.base.options.compress_debug_sections);
- man.hash.add(self.base.options.tsan);
- man.hash.addOptionalBytes(self.base.options.sysroot);
- man.hash.add(self.base.options.linker_optimization);
+ man.hash.add(self.bind_global_refs_locally);
+ man.hash.add(self.compress_debug_sections);
+ man.hash.add(comp.config.any_sanitize_thread);
+ man.hash.addOptionalBytes(self.sysroot);
+ man.hash.add(self.optimization);
// We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
_ = try man.hit();
@@ -2466,14 +2461,14 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
// However, because LLD wants to resolve BPF relocations which it shouldn't, it fails
// before even generating the relocatable.
if (output_mode == .Obj and
- (self.base.options.lto or target.isBpfFreestanding()))
+ (comp.config.lto or target.isBpfFreestanding()))
{
// In this case we must do a simple file copy
// here. TODO: think carefully about how we can avoid this redundant operation when doing
// build-obj. See also the corresponding TODO in linkAsArchive.
const the_object_path = blk: {
- if (self.base.options.objects.len != 0)
- break :blk self.base.options.objects[0].path;
+ if (comp.objects.len != 0)
+ break :blk comp.objects[0].path;
if (comp.c_object_table.count() != 0)
break :blk comp.c_object_table.keys()[0].status.success.object_path;
@@ -2505,32 +2500,32 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
try argv.append("--error-limit=0");
- if (self.base.options.sysroot) |sysroot| {
+ if (self.sysroot) |sysroot| {
try argv.append(try std.fmt.allocPrint(arena, "--sysroot={s}", .{sysroot}));
}
- if (self.base.options.lto) {
- switch (self.base.options.optimize_mode) {
+ if (comp.config.lto) {
+ switch (comp.root_mod.optimize_mode) {
.Debug => {},
.ReleaseSmall => try argv.append("--lto-O2"),
.ReleaseFast, .ReleaseSafe => try argv.append("--lto-O3"),
}
}
try argv.append(try std.fmt.allocPrint(arena, "-O{d}", .{
- self.base.options.linker_optimization,
+ self.optimization,
}));
- if (self.base.options.entry) |entry| {
+ if (comp.config.entry) |entry| {
try argv.append("--entry");
try argv.append(entry);
}
- for (self.base.options.force_undefined_symbols.keys()) |sym| {
+ for (self.base.force_undefined_symbols.keys()) |sym| {
try argv.append("-u");
try argv.append(sym);
}
- switch (self.base.options.hash_style) {
+ switch (self.hash_style) {
.gnu => try argv.append("--hash-style=gnu"),
.sysv => try argv.append("--hash-style=sysv"),
.both => {}, // this is the default
@@ -2559,12 +2554,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{self.image_base}));
- if (self.base.options.linker_script) |linker_script| {
+ if (self.linker_script) |linker_script| {
try argv.append("-T");
try argv.append(linker_script);
}
- if (self.base.options.sort_section) |how| {
+ if (self.sort_section) |how| {
const arg = try std.fmt.allocPrint(arena, "--sort-section={s}", .{@tagName(how)});
try argv.append(arg);
}
@@ -2573,67 +2568,67 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
try argv.append("--gc-sections");
}
- if (self.base.options.print_gc_sections) {
+ if (self.base.print_gc_sections) {
try argv.append("--print-gc-sections");
}
- if (self.base.options.print_icf_sections) {
+ if (self.print_icf_sections) {
try argv.append("--print-icf-sections");
}
- if (self.base.options.print_map) {
+ if (self.print_map) {
try argv.append("--print-map");
}
- if (self.base.options.eh_frame_hdr) {
+ if (self.eh_frame_hdr) {
try argv.append("--eh-frame-hdr");
}
- if (self.base.options.emit_relocs) {
+ if (self.emit_relocs) {
try argv.append("--emit-relocs");
}
- if (self.base.options.rdynamic) {
+ if (self.rdynamic) {
try argv.append("--export-dynamic");
}
- if (self.base.options.strip) {
+ if (self.base.debug_format == .strip) {
try argv.append("-s");
}
- if (self.base.options.z_nodelete) {
+ if (self.z_nodelete) {
try argv.append("-z");
try argv.append("nodelete");
}
- if (self.base.options.z_notext) {
+ if (self.z_notext) {
try argv.append("-z");
try argv.append("notext");
}
- if (self.base.options.z_defs) {
+ if (self.z_defs) {
try argv.append("-z");
try argv.append("defs");
}
- if (self.base.options.z_origin) {
+ if (self.z_origin) {
try argv.append("-z");
try argv.append("origin");
}
- if (self.base.options.z_nocopyreloc) {
+ if (self.z_nocopyreloc) {
try argv.append("-z");
try argv.append("nocopyreloc");
}
- if (self.base.options.z_now) {
+ if (self.z_now) {
// LLD defaults to -zlazy
try argv.append("-znow");
}
- if (!self.base.options.z_relro) {
+ if (!self.z_relro) {
// LLD defaults to -zrelro
try argv.append("-znorelro");
}
- if (self.base.options.z_common_page_size) |size| {
+ if (self.z_common_page_size) |size| {
try argv.append("-z");
try argv.append(try std.fmt.allocPrint(arena, "common-page-size={d}", .{size}));
}
- if (self.base.options.z_max_page_size) |size| {
+ if (self.z_max_page_size) |size| {
try argv.append("-z");
try argv.append(try std.fmt.allocPrint(arena, "max-page-size={d}", .{size}));
}
@@ -2658,7 +2653,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
try argv.append("-shared");
}
- if (self.base.options.pie and output_mode == .Exe) {
+ if (comp.config.pie and output_mode == .Exe) {
try argv.append("-pie");
}
@@ -2683,20 +2678,20 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
// rpaths
var rpath_table = std.StringHashMap(void).init(gpa);
defer rpath_table.deinit();
- for (self.base.options.rpath_list) |rpath| {
+ for (self.base.rpath_list) |rpath| {
if ((try rpath_table.fetchPut(rpath, {})) == null) {
try argv.append("-rpath");
try argv.append(rpath);
}
}
- for (self.base.options.symbol_wrap_set.keys()) |symbol_name| {
+ for (self.symbol_wrap_set.keys()) |symbol_name| {
try argv.appendSlice(&.{ "-wrap", symbol_name });
}
- if (self.base.options.each_lib_rpath) {
+ if (self.each_lib_rpath) {
var test_path = std.ArrayList(u8).init(arena);
- for (self.base.options.lib_dirs) |lib_dir_path| {
+ for (self.lib_dirs) |lib_dir_path| {
for (self.base.comp.system_libs.keys()) |link_lib| {
if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic)))
continue;
@@ -2706,7 +2701,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
}
}
}
- for (self.base.options.objects) |obj| {
+ for (comp.objects) |obj| {
if (Compilation.classifyFileExt(obj.path) == .shared_library) {
const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue;
if (obj.loption) continue;
@@ -2719,12 +2714,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
}
}
- for (self.base.options.lib_dirs) |lib_dir| {
+ for (self.lib_dirs) |lib_dir| {
try argv.append("-L");
try argv.append(lib_dir);
}
- if (self.base.options.link_libc) {
+ if (comp.config.link_libc) {
if (self.base.comp.libc_installation) |libc_installation| {
try argv.append("-L");
try argv.append(libc_installation.crt_dir.?);
@@ -2739,11 +2734,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
}
if (is_dyn_lib) {
- if (self.base.options.soname) |soname| {
+ if (self.soname) |soname| {
try argv.append("-soname");
try argv.append(soname);
}
- if (self.base.options.version_script) |version_script| {
+ if (self.version_script) |version_script| {
try argv.append("-version-script");
try argv.append(version_script);
}
@@ -2751,7 +2746,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
// Positional arguments to the linker such as object files.
var whole_archive = false;
- for (self.base.options.objects) |obj| {
+ for (comp.objects) |obj| {
if (obj.must_link and !whole_archive) {
try argv.append("-whole-archive");
whole_archive = true;
@@ -2779,15 +2774,14 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
try argv.append(p);
}
- // TSAN
- if (self.base.options.tsan) {
+ if (comp.config.any_sanitize_thread) {
try argv.append(comp.tsan_static_lib.?.full_object_path);
}
// libc
if (is_exe_or_dyn_lib and
- !self.base.options.skip_linker_dependencies and
- !self.base.options.link_libc)
+ !comp.skip_linker_dependencies and
+ !comp.config.link_libc)
{
if (comp.libc_static_lib) |lib| {
try argv.append(lib.full_object_path);
@@ -2832,19 +2826,19 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
}
// libc++ dep
- if (self.base.options.link_libcpp) {
+ if (comp.config.link_libcpp) {
try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
try argv.append(comp.libcxx_static_lib.?.full_object_path);
}
// libunwind dep
- if (self.base.options.link_libunwind) {
+ if (comp.config.link_libunwind) {
try argv.append(comp.libunwind_static_lib.?.full_object_path);
}
// libc dep
self.error_flags.missing_libc = false;
- if (self.base.options.link_libc) {
+ if (comp.config.link_libc) {
if (self.base.comp.libc_installation != null) {
const needs_grouping = link_mode == .Static;
if (needs_grouping) try argv.append("--start-group");
@@ -2884,13 +2878,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
try argv.append("--allow-shlib-undefined");
}
- switch (self.base.options.compress_debug_sections) {
+ switch (self.compress_debug_sections) {
.none => {},
.zlib => try argv.append("--compress-debug-sections=zlib"),
.zstd => try argv.append("--compress-debug-sections=zstd"),
}
- if (self.base.options.bind_global_refs_locally) {
+ if (self.bind_global_refs_locally) {
try argv.append("-Bsymbolic");
}
@@ -2964,7 +2958,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
}
}
- if (!self.base.options.disable_lld_caching) {
+ if (!self.base.disable_lld_caching) {
// Update the file with the digest. If it fails we can continue; it only
// means that the next invocation will have an unnecessary cache miss.
Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
@@ -3101,7 +3095,8 @@ fn writeElfHeader(self: *Elf) !void {
};
index += 1;
- const target = self.base.comp.root_mod.resolved_target.result;
+ const comp = self.base.comp;
+ const target = comp.root_mod.resolved_target.result;
const endian = target.cpu.arch.endian();
hdr_buf[index] = switch (endian) {
.little => elf.ELFDATA2LSB,
@@ -3120,10 +3115,10 @@ fn writeElfHeader(self: *Elf) !void {
assert(index == 16);
- const output_mode = self.base.comp.config.output_mode;
- const link_mode = self.base.comp.config.link_mode;
+ const output_mode = comp.config.output_mode;
+ const link_mode = comp.config.link_mode;
const elf_type: elf.ET = switch (output_mode) {
- .Exe => if (self.base.options.pie) .DYN else .EXEC,
+ .Exe => if (comp.config.pie) .DYN else .EXEC,
.Obj => .REL,
.Lib => switch (link_mode) {
.Static => @as(elf.ET, .REL),
@@ -3283,7 +3278,7 @@ fn addLinkerDefinedSymbols(self: *Elf) !void {
self.plt_index = try linker_defined.addGlobal("_PROCEDURE_LINKAGE_TABLE_", self);
self.end_index = try linker_defined.addGlobal("_end", self);
- if (self.base.options.eh_frame_hdr) {
+ if (self.eh_frame_hdr) {
self.gnu_eh_frame_hdr_index = try linker_defined.addGlobal("__GNU_EH_FRAME_HDR", self);
}
@@ -3314,7 +3309,8 @@ fn addLinkerDefinedSymbols(self: *Elf) !void {
}
fn allocateLinkerDefinedSymbols(self: *Elf) void {
- const link_mode = self.base.comp.config.link_mode;
+ const comp = self.base.comp;
+ const link_mode = comp.config.link_mode;
// _DYNAMIC
if (self.dynamic_section_index) |shndx| {
@@ -3398,7 +3394,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
// __rela_iplt_start, __rela_iplt_end
if (self.rela_dyn_section_index) |shndx| blk: {
- if (link_mode != .Static or self.base.options.pie) break :blk;
+ if (link_mode != .Static or comp.config.pie) break :blk;
const shdr = &self.shdrs.items[shndx];
const end_addr = shdr.sh_addr + shdr.sh_size;
const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);
@@ -3445,7 +3441,8 @@ fn initOutputSections(self: *Elf) !void {
}
fn initSyntheticSections(self: *Elf) !void {
- const target = self.base.comp.root_mod.resolved_target.result;
+ const comp = self.base.comp;
+ const target = comp.root_mod.resolved_target.result;
const ptr_size = self.ptrWidthBytes();
const needs_eh_frame = for (self.objects.items) |index| {
@@ -3460,7 +3457,7 @@ fn initSyntheticSections(self: *Elf) !void {
.offset = std.math.maxInt(u64),
});
- if (self.base.options.eh_frame_hdr) {
+ if (self.eh_frame_hdr) {
self.eh_frame_hdr_section_index = try self.addSection(.{
.name = ".eh_frame_hdr",
.type = elf.SHT_PROGBITS,
@@ -3554,7 +3551,7 @@ fn initSyntheticSections(self: *Elf) !void {
// In this case, if we do generate .interp section and segment, we will get
// a segfault in the dynamic linker trying to load a binary that is static
// and doesn't contain .dynamic section.
- if (self.isStatic() and !self.base.options.pie) break :blk false;
+ if (self.isStatic() and !comp.config.pie) break :blk false;
break :blk target.dynamic_linker.get() != null;
};
if (needs_interp) {
@@ -3567,7 +3564,7 @@ fn initSyntheticSections(self: *Elf) !void {
});
}
- if (self.base.isDynLib() or self.shared_objects.items.len > 0 or self.base.options.pie) {
+ if (self.base.isDynLib() or self.shared_objects.items.len > 0 or comp.config.pie) {
self.dynstrtab_section_index = try self.addSection(.{
.name = ".dynstr",
.flags = elf.SHF_ALLOC,
@@ -3859,7 +3856,7 @@ fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {
}
if (self.base.isDynLib()) {
- if (self.base.options.soname) |soname| {
+ if (self.soname) |soname| {
try self.dynamic.setSoname(soname, self);
}
}
src/link/MachO.zig
@@ -252,7 +252,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO {
self.d_sym = .{
.allocator = gpa,
- .dwarf = link.File.Dwarf.init(gpa, &self.base, .dwarf32),
+ .dwarf = link.File.Dwarf.init(&self.base, .dwarf32),
.file = d_sym_file,
};
}
@@ -573,7 +573,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
try self.writeLinkeditSegmentData();
- var codesig: ?CodeSignature = if (requiresCodeSignature(&self.base.options)) blk: {
+ var codesig: ?CodeSignature = if (self.requiresCodeSignature()) blk: {
// Preallocate space for the code signature.
// We need to do this at this stage so that we have the load commands with proper values
// written out to the file.
@@ -619,12 +619,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
});
},
.Lib => if (self.base.comp.config.link_mode == .Dynamic) {
- try load_commands.writeDylibIdLC(gpa, &self.base.options, lc_writer);
+ try load_commands.writeDylibIdLC(self, lc_writer);
},
else => {},
}
- try load_commands.writeRpathLCs(gpa, &self.base.options, lc_writer);
+ try load_commands.writeRpathLCs(self, lc_writer);
try lc_writer.writeStruct(macho.source_version_command{
.version = 0,
});
@@ -713,7 +713,7 @@ pub fn resolveLibSystem(
success: {
if (self.sdk_layout) |sdk_layout| switch (sdk_layout) {
.sdk => {
- const dir = try fs.path.join(arena, &[_][]const u8{ self.base.options.sysroot.?, "usr", "lib" });
+ const dir = try fs.path.join(arena, &[_][]const u8{ comp.sysroot.?, "usr", "lib" });
if (try accessLibPath(arena, &test_path, &checked_paths, dir, "libSystem")) break :success;
},
.vendored => {
@@ -1156,7 +1156,8 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype) !void {
// 2) afterwards, we parse dependents of the included dylibs
// TODO this should not be performed if the user specifies `-flat_namespace` flag.
// See ld64 manpages.
- const gpa = self.base.comp.gpa;
+ const comp = self.base.comp;
+ const gpa = comp.gpa;
while (dependent_libs.readItem()) |dep_id| {
defer dep_id.id.deinit(gpa);
@@ -1176,7 +1177,7 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype) !void {
var checked_paths = std.ArrayList([]const u8).init(arena);
success: {
- if (self.base.options.sysroot) |root| {
+ if (comp.sysroot) |root| {
const dir = try fs.path.join(arena, &[_][]const u8{ root, dirname });
if (try accessLibPath(gpa, &test_path, &checked_paths, dir, stem)) break :success;
}
@@ -1713,12 +1714,12 @@ pub fn resolveSymbols(self: *MachO) !void {
// we search for it in libraries should there be no object files specified
// on the linker line.
if (output_mode == .Exe) {
- const entry_name = self.base.options.entry orelse load_commands.default_entry_point;
+ const entry_name = comp.config.entry.?;
_ = try self.addUndefined(entry_name, .{});
}
// Force resolution of any symbols requested by the user.
- for (self.base.options.force_undefined_symbols.keys()) |sym_name| {
+ for (self.base.force_undefined_symbols.keys()) |sym_name| {
_ = try self.addUndefined(sym_name, .{});
}
@@ -4367,7 +4368,7 @@ fn writeSymtab(self: *MachO) !SymtabCtx {
// We generate stabs last in order to ensure that the strtab always has debug info
// strings trailing
- if (!self.base.options.strip) {
+ if (self.base.debug_format != .strip) {
for (self.objects.items) |object| {
assert(self.d_sym == null); // TODO
try self.generateSymbolStabs(object, &locals);
@@ -5171,7 +5172,8 @@ pub fn getStubsEntryAddress(self: *MachO, sym_with_loc: SymbolWithLoc) ?u64 {
/// Returns symbol location corresponding to the set entrypoint if any.
/// Asserts output mode is executable.
pub fn getEntryPoint(self: MachO) ?SymbolWithLoc {
- const entry_name = self.base.options.entry orelse load_commands.default_entry_point;
+ const comp = self.base.comp;
+ const entry_name = comp.config.entry orelse return null;
const global = self.getGlobal(entry_name) orelse return null;
return global;
}
@@ -5189,11 +5191,13 @@ pub inline fn getPageSize(cpu_arch: std.Target.Cpu.Arch) u16 {
};
}
-pub fn requiresCodeSignature(options: *const link.Options) bool {
- if (options.entitlements) |_| return true;
- const cpu_arch = options.target.cpu.arch;
- const os_tag = options.target.os.tag;
- const abi = options.target.abi;
+pub fn requiresCodeSignature(m: *MachO) bool {
+ if (m.entitlements) |_| return true;
+ const comp = m.base.comp;
+ const target = comp.root_mod.resolved_target.result;
+ const cpu_arch = target.cpu.arch;
+ const os_tag = target.os.tag;
+ const abi = target.abi;
if (cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator)) return true;
return false;
}
src/link/NvPtx.zig
@@ -57,6 +57,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx {
.build_id = options.build_id,
.rpath_list = options.rpath_list,
.force_undefined_symbols = options.force_undefined_symbols,
+ .debug_format = options.debug_format orelse .{ .dwarf = .@"32" },
.function_sections = options.function_sections,
.data_sections = options.data_sections,
},
@@ -66,7 +67,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx {
return nvptx;
}
-pub fn open(arena: Allocator, options: link.FileOpenOptions) !*NvPtx {
+pub fn open(arena: Allocator, options: link.File.OpenOptions) !*NvPtx {
const target = options.comp.root_mod.resolved_target.result;
assert(target.ofmt == .nvptx);
return createEmpty(arena, options);
src/link/Plan9.zig
@@ -295,26 +295,36 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {
}
pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Plan9 {
- _ = arena;
- const target = options.comp.root_mod.resolved_target.result;
- const gpa = options.comp.gpa;
+ const comp = options.comp;
+ const target = comp.root_mod.resolved_target.result;
+ const gpa = comp.gpa;
+ const optimize_mode = comp.root_mod.optimize_mode;
+ const output_mode = comp.config.output_mode;
- const sixtyfour_bit: bool = switch (options.target.ptrBitWidth()) {
+ const sixtyfour_bit: bool = switch (target.ptrBitWidth()) {
0...32 => false,
33...64 => true,
else => return error.UnsupportedP9Architecture,
};
- const arena_allocator = std.heap.ArenaAllocator.init(gpa);
-
- const self = try gpa.create(Plan9);
+ const self = try arena.create(Plan9);
self.* = .{
- .path_arena = arena_allocator,
+ .path_arena = std.heap.ArenaAllocator.init(gpa),
.base = .{
.tag = .plan9,
- .options = options,
- .allocator = gpa,
+ .comp = comp,
+ .emit = options.emit,
+ .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj),
+ .stack_size = options.stack_size orelse 16777216,
+ .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
.file = null,
+ .disable_lld_caching = options.disable_lld_caching,
+ .build_id = options.build_id,
+ .rpath_list = options.rpath_list,
+ .force_undefined_symbols = options.force_undefined_symbols,
+ .debug_format = options.debug_format orelse .{ .dwarf = .@"32" },
+ .function_sections = options.function_sections,
+ .data_sections = options.data_sections,
},
.sixtyfour_bit = sixtyfour_bit,
.bases = undefined,
@@ -602,7 +612,7 @@ pub fn flush(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) li
const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;
assert(!use_lld);
- switch (self.base.options.effectiveOutputMode()) {
+ switch (link.File.effectiveOutputMode(use_lld, comp.config.output_mode)) {
.Exe => {},
// plan9 object files are totally different
.Obj => return error.TODOImplementPlan9Objs,
src/link/SpirV.zig
@@ -67,6 +67,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*SpirV {
.force_undefined_symbols = options.force_undefined_symbols,
.function_sections = options.function_sections,
.data_sections = options.data_sections,
+ .debug_format = options.debug_format orelse .{ .dwarf = .@"32" },
},
.object = codegen.Object.init(gpa),
};
@@ -102,7 +103,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*SpirV {
errdefer spirv.base.destroy();
// TODO: read the file and keep valid parts instead of truncating
- const file = try options.emit.?.directory.handle.createFile(options.emit.sub_path, .{
+ const file = try options.emit.directory.handle.createFile(options.emit.sub_path, .{
.truncate = true,
.read = true,
});
src/link/Wasm.zig
@@ -37,6 +37,13 @@ pub const Relocation = types.Relocation;
pub const base_tag: link.File.Tag = .wasm;
base: link.File,
+import_symbols: bool,
+export_symbol_names: []const []const u8,
+rdynamic: bool,
+global_base: ?u64,
+initial_memory: ?u64,
+max_memory: ?u64,
+wasi_emulated_libs: []const wasi_libc.CRTFile,
/// Output name of the file
name: []const u8,
/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
@@ -368,13 +375,15 @@ pub const StringTable = struct {
pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm {
if (build_options.only_c) unreachable;
- const gpa = options.comp.gpa;
- const target = options.comp.root_mod.resolved_target.result;
+ const comp = options.comp;
+ const gpa = comp.gpa;
+ const target = comp.root_mod.resolved_target.result;
assert(target.ofmt == .wasm);
- const use_lld = build_options.have_llvm and options.comp.config.use_lld;
- const use_llvm = options.comp.config.use_llvm;
- const output_mode = options.comp.config.output_mode;
+ const use_lld = build_options.have_llvm and comp.config.use_lld;
+ const use_llvm = comp.config.use_llvm;
+ const output_mode = comp.config.output_mode;
+ const shared_memory = comp.config.shared_memory;
const wasm = try createEmpty(arena, options);
errdefer wasm.base.destroy();
@@ -395,7 +404,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm {
};
// TODO: read the file and keep valid parts instead of truncating
- const file = try options.emit.?.directory.handle.createFile(sub_path, .{
+ const file = try options.emit.directory.handle.createFile(sub_path, .{
.truncate = true,
.read = true,
.mode = if (fs.has_executable_bit)
@@ -480,7 +489,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm {
}
// shared-memory symbols for TLS support
- if (wasm.base.options.shared_memory) {
+ if (shared_memory) {
{
const loc = try wasm.createSyntheticSymbol("__tls_base", .global);
const symbol = loc.getSymbol(wasm);
@@ -522,14 +531,15 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm {
}
pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm {
- const use_llvm = options.comp.config.use_llvm;
- const output_mode = options.comp.config.output_mode;
+ const comp = options.comp;
+ const use_llvm = comp.config.use_llvm;
+ const output_mode = comp.config.output_mode;
const wasm = try arena.create(Wasm);
wasm.* = .{
.base = .{
.tag = .wasm,
- .comp = options.comp,
+ .comp = comp,
.emit = options.emit,
.gc_sections = options.gc_sections orelse (output_mode != .Obj),
.stack_size = options.stack_size orelse std.wasm.page_size * 16, // 1MB
@@ -546,6 +556,13 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm {
.name = undefined,
.import_table = options.import_table,
.export_table = options.export_table,
+ .import_symbols = options.import_symbols,
+ .export_symbol_names = options.export_symbol_names,
+ .rdynamic = options.rdynamic,
+ .global_base = options.global_base,
+ .initial_memory = options.initial_memory,
+ .max_memory = options.max_memory,
+ .wasi_emulated_libs = options.wasi_emulated_libs,
};
if (use_llvm) {
@@ -909,7 +926,10 @@ fn writeI32Const(writer: anytype, val: u32) !void {
}
fn setupInitMemoryFunction(wasm: *Wasm) !void {
- const gpa = wasm.base.comp.gpa;
+ const comp = wasm.base.comp;
+ const gpa = comp.gpa;
+ const shared_memory = comp.config.shared_memory;
+ const import_memory = comp.config.import_memory;
// Passive segments are used to avoid memory being reinitialized on each
// thread's instantiation. These passive segments are initialized and
@@ -920,7 +940,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
return;
}
- const flag_address: u32 = if (wasm.base.options.shared_memory) address: {
+ const flag_address: u32 = if (shared_memory) address: {
// when we have passive initialization segments and shared memory
// `setupMemory` will create this symbol and set its virtual address.
const loc = wasm.findGlobalSymbol("__wasm_init_memory_flag").?;
@@ -934,7 +954,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
// we have 0 locals
try leb.writeULEB128(writer, @as(u32, 0));
- if (wasm.base.options.shared_memory) {
+ if (shared_memory) {
// destination blocks
// based on values we jump to corresponding label
try writer.writeByte(std.wasm.opcode(.block)); // $drop
@@ -968,14 +988,14 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
var segment_index: u32 = 0;
while (it.next()) |entry| : (segment_index += 1) {
const segment: Segment = wasm.segments.items[entry.value_ptr.*];
- if (segment.needsPassiveInitialization(wasm.base.options.import_memory, entry.key_ptr.*)) {
+ if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) {
// For passive BSS segments we can simple issue a memory.fill(0).
// For non-BSS segments we do a memory.init. Both these
// instructions take as their first argument the destination
// address.
try writeI32Const(writer, segment.offset);
- if (wasm.base.options.shared_memory and std.mem.eql(u8, entry.key_ptr.*, ".tdata")) {
+ if (shared_memory and std.mem.eql(u8, entry.key_ptr.*, ".tdata")) {
// When we initialize the TLS segment we also set the `__tls_base`
// global. This allows the runtime to use this static copy of the
// TLS data for the first/main thread.
@@ -1000,7 +1020,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
}
}
- if (wasm.base.options.shared_memory) {
+ if (shared_memory) {
// we set the init memory flag to value '2'
try writeI32Const(writer, flag_address);
try writeI32Const(writer, 2);
@@ -1043,12 +1063,12 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
while (it.next()) |entry| : (segment_index += 1) {
const name = entry.key_ptr.*;
const segment: Segment = wasm.segments.items[entry.value_ptr.*];
- if (segment.needsPassiveInitialization(wasm.base.options.import_memory, name) and
+ if (segment.needsPassiveInitialization(import_memory, name) and
!std.mem.eql(u8, name, ".bss"))
{
// The TLS region should not be dropped since its is needed
// during the initialization of each thread (__wasm_init_tls).
- if (wasm.base.options.shared_memory and std.mem.eql(u8, name, ".tdata")) {
+ if (shared_memory and std.mem.eql(u8, name, ".tdata")) {
continue;
}
@@ -1071,11 +1091,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
/// Constructs a synthetic function that performs runtime relocations for
/// TLS symbols. This function is called by `__wasm_init_tls`.
fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
- const gpa = wasm.base.comp.gpa;
+ const comp = wasm.base.comp;
+ const gpa = comp.gpa;
+ const shared_memory = comp.config.shared_memory;
// When we have TLS GOT entries and shared memory is enabled,
// we must perform runtime relocations or else we don't create the function.
- if (!wasm.base.options.shared_memory or !wasm.requiresTLSReloc()) {
+ if (!shared_memory or !wasm.requiresTLSReloc()) {
return;
}
@@ -1119,7 +1141,9 @@ fn validateFeatures(
to_emit: *[@typeInfo(types.Feature.Tag).Enum.fields.len]bool,
emit_features_count: *u32,
) !void {
- const target = wasm.base.comp.root_mod.resolved_target.result;
+ const comp = wasm.base.comp;
+ const target = comp.root_mod.resolved_target.result;
+ const shared_memory = comp.config.shared_memory;
const cpu_features = target.cpu.features;
const infer = cpu_features.isEmpty(); // when the user did not define any features, we infer them from linked objects.
const known_features_count = @typeInfo(types.Feature.Tag).Enum.fields.len;
@@ -1190,7 +1214,7 @@ fn validateFeatures(
return error.InvalidFeatureSet;
}
- if (wasm.base.options.shared_memory) {
+ if (shared_memory) {
const disallowed_feature = disallowed[@intFromEnum(types.Feature.Tag.shared_mem)];
if (@as(u1, @truncate(disallowed_feature)) != 0) {
log.err(
@@ -1255,7 +1279,9 @@ fn validateFeatures(
/// if one or multiple undefined references exist. When none exist, the symbol will
/// not be created, ensuring we don't unneccesarily emit unreferenced symbols.
fn resolveLazySymbols(wasm: *Wasm) !void {
- const gpa = wasm.base.comp.gpa;
+ const comp = wasm.base.comp;
+ const gpa = comp.gpa;
+ const shared_memory = comp.config.shared_memory;
if (wasm.string_table.getOffset("__heap_base")) |name_offset| {
if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
@@ -1273,7 +1299,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
}
}
- if (!wasm.base.options.shared_memory) {
+ if (!shared_memory) {
if (wasm.string_table.getOffset("__tls_base")) |name_offset| {
if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global);
@@ -1306,8 +1332,9 @@ pub fn findGlobalSymbol(wasm: *Wasm, name: []const u8) ?SymbolLoc {
}
fn checkUndefinedSymbols(wasm: *const Wasm) !void {
- if (wasm.base.comp.config.output_mode == .Obj) return;
- if (wasm.base.options.import_symbols) return;
+ const comp = wasm.base.comp;
+ if (comp.config.output_mode == .Obj) return;
+ if (wasm.import_symbols) return;
var found_undefined_symbols = false;
for (wasm.undefs.values()) |undef| {
@@ -2182,7 +2209,10 @@ const Kind = union(enum) {
/// Parses an Atom and inserts its metadata into the corresponding sections.
fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
- const gpa = wasm.base.comp.gpa;
+ const comp = wasm.base.comp;
+ const gpa = comp.gpa;
+ const shared_memory = comp.config.shared_memory;
+ const import_memory = comp.config.import_memory;
const atom = wasm.getAtomPtr(atom_index);
const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm);
const do_garbage_collect = wasm.base.gc_sections;
@@ -2233,7 +2263,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
// we set the entire region of it to zeroes.
// We do not have to do this when exporting the memory (the default) because the runtime
// will do it for us, and we do not emit the bss segment at all.
- if ((wasm.base.comp.config.output_mode == .Obj or wasm.base.options.import_memory) and kind.data == .uninitialized) {
+ if ((wasm.base.comp.config.output_mode == .Obj or import_memory) and kind.data == .uninitialized) {
@memset(atom.code.items, 0);
}
@@ -2250,7 +2280,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
} else {
const index: u32 = @intCast(wasm.segments.items.len);
var flags: u32 = 0;
- if (wasm.base.options.shared_memory) {
+ if (shared_memory) {
flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
}
try wasm.segments.append(gpa, .{
@@ -2679,9 +2709,11 @@ fn setupStartSection(wasm: *Wasm) !void {
}
fn initializeTLSFunction(wasm: *Wasm) !void {
- const gpa = wasm.base.comp.gpa;
+ const comp = wasm.base.comp;
+ const gpa = comp.gpa;
+ const shared_memory = comp.config.shared_memory;
- if (!wasm.base.options.shared_memory) return;
+ if (!shared_memory) return;
var function_body = std.ArrayList(u8).init(gpa);
defer function_body.deinit();
@@ -2940,7 +2972,7 @@ fn setupExports(wasm: *Wasm) !void {
if (wasm.base.comp.config.output_mode == .Obj) return;
log.debug("Building exports from symbols", .{});
- const force_exp_names = wasm.base.options.export_symbol_names;
+ const force_exp_names = wasm.export_symbol_names;
if (force_exp_names.len > 0) {
var failed_exports = false;
@@ -2962,7 +2994,7 @@ fn setupExports(wasm: *Wasm) !void {
for (wasm.resolved_symbols.keys()) |sym_loc| {
const symbol = sym_loc.getSymbol(wasm);
- if (!symbol.isExported(wasm.base.options.rdynamic)) continue;
+ if (!symbol.isExported(wasm.rdynamic)) continue;
const sym_name = sym_loc.getName(wasm);
const export_name = if (wasm.export_names.get(sym_loc)) |name| name else blk: {
@@ -2997,8 +3029,9 @@ fn setupExports(wasm: *Wasm) !void {
}
fn setupStart(wasm: *Wasm) !void {
+ const comp = wasm.base.comp;
// do not export entry point if user set none or no default was set.
- const entry_name = wasm.base.options.entry orelse return;
+ const entry_name = comp.config.entry orelse return;
const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse {
log.err("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name});
@@ -3012,13 +3045,15 @@ fn setupStart(wasm: *Wasm) !void {
}
// Ensure the symbol is exported so host environment can access it
- if (wasm.base.comp.config.output_mode != .Obj) {
+ if (comp.config.output_mode != .Obj) {
symbol.setFlag(.WASM_SYM_EXPORTED);
}
}
/// Sets up the memory section of the wasm module, as well as the stack.
fn setupMemory(wasm: *Wasm) !void {
+ const comp = wasm.base.comp;
+ const shared_memory = comp.config.shared_memory;
log.debug("Setting up memory layout", .{});
const page_size = std.wasm.page_size; // 64kb
const stack_alignment: Alignment = .@"16"; // wasm's stack alignment as specified by tool-convention
@@ -3027,12 +3062,12 @@ fn setupMemory(wasm: *Wasm) !void {
// Always place the stack at the start by default
// unless the user specified the global-base flag
var place_stack_first = true;
- var memory_ptr: u64 = if (wasm.base.options.global_base) |base| blk: {
+ var memory_ptr: u64 = if (wasm.global_base) |base| blk: {
place_stack_first = false;
break :blk base;
} else 0;
- const is_obj = wasm.base.comp.config.output_mode == .Obj;
+ const is_obj = comp.config.output_mode == .Obj;
if (place_stack_first and !is_obj) {
memory_ptr = stack_alignment.forward(memory_ptr);
@@ -3059,7 +3094,7 @@ fn setupMemory(wasm: *Wasm) !void {
}
if (wasm.findGlobalSymbol("__tls_base")) |loc| {
const sym = loc.getSymbol(wasm);
- wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (wasm.base.options.shared_memory)
+ wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory)
@as(i32, 0)
else
@as(i32, @intCast(memory_ptr));
@@ -3072,7 +3107,7 @@ fn setupMemory(wasm: *Wasm) !void {
}
// create the memory init flag which is used by the init memory function
- if (wasm.base.options.shared_memory and wasm.hasPassiveInitializationSegments()) {
+ if (shared_memory and wasm.hasPassiveInitializationSegments()) {
// align to pointer size
memory_ptr = mem.alignForward(u64, memory_ptr, 4);
const loc = try wasm.createSyntheticSymbol("__wasm_init_memory_flag", .data);
@@ -3098,7 +3133,7 @@ fn setupMemory(wasm: *Wasm) !void {
// For now we only support wasm32 by setting the maximum allowed memory size 2^32-1
const max_memory_allowed: u64 = (1 << 32) - 1;
- if (wasm.base.options.initial_memory) |initial_memory| {
+ if (wasm.initial_memory) |initial_memory| {
if (!std.mem.isAlignedGeneric(u64, initial_memory, page_size)) {
log.err("Initial memory must be {d}-byte aligned", .{page_size});
return error.MissAlignment;
@@ -3124,7 +3159,7 @@ fn setupMemory(wasm: *Wasm) !void {
symbol.virtual_address = @as(u32, @intCast(memory_ptr));
}
- if (wasm.base.options.max_memory) |max_memory| {
+ if (wasm.max_memory) |max_memory| {
if (!std.mem.isAlignedGeneric(u64, max_memory, page_size)) {
log.err("Maximum memory must be {d}-byte aligned", .{page_size});
return error.MissAlignment;
@@ -3139,7 +3174,7 @@ fn setupMemory(wasm: *Wasm) !void {
}
wasm.memories.limits.max = @as(u32, @intCast(max_memory / page_size));
wasm.memories.limits.setFlag(.WASM_LIMITS_FLAG_HAS_MAX);
- if (wasm.base.options.shared_memory) {
+ if (shared_memory) {
wasm.memories.limits.setFlag(.WASM_LIMITS_FLAG_IS_SHARED);
}
log.debug("Maximum memory pages: {?d}", .{wasm.memories.limits.max});
@@ -3150,20 +3185,22 @@ fn setupMemory(wasm: *Wasm) !void {
/// index of the segment within the final data section. When the segment does not yet
/// exist, a new one will be initialized and appended. The new index will be returned in that case.
pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u32 {
- const gpa = wasm.base.comp.gpa;
+ const comp = wasm.base.comp;
+ const gpa = comp.gpa;
const object: Object = wasm.objects.items[object_index];
const symbol = object.symtable[symbol_index];
const index: u32 = @intCast(wasm.segments.items.len);
+ const shared_memory = comp.config.shared_memory;
switch (symbol.tag) {
.data => {
const segment_info = object.segment_info[symbol.index];
- const merge_segment = wasm.base.comp.config.output_mode != .Obj;
+ const merge_segment = comp.config.output_mode != .Obj;
const result = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(merge_segment));
if (!result.found_existing) {
result.value_ptr.* = index;
var flags: u32 = 0;
- if (wasm.base.options.shared_memory) {
+ if (shared_memory) {
flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
}
try wasm.segments.append(gpa, .{
@@ -3445,6 +3482,8 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
defer tracy.end();
const gpa = wasm.base.comp.gpa;
+ const shared_memory = comp.config.shared_memory;
+ const import_memory = comp.config.import_memory;
// Used for all temporary memory allocated during flushin
var arena_instance = std.heap.ArenaAllocator.init(gpa);
@@ -3509,8 +3548,8 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
man.hash.addOptionalBytes(wasm.base.comp.config.entry);
man.hash.add(wasm.base.stack_size);
man.hash.add(wasm.base.build_id);
- man.hash.add(wasm.base.comp.config.import_memory);
- man.hash.add(wasm.base.comp.config.shared_memory);
+ man.hash.add(import_memory);
+ man.hash.add(shared_memory);
man.hash.add(wasm.import_table);
man.hash.add(wasm.export_table);
man.hash.addOptional(wasm.initial_memory);
@@ -3726,8 +3765,12 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
} else if (Value.fromInterned(variable.init).isUndefDeep(mod)) {
// for safe build modes, we store the atom in the data segment,
// whereas for unsafe build modes we store it in bss.
- const is_initialized = wasm.base.options.optimize_mode == .Debug or
- wasm.base.options.optimize_mode == .ReleaseSafe;
+ const decl_namespace = mod.namespacePtr(decl.src_namespace);
+ const optimize_mode = decl_namespace.file_scope.mod.optimize_mode;
+ const is_initialized = switch (optimize_mode) {
+ .Debug, .ReleaseSafe => true,
+ .ReleaseFast, .ReleaseSmall => false,
+ };
try wasm.parseAtom(atom_index, .{ .data = if (is_initialized) .initialized else .uninitialized });
} else {
// when the decl is all zeroes, we store the atom in the bss segment,
@@ -3788,9 +3831,13 @@ fn writeToFile(
feature_count: u32,
arena: Allocator,
) !void {
- const gpa = wasm.base.comp.gpa;
- const use_llvm = wasm.base.comp.config.use_llvm;
- const use_lld = build_options.have_llvm and wasm.base.comp.config.use_lld;
+ const comp = wasm.base.comp;
+ const gpa = comp.gpa;
+ const use_llvm = comp.config.use_llvm;
+ const use_lld = build_options.have_llvm and comp.config.use_lld;
+ const shared_memory = comp.config.shared_memory;
+ const import_memory = comp.config.import_memory;
+ const export_memory = comp.config.export_memory;
// Size of each section header
const header_size = 5 + 1;
@@ -3800,7 +3847,7 @@ fn writeToFile(
var code_section_index: ?u32 = null;
// Index of the data section. Used to tell relocation table where the section lives.
var data_section_index: ?u32 = null;
- const is_obj = wasm.base.comp.config.output_mode == .Obj or (!use_llvm and use_lld);
+ const is_obj = comp.config.output_mode == .Obj or (!use_llvm and use_lld);
var binary_bytes = std.ArrayList(u8).init(gpa);
defer binary_bytes.deinit();
@@ -3840,8 +3887,6 @@ fn writeToFile(
}
// Import section
- const import_memory = wasm.base.options.import_memory or is_obj;
- const export_memory = wasm.base.options.export_memory;
if (wasm.imports.count() != 0 or import_memory) {
const header_offset = try reserveVecSectionHeader(&binary_bytes);
@@ -4018,7 +4063,7 @@ fn writeToFile(
// When the shared-memory option is enabled, we *must* emit the 'data count' section.
const data_segments_count = wasm.data_segments.count() - @intFromBool(wasm.data_segments.contains(".bss") and !import_memory);
- if (data_segments_count != 0 and wasm.base.options.shared_memory) {
+ if (data_segments_count != 0 and shared_memory) {
const header_offset = try reserveVecSectionHeader(&binary_bytes);
try writeVecSectionHeader(
binary_bytes.items,
@@ -4160,11 +4205,11 @@ fn writeToFile(
if (data_section_index) |data_index| {
try wasm.emitDataRelocations(&binary_bytes, data_index, symbol_table);
}
- } else if (!wasm.base.options.strip) {
+ } else if (wasm.base.debug_format != .strip) {
try wasm.emitNameSection(&binary_bytes, arena);
}
- if (!wasm.base.options.strip) {
+ if (wasm.base.debug_format != .strip) {
// The build id must be computed on the main sections only,
// so we have to do it now, before the debug sections.
switch (wasm.base.build_id) {
@@ -4193,7 +4238,7 @@ fn writeToFile(
}
// if (wasm.dwarf) |*dwarf| {
- // const mod = wasm.base.comp.module.?;
+ // const mod = comp.module.?;
// try dwarf.writeDbgAbbrev();
// // for debug info and ranges, the address is always 0,
// // as locations are always offsets relative to 'code' section.
@@ -4380,6 +4425,8 @@ fn emitFeaturesSection(binary_bytes: *std.ArrayList(u8), enabled_features: []con
}
fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem.Allocator) !void {
+ const comp = wasm.base.comp;
+ const import_memory = comp.config.import_memory;
const Name = struct {
index: u32,
name: []const u8,
@@ -4418,7 +4465,7 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem
for (wasm.data_segments.keys()) |key| {
// bss section is not emitted when this condition holds true, so we also
// do not output a name for it.
- if (!wasm.base.options.import_memory and std.mem.eql(u8, key, ".bss")) continue;
+ if (!import_memory and std.mem.eql(u8, key, ".bss")) continue;
segments.appendAssumeCapacity(.{ .index = data_segment_index, .name = key });
data_segment_index += 1;
}
@@ -4528,6 +4575,11 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
const tracy = trace(@src());
defer tracy.end();
+ const shared_memory = comp.config.shared_memory;
+ const export_memory = comp.config.export_memory;
+ const import_memory = comp.config.import_memory;
+ const target = comp.root_mod.resolved_target.result;
+
const gpa = wasm.base.comp.gpa;
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
defer arena_allocator.deinit();
@@ -4560,8 +4612,6 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
break :blk null;
};
- const target = wasm.base.comp.root_mod.resolved_target.result;
-
const id_symlink_basename = "lld.id";
var man: Cache.Manifest = undefined;
@@ -4577,7 +4627,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
comptime assert(Compilation.link_hash_implementation_version == 10);
- for (wasm.base.options.objects) |obj| {
+ for (comp.objects) |obj| {
_ = try man.addFile(obj.path, null);
man.hash.add(obj.must_link);
}
@@ -4589,17 +4639,17 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
man.hash.addOptionalBytes(wasm.base.comp.config.entry);
man.hash.add(wasm.base.stack_size);
man.hash.add(wasm.base.build_id);
- man.hash.add(wasm.base.options.import_memory);
- man.hash.add(wasm.base.options.export_memory);
+ man.hash.add(import_memory);
+ man.hash.add(export_memory);
man.hash.add(wasm.import_table);
man.hash.add(wasm.export_table);
- man.hash.addOptional(wasm.base.options.initial_memory);
- man.hash.addOptional(wasm.base.options.max_memory);
- man.hash.add(wasm.base.options.shared_memory);
- man.hash.addOptional(wasm.base.options.global_base);
- man.hash.add(wasm.base.options.export_symbol_names.len);
+ man.hash.addOptional(wasm.initial_memory);
+ man.hash.addOptional(wasm.max_memory);
+ man.hash.add(shared_memory);
+ man.hash.addOptional(wasm.global_base);
+ man.hash.add(wasm.export_symbol_names.len);
// strip does not need to go into the linker hash because it is part of the hash namespace
- for (wasm.base.options.export_symbol_names) |symbol_name| {
+ for (wasm.export_symbol_names) |symbol_name| {
man.hash.addBytes(symbol_name);
}
@@ -4637,8 +4687,8 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
// here. TODO: think carefully about how we can avoid this redundant operation when doing
// build-obj. See also the corresponding TODO in linkAsArchive.
const the_object_path = blk: {
- if (wasm.base.options.objects.len != 0)
- break :blk wasm.base.options.objects[0].path;
+ if (comp.objects.len != 0)
+ break :blk comp.objects[0].path;
if (comp.c_object_table.count() != 0)
break :blk comp.c_object_table.keys()[0].status.success.object_path;
@@ -4666,19 +4716,19 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command });
try argv.append("--error-limit=0");
- if (wasm.base.options.lto) {
- switch (wasm.base.options.optimize_mode) {
+ if (comp.config.lto) {
+ switch (comp.root_mod.optimize_mode) {
.Debug => {},
.ReleaseSmall => try argv.append("-O2"),
.ReleaseFast, .ReleaseSafe => try argv.append("-O3"),
}
}
- if (wasm.base.options.import_memory) {
+ if (import_memory) {
try argv.append("--import-memory");
}
- if (wasm.base.options.export_memory) {
+ if (export_memory) {
try argv.append("--export-memory");
}
@@ -4698,25 +4748,25 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
try argv.append("--no-gc-sections");
}
- if (wasm.base.options.strip) {
+ if (wasm.base.debug_format == .strip) {
try argv.append("-s");
}
- if (wasm.base.options.initial_memory) |initial_memory| {
+ if (wasm.initial_memory) |initial_memory| {
const arg = try std.fmt.allocPrint(arena, "--initial-memory={d}", .{initial_memory});
try argv.append(arg);
}
- if (wasm.base.options.max_memory) |max_memory| {
+ if (wasm.max_memory) |max_memory| {
const arg = try std.fmt.allocPrint(arena, "--max-memory={d}", .{max_memory});
try argv.append(arg);
}
- if (wasm.base.options.shared_memory) {
+ if (shared_memory) {
try argv.append("--shared-memory");
}
- if (wasm.base.options.global_base) |global_base| {
+ if (wasm.global_base) |global_base| {
const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base});
try argv.append(arg);
} else {
@@ -4728,16 +4778,16 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
}
// Users are allowed to specify which symbols they want to export to the wasm host.
- for (wasm.base.options.export_symbol_names) |symbol_name| {
+ for (wasm.export_symbol_names) |symbol_name| {
const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name});
try argv.append(arg);
}
- if (wasm.base.options.rdynamic) {
+ if (wasm.rdynamic) {
try argv.append("--export-dynamic");
}
- if (wasm.base.options.entry) |entry| {
+ if (comp.config.entry) |entry| {
try argv.append("--entry");
try argv.append(entry);
} else {
@@ -4749,14 +4799,14 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
try std.fmt.allocPrint(arena, "stack-size={d}", .{wasm.base.stack_size}),
});
- if (wasm.base.options.import_symbols) {
+ if (wasm.import_symbols) {
try argv.append("--allow-undefined");
}
if (wasm.base.comp.config.output_mode == .Lib and wasm.base.comp.config.link_mode == .Dynamic) {
try argv.append("--shared");
}
- if (wasm.base.options.pie) {
+ if (comp.config.pie) {
try argv.append("--pie");
}
@@ -4782,15 +4832,15 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
));
}
- if (wasm.base.options.link_libc) {
+ if (comp.config.link_libc) {
try argv.append(try comp.get_libc_crt_file(
arena,
- wasi_libc.execModelCrtFileFullName(wasm.base.options.wasi_exec_model),
+ wasi_libc.execModelCrtFileFullName(comp.config.wasi_exec_model),
));
try argv.append(try comp.get_libc_crt_file(arena, "libc.a"));
}
- if (wasm.base.options.link_libcpp) {
+ if (comp.config.link_libcpp) {
try argv.append(comp.libcxx_static_lib.?.full_object_path);
try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
}
@@ -4799,7 +4849,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
// Positional arguments to the linker such as object files.
var whole_archive = false;
- for (wasm.base.options.objects) |obj| {
+ for (comp.objects) |obj| {
if (obj.must_link and !whole_archive) {
try argv.append("-whole-archive");
whole_archive = true;
@@ -4822,8 +4872,8 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
}
if (wasm.base.comp.config.output_mode != .Obj and
- !wasm.base.options.skip_linker_dependencies and
- !wasm.base.options.link_libc)
+ !comp.skip_linker_dependencies and
+ !comp.config.link_libc)
{
try argv.append(comp.libc_static_lib.?.full_object_path);
}
@@ -5168,10 +5218,13 @@ fn emitDataRelocations(
}
fn hasPassiveInitializationSegments(wasm: *const Wasm) bool {
+ const comp = wasm.base.comp;
+ const import_memory = comp.config.import_memory;
+
var it = wasm.data_segments.iterator();
while (it.next()) |entry| {
const segment: Segment = wasm.segments.items[entry.value_ptr.*];
- if (segment.needsPassiveInitialization(wasm.base.options.import_memory, entry.key_ptr.*)) {
+ if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) {
return true;
}
}
@@ -5227,14 +5280,14 @@ fn markReferences(wasm: *Wasm) !void {
for (wasm.resolved_symbols.keys()) |sym_loc| {
const sym = sym_loc.getSymbol(wasm);
- if (sym.isExported(wasm.base.options.rdynamic) or sym.isNoStrip() or !do_garbage_collect) {
+ if (sym.isExported(wasm.rdynamic) or sym.isNoStrip() or !do_garbage_collect) {
try wasm.mark(sym_loc);
continue;
}
// Debug sections may require to be parsed and marked when it contains
// relocations to alive symbols.
- if (sym.tag == .section and !wasm.base.options.strip) {
+ if (sym.tag == .section and wasm.base.debug_format != .strip) {
const file = sym_loc.file orelse continue; // Incremental debug info is done independently
const object = &wasm.objects.items[file];
const atom_index = try Object.parseSymbolIntoAtom(object, file, sym_loc.index, wasm);
src/Compilation.zig
@@ -76,6 +76,7 @@ framework_dirs: []const []const u8,
system_libs: std.StringArrayHashMapUnmanaged(SystemLib),
version: ?std.SemanticVersion,
libc_installation: ?*const LibCInstallation,
+skip_linker_dependencies: bool,
c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{},
win32_resource_table: if (build_options.only_core_functionality) void else std.AutoArrayHashMapUnmanaged(*Win32Resource, void) =
@@ -940,7 +941,7 @@ pub const InitOptions = struct {
/// * getpid
/// * mman
/// * signal
- wasi_emulated_libs: []const wasi_libc.CRTFile = &[0]wasi_libc.CRTFile{},
+ wasi_emulated_libs: []const wasi_libc.CRTFile = &.{},
/// This means that if the output mode is an executable it will be a
/// Position Independent Executable. If the output mode is not an
/// executable this field is ignored.
@@ -1238,7 +1239,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
const sysroot = options.sysroot orelse libc_dirs.sysroot;
const include_compiler_rt = options.want_compiler_rt orelse
- (!options.skip_linker_dependencies and is_exe_or_dyn_lib);
+ (!comp.skip_linker_dependencies and is_exe_or_dyn_lib);
if (include_compiler_rt and output_mode == .Obj) {
// For objects, this mechanism relies on essentially `_ = @import("compiler-rt");`
@@ -1639,6 +1640,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.objects = options.link_objects,
.framework_dirs = options.framework_dirs,
.llvm_opt_bisect_limit = options.llvm_opt_bisect_limit,
+ .skip_linker_dependencies = options.skip_linker_dependencies,
};
if (bin_file_emit) |emit| {
@@ -1695,7 +1697,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.soname = options.soname,
.compatibility_version = options.compatibility_version,
.dll_export_fns = dll_export_fns,
- .skip_linker_dependencies = options.skip_linker_dependencies,
.parent_compilation_link_libc = options.parent_compilation_link_libc,
.each_lib_rpath = each_lib_rpath,
.build_id = build_id,
@@ -1765,9 +1766,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
}
}
- const have_bin_emit = comp.bin_file.options.emit != null or comp.whole_bin_sub_path != null;
+ const have_bin_emit = comp.bin_file != null or comp.whole_bin_sub_path != null;
- if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies and target.ofmt != .c) {
+ if (have_bin_emit and !comp.skip_linker_dependencies and target.ofmt != .c) {
if (target.isDarwin()) {
switch (target.abi) {
.none,
@@ -1808,27 +1809,34 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.{ .musl_crt_file = .crt1_o },
.{ .musl_crt_file = .scrt1_o },
.{ .musl_crt_file = .rcrt1_o },
- switch (comp.bin_file.options.link_mode) {
+ switch (comp.config.link_mode) {
.Static => .{ .musl_crt_file = .libc_a },
.Dynamic => .{ .musl_crt_file = .libc_so },
},
});
}
- if (comp.wantBuildWasiLibcFromSource()) {
- if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
- const wasi_emulated_libs = comp.bin_file.options.wasi_emulated_libs;
- try comp.work_queue.ensureUnusedCapacity(wasi_emulated_libs.len + 2); // worst-case we need all components
- for (wasi_emulated_libs) |crt_file| {
- comp.work_queue.writeItemAssumeCapacity(.{
- .wasi_libc_crt_file = crt_file,
- });
+ if (comp.bin_file) |lf| {
+ if (lf.cast(link.File.Wasm)) |wasm| {
+ if (comp.wantBuildWasiLibcFromSource()) {
+ if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
+
+ // worst-case we need all components
+ try comp.work_queue.ensureUnusedCapacity(wasm.wasi_emulated_libs.len + 2);
+
+ for (wasm.wasi_emulated_libs) |crt_file| {
+ comp.work_queue.writeItemAssumeCapacity(.{
+ .wasi_libc_crt_file = crt_file,
+ });
+ }
+ comp.work_queue.writeAssumeCapacity(&[_]Job{
+ .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(options.config.wasi_exec_model) },
+ .{ .wasi_libc_crt_file = .libc_a },
+ });
+ }
}
- comp.work_queue.writeAssumeCapacity(&[_]Job{
- .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(options.config.wasi_exec_model) },
- .{ .wasi_libc_crt_file = .libc_a },
- });
}
+
if (comp.wantBuildMinGWFromSource()) {
if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
@@ -1863,27 +1871,29 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
if (comp.wantBuildLibUnwindFromSource()) {
try comp.work_queue.writeItem(.{ .libunwind = {} });
}
- if (build_options.have_llvm and is_exe_or_dyn_lib and comp.bin_file.options.link_libcpp) {
+ if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) {
try comp.work_queue.writeItem(.libcxx);
try comp.work_queue.writeItem(.libcxxabi);
}
- if (build_options.have_llvm and comp.bin_file.options.tsan) {
+ if (build_options.have_llvm and comp.config.any_sanitize_thread) {
try comp.work_queue.writeItem(.libtsan);
}
- if (comp.getTarget().isMinGW() and comp.config.any_non_single_threaded) {
- // LLD might drop some symbols as unused during LTO and GCing, therefore,
- // we force mark them for resolution here.
+ if (comp.bin_file) |lf| {
+ if (comp.getTarget().isMinGW() and comp.config.any_non_single_threaded) {
+ // LLD might drop some symbols as unused during LTO and GCing, therefore,
+ // we force mark them for resolution here.
- const tls_index_sym = switch (comp.getTarget().cpu.arch) {
- .x86 => "__tls_index",
- else => "_tls_index",
- };
+ const tls_index_sym = switch (comp.getTarget().cpu.arch) {
+ .x86 => "__tls_index",
+ else => "_tls_index",
+ };
- try comp.bin_file.options.force_undefined_symbols.put(comp.gpa, tls_index_sym, {});
+ try lf.force_undefined_symbols.put(comp.gpa, tls_index_sym, {});
+ }
}
- if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) {
+ if (comp.include_compiler_rt and capable_of_building_compiler_rt) {
if (is_exe_or_dyn_lib) {
log.debug("queuing a job to build compiler_rt_lib", .{});
comp.job_queued_compiler_rt_lib = true;
@@ -1895,8 +1905,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
}
}
- if (!comp.bin_file.options.skip_linker_dependencies and is_exe_or_dyn_lib and
- !comp.bin_file.options.link_libc and capable_of_building_zig_libc)
+ if (!comp.skip_linker_dependencies and is_exe_or_dyn_lib and
+ !comp.config.link_libc and capable_of_building_zig_libc)
{
try comp.work_queue.writeItem(.{ .zig_libc = {} });
}
@@ -2425,7 +2435,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
man.hash.add(comp.test_evented_io);
man.hash.addOptionalBytes(comp.test_filter);
man.hash.addOptionalBytes(comp.test_name_prefix);
- man.hash.add(comp.bin_file.options.skip_linker_dependencies);
+ man.hash.add(comp.skip_linker_dependencies);
man.hash.add(comp.formatted_panics);
man.hash.add(mod.emit_h != null);
man.hash.add(mod.error_limit);
@@ -2477,7 +2487,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys());
man.hash.add(comp.bin_file.options.each_lib_rpath);
man.hash.add(comp.bin_file.build_id);
- man.hash.add(comp.bin_file.options.skip_linker_dependencies);
+ man.hash.add(comp.skip_linker_dependencies);
man.hash.add(comp.bin_file.options.z_nodelete);
man.hash.add(comp.bin_file.options.z_notext);
man.hash.add(comp.bin_file.options.z_defs);
@@ -2489,7 +2499,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
man.hash.add(comp.bin_file.options.z_max_page_size orelse 0);
man.hash.add(comp.bin_file.options.hash_style);
man.hash.add(comp.bin_file.options.compress_debug_sections);
- man.hash.add(comp.bin_file.options.include_compiler_rt);
+ man.hash.add(comp.include_compiler_rt);
man.hash.add(comp.bin_file.options.sort_section);
if (comp.config.link_libc) {
man.hash.add(comp.bin_file.options.libc_installation != null);
@@ -3836,7 +3846,7 @@ pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest {
// Also nothing that applies only to compiling .zig code.
man.hash.add(comp.sanitize_c);
man.hash.addListOfBytes(comp.clang_argv);
- man.hash.add(comp.bin_file.options.link_libcpp);
+ man.hash.add(comp.config.link_libcpp);
// When libc_installation is null it means that Zig generated this dir list
// based on the zig library directory alone. The zig lib directory file
@@ -4909,7 +4919,7 @@ pub fn addCCArgs(
try argv.append("-fno-builtin");
}
- if (comp.bin_file.options.link_libcpp) {
+ if (comp.config.link_libcpp) {
const libcxx_include_path = try std.fs.path.join(arena, &[_][]const u8{
comp.zig_lib_directory.path.?, "libcxx", "include",
});
@@ -4954,7 +4964,7 @@ pub fn addCCArgs(
try argv.append(libunwind_include_path);
}
- if (comp.bin_file.options.link_libc and target.isGnuLibC()) {
+ if (comp.config.link_libc and target.isGnuLibC()) {
const target_version = target.os.version_range.linux.glibc;
const glibc_minor_define = try std.fmt.allocPrint(arena, "-D__GLIBC_MINOR__={d}", .{
target_version.minor,
@@ -5944,7 +5954,7 @@ fn wantBuildLibCFromSource(comp: Compilation) bool {
.Lib => comp.bin_file.options.link_mode == .Dynamic,
.Exe => true,
};
- return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and
+ return comp.config.link_libc and is_exe_or_dyn_lib and
comp.bin_file.options.libc_installation == null and
comp.bin_file.options.target.ofmt != .c;
}
@@ -6164,6 +6174,7 @@ fn buildOutputFromZig(
.have_zcu = true,
.emit_bin = true,
.root_optimize_mode = comp.compilerRtOptMode(),
+ .link_libc = comp.config.link_libc,
});
const root_mod = Package.Module.create(.{
@@ -6224,7 +6235,6 @@ fn buildOutputFromZig(
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.skip_linker_dependencies = true,
- .link_libc = comp.bin_file.options.link_libc,
.want_structured_cfg = comp.bin_file.options.want_structured_cfg,
});
defer sub_compilation.destroy();
@@ -6305,7 +6315,6 @@ pub fn build_crt_file(
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.skip_linker_dependencies = true,
- .link_libc = comp.bin_file.options.link_libc,
.want_structured_cfg = comp.bin_file.options.want_structured_cfg,
});
defer sub_compilation.destroy();
@@ -6327,7 +6336,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
// This can happen when the user uses `build-exe foo.obj -lkernel32` and
// then when we create a sub-Compilation for zig libc, it also tries to
// build kernel32.lib.
- if (comp.bin_file.options.skip_linker_dependencies) return;
+ if (comp.skip_linker_dependencies) return;
// This happens when an `extern "foo"` function is referenced.
// If we haven't seen this library yet and we're targeting Windows, we need
src/libtsan.zig
@@ -119,7 +119,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) !void {
});
}
- const to_c_or_not_to_c_sources = if (comp.bin_file.options.link_libc)
+ const to_c_or_not_to_c_sources = if (comp.config.link_libc)
&sanitizer_libcdep_sources
else
&sanitizer_nolibc_sources;
src/link.zig
@@ -133,7 +133,6 @@ pub const File = struct {
export_symbol_names: []const []const u8,
global_base: ?u64,
dll_export_fns: bool,
- skip_linker_dependencies: bool,
parent_compilation_link_libc: bool,
each_lib_rpath: bool,
build_id: std.zig.BuildId,
@@ -1099,7 +1098,7 @@ pub const File = struct {
}
pub fn isStatic(self: File) bool {
- return self.base.comp.config.link_mode == .Static;
+ return self.comp.config.link_mode == .Static;
}
pub fn isObject(self: File) bool {
src/Sema.zig
@@ -5742,7 +5742,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
const msg = try sema.errMsg(&child_block, src, "C import failed", .{});
errdefer msg.destroy(gpa);
- if (!comp.bin_file.options.link_libc)
+ if (!comp.config.link_libc)
try sema.errNote(&child_block, src, msg, "libc headers not available; compilation does not link against libc", .{});
const gop = try mod.cimport_errors.getOrPut(gpa, sema.owner_decl_index);
@@ -9058,7 +9058,7 @@ fn resolveGenericBody(
/// Given a library name, examines if the library name should end up in
/// `link.File.Options.system_libs` table (for example, libc is always
-/// specified via dedicated flag `link.File.Options.link_libc` instead),
+/// specified via dedicated flag `link_libc` instead),
/// and puts it there if it doesn't exist.
/// It also dupes the library name which can then be saved as part of the
/// respective `Decl` (either `ExternFn` or `Var`).
@@ -9076,7 +9076,7 @@ fn handleExternLibName(
const target = mod.getTarget();
log.debug("extern fn symbol expected in lib '{s}'", .{lib_name});
if (target.is_libc_lib_name(lib_name)) {
- if (!comp.bin_file.options.link_libc) {
+ if (!comp.config.link_libc) {
return sema.fail(
block,
src_loc,
@@ -9087,18 +9087,21 @@ fn handleExternLibName(
break :blk;
}
if (target.is_libcpp_lib_name(lib_name)) {
- if (!comp.bin_file.options.link_libcpp) {
- return sema.fail(
- block,
- src_loc,
- "dependency on libc++ must be explicitly specified in the build command",
- .{},
- );
- }
+ if (!comp.config.link_libcpp) return sema.fail(
+ block,
+ src_loc,
+ "dependency on libc++ must be explicitly specified in the build command",
+ .{},
+ );
break :blk;
}
if (mem.eql(u8, lib_name, "unwind")) {
- comp.bin_file.options.link_libunwind = true;
+ if (!comp.config.link_libunwind) return sema.fail(
+ block,
+ src_loc,
+ "dependency on libunwind must be explicitly specified in the build command",
+ .{},
+ );
break :blk;
}
if (!target.isWasm() and !comp.bin_file.options.pic) {