Commit 14c8e270bb
Changed files (29)
lib
std
src
link
lib/std/Build/Cache/Path.zig
@@ -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,
@@ -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;
lib/std/Build/Cache.zig
@@ -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| {
lib/std/zig/LibCInstallation.zig
@@ -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;
src/link/Coff/lld.zig
@@ -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| {
src/link/Elf/Archive.zig
@@ -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();
src/link/Elf/file.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;
src/link/Elf/LdScript.zig
@@ -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");
src/link/Elf/Object.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");
src/link/Elf/relocatable.zig
@@ -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");
src/link/Elf/ZigObject.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");
src/link/MachO/Archive.zig
@@ -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");
src/link/MachO/Dylib.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;
src/link/MachO/file.zig
@@ -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");
src/link/MachO/load_commands.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),
src/link/MachO/Object.zig
@@ -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");
src/link/MachO/relocatable.zig
@@ -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");
src/link/MachO/ZigObject.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);
}
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 {
src/link/MachO.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,
src/link/StringTable.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);
src/link/Wasm.zig
@@ -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) {
src/Compilation.zig
@@ -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.
@@ -2578,7 +2578,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 +2703,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 +2719,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) });
};
}
@@ -3774,7 +3773,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 +3797,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 +3810,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 +3893,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 +4601,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 +4702,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 +4723,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 +4745,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 +4909,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 +4983,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 +6094,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 +6321,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 +6549,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
src/glibc.zig
@@ -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;
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) {
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",
});
src/mingw.zig
@@ -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(),
});
}
src/musl.zig
@@ -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;
}
src/wasi_libc.zig
@@ -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;
}