authorgravatar for mrjbq7@gmail.comJohn Benediktsson <mrjbq7@gmail.com> 2026-07-06 18:30:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-07-08 03:35:02+02:00
logf2c9e7a5c9d6fb171ec78e094e5c41df6b9cdfe5
tree92b42578b6ee273354c1f4775242dd55ab473f2f
parentf61b5c0e7cbc9ffed36dcd2e549ba3c481faf9c7

std.Build: cache package_map to improve dependency resolution


1 files changed, 59 insertions(+), 39 deletions(-)

lib/std/Build.zig+59-39
......@@ -2135,25 +2135,46 @@ pub fn lazyDependency(b: *Build, name: []const u8, args: anytype) ?*Dependency {
21352135///
21362136/// For non-lazy dependencies, this always succeeds.
21372137pub fn dependencyLazy(b: *Build, name: []const u8, args: anytype) error{LazyDependencyNeeded}!*Dependency {
2138 const build_runner = @import("root");
2139 const deps = build_runner.dependencies;
21402138 const pkg_hash = findPkgHashOrFatal(b, name);
2141
2142 inline for (@typeInfo(deps.packages).@"struct".decl_names) |decl_name| {
2143 if (mem.eql(u8, decl_name, pkg_hash)) {
2144 const pkg = @field(deps.packages, decl_name);
2145 const available = !@hasDecl(pkg, "available") or pkg.available;
2146 if (!available) {
2147 markNeededLazyDep(b, pkg_hash);
2148 return error.LazyDependencyNeeded;
2149 }
2150 return dependencyInner(b, name, pkg.build_root, if (@hasDecl(pkg, "build_zig")) pkg.build_zig else null, pkg_hash, pkg.deps, args);
2151 }
2139 const entry = package_map.get(pkg_hash) orelse unreachable;
2140 if (!entry.available) {
2141 markNeededLazyDep(b, pkg_hash);
2142 return error.LazyDependencyNeeded;
21522143 }
2153
2154 unreachable; // bad @dependencies source
2144 return dependencyResolved(b, name, entry, userInputOptionsFromArgs(b.graph.arena, args));
21552145}
21562146
2147const PackageEntry = struct {
2148 hash: []const u8,
2149 available: bool,
2150 build_root: []const u8,
2151 deps: AvailableDeps,
2152 run_build: ?*const fn (*Build) void,
2153};
2154
2155const package_map: std.StaticStringMap(PackageEntry) = blk: {
2156 const deps = @import("root").dependencies;
2157 const decl_names = @typeInfo(deps.packages).@"struct".decl_names;
2158 var kvs: [decl_names.len]struct { []const u8, PackageEntry } = undefined;
2159 for (decl_names, 0..) |decl_name, i| {
2160 const pkg = @field(deps.packages, decl_name);
2161 const available = !@hasDecl(pkg, "available") or pkg.available;
2162 kvs[i] = .{ decl_name, .{
2163 .hash = decl_name,
2164 .available = available,
2165 .build_root = if (available) pkg.build_root else "",
2166 .deps = if (available) pkg.deps else &.{},
2167 .run_build = if (available and @hasDecl(pkg, "build_zig")) &struct {
2168 fn run(sb: *Build) void {
2169 sb.runPackageScript(pkg.build_zig);
2170 }
2171 }.run else null,
2172 } };
2173 }
2174 const frozen = kvs;
2175 break :blk .initComptime(&frozen);
2176};
2177
21572178/// Declares that the current configuration does in fact require a potentially
21582179/// lazy dependency.
21592180///
......@@ -2210,6 +2231,14 @@ pub inline fn lazyImport(
22102231 comptime unreachable; // Bad @dependencies source
22112232}
22122233
2234fn pkgHashFromBuildZig(comptime build_zig: type) ?[]const u8 {
2235 const deps = @import("root").dependencies;
2236 return comptime for (@typeInfo(deps.packages).@"struct".decl_names) |pkg_hash| {
2237 const pkg = @field(deps.packages, pkg_hash);
2238 if (@hasDecl(pkg, "build_zig") and pkg.build_zig == build_zig) break pkg_hash;
2239 } else null;
2240}
2241
22132242/// Build system implementation detail.
22142243pub fn dependencyFromBuildZig(
22152244 b: *Build,
......@@ -2218,20 +2247,15 @@ pub fn dependencyFromBuildZig(
22182247 comptime build_zig: type,
22192248 args: anytype,
22202249) *Dependency {
2221 const build_runner = @import("root");
2222 const deps = build_runner.dependencies;
2223 const graph = b.graph;
2224 const arena = graph.arena;
2250 const arena = b.graph.arena;
22252251
22262252 find_dep: {
2227 const pkg, const pkg_hash = inline for (@typeInfo(deps.packages).@"struct".decl_names) |pkg_hash| {
2228 const pkg = @field(deps.packages, pkg_hash);
2229 if (@hasDecl(pkg, "build_zig") and pkg.build_zig == build_zig) break .{ pkg, pkg_hash };
2230 } else break :find_dep;
2253 const pkg_hash = comptime pkgHashFromBuildZig(build_zig) orelse break :find_dep;
22312254 const dep_name = for (b.available_deps) |dep| {
22322255 if (mem.eql(u8, dep[1], pkg_hash)) break dep[1];
22332256 } else break :find_dep;
2234 return dependencyInner(b, dep_name, pkg.build_root, pkg.build_zig, pkg_hash, pkg.deps, args);
2257 const entry = package_map.get(pkg_hash) orelse break :find_dep;
2258 return dependencyResolved(b, dep_name, entry, userInputOptionsFromArgs(arena, args));
22352259 }
22362260
22372261 const full_path = b.root.join(arena, "build.zig.zon") catch @panic("OOM");
......@@ -2321,35 +2345,31 @@ fn userLazyPathsAreTheSame(lhs_lp: LazyPath, rhs_lp: LazyPath) bool {
23212345 return true;
23222346}
23232347
2324fn dependencyInner(
2348fn dependencyResolved(
23252349 b: *Build,
23262350 name: []const u8,
2327 build_root_string: []const u8,
2328 comptime build_zig: ?type,
2329 pkg_hash: []const u8,
2330 pkg_deps: AvailableDeps,
2331 args: anytype,
2351 entry: PackageEntry,
2352 user_input_options: UserInputOptionsMap,
23322353) *Dependency {
23332354 const graph = b.graph;
23342355 const io = graph.io;
23352356 const arena = graph.arena;
2336 const user_input_options = userInputOptionsFromArgs(arena, args);
23372357 if (graph.dependency_cache.getContext(.{
2338 .build_root_string = build_root_string,
2358 .build_root_string = entry.build_root,
23392359 .user_input_options = user_input_options,
23402360 }, .{ .allocator = arena })) |dep| return dep;
23412361
23422362 const dep_root: Cache.Path = .{
23432363 .root_dir = .{
2344 .path = build_root_string,
2345 .handle = Io.Dir.cwd().openDir(io, build_root_string, .{}) catch |err|
2346 fatal("failed to open {q}: {t}", .{ build_root_string, err }),
2364 .path = entry.build_root,
2365 .handle = Io.Dir.cwd().openDir(io, entry.build_root, .{}) catch |err|
2366 fatal("failed to open {q}: {t}", .{ entry.build_root, err }),
23472367 },
23482368 };
23492369
2350 const sub_builder = b.createChild(name, dep_root, pkg_hash, pkg_deps, user_input_options) catch @panic("OOM");
2351 if (build_zig) |bz| {
2352 sub_builder.runPackageScript(bz);
2370 const sub_builder = b.createChild(name, dep_root, entry.hash, entry.deps, user_input_options) catch @panic("OOM");
2371 if (entry.run_build) |run_build| {
2372 run_build(sub_builder);
23532373
23542374 if (sub_builder.validateUserInputDidItFail()) {
23552375 std.debug.dumpCurrentStackTrace(.{ .first_address = @returnAddress() });
......@@ -2360,7 +2380,7 @@ fn dependencyInner(
23602380 dep.* = .{ .builder = sub_builder };
23612381
23622382 graph.dependency_cache.putContext(arena, .{
2363 .build_root_string = build_root_string,
2383 .build_root_string = entry.build_root,
23642384 .user_input_options = user_input_options,
23652385 }, dep, .{ .allocator = arena }) catch @panic("OOM");
23662386 return dep;