Merge pull request 'Compilation: make libzigc share zcu if possible' (#31037) from GasInfinity/zig:libc-share-zcu into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31037
This commit is contained in:
Andrew Kelley 2026-01-30 08:16:39 +01:00
commit 380ea6fb5e
4 changed files with 69 additions and 16 deletions

View file

@ -1,18 +1,14 @@
const builtin = @import("builtin");
const std = @import("std");
pub const linkage: std.builtin.GlobalLinkage = if (builtin.is_test)
.internal
else
.strong;
/// It is incorrect to make this conditional on `builtin.is_test`, because it is possible that
/// libzigc is being linked into a different test compilation, as opposed to being tested itself.
pub const linkage: std.builtin.GlobalLinkage = .strong;
/// Determines the symbol's visibility to other objects.
/// For WebAssembly this allows the symbol to be resolved to other modules, but will not
/// export it to the host runtime.
pub const visibility: std.builtin.SymbolVisibility = if (linkage != .internal)
.hidden
else
.default;
pub const visibility: std.builtin.SymbolVisibility = .hidden;
/// Given a low-level syscall return value, sets errno and returns `-1`, or on
/// success returns the result.

View file

@ -80,6 +80,7 @@ sysroot: ?[]const u8,
root_name: [:0]const u8,
compiler_rt_strat: RtStrat,
ubsan_rt_strat: RtStrat,
zigc_strat: RtStrat,
/// Resolved into known paths, any GNU ld scripts already resolved.
link_inputs: []const link.Input,
/// Needed only for passing -F args to clang.
@ -2101,6 +2102,47 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
try options.root_mod.deps.putNoClobber(arena, "ubsan_rt", ubsan_rt_mod);
}
// Like with ubsan_rt we want to go through the `_ = @import("zigc")`
// approach if possible since it uses even more of the standard library
// and can thus reduce further unnecesary bloat.
const zigc_strat: RtStrat = s: {
if (options.skip_linker_dependencies) break :s .none;
if (target.ofmt == .c) break :s .none;
if (!link_libc or !is_exe_or_dyn_lib) break :s .none;
if (!target_util.wantsZigC(target, options.config.link_mode)) break :s .none;
if (have_zcu) break :s .zcu;
break :s .lib;
};
if (zigc_strat == .zcu) {
const zigc_mod = Package.Module.create(arena, .{
.paths = .{
.root = .zig_lib_root,
.root_src_path = "c.zig",
},
.fully_qualified_name = "zigc",
.cc_argv = &.{},
.inherited = .{},
.global = options.config,
.parent = options.root_mod,
}) catch |err| switch (err) {
error.OutOfMemory => |e| return e,
// None of these are possible because the configuration matches the root module
// which already passed these checks.
error.ValgrindUnsupportedOnTarget => unreachable,
error.TargetRequiresSingleThreaded => unreachable,
error.BackendRequiresSingleThreaded => unreachable,
error.TargetRequiresPic => unreachable,
error.PieRequiresPic => unreachable,
error.DynamicLinkingRequiresPic => unreachable,
error.TargetHasNoRedZone => unreachable,
error.StackCheckUnsupportedByTarget => unreachable,
error.StackProtectorUnsupportedByTarget => unreachable,
error.StackProtectorUnavailableWithoutLibC => unreachable,
};
try options.root_mod.deps.putNoClobber(arena, "zigc", zigc_mod);
}
if (options.verbose_llvm_cpu_features) {
if (options.root_mod.resolved_target.llvm_cpu_features) |cf| {
const stderr = try io.lockStderr(&.{}, null);
@ -2296,6 +2338,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
.libc_installation = libc_dirs.libc_installation,
.compiler_rt_strat = compiler_rt_strat,
.ubsan_rt_strat = ubsan_rt_strat,
.zigc_strat = zigc_strat,
.link_inputs = options.link_inputs,
.framework_dirs = options.framework_dirs,
.llvm_opt_bisect_limit = options.llvm_opt_bisect_limit,
@ -2651,13 +2694,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
} else {
return diag.fail(.cross_libc_unavailable);
}
if ((target.isMuslLibC() and comp.config.link_mode == .static) or
target.isWasiLibC() or
target.isMinGW())
{
comp.queued_jobs.zigc_lib = true;
}
}
// Generate Windows import libs.
@ -2711,6 +2747,15 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
.dyn_lib => unreachable, // hack for compiler_rt only
}
switch (comp.zigc_strat) {
.none, .zcu => {},
.lib => {
log.debug("queuing a job to build libzigc", .{});
comp.queued_jobs.zigc_lib = true;
},
.obj, .dyn_lib => unreachable, // only available as a static library or inside an existing ZCU
}
if (is_exe_or_dyn_lib and comp.config.any_fuzz) {
log.debug("queuing a job to build libfuzzer", .{});
comp.queued_jobs.fuzzer_lib = true;
@ -3100,6 +3145,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
zcu.analysis_roots_buffer[zcu.analysis_roots_len] = ubsan_rt_mod;
zcu.analysis_roots_len += 1;
}
if (zcu.root_mod.deps.get("zigc")) |zigc_mod| {
zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zigc_mod;
zcu.analysis_roots_len += 1;
}
}
// The linker progress node is set up here instead of in `performAllTheWork`, because
@ -3531,6 +3581,7 @@ fn addNonIncrementalStuffToCacheManifest(
man.hash.add(comp.skip_linker_dependencies);
man.hash.add(comp.compiler_rt_strat);
man.hash.add(comp.ubsan_rt_strat);
man.hash.add(comp.zigc_strat);
man.hash.add(comp.rc_includes);
man.hash.addListOfBytes(comp.force_undefined_symbols.keys());
man.hash.addListOfBytes(comp.framework_dirs);

View file

@ -269,7 +269,7 @@ nav_val_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, voi
/// These are the modules which we initially queue for analysis in `Compilation.update`.
/// `resolveReferences` will use these as the root of its reachability traversal.
analysis_roots_buffer: [4]*Package.Module,
analysis_roots_buffer: [5]*Package.Module,
analysis_roots_len: usize = 0,
/// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and
/// reset to `null` when any semantic analysis occurs (since this invalidates the data).

View file

@ -423,6 +423,12 @@ pub fn canBuildLibUbsanRt(target: *const std.Target) enum { no, yes, llvm_only,
};
}
/// Whether libzigc can fill-in the gaps of an existing libc
/// or *is* the libc of the target.
pub fn wantsZigC(target: *const std.Target, link_mode: std.builtin.LinkMode) bool {
return (target.isMuslLibC() and link_mode == .static) or target.isWasiLibC() or target.isMinGW();
}
pub fn hasRedZone(target: *const std.Target) bool {
return switch (target.cpu.arch) {
.aarch64,