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 {...@@ -2135,25 +2135,46 @@ pub fn lazyDependency(b: *Build, name: []const u8, args: anytype) ?*Dependency {
2135///2135///
2136/// For non-lazy dependencies, this always succeeds.2136/// For non-lazy dependencies, this always succeeds.
2137pub fn dependencyLazy(b: *Build, name: []const u8, args: anytype) error{LazyDependencyNeeded}!*Dependency {2137pub fn dependencyLazy(b: *Build, name: []const u8, args: anytype) error{LazyDependencyNeeded}!*Dependency {
2138 const build_runner = @import("root");
2139 const deps = build_runner.dependencies;
2140 const pkg_hash = findPkgHashOrFatal(b, name);2138 const pkg_hash = findPkgHashOrFatal(b, name);
21412139 const entry = package_map.get(pkg_hash) orelse unreachable;
2142 inline for (@typeInfo(deps.packages).@"struct".decl_names) |decl_name| {2140 if (!entry.available) {
2143 if (mem.eql(u8, decl_name, pkg_hash)) {2141 markNeededLazyDep(b, pkg_hash);
2144 const pkg = @field(deps.packages, decl_name);2142 return error.LazyDependencyNeeded;
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 }
2152 }2143 }
21532144 return dependencyResolved(b, name, entry, userInputOptionsFromArgs(b.graph.arena, args));
2154 unreachable; // bad @dependencies source
2155}2145}
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
2157/// Declares that the current configuration does in fact require a potentially2178/// Declares that the current configuration does in fact require a potentially
2158/// lazy dependency.2179/// lazy dependency.
2159///2180///
...@@ -2210,6 +2231,14 @@ pub inline fn lazyImport(...@@ -2210,6 +2231,14 @@ pub inline fn lazyImport(
2210 comptime unreachable; // Bad @dependencies source2231 comptime unreachable; // Bad @dependencies source
2211}2232}
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
2213/// Build system implementation detail.2242/// Build system implementation detail.
2214pub fn dependencyFromBuildZig(2243pub fn dependencyFromBuildZig(
2215 b: *Build,2244 b: *Build,
...@@ -2218,20 +2247,15 @@ pub fn dependencyFromBuildZig(...@@ -2218,20 +2247,15 @@ pub fn dependencyFromBuildZig(
2218 comptime build_zig: type,2247 comptime build_zig: type,
2219 args: anytype,2248 args: anytype,
2220) *Dependency {2249) *Dependency {
2221 const build_runner = @import("root");2250 const arena = b.graph.arena;
2222 const deps = build_runner.dependencies;
2223 const graph = b.graph;
2224 const arena = graph.arena;
22252251
2226 find_dep: {2252 find_dep: {
2227 const pkg, const pkg_hash = inline for (@typeInfo(deps.packages).@"struct".decl_names) |pkg_hash| {2253 const pkg_hash = comptime pkgHashFromBuildZig(build_zig) orelse break :find_dep;
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;
2231 const dep_name = for (b.available_deps) |dep| {2254 const dep_name = for (b.available_deps) |dep| {
2232 if (mem.eql(u8, dep[1], pkg_hash)) break dep[1];2255 if (mem.eql(u8, dep[1], pkg_hash)) break dep[1];
2233 } else break :find_dep;2256 } 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));
2235 }2259 }
22362260
2237 const full_path = b.root.join(arena, "build.zig.zon") catch @panic("OOM");2261 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 {...@@ -2321,35 +2345,31 @@ fn userLazyPathsAreTheSame(lhs_lp: LazyPath, rhs_lp: LazyPath) bool {
2321 return true;2345 return true;
2322}2346}
23232347
2324fn dependencyInner(2348fn dependencyResolved(
2325 b: *Build,2349 b: *Build,
2326 name: []const u8,2350 name: []const u8,
2327 build_root_string: []const u8,2351 entry: PackageEntry,
2328 comptime build_zig: ?type,2352 user_input_options: UserInputOptionsMap,
2329 pkg_hash: []const u8,
2330 pkg_deps: AvailableDeps,
2331 args: anytype,
2332) *Dependency {2353) *Dependency {
2333 const graph = b.graph;2354 const graph = b.graph;
2334 const io = graph.io;2355 const io = graph.io;
2335 const arena = graph.arena;2356 const arena = graph.arena;
2336 const user_input_options = userInputOptionsFromArgs(arena, args);
2337 if (graph.dependency_cache.getContext(.{2357 if (graph.dependency_cache.getContext(.{
2338 .build_root_string = build_root_string,2358 .build_root_string = entry.build_root,
2339 .user_input_options = user_input_options,2359 .user_input_options = user_input_options,
2340 }, .{ .allocator = arena })) |dep| return dep;2360 }, .{ .allocator = arena })) |dep| return dep;
23412361
2342 const dep_root: Cache.Path = .{2362 const dep_root: Cache.Path = .{
2343 .root_dir = .{2363 .root_dir = .{
2344 .path = build_root_string,2364 .path = entry.build_root,
2345 .handle = Io.Dir.cwd().openDir(io, build_root_string, .{}) catch |err|2365 .handle = Io.Dir.cwd().openDir(io, entry.build_root, .{}) catch |err|
2346 fatal("failed to open {q}: {t}", .{ build_root_string, err }),2366 fatal("failed to open {q}: {t}", .{ entry.build_root, err }),
2347 },2367 },
2348 };2368 };
23492369
2350 const sub_builder = b.createChild(name, dep_root, pkg_hash, pkg_deps, user_input_options) catch @panic("OOM");2370 const sub_builder = b.createChild(name, dep_root, entry.hash, entry.deps, user_input_options) catch @panic("OOM");
2351 if (build_zig) |bz| {2371 if (entry.run_build) |run_build| {
2352 sub_builder.runPackageScript(bz);2372 run_build(sub_builder);
23532373
2354 if (sub_builder.validateUserInputDidItFail()) {2374 if (sub_builder.validateUserInputDidItFail()) {
2355 std.debug.dumpCurrentStackTrace(.{ .first_address = @returnAddress() });2375 std.debug.dumpCurrentStackTrace(.{ .first_address = @returnAddress() });
...@@ -2360,7 +2380,7 @@ fn dependencyInner(...@@ -2360,7 +2380,7 @@ fn dependencyInner(
2360 dep.* = .{ .builder = sub_builder };2380 dep.* = .{ .builder = sub_builder };
23612381
2362 graph.dependency_cache.putContext(arena, .{2382 graph.dependency_cache.putContext(arena, .{
2363 .build_root_string = build_root_string,2383 .build_root_string = entry.build_root,
2364 .user_input_options = user_input_options,2384 .user_input_options = user_input_options,
2365 }, dep, .{ .allocator = arena }) catch @panic("OOM");2385 }, dep, .{ .allocator = arena }) catch @panic("OOM");
2366 return dep;2386 return dep;