mirror of
https://github.com/ziglang/zig.git
synced 2025-12-08 07:13:08 +00:00
branch fixes
This commit is contained in:
parent
5ca54036ca
commit
c2898c436f
@ -25,7 +25,7 @@ pub const available_libcs = [_]ArchOsAbi{
|
||||
.{ .arch = .thumbeb, .os = .linux, .abi = .musleabihf },
|
||||
.{ .arch = .aarch64, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 17, .patch = 0 } },
|
||||
.{ .arch = .aarch64, .os = .linux, .abi = .musl },
|
||||
.{ .arch = .aarch64, .os = .macos, .abi = .none, .os_ver = .{ .major = 11, .minor = 0, .patch = 0 } },
|
||||
.{ .arch = .aarch64, .os = .macos, .abi = .none, .os_ver = .{ .major = 13, .minor = 0, .patch = 0 } },
|
||||
.{ .arch = .aarch64, .os = .windows, .abi = .gnu },
|
||||
.{ .arch = .aarch64_be, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 17, .patch = 0 } },
|
||||
.{ .arch = .aarch64_be, .os = .linux, .abi = .musl },
|
||||
@ -74,7 +74,7 @@ pub const available_libcs = [_]ArchOsAbi{
|
||||
.{ .arch = .x86_64, .os = .linux, .abi = .gnu },
|
||||
.{ .arch = .x86_64, .os = .linux, .abi = .gnux32 },
|
||||
.{ .arch = .x86_64, .os = .linux, .abi = .musl },
|
||||
.{ .arch = .x86_64, .os = .macos, .abi = .none, .os_ver = .{ .major = 10, .minor = 7, .patch = 0 } },
|
||||
.{ .arch = .x86_64, .os = .macos, .abi = .none, .os_ver = .{ .major = 13, .minor = 0, .patch = 0 } },
|
||||
.{ .arch = .x86_64, .os = .windows, .abi = .gnu },
|
||||
};
|
||||
|
||||
|
||||
@ -49,6 +49,8 @@ pub const Config = @import("Compilation/Config.zig");
|
||||
gpa: Allocator,
|
||||
/// Arena-allocated memory, mostly used during initialization. However, it can
|
||||
/// be used for other things requiring the same lifetime as the `Compilation`.
|
||||
/// Not thread-safe - lock `mutex` if potentially accessing from multiple
|
||||
/// threads at once.
|
||||
arena: Allocator,
|
||||
/// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`.
|
||||
zcu: ?*Zcu,
|
||||
@ -1760,21 +1762,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
|
||||
.incremental => comp.bin_file != null,
|
||||
};
|
||||
|
||||
if (have_bin_emit and !comp.skip_linker_dependencies and target.ofmt != .c) {
|
||||
if (target.isDarwin()) {
|
||||
switch (target.abi) {
|
||||
.none,
|
||||
.simulator,
|
||||
.macabi,
|
||||
=> {},
|
||||
else => return error.LibCUnavailable,
|
||||
}
|
||||
}
|
||||
// If we need to build glibc for the target, add work items for it.
|
||||
if (have_bin_emit and target.ofmt != .c) {
|
||||
if (!comp.skip_linker_dependencies) {
|
||||
// If we need to build libc for the target, add work items for it.
|
||||
// We go through the work queue so that building can be done in parallel.
|
||||
// If linking against host libc installation, instead queue up jobs
|
||||
// for loading those files in the linker.
|
||||
if (comp.config.link_libc and is_exe_or_dyn_lib and target.ofmt != .c) {
|
||||
if (comp.config.link_libc and is_exe_or_dyn_lib) {
|
||||
if (comp.libc_installation) |lci| {
|
||||
const basenames = LibCInstallation.CrtBasenames.get(.{
|
||||
.target = target,
|
||||
@ -1868,6 +1862,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
|
||||
// When linking mingw-w64 there are some import libs we always need.
|
||||
try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len);
|
||||
for (mingw.always_link_libs) |name| comp.windows_libs.putAssumeCapacity(name, {});
|
||||
} else if (target.isDarwin()) {
|
||||
switch (target.abi) {
|
||||
.none, .simulator, .macabi => {},
|
||||
else => return error.LibCUnavailable,
|
||||
}
|
||||
} else if (target.os.tag == .freestanding and capable_of_building_zig_libc) {
|
||||
try comp.queueJob(.{ .zig_libc = {} });
|
||||
} else {
|
||||
return error.LibCUnavailable;
|
||||
}
|
||||
@ -1921,11 +1922,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
|
||||
comp.job_queued_fuzzer_lib = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!comp.skip_linker_dependencies and is_exe_or_dyn_lib and
|
||||
!comp.config.link_libc and capable_of_building_zig_libc)
|
||||
{
|
||||
try comp.queueJob(.{ .zig_libc = {} });
|
||||
}
|
||||
|
||||
try comp.link_task_queue.shared.append(gpa, .load_explicitly_provided);
|
||||
@ -3521,7 +3517,7 @@ fn performAllTheWorkInner(
|
||||
defer work_queue_wait_group.wait();
|
||||
|
||||
if (comp.bin_file) |lf| {
|
||||
if (try comp.link_task_queue.enqueue(comp.gpa, &.{.load_explicitly_provided})) {
|
||||
if (comp.link_task_queue.start()) {
|
||||
comp.thread_pool.spawnWg(work_queue_wait_group, link.File.flushTaskQueue, .{ lf, main_progress_node });
|
||||
}
|
||||
}
|
||||
@ -4980,7 +4976,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
|
||||
},
|
||||
};
|
||||
|
||||
comp.enqueueLinkTasks(&.{.{ .load_object = c_object.status.success.object_path }});
|
||||
comp.queueLinkTasks(&.{.{ .load_object = c_object.status.success.object_path }});
|
||||
}
|
||||
|
||||
fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: std.Progress.Node) !void {
|
||||
@ -6114,7 +6110,7 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {
|
||||
return is_exe_or_dyn_lib and comp.config.link_libunwind and ofmt != .c;
|
||||
}
|
||||
|
||||
fn setAllocFailure(comp: *Compilation) void {
|
||||
pub fn setAllocFailure(comp: *Compilation) void {
|
||||
@branchHint(.cold);
|
||||
log.debug("memory allocation failure", .{});
|
||||
comp.alloc_failure_occurred = true;
|
||||
@ -6355,7 +6351,7 @@ fn buildOutputFromZig(
|
||||
assert(out.* == null);
|
||||
out.* = crt_file;
|
||||
|
||||
comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
}
|
||||
|
||||
pub fn build_crt_file(
|
||||
@ -6463,7 +6459,7 @@ pub fn build_crt_file(
|
||||
try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);
|
||||
|
||||
const crt_file = try sub_compilation.toCrtFile();
|
||||
comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
|
||||
{
|
||||
comp.mutex.lock();
|
||||
@ -6473,8 +6469,8 @@ pub fn build_crt_file(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enqueueLinkTaskMode(comp: *Compilation, path: Path, output_mode: std.builtin.OutputMode) void {
|
||||
comp.enqueueLinkTasks(switch (output_mode) {
|
||||
pub fn queueLinkTaskMode(comp: *Compilation, path: Path, output_mode: std.builtin.OutputMode) void {
|
||||
comp.queueLinkTasks(switch (output_mode) {
|
||||
.Exe => unreachable,
|
||||
.Obj => &.{.{ .load_object = path }},
|
||||
.Lib => &.{.{ .load_archive = path }},
|
||||
@ -6483,7 +6479,7 @@ pub fn enqueueLinkTaskMode(comp: *Compilation, path: Path, output_mode: std.buil
|
||||
|
||||
/// Only valid to call during `update`. Automatically handles queuing up a
|
||||
/// linker worker task if there is not already one.
|
||||
fn enqueueLinkTasks(comp: *Compilation, tasks: []const link.File.Task) void {
|
||||
pub fn queueLinkTasks(comp: *Compilation, tasks: []const link.File.Task) void {
|
||||
const use_lld = build_options.have_llvm and comp.config.use_lld;
|
||||
if (use_lld) return;
|
||||
const target = comp.root_mod.resolved_target.result;
|
||||
|
||||
@ -59,5 +59,13 @@ pub fn ThreadSafeQueue(comptime T: type) type {
|
||||
self.state = .run;
|
||||
return was_waiting;
|
||||
}
|
||||
|
||||
/// Safe only to call exactly once when initially starting the worker.
|
||||
pub fn start(self: *Self) bool {
|
||||
assert(self.state == .wait);
|
||||
if (self.shared.items.len == 0) return false;
|
||||
self.state = .run;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -6,12 +6,14 @@ const fs = std.fs;
|
||||
const path = fs.path;
|
||||
const assert = std.debug.assert;
|
||||
const Version = std.SemanticVersion;
|
||||
const Path = std.Build.Cache.Path;
|
||||
|
||||
const Compilation = @import("Compilation.zig");
|
||||
const build_options = @import("build_options");
|
||||
const trace = @import("tracy.zig").trace;
|
||||
const Cache = std.Build.Cache;
|
||||
const Module = @import("Package/Module.zig");
|
||||
const link = @import("link.zig");
|
||||
|
||||
pub const Lib = struct {
|
||||
name: []const u8,
|
||||
@ -717,11 +719,11 @@ fn lib_path(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const
|
||||
|
||||
pub const BuiltSharedObjects = struct {
|
||||
lock: Cache.Lock,
|
||||
dir_path: []u8,
|
||||
dir_path: Path,
|
||||
|
||||
pub fn deinit(self: *BuiltSharedObjects, gpa: Allocator) void {
|
||||
self.lock.release();
|
||||
gpa.free(self.dir_path);
|
||||
gpa.free(self.dir_path.sub_path);
|
||||
self.* = undefined;
|
||||
}
|
||||
};
|
||||
@ -742,7 +744,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
|
||||
return error.ZigCompilerNotBuiltWithLLVMExtensions;
|
||||
}
|
||||
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
|
||||
const gpa = comp.gpa;
|
||||
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
|
||||
defer arena_allocator.deinit();
|
||||
const arena = arena_allocator.allocator();
|
||||
|
||||
@ -751,7 +755,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
|
||||
|
||||
// Use the global cache directory.
|
||||
var cache: Cache = .{
|
||||
.gpa = comp.gpa,
|
||||
.gpa = gpa,
|
||||
.manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}),
|
||||
};
|
||||
cache.addPrefix(.{ .path = null, .handle = fs.cwd() });
|
||||
@ -772,12 +776,13 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
|
||||
if (try man.hit()) {
|
||||
const digest = man.final();
|
||||
|
||||
assert(comp.glibc_so_files == null);
|
||||
comp.glibc_so_files = BuiltSharedObjects{
|
||||
return queueSharedObjects(comp, .{
|
||||
.lock = man.toOwnedLock(),
|
||||
.dir_path = try comp.global_cache_directory.join(comp.gpa, &.{ "o", &digest }),
|
||||
};
|
||||
return;
|
||||
.dir_path = .{
|
||||
.root_dir = comp.global_cache_directory,
|
||||
.sub_path = try gpa.dupe(u8, "o" ++ fs.path.sep_str ++ digest),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const digest = man.final();
|
||||
@ -790,8 +795,8 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
|
||||
defer o_directory.handle.close();
|
||||
|
||||
const abilists_contents = man.files.keys()[abilists_index].contents.?;
|
||||
const metadata = try loadMetaData(comp.gpa, abilists_contents);
|
||||
defer metadata.destroy(comp.gpa);
|
||||
const metadata = try loadMetaData(gpa, abilists_contents);
|
||||
defer metadata.destroy(gpa);
|
||||
|
||||
const target_targ_index = for (metadata.all_targets, 0..) |targ, i| {
|
||||
if (targ.arch == target.cpu.arch and
|
||||
@ -835,7 +840,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
|
||||
map_contents.deinit(); // The most recent allocation of an arena can be freed :)
|
||||
}
|
||||
|
||||
var stubs_asm = std.ArrayList(u8).init(comp.gpa);
|
||||
var stubs_asm = std.ArrayList(u8).init(gpa);
|
||||
defer stubs_asm.deinit();
|
||||
|
||||
for (libs, 0..) |lib, lib_i| {
|
||||
@ -1195,7 +1200,6 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
|
||||
var lib_name_buf: [32]u8 = undefined; // Larger than each of the names "c", "pthread", etc.
|
||||
const asm_file_basename = std.fmt.bufPrint(&lib_name_buf, "{s}.s", .{lib.name}) catch unreachable;
|
||||
try o_directory.handle.writeFile(.{ .sub_path = asm_file_basename, .data = stubs_asm.items });
|
||||
|
||||
try buildSharedLib(comp, arena, comp.global_cache_directory, o_directory, asm_file_basename, lib, prog_node);
|
||||
}
|
||||
|
||||
@ -1203,11 +1207,44 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
|
||||
log.warn("failed to write cache manifest for glibc stubs: {s}", .{@errorName(err)});
|
||||
};
|
||||
|
||||
assert(comp.glibc_so_files == null);
|
||||
comp.glibc_so_files = .{
|
||||
return queueSharedObjects(comp, .{
|
||||
.lock = man.toOwnedLock(),
|
||||
.dir_path = try comp.global_cache_directory.join(comp.gpa, &.{ "o", &digest }),
|
||||
.dir_path = .{
|
||||
.root_dir = comp.global_cache_directory,
|
||||
.sub_path = try gpa.dupe(u8, "o" ++ fs.path.sep_str ++ digest),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
|
||||
const target_version = comp.getTarget().os.version_range.linux.glibc;
|
||||
|
||||
assert(comp.glibc_so_files == null);
|
||||
comp.glibc_so_files = so_files;
|
||||
|
||||
var task_buffer: [libs.len]link.File.Task = undefined;
|
||||
var task_buffer_i: usize = 0;
|
||||
|
||||
{
|
||||
comp.mutex.lock(); // protect comp.arena
|
||||
defer comp.mutex.unlock();
|
||||
|
||||
for (libs) |lib| {
|
||||
if (lib.removed_in) |rem_in| {
|
||||
if (target_version.order(rem_in) != .lt) continue;
|
||||
}
|
||||
const so_path: Path = .{
|
||||
.root_dir = so_files.dir_path.root_dir,
|
||||
.sub_path = std.fmt.allocPrint(comp.arena, "{s}{c}lib{s}.so.{d}", .{
|
||||
so_files.dir_path.sub_path, fs.path.sep, lib.name, lib.sover,
|
||||
}) catch return comp.setAllocFailure(),
|
||||
};
|
||||
task_buffer[task_buffer_i] = .{ .load_dso = so_path };
|
||||
task_buffer_i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
comp.queueLinkTasks(task_buffer[0..task_buffer_i]);
|
||||
}
|
||||
|
||||
fn buildSharedLib(
|
||||
|
||||
@ -357,7 +357,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
|
||||
assert(comp.libcxx_static_lib == null);
|
||||
const crt_file = try sub_compilation.toCrtFile();
|
||||
comp.libcxx_static_lib = crt_file;
|
||||
comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
}
|
||||
|
||||
pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
|
||||
@ -588,7 +588,7 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
|
||||
assert(comp.libcxxabi_static_lib == null);
|
||||
const crt_file = try sub_compilation.toCrtFile();
|
||||
comp.libcxxabi_static_lib = crt_file;
|
||||
comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
}
|
||||
|
||||
pub fn hardeningModeFlag(optimize_mode: std.builtin.OptimizeMode) []const u8 {
|
||||
|
||||
@ -343,7 +343,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
|
||||
};
|
||||
|
||||
const crt_file = try sub_compilation.toCrtFile();
|
||||
comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
assert(comp.tsan_lib == null);
|
||||
comp.tsan_lib = crt_file;
|
||||
}
|
||||
|
||||
@ -200,7 +200,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
|
||||
};
|
||||
|
||||
const crt_file = try sub_compilation.toCrtFile();
|
||||
comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
assert(comp.libunwind_static_lib == null);
|
||||
comp.libunwind_static_lib = crt_file;
|
||||
}
|
||||
|
||||
32
src/link.zig
32
src/link.zig
@ -1349,12 +1349,14 @@ pub const File = struct {
|
||||
/// Does all the tasks in the queue. Runs in exactly one separate thread
|
||||
/// from the rest of compilation. All tasks performed here are
|
||||
/// single-threaded with respect to one another.
|
||||
pub fn flushTaskQueue(base: *File, prog_node: std.Progress.Node) void {
|
||||
pub fn flushTaskQueue(base: *File, parent_prog_node: std.Progress.Node) void {
|
||||
const comp = base.comp;
|
||||
base.task_queue_safety.lock();
|
||||
defer base.task_queue_safety.unlock();
|
||||
const prog_node = parent_prog_node.start("Parse Linker Inputs", 0);
|
||||
defer prog_node.end();
|
||||
while (comp.link_task_queue.check()) |tasks| {
|
||||
for (tasks) |task| doTask(base, prog_node, task);
|
||||
for (tasks) |task| doTask(base, task);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1374,16 +1376,11 @@ pub const File = struct {
|
||||
load_input: Input,
|
||||
};
|
||||
|
||||
fn doTask(base: *File, parent_prog_node: std.Progress.Node, task: Task) void {
|
||||
fn doTask(base: *File, task: Task) void {
|
||||
const comp = base.comp;
|
||||
switch (task) {
|
||||
.load_explicitly_provided => {
|
||||
const prog_node = parent_prog_node.start("Linker Parse Input", comp.link_inputs.len);
|
||||
defer prog_node.end();
|
||||
|
||||
for (comp.link_inputs) |input| {
|
||||
const sub_node = prog_node.start(input.taskName(), 0);
|
||||
defer sub_node.end();
|
||||
base.loadInput(input) catch |err| switch (err) {
|
||||
error.LinkFailure => return, // error reported via link_diags
|
||||
else => |e| {
|
||||
@ -1397,33 +1394,18 @@ pub const File = struct {
|
||||
}
|
||||
},
|
||||
.load_object => |path| {
|
||||
const prog_node = parent_prog_node.start("Linker Parse Object", 0);
|
||||
defer prog_node.end();
|
||||
const sub_node = prog_node.start(path.basename(), 0);
|
||||
defer sub_node.end();
|
||||
|
||||
base.openLoadObject(path) catch |err| switch (err) {
|
||||
error.LinkFailure => return, // error reported via link_diags
|
||||
else => |e| comp.link_diags.addParseError(path, "failed to parse object: {s}", .{@errorName(e)}),
|
||||
};
|
||||
},
|
||||
.load_archive => |path| {
|
||||
const prog_node = parent_prog_node.start("Linker Parse Archive", 0);
|
||||
defer prog_node.end();
|
||||
const sub_node = prog_node.start(path.basename(), 0);
|
||||
defer sub_node.end();
|
||||
|
||||
base.openLoadArchive(path) catch |err| switch (err) {
|
||||
error.LinkFailure => return, // error reported via link_diags
|
||||
else => |e| comp.link_diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}),
|
||||
};
|
||||
},
|
||||
.load_dso => |path| {
|
||||
const prog_node = parent_prog_node.start("Linker Parse Shared Library", 0);
|
||||
defer prog_node.end();
|
||||
const sub_node = prog_node.start(path.basename(), 0);
|
||||
defer sub_node.end();
|
||||
|
||||
base.openLoadDso(path, .{
|
||||
.preferred_mode = .dynamic,
|
||||
.search_strategy = .paths_first,
|
||||
@ -1433,10 +1415,6 @@ pub const File = struct {
|
||||
};
|
||||
},
|
||||
.load_input => |input| {
|
||||
const prog_node = parent_prog_node.start("Linker Parse Input", 0);
|
||||
defer prog_node.end();
|
||||
const sub_node = prog_node.start(input.taskName(), 0);
|
||||
defer sub_node.end();
|
||||
base.loadInput(input) catch |err| switch (err) {
|
||||
error.LinkFailure => return, // error reported via link_diags
|
||||
else => |e| {
|
||||
|
||||
282
src/link/Elf.zig
282
src/link/Elf.zig
@ -114,6 +114,10 @@ comment_merge_section_index: ?Merge.Section.Index = null,
|
||||
|
||||
first_eflags: ?elf.Word = null,
|
||||
|
||||
/// `--verbose-link` output.
|
||||
/// Initialized on creation, appended to as inputs are added, printed during `flush`.
|
||||
dump_argv_list: std.ArrayListUnmanaged([]const u8),
|
||||
|
||||
const SectionIndexes = struct {
|
||||
copy_rel: ?u32 = null,
|
||||
dynamic: ?u32 = null,
|
||||
@ -338,6 +342,7 @@ pub fn createEmpty(
|
||||
.enable_new_dtags = options.enable_new_dtags,
|
||||
.print_icf_sections = options.print_icf_sections,
|
||||
.print_map = options.print_map,
|
||||
.dump_argv_list = .empty,
|
||||
};
|
||||
if (use_llvm and comp.config.have_zcu) {
|
||||
self.llvm_object = try LlvmObject.create(arena, comp);
|
||||
@ -350,7 +355,7 @@ pub fn createEmpty(
|
||||
}
|
||||
|
||||
// --verbose-link
|
||||
if (comp.verbose_link) try self.dumpArgv(comp);
|
||||
if (comp.verbose_link) try dumpArgvInit(self, arena);
|
||||
|
||||
const is_obj = output_mode == .Obj;
|
||||
const is_obj_or_ar = is_obj or (output_mode == .Lib and link_mode == .static);
|
||||
@ -501,6 +506,7 @@ pub fn deinit(self: *Elf) void {
|
||||
self.rela_dyn.deinit(gpa);
|
||||
self.rela_plt.deinit(gpa);
|
||||
self.comdat_group_sections.deinit(gpa);
|
||||
self.dump_argv_list.deinit(gpa);
|
||||
}
|
||||
|
||||
pub fn getNavVAddr(self: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: link.File.RelocInfo) !u64 {
|
||||
@ -753,12 +759,23 @@ pub fn allocateChunk(self: *Elf, args: struct {
|
||||
}
|
||||
|
||||
pub fn loadInput(self: *Elf, input: link.Input) !void {
|
||||
const gpa = self.base.comp.gpa;
|
||||
const diags = &self.base.comp.link_diags;
|
||||
const comp = self.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
const diags = &comp.link_diags;
|
||||
const target = self.getTarget();
|
||||
const debug_fmt_strip = self.base.comp.config.debug_format == .strip;
|
||||
const debug_fmt_strip = comp.config.debug_format == .strip;
|
||||
const default_sym_version = self.default_sym_version;
|
||||
|
||||
if (comp.verbose_link) {
|
||||
const argv = &self.dump_argv_list;
|
||||
switch (input) {
|
||||
.res => unreachable,
|
||||
.dso_exact => |dso_exact| try argv.appendSlice(gpa, &.{ "-l", dso_exact.name }),
|
||||
.object, .archive => |obj| try argv.append(gpa, try obj.path.toString(comp.arena)),
|
||||
.dso => |dso| try argv.append(gpa, try dso.path.toString(comp.arena)),
|
||||
}
|
||||
}
|
||||
|
||||
switch (input) {
|
||||
.res => unreachable,
|
||||
.dso_exact => @panic("TODO"),
|
||||
@ -790,6 +807,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
|
||||
if (use_lld) return;
|
||||
}
|
||||
|
||||
if (comp.verbose_link) Compilation.dump_argv(self.dump_argv_list.items);
|
||||
|
||||
const sub_prog_node = prog_node.start("ELF Flush", 0);
|
||||
defer sub_prog_node.end();
|
||||
|
||||
@ -965,291 +984,110 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
|
||||
if (diags.hasErrors()) return error.FlushFailure;
|
||||
}
|
||||
|
||||
/// --verbose-link output
|
||||
fn dumpArgv(self: *Elf, comp: *Compilation) !void {
|
||||
const gpa = self.base.comp.gpa;
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
|
||||
defer arena_allocator.deinit();
|
||||
const arena = arena_allocator.allocator();
|
||||
|
||||
fn dumpArgvInit(self: *Elf, arena: Allocator) !void {
|
||||
const comp = self.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
const target = self.getTarget();
|
||||
const link_mode = self.base.comp.config.link_mode;
|
||||
const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
|
||||
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
|
||||
const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
|
||||
if (fs.path.dirname(full_out_path)) |dirname| {
|
||||
break :blk try fs.path.join(arena, &.{ dirname, path });
|
||||
} else {
|
||||
break :blk path;
|
||||
}
|
||||
} else null;
|
||||
const full_out_path = try self.base.emit.root_dir.join(arena, &[_][]const u8{self.base.emit.sub_path});
|
||||
|
||||
const crt_basenames = std.zig.LibCInstallation.CrtBasenames.get(.{
|
||||
.target = target,
|
||||
.link_libc = comp.config.link_libc,
|
||||
.output_mode = comp.config.output_mode,
|
||||
.link_mode = link_mode,
|
||||
.pie = comp.config.pie,
|
||||
});
|
||||
const crt_paths: std.zig.LibCInstallation.CrtPaths = if (comp.libc_installation) |lci|
|
||||
try lci.resolveCrtPaths(arena, crt_basenames, target)
|
||||
else
|
||||
.{};
|
||||
const compiler_rt_path: ?[]const u8 = blk: {
|
||||
if (comp.compiler_rt_lib) |x| break :blk try x.full_object_path.toString(arena);
|
||||
if (comp.compiler_rt_obj) |x| break :blk try x.full_object_path.toString(arena);
|
||||
break :blk null;
|
||||
};
|
||||
const argv = &self.dump_argv_list;
|
||||
|
||||
var argv = std.ArrayList([]const u8).init(arena);
|
||||
|
||||
try argv.append("zig");
|
||||
try argv.append(gpa, "zig");
|
||||
|
||||
if (self.base.isStaticLib()) {
|
||||
try argv.append("ar");
|
||||
try argv.append(gpa, "ar");
|
||||
} else {
|
||||
try argv.append("ld");
|
||||
try argv.append(gpa, "ld");
|
||||
}
|
||||
|
||||
if (self.base.isObject()) {
|
||||
try argv.append("-r");
|
||||
try argv.append(gpa, "-r");
|
||||
}
|
||||
|
||||
try argv.append("-o");
|
||||
try argv.append(full_out_path);
|
||||
try argv.append(gpa, "-o");
|
||||
try argv.append(gpa, full_out_path);
|
||||
|
||||
if (self.base.isRelocatable()) {
|
||||
for (self.base.comp.link_inputs) |link_input| switch (link_input) {
|
||||
.res => unreachable,
|
||||
.dso => |dso| try argv.append(try dso.path.toString(arena)),
|
||||
.object, .archive => |obj| try argv.append(try obj.path.toString(arena)),
|
||||
.dso_exact => |dso_exact| {
|
||||
assert(dso_exact.name[0] == ':');
|
||||
try argv.appendSlice(&.{ "-l", dso_exact.name });
|
||||
},
|
||||
};
|
||||
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
try argv.append(try key.status.success.object_path.toString(arena));
|
||||
}
|
||||
|
||||
if (module_obj_path) |p| {
|
||||
try argv.append(p);
|
||||
}
|
||||
} else {
|
||||
if (!self.base.isRelocatable()) {
|
||||
if (!self.base.isStatic()) {
|
||||
if (target.dynamic_linker.get()) |path| {
|
||||
try argv.append("-dynamic-linker");
|
||||
try argv.append(path);
|
||||
try argv.appendSlice(gpa, &.{ "-dynamic-linker", try arena.dupe(u8, path) });
|
||||
}
|
||||
}
|
||||
|
||||
if (self.base.isDynLib()) {
|
||||
if (self.soname) |name| {
|
||||
try argv.append("-soname");
|
||||
try argv.append(name);
|
||||
try argv.append(gpa, "-soname");
|
||||
try argv.append(gpa, name);
|
||||
}
|
||||
}
|
||||
|
||||
if (self.entry_name) |name| {
|
||||
try argv.appendSlice(&.{ "--entry", name });
|
||||
try argv.appendSlice(gpa, &.{ "--entry", name });
|
||||
}
|
||||
|
||||
for (self.rpath_table.keys()) |rpath| {
|
||||
try argv.appendSlice(&.{ "-rpath", rpath });
|
||||
try argv.appendSlice(gpa, &.{ "-rpath", rpath });
|
||||
}
|
||||
|
||||
try argv.appendSlice(&.{
|
||||
try argv.appendSlice(gpa, &.{
|
||||
"-z",
|
||||
try std.fmt.allocPrint(arena, "stack-size={d}", .{self.base.stack_size}),
|
||||
});
|
||||
|
||||
try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{self.image_base}));
|
||||
try argv.append(gpa, try std.fmt.allocPrint(arena, "--image-base={d}", .{self.image_base}));
|
||||
|
||||
if (self.base.gc_sections) {
|
||||
try argv.append("--gc-sections");
|
||||
try argv.append(gpa, "--gc-sections");
|
||||
}
|
||||
|
||||
if (self.base.print_gc_sections) {
|
||||
try argv.append("--print-gc-sections");
|
||||
try argv.append(gpa, "--print-gc-sections");
|
||||
}
|
||||
|
||||
if (comp.link_eh_frame_hdr) {
|
||||
try argv.append("--eh-frame-hdr");
|
||||
try argv.append(gpa, "--eh-frame-hdr");
|
||||
}
|
||||
|
||||
if (comp.config.rdynamic) {
|
||||
try argv.append("--export-dynamic");
|
||||
try argv.append(gpa, "--export-dynamic");
|
||||
}
|
||||
|
||||
if (self.z_notext) {
|
||||
try argv.append("-z");
|
||||
try argv.append("notext");
|
||||
try argv.append(gpa, "-z");
|
||||
try argv.append(gpa, "notext");
|
||||
}
|
||||
|
||||
if (self.z_nocopyreloc) {
|
||||
try argv.append("-z");
|
||||
try argv.append("nocopyreloc");
|
||||
try argv.append(gpa, "-z");
|
||||
try argv.append(gpa, "nocopyreloc");
|
||||
}
|
||||
|
||||
if (self.z_now) {
|
||||
try argv.append("-z");
|
||||
try argv.append("now");
|
||||
try argv.append(gpa, "-z");
|
||||
try argv.append(gpa, "now");
|
||||
}
|
||||
|
||||
if (self.base.isStatic()) {
|
||||
try argv.append("-static");
|
||||
try argv.append(gpa, "-static");
|
||||
} else if (self.isEffectivelyDynLib()) {
|
||||
try argv.append("-shared");
|
||||
try argv.append(gpa, "-shared");
|
||||
}
|
||||
|
||||
if (comp.config.pie and self.base.isExe()) {
|
||||
try argv.append("-pie");
|
||||
try argv.append(gpa, "-pie");
|
||||
}
|
||||
|
||||
if (comp.config.debug_format == .strip) {
|
||||
try argv.append("-s");
|
||||
try argv.append(gpa, "-s");
|
||||
}
|
||||
|
||||
if (crt_paths.crt0) |path| try argv.append(try path.toString(arena));
|
||||
if (crt_paths.crti) |path| try argv.append(try path.toString(arena));
|
||||
if (crt_paths.crtbegin) |path| try argv.append(try path.toString(arena));
|
||||
|
||||
if (comp.config.link_libc) {
|
||||
if (self.base.comp.libc_installation) |libc_installation| {
|
||||
try argv.append("-L");
|
||||
try argv.append(libc_installation.crt_dir.?);
|
||||
if (self.base.comp.libc_installation) |lci| {
|
||||
try argv.append(gpa, "-L");
|
||||
try argv.append(gpa, lci.crt_dir.?);
|
||||
}
|
||||
}
|
||||
|
||||
var whole_archive = false;
|
||||
|
||||
for (self.base.comp.link_inputs) |link_input| switch (link_input) {
|
||||
.res => unreachable,
|
||||
.dso => continue,
|
||||
.object, .archive => |obj| {
|
||||
if (obj.must_link and !whole_archive) {
|
||||
try argv.append("-whole-archive");
|
||||
whole_archive = true;
|
||||
} else if (!obj.must_link and whole_archive) {
|
||||
try argv.append("-no-whole-archive");
|
||||
whole_archive = false;
|
||||
}
|
||||
try argv.append(try obj.path.toString(arena));
|
||||
},
|
||||
.dso_exact => |dso_exact| {
|
||||
assert(dso_exact.name[0] == ':');
|
||||
try argv.appendSlice(&.{ "-l", dso_exact.name });
|
||||
},
|
||||
};
|
||||
|
||||
if (whole_archive) {
|
||||
try argv.append("-no-whole-archive");
|
||||
whole_archive = false;
|
||||
}
|
||||
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
try argv.append(try key.status.success.object_path.toString(arena));
|
||||
}
|
||||
|
||||
if (module_obj_path) |p| {
|
||||
try argv.append(p);
|
||||
}
|
||||
|
||||
if (comp.config.any_sanitize_thread) {
|
||||
try argv.append(try comp.tsan_lib.?.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
if (comp.config.any_fuzz) {
|
||||
try argv.append(try comp.fuzzer_lib.?.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
// libc
|
||||
if (!comp.skip_linker_dependencies and !comp.config.link_libc) {
|
||||
if (comp.libc_static_lib) |lib| {
|
||||
try argv.append(try lib.full_object_path.toString(arena));
|
||||
}
|
||||
}
|
||||
|
||||
// Shared libraries.
|
||||
// Worst-case, we need an --as-needed argument for every lib, as well
|
||||
// as one before and one after.
|
||||
argv.appendAssumeCapacity("--as-needed");
|
||||
var as_needed = true;
|
||||
|
||||
for (self.base.comp.link_inputs) |link_input| switch (link_input) {
|
||||
.object, .archive, .dso_exact => continue,
|
||||
.dso => |dso| {
|
||||
const lib_as_needed = !dso.needed;
|
||||
switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {
|
||||
0b00, 0b11 => {},
|
||||
0b01 => {
|
||||
try argv.append("--no-as-needed");
|
||||
as_needed = false;
|
||||
},
|
||||
0b10 => {
|
||||
try argv.append("--as-needed");
|
||||
as_needed = true;
|
||||
},
|
||||
}
|
||||
argv.appendAssumeCapacity(try dso.path.toString(arena));
|
||||
},
|
||||
.res => unreachable,
|
||||
};
|
||||
|
||||
if (!as_needed) {
|
||||
argv.appendAssumeCapacity("--as-needed");
|
||||
as_needed = true;
|
||||
}
|
||||
|
||||
// libc++ dep
|
||||
if (comp.config.link_libcpp) {
|
||||
try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
|
||||
try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
// libunwind dep
|
||||
if (comp.config.link_libunwind) {
|
||||
try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
// libc dep
|
||||
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");
|
||||
try argv.appendSlice(target_util.libcFullLinkFlags(target));
|
||||
if (needs_grouping) try argv.append("--end-group");
|
||||
} else if (target.isGnuLibC()) {
|
||||
for (glibc.libs) |lib| {
|
||||
if (lib.removed_in) |rem_in| {
|
||||
if (target.os.version_range.linux.glibc.order(rem_in) != .lt) continue;
|
||||
}
|
||||
|
||||
const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
|
||||
comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
|
||||
});
|
||||
try argv.append(lib_path);
|
||||
}
|
||||
try argv.append(try comp.crtFileAsString(arena, "libc_nonshared.a"));
|
||||
} else if (target.isMusl()) {
|
||||
try argv.append(try comp.crtFileAsString(arena, switch (link_mode) {
|
||||
.static => "libc.a",
|
||||
.dynamic => "libc.so",
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// compiler-rt
|
||||
if (compiler_rt_path) |p| {
|
||||
try argv.append(p);
|
||||
}
|
||||
|
||||
if (crt_paths.crtend) |path| try argv.append(try path.toString(arena));
|
||||
if (crt_paths.crtn) |path| try argv.append(try path.toString(arena));
|
||||
}
|
||||
|
||||
Compilation.dump_argv(argv.items);
|
||||
}
|
||||
|
||||
pub const ParseError = error{
|
||||
@ -2177,7 +2015,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
if (target.os.version_range.linux.glibc.order(rem_in) != .lt) continue;
|
||||
}
|
||||
|
||||
const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
|
||||
const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{
|
||||
comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
|
||||
});
|
||||
try argv.append(lib_path);
|
||||
|
||||
@ -281,7 +281,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
|
||||
errdefer comp.gpa.free(basename);
|
||||
|
||||
const crt_file = try sub_compilation.toCrtFile();
|
||||
comp.enqueueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
||||
{
|
||||
comp.mutex.lock();
|
||||
defer comp.mutex.unlock();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user