authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-05-05 07:23:28+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-05-10 20:58:15+02:00
logd3a6236eef400ff0f99c3fe7d85cfda1c687bb82
tree2274b70e9e07a613f8e10d48022f8dc2e05bcc25
parent0e3609b8e05c12285786235636e9923deeea8c09
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

compiler: Support building FreeBSD crt1.o/Scrt1.o and stub shared libraries.

Only works for FreeBSD 14+. Note that we still default to targeting FreeBSD 13. Contributes to #2876.

4 files changed, 1172 insertions(+), 2 deletions(-)

CMakeLists.txt+1
...@@ -586,6 +586,7 @@ set(ZIG_STAGE2_SOURCES...@@ -586,6 +586,7 @@ set(ZIG_STAGE2_SOURCES
586 src/codegen/spirv/spec.zig586 src/codegen/spirv/spec.zig
587 src/crash_report.zig587 src/crash_report.zig
588 src/dev.zig588 src/dev.zig
589 src/libs/freebsd.zig
589 src/libs/glibc.zig590 src/libs/glibc.zig
590 src/introspect.zig591 src/introspect.zig
591 src/libs/libcxx.zig592 src/libs/libcxx.zig
src/Compilation.zig+57
...@@ -23,6 +23,7 @@ const build_options = @import("build_options");...@@ -23,6 +23,7 @@ const build_options = @import("build_options");
23const LibCInstallation = std.zig.LibCInstallation;23const LibCInstallation = std.zig.LibCInstallation;
24const glibc = @import("libs/glibc.zig");24const glibc = @import("libs/glibc.zig");
25const musl = @import("libs/musl.zig");25const musl = @import("libs/musl.zig");
26const freebsd = @import("libs/freebsd.zig");
26const mingw = @import("libs/mingw.zig");27const mingw = @import("libs/mingw.zig");
27const libunwind = @import("libs/libunwind.zig");28const libunwind = @import("libs/libunwind.zig");
28const libcxx = @import("libs/libcxx.zig");29const libcxx = @import("libs/libcxx.zig");
...@@ -248,6 +249,7 @@ compiler_rt_obj: ?CrtFile = null,...@@ -248,6 +249,7 @@ compiler_rt_obj: ?CrtFile = null,
248fuzzer_lib: ?CrtFile = null,249fuzzer_lib: ?CrtFile = null,
249250
250glibc_so_files: ?glibc.BuiltSharedObjects = null,251glibc_so_files: ?glibc.BuiltSharedObjects = null,
252freebsd_so_files: ?freebsd.BuiltSharedObjects = null,
251wasi_emulated_libs: []const wasi_libc.CrtFile,253wasi_emulated_libs: []const wasi_libc.CrtFile,
252254
253/// For example `Scrt1.o` and `libc_nonshared.a`. These are populated after building libc from source,255/// For example `Scrt1.o` and `libc_nonshared.a`. These are populated after building libc from source,
...@@ -294,12 +296,14 @@ const QueuedJobs = struct {...@@ -294,12 +296,14 @@ const QueuedJobs = struct {
294 update_builtin_zig: bool,296 update_builtin_zig: bool,
295 musl_crt_file: [@typeInfo(musl.CrtFile).@"enum".fields.len]bool = @splat(false),297 musl_crt_file: [@typeInfo(musl.CrtFile).@"enum".fields.len]bool = @splat(false),
296 glibc_crt_file: [@typeInfo(glibc.CrtFile).@"enum".fields.len]bool = @splat(false),298 glibc_crt_file: [@typeInfo(glibc.CrtFile).@"enum".fields.len]bool = @splat(false),
299 freebsd_crt_file: [@typeInfo(freebsd.CrtFile).@"enum".fields.len]bool = @splat(false),
297 /// one of WASI libc static objects300 /// one of WASI libc static objects
298 wasi_libc_crt_file: [@typeInfo(wasi_libc.CrtFile).@"enum".fields.len]bool = @splat(false),301 wasi_libc_crt_file: [@typeInfo(wasi_libc.CrtFile).@"enum".fields.len]bool = @splat(false),
299 /// one of the mingw-w64 static objects302 /// one of the mingw-w64 static objects
300 mingw_crt_file: [@typeInfo(mingw.CrtFile).@"enum".fields.len]bool = @splat(false),303 mingw_crt_file: [@typeInfo(mingw.CrtFile).@"enum".fields.len]bool = @splat(false),
301 /// all of the glibc shared objects304 /// all of the glibc shared objects
302 glibc_shared_objects: bool = false,305 glibc_shared_objects: bool = false,
306 freebsd_shared_objects: bool = false,
303 /// libunwind.a, usually needed when linking libc307 /// libunwind.a, usually needed when linking libc
304 libunwind: bool = false,308 libunwind: bool = false,
305 libcxx: bool = false,309 libcxx: bool = false,
...@@ -789,6 +793,8 @@ pub const MiscTask = enum {...@@ -789,6 +793,8 @@ pub const MiscTask = enum {
789 glibc_crt_file,793 glibc_crt_file,
790 glibc_shared_objects,794 glibc_shared_objects,
791 musl_crt_file,795 musl_crt_file,
796 freebsd_crt_file,
797 freebsd_shared_objects,
792 mingw_crt_file,798 mingw_crt_file,
793 windows_import_lib,799 windows_import_lib,
794 libunwind,800 libunwind,
...@@ -823,6 +829,9 @@ pub const MiscTask = enum {...@@ -823,6 +829,9 @@ pub const MiscTask = enum {
823 @"glibc libc_nonshared.a",829 @"glibc libc_nonshared.a",
824 @"glibc shared object",830 @"glibc shared object",
825831
832 @"freebsd libc Scrt1.o",
833 @"freebsd libc shared object",
834
826 @"mingw-w64 crt2.o",835 @"mingw-w64 crt2.o",
827 @"mingw-w64 dllcrt2.o",836 @"mingw-w64 dllcrt2.o",
828 @"mingw-w64 libmingw32.lib",837 @"mingw-w64 libmingw32.lib",
...@@ -1874,6 +1883,16 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1874,6 +1883,16 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
18741883
1875 comp.queued_jobs.glibc_crt_file[@intFromEnum(glibc.CrtFile.libc_nonshared_a)] = true;1884 comp.queued_jobs.glibc_crt_file[@intFromEnum(glibc.CrtFile.libc_nonshared_a)] = true;
1876 comp.remaining_prelink_tasks += 1;1885 comp.remaining_prelink_tasks += 1;
1886 } else if (target.isFreeBSDLibC()) {
1887 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
1888
1889 if (freebsd.needsCrt0(comp.config.output_mode)) |f| {
1890 comp.queued_jobs.freebsd_crt_file[@intFromEnum(f)] = true;
1891 comp.remaining_prelink_tasks += 1;
1892 }
1893
1894 comp.queued_jobs.freebsd_shared_objects = true;
1895 comp.remaining_prelink_tasks += freebsd.sharedObjectsCount();
1877 } else if (target.isWasiLibC()) {1896 } else if (target.isWasiLibC()) {
1878 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;1897 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
18791898
...@@ -2028,6 +2047,10 @@ pub fn destroy(comp: *Compilation) void {...@@ -2028,6 +2047,10 @@ pub fn destroy(comp: *Compilation) void {
2028 glibc_file.deinit(gpa);2047 glibc_file.deinit(gpa);
2029 }2048 }
20302049
2050 if (comp.freebsd_so_files) |*freebsd_file| {
2051 freebsd_file.deinit(gpa);
2052 }
2053
2031 for (comp.c_object_table.keys()) |key| {2054 for (comp.c_object_table.keys()) |key| {
2032 key.destroy(gpa);2055 key.destroy(gpa);
2033 }2056 }
...@@ -3839,6 +3862,10 @@ fn performAllTheWorkInner(...@@ -3839,6 +3862,10 @@ fn performAllTheWorkInner(
3839 comp.link_task_wait_group.spawnManager(buildGlibcSharedObjects, .{ comp, main_progress_node });3862 comp.link_task_wait_group.spawnManager(buildGlibcSharedObjects, .{ comp, main_progress_node });
3840 }3863 }
38413864
3865 if (comp.queued_jobs.freebsd_shared_objects) {
3866 comp.link_task_wait_group.spawnManager(buildFreeBSDSharedObjects, .{ comp, main_progress_node });
3867 }
3868
3842 if (comp.queued_jobs.libunwind) {3869 if (comp.queued_jobs.libunwind) {
3843 comp.link_task_wait_group.spawnManager(buildLibUnwind, .{ comp, main_progress_node });3870 comp.link_task_wait_group.spawnManager(buildLibUnwind, .{ comp, main_progress_node });
3844 }3871 }
...@@ -3873,6 +3900,13 @@ fn performAllTheWorkInner(...@@ -3873,6 +3900,13 @@ fn performAllTheWorkInner(
3873 }3900 }
3874 }3901 }
38753902
3903 for (0..@typeInfo(freebsd.CrtFile).@"enum".fields.len) |i| {
3904 if (comp.queued_jobs.freebsd_crt_file[i]) {
3905 const tag: freebsd.CrtFile = @enumFromInt(i);
3906 comp.link_task_wait_group.spawnManager(buildFreeBSDCrtFile, .{ comp, tag, main_progress_node });
3907 }
3908 }
3909
3876 for (0..@typeInfo(wasi_libc.CrtFile).@"enum".fields.len) |i| {3910 for (0..@typeInfo(wasi_libc.CrtFile).@"enum".fields.len) |i| {
3877 if (comp.queued_jobs.wasi_libc_crt_file[i]) {3911 if (comp.queued_jobs.wasi_libc_crt_file[i]) {
3878 const tag: wasi_libc.CrtFile = @enumFromInt(i);3912 const tag: wasi_libc.CrtFile = @enumFromInt(i);
...@@ -4876,6 +4910,29 @@ fn buildGlibcSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) voi...@@ -4876,6 +4910,29 @@ fn buildGlibcSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) voi
4876 }4910 }
4877}4911}
48784912
4913fn buildFreeBSDCrtFile(comp: *Compilation, crt_file: freebsd.CrtFile, prog_node: std.Progress.Node) void {
4914 if (freebsd.buildCrtFile(comp, crt_file, prog_node)) |_| {
4915 comp.queued_jobs.freebsd_crt_file[@intFromEnum(crt_file)] = false;
4916 } else |err| switch (err) {
4917 error.SubCompilationFailed => return, // error reported already
4918 else => comp.lockAndSetMiscFailure(.freebsd_crt_file, "unable to build FreeBSD {s}: {s}", .{
4919 @tagName(crt_file), @errorName(err),
4920 }),
4921 }
4922}
4923
4924fn buildFreeBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void {
4925 if (freebsd.buildSharedObjects(comp, prog_node)) |_| {
4926 // The job should no longer be queued up since it succeeded.
4927 comp.queued_jobs.freebsd_shared_objects = false;
4928 } else |err| switch (err) {
4929 error.SubCompilationFailed => return, // error reported already
4930 else => comp.lockAndSetMiscFailure(.freebsd_shared_objects, "unable to build FreeBSD libc shared objects: {s}", .{
4931 @errorName(err),
4932 }),
4933 }
4934}
4935
4879fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std.Progress.Node) void {4936fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std.Progress.Node) void {
4880 if (mingw.buildCrtFile(comp, crt_file, prog_node)) |_| {4937 if (mingw.buildCrtFile(comp, crt_file, prog_node)) |_| {
4881 comp.queued_jobs.mingw_crt_file[@intFromEnum(crt_file)] = false;4938 comp.queued_jobs.mingw_crt_file[@intFromEnum(crt_file)] = false;
src/libs/freebsd.zig created+1104
...@@ -0,0 +1,1104 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const mem = std.mem;
4const log = std.log;
5const fs = std.fs;
6const path = fs.path;
7const assert = std.debug.assert;
8const Version = std.SemanticVersion;
9const Path = std.Build.Cache.Path;
10
11const Compilation = @import("../Compilation.zig");
12const build_options = @import("build_options");
13const trace = @import("../tracy.zig").trace;
14const Cache = std.Build.Cache;
15const Module = @import("../Package/Module.zig");
16const link = @import("../link.zig");
17
18pub const CrtFile = enum {
19 scrt1_o,
20};
21
22pub fn needsCrt0(output_mode: std.builtin.OutputMode) ?CrtFile {
23 // For shared libraries and PIC executables, we should actually link in a variant of crt1 that
24 // is built with `-DSHARED` so that it calls `__cxa_finalize` in an ELF destructor. However, we
25 // currently make no effort to respect `__cxa_finalize` on any other targets, so for now, we're
26 // not doing it here either.
27 //
28 // See: https://github.com/ziglang/zig/issues/23574#issuecomment-2869089897
29 return switch (output_mode) {
30 .Obj, .Lib => null,
31 .Exe => .scrt1_o,
32 };
33}
34
35fn includePath(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const u8 {
36 return path.join(arena, &.{
37 comp.zig_lib_directory.path.?,
38 "libc" ++ path.sep_str ++ "include",
39 sub_path,
40 });
41}
42
43fn csuPath(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const u8 {
44 return path.join(arena, &.{
45 comp.zig_lib_directory.path.?,
46 "libc" ++ path.sep_str ++ "freebsd" ++ path.sep_str ++ "lib" ++ path.sep_str ++ "csu",
47 sub_path,
48 });
49}
50
51fn libcPath(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const u8 {
52 return path.join(arena, &.{
53 comp.zig_lib_directory.path.?,
54 "libc" ++ path.sep_str ++ "freebsd" ++ path.sep_str ++ "lib" ++ path.sep_str ++ "libc",
55 sub_path,
56 });
57}
58
59/// TODO replace anyerror with explicit error set, recording user-friendly errors with
60/// setMiscFailure and returning error.SubCompilationFailed. see libcxx.zig for example.
61pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progress.Node) anyerror!void {
62 if (!build_options.have_llvm) return error.ZigCompilerNotBuiltWithLLVMExtensions;
63
64 const gpa = comp.gpa;
65 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
66 defer arena_allocator.deinit();
67 const arena = arena_allocator.allocator();
68
69 const target = comp.root_mod.resolved_target.result;
70
71 // In all cases in this function, we add the C compiler flags to
72 // cache_exempt_flags rather than extra_flags, because these arguments
73 // depend on only properties that are already covered by the cache
74 // manifest. Including these arguments in the cache could only possibly
75 // waste computation and create false negatives.
76
77 switch (crt_file) {
78 .scrt1_o => {
79 var cflags = std.ArrayList([]const u8).init(arena);
80 try cflags.appendSlice(&.{
81 "-O2",
82 "-fno-common",
83 "-std=gnu99",
84 "-DPIC",
85 "-w", // Disable all warnings.
86 });
87
88 if (target.cpu.arch.isPowerPC64()) {
89 try cflags.append("-mlongcall");
90 }
91
92 var acflags = std.ArrayList([]const u8).init(arena);
93 try acflags.appendSlice(&.{
94 "-DLOCORE",
95 // See `Compilation.addCCArgs`.
96 try std.fmt.allocPrint(arena, "-D__FreeBSD_version={d}", .{target.os.version_range.semver.min.major * 100_000}),
97 });
98
99 inline for (.{ &cflags, &acflags }) |flags| {
100 try flags.appendSlice(&.{
101 "-DSTRIP_FBSDID",
102 "-I",
103 try includePath(comp, arena, try std.fmt.allocPrint(arena, "{s}-{s}-{s}", .{
104 std.zig.target.freebsdArchNameHeaders(target.cpu.arch),
105 @tagName(target.os.tag),
106 @tagName(target.abi),
107 })),
108 "-I",
109 try includePath(comp, arena, "generic-freebsd"),
110 "-I",
111 try csuPath(comp, arena, switch (target.cpu.arch) {
112 .arm, .thumb => "arm",
113 .aarch64 => "aarch64",
114 .powerpc => "powerpc",
115 .powerpc64, .powerpc64le => "powerpc64",
116 .riscv64 => "riscv",
117 .x86 => "i386",
118 .x86_64 => "amd64",
119 else => unreachable,
120 }),
121 "-I",
122 try csuPath(comp, arena, "common"),
123 "-I",
124 try libcPath(comp, arena, "include"),
125 "-Qunused-arguments",
126 });
127 }
128
129 const sources = [_]struct {
130 path: []const u8,
131 flags: []const []const u8,
132 condition: bool = true,
133 }{
134 .{
135 .path = "common" ++ path.sep_str ++ "crtbegin.c",
136 .flags = cflags.items,
137 },
138 .{
139 .path = "common" ++ path.sep_str ++ "crtbrand.S",
140 .flags = acflags.items,
141 },
142 .{
143 .path = "common" ++ path.sep_str ++ "crtend.c",
144 .flags = cflags.items,
145 },
146 .{
147 .path = "common" ++ path.sep_str ++ "feature_note.S",
148 .flags = acflags.items,
149 },
150 .{
151 .path = "common" ++ path.sep_str ++ "ignore_init_note.S",
152 .flags = acflags.items,
153 },
154
155 .{
156 .path = "arm" ++ path.sep_str ++ "crt1_c.c",
157 .flags = cflags.items,
158 .condition = target.cpu.arch == .arm or target.cpu.arch == .thumb,
159 },
160 .{
161 .path = "arm" ++ path.sep_str ++ "crt1_s.S",
162 .flags = acflags.items,
163 .condition = target.cpu.arch == .arm or target.cpu.arch == .thumb,
164 },
165
166 .{
167 .path = "aarch64" ++ path.sep_str ++ "crt1_c.c",
168 .flags = cflags.items,
169 .condition = target.cpu.arch == .aarch64,
170 },
171 .{
172 .path = "aarch64" ++ path.sep_str ++ "crt1_s.S",
173 .flags = acflags.items,
174 .condition = target.cpu.arch == .aarch64,
175 },
176
177 .{
178 .path = "powerpc" ++ path.sep_str ++ "crt1_c.c",
179 .flags = cflags.items,
180 .condition = target.cpu.arch == .powerpc,
181 },
182 .{
183 .path = "powerpc" ++ path.sep_str ++ "crtsavres.S",
184 .flags = acflags.items,
185 .condition = target.cpu.arch == .powerpc,
186 },
187
188 .{
189 .path = "powerpc64" ++ path.sep_str ++ "crt1_c.c",
190 .flags = cflags.items,
191 .condition = target.cpu.arch.isPowerPC64(),
192 },
193
194 .{
195 .path = "riscv" ++ path.sep_str ++ "crt1_c.c",
196 .flags = cflags.items,
197 .condition = target.cpu.arch == .riscv64,
198 },
199 .{
200 .path = "riscv" ++ path.sep_str ++ "crt1_s.S",
201 .flags = acflags.items,
202 .condition = target.cpu.arch == .riscv64,
203 },
204
205 .{
206 .path = "i386" ++ path.sep_str ++ "crt1_c.c",
207 .flags = cflags.items,
208 .condition = target.cpu.arch == .x86,
209 },
210 .{
211 .path = "i386" ++ path.sep_str ++ "crt1_s.S",
212 .flags = acflags.items,
213 .condition = target.cpu.arch == .x86,
214 },
215
216 .{
217 .path = "amd64" ++ path.sep_str ++ "crt1_c.c",
218 .flags = cflags.items,
219 .condition = target.cpu.arch == .x86_64,
220 },
221 .{
222 .path = "amd64" ++ path.sep_str ++ "crt1_s.S",
223 .flags = acflags.items,
224 .condition = target.cpu.arch == .x86_64,
225 },
226 };
227
228 var files_buf: [sources.len]Compilation.CSourceFile = undefined;
229 var files_index: usize = 0;
230 for (sources) |file| {
231 if (!file.condition) continue;
232
233 files_buf[files_index] = .{
234 .src_path = try csuPath(comp, arena, file.path),
235 .cache_exempt_flags = file.flags,
236 .owner = undefined,
237 };
238 files_index += 1;
239 }
240 const files = files_buf[0..files_index];
241
242 return comp.build_crt_file(
243 if (comp.config.pie) "Scrt1" else "crt1",
244 .Obj,
245 .@"freebsd libc Scrt1.o",
246 prog_node,
247 files,
248 .{
249 .omit_frame_pointer = false,
250 .pic = true,
251 },
252 );
253 },
254 }
255}
256
257pub const Lib = struct {
258 name: []const u8,
259 sover: u8,
260};
261
262pub const libs = [_]Lib{
263 .{ .name = "m", .sover = 5 },
264 .{ .name = "stdthreads", .sover = 0 },
265 .{ .name = "thr", .sover = 3 },
266 .{ .name = "c", .sover = 7 },
267 .{ .name = "dl", .sover = 1 },
268 .{ .name = "rt", .sover = 1 },
269 .{ .name = "ld", .sover = 1 },
270 .{ .name = "util", .sover = 9 },
271 .{ .name = "execinfo", .sover = 1 },
272};
273
274pub const ABI = struct {
275 all_versions: []const Version, // all defined versions (one abilist from v2.0.0 up to current)
276 all_targets: []const std.zig.target.ArchOsAbi,
277 /// The bytes from the file verbatim, starting from the u16 number
278 /// of function inclusions.
279 inclusions: []const u8,
280 arena_state: std.heap.ArenaAllocator.State,
281
282 pub fn destroy(abi: *ABI, gpa: Allocator) void {
283 abi.arena_state.promote(gpa).deinit();
284 }
285};
286
287pub const LoadMetaDataError = error{
288 /// The files that ship with the Zig compiler were unable to be read, or otherwise had malformed data.
289 ZigInstallationCorrupt,
290 OutOfMemory,
291};
292
293pub const abilists_path = "libc" ++ path.sep_str ++ "freebsd" ++ path.sep_str ++ "abilists";
294pub const abilists_max_size = 150 * 1024; // Bigger than this and something is definitely borked.
295
296/// This function will emit a log error when there is a problem with the zig
297/// installation and then return `error.ZigInstallationCorrupt`.
298pub fn loadMetaData(gpa: Allocator, contents: []const u8) LoadMetaDataError!*ABI {
299 const tracy = trace(@src());
300 defer tracy.end();
301
302 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
303 errdefer arena_allocator.deinit();
304 const arena = arena_allocator.allocator();
305
306 var index: usize = 0;
307
308 {
309 const libs_len = contents[index];
310 index += 1;
311
312 var i: u8 = 0;
313 while (i < libs_len) : (i += 1) {
314 const lib_name = mem.sliceTo(contents[index..], 0);
315 index += lib_name.len + 1;
316
317 if (i >= libs.len or !mem.eql(u8, libs[i].name, lib_name)) {
318 log.err("libc" ++ path.sep_str ++ "freebsd" ++ path.sep_str ++
319 "abilists: invalid library name or index ({d}): '{s}'", .{ i, lib_name });
320 return error.ZigInstallationCorrupt;
321 }
322 }
323 }
324
325 const versions = b: {
326 const versions_len = contents[index];
327 index += 1;
328
329 const versions = try arena.alloc(Version, versions_len);
330 var i: u8 = 0;
331 while (i < versions.len) : (i += 1) {
332 versions[i] = .{
333 .major = contents[index + 0],
334 .minor = contents[index + 1],
335 .patch = contents[index + 2],
336 };
337 index += 3;
338 }
339 break :b versions;
340 };
341
342 const targets = b: {
343 const targets_len = contents[index];
344 index += 1;
345
346 const targets = try arena.alloc(std.zig.target.ArchOsAbi, targets_len);
347 var i: u8 = 0;
348 while (i < targets.len) : (i += 1) {
349 const target_name = mem.sliceTo(contents[index..], 0);
350 index += target_name.len + 1;
351
352 var component_it = mem.tokenizeScalar(u8, target_name, '-');
353 const arch_name = component_it.next() orelse {
354 log.err("abilists: expected arch name", .{});
355 return error.ZigInstallationCorrupt;
356 };
357 const os_name = component_it.next() orelse {
358 log.err("abilists: expected OS name", .{});
359 return error.ZigInstallationCorrupt;
360 };
361 const abi_name = component_it.next() orelse {
362 log.err("abilists: expected ABI name", .{});
363 return error.ZigInstallationCorrupt;
364 };
365 const arch_tag = std.meta.stringToEnum(std.Target.Cpu.Arch, arch_name) orelse {
366 log.err("abilists: unrecognized arch: '{s}'", .{arch_name});
367 return error.ZigInstallationCorrupt;
368 };
369 if (!mem.eql(u8, os_name, "freebsd")) {
370 log.err("abilists: expected OS 'freebsd', found '{s}'", .{os_name});
371 return error.ZigInstallationCorrupt;
372 }
373 const abi_tag = std.meta.stringToEnum(std.Target.Abi, abi_name) orelse {
374 log.err("abilists: unrecognized ABI: '{s}'", .{abi_name});
375 return error.ZigInstallationCorrupt;
376 };
377
378 targets[i] = .{
379 .arch = arch_tag,
380 .os = .freebsd,
381 .abi = abi_tag,
382 };
383 }
384 break :b targets;
385 };
386
387 const abi = try arena.create(ABI);
388 abi.* = .{
389 .all_versions = versions,
390 .all_targets = targets,
391 .inclusions = contents[index..],
392 .arena_state = arena_allocator.state,
393 };
394 return abi;
395}
396
397pub const BuiltSharedObjects = struct {
398 lock: Cache.Lock,
399 dir_path: Path,
400
401 pub fn deinit(self: *BuiltSharedObjects, gpa: Allocator) void {
402 self.lock.release();
403 gpa.free(self.dir_path.sub_path);
404 self.* = undefined;
405 }
406};
407
408const all_map_basename = "all.map";
409
410fn wordDirective(target: std.Target) []const u8 {
411 // Based on its description in the GNU `as` manual, you might assume that `.word` is sized
412 // according to the target word size. But no; that would just make too much sense.
413 return if (target.ptrBitWidth() == 64) ".quad" else ".long";
414}
415
416/// TODO replace anyerror with explicit error set, recording user-friendly errors with
417/// setMiscFailure and returning error.SubCompilationFailed. see libcxx.zig for example.
418pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anyerror!void {
419 // See also glibc.zig which this code is based on.
420
421 const tracy = trace(@src());
422 defer tracy.end();
423
424 if (!build_options.have_llvm) {
425 return error.ZigCompilerNotBuiltWithLLVMExtensions;
426 }
427
428 const gpa = comp.gpa;
429
430 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
431 defer arena_allocator.deinit();
432 const arena = arena_allocator.allocator();
433
434 const target = comp.getTarget();
435 // FreeBSD 7 == FBSD_1.0, ..., FreeBSD 14 == FBSD_1.7
436 const target_version: Version = .{ .major = 1, .minor = target.os.version_range.semver.min.major - 7, .patch = 0 };
437
438 // Use the global cache directory.
439 var cache: Cache = .{
440 .gpa = gpa,
441 .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}),
442 };
443 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });
444 cache.addPrefix(comp.zig_lib_directory);
445 cache.addPrefix(comp.global_cache_directory);
446 defer cache.manifest_dir.close();
447
448 var man = cache.obtain();
449 defer man.deinit();
450 man.hash.addBytes(build_options.version);
451 man.hash.add(target.cpu.arch);
452 man.hash.add(target.abi);
453 man.hash.add(target_version);
454
455 const full_abilists_path = try comp.zig_lib_directory.join(arena, &.{abilists_path});
456 const abilists_index = try man.addFile(full_abilists_path, abilists_max_size);
457
458 if (try man.hit()) {
459 const digest = man.final();
460
461 return queueSharedObjects(comp, .{
462 .lock = man.toOwnedLock(),
463 .dir_path = .{
464 .root_dir = comp.global_cache_directory,
465 .sub_path = try gpa.dupe(u8, "o" ++ fs.path.sep_str ++ digest),
466 },
467 });
468 }
469
470 const digest = man.final();
471 const o_sub_path = try path.join(arena, &[_][]const u8{ "o", &digest });
472
473 var o_directory: Compilation.Directory = .{
474 .handle = try comp.global_cache_directory.handle.makeOpenPath(o_sub_path, .{}),
475 .path = try comp.global_cache_directory.join(arena, &.{o_sub_path}),
476 };
477 defer o_directory.handle.close();
478
479 const abilists_contents = man.files.keys()[abilists_index].contents.?;
480 const metadata = try loadMetaData(gpa, abilists_contents);
481 defer metadata.destroy(gpa);
482
483 const target_targ_index = for (metadata.all_targets, 0..) |targ, i| {
484 if (targ.arch == target.cpu.arch and
485 targ.os == target.os.tag and
486 targ.abi == target.abi)
487 {
488 break i;
489 }
490 } else {
491 unreachable; // std.zig.target.available_libcs prevents us from getting here
492 };
493
494 const target_ver_index = for (metadata.all_versions, 0..) |ver, i| {
495 switch (ver.order(target_version)) {
496 .eq => break i,
497 .lt => continue,
498 .gt => {
499 // TODO Expose via compile error mechanism instead of log.
500 log.warn("invalid target FreeBSD libc version: {}", .{target_version});
501 return error.InvalidTargetLibCVersion;
502 },
503 }
504 } else blk: {
505 const latest_index = metadata.all_versions.len - 1;
506 log.warn("zig cannot build new FreeBSD libc version {}; providing instead {}", .{
507 target_version, metadata.all_versions[latest_index],
508 });
509 break :blk latest_index;
510 };
511
512 {
513 var map_contents = std.ArrayList(u8).init(arena);
514 for (metadata.all_versions[0 .. target_ver_index + 1]) |ver| {
515 try map_contents.writer().print("FBSD_{d}.{d} {{ }};\n", .{ ver.major, ver.minor });
516 }
517 try o_directory.handle.writeFile(.{ .sub_path = all_map_basename, .data = map_contents.items });
518 map_contents.deinit();
519 }
520
521 var stubs_asm = std.ArrayList(u8).init(gpa);
522 defer stubs_asm.deinit();
523
524 for (libs, 0..) |lib, lib_i| {
525 stubs_asm.shrinkRetainingCapacity(0);
526
527 const stubs_writer = stubs_asm.writer();
528
529 try stubs_writer.writeAll(".text\n");
530
531 var sym_i: usize = 0;
532 var sym_name_buf = std.ArrayList(u8).init(arena);
533 var opt_symbol_name: ?[]const u8 = null;
534 var versions = try std.DynamicBitSetUnmanaged.initEmpty(arena, metadata.all_versions.len);
535 var weak_linkages = try std.DynamicBitSetUnmanaged.initEmpty(arena, metadata.all_versions.len);
536 var sym_unversioned = false;
537
538 var inc_fbs = std.io.fixedBufferStream(metadata.inclusions);
539 var inc_reader = inc_fbs.reader();
540
541 const fn_inclusions_len = try inc_reader.readInt(u16, .little);
542
543 while (sym_i < fn_inclusions_len) : (sym_i += 1) {
544 const sym_name = opt_symbol_name orelse n: {
545 sym_name_buf.clearRetainingCapacity();
546 try inc_reader.streamUntilDelimiter(sym_name_buf.writer(), 0, null);
547
548 opt_symbol_name = sym_name_buf.items;
549 versions.unsetAll();
550 weak_linkages.unsetAll();
551 sym_unversioned = false;
552
553 break :n sym_name_buf.items;
554 };
555
556 {
557 const targets = try std.leb.readUleb128(u64, inc_reader);
558 var lib_index = try inc_reader.readByte();
559
560 const is_unversioned = (lib_index & (1 << 5)) != 0;
561 const is_weak = (lib_index & (1 << 6)) != 0;
562 const is_terminal = (lib_index & (1 << 7)) != 0;
563
564 lib_index = @as(u5, @truncate(lib_index));
565
566 // Test whether the inclusion applies to our current library and target.
567 const ok_lib_and_target =
568 (lib_index == lib_i) and
569 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);
570
571 while (true) {
572 const byte = try inc_reader.readByte();
573 const last = (byte & 0b1000_0000) != 0;
574 const ver_i = @as(u7, @truncate(byte));
575 if (ok_lib_and_target and ver_i <= target_ver_index) {
576 versions.set(ver_i);
577 if (is_unversioned) sym_unversioned = true;
578 if (is_weak) weak_linkages.set(ver_i);
579 }
580 if (last) break;
581 }
582
583 if (is_terminal) {
584 opt_symbol_name = null;
585 } else continue;
586 }
587
588 // Pick the default symbol version:
589 // - If there are no versions, don't emit it
590 // - Take the greatest one <= than the target one
591 // - If none of them is <= than the
592 // specified one don't pick any default version
593 var chosen_def_ver_index: usize = 255;
594 {
595 var versions_iter = versions.iterator(.{});
596 while (versions_iter.next()) |ver_i| {
597 if (chosen_def_ver_index == 255 or ver_i > chosen_def_ver_index) {
598 chosen_def_ver_index = ver_i;
599 }
600 }
601 }
602
603 {
604 var versions_iter = versions.iterator(.{});
605 while (versions_iter.next()) |ver_index| {
606 if (sym_unversioned) {
607 // Example:
608 // .balign 4
609 // .globl _Exit
610 // .type _Exit, %function
611 // _Exit: .long 0
612 try stubs_writer.print(
613 \\.balign {d}
614 \\.{s} {s}
615 \\.type {s}, %function
616 \\{s}: {s} 0
617 \\
618 , .{
619 target.ptrBitWidth() / 8,
620 if (weak_linkages.isSet(ver_index)) "weak" else "globl",
621 sym_name,
622 sym_name,
623 sym_name,
624 wordDirective(target),
625 });
626 }
627
628 // Example:
629 // .balign 4
630 // .globl _Exit_1_0
631 // .type _Exit_1_0, %function
632 // .symver _Exit_1_0, _Exit@@FBSD_1.0, remove
633 // _Exit_1_0: .long 0
634 const ver = metadata.all_versions[ver_index];
635
636 // Default symbol version definition vs normal symbol version definition
637 const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index;
638 const at_sign_str: []const u8 = if (want_default) "@@" else "@";
639 const sym_plus_ver = try std.fmt.allocPrint(
640 arena,
641 "{s}_FBSD_{d}_{d}",
642 .{ sym_name, ver.major, ver.minor },
643 );
644
645 try stubs_writer.print(
646 \\.balign {d}
647 \\.{s} {s}
648 \\.type {s}, %function
649 \\.symver {s}, {s}{s}FBSD_{d}.{d}, remove
650 \\{s}: {s} 0
651 \\
652 , .{
653 target.ptrBitWidth() / 8,
654 if (weak_linkages.isSet(ver_index)) "weak" else "globl",
655 sym_plus_ver,
656 sym_plus_ver,
657 sym_plus_ver,
658 sym_name,
659 at_sign_str,
660 ver.major,
661 ver.minor,
662 sym_plus_ver,
663 wordDirective(target),
664 });
665 }
666 }
667 }
668
669 try stubs_writer.writeAll(".data\n");
670
671 const obj_inclusions_len = try inc_reader.readInt(u16, .little);
672
673 var sizes = try arena.alloc(u16, metadata.all_versions.len);
674
675 sym_i = 0;
676 opt_symbol_name = null;
677 while (sym_i < obj_inclusions_len) : (sym_i += 1) {
678 const sym_name = opt_symbol_name orelse n: {
679 sym_name_buf.clearRetainingCapacity();
680 try inc_reader.streamUntilDelimiter(sym_name_buf.writer(), 0, null);
681
682 opt_symbol_name = sym_name_buf.items;
683 versions.unsetAll();
684 weak_linkages.unsetAll();
685 sym_unversioned = false;
686
687 break :n sym_name_buf.items;
688 };
689
690 {
691 const targets = try std.leb.readUleb128(u64, inc_reader);
692 const size = try std.leb.readUleb128(u16, inc_reader);
693 var lib_index = try inc_reader.readByte();
694
695 const is_unversioned = (lib_index & (1 << 5)) != 0;
696 const is_weak = (lib_index & (1 << 6)) != 0;
697 const is_terminal = (lib_index & (1 << 7)) != 0;
698
699 lib_index = @as(u5, @truncate(lib_index));
700
701 // Test whether the inclusion applies to our current library and target.
702 const ok_lib_and_target =
703 (lib_index == lib_i) and
704 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);
705
706 while (true) {
707 const byte = try inc_reader.readByte();
708 const last = (byte & 0b1000_0000) != 0;
709 const ver_i = @as(u7, @truncate(byte));
710 if (ok_lib_and_target and ver_i <= target_ver_index) {
711 versions.set(ver_i);
712 sizes[ver_i] = size;
713 if (is_unversioned) sym_unversioned = true;
714 if (is_weak) weak_linkages.set(ver_i);
715 }
716 if (last) break;
717 }
718
719 if (is_terminal) {
720 opt_symbol_name = null;
721 } else continue;
722 }
723
724 // Pick the default symbol version:
725 // - If there are no versions, don't emit it
726 // - Take the greatest one <= than the target one
727 // - If none of them is <= than the
728 // specified one don't pick any default version
729 var chosen_def_ver_index: usize = 255;
730 {
731 var versions_iter = versions.iterator(.{});
732 while (versions_iter.next()) |ver_i| {
733 if (chosen_def_ver_index == 255 or ver_i > chosen_def_ver_index) {
734 chosen_def_ver_index = ver_i;
735 }
736 }
737 }
738
739 {
740 var versions_iter = versions.iterator(.{});
741 while (versions_iter.next()) |ver_index| {
742 if (sym_unversioned) {
743 // Example:
744 // .balign 4
745 // .globl malloc_conf
746 // .type malloc_conf, %object
747 // .size malloc_conf, 4
748 // malloc_conf: .fill 4, 1, 0
749 try stubs_writer.print(
750 \\.balign {d}
751 \\.{s} {s}
752 \\.type {s}, %object
753 \\.size {s}, {d}
754 \\{s}: {s} 0
755 \\
756 , .{
757 target.ptrBitWidth() / 8,
758 if (weak_linkages.isSet(ver_index)) "weak" else "globl",
759 sym_name,
760 sym_name,
761 sym_name,
762 sizes[ver_index],
763 sym_name,
764 wordDirective(target),
765 });
766 }
767
768 // Example:
769 // .balign 4
770 // .globl malloc_conf_1_3
771 // .type malloc_conf_1_3, %object
772 // .size malloc_conf_1_3, 4
773 // .symver malloc_conf_1_3, malloc_conf@@FBSD_1.3
774 // malloc_conf_1_3: .fill 4, 1, 0
775 const ver = metadata.all_versions[ver_index];
776
777 // Default symbol version definition vs normal symbol version definition
778 const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index;
779 const at_sign_str: []const u8 = if (want_default) "@@" else "@";
780 const sym_plus_ver = try std.fmt.allocPrint(
781 arena,
782 "{s}_FBSD_{d}_{d}",
783 .{ sym_name, ver.major, ver.minor },
784 );
785
786 try stubs_asm.writer().print(
787 \\.balign {d}
788 \\.{s} {s}
789 \\.type {s}, %object
790 \\.size {s}, {d}
791 \\.symver {s}, {s}{s}FBSD_{d}.{d}
792 \\{s}: .fill {d}, 1, 0
793 \\
794 , .{
795 target.ptrBitWidth() / 8,
796 if (weak_linkages.isSet(ver_index)) "weak" else "globl",
797 sym_plus_ver,
798 sym_plus_ver,
799 sym_plus_ver,
800 sizes[ver_index],
801 sym_plus_ver,
802 sym_name,
803 at_sign_str,
804 ver.major,
805 ver.minor,
806 sym_plus_ver,
807 sizes[ver_index],
808 });
809 }
810 }
811 }
812
813 try stubs_writer.writeAll(".tdata\n");
814
815 const tls_inclusions_len = try inc_reader.readInt(u16, .little);
816
817 sym_i = 0;
818 opt_symbol_name = null;
819 while (sym_i < tls_inclusions_len) : (sym_i += 1) {
820 const sym_name = opt_symbol_name orelse n: {
821 sym_name_buf.clearRetainingCapacity();
822 try inc_reader.streamUntilDelimiter(sym_name_buf.writer(), 0, null);
823
824 opt_symbol_name = sym_name_buf.items;
825 versions.unsetAll();
826 weak_linkages.unsetAll();
827 sym_unversioned = false;
828
829 break :n sym_name_buf.items;
830 };
831
832 {
833 const targets = try std.leb.readUleb128(u64, inc_reader);
834 const size = try std.leb.readUleb128(u16, inc_reader);
835 var lib_index = try inc_reader.readByte();
836
837 const is_unversioned = (lib_index & (1 << 5)) != 0;
838 const is_weak = (lib_index & (1 << 6)) != 0;
839 const is_terminal = (lib_index & (1 << 7)) != 0;
840
841 lib_index = @as(u5, @truncate(lib_index));
842
843 // Test whether the inclusion applies to our current library and target.
844 const ok_lib_and_target =
845 (lib_index == lib_i) and
846 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0);
847
848 while (true) {
849 const byte = try inc_reader.readByte();
850 const last = (byte & 0b1000_0000) != 0;
851 const ver_i = @as(u7, @truncate(byte));
852 if (ok_lib_and_target and ver_i <= target_ver_index) {
853 versions.set(ver_i);
854 sizes[ver_i] = size;
855 if (is_unversioned) sym_unversioned = true;
856 if (is_weak) weak_linkages.set(ver_i);
857 }
858 if (last) break;
859 }
860
861 if (is_terminal) {
862 opt_symbol_name = null;
863 } else continue;
864 }
865
866 // Pick the default symbol version:
867 // - If there are no versions, don't emit it
868 // - Take the greatest one <= than the target one
869 // - If none of them is <= than the
870 // specified one don't pick any default version
871 var chosen_def_ver_index: usize = 255;
872 {
873 var versions_iter = versions.iterator(.{});
874 while (versions_iter.next()) |ver_i| {
875 if (chosen_def_ver_index == 255 or ver_i > chosen_def_ver_index) {
876 chosen_def_ver_index = ver_i;
877 }
878 }
879 }
880
881 {
882 var versions_iter = versions.iterator(.{});
883 while (versions_iter.next()) |ver_index| {
884 if (sym_unversioned) {
885 // Example:
886 // .balign 4
887 // .globl _ThreadRuneLocale
888 // .type _ThreadRuneLocale, %object
889 // .size _ThreadRuneLocale, 4
890 // _ThreadRuneLocale: .fill 4, 1, 0
891 try stubs_writer.print(
892 \\.balign {d}
893 \\.{s} {s}
894 \\.type {s}, %tls_object
895 \\.size {s}, {d}
896 \\{s}: {s} 0
897 \\
898 , .{
899 target.ptrBitWidth() / 8,
900 if (weak_linkages.isSet(ver_index)) "weak" else "globl",
901 sym_name,
902 sym_name,
903 sym_name,
904 sizes[ver_index],
905 sym_name,
906 wordDirective(target),
907 });
908 }
909
910 // Example:
911 // .balign 4
912 // .globl _ThreadRuneLocale_1_3
913 // .type _ThreadRuneLocale_1_3, %tls_object
914 // .size _ThreadRuneLocale_1_3, 4
915 // .symver _ThreadRuneLocale_1_3, _ThreadRuneLocale@@FBSD_1.3
916 // _ThreadRuneLocale_1_3: .fill 4, 1, 0
917 const ver = metadata.all_versions[ver_index];
918
919 // Default symbol version definition vs normal symbol version definition
920 const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index;
921 const at_sign_str: []const u8 = if (want_default) "@@" else "@";
922 const sym_plus_ver = try std.fmt.allocPrint(
923 arena,
924 "{s}_FBSD_{d}_{d}",
925 .{ sym_name, ver.major, ver.minor },
926 );
927
928 try stubs_writer.print(
929 \\.balign {d}
930 \\.{s} {s}
931 \\.type {s}, %tls_object
932 \\.size {s}, {d}
933 \\.symver {s}, {s}{s}FBSD_{d}.{d}
934 \\{s}: .fill {d}, 1, 0
935 \\
936 , .{
937 target.ptrBitWidth() / 8,
938 if (weak_linkages.isSet(ver_index)) "weak" else "globl",
939 sym_plus_ver,
940 sym_plus_ver,
941 sym_plus_ver,
942 sizes[ver_index],
943 sym_plus_ver,
944 sym_name,
945 at_sign_str,
946 ver.major,
947 ver.minor,
948 sym_plus_ver,
949 sizes[ver_index],
950 });
951 }
952 }
953 }
954
955 var lib_name_buf: [32]u8 = undefined; // Larger than each of the names "c", "stdthreads", etc.
956 const asm_file_basename = std.fmt.bufPrint(&lib_name_buf, "{s}.s", .{lib.name}) catch unreachable;
957 try o_directory.handle.writeFile(.{ .sub_path = asm_file_basename, .data = stubs_asm.items });
958 try buildSharedLib(comp, arena, comp.global_cache_directory, o_directory, asm_file_basename, lib, prog_node);
959 }
960
961 man.writeManifest() catch |err| {
962 log.warn("failed to write cache manifest for FreeBSD libc stubs: {s}", .{@errorName(err)});
963 };
964
965 return queueSharedObjects(comp, .{
966 .lock = man.toOwnedLock(),
967 .dir_path = .{
968 .root_dir = comp.global_cache_directory,
969 .sub_path = try gpa.dupe(u8, "o" ++ fs.path.sep_str ++ digest),
970 },
971 });
972}
973
974pub fn sharedObjectsCount() u8 {
975 return libs.len;
976}
977
978fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
979 assert(comp.freebsd_so_files == null);
980 comp.freebsd_so_files = so_files;
981
982 var task_buffer: [libs.len]link.Task = undefined;
983 var task_buffer_i: usize = 0;
984
985 {
986 comp.mutex.lock(); // protect comp.arena
987 defer comp.mutex.unlock();
988
989 for (libs) |lib| {
990 const so_path: Path = .{
991 .root_dir = so_files.dir_path.root_dir,
992 .sub_path = std.fmt.allocPrint(comp.arena, "{s}{c}lib{s}.so.{d}", .{
993 so_files.dir_path.sub_path, fs.path.sep, lib.name, lib.sover,
994 }) catch return comp.setAllocFailure(),
995 };
996 task_buffer[task_buffer_i] = .{ .load_dso = so_path };
997 task_buffer_i += 1;
998 }
999 }
1000
1001 comp.queueLinkTasks(task_buffer[0..task_buffer_i]);
1002}
1003
1004fn buildSharedLib(
1005 comp: *Compilation,
1006 arena: Allocator,
1007 zig_cache_directory: Compilation.Directory,
1008 bin_directory: Compilation.Directory,
1009 asm_file_basename: []const u8,
1010 lib: Lib,
1011 prog_node: std.Progress.Node,
1012) !void {
1013 const tracy = trace(@src());
1014 defer tracy.end();
1015
1016 const basename = try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ lib.name, lib.sover });
1017 const emit_bin = Compilation.EmitLoc{
1018 .directory = bin_directory,
1019 .basename = basename,
1020 };
1021 const version: Version = .{ .major = lib.sover, .minor = 0, .patch = 0 };
1022 const ld_basename = path.basename(comp.getTarget().standardDynamicLinkerPath().get().?);
1023 const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename;
1024 const map_file_path = try path.join(arena, &.{ bin_directory.path.?, all_map_basename });
1025
1026 const optimize_mode = comp.compilerRtOptMode();
1027 const strip = comp.compilerRtStrip();
1028 const config = try Compilation.Config.resolve(.{
1029 .output_mode = .Lib,
1030 .link_mode = .dynamic,
1031 .resolved_target = comp.root_mod.resolved_target,
1032 .is_test = false,
1033 .have_zcu = false,
1034 .emit_bin = true,
1035 .root_optimize_mode = optimize_mode,
1036 .root_strip = strip,
1037 .link_libc = false,
1038 });
1039
1040 const root_mod = try Module.create(arena, .{
1041 .global_cache_directory = comp.global_cache_directory,
1042 .paths = .{
1043 .root = .{ .root_dir = comp.zig_lib_directory },
1044 .root_src_path = "",
1045 },
1046 .fully_qualified_name = "root",
1047 .inherited = .{
1048 .resolved_target = comp.root_mod.resolved_target,
1049 .strip = strip,
1050 .stack_check = false,
1051 .stack_protector = 0,
1052 .sanitize_c = .off,
1053 .sanitize_thread = false,
1054 .red_zone = comp.root_mod.red_zone,
1055 .omit_frame_pointer = comp.root_mod.omit_frame_pointer,
1056 .valgrind = false,
1057 .optimize_mode = optimize_mode,
1058 .structured_cfg = comp.root_mod.structured_cfg,
1059 },
1060 .global = config,
1061 .cc_argv = &.{},
1062 .parent = null,
1063 .builtin_mod = null,
1064 .builtin_modules = null, // there is only one module in this compilation
1065 });
1066
1067 const c_source_files = [1]Compilation.CSourceFile{
1068 .{
1069 .src_path = try path.join(arena, &.{ bin_directory.path.?, asm_file_basename }),
1070 .owner = root_mod,
1071 },
1072 };
1073
1074 const sub_compilation = try Compilation.create(comp.gpa, arena, .{
1075 .local_cache_directory = zig_cache_directory,
1076 .global_cache_directory = comp.global_cache_directory,
1077 .zig_lib_directory = comp.zig_lib_directory,
1078 .thread_pool = comp.thread_pool,
1079 .self_exe_path = comp.self_exe_path,
1080 .cache_mode = .incremental,
1081 .config = config,
1082 .root_mod = root_mod,
1083 .root_name = lib.name,
1084 .libc_installation = comp.libc_installation,
1085 .emit_bin = emit_bin,
1086 .emit_h = null,
1087 .verbose_cc = comp.verbose_cc,
1088 .verbose_link = comp.verbose_link,
1089 .verbose_air = comp.verbose_air,
1090 .verbose_llvm_ir = comp.verbose_llvm_ir,
1091 .verbose_llvm_bc = comp.verbose_llvm_bc,
1092 .verbose_cimport = comp.verbose_cimport,
1093 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
1094 .clang_passthrough_mode = comp.clang_passthrough_mode,
1095 .version = version,
1096 .version_script = map_file_path,
1097 .soname = soname,
1098 .c_source_files = &c_source_files,
1099 .skip_linker_dependencies = true,
1100 });
1101 defer sub_compilation.destroy();
1102
1103 try comp.updateSubCompilation(sub_compilation, .@"freebsd libc shared object", prog_node);
1104}
src/link/Elf.zig+10-2
...@@ -2058,11 +2058,18 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2058,11 +2058,18 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2058 try argv.append(lib_path);2058 try argv.append(lib_path);
2059 }2059 }
2060 try argv.append(try comp.crtFileAsString(arena, "libc_nonshared.a"));2060 try argv.append(try comp.crtFileAsString(arena, "libc_nonshared.a"));
2061 } else if (target.abi.isMusl()) {2061 } else if (target.isMuslLibC()) {
2062 try argv.append(try comp.crtFileAsString(arena, switch (link_mode) {2062 try argv.append(try comp.crtFileAsString(arena, switch (link_mode) {
2063 .static => "libc.a",2063 .static => "libc.a",
2064 .dynamic => "libc.so",2064 .dynamic => "libc.so",
2065 }));2065 }));
2066 } else if (target.isFreeBSDLibC()) {
2067 for (freebsd.libs) |lib| {
2068 const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{
2069 comp.freebsd_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
2070 });
2071 try argv.append(lib_path);
2072 }
2066 } else {2073 } else {
2067 diags.flags.missing_libc = true;2074 diags.flags.missing_libc = true;
2068 }2075 }
...@@ -5280,8 +5287,9 @@ const dev = @import("../dev.zig");...@@ -5280,8 +5287,9 @@ const dev = @import("../dev.zig");
5280const eh_frame = @import("Elf/eh_frame.zig");5287const eh_frame = @import("Elf/eh_frame.zig");
5281const gc = @import("Elf/gc.zig");5288const gc = @import("Elf/gc.zig");
5282const glibc = @import("../libs/glibc.zig");5289const glibc = @import("../libs/glibc.zig");
5283const link = @import("../link.zig");
5284const musl = @import("../libs/musl.zig");5290const musl = @import("../libs/musl.zig");
5291const freebsd = @import("../libs/freebsd.zig");
5292const link = @import("../link.zig");
5285const relocatable = @import("Elf/relocatable.zig");5293const relocatable = @import("Elf/relocatable.zig");
5286const relocation = @import("Elf/relocation.zig");5294const relocation = @import("Elf/relocation.zig");
5287const target_util = @import("../target.zig");5295const target_util = @import("../target.zig");