diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 7ef504851e..d97a5c5d7a 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -124,6 +124,9 @@ host: NativeTargetInfo, dep_prefix: []const u8 = "", modules: std.StringArrayHashMap(*Module), +/// A map from build root dirs to the corresponding `*Dependency`. This is shared with all child +/// `Build`s. +initialized_deps: *std.StringHashMap(*Dependency), pub const ExecError = error{ ReadFailure, @@ -209,6 +212,9 @@ pub fn create( const env_map = try allocator.create(EnvMap); env_map.* = try process.getEnvMap(allocator); + const initialized_deps = try allocator.create(std.StringHashMap(*Dependency)); + initialized_deps.* = std.StringHashMap(*Dependency).init(allocator); + const self = try allocator.create(Build); self.* = .{ .zig_exe = zig_exe, @@ -261,6 +267,7 @@ pub fn create( .args = null, .host = host, .modules = std.StringArrayHashMap(*Module).init(allocator), + .initialized_deps = initialized_deps, }; try self.top_level_steps.put(allocator, self.install_tls.step.name, &self.install_tls); try self.top_level_steps.put(allocator, self.uninstall_tls.step.name, &self.uninstall_tls); @@ -345,6 +352,7 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Direc .host = parent.host, .dep_prefix = parent.fmt("{s}{s}.", .{ parent.dep_prefix, dep_name }), .modules = std.StringArrayHashMap(*Module).init(allocator), + .initialized_deps = parent.initialized_deps, }; try child.top_level_steps.put(allocator, child.install_tls.step.name, &child.install_tls); try child.top_level_steps.put(allocator, child.uninstall_tls.step.name, &child.uninstall_tls); @@ -1560,6 +1568,11 @@ pub fn dependencyInner( comptime build_zig: type, args: anytype, ) *Dependency { + if (b.initialized_deps.get(build_root_string)) |dep| { + // TODO: check args are the same + return dep; + } + const build_root: std.Build.Cache.Directory = .{ .path = build_root_string, .handle = std.fs.cwd().openDir(build_root_string, .{}) catch |err| { @@ -1578,6 +1591,9 @@ pub fn dependencyInner( const dep = b.allocator.create(Dependency) catch @panic("OOM"); dep.* = .{ .builder = sub_builder }; + + b.initialized_deps.put(build_root_string, dep) catch @panic("OOM"); + return dep; } diff --git a/src/Package.zig b/src/Package.zig index f84f0a8a1b..8a2875667a 100644 --- a/src/Package.zig +++ b/src/Package.zig @@ -216,7 +216,7 @@ pub const build_zig_basename = "build.zig"; pub fn fetchAndAddDependencies( pkg: *Package, - root_pkg: *Package, + deps_pkg: *Package, arena: Allocator, thread_pool: *ThreadPool, http_client: *std.http.Client, @@ -272,7 +272,6 @@ pub fn fetchAndAddDependencies( .error_bundle = error_bundle, }; - var any_error = false; const deps_list = manifest.dependencies.values(); for (manifest.dependencies.keys(), 0..) |name, i| { const dep = deps_list[i]; @@ -292,7 +291,7 @@ pub fn fetchAndAddDependencies( ); try sub_pkg.fetchAndAddDependencies( - root_pkg, + deps_pkg, arena, thread_pool, http_client, @@ -307,14 +306,18 @@ pub fn fetchAndAddDependencies( ); try pkg.add(gpa, name, sub_pkg); - try root_pkg.add(gpa, fqn, sub_pkg); + if (deps_pkg.table.get(dep.hash.?)) |other_sub| { + // This should be the same package (and hence module) since it's the same hash + // TODO: dedup multiple versions of the same package + assert(other_sub == sub_pkg); + } else { + try deps_pkg.add(gpa, dep.hash.?, sub_pkg); + } try dependencies_source.writer().print(" pub const {s} = @import(\"{}\");\n", .{ - std.zig.fmtId(fqn), std.zig.fmtEscapes(fqn), + std.zig.fmtId(fqn), std.zig.fmtEscapes(dep.hash.?), }); } - - if (any_error) return error.InvalidBuildManifestFile; } pub fn createFilePkg(