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.
This commit is contained in:
Alex Rønne Petersen 2025-05-05 07:23:28 +02:00
parent 0e3609b8e0
commit d3a6236eef
No known key found for this signature in database
4 changed files with 1172 additions and 2 deletions

View File

@ -586,6 +586,7 @@ set(ZIG_STAGE2_SOURCES
src/codegen/spirv/spec.zig src/codegen/spirv/spec.zig
src/crash_report.zig src/crash_report.zig
src/dev.zig src/dev.zig
src/libs/freebsd.zig
src/libs/glibc.zig src/libs/glibc.zig
src/introspect.zig src/introspect.zig
src/libs/libcxx.zig src/libs/libcxx.zig

View File

@ -23,6 +23,7 @@ const build_options = @import("build_options");
const LibCInstallation = std.zig.LibCInstallation; const LibCInstallation = std.zig.LibCInstallation;
const glibc = @import("libs/glibc.zig"); const glibc = @import("libs/glibc.zig");
const musl = @import("libs/musl.zig"); const musl = @import("libs/musl.zig");
const freebsd = @import("libs/freebsd.zig");
const mingw = @import("libs/mingw.zig"); const mingw = @import("libs/mingw.zig");
const libunwind = @import("libs/libunwind.zig"); const libunwind = @import("libs/libunwind.zig");
const libcxx = @import("libs/libcxx.zig"); const libcxx = @import("libs/libcxx.zig");
@ -248,6 +249,7 @@ compiler_rt_obj: ?CrtFile = null,
fuzzer_lib: ?CrtFile = null, fuzzer_lib: ?CrtFile = null,
glibc_so_files: ?glibc.BuiltSharedObjects = null, glibc_so_files: ?glibc.BuiltSharedObjects = null,
freebsd_so_files: ?freebsd.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, /// For example `Scrt1.o` and `libc_nonshared.a`. These are populated after building libc from source,
@ -294,12 +296,14 @@ const QueuedJobs = struct {
update_builtin_zig: bool, update_builtin_zig: bool,
musl_crt_file: [@typeInfo(musl.CrtFile).@"enum".fields.len]bool = @splat(false), musl_crt_file: [@typeInfo(musl.CrtFile).@"enum".fields.len]bool = @splat(false),
glibc_crt_file: [@typeInfo(glibc.CrtFile).@"enum".fields.len]bool = @splat(false), glibc_crt_file: [@typeInfo(glibc.CrtFile).@"enum".fields.len]bool = @splat(false),
freebsd_crt_file: [@typeInfo(freebsd.CrtFile).@"enum".fields.len]bool = @splat(false),
/// one of WASI libc static objects /// one of WASI libc static objects
wasi_libc_crt_file: [@typeInfo(wasi_libc.CrtFile).@"enum".fields.len]bool = @splat(false), wasi_libc_crt_file: [@typeInfo(wasi_libc.CrtFile).@"enum".fields.len]bool = @splat(false),
/// one of the mingw-w64 static objects /// one of the mingw-w64 static objects
mingw_crt_file: [@typeInfo(mingw.CrtFile).@"enum".fields.len]bool = @splat(false), mingw_crt_file: [@typeInfo(mingw.CrtFile).@"enum".fields.len]bool = @splat(false),
/// all of the glibc shared objects /// all of the glibc shared objects
glibc_shared_objects: bool = false, glibc_shared_objects: bool = false,
freebsd_shared_objects: bool = false,
/// libunwind.a, usually needed when linking libc /// libunwind.a, usually needed when linking libc
libunwind: bool = false, libunwind: bool = false,
libcxx: bool = false, libcxx: bool = false,
@ -789,6 +793,8 @@ pub const MiscTask = enum {
glibc_crt_file, glibc_crt_file,
glibc_shared_objects, glibc_shared_objects,
musl_crt_file, musl_crt_file,
freebsd_crt_file,
freebsd_shared_objects,
mingw_crt_file, mingw_crt_file,
windows_import_lib, windows_import_lib,
libunwind, libunwind,
@ -823,6 +829,9 @@ pub const MiscTask = enum {
@"glibc libc_nonshared.a", @"glibc libc_nonshared.a",
@"glibc shared object", @"glibc shared object",
@"freebsd libc Scrt1.o",
@"freebsd libc shared object",
@"mingw-w64 crt2.o", @"mingw-w64 crt2.o",
@"mingw-w64 dllcrt2.o", @"mingw-w64 dllcrt2.o",
@"mingw-w64 libmingw32.lib", @"mingw-w64 libmingw32.lib",
@ -1874,6 +1883,16 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
comp.queued_jobs.glibc_crt_file[@intFromEnum(glibc.CrtFile.libc_nonshared_a)] = true; comp.queued_jobs.glibc_crt_file[@intFromEnum(glibc.CrtFile.libc_nonshared_a)] = true;
comp.remaining_prelink_tasks += 1; comp.remaining_prelink_tasks += 1;
} else if (target.isFreeBSDLibC()) {
if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
if (freebsd.needsCrt0(comp.config.output_mode)) |f| {
comp.queued_jobs.freebsd_crt_file[@intFromEnum(f)] = true;
comp.remaining_prelink_tasks += 1;
}
comp.queued_jobs.freebsd_shared_objects = true;
comp.remaining_prelink_tasks += freebsd.sharedObjectsCount();
} else if (target.isWasiLibC()) { } else if (target.isWasiLibC()) {
if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
@ -2028,6 +2047,10 @@ pub fn destroy(comp: *Compilation) void {
glibc_file.deinit(gpa); glibc_file.deinit(gpa);
} }
if (comp.freebsd_so_files) |*freebsd_file| {
freebsd_file.deinit(gpa);
}
for (comp.c_object_table.keys()) |key| { for (comp.c_object_table.keys()) |key| {
key.destroy(gpa); key.destroy(gpa);
} }
@ -3839,6 +3862,10 @@ fn performAllTheWorkInner(
comp.link_task_wait_group.spawnManager(buildGlibcSharedObjects, .{ comp, main_progress_node }); comp.link_task_wait_group.spawnManager(buildGlibcSharedObjects, .{ comp, main_progress_node });
} }
if (comp.queued_jobs.freebsd_shared_objects) {
comp.link_task_wait_group.spawnManager(buildFreeBSDSharedObjects, .{ comp, main_progress_node });
}
if (comp.queued_jobs.libunwind) { if (comp.queued_jobs.libunwind) {
comp.link_task_wait_group.spawnManager(buildLibUnwind, .{ comp, main_progress_node }); comp.link_task_wait_group.spawnManager(buildLibUnwind, .{ comp, main_progress_node });
} }
@ -3873,6 +3900,13 @@ fn performAllTheWorkInner(
} }
} }
for (0..@typeInfo(freebsd.CrtFile).@"enum".fields.len) |i| {
if (comp.queued_jobs.freebsd_crt_file[i]) {
const tag: freebsd.CrtFile = @enumFromInt(i);
comp.link_task_wait_group.spawnManager(buildFreeBSDCrtFile, .{ comp, tag, main_progress_node });
}
}
for (0..@typeInfo(wasi_libc.CrtFile).@"enum".fields.len) |i| { for (0..@typeInfo(wasi_libc.CrtFile).@"enum".fields.len) |i| {
if (comp.queued_jobs.wasi_libc_crt_file[i]) { if (comp.queued_jobs.wasi_libc_crt_file[i]) {
const tag: wasi_libc.CrtFile = @enumFromInt(i); const tag: wasi_libc.CrtFile = @enumFromInt(i);
@ -4876,6 +4910,29 @@ fn buildGlibcSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) voi
} }
} }
fn buildFreeBSDCrtFile(comp: *Compilation, crt_file: freebsd.CrtFile, prog_node: std.Progress.Node) void {
if (freebsd.buildCrtFile(comp, crt_file, prog_node)) |_| {
comp.queued_jobs.freebsd_crt_file[@intFromEnum(crt_file)] = false;
} else |err| switch (err) {
error.SubCompilationFailed => return, // error reported already
else => comp.lockAndSetMiscFailure(.freebsd_crt_file, "unable to build FreeBSD {s}: {s}", .{
@tagName(crt_file), @errorName(err),
}),
}
}
fn buildFreeBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void {
if (freebsd.buildSharedObjects(comp, prog_node)) |_| {
// The job should no longer be queued up since it succeeded.
comp.queued_jobs.freebsd_shared_objects = false;
} else |err| switch (err) {
error.SubCompilationFailed => return, // error reported already
else => comp.lockAndSetMiscFailure(.freebsd_shared_objects, "unable to build FreeBSD libc shared objects: {s}", .{
@errorName(err),
}),
}
}
fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std.Progress.Node) void { fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std.Progress.Node) void {
if (mingw.buildCrtFile(comp, crt_file, prog_node)) |_| { if (mingw.buildCrtFile(comp, crt_file, prog_node)) |_| {
comp.queued_jobs.mingw_crt_file[@intFromEnum(crt_file)] = false; comp.queued_jobs.mingw_crt_file[@intFromEnum(crt_file)] = false;

1104
src/libs/freebsd.zig Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2058,11 +2058,18 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
try argv.append(lib_path); try argv.append(lib_path);
} }
try argv.append(try comp.crtFileAsString(arena, "libc_nonshared.a")); try argv.append(try comp.crtFileAsString(arena, "libc_nonshared.a"));
} else if (target.abi.isMusl()) { } else if (target.isMuslLibC()) {
try argv.append(try comp.crtFileAsString(arena, switch (link_mode) { try argv.append(try comp.crtFileAsString(arena, switch (link_mode) {
.static => "libc.a", .static => "libc.a",
.dynamic => "libc.so", .dynamic => "libc.so",
})); }));
} else if (target.isFreeBSDLibC()) {
for (freebsd.libs) |lib| {
const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{
comp.freebsd_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
});
try argv.append(lib_path);
}
} else { } else {
diags.flags.missing_libc = true; diags.flags.missing_libc = true;
} }
@ -5280,8 +5287,9 @@ const dev = @import("../dev.zig");
const eh_frame = @import("Elf/eh_frame.zig"); const eh_frame = @import("Elf/eh_frame.zig");
const gc = @import("Elf/gc.zig"); const gc = @import("Elf/gc.zig");
const glibc = @import("../libs/glibc.zig"); const glibc = @import("../libs/glibc.zig");
const link = @import("../link.zig");
const musl = @import("../libs/musl.zig"); const musl = @import("../libs/musl.zig");
const freebsd = @import("../libs/freebsd.zig");
const link = @import("../link.zig");
const relocatable = @import("Elf/relocatable.zig"); const relocatable = @import("Elf/relocatable.zig");
const relocation = @import("Elf/relocation.zig"); const relocation = @import("Elf/relocation.zig");
const target_util = @import("../target.zig"); const target_util = @import("../target.zig");