mirror of
https://github.com/ziglang/zig.git
synced 2026-02-15 05:48:31 +00:00
Merge pull request #21654 from ziglang/embrace-path-abstraction
link: fix false positive crtbegin/crtend detection
This commit is contained in:
commit
1340565e22
@ -398,12 +398,19 @@ pub const Manifest = struct {
|
||||
return gop.index;
|
||||
}
|
||||
|
||||
/// Deprecated, use `addOptionalFilePath`.
|
||||
pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void {
|
||||
self.hash.add(optional_file_path != null);
|
||||
const file_path = optional_file_path orelse return;
|
||||
_ = try self.addFile(file_path, null);
|
||||
}
|
||||
|
||||
pub fn addOptionalFilePath(self: *Manifest, optional_file_path: ?Path) !void {
|
||||
self.hash.add(optional_file_path != null);
|
||||
const file_path = optional_file_path orelse return;
|
||||
_ = try self.addFilePath(file_path, null);
|
||||
}
|
||||
|
||||
pub fn addListOfFiles(self: *Manifest, list_of_files: []const []const u8) !void {
|
||||
self.hash.add(list_of_files.len);
|
||||
for (list_of_files) |file_path| {
|
||||
|
||||
@ -11,7 +11,11 @@ pub fn clone(p: Path, arena: Allocator) Allocator.Error!Path {
|
||||
}
|
||||
|
||||
pub fn cwd() Path {
|
||||
return .{ .root_dir = Cache.Directory.cwd() };
|
||||
return initCwd("");
|
||||
}
|
||||
|
||||
pub fn initCwd(sub_path: []const u8) Path {
|
||||
return .{ .root_dir = Cache.Directory.cwd(), .sub_path = sub_path };
|
||||
}
|
||||
|
||||
pub fn join(p: Path, arena: Allocator, sub_path: []const u8) Allocator.Error!Path {
|
||||
@ -126,6 +130,14 @@ pub fn makePath(p: Path, sub_path: []const u8) !void {
|
||||
return p.root_dir.handle.makePath(joined_path);
|
||||
}
|
||||
|
||||
pub fn toString(p: Path, allocator: Allocator) Allocator.Error![]u8 {
|
||||
return std.fmt.allocPrint(allocator, "{}", .{p});
|
||||
}
|
||||
|
||||
pub fn toStringZ(p: Path, allocator: Allocator) Allocator.Error![:0]u8 {
|
||||
return std.fmt.allocPrintZ(allocator, "{}", .{p});
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: Path,
|
||||
comptime fmt_string: []const u8,
|
||||
@ -137,7 +149,7 @@ pub fn format(
|
||||
const stringEscape = std.zig.stringEscape;
|
||||
const f = switch (fmt_string[0]) {
|
||||
'q' => "",
|
||||
'\'' => '\'',
|
||||
'\'' => "\'",
|
||||
else => @compileError("unsupported format string: " ++ fmt_string),
|
||||
};
|
||||
if (self.root_dir.path) |p| {
|
||||
@ -182,6 +194,14 @@ pub fn subPathOrDot(self: Path) []const u8 {
|
||||
return if (self.sub_path.len == 0) "." else self.sub_path;
|
||||
}
|
||||
|
||||
pub fn stem(p: Path) []const u8 {
|
||||
return fs.path.stem(p.sub_path);
|
||||
}
|
||||
|
||||
pub fn basename(p: Path) []const u8 {
|
||||
return fs.path.basename(p.sub_path);
|
||||
}
|
||||
|
||||
/// Useful to make `Path` a key in `std.ArrayHashMap`.
|
||||
pub const TableAdapter = struct {
|
||||
pub const Hash = std.hash.Wyhash;
|
||||
|
||||
@ -557,15 +557,15 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
|
||||
const check_object: *CheckObject = @fieldParentPtr("step", step);
|
||||
try step.singleUnchangingWatchInput(check_object.source);
|
||||
|
||||
const src_path = check_object.source.getPath2(b, step);
|
||||
const contents = fs.cwd().readFileAllocOptions(
|
||||
const src_path = check_object.source.getPath3(b, step);
|
||||
const contents = src_path.root_dir.handle.readFileAllocOptions(
|
||||
gpa,
|
||||
src_path,
|
||||
src_path.sub_path,
|
||||
check_object.max_bytes,
|
||||
null,
|
||||
@alignOf(u64),
|
||||
null,
|
||||
) catch |err| return step.fail("unable to read '{s}': {s}", .{ src_path, @errorName(err) });
|
||||
) catch |err| return step.fail("unable to read '{'}': {s}", .{ src_path, @errorName(err) });
|
||||
|
||||
var vars = std.StringHashMap(u64).init(gpa);
|
||||
for (check_object.checks.items) |chk| {
|
||||
@ -640,8 +640,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
|
||||
\\{s}
|
||||
\\========= but parsed file does not contain it: =======
|
||||
\\{s}
|
||||
\\======================================================
|
||||
, .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
|
||||
\\========= file path: =================================
|
||||
\\{}
|
||||
, .{
|
||||
fmtMessageString(chk.kind, act.phrase.resolve(b, step)),
|
||||
fmtMessageString(chk.kind, output),
|
||||
src_path,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@ -655,8 +660,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
|
||||
\\*{s}*
|
||||
\\========= but parsed file does not contain it: =======
|
||||
\\{s}
|
||||
\\======================================================
|
||||
, .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
|
||||
\\========= file path: =================================
|
||||
\\{}
|
||||
, .{
|
||||
fmtMessageString(chk.kind, act.phrase.resolve(b, step)),
|
||||
fmtMessageString(chk.kind, output),
|
||||
src_path,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@ -669,8 +679,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
|
||||
\\{s}
|
||||
\\========= but parsed file does contain it: ========
|
||||
\\{s}
|
||||
\\===================================================
|
||||
, .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
|
||||
\\========= file path: ==============================
|
||||
\\{}
|
||||
, .{
|
||||
fmtMessageString(chk.kind, act.phrase.resolve(b, step)),
|
||||
fmtMessageString(chk.kind, output),
|
||||
src_path,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@ -684,8 +699,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
|
||||
\\{s}
|
||||
\\========= but parsed file does not contain it: =======
|
||||
\\{s}
|
||||
\\======================================================
|
||||
, .{ act.phrase.resolve(b, step), fmtMessageString(chk.kind, output) });
|
||||
\\========= file path: ==============================
|
||||
\\{}
|
||||
, .{
|
||||
act.phrase.resolve(b, step),
|
||||
fmtMessageString(chk.kind, output),
|
||||
src_path,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -690,12 +690,340 @@ fn appendCcExe(args: *std.ArrayList([]const u8), skip_cc_env_var: bool) !void {
|
||||
}
|
||||
}
|
||||
|
||||
/// These are basenames. This data is produced with a pure function. See also
|
||||
/// `CsuPaths`.
|
||||
pub const CrtBasenames = struct {
|
||||
crt0: ?[]const u8 = null,
|
||||
crti: ?[]const u8 = null,
|
||||
crtbegin: ?[]const u8 = null,
|
||||
crtend: ?[]const u8 = null,
|
||||
crtn: ?[]const u8 = null,
|
||||
|
||||
pub const GetArgs = struct {
|
||||
target: std.Target,
|
||||
link_libc: bool,
|
||||
output_mode: std.builtin.OutputMode,
|
||||
link_mode: std.builtin.LinkMode,
|
||||
pie: bool,
|
||||
};
|
||||
|
||||
/// Determine file system path names of C runtime startup objects for supported
|
||||
/// link modes.
|
||||
pub fn get(args: GetArgs) CrtBasenames {
|
||||
// crt objects are only required for libc.
|
||||
if (!args.link_libc) return .{};
|
||||
|
||||
// Flatten crt cases.
|
||||
const mode: enum {
|
||||
dynamic_lib,
|
||||
dynamic_exe,
|
||||
dynamic_pie,
|
||||
static_exe,
|
||||
static_pie,
|
||||
} = switch (args.output_mode) {
|
||||
.Obj => return .{},
|
||||
.Lib => switch (args.link_mode) {
|
||||
.dynamic => .dynamic_lib,
|
||||
.static => return .{},
|
||||
},
|
||||
.Exe => switch (args.link_mode) {
|
||||
.dynamic => if (args.pie) .dynamic_pie else .dynamic_exe,
|
||||
.static => if (args.pie) .static_pie else .static_exe,
|
||||
},
|
||||
};
|
||||
|
||||
const target = args.target;
|
||||
|
||||
if (target.isAndroid()) return switch (mode) {
|
||||
.dynamic_lib => .{
|
||||
.crtbegin = "crtbegin_so.o",
|
||||
.crtend = "crtend_so.o",
|
||||
},
|
||||
.dynamic_exe, .dynamic_pie => .{
|
||||
.crtbegin = "crtbegin_dynamic.o",
|
||||
.crtend = "crtend_android.o",
|
||||
},
|
||||
.static_exe, .static_pie => .{
|
||||
.crtbegin = "crtbegin_static.o",
|
||||
.crtend = "crtend_android.o",
|
||||
},
|
||||
};
|
||||
|
||||
return switch (target.os.tag) {
|
||||
.linux => switch (mode) {
|
||||
.dynamic_lib => .{
|
||||
.crti = "crti.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.dynamic_exe => .{
|
||||
.crt0 = "crt1.o",
|
||||
.crti = "crti.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.dynamic_pie => .{
|
||||
.crt0 = "Scrt1.o",
|
||||
.crti = "crti.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.static_exe => .{
|
||||
.crt0 = "crt1.o",
|
||||
.crti = "crti.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.static_pie => .{
|
||||
.crt0 = "rcrt1.o",
|
||||
.crti = "crti.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
},
|
||||
.dragonfly => switch (mode) {
|
||||
.dynamic_lib => .{
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginS.o",
|
||||
.crtend = "crtendS.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.dynamic_exe => .{
|
||||
.crt0 = "crt1.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbegin.o",
|
||||
.crtend = "crtend.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.dynamic_pie => .{
|
||||
.crt0 = "Scrt1.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginS.o",
|
||||
.crtend = "crtendS.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.static_exe => .{
|
||||
.crt0 = "crt1.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbegin.o",
|
||||
.crtend = "crtend.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.static_pie => .{
|
||||
.crt0 = "Scrt1.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginS.o",
|
||||
.crtend = "crtendS.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
},
|
||||
.freebsd => switch (mode) {
|
||||
.dynamic_lib => .{
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginS.o",
|
||||
.crtend = "crtendS.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.dynamic_exe => .{
|
||||
.crt0 = "crt1.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbegin.o",
|
||||
.crtend = "crtend.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.dynamic_pie => .{
|
||||
.crt0 = "Scrt1.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginS.o",
|
||||
.crtend = "crtendS.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.static_exe => .{
|
||||
.crt0 = "crt1.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginT.o",
|
||||
.crtend = "crtend.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.static_pie => .{
|
||||
.crt0 = "Scrt1.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginS.o",
|
||||
.crtend = "crtendS.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
},
|
||||
.netbsd => switch (mode) {
|
||||
.dynamic_lib => .{
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginS.o",
|
||||
.crtend = "crtendS.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.dynamic_exe => .{
|
||||
.crt0 = "crt0.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbegin.o",
|
||||
.crtend = "crtend.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.dynamic_pie => .{
|
||||
.crt0 = "crt0.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginS.o",
|
||||
.crtend = "crtendS.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.static_exe => .{
|
||||
.crt0 = "crt0.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginT.o",
|
||||
.crtend = "crtend.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.static_pie => .{
|
||||
.crt0 = "crt0.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginT.o",
|
||||
.crtend = "crtendS.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
},
|
||||
.openbsd => switch (mode) {
|
||||
.dynamic_lib => .{
|
||||
.crtbegin = "crtbeginS.o",
|
||||
.crtend = "crtendS.o",
|
||||
},
|
||||
.dynamic_exe, .dynamic_pie => .{
|
||||
.crt0 = "crt0.o",
|
||||
.crtbegin = "crtbegin.o",
|
||||
.crtend = "crtend.o",
|
||||
},
|
||||
.static_exe, .static_pie => .{
|
||||
.crt0 = "rcrt0.o",
|
||||
.crtbegin = "crtbegin.o",
|
||||
.crtend = "crtend.o",
|
||||
},
|
||||
},
|
||||
.haiku => switch (mode) {
|
||||
.dynamic_lib => .{
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginS.o",
|
||||
.crtend = "crtendS.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.dynamic_exe => .{
|
||||
.crt0 = "start_dyn.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbegin.o",
|
||||
.crtend = "crtend.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.dynamic_pie => .{
|
||||
.crt0 = "start_dyn.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginS.o",
|
||||
.crtend = "crtendS.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.static_exe => .{
|
||||
.crt0 = "start_dyn.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbegin.o",
|
||||
.crtend = "crtend.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.static_pie => .{
|
||||
.crt0 = "start_dyn.o",
|
||||
.crti = "crti.o",
|
||||
.crtbegin = "crtbeginS.o",
|
||||
.crtend = "crtendS.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
},
|
||||
.solaris, .illumos => switch (mode) {
|
||||
.dynamic_lib => .{
|
||||
.crti = "crti.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.dynamic_exe, .dynamic_pie => .{
|
||||
.crt0 = "crt1.o",
|
||||
.crti = "crti.o",
|
||||
.crtn = "crtn.o",
|
||||
},
|
||||
.static_exe, .static_pie => .{},
|
||||
},
|
||||
else => .{},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const CrtPaths = struct {
|
||||
crt0: ?Path = null,
|
||||
crti: ?Path = null,
|
||||
crtbegin: ?Path = null,
|
||||
crtend: ?Path = null,
|
||||
crtn: ?Path = null,
|
||||
};
|
||||
|
||||
pub fn resolveCrtPaths(
|
||||
lci: LibCInstallation,
|
||||
arena: Allocator,
|
||||
crt_basenames: CrtBasenames,
|
||||
target: std.Target,
|
||||
) error{ OutOfMemory, LibCInstallationMissingCrtDir }!CrtPaths {
|
||||
const crt_dir_path: Path = .{
|
||||
.root_dir = std.Build.Cache.Directory.cwd(),
|
||||
.sub_path = lci.crt_dir orelse return error.LibCInstallationMissingCrtDir,
|
||||
};
|
||||
switch (target.os.tag) {
|
||||
.dragonfly => {
|
||||
const gccv: []const u8 = if (target.os.version_range.semver.isAtLeast(.{
|
||||
.major = 5,
|
||||
.minor = 4,
|
||||
.patch = 0,
|
||||
}) orelse true) "gcc80" else "gcc54";
|
||||
return .{
|
||||
.crt0 = if (crt_basenames.crt0) |basename| try crt_dir_path.join(arena, basename) else null,
|
||||
.crti = if (crt_basenames.crti) |basename| try crt_dir_path.join(arena, basename) else null,
|
||||
.crtbegin = if (crt_basenames.crtbegin) |basename| .{
|
||||
.root_dir = crt_dir_path.root_dir,
|
||||
.sub_path = try fs.path.join(arena, &.{ crt_dir_path.sub_path, gccv, basename }),
|
||||
} else null,
|
||||
.crtend = if (crt_basenames.crtend) |basename| .{
|
||||
.root_dir = crt_dir_path.root_dir,
|
||||
.sub_path = try fs.path.join(arena, &.{ crt_dir_path.sub_path, gccv, basename }),
|
||||
} else null,
|
||||
.crtn = if (crt_basenames.crtn) |basename| try crt_dir_path.join(arena, basename) else null,
|
||||
};
|
||||
},
|
||||
.haiku => {
|
||||
const gcc_dir_path: Path = .{
|
||||
.root_dir = std.Build.Cache.Directory.cwd(),
|
||||
.sub_path = lci.gcc_dir orelse return error.LibCInstallationMissingCrtDir,
|
||||
};
|
||||
return .{
|
||||
.crt0 = if (crt_basenames.crt0) |basename| try crt_dir_path.join(arena, basename) else null,
|
||||
.crti = if (crt_basenames.crti) |basename| try crt_dir_path.join(arena, basename) else null,
|
||||
.crtbegin = if (crt_basenames.crtbegin) |basename| try gcc_dir_path.join(arena, basename) else null,
|
||||
.crtend = if (crt_basenames.crtend) |basename| try gcc_dir_path.join(arena, basename) else null,
|
||||
.crtn = if (crt_basenames.crtn) |basename| try crt_dir_path.join(arena, basename) else null,
|
||||
};
|
||||
},
|
||||
else => {
|
||||
return .{
|
||||
.crt0 = if (crt_basenames.crt0) |basename| try crt_dir_path.join(arena, basename) else null,
|
||||
.crti = if (crt_basenames.crti) |basename| try crt_dir_path.join(arena, basename) else null,
|
||||
.crtbegin = if (crt_basenames.crtbegin) |basename| try crt_dir_path.join(arena, basename) else null,
|
||||
.crtend = if (crt_basenames.crtend) |basename| try crt_dir_path.join(arena, basename) else null,
|
||||
.crtn = if (crt_basenames.crtn) |basename| try crt_dir_path.join(arena, basename) else null,
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const LibCInstallation = @This();
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const Target = std.Target;
|
||||
const fs = std.fs;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Path = std.Build.Cache.Path;
|
||||
|
||||
const is_darwin = builtin.target.isDarwin();
|
||||
const is_windows = builtin.target.os.tag == .windows;
|
||||
|
||||
@ -217,37 +217,37 @@ thread_pool: *ThreadPool,
|
||||
|
||||
/// Populated when we build the libc++ static library. A Job to build this is placed in the queue
|
||||
/// and resolved before calling linker.flush().
|
||||
libcxx_static_lib: ?CRTFile = null,
|
||||
libcxx_static_lib: ?CrtFile = null,
|
||||
/// Populated when we build the libc++abi static library. A Job to build this is placed in the queue
|
||||
/// and resolved before calling linker.flush().
|
||||
libcxxabi_static_lib: ?CRTFile = null,
|
||||
libcxxabi_static_lib: ?CrtFile = null,
|
||||
/// Populated when we build the libunwind static library. A Job to build this is placed in the queue
|
||||
/// and resolved before calling linker.flush().
|
||||
libunwind_static_lib: ?CRTFile = null,
|
||||
libunwind_static_lib: ?CrtFile = null,
|
||||
/// Populated when we build the TSAN library. A Job to build this is placed in the queue
|
||||
/// and resolved before calling linker.flush().
|
||||
tsan_lib: ?CRTFile = null,
|
||||
tsan_lib: ?CrtFile = null,
|
||||
/// Populated when we build the libc static library. A Job to build this is placed in the queue
|
||||
/// and resolved before calling linker.flush().
|
||||
libc_static_lib: ?CRTFile = null,
|
||||
libc_static_lib: ?CrtFile = null,
|
||||
/// Populated when we build the libcompiler_rt static library. A Job to build this is indicated
|
||||
/// by setting `job_queued_compiler_rt_lib` and resolved before calling linker.flush().
|
||||
compiler_rt_lib: ?CRTFile = null,
|
||||
compiler_rt_lib: ?CrtFile = null,
|
||||
/// Populated when we build the compiler_rt_obj object. A Job to build this is indicated
|
||||
/// by setting `job_queued_compiler_rt_obj` and resolved before calling linker.flush().
|
||||
compiler_rt_obj: ?CRTFile = null,
|
||||
compiler_rt_obj: ?CrtFile = null,
|
||||
/// Populated when we build the libfuzzer static library. A Job to build this
|
||||
/// is indicated by setting `job_queued_fuzzer_lib` and resolved before
|
||||
/// calling linker.flush().
|
||||
fuzzer_lib: ?CRTFile = null,
|
||||
fuzzer_lib: ?CrtFile = null,
|
||||
|
||||
glibc_so_files: ?glibc.BuiltSharedObjects = null,
|
||||
wasi_emulated_libs: []const wasi_libc.CRTFile,
|
||||
wasi_emulated_libs: []const wasi_libc.CrtFile,
|
||||
|
||||
/// For example `Scrt1.o` and `libc_nonshared.a`. These are populated after building libc from source,
|
||||
/// The set of needed CRT (C runtime) files differs depending on the target and compilation settings.
|
||||
/// The key is the basename, and the value is the absolute path to the completed build artifact.
|
||||
crt_files: std.StringHashMapUnmanaged(CRTFile) = .empty,
|
||||
crt_files: std.StringHashMapUnmanaged(CrtFile) = .empty,
|
||||
|
||||
/// How many lines of reference trace should be included per compile error.
|
||||
/// Null means only show snippet on first error.
|
||||
@ -276,20 +276,20 @@ digest: ?[Cache.bin_digest_len]u8 = null,
|
||||
pub const default_stack_protector_buffer_size = target_util.default_stack_protector_buffer_size;
|
||||
pub const SemaError = Zcu.SemaError;
|
||||
|
||||
pub const CRTFile = struct {
|
||||
pub const CrtFile = struct {
|
||||
lock: Cache.Lock,
|
||||
full_object_path: []const u8,
|
||||
full_object_path: Path,
|
||||
|
||||
pub fn isObject(cf: CRTFile) bool {
|
||||
return switch (classifyFileExt(cf.full_object_path)) {
|
||||
pub fn isObject(cf: CrtFile) bool {
|
||||
return switch (classifyFileExt(cf.full_object_path.sub_path)) {
|
||||
.object => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *CRTFile, gpa: Allocator) void {
|
||||
pub fn deinit(self: *CrtFile, gpa: Allocator) void {
|
||||
self.lock.release();
|
||||
gpa.free(self.full_object_path);
|
||||
gpa.free(self.full_object_path.sub_path);
|
||||
self.* = undefined;
|
||||
}
|
||||
};
|
||||
@ -369,13 +369,13 @@ const Job = union(enum) {
|
||||
resolve_type_fully: InternPool.Index,
|
||||
|
||||
/// one of the glibc static objects
|
||||
glibc_crt_file: glibc.CRTFile,
|
||||
glibc_crt_file: glibc.CrtFile,
|
||||
/// all of the glibc shared objects
|
||||
glibc_shared_objects,
|
||||
/// one of the musl static objects
|
||||
musl_crt_file: musl.CRTFile,
|
||||
musl_crt_file: musl.CrtFile,
|
||||
/// one of the mingw-w64 static objects
|
||||
mingw_crt_file: mingw.CRTFile,
|
||||
mingw_crt_file: mingw.CrtFile,
|
||||
/// libunwind.a, usually needed when linking libc
|
||||
libunwind: void,
|
||||
libcxx: void,
|
||||
@ -385,7 +385,7 @@ const Job = union(enum) {
|
||||
/// calls to, for example, memcpy and memset.
|
||||
zig_libc: void,
|
||||
/// one of WASI libc static objects
|
||||
wasi_libc_crt_file: wasi_libc.CRTFile,
|
||||
wasi_libc_crt_file: wasi_libc.CrtFile,
|
||||
|
||||
/// The value is the index into `system_libs`.
|
||||
windows_import_lib: usize,
|
||||
@ -422,8 +422,8 @@ pub const CObject = struct {
|
||||
status: union(enum) {
|
||||
new,
|
||||
success: struct {
|
||||
/// The outputted result. Owned by gpa.
|
||||
object_path: []u8,
|
||||
/// The outputted result. `sub_path` owned by gpa.
|
||||
object_path: Path,
|
||||
/// This is a file system lock on the cache hash manifest representing this
|
||||
/// object. It prevents other invocations of the Zig compiler from interfering
|
||||
/// with this object until released.
|
||||
@ -719,7 +719,7 @@ pub const CObject = struct {
|
||||
return true;
|
||||
},
|
||||
.success => |*success| {
|
||||
gpa.free(success.object_path);
|
||||
gpa.free(success.object_path.sub_path);
|
||||
success.lock.release();
|
||||
self.status = .new;
|
||||
return false;
|
||||
@ -1018,7 +1018,7 @@ const CacheUse = union(CacheMode) {
|
||||
};
|
||||
|
||||
pub const LinkObject = struct {
|
||||
path: []const u8,
|
||||
path: Path,
|
||||
must_link: bool = false,
|
||||
// When the library is passed via a positional argument, it will be
|
||||
// added as a full path. If it's `-l<lib>`, then just the basename.
|
||||
@ -1027,7 +1027,7 @@ pub const LinkObject = struct {
|
||||
loption: bool = false,
|
||||
|
||||
pub fn isObject(lo: LinkObject) bool {
|
||||
return switch (classifyFileExt(lo.path)) {
|
||||
return switch (classifyFileExt(lo.path.sub_path)) {
|
||||
.object => true,
|
||||
else => false,
|
||||
};
|
||||
@ -1095,7 +1095,7 @@ pub const CreateOptions = struct {
|
||||
/// * getpid
|
||||
/// * mman
|
||||
/// * signal
|
||||
wasi_emulated_libs: []const 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.
|
||||
@ -2302,7 +2302,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
|
||||
try pt.processExports();
|
||||
}
|
||||
|
||||
if (try comp.totalErrorCount() != 0) {
|
||||
if (anyErrors(comp)) {
|
||||
// Skip flushing and keep source files loaded for error reporting.
|
||||
comp.link_error_flags = .{};
|
||||
return;
|
||||
@ -2392,6 +2392,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
|
||||
.sub_path = o_sub_path,
|
||||
}, .main, main_progress_node);
|
||||
|
||||
// Calling `flush` may have produced errors, in which case the
|
||||
// cache manifest must not be written.
|
||||
if (anyErrors(comp)) return;
|
||||
|
||||
// Failure here only means an unnecessary cache miss.
|
||||
man.writeManifest() catch |err| {
|
||||
log.warn("failed to write cache manifest: {s}", .{@errorName(err)});
|
||||
@ -2578,7 +2582,7 @@ fn addNonIncrementalStuffToCacheManifest(
|
||||
}
|
||||
|
||||
for (comp.objects) |obj| {
|
||||
_ = try man.addFile(obj.path, null);
|
||||
_ = try man.addFilePath(obj.path, null);
|
||||
man.hash.add(obj.must_link);
|
||||
man.hash.add(obj.loption);
|
||||
}
|
||||
@ -2703,9 +2707,8 @@ fn emitOthers(comp: *Compilation) void {
|
||||
return;
|
||||
}
|
||||
const obj_path = comp.c_object_table.keys()[0].status.success.object_path;
|
||||
const cwd = std.fs.cwd();
|
||||
const ext = std.fs.path.extension(obj_path);
|
||||
const basename = obj_path[0 .. obj_path.len - ext.len];
|
||||
const ext = std.fs.path.extension(obj_path.sub_path);
|
||||
const dirname = obj_path.sub_path[0 .. obj_path.sub_path.len - ext.len];
|
||||
// This obj path always ends with the object file extension, but if we change the
|
||||
// extension to .ll, .bc, or .s, then it will be the path to those things.
|
||||
const outs = [_]struct {
|
||||
@ -2720,13 +2723,13 @@ fn emitOthers(comp: *Compilation) void {
|
||||
if (out.emit) |loc| {
|
||||
if (loc.directory) |directory| {
|
||||
const src_path = std.fmt.allocPrint(comp.gpa, "{s}{s}", .{
|
||||
basename, out.ext,
|
||||
dirname, out.ext,
|
||||
}) catch |err| {
|
||||
log.err("unable to copy {s}{s}: {s}", .{ basename, out.ext, @errorName(err) });
|
||||
log.err("unable to copy {s}{s}: {s}", .{ dirname, out.ext, @errorName(err) });
|
||||
continue;
|
||||
};
|
||||
defer comp.gpa.free(src_path);
|
||||
cwd.copyFile(src_path, directory.handle, loc.basename, .{}) catch |err| {
|
||||
obj_path.root_dir.handle.copyFile(src_path, directory.handle, loc.basename, .{}) catch |err| {
|
||||
log.err("unable to copy {s}: {s}", .{ src_path, @errorName(err) });
|
||||
};
|
||||
}
|
||||
@ -3292,6 +3295,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
||||
return bundle.toOwnedBundle(compile_log_text);
|
||||
}
|
||||
|
||||
fn anyErrors(comp: *Compilation) bool {
|
||||
return (totalErrorCount(comp) catch return true) != 0;
|
||||
}
|
||||
|
||||
fn totalErrorCount(comp: *Compilation) !u32 {
|
||||
var errors = try comp.getAllErrorsAlloc();
|
||||
defer errors.deinit(comp.gpa);
|
||||
@ -3774,7 +3781,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
|
||||
const named_frame = tracy.namedFrame("glibc_crt_file");
|
||||
defer named_frame.end();
|
||||
|
||||
glibc.buildCRTFile(comp, crt_file, prog_node) catch |err| {
|
||||
glibc.buildCrtFile(comp, crt_file, prog_node) catch |err| {
|
||||
// TODO Surface more error details.
|
||||
comp.lockAndSetMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{
|
||||
@errorName(err),
|
||||
@ -3798,7 +3805,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
|
||||
const named_frame = tracy.namedFrame("musl_crt_file");
|
||||
defer named_frame.end();
|
||||
|
||||
musl.buildCRTFile(comp, crt_file, prog_node) catch |err| {
|
||||
musl.buildCrtFile(comp, crt_file, prog_node) catch |err| {
|
||||
// TODO Surface more error details.
|
||||
comp.lockAndSetMiscFailure(
|
||||
.musl_crt_file,
|
||||
@ -3811,7 +3818,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
|
||||
const named_frame = tracy.namedFrame("mingw_crt_file");
|
||||
defer named_frame.end();
|
||||
|
||||
mingw.buildCRTFile(comp, crt_file, prog_node) catch |err| {
|
||||
mingw.buildCrtFile(comp, crt_file, prog_node) catch |err| {
|
||||
// TODO Surface more error details.
|
||||
comp.lockAndSetMiscFailure(
|
||||
.mingw_crt_file,
|
||||
@ -3894,7 +3901,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
|
||||
const named_frame = tracy.namedFrame("wasi_libc_crt_file");
|
||||
defer named_frame.end();
|
||||
|
||||
wasi_libc.buildCRTFile(comp, crt_file, prog_node) catch |err| {
|
||||
wasi_libc.buildCrtFile(comp, crt_file, prog_node) catch |err| {
|
||||
// TODO Surface more error details.
|
||||
comp.lockAndSetMiscFailure(
|
||||
.wasi_libc_crt_file,
|
||||
@ -4602,7 +4609,7 @@ fn buildRt(
|
||||
root_source_name: []const u8,
|
||||
misc_task: MiscTask,
|
||||
output_mode: std.builtin.OutputMode,
|
||||
out: *?CRTFile,
|
||||
out: *?CrtFile,
|
||||
prog_node: std.Progress.Node,
|
||||
) void {
|
||||
comp.buildOutputFromZig(
|
||||
@ -4703,7 +4710,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
|
||||
|
||||
log.debug("updating C object: {s}", .{c_object.src.src_path});
|
||||
|
||||
if (c_object.clearStatus(comp.gpa)) {
|
||||
const gpa = comp.gpa;
|
||||
|
||||
if (c_object.clearStatus(gpa)) {
|
||||
// There was previous failure.
|
||||
comp.mutex.lock();
|
||||
defer comp.mutex.unlock();
|
||||
@ -4722,7 +4731,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
|
||||
|
||||
try cache_helpers.hashCSource(&man, c_object.src);
|
||||
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
|
||||
defer arena_allocator.deinit();
|
||||
const arena = arena_allocator.allocator();
|
||||
|
||||
@ -4744,7 +4753,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
|
||||
const target = comp.getTarget();
|
||||
const o_ext = target.ofmt.fileExt(target.cpu.arch);
|
||||
const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {
|
||||
var argv = std.ArrayList([]const u8).init(comp.gpa);
|
||||
var argv = std.ArrayList([]const u8).init(gpa);
|
||||
defer argv.deinit();
|
||||
|
||||
// In case we are doing passthrough mode, we need to detect -S and -emit-llvm.
|
||||
@ -4908,7 +4917,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
|
||||
|
||||
switch (term) {
|
||||
.Exited => |code| if (code != 0) if (out_diag_path) |diag_file_path| {
|
||||
const bundle = CObject.Diag.Bundle.parse(comp.gpa, diag_file_path) catch |err| {
|
||||
const bundle = CObject.Diag.Bundle.parse(gpa, diag_file_path) catch |err| {
|
||||
log.err("{}: failed to parse clang diagnostics: {s}", .{ err, stderr });
|
||||
return comp.failCObj(c_object, "clang exited with code {d}", .{code});
|
||||
};
|
||||
@ -4982,9 +4991,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
|
||||
|
||||
c_object.status = .{
|
||||
.success = .{
|
||||
.object_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{
|
||||
"o", &digest, o_basename,
|
||||
}),
|
||||
.object_path = .{
|
||||
.root_dir = comp.local_cache_directory,
|
||||
.sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, o_basename }),
|
||||
},
|
||||
.lock = man.toOwnedLock(),
|
||||
},
|
||||
};
|
||||
@ -6092,18 +6102,23 @@ test "classifyFileExt" {
|
||||
try std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));
|
||||
}
|
||||
|
||||
pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {
|
||||
if (comp.wantBuildGLibCFromSource() or
|
||||
comp.wantBuildMuslFromSource() or
|
||||
comp.wantBuildMinGWFromSource() or
|
||||
comp.wantBuildWasiLibcFromSource())
|
||||
{
|
||||
return comp.crt_files.get(basename).?.full_object_path;
|
||||
}
|
||||
const lci = comp.libc_installation orelse return error.LibCInstallationNotAvailable;
|
||||
const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir;
|
||||
const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
|
||||
return full_path;
|
||||
pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) !Path {
|
||||
return (try crtFilePath(comp, basename)) orelse {
|
||||
const lci = comp.libc_installation orelse return error.LibCInstallationNotAvailable;
|
||||
const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCrtDir;
|
||||
const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
|
||||
return Path.initCwd(full_path);
|
||||
};
|
||||
}
|
||||
|
||||
pub fn crtFileAsString(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {
|
||||
const path = try get_libc_crt_file(comp, arena, basename);
|
||||
return path.toString(arena);
|
||||
}
|
||||
|
||||
pub fn crtFilePath(comp: *Compilation, basename: []const u8) Allocator.Error!?Path {
|
||||
const crt_file = comp.crt_files.get(basename) orelse return null;
|
||||
return crt_file.full_object_path;
|
||||
}
|
||||
|
||||
fn wantBuildLibCFromSource(comp: Compilation) bool {
|
||||
@ -6314,7 +6329,7 @@ fn buildOutputFromZig(
|
||||
comp: *Compilation,
|
||||
src_basename: []const u8,
|
||||
output_mode: std.builtin.OutputMode,
|
||||
out: *?CRTFile,
|
||||
out: *?CrtFile,
|
||||
misc_task_tag: MiscTask,
|
||||
prog_node: std.Progress.Node,
|
||||
) !void {
|
||||
@ -6542,15 +6557,39 @@ pub fn build_crt_file(
|
||||
comp.crt_files.putAssumeCapacityNoClobber(basename, try sub_compilation.toCrtFile());
|
||||
}
|
||||
|
||||
pub fn toCrtFile(comp: *Compilation) Allocator.Error!CRTFile {
|
||||
pub fn toCrtFile(comp: *Compilation) Allocator.Error!CrtFile {
|
||||
return .{
|
||||
.full_object_path = try comp.local_cache_directory.join(comp.gpa, &.{
|
||||
comp.cache_use.whole.bin_sub_path.?,
|
||||
}),
|
||||
.full_object_path = .{
|
||||
.root_dir = comp.local_cache_directory,
|
||||
.sub_path = try comp.gpa.dupe(u8, comp.cache_use.whole.bin_sub_path.?),
|
||||
},
|
||||
.lock = comp.cache_use.whole.moveLock(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getCrtPaths(
|
||||
comp: *Compilation,
|
||||
arena: Allocator,
|
||||
) error{ OutOfMemory, LibCInstallationMissingCrtDir }!LibCInstallation.CrtPaths {
|
||||
const target = comp.root_mod.resolved_target.result;
|
||||
const basenames = LibCInstallation.CrtBasenames.get(.{
|
||||
.target = target,
|
||||
.link_libc = comp.config.link_libc,
|
||||
.output_mode = comp.config.output_mode,
|
||||
.link_mode = comp.config.link_mode,
|
||||
.pie = comp.config.pie,
|
||||
});
|
||||
if (comp.libc_installation) |lci| return lci.resolveCrtPaths(arena, basenames, target);
|
||||
|
||||
return .{
|
||||
.crt0 = if (basenames.crt0) |basename| try comp.crtFilePath(basename) else null,
|
||||
.crti = if (basenames.crti) |basename| try comp.crtFilePath(basename) else null,
|
||||
.crtbegin = if (basenames.crtbegin) |basename| try comp.crtFilePath(basename) else null,
|
||||
.crtend = if (basenames.crtend) |basename| try comp.crtFilePath(basename) else null,
|
||||
.crtn = if (basenames.crtn) |basename| try comp.crtFilePath(basename) else null,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||
// Avoid deadlocking on building import libs such as kernel32.lib
|
||||
// This can happen when the user uses `build-exe foo.obj -lkernel32` and
|
||||
|
||||
@ -169,14 +169,14 @@ fn useElfInitFini(target: std.Target) bool {
|
||||
};
|
||||
}
|
||||
|
||||
pub const CRTFile = enum {
|
||||
pub const CrtFile = enum {
|
||||
crti_o,
|
||||
crtn_o,
|
||||
scrt1_o,
|
||||
libc_nonshared_a,
|
||||
};
|
||||
|
||||
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void {
|
||||
pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progress.Node) !void {
|
||||
if (!build_options.have_llvm) {
|
||||
return error.ZigCompilerNotBuiltWithLLVMExtensions;
|
||||
}
|
||||
@ -292,7 +292,8 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progre
|
||||
.owner = undefined,
|
||||
};
|
||||
var files = [_]Compilation.CSourceFile{ start_o, abi_note_o, init_o };
|
||||
return comp.build_crt_file("Scrt1", .Obj, .@"glibc Scrt1.o", prog_node, &files);
|
||||
const basename = if (comp.config.output_mode == .Exe and !comp.config.pie) "crt1" else "Scrt1";
|
||||
return comp.build_crt_file(basename, .Obj, .@"glibc Scrt1.o", prog_node, &files);
|
||||
},
|
||||
.libc_nonshared_a => {
|
||||
const s = path.sep_str;
|
||||
|
||||
27
src/link.zig
27
src/link.zig
@ -11,7 +11,7 @@ const wasi_libc = @import("wasi_libc.zig");
|
||||
const Air = @import("Air.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Cache = std.Build.Cache;
|
||||
const Path = Cache.Path;
|
||||
const Path = std.Build.Cache.Path;
|
||||
const Compilation = @import("Compilation.zig");
|
||||
const LibCInstallation = std.zig.LibCInstallation;
|
||||
const Liveness = @import("Liveness.zig");
|
||||
@ -34,7 +34,7 @@ pub const SystemLib = struct {
|
||||
/// 1. Windows DLLs that zig ships such as advapi32.
|
||||
/// 2. extern "foo" fn declarations where we find out about libraries too late
|
||||
/// TODO: make this non-optional and resolve those two cases somehow.
|
||||
path: ?[]const u8,
|
||||
path: ?Path,
|
||||
};
|
||||
|
||||
pub fn hashAddSystemLibs(
|
||||
@ -46,7 +46,7 @@ pub fn hashAddSystemLibs(
|
||||
for (hm.values()) |value| {
|
||||
man.hash.add(value.needed);
|
||||
man.hash.add(value.weak);
|
||||
if (value.path) |p| _ = try man.addFile(p, null);
|
||||
if (value.path) |p| _ = try man.addFilePath(p, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -551,7 +551,7 @@ pub const File = struct {
|
||||
LLDCrashed,
|
||||
LLDReportedFailure,
|
||||
LLD_LinkingIsTODO_ForSpirV,
|
||||
LibCInstallationMissingCRTDir,
|
||||
LibCInstallationMissingCrtDir,
|
||||
LibCInstallationNotAvailable,
|
||||
LinkingWithoutZigSourceUnimplemented,
|
||||
MalformedArchive,
|
||||
@ -606,18 +606,15 @@ pub const File = struct {
|
||||
const comp = base.comp;
|
||||
if (comp.clang_preprocessor_mode == .yes or comp.clang_preprocessor_mode == .pch) {
|
||||
dev.check(.clang_command);
|
||||
const gpa = comp.gpa;
|
||||
const emit = base.emit;
|
||||
// TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case)
|
||||
// Until then, we do `lld -r -o output.o input.o` even though the output is the same
|
||||
// as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file
|
||||
// to the final location. See also the corresponding TODO in Coff linking.
|
||||
const full_out_path = try emit.root_dir.join(gpa, &[_][]const u8{emit.sub_path});
|
||||
defer gpa.free(full_out_path);
|
||||
assert(comp.c_object_table.count() == 1);
|
||||
const the_key = comp.c_object_table.keys()[0];
|
||||
const cached_pp_file_path = the_key.status.success.object_path;
|
||||
try fs.cwd().copyFile(cached_pp_file_path, fs.cwd(), full_out_path, .{});
|
||||
try cached_pp_file_path.root_dir.handle.copyFile(cached_pp_file_path.sub_path, emit.root_dir.handle, emit.sub_path, .{});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -781,7 +778,7 @@ pub const File = struct {
|
||||
|
||||
log.debug("zcu_obj_path={s}", .{if (zcu_obj_path) |s| s else "(null)"});
|
||||
|
||||
const compiler_rt_path: ?[]const u8 = if (comp.include_compiler_rt)
|
||||
const compiler_rt_path: ?Path = if (comp.include_compiler_rt)
|
||||
comp.compiler_rt_obj.?.full_object_path
|
||||
else
|
||||
null;
|
||||
@ -806,18 +803,18 @@ pub const File = struct {
|
||||
base.releaseLock();
|
||||
|
||||
for (objects) |obj| {
|
||||
_ = try man.addFile(obj.path, null);
|
||||
_ = try man.addFilePath(obj.path, null);
|
||||
man.hash.add(obj.must_link);
|
||||
man.hash.add(obj.loption);
|
||||
}
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
_ = try man.addFile(key.status.success.object_path, null);
|
||||
_ = try man.addFilePath(key.status.success.object_path, null);
|
||||
}
|
||||
for (comp.win32_resource_table.keys()) |key| {
|
||||
_ = try man.addFile(key.status.success.res_path, null);
|
||||
}
|
||||
try man.addOptionalFile(zcu_obj_path);
|
||||
try man.addOptionalFile(compiler_rt_path);
|
||||
try man.addOptionalFilePath(compiler_rt_path);
|
||||
|
||||
// We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
|
||||
_ = try man.hit();
|
||||
@ -851,10 +848,10 @@ pub const File = struct {
|
||||
defer object_files.deinit();
|
||||
|
||||
for (objects) |obj| {
|
||||
object_files.appendAssumeCapacity(try arena.dupeZ(u8, obj.path));
|
||||
object_files.appendAssumeCapacity(try obj.path.toStringZ(arena));
|
||||
}
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.object_path));
|
||||
object_files.appendAssumeCapacity(try key.status.success.object_path.toStringZ(arena));
|
||||
}
|
||||
for (comp.win32_resource_table.keys()) |key| {
|
||||
object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.res_path));
|
||||
@ -863,7 +860,7 @@ pub const File = struct {
|
||||
object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
|
||||
}
|
||||
if (compiler_rt_path) |p| {
|
||||
object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
|
||||
object_files.appendAssumeCapacity(try p.toStringZ(arena));
|
||||
}
|
||||
|
||||
if (comp.verbose_link) {
|
||||
|
||||
@ -7,6 +7,7 @@ const fs = std.fs;
|
||||
const log = std.log.scoped(.link);
|
||||
const mem = std.mem;
|
||||
const Cache = std.Build.Cache;
|
||||
const Path = std.Build.Cache.Path;
|
||||
|
||||
const mingw = @import("../../mingw.zig");
|
||||
const link = @import("../../link.zig");
|
||||
@ -74,11 +75,11 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
|
||||
comptime assert(Compilation.link_hash_implementation_version == 14);
|
||||
|
||||
for (comp.objects) |obj| {
|
||||
_ = try man.addFile(obj.path, null);
|
||||
_ = try man.addFilePath(obj.path, null);
|
||||
man.hash.add(obj.must_link);
|
||||
}
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
_ = try man.addFile(key.status.success.object_path, null);
|
||||
_ = try man.addFilePath(key.status.success.object_path, null);
|
||||
}
|
||||
for (comp.win32_resource_table.keys()) |key| {
|
||||
_ = try man.addFile(key.status.success.res_path, null);
|
||||
@ -154,17 +155,19 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
|
||||
break :blk comp.c_object_table.keys()[0].status.success.object_path;
|
||||
|
||||
if (module_obj_path) |p|
|
||||
break :blk p;
|
||||
break :blk Path.initCwd(p);
|
||||
|
||||
// TODO I think this is unreachable. Audit this situation when solving the above TODO
|
||||
// regarding eliding redundant object -> object transformations.
|
||||
return error.NoObjectsToLink;
|
||||
};
|
||||
// This can happen when using --enable-cache and using the stage1 backend. In this case
|
||||
// we can skip the file copy.
|
||||
if (!mem.eql(u8, the_object_path, full_out_path)) {
|
||||
try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
|
||||
}
|
||||
try std.fs.Dir.copyFile(
|
||||
the_object_path.root_dir.handle,
|
||||
the_object_path.sub_path,
|
||||
directory.handle,
|
||||
self.base.emit.sub_path,
|
||||
.{},
|
||||
);
|
||||
} else {
|
||||
// Create an LLD command line and invoke it.
|
||||
var argv = std.ArrayList([]const u8).init(gpa);
|
||||
@ -270,14 +273,14 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
|
||||
try argv.ensureUnusedCapacity(comp.objects.len);
|
||||
for (comp.objects) |obj| {
|
||||
if (obj.must_link) {
|
||||
argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{s}", .{obj.path}));
|
||||
argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{}", .{@as(Path, obj.path)}));
|
||||
} else {
|
||||
argv.appendAssumeCapacity(obj.path);
|
||||
argv.appendAssumeCapacity(try obj.path.toString(arena));
|
||||
}
|
||||
}
|
||||
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
try argv.append(key.status.success.object_path);
|
||||
try argv.append(try key.status.success.object_path.toString(arena));
|
||||
}
|
||||
|
||||
for (comp.win32_resource_table.keys()) |key| {
|
||||
@ -401,17 +404,17 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
|
||||
}
|
||||
|
||||
if (is_dyn_lib) {
|
||||
try argv.append(try comp.get_libc_crt_file(arena, "dllcrt2.obj"));
|
||||
try argv.append(try comp.crtFileAsString(arena, "dllcrt2.obj"));
|
||||
if (target.cpu.arch == .x86) {
|
||||
try argv.append("-ALTERNATENAME:__DllMainCRTStartup@12=_DllMainCRTStartup@12");
|
||||
} else {
|
||||
try argv.append("-ALTERNATENAME:_DllMainCRTStartup=DllMainCRTStartup");
|
||||
}
|
||||
} else {
|
||||
try argv.append(try comp.get_libc_crt_file(arena, "crt2.obj"));
|
||||
try argv.append(try comp.crtFileAsString(arena, "crt2.obj"));
|
||||
}
|
||||
|
||||
try argv.append(try comp.get_libc_crt_file(arena, "mingw32.lib"));
|
||||
try argv.append(try comp.crtFileAsString(arena, "mingw32.lib"));
|
||||
} else {
|
||||
const lib_str = switch (comp.config.link_mode) {
|
||||
.dynamic => "",
|
||||
@ -456,36 +459,36 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
|
||||
|
||||
// libc++ dep
|
||||
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);
|
||||
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(comp.libunwind_static_lib.?.full_object_path);
|
||||
try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
if (comp.config.any_fuzz) {
|
||||
try argv.append(comp.fuzzer_lib.?.full_object_path);
|
||||
try argv.append(try comp.fuzzer_lib.?.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
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);
|
||||
try argv.append(try lib.full_object_path.toString(arena));
|
||||
}
|
||||
}
|
||||
// MSVC compiler_rt is missing some stuff, so we build it unconditionally but
|
||||
// and rely on weak linkage to allow MSVC compiler_rt functions to override ours.
|
||||
if (comp.compiler_rt_obj) |obj| try argv.append(obj.full_object_path);
|
||||
if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path);
|
||||
if (comp.compiler_rt_obj) |obj| try argv.append(try obj.full_object_path.toString(arena));
|
||||
if (comp.compiler_rt_lib) |lib| try argv.append(try lib.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
try argv.ensureUnusedCapacity(comp.system_libs.count());
|
||||
for (comp.system_libs.keys()) |key| {
|
||||
const lib_basename = try allocPrint(arena, "{s}.lib", .{key});
|
||||
if (comp.crt_files.get(lib_basename)) |crt_file| {
|
||||
argv.appendAssumeCapacity(crt_file.full_object_path);
|
||||
argv.appendAssumeCapacity(try crt_file.full_object_path.toString(arena));
|
||||
continue;
|
||||
}
|
||||
if (try findLib(arena, lib_basename, self.lib_dirs)) |full_path| {
|
||||
|
||||
443
src/link/Elf.zig
443
src/link/Elf.zig
@ -383,9 +383,9 @@ pub fn createEmpty(
|
||||
const index: File.Index = @intCast(try self.files.addOne(gpa));
|
||||
self.files.set(index, .{ .zig_object = .{
|
||||
.index = index,
|
||||
.path = try std.fmt.allocPrint(arena, "{s}.o", .{fs.path.stem(
|
||||
zcu.main_mod.root_src_path,
|
||||
)}),
|
||||
.basename = try std.fmt.allocPrint(arena, "{s}.o", .{
|
||||
fs.path.stem(zcu.main_mod.root_src_path),
|
||||
}),
|
||||
} });
|
||||
self.zig_object_index = index;
|
||||
try self.zigObjectPtr().?.init(self, .{
|
||||
@ -742,13 +742,12 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
|
||||
const target = self.getTarget();
|
||||
const link_mode = comp.config.link_mode;
|
||||
const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
|
||||
const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {
|
||||
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
|
||||
if (fs.path.dirname(full_out_path)) |dirname| {
|
||||
break :blk try fs.path.join(arena, &.{ dirname, path });
|
||||
} else {
|
||||
break :blk path;
|
||||
}
|
||||
const module_obj_path: ?Path = if (self.base.zcu_object_sub_path) |path| .{
|
||||
.root_dir = directory,
|
||||
.sub_path = if (fs.path.dirname(self.base.emit.sub_path)) |dirname|
|
||||
try fs.path.join(arena, &.{ dirname, path })
|
||||
else
|
||||
path,
|
||||
} else null;
|
||||
|
||||
// --verbose-link
|
||||
@ -758,7 +757,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
|
||||
if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path);
|
||||
if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path);
|
||||
|
||||
const csu = try CsuObjects.init(arena, comp);
|
||||
const csu = try comp.getCrtPaths(arena);
|
||||
|
||||
// csu prelude
|
||||
if (csu.crt0) |path| try parseObjectReportingFailure(self, path);
|
||||
@ -790,23 +789,22 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
|
||||
if (comp.libc_static_lib) |lib| try parseCrtFileReportingFailure(self, lib);
|
||||
}
|
||||
|
||||
var system_libs = std.ArrayList(SystemLib).init(arena);
|
||||
|
||||
try system_libs.ensureUnusedCapacity(comp.system_libs.values().len);
|
||||
for (comp.system_libs.values()) |lib_info| {
|
||||
system_libs.appendAssumeCapacity(.{ .needed = lib_info.needed, .path = lib_info.path.? });
|
||||
try self.parseLibraryReportingFailure(.{
|
||||
.needed = lib_info.needed,
|
||||
.path = lib_info.path.?,
|
||||
}, false);
|
||||
}
|
||||
|
||||
// libc++ dep
|
||||
if (comp.config.link_libcpp) {
|
||||
try system_libs.ensureUnusedCapacity(2);
|
||||
system_libs.appendAssumeCapacity(.{ .path = comp.libcxxabi_static_lib.?.full_object_path });
|
||||
system_libs.appendAssumeCapacity(.{ .path = comp.libcxx_static_lib.?.full_object_path });
|
||||
try self.parseLibraryReportingFailure(.{ .path = comp.libcxxabi_static_lib.?.full_object_path }, false);
|
||||
try self.parseLibraryReportingFailure(.{ .path = comp.libcxx_static_lib.?.full_object_path }, false);
|
||||
}
|
||||
|
||||
// libunwind dep
|
||||
if (comp.config.link_libunwind) {
|
||||
try system_libs.append(.{ .path = comp.libunwind_static_lib.?.full_object_path });
|
||||
try self.parseLibraryReportingFailure(.{ .path = comp.libunwind_static_lib.?.full_object_path }, false);
|
||||
}
|
||||
|
||||
// libc dep
|
||||
@ -814,7 +812,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
|
||||
if (comp.config.link_libc) {
|
||||
if (comp.libc_installation) |lc| {
|
||||
const flags = target_util.libcFullLinkFlags(target);
|
||||
try system_libs.ensureUnusedCapacity(flags.len);
|
||||
|
||||
var test_path = std.ArrayList(u8).init(arena);
|
||||
var checked_paths = std.ArrayList([]const u8).init(arena);
|
||||
@ -840,39 +837,34 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
|
||||
continue;
|
||||
}
|
||||
|
||||
const resolved_path = try arena.dupe(u8, test_path.items);
|
||||
system_libs.appendAssumeCapacity(.{ .path = resolved_path });
|
||||
const resolved_path = Path.initCwd(try arena.dupe(u8, test_path.items));
|
||||
try self.parseLibraryReportingFailure(.{ .path = resolved_path }, false);
|
||||
}
|
||||
} else if (target.isGnuLibC()) {
|
||||
try system_libs.ensureUnusedCapacity(glibc.libs.len + 1);
|
||||
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}", .{
|
||||
const lib_path = Path.initCwd(try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
|
||||
comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
|
||||
});
|
||||
system_libs.appendAssumeCapacity(.{ .path = lib_path });
|
||||
}));
|
||||
try self.parseLibraryReportingFailure(.{ .path = lib_path }, false);
|
||||
}
|
||||
system_libs.appendAssumeCapacity(.{
|
||||
try self.parseLibraryReportingFailure(.{
|
||||
.path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"),
|
||||
});
|
||||
}, false);
|
||||
} else if (target.isMusl()) {
|
||||
const path = try comp.get_libc_crt_file(arena, switch (link_mode) {
|
||||
.static => "libc.a",
|
||||
.dynamic => "libc.so",
|
||||
});
|
||||
try system_libs.append(.{ .path = path });
|
||||
try self.parseLibraryReportingFailure(.{ .path = path }, false);
|
||||
} else {
|
||||
comp.link_error_flags.missing_libc = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (system_libs.items) |lib| {
|
||||
try self.parseLibraryReportingFailure(lib, false);
|
||||
}
|
||||
|
||||
// Finally, as the last input objects we add compiler_rt and CSU postlude (if any).
|
||||
|
||||
// compiler-rt. Since compiler_rt exports symbols like `memset`, it needs
|
||||
@ -1066,10 +1058,10 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
|
||||
}
|
||||
} else null;
|
||||
|
||||
const csu = try CsuObjects.init(arena, comp);
|
||||
const csu = try comp.getCrtPaths(arena);
|
||||
const compiler_rt_path: ?[]const u8 = blk: {
|
||||
if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
|
||||
if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
|
||||
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;
|
||||
};
|
||||
|
||||
@ -1092,11 +1084,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
|
||||
|
||||
if (self.base.isRelocatable()) {
|
||||
for (comp.objects) |obj| {
|
||||
try argv.append(obj.path);
|
||||
try argv.append(try obj.path.toString(arena));
|
||||
}
|
||||
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
try argv.append(key.status.success.object_path);
|
||||
try argv.append(try key.status.success.object_path.toString(arena));
|
||||
}
|
||||
|
||||
if (module_obj_path) |p| {
|
||||
@ -1178,9 +1170,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
|
||||
}
|
||||
|
||||
// csu prelude
|
||||
if (csu.crt0) |v| try argv.append(v);
|
||||
if (csu.crti) |v| try argv.append(v);
|
||||
if (csu.crtbegin) |v| try argv.append(v);
|
||||
if (csu.crt0) |path| try argv.append(try path.toString(arena));
|
||||
if (csu.crti) |path| try argv.append(try path.toString(arena));
|
||||
if (csu.crtbegin) |path| try argv.append(try path.toString(arena));
|
||||
|
||||
for (self.lib_dirs) |lib_dir| {
|
||||
try argv.append("-L");
|
||||
@ -1205,10 +1197,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
|
||||
}
|
||||
|
||||
if (obj.loption) {
|
||||
assert(obj.path[0] == ':');
|
||||
try argv.append("-l");
|
||||
}
|
||||
try argv.append(obj.path);
|
||||
try argv.append(try obj.path.toString(arena));
|
||||
}
|
||||
if (whole_archive) {
|
||||
try argv.append("-no-whole-archive");
|
||||
@ -1216,7 +1207,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
|
||||
}
|
||||
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
try argv.append(key.status.success.object_path);
|
||||
try argv.append(try key.status.success.object_path.toString(arena));
|
||||
}
|
||||
|
||||
if (module_obj_path) |p| {
|
||||
@ -1224,17 +1215,17 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
|
||||
}
|
||||
|
||||
if (comp.config.any_sanitize_thread) {
|
||||
try argv.append(comp.tsan_lib.?.full_object_path);
|
||||
try argv.append(try comp.tsan_lib.?.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
if (comp.config.any_fuzz) {
|
||||
try argv.append(comp.fuzzer_lib.?.full_object_path);
|
||||
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(lib.full_object_path);
|
||||
try argv.append(try lib.full_object_path.toString(arena));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1258,7 +1249,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
|
||||
as_needed = true;
|
||||
},
|
||||
}
|
||||
argv.appendAssumeCapacity(lib_info.path.?);
|
||||
argv.appendAssumeCapacity(try lib_info.path.?.toString(arena));
|
||||
}
|
||||
|
||||
if (!as_needed) {
|
||||
@ -1268,13 +1259,13 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
|
||||
|
||||
// libc++ dep
|
||||
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);
|
||||
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(comp.libunwind_static_lib.?.full_object_path);
|
||||
try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
// libc dep
|
||||
@ -1295,9 +1286,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
|
||||
});
|
||||
try argv.append(lib_path);
|
||||
}
|
||||
try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
|
||||
try argv.append(try comp.crtFileAsString(arena, "libc_nonshared.a"));
|
||||
} else if (target.isMusl()) {
|
||||
try argv.append(try comp.get_libc_crt_file(arena, switch (link_mode) {
|
||||
try argv.append(try comp.crtFileAsString(arena, switch (link_mode) {
|
||||
.static => "libc.a",
|
||||
.dynamic => "libc.so",
|
||||
}));
|
||||
@ -1310,8 +1301,8 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
|
||||
}
|
||||
|
||||
// crt postlude
|
||||
if (csu.crtend) |v| try argv.append(v);
|
||||
if (csu.crtn) |v| try argv.append(v);
|
||||
if (csu.crtend) |path| try argv.append(try path.toString(arena));
|
||||
if (csu.crtn) |path| try argv.append(try path.toString(arena));
|
||||
}
|
||||
|
||||
Compilation.dump_argv(argv.items);
|
||||
@ -1331,7 +1322,7 @@ pub const ParseError = error{
|
||||
UnknownFileType,
|
||||
} || LdScript.Error || fs.Dir.AccessError || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError;
|
||||
|
||||
fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CRTFile) error{OutOfMemory}!void {
|
||||
fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CrtFile) error{OutOfMemory}!void {
|
||||
if (crt_file.isObject()) {
|
||||
try parseObjectReportingFailure(self, crt_file.full_object_path);
|
||||
} else {
|
||||
@ -1339,7 +1330,7 @@ fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CRTFile) error
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parseObjectReportingFailure(self: *Elf, path: []const u8) error{OutOfMemory}!void {
|
||||
pub fn parseObjectReportingFailure(self: *Elf, path: Path) error{OutOfMemory}!void {
|
||||
self.parseObject(path) catch |err| switch (err) {
|
||||
error.LinkFailure => return, // already reported
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
@ -1367,17 +1358,20 @@ fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {
|
||||
}
|
||||
}
|
||||
|
||||
fn parseObject(self: *Elf, path: []const u8) ParseError!void {
|
||||
fn parseObject(self: *Elf, path: Path) ParseError!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const gpa = self.base.comp.gpa;
|
||||
const handle = try fs.cwd().openFile(path, .{});
|
||||
const handle = try path.root_dir.handle.openFile(path.sub_path, .{});
|
||||
const fh = try self.addFileHandle(handle);
|
||||
|
||||
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
|
||||
const index: File.Index = @intCast(try self.files.addOne(gpa));
|
||||
self.files.set(index, .{ .object = .{
|
||||
.path = try gpa.dupe(u8, path),
|
||||
.path = .{
|
||||
.root_dir = path.root_dir,
|
||||
.sub_path = try gpa.dupe(u8, path.sub_path),
|
||||
},
|
||||
.file_handle = fh,
|
||||
.index = index,
|
||||
} });
|
||||
@ -1387,15 +1381,15 @@ fn parseObject(self: *Elf, path: []const u8) ParseError!void {
|
||||
try object.parse(self);
|
||||
}
|
||||
|
||||
fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
|
||||
fn parseArchive(self: *Elf, path: Path, must_link: bool) ParseError!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const gpa = self.base.comp.gpa;
|
||||
const handle = try fs.cwd().openFile(path, .{});
|
||||
const handle = try path.root_dir.handle.openFile(path.sub_path, .{});
|
||||
const fh = try self.addFileHandle(handle);
|
||||
|
||||
var archive = Archive{};
|
||||
var archive: Archive = .{};
|
||||
defer archive.deinit(gpa);
|
||||
try archive.parse(self, path, fh);
|
||||
|
||||
@ -1403,7 +1397,7 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
|
||||
defer gpa.free(objects);
|
||||
|
||||
for (objects) |extracted| {
|
||||
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
|
||||
const index: File.Index = @intCast(try self.files.addOne(gpa));
|
||||
self.files.set(index, .{ .object = extracted });
|
||||
const object = &self.files.items(.data)[index].object;
|
||||
object.index = index;
|
||||
@ -1418,12 +1412,15 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void {
|
||||
defer tracy.end();
|
||||
|
||||
const gpa = self.base.comp.gpa;
|
||||
const handle = try fs.cwd().openFile(lib.path, .{});
|
||||
const handle = try lib.path.root_dir.handle.openFile(lib.path.sub_path, .{});
|
||||
defer handle.close();
|
||||
|
||||
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
|
||||
self.files.set(index, .{ .shared_object = .{
|
||||
.path = try gpa.dupe(u8, lib.path),
|
||||
.path = .{
|
||||
.root_dir = lib.path.root_dir,
|
||||
.sub_path = try gpa.dupe(u8, lib.path.sub_path),
|
||||
},
|
||||
.index = index,
|
||||
.needed = lib.needed,
|
||||
.alive = lib.needed,
|
||||
@ -1439,12 +1436,12 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
|
||||
defer tracy.end();
|
||||
|
||||
const gpa = self.base.comp.gpa;
|
||||
const in_file = try fs.cwd().openFile(lib.path, .{});
|
||||
const in_file = try lib.path.root_dir.handle.openFile(lib.path.sub_path, .{});
|
||||
defer in_file.close();
|
||||
const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
|
||||
defer gpa.free(data);
|
||||
|
||||
var script = LdScript{ .path = lib.path };
|
||||
var script: LdScript = .{ .path = lib.path };
|
||||
defer script.deinit(gpa);
|
||||
try script.parse(data, self);
|
||||
|
||||
@ -1455,12 +1452,12 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
|
||||
var test_path = std.ArrayList(u8).init(arena);
|
||||
var checked_paths = std.ArrayList([]const u8).init(arena);
|
||||
|
||||
for (script.args.items) |scr_obj| {
|
||||
for (script.args.items) |script_arg| {
|
||||
checked_paths.clearRetainingCapacity();
|
||||
|
||||
success: {
|
||||
if (mem.startsWith(u8, scr_obj.path, "-l")) {
|
||||
const lib_name = scr_obj.path["-l".len..];
|
||||
if (mem.startsWith(u8, script_arg.path, "-l")) {
|
||||
const lib_name = script_arg.path["-l".len..];
|
||||
|
||||
// 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?
|
||||
@ -1474,33 +1471,30 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
|
||||
}
|
||||
} else {
|
||||
var buffer: [fs.max_path_bytes]u8 = undefined;
|
||||
if (fs.realpath(scr_obj.path, &buffer)) |path| {
|
||||
if (fs.realpath(script_arg.path, &buffer)) |path| {
|
||||
test_path.clearRetainingCapacity();
|
||||
try test_path.writer().writeAll(path);
|
||||
break :success;
|
||||
} else |_| {}
|
||||
|
||||
try checked_paths.append(try arena.dupe(u8, scr_obj.path));
|
||||
try checked_paths.append(try arena.dupe(u8, script_arg.path));
|
||||
for (self.lib_dirs) |lib_dir| {
|
||||
if (try self.accessLibPath(arena, &test_path, &checked_paths, lib_dir, scr_obj.path, null))
|
||||
if (try self.accessLibPath(arena, &test_path, &checked_paths, lib_dir, script_arg.path, null))
|
||||
break :success;
|
||||
}
|
||||
}
|
||||
|
||||
try self.reportMissingLibraryError(
|
||||
checked_paths.items,
|
||||
"missing library dependency: GNU ld script '{s}' requires '{s}', but file not found",
|
||||
.{
|
||||
lib.path,
|
||||
scr_obj.path,
|
||||
},
|
||||
"missing library dependency: GNU ld script '{}' requires '{s}', but file not found",
|
||||
.{ @as(Path, lib.path), script_arg.path },
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
const full_path = test_path.items;
|
||||
const full_path = Path.initCwd(test_path.items);
|
||||
self.parseLibrary(.{
|
||||
.needed = scr_obj.needed,
|
||||
.needed = script_arg.needed,
|
||||
.path = full_path,
|
||||
}, false) catch |err| switch (err) {
|
||||
error.LinkFailure => continue, // already reported
|
||||
@ -1841,7 +1835,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
const have_dynamic_linker = comp.config.link_libc and
|
||||
link_mode == .dynamic and is_exe_or_dyn_lib;
|
||||
const target = self.getTarget();
|
||||
const compiler_rt_path: ?[]const u8 = blk: {
|
||||
const compiler_rt_path: ?Path = blk: {
|
||||
if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
|
||||
if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
|
||||
break :blk null;
|
||||
@ -1875,17 +1869,17 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
man.hash.add(self.allow_undefined_version);
|
||||
man.hash.addOptional(self.enable_new_dtags);
|
||||
for (comp.objects) |obj| {
|
||||
_ = try man.addFile(obj.path, null);
|
||||
_ = try man.addFilePath(obj.path, null);
|
||||
man.hash.add(obj.must_link);
|
||||
man.hash.add(obj.loption);
|
||||
}
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
_ = try man.addFile(key.status.success.object_path, null);
|
||||
_ = try man.addFilePath(key.status.success.object_path, null);
|
||||
}
|
||||
try man.addOptionalFile(module_obj_path);
|
||||
try man.addOptionalFile(compiler_rt_path);
|
||||
try man.addOptionalFile(if (comp.tsan_lib) |l| l.full_object_path else null);
|
||||
try man.addOptionalFile(if (comp.fuzzer_lib) |l| l.full_object_path else null);
|
||||
try man.addOptionalFilePath(compiler_rt_path);
|
||||
try man.addOptionalFilePath(if (comp.tsan_lib) |l| l.full_object_path else null);
|
||||
try man.addOptionalFilePath(if (comp.fuzzer_lib) |l| l.full_object_path else null);
|
||||
|
||||
// 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.
|
||||
@ -1982,17 +1976,19 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
break :blk comp.c_object_table.keys()[0].status.success.object_path;
|
||||
|
||||
if (module_obj_path) |p|
|
||||
break :blk p;
|
||||
break :blk Path.initCwd(p);
|
||||
|
||||
// TODO I think this is unreachable. Audit this situation when solving the above TODO
|
||||
// regarding eliding redundant object -> object transformations.
|
||||
return error.NoObjectsToLink;
|
||||
};
|
||||
// This can happen when using --enable-cache and using the stage1 backend. In this case
|
||||
// we can skip the file copy.
|
||||
if (!mem.eql(u8, the_object_path, full_out_path)) {
|
||||
try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
|
||||
}
|
||||
try std.fs.Dir.copyFile(
|
||||
the_object_path.root_dir.handle,
|
||||
the_object_path.sub_path,
|
||||
directory.handle,
|
||||
self.base.emit.sub_path,
|
||||
.{},
|
||||
);
|
||||
} else {
|
||||
// Create an LLD command line and invoke it.
|
||||
var argv = std.ArrayList([]const u8).init(gpa);
|
||||
@ -2177,10 +2173,10 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
try argv.append(full_out_path);
|
||||
|
||||
// csu prelude
|
||||
const csu = try CsuObjects.init(arena, comp);
|
||||
if (csu.crt0) |v| try argv.append(v);
|
||||
if (csu.crti) |v| try argv.append(v);
|
||||
if (csu.crtbegin) |v| try argv.append(v);
|
||||
const csu = try comp.getCrtPaths(arena);
|
||||
if (csu.crt0) |p| try argv.append(try p.toString(arena));
|
||||
if (csu.crti) |p| try argv.append(try p.toString(arena));
|
||||
if (csu.crtbegin) |p| try argv.append(try p.toString(arena));
|
||||
|
||||
for (self.rpath_table.keys()) |rpath| {
|
||||
try argv.appendSlice(&.{ "-rpath", rpath });
|
||||
@ -2244,10 +2240,10 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
}
|
||||
|
||||
if (obj.loption) {
|
||||
assert(obj.path[0] == ':');
|
||||
assert(obj.path.sub_path[0] == ':');
|
||||
try argv.append("-l");
|
||||
}
|
||||
try argv.append(obj.path);
|
||||
try argv.append(try obj.path.toString(arena));
|
||||
}
|
||||
if (whole_archive) {
|
||||
try argv.append("-no-whole-archive");
|
||||
@ -2255,7 +2251,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
}
|
||||
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
try argv.append(key.status.success.object_path);
|
||||
try argv.append(try key.status.success.object_path.toString(arena));
|
||||
}
|
||||
|
||||
if (module_obj_path) |p| {
|
||||
@ -2264,12 +2260,12 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
|
||||
if (comp.tsan_lib) |lib| {
|
||||
assert(comp.config.any_sanitize_thread);
|
||||
try argv.append(lib.full_object_path);
|
||||
try argv.append(try lib.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
if (comp.fuzzer_lib) |lib| {
|
||||
assert(comp.config.any_fuzz);
|
||||
try argv.append(lib.full_object_path);
|
||||
try argv.append(try lib.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
// libc
|
||||
@ -2278,7 +2274,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
!comp.config.link_libc)
|
||||
{
|
||||
if (comp.libc_static_lib) |lib| {
|
||||
try argv.append(lib.full_object_path);
|
||||
try argv.append(try lib.full_object_path.toString(arena));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2311,7 +2307,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
// libraries and not static libraries (the check for that needs to be earlier),
|
||||
// but they could be full paths to .so files, in which case we
|
||||
// want to avoid prepending "-l".
|
||||
argv.appendAssumeCapacity(lib_info.path.?);
|
||||
argv.appendAssumeCapacity(try lib_info.path.?.toString(arena));
|
||||
}
|
||||
|
||||
if (!as_needed) {
|
||||
@ -2321,13 +2317,13 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
|
||||
// libc++ dep
|
||||
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);
|
||||
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(comp.libunwind_static_lib.?.full_object_path);
|
||||
try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
// libc dep
|
||||
@ -2349,9 +2345,9 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
});
|
||||
try argv.append(lib_path);
|
||||
}
|
||||
try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
|
||||
try argv.append(try comp.crtFileAsString(arena, "libc_nonshared.a"));
|
||||
} else if (target.isMusl()) {
|
||||
try argv.append(try comp.get_libc_crt_file(arena, switch (link_mode) {
|
||||
try argv.append(try comp.crtFileAsString(arena, switch (link_mode) {
|
||||
.static => "libc.a",
|
||||
.dynamic => "libc.so",
|
||||
}));
|
||||
@ -2365,12 +2361,12 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
|
||||
// to be after the shared libraries, so they are picked up from the shared
|
||||
// libraries, not libcompiler_rt.
|
||||
if (compiler_rt_path) |p| {
|
||||
try argv.append(p);
|
||||
try argv.append(try p.toString(arena));
|
||||
}
|
||||
|
||||
// crt postlude
|
||||
if (csu.crtend) |v| try argv.append(v);
|
||||
if (csu.crtn) |v| try argv.append(v);
|
||||
if (csu.crtend) |p| try argv.append(try p.toString(arena));
|
||||
if (csu.crtn) |p| try argv.append(try p.toString(arena));
|
||||
|
||||
if (self.base.allow_shlib_undefined) {
|
||||
try argv.append("--allow-shlib-undefined");
|
||||
@ -3183,8 +3179,9 @@ fn sortInitFini(self: *Elf) !void {
|
||||
const object = atom_ptr.file(self).?.object;
|
||||
const priority = blk: {
|
||||
if (is_ctor_dtor) {
|
||||
if (mem.indexOf(u8, object.path, "crtbegin") != null) break :blk std.math.minInt(i32);
|
||||
if (mem.indexOf(u8, object.path, "crtend") != null) break :blk std.math.maxInt(i32);
|
||||
const basename = object.path.basename();
|
||||
if (mem.eql(u8, basename, "crtbegin.o")) break :blk std.math.minInt(i32);
|
||||
if (mem.eql(u8, basename, "crtend.o")) break :blk std.math.maxInt(i32);
|
||||
}
|
||||
const default: i32 = if (is_ctor_dtor) -1 else std.math.maxInt(i32);
|
||||
const name = atom_ptr.name(self);
|
||||
@ -4472,210 +4469,6 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
|
||||
return actual_size +| (actual_size / ideal_factor);
|
||||
}
|
||||
|
||||
// Provide a blueprint of csu (c-runtime startup) objects for supported
|
||||
// link modes.
|
||||
//
|
||||
// This is for cross-mode targets only. For host-mode targets the system
|
||||
// compiler can be probed to produce a robust blueprint.
|
||||
//
|
||||
// Targets requiring a libc for which zig does not bundle a libc are
|
||||
// host-mode targets. Unfortunately, host-mode probes are not yet
|
||||
// implemented. For now the data is hard-coded here. Such targets are
|
||||
// { freebsd, netbsd, openbsd, dragonfly }.
|
||||
const CsuObjects = struct {
|
||||
crt0: ?[]const u8 = null,
|
||||
crti: ?[]const u8 = null,
|
||||
crtbegin: ?[]const u8 = null,
|
||||
crtend: ?[]const u8 = null,
|
||||
crtn: ?[]const u8 = null,
|
||||
|
||||
const InitArgs = struct {};
|
||||
|
||||
fn init(arena: Allocator, comp: *const Compilation) !CsuObjects {
|
||||
// crt objects are only required for libc.
|
||||
if (!comp.config.link_libc) return .{};
|
||||
|
||||
var result: CsuObjects = .{};
|
||||
|
||||
// Flatten crt cases.
|
||||
const mode: enum {
|
||||
dynamic_lib,
|
||||
dynamic_exe,
|
||||
dynamic_pie,
|
||||
static_exe,
|
||||
static_pie,
|
||||
} = switch (comp.config.output_mode) {
|
||||
.Obj => return CsuObjects{},
|
||||
.Lib => switch (comp.config.link_mode) {
|
||||
.dynamic => .dynamic_lib,
|
||||
.static => return CsuObjects{},
|
||||
},
|
||||
.Exe => switch (comp.config.link_mode) {
|
||||
.dynamic => if (comp.config.pie) .dynamic_pie else .dynamic_exe,
|
||||
.static => if (comp.config.pie) .static_pie else .static_exe,
|
||||
},
|
||||
};
|
||||
|
||||
const target = comp.root_mod.resolved_target.result;
|
||||
|
||||
if (target.isAndroid()) {
|
||||
switch (mode) {
|
||||
// zig fmt: off
|
||||
.dynamic_lib => result.set( null, null, "crtbegin_so.o", "crtend_so.o", null ),
|
||||
.dynamic_exe,
|
||||
.dynamic_pie => result.set( null, null, "crtbegin_dynamic.o", "crtend_android.o", null ),
|
||||
.static_exe,
|
||||
.static_pie => result.set( null, null, "crtbegin_static.o", "crtend_android.o", null ),
|
||||
// zig fmt: on
|
||||
}
|
||||
} else {
|
||||
switch (target.os.tag) {
|
||||
.linux => {
|
||||
switch (mode) {
|
||||
// zig fmt: off
|
||||
.dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
.dynamic_exe => result.set( "crt1.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
|
||||
.dynamic_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
.static_exe => result.set( "crt1.o", "crti.o", "crtbeginT.o", "crtend.o", "crtn.o" ),
|
||||
.static_pie => result.set( "rcrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
// zig fmt: on
|
||||
}
|
||||
if (comp.libc_installation) |_| {
|
||||
// hosted-glibc provides crtbegin/end objects in platform/compiler-specific dirs
|
||||
// and they are not known at comptime. For now null-out crtbegin/end objects;
|
||||
// there is no feature loss, zig has never linked those objects in before.
|
||||
result.crtbegin = null;
|
||||
result.crtend = null;
|
||||
} else {
|
||||
// Bundled glibc only has Scrt1.o .
|
||||
if (result.crt0 != null and target.isGnuLibC()) result.crt0 = "Scrt1.o";
|
||||
}
|
||||
},
|
||||
.dragonfly => switch (mode) {
|
||||
// zig fmt: off
|
||||
.dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
.dynamic_exe => result.set( "crt1.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
|
||||
.dynamic_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
.static_exe => result.set( "crt1.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
|
||||
.static_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
// zig fmt: on
|
||||
},
|
||||
.freebsd => switch (mode) {
|
||||
// zig fmt: off
|
||||
.dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
.dynamic_exe => result.set( "crt1.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
|
||||
.dynamic_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
.static_exe => result.set( "crt1.o", "crti.o", "crtbeginT.o", "crtend.o", "crtn.o" ),
|
||||
.static_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
// zig fmt: on
|
||||
},
|
||||
.netbsd => switch (mode) {
|
||||
// zig fmt: off
|
||||
.dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
.dynamic_exe => result.set( "crt0.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
|
||||
.dynamic_pie => result.set( "crt0.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
.static_exe => result.set( "crt0.o", "crti.o", "crtbeginT.o", "crtend.o", "crtn.o" ),
|
||||
.static_pie => result.set( "crt0.o", "crti.o", "crtbeginT.o", "crtendS.o", "crtn.o" ),
|
||||
// zig fmt: on
|
||||
},
|
||||
.openbsd => switch (mode) {
|
||||
// zig fmt: off
|
||||
.dynamic_lib => result.set( null, null, "crtbeginS.o", "crtendS.o", null ),
|
||||
.dynamic_exe,
|
||||
.dynamic_pie => result.set( "crt0.o", null, "crtbegin.o", "crtend.o", null ),
|
||||
.static_exe,
|
||||
.static_pie => result.set( "rcrt0.o", null, "crtbegin.o", "crtend.o", null ),
|
||||
// zig fmt: on
|
||||
},
|
||||
.haiku => switch (mode) {
|
||||
// zig fmt: off
|
||||
.dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
.dynamic_exe => result.set( "start_dyn.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
|
||||
.dynamic_pie => result.set( "start_dyn.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
.static_exe => result.set( "start_dyn.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
|
||||
.static_pie => result.set( "start_dyn.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
|
||||
// zig fmt: on
|
||||
},
|
||||
.solaris, .illumos => switch (mode) {
|
||||
// zig fmt: off
|
||||
.dynamic_lib => result.set( null, "crti.o", null, null, "crtn.o" ),
|
||||
.dynamic_exe,
|
||||
.dynamic_pie => result.set( "crt1.o", "crti.o", null, null, "crtn.o" ),
|
||||
.static_exe,
|
||||
.static_pie => result.set( null, null, null, null, null ),
|
||||
// zig fmt: on
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
// Convert each object to a full pathname.
|
||||
if (comp.libc_installation) |lci| {
|
||||
const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir;
|
||||
switch (target.os.tag) {
|
||||
.dragonfly => {
|
||||
if (result.crt0) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
|
||||
if (result.crti) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
|
||||
if (result.crtn) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
|
||||
|
||||
var gccv: []const u8 = undefined;
|
||||
if (target.os.version_range.semver.isAtLeast(.{ .major = 5, .minor = 4, .patch = 0 }) orelse true) {
|
||||
gccv = "gcc80";
|
||||
} else {
|
||||
gccv = "gcc54";
|
||||
}
|
||||
|
||||
if (result.crtbegin) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, gccv, obj.* });
|
||||
if (result.crtend) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, gccv, obj.* });
|
||||
},
|
||||
.haiku => {
|
||||
const gcc_dir_path = lci.gcc_dir orelse return error.LibCInstallationMissingCRTDir;
|
||||
if (result.crt0) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
|
||||
if (result.crti) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
|
||||
if (result.crtn) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
|
||||
|
||||
if (result.crtbegin) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ gcc_dir_path, obj.* });
|
||||
if (result.crtend) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ gcc_dir_path, obj.* });
|
||||
},
|
||||
else => {
|
||||
inline for (std.meta.fields(@TypeOf(result))) |f| {
|
||||
if (@field(result, f.name)) |*obj| {
|
||||
obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
} else {
|
||||
inline for (std.meta.fields(@TypeOf(result))) |f| {
|
||||
if (@field(result, f.name)) |*obj| {
|
||||
if (comp.crt_files.get(obj.*)) |crtf| {
|
||||
obj.* = crtf.full_object_path;
|
||||
} else {
|
||||
@field(result, f.name) = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn set(
|
||||
self: *CsuObjects,
|
||||
crt0: ?[]const u8,
|
||||
crti: ?[]const u8,
|
||||
crtbegin: ?[]const u8,
|
||||
crtend: ?[]const u8,
|
||||
crtn: ?[]const u8,
|
||||
) void {
|
||||
self.crt0 = crt0;
|
||||
self.crti = crti;
|
||||
self.crtbegin = crtbegin;
|
||||
self.crtend = crtend;
|
||||
self.crtn = crtn;
|
||||
}
|
||||
};
|
||||
|
||||
/// If a target compiles other output modes as dynamic libraries,
|
||||
/// this function returns true for those too.
|
||||
pub fn isEffectivelyDynLib(self: Elf) bool {
|
||||
@ -5089,13 +4882,13 @@ fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
|
||||
|
||||
pub fn addParseError(
|
||||
self: *Elf,
|
||||
path: []const u8,
|
||||
path: Path,
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) error{OutOfMemory}!void {
|
||||
var err = try self.base.addErrorWithNotes(1);
|
||||
try err.addMsg(format, args);
|
||||
try err.addNote("while parsing {s}", .{path});
|
||||
try err.addNote("while parsing {}", .{path});
|
||||
}
|
||||
|
||||
pub fn addFileError(
|
||||
@ -5121,7 +4914,7 @@ pub fn failFile(
|
||||
|
||||
pub fn failParse(
|
||||
self: *Elf,
|
||||
path: []const u8,
|
||||
path: Path,
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) error{ OutOfMemory, LinkFailure } {
|
||||
@ -5274,7 +5067,7 @@ fn fmtDumpState(
|
||||
_ = options;
|
||||
|
||||
if (self.zigObjectPtr()) |zig_object| {
|
||||
try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.path });
|
||||
try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.basename });
|
||||
try writer.print("{}{}", .{
|
||||
zig_object.fmtAtoms(self),
|
||||
zig_object.fmtSymtab(self),
|
||||
@ -5299,7 +5092,7 @@ fn fmtDumpState(
|
||||
for (self.shared_objects.items) |index| {
|
||||
const shared_object = self.file(index).?.shared_object;
|
||||
try writer.print("shared_object({d}) : ", .{index});
|
||||
try writer.print("{s}", .{shared_object.path});
|
||||
try writer.print("{}", .{shared_object.path});
|
||||
try writer.print(" : needed({})", .{shared_object.needed});
|
||||
if (!shared_object.alive) try writer.writeAll(" : [*]");
|
||||
try writer.writeByte('\n');
|
||||
@ -5482,7 +5275,7 @@ pub const null_shdr = elf.Elf64_Shdr{
|
||||
|
||||
pub const SystemLib = struct {
|
||||
needed: bool = false,
|
||||
path: []const u8,
|
||||
path: Path,
|
||||
};
|
||||
|
||||
pub const Ref = struct {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
objects: std.ArrayListUnmanaged(Object) = .empty,
|
||||
strtab: std.ArrayListUnmanaged(u8) = .empty,
|
||||
|
||||
pub fn isArchive(path: []const u8) !bool {
|
||||
const file = try std.fs.cwd().openFile(path, .{});
|
||||
pub fn isArchive(path: Path) !bool {
|
||||
const file = try path.root_dir.handle.openFile(path.sub_path, .{});
|
||||
defer file.close();
|
||||
const reader = file.reader();
|
||||
const magic = reader.readBytesNoEof(elf.ARMAG.len) catch return false;
|
||||
@ -15,7 +15,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {
|
||||
self.strtab.deinit(allocator);
|
||||
}
|
||||
|
||||
pub fn parse(self: *Archive, elf_file: *Elf, path: []const u8, handle_index: File.HandleIndex) !void {
|
||||
pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.HandleIndex) !void {
|
||||
const comp = elf_file.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
const handle = elf_file.fileHandle(handle_index);
|
||||
@ -59,19 +59,24 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: []const u8, handle_index: Fil
|
||||
else
|
||||
unreachable;
|
||||
|
||||
const object = Object{
|
||||
const object: Object = .{
|
||||
.archive = .{
|
||||
.path = try gpa.dupe(u8, path),
|
||||
.path = .{
|
||||
.root_dir = path.root_dir,
|
||||
.sub_path = try gpa.dupe(u8, path.sub_path),
|
||||
},
|
||||
.offset = pos,
|
||||
.size = obj_size,
|
||||
},
|
||||
.path = try gpa.dupe(u8, name),
|
||||
.path = Path.initCwd(try gpa.dupe(u8, name)),
|
||||
.file_handle = handle_index,
|
||||
.index = undefined,
|
||||
.alive = false,
|
||||
};
|
||||
|
||||
log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, path });
|
||||
log.debug("extracting object '{}' from archive '{}'", .{
|
||||
@as(Path, object.path), @as(Path, path),
|
||||
});
|
||||
|
||||
try self.objects.append(gpa, object);
|
||||
}
|
||||
@ -292,6 +297,7 @@ const elf = std.elf;
|
||||
const fs = std.fs;
|
||||
const log = std.log.scoped(.link);
|
||||
const mem = std.mem;
|
||||
const Path = std.Build.Cache.Path;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Archive = @This();
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
path: []const u8,
|
||||
path: Path,
|
||||
cpu_arch: ?std.Target.Cpu.Arch = null,
|
||||
args: std.ArrayListUnmanaged(Elf.SystemLib) = .empty,
|
||||
args: std.ArrayListUnmanaged(Arg) = .empty,
|
||||
|
||||
pub const Arg = struct {
|
||||
needed: bool = false,
|
||||
path: []const u8,
|
||||
};
|
||||
|
||||
pub fn deinit(scr: *LdScript, allocator: Allocator) void {
|
||||
scr.args.deinit(allocator);
|
||||
@ -47,7 +52,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
|
||||
|
||||
var it = TokenIterator{ .tokens = tokens.items };
|
||||
var parser = Parser{ .source = data, .it = &it };
|
||||
var args = std.ArrayList(Elf.SystemLib).init(gpa);
|
||||
var args = std.ArrayList(Arg).init(gpa);
|
||||
scr.doParse(.{
|
||||
.parser = &parser,
|
||||
.args = &args,
|
||||
@ -70,7 +75,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
|
||||
|
||||
fn doParse(scr: *LdScript, ctx: struct {
|
||||
parser: *Parser,
|
||||
args: *std.ArrayList(Elf.SystemLib),
|
||||
args: *std.ArrayList(Arg),
|
||||
}) !void {
|
||||
while (true) {
|
||||
ctx.parser.skipAny(&.{ .comment, .new_line });
|
||||
@ -142,7 +147,7 @@ const Parser = struct {
|
||||
return error.UnknownCpuArch;
|
||||
}
|
||||
|
||||
fn group(p: *Parser, args: *std.ArrayList(Elf.SystemLib)) !void {
|
||||
fn group(p: *Parser, args: *std.ArrayList(Arg)) !void {
|
||||
if (!p.skip(&.{.lparen})) return error.UnexpectedToken;
|
||||
|
||||
while (true) {
|
||||
@ -162,7 +167,7 @@ const Parser = struct {
|
||||
_ = try p.require(.rparen);
|
||||
}
|
||||
|
||||
fn asNeeded(p: *Parser, args: *std.ArrayList(Elf.SystemLib)) !void {
|
||||
fn asNeeded(p: *Parser, args: *std.ArrayList(Arg)) !void {
|
||||
if (!p.skip(&.{.lparen})) return error.UnexpectedToken;
|
||||
|
||||
while (p.maybe(.literal)) |tok_id| {
|
||||
@ -239,7 +244,7 @@ const Token = struct {
|
||||
|
||||
const Index = usize;
|
||||
|
||||
inline fn get(tok: Token, source: []const u8) []const u8 {
|
||||
fn get(tok: Token, source: []const u8) []const u8 {
|
||||
return source[tok.start..tok.end];
|
||||
}
|
||||
};
|
||||
@ -399,11 +404,11 @@ const TokenIterator = struct {
|
||||
return it.tokens[it.pos];
|
||||
}
|
||||
|
||||
inline fn reset(it: *TokenIterator) void {
|
||||
fn reset(it: *TokenIterator) void {
|
||||
it.pos = 0;
|
||||
}
|
||||
|
||||
inline fn seekTo(it: *TokenIterator, pos: Token.Index) void {
|
||||
fn seekTo(it: *TokenIterator, pos: Token.Index) void {
|
||||
it.pos = pos;
|
||||
}
|
||||
|
||||
@ -416,7 +421,7 @@ const TokenIterator = struct {
|
||||
}
|
||||
}
|
||||
|
||||
inline fn get(it: *TokenIterator, pos: Token.Index) Token {
|
||||
fn get(it: *TokenIterator, pos: Token.Index) Token {
|
||||
assert(pos < it.tokens.len);
|
||||
return it.tokens[pos];
|
||||
}
|
||||
@ -426,6 +431,7 @@ const LdScript = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const Path = std.Build.Cache.Path;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Elf = @import("../Elf.zig");
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
archive: ?InArchive = null,
|
||||
path: []const u8,
|
||||
/// Archive files cannot contain subdirectories, so only the basename is needed
|
||||
/// for output. However, the full path is kept for error reporting.
|
||||
path: Path,
|
||||
file_handle: File.HandleIndex,
|
||||
index: File.Index,
|
||||
|
||||
@ -36,8 +38,8 @@ output_symtab_ctx: Elf.SymtabCtx = .{},
|
||||
output_ar_state: Archive.ArState = .{},
|
||||
|
||||
pub fn deinit(self: *Object, allocator: Allocator) void {
|
||||
if (self.archive) |*ar| allocator.free(ar.path);
|
||||
allocator.free(self.path);
|
||||
if (self.archive) |*ar| allocator.free(ar.path.sub_path);
|
||||
allocator.free(self.path.sub_path);
|
||||
self.shdrs.deinit(allocator);
|
||||
self.symtab.deinit(allocator);
|
||||
self.strtab.deinit(allocator);
|
||||
@ -474,8 +476,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
|
||||
if (sym.type(elf_file) != elf.STT_FUNC)
|
||||
// TODO convert into an error
|
||||
log.debug("{s}: {s}: CIE referencing external data reference", .{
|
||||
self.fmtPath(),
|
||||
sym.name(elf_file),
|
||||
self.fmtPath(), sym.name(elf_file),
|
||||
});
|
||||
sym.flags.needs_plt = true;
|
||||
}
|
||||
@ -996,7 +997,7 @@ pub fn updateArSize(self: *Object, elf_file: *Elf) !void {
|
||||
pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {
|
||||
const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
|
||||
const offset: u64 = if (self.archive) |ar| ar.offset else 0;
|
||||
const name = self.path;
|
||||
const name = std.fs.path.basename(self.path.sub_path);
|
||||
const hdr = Archive.setArHdr(.{
|
||||
.name = if (name.len <= Archive.max_member_name_len)
|
||||
.{ .name = name }
|
||||
@ -1489,15 +1490,14 @@ fn formatPath(
|
||||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
if (object.archive) |ar| {
|
||||
try writer.writeAll(ar.path);
|
||||
try writer.writeByte('(');
|
||||
try writer.writeAll(object.path);
|
||||
try writer.writeByte(')');
|
||||
} else try writer.writeAll(object.path);
|
||||
try writer.print("{}({})", .{ ar.path, object.path });
|
||||
} else {
|
||||
try writer.print("{}", .{object.path});
|
||||
}
|
||||
}
|
||||
|
||||
const InArchive = struct {
|
||||
path: []const u8,
|
||||
path: Path,
|
||||
offset: u64,
|
||||
size: u32,
|
||||
};
|
||||
@ -1512,8 +1512,9 @@ const fs = std.fs;
|
||||
const log = std.log.scoped(.link);
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
|
||||
const Path = std.Build.Cache.Path;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
const Archive = @import("Archive.zig");
|
||||
const Atom = @import("Atom.zig");
|
||||
const AtomList = @import("AtomList.zig");
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
path: []const u8,
|
||||
path: Path,
|
||||
index: File.Index,
|
||||
|
||||
header: ?elf.Elf64_Ehdr = null,
|
||||
@ -22,8 +22,8 @@ alive: bool,
|
||||
|
||||
output_symtab_ctx: Elf.SymtabCtx = .{},
|
||||
|
||||
pub fn isSharedObject(path: []const u8) !bool {
|
||||
const file = try std.fs.cwd().openFile(path, .{});
|
||||
pub fn isSharedObject(path: Path) !bool {
|
||||
const file = try path.root_dir.handle.openFile(path.sub_path, .{});
|
||||
defer file.close();
|
||||
const reader = file.reader();
|
||||
const header = reader.readStruct(elf.Elf64_Ehdr) catch return false;
|
||||
@ -34,7 +34,7 @@ pub fn isSharedObject(path: []const u8) !bool {
|
||||
}
|
||||
|
||||
pub fn deinit(self: *SharedObject, allocator: Allocator) void {
|
||||
allocator.free(self.path);
|
||||
allocator.free(self.path.sub_path);
|
||||
self.shdrs.deinit(allocator);
|
||||
self.symtab.deinit(allocator);
|
||||
self.strtab.deinit(allocator);
|
||||
@ -319,7 +319,7 @@ pub fn asFile(self: *SharedObject) File {
|
||||
|
||||
fn verdefNum(self: *SharedObject) u32 {
|
||||
for (self.dynamic_table.items) |entry| switch (entry.d_tag) {
|
||||
elf.DT_VERDEFNUM => return @as(u32, @intCast(entry.d_val)),
|
||||
elf.DT_VERDEFNUM => return @intCast(entry.d_val),
|
||||
else => {},
|
||||
};
|
||||
return 0;
|
||||
@ -327,10 +327,10 @@ fn verdefNum(self: *SharedObject) u32 {
|
||||
|
||||
pub fn soname(self: *SharedObject) []const u8 {
|
||||
for (self.dynamic_table.items) |entry| switch (entry.d_tag) {
|
||||
elf.DT_SONAME => return self.getString(@as(u32, @intCast(entry.d_val))),
|
||||
elf.DT_SONAME => return self.getString(@intCast(entry.d_val)),
|
||||
else => {},
|
||||
};
|
||||
return std.fs.path.basename(self.path);
|
||||
return std.fs.path.basename(self.path.sub_path);
|
||||
}
|
||||
|
||||
pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
|
||||
@ -508,6 +508,7 @@ const assert = std.debug.assert;
|
||||
const elf = std.elf;
|
||||
const log = std.log.scoped(.elf);
|
||||
const mem = std.mem;
|
||||
const Path = std.Build.Cache.Path;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Elf = @import("../Elf.zig");
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
data: std.ArrayListUnmanaged(u8) = .empty,
|
||||
/// Externally owned memory.
|
||||
path: []const u8,
|
||||
basename: []const u8,
|
||||
index: File.Index,
|
||||
|
||||
symtab: std.MultiArrayList(ElfSym) = .{},
|
||||
@ -88,7 +88,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
|
||||
try self.strtab.buffer.append(gpa, 0);
|
||||
|
||||
{
|
||||
const name_off = try self.strtab.insert(gpa, self.path);
|
||||
const name_off = try self.strtab.insert(gpa, self.basename);
|
||||
const symbol_index = try self.newLocalSymbol(gpa, name_off);
|
||||
const sym = self.symbol(symbol_index);
|
||||
const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
|
||||
@ -774,7 +774,7 @@ pub fn updateArSize(self: *ZigObject) void {
|
||||
}
|
||||
|
||||
pub fn writeAr(self: ZigObject, writer: anytype) !void {
|
||||
const name = self.path;
|
||||
const name = self.basename;
|
||||
const hdr = Archive.setArHdr(.{
|
||||
.name = if (name.len <= Archive.max_member_name_len)
|
||||
.{ .name = name }
|
||||
@ -2384,9 +2384,9 @@ const relocation = @import("relocation.zig");
|
||||
const target_util = @import("../../target.zig");
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Air = @import("../../Air.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Archive = @import("Archive.zig");
|
||||
const Atom = @import("Atom.zig");
|
||||
const Dwarf = @import("../Dwarf.zig");
|
||||
|
||||
@ -23,10 +23,10 @@ pub const File = union(enum) {
|
||||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
switch (file) {
|
||||
.zig_object => |x| try writer.print("{s}", .{x.path}),
|
||||
.zig_object => |zo| try writer.writeAll(zo.basename),
|
||||
.linker_defined => try writer.writeAll("(linker defined)"),
|
||||
.object => |x| try writer.print("{}", .{x.fmtPath()}),
|
||||
.shared_object => |x| try writer.writeAll(x.path),
|
||||
.shared_object => |x| try writer.print("{}", .{@as(Path, x.path)}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,30 +240,31 @@ pub const File = union(enum) {
|
||||
return switch (file) {
|
||||
.zig_object => |x| x.updateArSymtab(ar_symtab, elf_file),
|
||||
.object => |x| x.updateArSymtab(ar_symtab, elf_file),
|
||||
inline else => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn updateArStrtab(file: File, allocator: Allocator, ar_strtab: *Archive.ArStrtab) !void {
|
||||
const path = switch (file) {
|
||||
.zig_object => |x| x.path,
|
||||
.object => |x| x.path,
|
||||
inline else => unreachable,
|
||||
};
|
||||
const state = switch (file) {
|
||||
.zig_object => |x| &x.output_ar_state,
|
||||
.object => |x| &x.output_ar_state,
|
||||
inline else => unreachable,
|
||||
};
|
||||
if (path.len <= Archive.max_member_name_len) return;
|
||||
state.name_off = try ar_strtab.insert(allocator, path);
|
||||
switch (file) {
|
||||
.zig_object => |zo| {
|
||||
const basename = zo.basename;
|
||||
if (basename.len <= Archive.max_member_name_len) return;
|
||||
zo.output_ar_state.name_off = try ar_strtab.insert(allocator, basename);
|
||||
},
|
||||
.object => |o| {
|
||||
const basename = std.fs.path.basename(o.path.sub_path);
|
||||
if (basename.len <= Archive.max_member_name_len) return;
|
||||
o.output_ar_state.name_off = try ar_strtab.insert(allocator, basename);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateArSize(file: File, elf_file: *Elf) !void {
|
||||
return switch (file) {
|
||||
.zig_object => |x| x.updateArSize(),
|
||||
.object => |x| x.updateArSize(elf_file),
|
||||
inline else => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
@ -271,7 +272,7 @@ pub const File = union(enum) {
|
||||
return switch (file) {
|
||||
.zig_object => |x| x.writeAr(writer),
|
||||
.object => |x| x.writeAr(elf_file, writer),
|
||||
inline else => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
@ -292,8 +293,9 @@ pub const File = union(enum) {
|
||||
const std = @import("std");
|
||||
const elf = std.elf;
|
||||
const log = std.log.scoped(.link);
|
||||
|
||||
const Path = std.Build.Cache.Path;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Archive = @import("Archive.zig");
|
||||
const Atom = @import("Atom.zig");
|
||||
const Cie = @import("eh_frame.zig").Cie;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
|
||||
pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {
|
||||
const gpa = comp.gpa;
|
||||
|
||||
for (comp.objects) |obj| {
|
||||
switch (Compilation.classifyFileExt(obj.path)) {
|
||||
switch (Compilation.classifyFileExt(obj.path.sub_path)) {
|
||||
.object => try parseObjectStaticLibReportingFailure(elf_file, obj.path),
|
||||
.static_library => try parseArchiveStaticLibReportingFailure(elf_file, obj.path),
|
||||
else => try elf_file.addParseError(obj.path, "unrecognized file extension", .{}),
|
||||
@ -140,7 +140,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
|
||||
if (elf_file.base.hasErrors()) return error.FlushFailure;
|
||||
}
|
||||
|
||||
pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
|
||||
pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {
|
||||
for (comp.objects) |obj| {
|
||||
if (obj.isObject()) {
|
||||
try elf_file.parseObjectReportingFailure(obj.path);
|
||||
@ -198,7 +198,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
|
||||
if (elf_file.base.hasErrors()) return error.FlushFailure;
|
||||
}
|
||||
|
||||
fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error{OutOfMemory}!void {
|
||||
fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void {
|
||||
parseObjectStaticLib(elf_file, path) catch |err| switch (err) {
|
||||
error.LinkFailure => return,
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
@ -206,7 +206,7 @@ fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error{
|
||||
};
|
||||
}
|
||||
|
||||
fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error{OutOfMemory}!void {
|
||||
fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void {
|
||||
parseArchiveStaticLib(elf_file, path) catch |err| switch (err) {
|
||||
error.LinkFailure => return,
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
@ -214,14 +214,17 @@ fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error
|
||||
};
|
||||
}
|
||||
|
||||
fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
|
||||
fn parseObjectStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
|
||||
const gpa = elf_file.base.comp.gpa;
|
||||
const handle = try std.fs.cwd().openFile(path, .{});
|
||||
const handle = try path.root_dir.handle.openFile(path.sub_path, .{});
|
||||
const fh = try elf_file.addFileHandle(handle);
|
||||
|
||||
const index = @as(File.Index, @intCast(try elf_file.files.addOne(gpa)));
|
||||
const index: File.Index = @intCast(try elf_file.files.addOne(gpa));
|
||||
elf_file.files.set(index, .{ .object = .{
|
||||
.path = try gpa.dupe(u8, path),
|
||||
.path = .{
|
||||
.root_dir = path.root_dir,
|
||||
.sub_path = try gpa.dupe(u8, path.sub_path),
|
||||
},
|
||||
.file_handle = fh,
|
||||
.index = index,
|
||||
} });
|
||||
@ -231,9 +234,9 @@ fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
|
||||
try object.parseAr(elf_file);
|
||||
}
|
||||
|
||||
fn parseArchiveStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
|
||||
fn parseArchiveStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
|
||||
const gpa = elf_file.base.comp.gpa;
|
||||
const handle = try std.fs.cwd().openFile(path, .{});
|
||||
const handle = try path.root_dir.handle.openFile(path.sub_path, .{});
|
||||
const fh = try elf_file.addFileHandle(handle);
|
||||
|
||||
var archive = Archive{};
|
||||
@ -531,6 +534,7 @@ const log = std.log.scoped(.link);
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const state_log = std.log.scoped(.link_state);
|
||||
const Path = std.Build.Cache.Path;
|
||||
const std = @import("std");
|
||||
|
||||
const Archive = @import("Archive.zig");
|
||||
|
||||
@ -144,14 +144,14 @@ hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},
|
||||
pub const Framework = struct {
|
||||
needed: bool = false,
|
||||
weak: bool = false,
|
||||
path: []const u8,
|
||||
path: Path,
|
||||
};
|
||||
|
||||
pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {
|
||||
for (hm) |value| {
|
||||
man.hash.add(value.needed);
|
||||
man.hash.add(value.weak);
|
||||
_ = try man.addFile(value.path, null);
|
||||
_ = try man.addFilePath(value.path, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,9 +239,9 @@ pub fn createEmpty(
|
||||
const index: File.Index = @intCast(try self.files.addOne(gpa));
|
||||
self.files.set(index, .{ .zig_object = .{
|
||||
.index = index,
|
||||
.path = try std.fmt.allocPrint(arena, "{s}.o", .{fs.path.stem(
|
||||
zcu.main_mod.root_src_path,
|
||||
)}),
|
||||
.basename = try std.fmt.allocPrint(arena, "{s}.o", .{
|
||||
fs.path.stem(zcu.main_mod.root_src_path),
|
||||
}),
|
||||
} });
|
||||
self.zig_object = index;
|
||||
const zo = self.getZigObject().?;
|
||||
@ -356,13 +356,12 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
|
||||
defer sub_prog_node.end();
|
||||
|
||||
const directory = self.base.emit.root_dir;
|
||||
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;
|
||||
}
|
||||
const module_obj_path: ?Path = if (self.base.zcu_object_sub_path) |path| .{
|
||||
.root_dir = directory,
|
||||
.sub_path = if (fs.path.dirname(self.base.emit.sub_path)) |dirname|
|
||||
try fs.path.join(arena, &.{ dirname, path })
|
||||
else
|
||||
path,
|
||||
} else null;
|
||||
|
||||
// --verbose-link
|
||||
@ -455,7 +454,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
|
||||
}
|
||||
|
||||
// Finally, link against compiler_rt.
|
||||
const compiler_rt_path: ?[]const u8 = blk: {
|
||||
const compiler_rt_path: ?Path = blk: {
|
||||
if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
|
||||
if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
|
||||
break :blk null;
|
||||
@ -567,7 +566,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
|
||||
// The most important here is to have the correct vm and filesize of the __LINKEDIT segment
|
||||
// where the code signature goes into.
|
||||
var codesig = CodeSignature.init(self.getPageSize());
|
||||
codesig.code_directory.ident = fs.path.basename(full_out_path);
|
||||
codesig.code_directory.ident = fs.path.basename(self.base.emit.sub_path);
|
||||
if (self.entitlements) |path| try codesig.addEntitlements(gpa, path);
|
||||
try self.writeCodeSignaturePadding(&codesig);
|
||||
break :blk codesig;
|
||||
@ -625,11 +624,11 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
|
||||
|
||||
if (self.base.isRelocatable()) {
|
||||
for (comp.objects) |obj| {
|
||||
try argv.append(obj.path);
|
||||
try argv.append(try obj.path.toString(arena));
|
||||
}
|
||||
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
try argv.append(key.status.success.object_path);
|
||||
try argv.append(try key.status.success.object_path.toString(arena));
|
||||
}
|
||||
|
||||
if (module_obj_path) |p| {
|
||||
@ -711,11 +710,11 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
|
||||
if (obj.must_link) {
|
||||
try argv.append("-force_load");
|
||||
}
|
||||
try argv.append(obj.path);
|
||||
try argv.append(try obj.path.toString(arena));
|
||||
}
|
||||
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
try argv.append(key.status.success.object_path);
|
||||
try argv.append(try key.status.success.object_path.toString(arena));
|
||||
}
|
||||
|
||||
if (module_obj_path) |p| {
|
||||
@ -723,13 +722,12 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
|
||||
}
|
||||
|
||||
if (comp.config.any_sanitize_thread) {
|
||||
const path = comp.tsan_lib.?.full_object_path;
|
||||
try argv.append(path);
|
||||
try argv.appendSlice(&.{ "-rpath", std.fs.path.dirname(path) orelse "." });
|
||||
const path = try comp.tsan_lib.?.full_object_path.toString(arena);
|
||||
try argv.appendSlice(&.{ path, "-rpath", std.fs.path.dirname(path) orelse "." });
|
||||
}
|
||||
|
||||
if (comp.config.any_fuzz) {
|
||||
try argv.append(comp.fuzzer_lib.?.full_object_path);
|
||||
try argv.append(try comp.fuzzer_lib.?.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
for (self.lib_dirs) |lib_dir| {
|
||||
@ -754,7 +752,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
|
||||
}
|
||||
|
||||
for (self.frameworks) |framework| {
|
||||
const name = fs.path.stem(framework.path);
|
||||
const name = framework.path.stem();
|
||||
const arg = if (framework.needed)
|
||||
try std.fmt.allocPrint(arena, "-needed_framework {s}", .{name})
|
||||
else if (framework.weak)
|
||||
@ -765,14 +763,16 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
|
||||
}
|
||||
|
||||
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);
|
||||
try argv.appendSlice(&.{
|
||||
try comp.libcxxabi_static_lib.?.full_object_path.toString(arena),
|
||||
try comp.libcxx_static_lib.?.full_object_path.toString(arena),
|
||||
});
|
||||
}
|
||||
|
||||
try argv.append("-lSystem");
|
||||
|
||||
if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path);
|
||||
if (comp.compiler_rt_obj) |obj| try argv.append(obj.full_object_path);
|
||||
if (comp.compiler_rt_lib) |lib| try argv.append(try lib.full_object_path.toString(arena));
|
||||
if (comp.compiler_rt_obj) |obj| try argv.append(try obj.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
Compilation.dump_argv(argv.items);
|
||||
@ -807,20 +807,20 @@ pub fn resolveLibSystem(
|
||||
return error.MissingLibSystem;
|
||||
}
|
||||
|
||||
const libsystem_path = try arena.dupe(u8, test_path.items);
|
||||
const libsystem_path = Path.initCwd(try arena.dupe(u8, test_path.items));
|
||||
try out_libs.append(.{
|
||||
.needed = true,
|
||||
.path = libsystem_path,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn classifyInputFile(self: *MachO, path: []const u8, lib: SystemLib, must_link: bool) !void {
|
||||
pub fn classifyInputFile(self: *MachO, path: Path, lib: SystemLib, must_link: bool) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
log.debug("classifying input file {s}", .{path});
|
||||
log.debug("classifying input file {}", .{path});
|
||||
|
||||
const file = try std.fs.cwd().openFile(path, .{});
|
||||
const file = try path.root_dir.handle.openFile(path.sub_path, .{});
|
||||
const fh = try self.addFileHandle(file);
|
||||
var buffer: [Archive.SARMAG]u8 = undefined;
|
||||
|
||||
@ -844,7 +844,7 @@ pub fn classifyInputFile(self: *MachO, path: []const u8, lib: SystemLib, must_li
|
||||
_ = try self.addTbd(lib, true, fh);
|
||||
}
|
||||
|
||||
fn parseFatFile(self: *MachO, file: std.fs.File, path: []const u8) !?fat.Arch {
|
||||
fn parseFatFile(self: *MachO, file: std.fs.File, path: Path) !?fat.Arch {
|
||||
const fat_h = fat.readFatHeader(file) catch return null;
|
||||
if (fat_h.magic != macho.FAT_MAGIC and fat_h.magic != macho.FAT_MAGIC_64) return null;
|
||||
var fat_archs_buffer: [2]fat.Arch = undefined;
|
||||
@ -873,7 +873,7 @@ pub fn readArMagic(file: std.fs.File, offset: usize, buffer: *[Archive.SARMAG]u8
|
||||
return buffer[0..Archive.SARMAG];
|
||||
}
|
||||
|
||||
fn addObject(self: *MachO, path: []const u8, handle: File.HandleIndex, offset: u64) !void {
|
||||
fn addObject(self: *MachO, path: Path, handle: File.HandleIndex, offset: u64) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -886,7 +886,10 @@ fn addObject(self: *MachO, path: []const u8, handle: File.HandleIndex, offset: u
|
||||
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
|
||||
self.files.set(index, .{ .object = .{
|
||||
.offset = offset,
|
||||
.path = try gpa.dupe(u8, path),
|
||||
.path = .{
|
||||
.root_dir = path.root_dir,
|
||||
.sub_path = try gpa.dupe(u8, path.sub_path),
|
||||
},
|
||||
.file_handle = handle,
|
||||
.mtime = mtime,
|
||||
.index = index,
|
||||
@ -937,7 +940,7 @@ fn addArchive(self: *MachO, lib: SystemLib, must_link: bool, handle: File.Handle
|
||||
|
||||
const gpa = self.base.comp.gpa;
|
||||
|
||||
var archive = Archive{};
|
||||
var archive: Archive = .{};
|
||||
defer archive.deinit(gpa);
|
||||
try archive.unpack(self, lib.path, handle, fat_arch);
|
||||
|
||||
@ -963,7 +966,10 @@ fn addDylib(self: *MachO, lib: SystemLib, explicit: bool, handle: File.HandleInd
|
||||
.offset = offset,
|
||||
.file_handle = handle,
|
||||
.tag = .dylib,
|
||||
.path = try gpa.dupe(u8, lib.path),
|
||||
.path = .{
|
||||
.root_dir = lib.path.root_dir,
|
||||
.sub_path = try gpa.dupe(u8, lib.path.sub_path),
|
||||
},
|
||||
.index = index,
|
||||
.needed = lib.needed,
|
||||
.weak = lib.weak,
|
||||
@ -986,7 +992,10 @@ fn addTbd(self: *MachO, lib: SystemLib, explicit: bool, handle: File.HandleIndex
|
||||
.offset = 0,
|
||||
.file_handle = handle,
|
||||
.tag = .tbd,
|
||||
.path = try gpa.dupe(u8, lib.path),
|
||||
.path = .{
|
||||
.root_dir = lib.path.root_dir,
|
||||
.sub_path = try gpa.dupe(u8, lib.path.sub_path),
|
||||
},
|
||||
.index = index,
|
||||
.needed = lib.needed,
|
||||
.weak = lib.weak,
|
||||
@ -1175,11 +1184,11 @@ fn parseDependentDylibs(self: *MachO) !void {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
const lib = SystemLib{
|
||||
.path = full_path,
|
||||
const lib: SystemLib = .{
|
||||
.path = Path.initCwd(full_path),
|
||||
.weak = is_weak,
|
||||
};
|
||||
const file = try std.fs.cwd().openFile(lib.path, .{});
|
||||
const file = try lib.path.root_dir.handle.openFile(lib.path.sub_path, .{});
|
||||
const fh = try self.addFileHandle(file);
|
||||
const fat_arch = try self.parseFatFile(file, lib.path);
|
||||
const offset = if (fat_arch) |fa| fa.offset else 0;
|
||||
@ -2865,7 +2874,8 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
|
||||
ncmds += 1;
|
||||
}
|
||||
if (comp.config.any_sanitize_thread) {
|
||||
const path = comp.tsan_lib.?.full_object_path;
|
||||
const path = try comp.tsan_lib.?.full_object_path.toString(gpa);
|
||||
defer gpa.free(path);
|
||||
const rpath = std.fs.path.dirname(path) orelse ".";
|
||||
try load_commands.writeRpathLC(rpath, writer);
|
||||
ncmds += 1;
|
||||
@ -3758,13 +3768,13 @@ pub fn eatPrefix(path: []const u8, prefix: []const u8) ?[]const u8 {
|
||||
|
||||
pub fn reportParseError(
|
||||
self: *MachO,
|
||||
path: []const u8,
|
||||
path: Path,
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) error{OutOfMemory}!void {
|
||||
var err = try self.base.addErrorWithNotes(1);
|
||||
try err.addMsg(format, args);
|
||||
try err.addNote("while parsing {s}", .{path});
|
||||
try err.addNote("while parsing {}", .{path});
|
||||
}
|
||||
|
||||
pub fn reportParseError2(
|
||||
@ -3913,7 +3923,7 @@ fn fmtDumpState(
|
||||
_ = options;
|
||||
_ = unused_fmt_string;
|
||||
if (self.getZigObject()) |zo| {
|
||||
try writer.print("zig_object({d}) : {s}\n", .{ zo.index, zo.path });
|
||||
try writer.print("zig_object({d}) : {s}\n", .{ zo.index, zo.basename });
|
||||
try writer.print("{}{}\n", .{
|
||||
zo.fmtAtoms(self),
|
||||
zo.fmtSymtab(self),
|
||||
@ -3938,9 +3948,9 @@ fn fmtDumpState(
|
||||
}
|
||||
for (self.dylibs.items) |index| {
|
||||
const dylib = self.getFile(index).?.dylib;
|
||||
try writer.print("dylib({d}) : {s} : needed({}) : weak({})", .{
|
||||
try writer.print("dylib({d}) : {} : needed({}) : weak({})", .{
|
||||
index,
|
||||
dylib.path,
|
||||
@as(Path, dylib.path),
|
||||
dylib.needed,
|
||||
dylib.weak,
|
||||
});
|
||||
@ -4442,7 +4452,7 @@ pub const default_pagezero_size: u64 = 0x100000000;
|
||||
pub const default_headerpad_size: u32 = 0x1000;
|
||||
|
||||
const SystemLib = struct {
|
||||
path: []const u8,
|
||||
path: Path,
|
||||
needed: bool = false,
|
||||
weak: bool = false,
|
||||
hidden: bool = false,
|
||||
|
||||
@ -4,7 +4,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {
|
||||
self.objects.deinit(allocator);
|
||||
}
|
||||
|
||||
pub fn unpack(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: File.HandleIndex, fat_arch: ?fat.Arch) !void {
|
||||
pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File.HandleIndex, fat_arch: ?fat.Arch) !void {
|
||||
const gpa = macho_file.base.comp.gpa;
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(gpa);
|
||||
@ -55,20 +55,23 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: []const u8, handle_index
|
||||
mem.eql(u8, name, SYMDEF_SORTED) or
|
||||
mem.eql(u8, name, SYMDEF64_SORTED)) continue;
|
||||
|
||||
const object = Object{
|
||||
const object: Object = .{
|
||||
.offset = pos,
|
||||
.in_archive = .{
|
||||
.path = try gpa.dupe(u8, path),
|
||||
.path = .{
|
||||
.root_dir = path.root_dir,
|
||||
.sub_path = try gpa.dupe(u8, path.sub_path),
|
||||
},
|
||||
.size = hdr_size,
|
||||
},
|
||||
.path = try gpa.dupe(u8, name),
|
||||
.path = Path.initCwd(try gpa.dupe(u8, name)),
|
||||
.file_handle = handle_index,
|
||||
.index = undefined,
|
||||
.alive = false,
|
||||
.mtime = hdr.date() catch 0,
|
||||
};
|
||||
|
||||
log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, path });
|
||||
log.debug("extracting object '{}' from archive '{}'", .{ object.path, path });
|
||||
|
||||
try self.objects.append(gpa, object);
|
||||
}
|
||||
@ -301,8 +304,9 @@ const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
const std = @import("std");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Path = std.Build.Cache.Path;
|
||||
|
||||
const Archive = @This();
|
||||
const File = @import("file.zig").File;
|
||||
const MachO = @import("../MachO.zig");
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/// Non-zero for fat dylibs
|
||||
offset: u64,
|
||||
path: []const u8,
|
||||
path: Path,
|
||||
index: File.Index,
|
||||
file_handle: File.HandleIndex,
|
||||
tag: enum { dylib, tbd },
|
||||
@ -28,7 +28,7 @@ referenced: bool = false,
|
||||
output_symtab_ctx: MachO.SymtabCtx = .{},
|
||||
|
||||
pub fn deinit(self: *Dylib, allocator: Allocator) void {
|
||||
allocator.free(self.path);
|
||||
allocator.free(self.path.sub_path);
|
||||
self.exports.deinit(allocator);
|
||||
self.strtab.deinit(allocator);
|
||||
if (self.id) |*id| id.deinit(allocator);
|
||||
@ -61,7 +61,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
|
||||
const file = macho_file.getFileHandle(self.file_handle);
|
||||
const offset = self.offset;
|
||||
|
||||
log.debug("parsing dylib from binary: {s}", .{self.path});
|
||||
log.debug("parsing dylib from binary: {}", .{@as(Path, self.path)});
|
||||
|
||||
var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
|
||||
{
|
||||
@ -267,7 +267,7 @@ fn parseTbd(self: *Dylib, macho_file: *MachO) !void {
|
||||
|
||||
const gpa = macho_file.base.comp.gpa;
|
||||
|
||||
log.debug("parsing dylib from stub: {s}", .{self.path});
|
||||
log.debug("parsing dylib from stub: {}", .{self.path});
|
||||
|
||||
const file = macho_file.getFileHandle(self.file_handle);
|
||||
var lib_stub = LibStub.loadFromFile(gpa, file) catch |err| {
|
||||
@ -959,8 +959,9 @@ const mem = std.mem;
|
||||
const tapi = @import("../tapi.zig");
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
const std = @import("std");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Path = std.Build.Cache.Path;
|
||||
|
||||
const Dylib = @This();
|
||||
const File = @import("file.zig").File;
|
||||
const LibStub = tapi.LibStub;
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
/// Non-zero for fat object files or archives
|
||||
offset: u64,
|
||||
path: []const u8,
|
||||
/// Archive files cannot contain subdirectories, so only the basename is needed
|
||||
/// for output. However, the full path is kept for error reporting.
|
||||
path: Path,
|
||||
file_handle: File.HandleIndex,
|
||||
mtime: u64,
|
||||
index: File.Index,
|
||||
@ -39,8 +41,8 @@ output_symtab_ctx: MachO.SymtabCtx = .{},
|
||||
output_ar_state: Archive.ArState = .{},
|
||||
|
||||
pub fn deinit(self: *Object, allocator: Allocator) void {
|
||||
if (self.in_archive) |*ar| allocator.free(ar.path);
|
||||
allocator.free(self.path);
|
||||
if (self.in_archive) |*ar| allocator.free(ar.path.sub_path);
|
||||
allocator.free(self.path.sub_path);
|
||||
for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| {
|
||||
relocs.deinit(allocator);
|
||||
sub.deinit(allocator);
|
||||
@ -1723,7 +1725,8 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
|
||||
pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
|
||||
// Header
|
||||
const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
|
||||
try Archive.writeHeader(self.path, size, ar_format, writer);
|
||||
const basename = std.fs.path.basename(self.path.sub_path);
|
||||
try Archive.writeHeader(basename, size, ar_format, writer);
|
||||
// Data
|
||||
const file = macho_file.getFileHandle(self.file_handle);
|
||||
// TODO try using copyRangeAll
|
||||
@ -1774,6 +1777,11 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {
|
||||
self.calcStabsSize(macho_file);
|
||||
}
|
||||
|
||||
fn pathLen(path: Path) usize {
|
||||
// +1 for the path separator
|
||||
return (if (path.root_dir.path) |p| p.len + @intFromBool(path.sub_path.len != 0) else 0) + path.sub_path.len;
|
||||
}
|
||||
|
||||
pub fn calcStabsSize(self: *Object, macho_file: *MachO) void {
|
||||
if (self.compile_unit) |cu| {
|
||||
const comp_dir = cu.getCompDir(self.*);
|
||||
@ -1784,9 +1792,9 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) void {
|
||||
self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name
|
||||
|
||||
if (self.in_archive) |ar| {
|
||||
self.output_symtab_ctx.strsize += @as(u32, @intCast(ar.path.len + 1 + self.path.len + 1 + 1));
|
||||
self.output_symtab_ctx.strsize += @intCast(pathLen(ar.path) + 1 + self.path.basename().len + 1 + 1);
|
||||
} else {
|
||||
self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1));
|
||||
self.output_symtab_ctx.strsize += @intCast(pathLen(self.path) + 1);
|
||||
}
|
||||
|
||||
for (self.symbols.items, 0..) |sym, i| {
|
||||
@ -2118,19 +2126,36 @@ pub fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) v
|
||||
};
|
||||
index += 1;
|
||||
if (self.in_archive) |ar| {
|
||||
@memcpy(ctx.strtab.items[n_strx..][0..ar.path.len], ar.path);
|
||||
n_strx += @intCast(ar.path.len);
|
||||
if (ar.path.root_dir.path) |p| {
|
||||
@memcpy(ctx.strtab.items[n_strx..][0..p.len], p);
|
||||
n_strx += @intCast(p.len);
|
||||
if (ar.path.sub_path.len != 0) {
|
||||
ctx.strtab.items[n_strx] = '/';
|
||||
n_strx += 1;
|
||||
}
|
||||
}
|
||||
@memcpy(ctx.strtab.items[n_strx..][0..ar.path.sub_path.len], ar.path.sub_path);
|
||||
n_strx += @intCast(ar.path.sub_path.len);
|
||||
ctx.strtab.items[n_strx] = '(';
|
||||
n_strx += 1;
|
||||
@memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path);
|
||||
n_strx += @intCast(self.path.len);
|
||||
const basename = self.path.basename();
|
||||
@memcpy(ctx.strtab.items[n_strx..][0..basename.len], basename);
|
||||
n_strx += @intCast(basename.len);
|
||||
ctx.strtab.items[n_strx] = ')';
|
||||
n_strx += 1;
|
||||
ctx.strtab.items[n_strx] = 0;
|
||||
n_strx += 1;
|
||||
} else {
|
||||
@memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path);
|
||||
n_strx += @intCast(self.path.len);
|
||||
if (self.path.root_dir.path) |p| {
|
||||
@memcpy(ctx.strtab.items[n_strx..][0..p.len], p);
|
||||
n_strx += @intCast(p.len);
|
||||
if (self.path.sub_path.len != 0) {
|
||||
ctx.strtab.items[n_strx] = '/';
|
||||
n_strx += 1;
|
||||
}
|
||||
}
|
||||
@memcpy(ctx.strtab.items[n_strx..][0..self.path.sub_path.len], self.path.sub_path);
|
||||
n_strx += @intCast(self.path.sub_path.len);
|
||||
ctx.strtab.items[n_strx] = 0;
|
||||
n_strx += 1;
|
||||
}
|
||||
@ -2666,11 +2691,12 @@ fn formatPath(
|
||||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
if (object.in_archive) |ar| {
|
||||
try writer.writeAll(ar.path);
|
||||
try writer.writeByte('(');
|
||||
try writer.writeAll(object.path);
|
||||
try writer.writeByte(')');
|
||||
} else try writer.writeAll(object.path);
|
||||
try writer.print("{}({s})", .{
|
||||
@as(Path, ar.path), object.path.basename(),
|
||||
});
|
||||
} else {
|
||||
try writer.print("{}", .{@as(Path, object.path)});
|
||||
}
|
||||
}
|
||||
|
||||
const Section = struct {
|
||||
@ -2777,7 +2803,7 @@ const CompileUnit = struct {
|
||||
};
|
||||
|
||||
const InArchive = struct {
|
||||
path: []const u8,
|
||||
path: Path,
|
||||
size: u32,
|
||||
};
|
||||
|
||||
@ -3170,6 +3196,7 @@ const math = std.math;
|
||||
const mem = std.mem;
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
const std = @import("std");
|
||||
const Path = std.Build.Cache.Path;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Archive = @import("Archive.zig");
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
data: std.ArrayListUnmanaged(u8) = .empty,
|
||||
/// Externally owned memory.
|
||||
path: []const u8,
|
||||
basename: []const u8,
|
||||
index: File.Index,
|
||||
|
||||
symtab: std.MultiArrayList(Nlist) = .{},
|
||||
@ -317,7 +317,7 @@ pub fn updateArSize(self: *ZigObject) void {
|
||||
pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !void {
|
||||
// Header
|
||||
const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
|
||||
try Archive.writeHeader(self.path, size, ar_format, writer);
|
||||
try Archive.writeHeader(self.basename, size, ar_format, writer);
|
||||
// Data
|
||||
try writer.writeAll(self.data.items);
|
||||
}
|
||||
|
||||
@ -23,10 +23,10 @@ pub const File = union(enum) {
|
||||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
switch (file) {
|
||||
.zig_object => |x| try writer.writeAll(x.path),
|
||||
.zig_object => |zo| try writer.writeAll(zo.basename),
|
||||
.internal => try writer.writeAll("internal"),
|
||||
.object => |x| try writer.print("{}", .{x.fmtPath()}),
|
||||
.dylib => |x| try writer.writeAll(x.path),
|
||||
.dylib => |dl| try writer.print("{}", .{@as(Path, dl.path)}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,13 +373,14 @@ pub const File = union(enum) {
|
||||
pub const HandleIndex = Index;
|
||||
};
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const std = @import("std");
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Path = std.Build.Cache.Path;
|
||||
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
const Archive = @import("Archive.zig");
|
||||
const Atom = @import("Atom.zig");
|
||||
const InternalObject = @import("InternalObject.zig");
|
||||
|
||||
@ -72,7 +72,8 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
|
||||
}
|
||||
|
||||
if (comp.config.any_sanitize_thread) {
|
||||
const path = comp.tsan_lib.?.full_object_path;
|
||||
const path = try comp.tsan_lib.?.full_object_path.toString(gpa);
|
||||
defer gpa.free(path);
|
||||
const rpath = std.fs.path.dirname(path) orelse ".";
|
||||
sizeofcmds += calcInstallNameLen(
|
||||
@sizeOf(macho.rpath_command),
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
|
||||
pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {
|
||||
const gpa = macho_file.base.comp.gpa;
|
||||
|
||||
// TODO: "positional arguments" is a CLI concept, not a linker concept. Delete this unnecessary array list.
|
||||
var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
|
||||
defer positionals.deinit();
|
||||
try positionals.ensureUnusedCapacity(comp.objects.len);
|
||||
@ -19,7 +20,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c
|
||||
// TODO: in the future, when we implement `dsymutil` alternative directly in the Zig
|
||||
// compiler, investigate if we can get rid of this `if` prong here.
|
||||
const path = positionals.items[0].path;
|
||||
const in_file = try std.fs.cwd().openFile(path, .{});
|
||||
const in_file = try path.root_dir.handle.openFile(path.sub_path, .{});
|
||||
const stat = try in_file.stat();
|
||||
const amt = try in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size);
|
||||
if (amt != stat.size) return error.InputOutput; // TODO: report an actual user error
|
||||
@ -72,7 +73,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c
|
||||
try writeHeader(macho_file, ncmds, sizeofcmds);
|
||||
}
|
||||
|
||||
pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
|
||||
pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Path) link.File.FlushError!void {
|
||||
const gpa = comp.gpa;
|
||||
|
||||
var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
|
||||
@ -173,21 +174,25 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
|
||||
|
||||
for (files.items) |index| {
|
||||
const file = macho_file.getFile(index).?;
|
||||
const state = switch (file) {
|
||||
.zig_object => |x| &x.output_ar_state,
|
||||
.object => |x| &x.output_ar_state,
|
||||
switch (file) {
|
||||
.zig_object => |zo| {
|
||||
const state = &zo.output_ar_state;
|
||||
pos = mem.alignForward(usize, pos, 2);
|
||||
state.file_off = pos;
|
||||
pos += @sizeOf(Archive.ar_hdr);
|
||||
pos += mem.alignForward(usize, zo.basename.len + 1, ptr_width);
|
||||
pos += math.cast(usize, state.size) orelse return error.Overflow;
|
||||
},
|
||||
.object => |o| {
|
||||
const state = &o.output_ar_state;
|
||||
pos = mem.alignForward(usize, pos, 2);
|
||||
state.file_off = pos;
|
||||
pos += @sizeOf(Archive.ar_hdr);
|
||||
pos += mem.alignForward(usize, o.path.basename().len + 1, ptr_width);
|
||||
pos += math.cast(usize, state.size) orelse return error.Overflow;
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
const path = switch (file) {
|
||||
.zig_object => |x| x.path,
|
||||
.object => |x| x.path,
|
||||
else => unreachable,
|
||||
};
|
||||
pos = mem.alignForward(usize, pos, 2);
|
||||
state.file_off = pos;
|
||||
pos += @sizeOf(Archive.ar_hdr);
|
||||
pos += mem.alignForward(usize, path.len + 1, ptr_width);
|
||||
pos += math.cast(usize, state.size) orelse return error.Overflow;
|
||||
}
|
||||
}
|
||||
|
||||
break :blk pos;
|
||||
@ -777,6 +782,7 @@ const mem = std.mem;
|
||||
const state_log = std.log.scoped(.link_state);
|
||||
const std = @import("std");
|
||||
const trace = @import("../../tracy.zig").trace;
|
||||
const Path = std.Build.Cache.Path;
|
||||
|
||||
const Archive = @import("Archive.zig");
|
||||
const Atom = @import("Atom.zig");
|
||||
|
||||
@ -15,7 +15,7 @@ pub fn insert(self: *Self, gpa: Allocator, string: []const u8) !u32 {
|
||||
if (gop.found_existing) return gop.key_ptr.*;
|
||||
|
||||
try self.buffer.ensureUnusedCapacity(gpa, string.len + 1);
|
||||
const new_off = @as(u32, @intCast(self.buffer.items.len));
|
||||
const new_off: u32 = @intCast(self.buffer.items.len);
|
||||
|
||||
self.buffer.appendSliceAssumeCapacity(string);
|
||||
self.buffer.appendAssumeCapacity(0);
|
||||
|
||||
@ -2507,6 +2507,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
|
||||
} else null;
|
||||
|
||||
// Positional arguments to the linker such as object files and static archives.
|
||||
// TODO: "positional arguments" is a CLI concept, not a linker concept. Delete this unnecessary array list.
|
||||
var positionals = std.ArrayList([]const u8).init(arena);
|
||||
try positionals.ensureUnusedCapacity(comp.objects.len);
|
||||
|
||||
@ -2527,23 +2528,23 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
|
||||
(output_mode == .Lib and link_mode == .dynamic);
|
||||
if (is_exe_or_dyn_lib) {
|
||||
for (comp.wasi_emulated_libs) |crt_file| {
|
||||
try positionals.append(try comp.get_libc_crt_file(
|
||||
try positionals.append(try comp.crtFileAsString(
|
||||
arena,
|
||||
wasi_libc.emulatedLibCRFileLibName(crt_file),
|
||||
));
|
||||
}
|
||||
|
||||
if (link_libc) {
|
||||
try positionals.append(try comp.get_libc_crt_file(
|
||||
try positionals.append(try comp.crtFileAsString(
|
||||
arena,
|
||||
wasi_libc.execModelCrtFileFullName(wasi_exec_model),
|
||||
));
|
||||
try positionals.append(try comp.get_libc_crt_file(arena, "libc.a"));
|
||||
try positionals.append(try comp.crtFileAsString(arena, "libc.a"));
|
||||
}
|
||||
|
||||
if (link_libcpp) {
|
||||
try positionals.append(comp.libcxx_static_lib.?.full_object_path);
|
||||
try positionals.append(comp.libcxxabi_static_lib.?.full_object_path);
|
||||
try positionals.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
|
||||
try positionals.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2553,15 +2554,15 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_no
|
||||
}
|
||||
|
||||
for (comp.objects) |object| {
|
||||
try positionals.append(object.path);
|
||||
try positionals.append(try object.path.toString(arena));
|
||||
}
|
||||
|
||||
for (comp.c_object_table.keys()) |c_object| {
|
||||
try positionals.append(c_object.status.success.object_path);
|
||||
try positionals.append(try c_object.status.success.object_path.toString(arena));
|
||||
}
|
||||
|
||||
if (comp.compiler_rt_lib) |lib| try positionals.append(lib.full_object_path);
|
||||
if (comp.compiler_rt_obj) |obj| try positionals.append(obj.full_object_path);
|
||||
if (comp.compiler_rt_lib) |lib| try positionals.append(try lib.full_object_path.toString(arena));
|
||||
if (comp.compiler_rt_obj) |obj| try positionals.append(try obj.full_object_path.toString(arena));
|
||||
|
||||
try wasm.parseInputFiles(positionals.items);
|
||||
|
||||
@ -3365,7 +3366,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
|
||||
defer sub_prog_node.end();
|
||||
|
||||
const is_obj = comp.config.output_mode == .Obj;
|
||||
const compiler_rt_path: ?[]const u8 = blk: {
|
||||
const compiler_rt_path: ?Path = blk: {
|
||||
if (comp.compiler_rt_lib) |lib| break :blk lib.full_object_path;
|
||||
if (comp.compiler_rt_obj) |obj| break :blk obj.full_object_path;
|
||||
break :blk null;
|
||||
@ -3387,14 +3388,14 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
|
||||
comptime assert(Compilation.link_hash_implementation_version == 14);
|
||||
|
||||
for (comp.objects) |obj| {
|
||||
_ = try man.addFile(obj.path, null);
|
||||
_ = try man.addFilePath(obj.path, null);
|
||||
man.hash.add(obj.must_link);
|
||||
}
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
_ = try man.addFile(key.status.success.object_path, null);
|
||||
_ = try man.addFilePath(key.status.success.object_path, null);
|
||||
}
|
||||
try man.addOptionalFile(module_obj_path);
|
||||
try man.addOptionalFile(compiler_rt_path);
|
||||
try man.addOptionalFilePath(compiler_rt_path);
|
||||
man.hash.addOptionalBytes(wasm.entry_name);
|
||||
man.hash.add(wasm.base.stack_size);
|
||||
man.hash.add(wasm.base.build_id);
|
||||
@ -3450,17 +3451,19 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
|
||||
break :blk comp.c_object_table.keys()[0].status.success.object_path;
|
||||
|
||||
if (module_obj_path) |p|
|
||||
break :blk p;
|
||||
break :blk Path.initCwd(p);
|
||||
|
||||
// TODO I think this is unreachable. Audit this situation when solving the above TODO
|
||||
// regarding eliding redundant object -> object transformations.
|
||||
return error.NoObjectsToLink;
|
||||
};
|
||||
// This can happen when using --enable-cache and using the stage1 backend. In this case
|
||||
// we can skip the file copy.
|
||||
if (!mem.eql(u8, the_object_path, full_out_path)) {
|
||||
try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
|
||||
}
|
||||
try std.fs.Dir.copyFile(
|
||||
the_object_path.root_dir.handle,
|
||||
the_object_path.sub_path,
|
||||
directory.handle,
|
||||
wasm.base.emit.sub_path,
|
||||
.{},
|
||||
);
|
||||
} else {
|
||||
// Create an LLD command line and invoke it.
|
||||
var argv = std.ArrayList([]const u8).init(gpa);
|
||||
@ -3581,23 +3584,23 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
|
||||
(comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic);
|
||||
if (is_exe_or_dyn_lib) {
|
||||
for (comp.wasi_emulated_libs) |crt_file| {
|
||||
try argv.append(try comp.get_libc_crt_file(
|
||||
try argv.append(try comp.crtFileAsString(
|
||||
arena,
|
||||
wasi_libc.emulatedLibCRFileLibName(crt_file),
|
||||
));
|
||||
}
|
||||
|
||||
if (comp.config.link_libc) {
|
||||
try argv.append(try comp.get_libc_crt_file(
|
||||
try argv.append(try comp.crtFileAsString(
|
||||
arena,
|
||||
wasi_libc.execModelCrtFileFullName(comp.config.wasi_exec_model),
|
||||
));
|
||||
try argv.append(try comp.get_libc_crt_file(arena, "libc.a"));
|
||||
try argv.append(try comp.crtFileAsString(arena, "libc.a"));
|
||||
}
|
||||
|
||||
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);
|
||||
try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena));
|
||||
try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3612,7 +3615,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
|
||||
try argv.append("-no-whole-archive");
|
||||
whole_archive = false;
|
||||
}
|
||||
try argv.append(obj.path);
|
||||
try argv.append(try obj.path.toString(arena));
|
||||
}
|
||||
if (whole_archive) {
|
||||
try argv.append("-no-whole-archive");
|
||||
@ -3620,7 +3623,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
|
||||
}
|
||||
|
||||
for (comp.c_object_table.keys()) |key| {
|
||||
try argv.append(key.status.success.object_path);
|
||||
try argv.append(try key.status.success.object_path.toString(arena));
|
||||
}
|
||||
if (module_obj_path) |p| {
|
||||
try argv.append(p);
|
||||
@ -3630,11 +3633,11 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
|
||||
!comp.skip_linker_dependencies and
|
||||
!comp.config.link_libc)
|
||||
{
|
||||
try argv.append(comp.libc_static_lib.?.full_object_path);
|
||||
try argv.append(try comp.libc_static_lib.?.full_object_path.toString(arena));
|
||||
}
|
||||
|
||||
if (compiler_rt_path) |p| {
|
||||
try argv.append(p);
|
||||
try argv.append(try p.toString(arena));
|
||||
}
|
||||
|
||||
if (comp.verbose_link) {
|
||||
|
||||
47
src/main.zig
47
src/main.zig
@ -13,6 +13,12 @@ const warn = std.log.warn;
|
||||
const ThreadPool = std.Thread.Pool;
|
||||
const cleanExit = std.process.cleanExit;
|
||||
const native_os = builtin.os.tag;
|
||||
const Cache = std.Build.Cache;
|
||||
const Path = std.Build.Cache.Path;
|
||||
const EnvVar = std.zig.EnvVar;
|
||||
const LibCInstallation = std.zig.LibCInstallation;
|
||||
const AstGen = std.zig.AstGen;
|
||||
const Server = std.zig.Server;
|
||||
|
||||
const tracy = @import("tracy.zig");
|
||||
const Compilation = @import("Compilation.zig");
|
||||
@ -20,16 +26,11 @@ const link = @import("link.zig");
|
||||
const Package = @import("Package.zig");
|
||||
const build_options = @import("build_options");
|
||||
const introspect = @import("introspect.zig");
|
||||
const EnvVar = std.zig.EnvVar;
|
||||
const LibCInstallation = std.zig.LibCInstallation;
|
||||
const wasi_libc = @import("wasi_libc.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const target_util = @import("target.zig");
|
||||
const crash_report = @import("crash_report.zig");
|
||||
const Zcu = @import("Zcu.zig");
|
||||
const AstGen = std.zig.AstGen;
|
||||
const mingw = @import("mingw.zig");
|
||||
const Server = std.zig.Server;
|
||||
const dev = @import("dev.zig");
|
||||
|
||||
pub const std_options = .{
|
||||
@ -1724,14 +1725,14 @@ fn buildOutputType(
|
||||
}
|
||||
} else switch (file_ext orelse Compilation.classifyFileExt(arg)) {
|
||||
.shared_library => {
|
||||
try create_module.link_objects.append(arena, .{ .path = arg });
|
||||
try create_module.link_objects.append(arena, .{ .path = Path.initCwd(arg) });
|
||||
create_module.opts.any_dyn_libs = true;
|
||||
},
|
||||
.object, .static_library => {
|
||||
try create_module.link_objects.append(arena, .{ .path = arg });
|
||||
try create_module.link_objects.append(arena, .{ .path = Path.initCwd(arg) });
|
||||
},
|
||||
.res => {
|
||||
try create_module.link_objects.append(arena, .{ .path = arg });
|
||||
try create_module.link_objects.append(arena, .{ .path = Path.initCwd(arg) });
|
||||
contains_res_file = true;
|
||||
},
|
||||
.manifest => {
|
||||
@ -1845,20 +1846,20 @@ fn buildOutputType(
|
||||
},
|
||||
.shared_library => {
|
||||
try create_module.link_objects.append(arena, .{
|
||||
.path = it.only_arg,
|
||||
.path = Path.initCwd(it.only_arg),
|
||||
.must_link = must_link,
|
||||
});
|
||||
create_module.opts.any_dyn_libs = true;
|
||||
},
|
||||
.unknown, .object, .static_library => {
|
||||
try create_module.link_objects.append(arena, .{
|
||||
.path = it.only_arg,
|
||||
.path = Path.initCwd(it.only_arg),
|
||||
.must_link = must_link,
|
||||
});
|
||||
},
|
||||
.res => {
|
||||
try create_module.link_objects.append(arena, .{
|
||||
.path = it.only_arg,
|
||||
.path = Path.initCwd(it.only_arg),
|
||||
.must_link = must_link,
|
||||
});
|
||||
contains_res_file = true;
|
||||
@ -1894,7 +1895,7 @@ fn buildOutputType(
|
||||
// binary: no extra rpaths and DSO filename exactly
|
||||
// as provided. Hello, Go.
|
||||
try create_module.link_objects.append(arena, .{
|
||||
.path = it.only_arg,
|
||||
.path = Path.initCwd(it.only_arg),
|
||||
.must_link = must_link,
|
||||
.loption = true,
|
||||
});
|
||||
@ -2532,7 +2533,7 @@ fn buildOutputType(
|
||||
install_name = linker_args_it.nextOrFatal();
|
||||
} else if (mem.eql(u8, arg, "-force_load")) {
|
||||
try create_module.link_objects.append(arena, .{
|
||||
.path = linker_args_it.nextOrFatal(),
|
||||
.path = Path.initCwd(linker_args_it.nextOrFatal()),
|
||||
.must_link = true,
|
||||
});
|
||||
} else if (mem.eql(u8, arg, "-hash-style") or
|
||||
@ -2707,7 +2708,7 @@ fn buildOutputType(
|
||||
break :b create_module.c_source_files.items[0].src_path;
|
||||
|
||||
if (create_module.link_objects.items.len >= 1)
|
||||
break :b create_module.link_objects.items[0].path;
|
||||
break :b create_module.link_objects.items[0].path.sub_path;
|
||||
|
||||
if (emit_bin == .yes)
|
||||
break :b emit_bin.yes;
|
||||
@ -2963,7 +2964,7 @@ fn buildOutputType(
|
||||
framework_dir_path,
|
||||
framework_name,
|
||||
)) {
|
||||
const path = try arena.dupe(u8, test_path.items);
|
||||
const path = Path.initCwd(try arena.dupe(u8, test_path.items));
|
||||
try resolved_frameworks.append(.{
|
||||
.needed = info.needed,
|
||||
.weak = info.weak,
|
||||
@ -3635,7 +3636,7 @@ const CreateModule = struct {
|
||||
name: []const u8,
|
||||
lib: Compilation.SystemLib,
|
||||
}),
|
||||
wasi_emulated_libs: std.ArrayListUnmanaged(wasi_libc.CRTFile),
|
||||
wasi_emulated_libs: std.ArrayListUnmanaged(wasi_libc.CrtFile),
|
||||
|
||||
c_source_files: std.ArrayListUnmanaged(Compilation.CSourceFile),
|
||||
rc_source_files: std.ArrayListUnmanaged(Compilation.RcSourceFile),
|
||||
@ -3808,7 +3809,7 @@ fn createModule(
|
||||
}
|
||||
|
||||
if (target.os.tag == .wasi) {
|
||||
if (wasi_libc.getEmulatedLibCRTFile(lib_name)) |crt_file| {
|
||||
if (wasi_libc.getEmulatedLibCrtFile(lib_name)) |crt_file| {
|
||||
try create_module.wasi_emulated_libs.append(arena, crt_file);
|
||||
continue;
|
||||
}
|
||||
@ -3929,7 +3930,7 @@ fn createModule(
|
||||
target,
|
||||
info.preferred_mode,
|
||||
)) {
|
||||
const path = try arena.dupe(u8, test_path.items);
|
||||
const path = Path.initCwd(try arena.dupe(u8, test_path.items));
|
||||
switch (info.preferred_mode) {
|
||||
.static => try create_module.link_objects.append(arena, .{ .path = path }),
|
||||
.dynamic => try create_module.resolved_system_libs.append(arena, .{
|
||||
@ -3963,7 +3964,7 @@ fn createModule(
|
||||
target,
|
||||
info.fallbackMode(),
|
||||
)) {
|
||||
const path = try arena.dupe(u8, test_path.items);
|
||||
const path = Path.initCwd(try arena.dupe(u8, test_path.items));
|
||||
switch (info.fallbackMode()) {
|
||||
.static => try create_module.link_objects.append(arena, .{ .path = path }),
|
||||
.dynamic => try create_module.resolved_system_libs.append(arena, .{
|
||||
@ -3997,7 +3998,7 @@ fn createModule(
|
||||
target,
|
||||
info.preferred_mode,
|
||||
)) {
|
||||
const path = try arena.dupe(u8, test_path.items);
|
||||
const path = Path.initCwd(try arena.dupe(u8, test_path.items));
|
||||
switch (info.preferred_mode) {
|
||||
.static => try create_module.link_objects.append(arena, .{ .path = path }),
|
||||
.dynamic => try create_module.resolved_system_libs.append(arena, .{
|
||||
@ -4021,7 +4022,7 @@ fn createModule(
|
||||
target,
|
||||
info.fallbackMode(),
|
||||
)) {
|
||||
const path = try arena.dupe(u8, test_path.items);
|
||||
const path = Path.initCwd(try arena.dupe(u8, test_path.items));
|
||||
switch (info.fallbackMode()) {
|
||||
.static => try create_module.link_objects.append(arena, .{ .path = path }),
|
||||
.dynamic => try create_module.resolved_system_libs.append(arena, .{
|
||||
@ -6163,7 +6164,7 @@ fn cmdAstCheck(
|
||||
}
|
||||
|
||||
file.mod = try Package.Module.createLimited(arena, .{
|
||||
.root = Cache.Path.cwd(),
|
||||
.root = Path.cwd(),
|
||||
.root_src_path = file.sub_file_path,
|
||||
.fully_qualified_name = "root",
|
||||
});
|
||||
@ -6523,7 +6524,7 @@ fn cmdChangelist(
|
||||
};
|
||||
|
||||
file.mod = try Package.Module.createLimited(arena, .{
|
||||
.root = Cache.Path.cwd(),
|
||||
.root = Path.cwd(),
|
||||
.root_src_path = file.sub_file_path,
|
||||
.fully_qualified_name = "root",
|
||||
});
|
||||
|
||||
@ -11,13 +11,13 @@ const build_options = @import("build_options");
|
||||
const Cache = std.Build.Cache;
|
||||
const dev = @import("dev.zig");
|
||||
|
||||
pub const CRTFile = enum {
|
||||
pub const CrtFile = enum {
|
||||
crt2_o,
|
||||
dllcrt2_o,
|
||||
mingw32_lib,
|
||||
};
|
||||
|
||||
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void {
|
||||
pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progress.Node) !void {
|
||||
if (!build_options.have_llvm) {
|
||||
return error.ZigCompilerNotBuiltWithLLVMExtensions;
|
||||
}
|
||||
@ -160,7 +160,9 @@ fn add_cc_args(
|
||||
pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||
dev.check(.build_import_lib);
|
||||
|
||||
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();
|
||||
|
||||
@ -178,7 +180,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||
|
||||
// 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 = std.fs.cwd() });
|
||||
@ -195,17 +197,18 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||
|
||||
_ = try man.addFile(def_file_path, null);
|
||||
|
||||
const final_lib_basename = try std.fmt.allocPrint(comp.gpa, "{s}.lib", .{lib_name});
|
||||
errdefer comp.gpa.free(final_lib_basename);
|
||||
const final_lib_basename = try std.fmt.allocPrint(gpa, "{s}.lib", .{lib_name});
|
||||
errdefer gpa.free(final_lib_basename);
|
||||
|
||||
if (try man.hit()) {
|
||||
const digest = man.final();
|
||||
|
||||
try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1);
|
||||
try comp.crt_files.ensureUnusedCapacity(gpa, 1);
|
||||
comp.crt_files.putAssumeCapacityNoClobber(final_lib_basename, .{
|
||||
.full_object_path = try comp.global_cache_directory.join(comp.gpa, &[_][]const u8{
|
||||
"o", &digest, final_lib_basename,
|
||||
}),
|
||||
.full_object_path = .{
|
||||
.root_dir = comp.global_cache_directory,
|
||||
.sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename }),
|
||||
},
|
||||
.lock = man.toOwnedLock(),
|
||||
});
|
||||
return;
|
||||
@ -230,7 +233,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||
};
|
||||
|
||||
const aro = @import("aro");
|
||||
var aro_comp = aro.Compilation.init(comp.gpa, std.fs.cwd());
|
||||
var aro_comp = aro.Compilation.init(gpa, std.fs.cwd());
|
||||
defer aro_comp.deinit();
|
||||
|
||||
const include_dir = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", "def-include" });
|
||||
@ -244,7 +247,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||
nosuspend stderr.print("output path: {s}\n", .{def_final_path}) catch break :print;
|
||||
}
|
||||
|
||||
try aro_comp.include_dirs.append(comp.gpa, include_dir);
|
||||
try aro_comp.include_dirs.append(gpa, include_dir);
|
||||
|
||||
const builtin_macros = try aro_comp.generateBuiltinMacros(.include_system_defines);
|
||||
const user_macros = try aro_comp.addSourceFromBuffer("<command line>", target_defines);
|
||||
@ -271,17 +274,15 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||
try pp.prettyPrintTokens(def_final_file.writer(), .result_only);
|
||||
}
|
||||
|
||||
const lib_final_path = try comp.global_cache_directory.join(comp.gpa, &[_][]const u8{
|
||||
"o", &digest, final_lib_basename,
|
||||
});
|
||||
errdefer comp.gpa.free(lib_final_path);
|
||||
const lib_final_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename });
|
||||
errdefer gpa.free(lib_final_path);
|
||||
|
||||
if (!build_options.have_llvm) return error.ZigCompilerNotBuiltWithLLVMExtensions;
|
||||
const llvm_bindings = @import("codegen/llvm/bindings.zig");
|
||||
const llvm = @import("codegen/llvm.zig");
|
||||
const arch_tag = llvm.targetArch(target.cpu.arch);
|
||||
const def_final_path_z = try arena.dupeZ(u8, def_final_path);
|
||||
const lib_final_path_z = try arena.dupeZ(u8, lib_final_path);
|
||||
const lib_final_path_z = try comp.global_cache_directory.joinZ(arena, &.{lib_final_path});
|
||||
if (llvm_bindings.WriteImportLibrary(def_final_path_z.ptr, arch_tag, lib_final_path_z.ptr, true)) {
|
||||
// TODO surface a proper error here
|
||||
log.err("unable to turn {s}.def into {s}.lib", .{ lib_name, lib_name });
|
||||
@ -292,8 +293,11 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||
log.warn("failed to write cache manifest for DLL import {s}.lib: {s}", .{ lib_name, @errorName(err) });
|
||||
};
|
||||
|
||||
try comp.crt_files.putNoClobber(comp.gpa, final_lib_basename, .{
|
||||
.full_object_path = lib_final_path,
|
||||
try comp.crt_files.putNoClobber(gpa, final_lib_basename, .{
|
||||
.full_object_path = .{
|
||||
.root_dir = comp.global_cache_directory,
|
||||
.sub_path = lib_final_path,
|
||||
},
|
||||
.lock = man.toOwnedLock(),
|
||||
});
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ const archName = std.zig.target.muslArchName;
|
||||
const Compilation = @import("Compilation.zig");
|
||||
const build_options = @import("build_options");
|
||||
|
||||
pub const CRTFile = enum {
|
||||
pub const CrtFile = enum {
|
||||
crti_o,
|
||||
crtn_o,
|
||||
crt1_o,
|
||||
@ -19,7 +19,7 @@ pub const CRTFile = enum {
|
||||
libc_so,
|
||||
};
|
||||
|
||||
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void {
|
||||
pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progress.Node) !void {
|
||||
if (!build_options.have_llvm) {
|
||||
return error.ZigCompilerNotBuiltWithLLVMExtensions;
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ const Allocator = std.mem.Allocator;
|
||||
const Compilation = @import("Compilation.zig");
|
||||
const build_options = @import("build_options");
|
||||
|
||||
pub const CRTFile = enum {
|
||||
pub const CrtFile = enum {
|
||||
crt1_reactor_o,
|
||||
crt1_command_o,
|
||||
libc_a,
|
||||
@ -16,7 +16,7 @@ pub const CRTFile = enum {
|
||||
libwasi_emulated_signal_a,
|
||||
};
|
||||
|
||||
pub fn getEmulatedLibCRTFile(lib_name: []const u8) ?CRTFile {
|
||||
pub fn getEmulatedLibCrtFile(lib_name: []const u8) ?CrtFile {
|
||||
if (mem.eql(u8, lib_name, "wasi-emulated-process-clocks")) {
|
||||
return .libwasi_emulated_process_clocks_a;
|
||||
}
|
||||
@ -32,7 +32,7 @@ pub fn getEmulatedLibCRTFile(lib_name: []const u8) ?CRTFile {
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn emulatedLibCRFileLibName(crt_file: CRTFile) []const u8 {
|
||||
pub fn emulatedLibCRFileLibName(crt_file: CrtFile) []const u8 {
|
||||
return switch (crt_file) {
|
||||
.libwasi_emulated_process_clocks_a => "libwasi-emulated-process-clocks.a",
|
||||
.libwasi_emulated_getpid_a => "libwasi-emulated-getpid.a",
|
||||
@ -42,10 +42,10 @@ pub fn emulatedLibCRFileLibName(crt_file: CRTFile) []const u8 {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn execModelCrtFile(wasi_exec_model: std.builtin.WasiExecModel) CRTFile {
|
||||
pub fn execModelCrtFile(wasi_exec_model: std.builtin.WasiExecModel) CrtFile {
|
||||
return switch (wasi_exec_model) {
|
||||
.reactor => CRTFile.crt1_reactor_o,
|
||||
.command => CRTFile.crt1_command_o,
|
||||
.reactor => CrtFile.crt1_reactor_o,
|
||||
.command => CrtFile.crt1_command_o,
|
||||
};
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ pub fn execModelCrtFileFullName(wasi_exec_model: std.builtin.WasiExecModel) []co
|
||||
};
|
||||
}
|
||||
|
||||
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void {
|
||||
pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progress.Node) !void {
|
||||
if (!build_options.have_llvm) {
|
||||
return error.ZigCompilerNotBuiltWithLLVMExtensions;
|
||||
}
|
||||
|
||||
@ -952,25 +952,25 @@ fn testEmitStaticLib(b: *Build, opts: Options) *Step {
|
||||
|
||||
const check = lib.checkObject();
|
||||
check.checkInArchiveSymtab();
|
||||
check.checkExactPath("in object", obj1.getEmittedBin());
|
||||
check.checkExact("in object obj1.o");
|
||||
check.checkExact("foo");
|
||||
check.checkInArchiveSymtab();
|
||||
check.checkExactPath("in object", obj1.getEmittedBin());
|
||||
check.checkExact("in object obj1.o");
|
||||
check.checkExact("bar");
|
||||
check.checkInArchiveSymtab();
|
||||
check.checkExactPath("in object", obj1.getEmittedBin());
|
||||
check.checkExact("in object obj1.o");
|
||||
check.checkExact("fooBar");
|
||||
check.checkInArchiveSymtab();
|
||||
check.checkExactPath("in object", obj2.getEmittedBin());
|
||||
check.checkExact("in object obj2.o");
|
||||
check.checkExact("tentative");
|
||||
check.checkInArchiveSymtab();
|
||||
check.checkExactPath("in object", obj3.getEmittedBin());
|
||||
check.checkExact("in object a_very_long_file_name_so_that_it_ends_up_in_strtab.o");
|
||||
check.checkExact("weakFoo");
|
||||
check.checkInArchiveSymtab();
|
||||
check.checkExactPath("in object", obj3.getEmittedBin());
|
||||
check.checkExact("in object a_very_long_file_name_so_that_it_ends_up_in_strtab.o");
|
||||
check.checkExact("strongBar");
|
||||
check.checkInArchiveSymtab();
|
||||
check.checkExactPath("in object", obj3.getEmittedBin());
|
||||
check.checkExact("in object a_very_long_file_name_so_that_it_ends_up_in_strtab.o");
|
||||
check.checkExact("strongBarAlias");
|
||||
test_step.dependOn(&check.step);
|
||||
|
||||
|
||||
@ -74,8 +74,8 @@ fn addCompileStep(
|
||||
.target = base.target,
|
||||
.optimize = base.optimize,
|
||||
.root_source_file = rsf: {
|
||||
const name = b.fmt("{s}.zig", .{overlay.name});
|
||||
const bytes = overlay.zig_source_bytes orelse break :rsf null;
|
||||
const name = b.fmt("{s}.zig", .{overlay.name});
|
||||
break :rsf b.addWriteFiles().add(name, bytes);
|
||||
},
|
||||
.pic = overlay.pic,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user