╭ freebsd.zig ──────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1 const std = @import("std"); 2 const Io = std.Io; 3 const Allocator = std.mem.Allocator; 4 const mem = std.mem; 5 const log = std.log; 6 const path = std.Io.Dir.path; 7 const assert = std.debug.assert; 8 const Version = std.SemanticVersion; 9 const Path = std.Build.Cache.Path; 10 11 const Compilation = @import("../Compilation.zig"); 12 const build_options = @import("build_options"); 13 const trace = @import("../tracy.zig").trace; 14 const Cache = std.Build.Cache; 15 const Module = @import("../Module.zig"); 16 const link = @import("../link.zig"); 17 18 pub const CrtFile = enum { 19 scrt1_o, 20 }; 21 22 pub fn needsCrt0(output_mode: std.lang.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 35 fn includePath(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const u8 { 36 return path.join(arena, &.{ 37 comp.dirs.zig_lib.path.?, 38 "libc" ++ path.sep_str ++ "include", 39 sub_path, 40 }); 41 } 42 43 fn csuPath(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const u8 { 44 return path.join(arena, &.{ 45 comp.dirs.zig_lib.path.?, 46 "libc" ++ path.sep_str ++ "freebsd" ++ path.sep_str ++ "lib" ++ path.sep_str ++ "csu", 47 sub_path, 48 }); 49 } 50 51 fn libcPath(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const u8 { 52 return path.join(arena, &.{ 53 comp.dirs.zig_lib.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 /// lockAndSetMiscFailure and returning error.AlreadyReported. see libcxx.zig for example. 61 pub 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.array_list.Managed([]const u8).init(arena); 80 try cflags.appendSlice(&.{ 81 "-O2", 82 "-fno-common", 83 "-std=gnu99", 84 "-w", // Disable all warnings. 85 }); 86 87 if (target.cpu.arch.isPowerPC64()) { 88 try cflags.append("-mlongcall"); 89 } 90 91 var acflags = std.array_list.Managed([]const u8).init(arena); 92 try acflags.appendSlice(&.{ 93 "-DLOCORE", 94 // See `Compilation.addCCArgs`. 95 try std.fmt.allocPrint(arena, "-D__FreeBSD_version={d}", .{target.os.version_range.semver.min.major * 100_000 + 500}), 96 }); 97 98 inline for (.{ &cflags, &acflags }) |flags| { 99 try flags.appendSlice(&.{ 100 "-DPIC", 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 => "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 ++ "feature_note.S", 144 .flags = acflags.items, 145 }, 146 .{ 147 .path = "common" ++ path.sep_str ++ "ignore_init_note.S", 148 .flags = acflags.items, 149 }, 150 151 .{ 152 .path = "arm" ++ path.sep_str ++ "crt1_c.c", 153 .flags = cflags.items, 154 .condition = target.cpu.arch == .arm, 155 }, 156 .{ 157 .path = "arm" ++ path.sep_str ++ "crt1_s.S", 158 .flags = acflags.items, 159 .condition = target.cpu.arch == .arm, 160 }, 161 162 .{ 163 .path = "aarch64" ++ path.sep_str ++ "crt1_c.c", 164 .flags = cflags.items, 165 .condition = target.cpu.arch == .aarch64, 166 }, 167 .{ 168 .path = "aarch64" ++ path.sep_str ++ "crt1_s.S", 169 .flags = acflags.items, 170 .condition = target.cpu.arch == .aarch64, 171 }, 172 173 .{ 174 .path = "powerpc" ++ path.sep_str ++ "crt1_c.c", 175 .flags = cflags.items, 176 .condition = target.cpu.arch == .powerpc, 177 }, 178 .{ 179 .path = "powerpc" ++ path.sep_str ++ "crtsavres.S", 180 .flags = acflags.items, 181 .condition = target.cpu.arch == .powerpc, 182 }, 183 184 .{ 185 .path = "powerpc64" ++ path.sep_str ++ "crt1_c.c", 186 .flags = cflags.items, 187 .condition = target.cpu.arch.isPowerPC64(), 188 }, 189 190 .{ 191 .path = "riscv" ++ path.sep_str ++ "crt1_c.c", 192 .flags = cflags.items, 193 .condition = target.cpu.arch == .riscv64, 194 }, 195 .{ 196 .path = "riscv" ++ path.sep_str ++ "crt1_s.S", 197 .flags = acflags.items, 198 .condition = target.cpu.arch == .riscv64, 199 }, 200 201 .{ 202 .path = "i386" ++ path.sep_str ++ "crt1_c.c", 203 .flags = cflags.items, 204 .condition = target.cpu.arch == .x86, 205 }, 206 .{ 207 .path = "i386" ++ path.sep_str ++ "crt1_s.S", 208 .flags = acflags.items, 209 .condition = target.cpu.arch == .x86, 210 }, 211 212 .{ 213 .path = "amd64" ++ path.sep_str ++ "crt1_c.c", 214 .flags = cflags.items, 215 .condition = target.cpu.arch == .x86_64, 216 }, 217 .{ 218 .path = "amd64" ++ path.sep_str ++ "crt1_s.S", 219 .flags = acflags.items, 220 .condition = target.cpu.arch == .x86_64, 221 }, 222 }; 223 224 var files_buf: [sources.len]Compilation.CSourceFile = undefined; 225 var files_index: usize = 0; 226 for (sources) |file| { 227 if (!file.condition) continue; 228 229 files_buf[files_index] = .{ 230 .src_path = try csuPath(comp, arena, file.path), 231 .cache_exempt_flags = file.flags, 232 .owner = undefined, 233 }; 234 files_index += 1; 235 } 236 const files = files_buf[0..files_index]; 237 238 return comp.build_crt_file( 239 if (comp.config.pie) "Scrt1" else "crt1", 240 .Obj, 241 .@"freebsd libc Scrt1.o", 242 prog_node, 243 files, 244 .{ 245 .pic = true, 246 }, 247 ); 248 }, 249 } 250 } 251 252 pub const Lib = struct { 253 name: []const u8, 254 sover: u8, 255 added_in: ?Version = null, 256 257 pub fn getSoVersion(lib: Lib, os: *const std.Target.Os) u8 { 258 if (std.mem.eql(u8, lib.name, "util") and os.version_range.semver.min.major >= 15) return 10; 259 return lib.sover; 260 } 261 }; 262 263 pub const libs = [_]Lib{ 264 .{ .name = "m", .sover = 5 }, 265 .{ .name = "stdthreads", .sover = 0 }, 266 .{ .name = "thr", .sover = 3 }, 267 .{ .name = "c", .sover = 7 }, 268 .{ .name = "dl", .sover = 1 }, 269 .{ .name = "rt", .sover = 1 }, 270 .{ .name = "ld", .sover = 1 }, 271 .{ .name = "util", .sover = 9 }, 272 .{ .name = "execinfo", .sover = 1 }, 273 .{ .name = "sys", .sover = 7, .added_in = .{ .major = 15, .minor = 0, .patch = 0 } }, 274 }; 275 276 pub const ABI = struct { 277 all_versions: []const Version, // all defined versions (one abilist from v2.0.0 up to current) 278 all_targets: []const std.zig.target.ArchOsAbi, 279 /// The bytes from the file verbatim, starting from the u16 number 280 /// of function inclusions. 281 inclusions: []const u8, 282 arena_state: std.heap.ArenaAllocator.State, 283 284 pub fn destroy(abi: *ABI, gpa: Allocator) void { 285 abi.arena_state.promote(gpa).deinit(); 286 } 287 }; 288 289 pub const LoadMetaDataError = error{ 290 /// The files that ship with the Zig compiler were unable to be read, or otherwise had malformed data. 291 ZigInstallationCorrupt, 292 OutOfMemory, 293 }; 294 295 pub const abilists_path = "libc" ++ path.sep_str ++ "freebsd" ++ path.sep_str ++ "abilists"; 296 pub const abilists_max_size = 150 * 1024; // Bigger than this and something is definitely borked. 297 298 /// This function will emit a log error when there is a problem with the zig 299 /// installation and then return `error.ZigInstallationCorrupt`. 300 pub fn loadMetaData(gpa: Allocator, contents: []const u8) LoadMetaDataError!*ABI { 301 const tracy = trace(@src()); 302 defer tracy.end(); 303 304 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 305 errdefer arena_allocator.deinit(); 306 const arena = arena_allocator.allocator(); 307 308 var index: usize = 0; 309 310 { 311 const libs_len = contents[index]; 312 index += 1; 313 314 var i: u8 = 0; 315 while (i < libs_len) : (i += 1) { 316 const lib_name = mem.sliceTo(contents[index..], 0); 317 index += lib_name.len + 1; 318 319 if (i >= libs.len or !mem.eql(u8, libs[i].name, lib_name)) { 320 log.err("libc" ++ path.sep_str ++ "freebsd" ++ path.sep_str ++ 321 "abilists: invalid library name or index ({d}): '{s}'", .{ i, lib_name }); 322 return error.ZigInstallationCorrupt; 323 } 324 } 325 } 326 327 const versions = b: { 328 const versions_len = contents[index]; 329 index += 1; 330 331 const versions = try arena.alloc(Version, versions_len); 332 var i: u8 = 0; 333 while (i < versions.len) : (i += 1) { 334 versions[i] = .{ 335 .major = contents[index + 0], 336 .minor = contents[index + 1], 337 .patch = contents[index + 2], 338 }; 339 index += 3; 340 } 341 break :b versions; 342 }; 343 344 const targets = b: { 345 const targets_len = contents[index]; 346 index += 1; 347 348 const targets = try arena.alloc(std.zig.target.ArchOsAbi, targets_len); 349 var i: u8 = 0; 350 while (i < targets.len) : (i += 1) { 351 const target_name = mem.sliceTo(contents[index..], 0); 352 index += target_name.len + 1; 353 354 var component_it = mem.tokenizeScalar(u8, target_name, '-'); 355 const arch_name = component_it.next() orelse { 356 log.err("abilists: expected arch name", .{}); 357 return error.ZigInstallationCorrupt; 358 }; 359 const os_name = component_it.next() orelse { 360 log.err("abilists: expected OS name", .{}); 361 return error.ZigInstallationCorrupt; 362 }; 363 const abi_name = component_it.next() orelse { 364 log.err("abilists: expected ABI name", .{}); 365 return error.ZigInstallationCorrupt; 366 }; 367 const arch_tag = std.meta.stringToEnum(std.Target.Cpu.Arch, arch_name) orelse { 368 log.err("abilists: unrecognized arch: '{s}'", .{arch_name}); 369 return error.ZigInstallationCorrupt; 370 }; 371 if (!mem.eql(u8, os_name, "freebsd")) { 372 log.err("abilists: expected OS 'freebsd', found '{s}'", .{os_name}); 373 return error.ZigInstallationCorrupt; 374 } 375 const abi_tag = std.meta.stringToEnum(std.Target.Abi, abi_name) orelse { 376 log.err("abilists: unrecognized ABI: '{s}'", .{abi_name}); 377 return error.ZigInstallationCorrupt; 378 }; 379 380 targets[i] = .{ 381 .arch = arch_tag, 382 .os = .freebsd, 383 .abi = abi_tag, 384 }; 385 } 386 break :b targets; 387 }; 388 389 const abi = try arena.create(ABI); 390 abi.* = .{ 391 .all_versions = versions, 392 .all_targets = targets, 393 .inclusions = contents[index..], 394 .arena_state = arena_allocator.state, 395 }; 396 return abi; 397 } 398 399 pub const BuiltSharedObjects = struct { 400 lock: Cache.Lock, 401 dir_path: Path, 402 403 pub fn deinit(self: *BuiltSharedObjects, gpa: Allocator, io: Io) void { 404 self.lock.release(io); 405 gpa.free(self.dir_path.sub_path); 406 self.* = undefined; 407 } 408 }; 409 410 const all_map_basename = "all.map"; 411 412 fn wordDirective(target: *const std.Target) []const u8 { 413 // Based on its description in the GNU `as` manual, you might assume that `.word` is sized 414 // according to the target word size. But no; that would just make too much sense. 415 return if (target.ptrBitWidth() == 64) ".quad" else ".long"; 416 } 417 418 /// TODO replace anyerror with explicit error set, recording user-friendly errors with 419 /// lockAndSetMiscFailure and returning error.AlreadyReported. see libcxx.zig for example. 420 pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anyerror!void { 421 // See also glibc.zig which this code is based on. 422 423 const tracy = trace(@src()); 424 defer tracy.end(); 425 426 if (!build_options.have_llvm) { 427 return error.ZigCompilerNotBuiltWithLLVMExtensions; 428 } 429 430 const gpa = comp.gpa; 431 const io = comp.io; 432 433 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 434 defer arena_allocator.deinit(); 435 const arena = arena_allocator.allocator(); 436 437 const target = comp.getTarget(); 438 // FreeBSD 7 == FBSD_1.0, ..., FreeBSD 14 == FBSD_1.7 439 const target_os_version: Version = target.os.version_range.semver.min; 440 const target_libc_version: Version = .{ .major = 1, .minor = target_os_version.major - 7, .patch = 0 }; 441 442 // Use the global cache directory. 443 var cache: Cache = .{ 444 .gpa = gpa, 445 .io = io, 446 .manifest_dir = try comp.dirs.global_cache.handle.createDirPathOpen(io, "h", .{}), 447 .cwd = comp.dirs.cwd, 448 }; 449 cache.addPrefix(.{ .path = null, .handle = Io.Dir.cwd() }); 450 cache.addPrefix(comp.dirs.zig_lib); 451 cache.addPrefix(comp.dirs.global_cache); 452 defer cache.manifest_dir.close(io); 453 454 var man = cache.obtain(); 455 defer man.deinit(); 456 man.hash.addBytes(build_options.version); 457 man.hash.add(target.cpu.arch); 458 man.hash.add(target.abi); 459 man.hash.add(target_os_version); 460 461 const abilists_index = try man.addInputPath(.{ 462 .root_dir = comp.dirs.zig_lib, 463 .sub_path = abilists_path, 464 }, .{ 465 .request_contents = true, 466 }); 467 468 var diag: Cache.Manifest.CheckDiagnostic = undefined; 469 const status = man.check(&diag, prog_node) catch |err| switch (err) { 470 error.OutOfMemory, error.Canceled => |e| return e, 471 error.CacheCheckFailed => { 472 comp.lockAndSetMiscFailure( 473 .freebsd_shared_objects, 474 "compiling FreeBSD libc shared objects: checking cache failed: {f}", 475 .{diag.fmt(&man)}, 476 ); 477 return error.AlreadyReported; 478 }, 479 }; 480 log.debug("freebsd_shared_objects cache {f}", .{status.fmt(&man)}); 481 if (status == .hit) { 482 const digest = man.hitDigestHex(); 483 return queueSharedObjects(comp, .{ 484 .lock = man.toOwnedLock(), 485 .dir_path = .{ 486 .root_dir = comp.dirs.global_cache, 487 .sub_path = try gpa.dupe(u8, "o" ++ path.sep_str ++ digest), 488 }, 489 }); 490 } 491 492 const digest = man.missDigestHex(); 493 const o_sub_path = try path.join(arena, &[_][]const u8{ "o", &digest }); 494 495 var o_directory: Cache.Directory = .{ 496 .handle = try comp.dirs.global_cache.handle.createDirPathOpen(io, o_sub_path, .{}), 497 .path = try comp.dirs.global_cache.join(arena, &.{o_sub_path}), 498 }; 499 defer o_directory.handle.close(io); 500 501 const abilists_contents = abilists_index.contents(&man); 502 const metadata = try loadMetaData(gpa, abilists_contents); 503 defer metadata.destroy(gpa); 504 505 const target_targ_index = for (metadata.all_targets, 0..) |targ, i| { 506 if (targ.arch == target.cpu.arch and 507 targ.os == target.os.tag and 508 targ.abi == target.abi) 509 { 510 break i; 511 } 512 } else { 513 unreachable; // std.zig.target.available_libcs prevents us from getting here 514 }; 515 516 const target_ver_index = for (metadata.all_versions, 0..) |ver, i| { 517 switch (ver.order(target_libc_version)) { 518 .eq => break i, 519 .lt => continue, 520 .gt => { 521 // TODO Expose via compile error mechanism instead of log. 522 log.warn("invalid target FreeBSD libc version: {f}", .{target_libc_version}); 523 return error.InvalidTargetLibCVersion; 524 }, 525 } 526 } else blk: { 527 const latest_index = metadata.all_versions.len - 1; 528 log.warn("zig cannot build new FreeBSD libc version {f}; providing instead {f}", .{ 529 target_libc_version, metadata.all_versions[latest_index], 530 }); 531 break :blk latest_index; 532 }; 533 534 { 535 var map_contents = std.array_list.Managed(u8).init(arena); 536 for (metadata.all_versions[0 .. target_ver_index + 1]) |ver| { 537 try map_contents.print("FBSD_{d}.{d} {{ }};\n", .{ ver.major, ver.minor }); 538 } 539 try o_directory.handle.writeFile(io, .{ .sub_path = all_map_basename, .data = map_contents.items }); 540 map_contents.deinit(); 541 } 542 543 var stubs_asm = std.array_list.Managed(u8).init(gpa); 544 defer stubs_asm.deinit(); 545 546 for (libs, 0..) |lib, lib_i| { 547 if (lib.added_in) |add_in| { 548 // Note: Compare OS version, not libc version. 549 if (target.os.version_range.semver.min.order(add_in) == .lt) continue; 550 } 551 552 stubs_asm.shrinkRetainingCapacity(0); 553 554 try stubs_asm.appendSlice(".text\n"); 555 556 var sym_i: usize = 0; 557 var sym_name_buf: std.Io.Writer.Allocating = .init(arena); 558 var opt_symbol_name: ?[]const u8 = null; 559 var versions: std.bit_set.Dynamic = try .initEmpty(arena, metadata.all_versions.len); 560 var weak_linkages: std.bit_set.Dynamic = try .initEmpty(arena, metadata.all_versions.len); 561 562 var inc_reader: std.Io.Reader = .fixed(metadata.inclusions); 563 564 const fn_inclusions_len = try inc_reader.takeInt(u16, .little); 565 566 // Pick the default symbol version: 567 // - If there are no versions, don't emit it 568 // - Take the greatest one <= than the target one 569 // - If none of them is <= than the 570 // specified one don't pick any default version 571 var chosen_def_ver_index: usize = 255; 572 var chosen_unversioned_ver_index: usize = 255; 573 574 while (sym_i < fn_inclusions_len) : (sym_i += 1) { 575 const sym_name = opt_symbol_name orelse n: { 576 sym_name_buf.clearRetainingCapacity(); 577 _ = try inc_reader.streamDelimiter(&sym_name_buf.writer, 0); 578 assert(inc_reader.buffered()[0] == 0); // TODO change streamDelimiter API 579 inc_reader.toss(1); 580 581 opt_symbol_name = sym_name_buf.written(); 582 versions.unsetAll(); 583 weak_linkages.unsetAll(); 584 chosen_def_ver_index = 255; 585 chosen_unversioned_ver_index = 255; 586 587 break :n sym_name_buf.written(); 588 }; 589 { 590 const targets = try inc_reader.takeLeb128(u64); 591 var lib_index = try inc_reader.takeByte(); 592 593 const is_unversioned = (lib_index & (1 << 5)) != 0; 594 const is_weak = (lib_index & (1 << 6)) != 0; 595 const is_terminal = (lib_index & (1 << 7)) != 0; 596 597 lib_index = @as(u5, @truncate(lib_index)); 598 599 // Test whether the inclusion applies to our current library and target. 600 const ok_lib_and_target = 601 (lib_index == lib_i) and 602 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0); 603 604 while (true) { 605 const byte = try inc_reader.takeByte(); 606 const last = (byte & 0b1000_0000) != 0; 607 const ver_i = @as(u7, @truncate(byte)); 608 if (ok_lib_and_target and ver_i <= target_ver_index) { 609 if (is_unversioned) { 610 if (chosen_unversioned_ver_index == 255 or ver_i > chosen_unversioned_ver_index) { 611 chosen_unversioned_ver_index = ver_i; 612 } 613 } else { 614 if (chosen_def_ver_index == 255 or ver_i > chosen_def_ver_index) { 615 chosen_def_ver_index = ver_i; 616 } 617 618 versions.set(ver_i); 619 } 620 621 weak_linkages.setValue(ver_i, is_weak); 622 } 623 if (last) break; 624 } 625 626 if (is_terminal) { 627 opt_symbol_name = null; 628 } else continue; 629 } 630 631 if (chosen_unversioned_ver_index != 255) { 632 // Example: 633 // .balign 4 634 // .globl _Exit 635 // .type _Exit, %function 636 // _Exit: .long 0 637 try stubs_asm.print( 638 \\.balign {d} 639 \\.{s} {s} 640 \\.type {s}, %function 641 \\{s}: {s} 0 642 \\ 643 , .{ 644 target.ptrBitWidth() / 8, 645 if (weak_linkages.isSet(chosen_unversioned_ver_index)) "weak" else "globl", 646 sym_name, 647 sym_name, 648 sym_name, 649 wordDirective(target), 650 }); 651 } 652 653 { 654 var versions_iter = versions.iterator(.{}); 655 while (versions_iter.next()) |ver_index| { 656 // Example: 657 // .balign 4 658 // .globl _Exit_1_0 659 // .type _Exit_1_0, %function 660 // .symver _Exit_1_0, _Exit@@FBSD_1.0, remove 661 // _Exit_1_0: .long 0 662 const ver = metadata.all_versions[ver_index]; 663 const sym_plus_ver = try std.fmt.allocPrint( 664 arena, 665 "{s}_FBSD_{d}_{d}", 666 .{ sym_name, ver.major, ver.minor }, 667 ); 668 669 try stubs_asm.print( 670 \\.balign {d} 671 \\.{s} {s} 672 \\.type {s}, %function 673 \\.symver {s}, {s}{s}FBSD_{d}.{d}, remove 674 \\{s}: {s} 0 675 \\ 676 , .{ 677 target.ptrBitWidth() / 8, 678 if (weak_linkages.isSet(ver_index)) "weak" else "globl", 679 sym_plus_ver, 680 sym_plus_ver, 681 sym_plus_ver, 682 sym_name, 683 // Default symbol version definition vs normal symbol version definition 684 if (chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index) "@@" else "@", 685 ver.major, 686 ver.minor, 687 sym_plus_ver, 688 wordDirective(target), 689 }); 690 } 691 } 692 } 693 694 try stubs_asm.appendSlice(".data\n"); 695 696 // FreeBSD's `libc.so.7` contains strong references to `__progname` and `environ` which are 697 // defined in the statically-linked startup code. Those references cause the linker to put 698 // the symbols in the dynamic symbol table. We need to create dummy references to them here 699 // to get the same effect. 700 if (std.mem.eql(u8, lib.name, "c")) { 701 try stubs_asm.print( 702 \\.balign {d} 703 \\.globl __progname 704 \\.globl environ 705 \\{s} __progname 706 \\{s} environ 707 \\ 708 , .{ 709 target.ptrBitWidth() / 8, 710 wordDirective(target), 711 wordDirective(target), 712 }); 713 } 714 715 const obj_inclusions_len = try inc_reader.takeInt(u16, .little); 716 717 var sizes = try arena.alloc(u16, metadata.all_versions.len); 718 719 sym_i = 0; 720 opt_symbol_name = null; 721 722 while (sym_i < obj_inclusions_len) : (sym_i += 1) { 723 const sym_name = opt_symbol_name orelse n: { 724 sym_name_buf.clearRetainingCapacity(); 725 _ = try inc_reader.streamDelimiter(&sym_name_buf.writer, 0); 726 assert(inc_reader.buffered()[0] == 0); // TODO change streamDelimiter API 727 inc_reader.toss(1); 728 729 opt_symbol_name = sym_name_buf.written(); 730 versions.unsetAll(); 731 weak_linkages.unsetAll(); 732 chosen_def_ver_index = 255; 733 chosen_unversioned_ver_index = 255; 734 735 break :n sym_name_buf.written(); 736 }; 737 738 { 739 const targets = try inc_reader.takeLeb128(u64); 740 const size = try inc_reader.takeLeb128(u16); 741 var lib_index = try inc_reader.takeByte(); 742 743 const is_unversioned = (lib_index & (1 << 5)) != 0; 744 const is_weak = (lib_index & (1 << 6)) != 0; 745 const is_terminal = (lib_index & (1 << 7)) != 0; 746 747 lib_index = @as(u5, @truncate(lib_index)); 748 749 // Test whether the inclusion applies to our current library and target. 750 const ok_lib_and_target = 751 (lib_index == lib_i) and 752 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0); 753 754 while (true) { 755 const byte = try inc_reader.takeByte(); 756 const last = (byte & 0b1000_0000) != 0; 757 const ver_i = @as(u7, @truncate(byte)); 758 if (ok_lib_and_target and ver_i <= target_ver_index) { 759 if (is_unversioned) { 760 if (chosen_unversioned_ver_index == 255 or ver_i > chosen_unversioned_ver_index) { 761 chosen_unversioned_ver_index = ver_i; 762 } 763 } else { 764 if (chosen_def_ver_index == 255 or ver_i > chosen_def_ver_index) { 765 chosen_def_ver_index = ver_i; 766 } 767 768 versions.set(ver_i); 769 } 770 771 sizes[ver_i] = size; 772 weak_linkages.setValue(ver_i, is_weak); 773 } 774 if (last) break; 775 } 776 777 if (is_terminal) { 778 opt_symbol_name = null; 779 } else continue; 780 } 781 782 if (chosen_unversioned_ver_index != 255) { 783 // Example: 784 // .balign 4 785 // .globl malloc_conf 786 // .type malloc_conf, %object 787 // .size malloc_conf, 4 788 // malloc_conf: .fill 4, 1, 0 789 try stubs_asm.print( 790 \\.balign {d} 791 \\.{s} {s} 792 \\.type {s}, %object 793 \\.size {s}, {d} 794 \\{s}: {s} 0 795 \\ 796 , .{ 797 target.ptrBitWidth() / 8, 798 if (weak_linkages.isSet(chosen_unversioned_ver_index)) "weak" else "globl", 799 sym_name, 800 sym_name, 801 sym_name, 802 sizes[chosen_unversioned_ver_index], 803 sym_name, 804 wordDirective(target), 805 }); 806 } 807 808 { 809 var versions_iter = versions.iterator(.{}); 810 while (versions_iter.next()) |ver_index| { 811 // Example: 812 // .balign 4 813 // .globl malloc_conf_1_3 814 // .type malloc_conf_1_3, %object 815 // .size malloc_conf_1_3, 4 816 // .symver malloc_conf_1_3, malloc_conf@@FBSD_1.3 817 // malloc_conf_1_3: .fill 4, 1, 0 818 const ver = metadata.all_versions[ver_index]; 819 const sym_plus_ver = try std.fmt.allocPrint( 820 arena, 821 "{s}_FBSD_{d}_{d}", 822 .{ sym_name, ver.major, ver.minor }, 823 ); 824 825 try stubs_asm.print( 826 \\.balign {d} 827 \\.{s} {s} 828 \\.type {s}, %object 829 \\.size {s}, {d} 830 \\.symver {s}, {s}{s}FBSD_{d}.{d} 831 \\{s}: .fill {d}, 1, 0 832 \\ 833 , .{ 834 target.ptrBitWidth() / 8, 835 if (weak_linkages.isSet(ver_index)) "weak" else "globl", 836 sym_plus_ver, 837 sym_plus_ver, 838 sym_plus_ver, 839 sizes[ver_index], 840 sym_plus_ver, 841 sym_name, 842 // Default symbol version definition vs normal symbol version definition 843 if (chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index) "@@" else "@", 844 ver.major, 845 ver.minor, 846 sym_plus_ver, 847 sizes[ver_index], 848 }); 849 } 850 } 851 } 852 853 try stubs_asm.appendSlice(".tdata\n"); 854 855 const tls_inclusions_len = try inc_reader.takeInt(u16, .little); 856 857 sym_i = 0; 858 opt_symbol_name = null; 859 860 while (sym_i < tls_inclusions_len) : (sym_i += 1) { 861 const sym_name = opt_symbol_name orelse n: { 862 sym_name_buf.clearRetainingCapacity(); 863 _ = try inc_reader.streamDelimiter(&sym_name_buf.writer, 0); 864 assert(inc_reader.buffered()[0] == 0); // TODO change streamDelimiter API 865 inc_reader.toss(1); 866 867 opt_symbol_name = sym_name_buf.written(); 868 versions.unsetAll(); 869 weak_linkages.unsetAll(); 870 chosen_def_ver_index = 255; 871 chosen_unversioned_ver_index = 255; 872 873 break :n sym_name_buf.written(); 874 }; 875 876 { 877 const targets = try inc_reader.takeLeb128(u64); 878 const size = try inc_reader.takeLeb128(u16); 879 var lib_index = try inc_reader.takeByte(); 880 881 const is_unversioned = (lib_index & (1 << 5)) != 0; 882 const is_weak = (lib_index & (1 << 6)) != 0; 883 const is_terminal = (lib_index & (1 << 7)) != 0; 884 885 lib_index = @as(u5, @truncate(lib_index)); 886 887 // Test whether the inclusion applies to our current library and target. 888 const ok_lib_and_target = 889 (lib_index == lib_i) and 890 ((targets & (@as(u64, 1) << @as(u6, @intCast(target_targ_index)))) != 0); 891 892 while (true) { 893 const byte = try inc_reader.takeByte(); 894 const last = (byte & 0b1000_0000) != 0; 895 const ver_i = @as(u7, @truncate(byte)); 896 if (ok_lib_and_target and ver_i <= target_ver_index) { 897 if (is_unversioned) { 898 if (chosen_unversioned_ver_index == 255 or ver_i > chosen_unversioned_ver_index) { 899 chosen_unversioned_ver_index = ver_i; 900 } 901 } else { 902 if (chosen_def_ver_index == 255 or ver_i > chosen_def_ver_index) { 903 chosen_def_ver_index = ver_i; 904 } 905 906 versions.set(ver_i); 907 } 908 909 sizes[ver_i] = size; 910 weak_linkages.setValue(ver_i, is_weak); 911 } 912 if (last) break; 913 } 914 915 if (is_terminal) { 916 opt_symbol_name = null; 917 } else continue; 918 } 919 920 if (chosen_unversioned_ver_index != 255) { 921 // Example: 922 // .balign 4 923 // .globl _ThreadRuneLocale 924 // .type _ThreadRuneLocale, %object 925 // .size _ThreadRuneLocale, 4 926 // _ThreadRuneLocale: .fill 4, 1, 0 927 try stubs_asm.print( 928 \\.balign {d} 929 \\.{s} {s} 930 \\.type {s}, %tls_object 931 \\.size {s}, {d} 932 \\{s}: {s} 0 933 \\ 934 , .{ 935 target.ptrBitWidth() / 8, 936 if (weak_linkages.isSet(chosen_unversioned_ver_index)) "weak" else "globl", 937 sym_name, 938 sym_name, 939 sym_name, 940 sizes[chosen_unversioned_ver_index], 941 sym_name, 942 wordDirective(target), 943 }); 944 } 945 946 { 947 var versions_iter = versions.iterator(.{}); 948 while (versions_iter.next()) |ver_index| { 949 // Example: 950 // .balign 4 951 // .globl _ThreadRuneLocale_1_3 952 // .type _ThreadRuneLocale_1_3, %tls_object 953 // .size _ThreadRuneLocale_1_3, 4 954 // .symver _ThreadRuneLocale_1_3, _ThreadRuneLocale@@FBSD_1.3 955 // _ThreadRuneLocale_1_3: .fill 4, 1, 0 956 const ver = metadata.all_versions[ver_index]; 957 const sym_plus_ver = try std.fmt.allocPrint( 958 arena, 959 "{s}_FBSD_{d}_{d}", 960 .{ sym_name, ver.major, ver.minor }, 961 ); 962 963 try stubs_asm.print( 964 \\.balign {d} 965 \\.{s} {s} 966 \\.type {s}, %tls_object 967 \\.size {s}, {d} 968 \\.symver {s}, {s}{s}FBSD_{d}.{d} 969 \\{s}: .fill {d}, 1, 0 970 \\ 971 , .{ 972 target.ptrBitWidth() / 8, 973 if (weak_linkages.isSet(ver_index)) "weak" else "globl", 974 sym_plus_ver, 975 sym_plus_ver, 976 sym_plus_ver, 977 sizes[ver_index], 978 sym_plus_ver, 979 sym_name, 980 // Default symbol version definition vs normal symbol version definition 981 if (chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index) "@@" else "@", 982 ver.major, 983 ver.minor, 984 sym_plus_ver, 985 sizes[ver_index], 986 }); 987 } 988 } 989 } 990 991 var lib_name_buf: [32]u8 = undefined; // Larger than each of the names "c", "stdthreads", etc. 992 const asm_file_basename = std.mem.print(&lib_name_buf, "{s}.s", .{lib.name}) catch unreachable; 993 try o_directory.handle.writeFile(io, .{ .sub_path = asm_file_basename, .data = stubs_asm.items }); 994 try buildSharedLib(comp, arena, o_directory, asm_file_basename, lib, prog_node); 995 } 996 997 man.finalize() catch |err| log.warn("failed to write cache manifest for FreeBSD libc stubs: {t}", .{err}); 998 999 return queueSharedObjects(comp, .{ 1000 .lock = man.toOwnedLock(), 1001 .dir_path = .{ 1002 .root_dir = comp.dirs.global_cache, 1003 .sub_path = try gpa.dupe(u8, "o" ++ path.sep_str ++ digest), 1004 }, 1005 }); 1006 } 1007 1008 fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) std.Io.Cancelable!void { 1009 const io = comp.io; 1010 const target = comp.getTarget(); 1011 const target_os_version = target.os.version_range.semver.min; 1012 1013 assert(comp.freebsd_so_files == null); 1014 comp.freebsd_so_files = so_files; 1015 1016 var task_buffer: [libs.len]link.PrelinkTask = undefined; 1017 var task_buffer_i: usize = 0; 1018 1019 { 1020 comp.mutex.lockUncancelable(io); // protect comp.arena 1021 defer comp.mutex.unlock(io); 1022 1023 for (libs) |lib| { 1024 if (lib.added_in) |add_in| { 1025 if (target_os_version.order(add_in) == .lt) continue; 1026 } 1027 1028 const so_path: Path = .{ 1029 .root_dir = so_files.dir_path.root_dir, 1030 .sub_path = std.fmt.allocPrint(comp.arena, "{s}{c}lib{s}.so.{d}", .{ 1031 so_files.dir_path.sub_path, path.sep, lib.name, lib.getSoVersion(&target.os), 1032 }) catch return comp.setAllocFailure(), 1033 }; 1034 task_buffer[task_buffer_i] = .{ .load_dso = so_path }; 1035 task_buffer_i += 1; 1036 } 1037 } 1038 1039 try comp.queuePrelinkTasks(task_buffer[0..task_buffer_i]); 1040 } 1041 1042 fn buildSharedLib( 1043 comp: *Compilation, 1044 arena: Allocator, 1045 bin_directory: Cache.Directory, 1046 asm_file_basename: []const u8, 1047 lib: Lib, 1048 prog_node: std.Progress.Node, 1049 ) !void { 1050 const tracy = trace(@src()); 1051 defer tracy.end(); 1052 1053 const target = comp.getTarget(); 1054 1055 const io = comp.io; 1056 const sover = lib.getSoVersion(&target.os); 1057 const basename = try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ lib.name, sover }); 1058 const version: Version = .{ .major = sover, .minor = 0, .patch = 0 }; 1059 const ld_basename = path.basename(target.standardDynamicLinkerPath().get().?); 1060 const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename; 1061 1062 const optimize_mode = comp.compilerRtOptMode(); 1063 const strip = comp.compilerRtStrip(); 1064 const config = try Compilation.Config.resolve(.{ 1065 .output_mode = .Lib, 1066 .link_mode = .dynamic, 1067 .resolved_target = comp.root_mod.resolved_target, 1068 .is_test = false, 1069 .have_zcu = false, 1070 .emit_bin = true, 1071 .root_optimize_mode = optimize_mode, 1072 .root_strip = strip, 1073 .link_libc = false, 1074 }); 1075 1076 const root_mod = try Module.create(arena, .{ 1077 .paths = .{ 1078 .root = .zig_lib_root, 1079 .root_src_path = "", 1080 }, 1081 .fully_qualified_name = "root", 1082 .inherited = .{ 1083 .resolved_target = comp.root_mod.resolved_target, 1084 .strip = strip, 1085 .stack_check = false, 1086 .stack_protector = 0, 1087 .sanitize_c = .off, 1088 .sanitize_thread = false, 1089 .red_zone = comp.root_mod.red_zone, 1090 .omit_frame_pointer = comp.root_mod.omit_frame_pointer, 1091 .valgrind = false, 1092 .optimize_mode = optimize_mode, 1093 }, 1094 .global = config, 1095 .cc_argv = &.{}, 1096 .parent = null, 1097 }); 1098 1099 const c_source_files = [1]Compilation.CSourceFile{ 1100 .{ 1101 .src_path = try path.join(arena, &.{ bin_directory.path.?, asm_file_basename }), 1102 .owner = root_mod, 1103 }, 1104 }; 1105 1106 const misc_task: Compilation.MiscTask = .@"freebsd libc shared object"; 1107 1108 var sub_create_diag: Compilation.CreateDiagnostic = undefined; 1109 const sub_compilation = Compilation.create(comp.gpa, arena, io, &sub_create_diag, .{ 1110 .thread_limit = comp.thread_limit, 1111 .dirs = comp.dirs.withoutLocalCache(), 1112 .self_exe_path = comp.self_exe_path, 1113 // Because we manually cache the whole set of objects, we don't cache the individual objects 1114 // within it. In fact, we *can't* do that, because we need `emit_bin` to specify the path. 1115 .cache_mode = .none, 1116 .config = config, 1117 .root_mod = root_mod, 1118 .root_name = lib.name, 1119 .libc_installation = comp.libc_installation, 1120 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) }, 1121 .verbose_cc = comp.verbose_cc, 1122 .verbose_link = comp.verbose_link, 1123 .verbose_air = comp.verbose_air, 1124 .verbose_llvm_ir = comp.verbose_llvm_ir, 1125 .verbose_llvm_bc = comp.verbose_llvm_bc, 1126 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, 1127 .clang_passthrough_mode = comp.clang_passthrough_mode, 1128 .version = version, 1129 .version_script = .{ 1130 .root_dir = bin_directory, 1131 .sub_path = all_map_basename, 1132 }, 1133 .soname = soname, 1134 .c_source_files = &c_source_files, 1135 .skip_linker_dependencies = true, 1136 .environ_map = comp.environ_map, 1137 }) catch |err| switch (err) { 1138 error.CreateFail => { 1139 comp.lockAndSetMiscFailure(misc_task, "sub-compilation of {t} failed: {f}", .{ misc_task, sub_create_diag }); 1140 return error.AlreadyReported; 1141 }, 1142 else => |e| return e, 1143 }; 1144 defer sub_compilation.destroy(); 1145 1146 try comp.updateSubCompilation(sub_compilation, misc_task, prog_node); 1147 } 1148