authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-01 12:11:17-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-01 20:01:23-05:00
logdb8217f9a080f7c645a6448640a9af65f3944818
tree66469871a26ea98bfbb0fcaf8ccb133150292014
parent874d3a17ae0f270b3e3f0ece7839d483d749107d

packages: avoid creating multiple modules with same build.zig

When there is a diamond dependency, reuse a *Module instead of creating a redundant one using the same build.zig file. Otherwise, the compile error "file exists in multiple modules" would occur.

2 files changed, 30 insertions(+), 8 deletions(-)

src/Package.zig+26-8
......@@ -225,6 +225,7 @@ pub fn fetchAndAddDependencies(
225225 build_roots_source: *std.ArrayList(u8),
226226 name_prefix: []const u8,
227227 color: main.Color,
228 all_modules: *AllModules,
228229) !void {
229230 const max_bytes = 10 * 1024 * 1024;
230231 const gpa = thread_pool.allocator;
......@@ -291,6 +292,7 @@ pub fn fetchAndAddDependencies(
291292 report,
292293 build_roots_source,
293294 fqn,
295 all_modules,
294296 );
295297
296298 try pkg.fetchAndAddDependencies(
......@@ -304,6 +306,7 @@ pub fn fetchAndAddDependencies(
304306 build_roots_source,
305307 sub_prefix,
306308 color,
309 all_modules,
307310 );
308311
309312 try add(pkg, gpa, fqn, sub_pkg);
......@@ -402,6 +405,11 @@ const Report = struct {
402405 }
403406};
404407
408const hex_multihash_len = 2 * Manifest.multihash_len;
409const MultiHashHexDigest = [hex_multihash_len]u8;
410/// This is to avoid creating multiple modules for the same build.zig file.
411pub const AllModules = std.AutoHashMapUnmanaged(MultiHashHexDigest, *Package);
412
405413fn fetchAndUnpack(
406414 thread_pool: *ThreadPool,
407415 http_client: *std.http.Client,
......@@ -410,6 +418,7 @@ fn fetchAndUnpack(
410418 report: Report,
411419 build_roots_source: *std.ArrayList(u8),
412420 fqn: []const u8,
421 all_modules: *AllModules,
413422) !*Package {
414423 const gpa = http_client.allocator;
415424 const s = fs.path.sep_str;
......@@ -417,9 +426,24 @@ fn fetchAndUnpack(
417426 // Check if the expected_hash is already present in the global package
418427 // cache, and thereby avoid both fetching and unpacking.
419428 if (dep.hash) |h| cached: {
420 const hex_multihash_len = 2 * Manifest.multihash_len;
421429 const hex_digest = h[0..hex_multihash_len];
422430 const pkg_dir_sub_path = "p" ++ s ++ hex_digest;
431
432 const build_root = try global_cache_directory.join(gpa, &.{pkg_dir_sub_path});
433 errdefer gpa.free(build_root);
434
435 try build_roots_source.writer().print(" pub const {s} = \"{}\";\n", .{
436 std.zig.fmtId(fqn), std.zig.fmtEscapes(build_root),
437 });
438
439 // The compiler has a rule that a file must not be included in multiple modules,
440 // so we must detect if a module has been created for this package and reuse it.
441 const gop = try all_modules.getOrPut(gpa, hex_digest.*);
442 if (gop.found_existing) {
443 gpa.free(build_root);
444 return gop.value_ptr.*;
445 }
446
423447 var pkg_dir = global_cache_directory.handle.openDir(pkg_dir_sub_path, .{}) catch |err| switch (err) {
424448 error.FileNotFound => break :cached,
425449 else => |e| return e,
......@@ -432,13 +456,6 @@ fn fetchAndUnpack(
432456 const owned_src_path = try gpa.dupe(u8, build_zig_basename);
433457 errdefer gpa.free(owned_src_path);
434458
435 const build_root = try global_cache_directory.join(gpa, &.{pkg_dir_sub_path});
436 errdefer gpa.free(build_root);
437
438 try build_roots_source.writer().print(" pub const {s} = \"{}\";\n", .{
439 std.zig.fmtId(fqn), std.zig.fmtEscapes(build_root),
440 });
441
442459 ptr.* = .{
443460 .root_src_directory = .{
444461 .path = build_root,
......@@ -448,6 +465,7 @@ fn fetchAndUnpack(
448465 .root_src_path = owned_src_path,
449466 };
450467
468 gop.value_ptr.* = ptr;
451469 return ptr;
452470 }
453471
src/main.zig+4
......@@ -4244,6 +4244,9 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
42444244 var build_roots_source = std.ArrayList(u8).init(gpa);
42454245 defer build_roots_source.deinit();
42464246
4247 var all_modules: Package.AllModules = .{};
4248 defer all_modules.deinit(gpa);
4249
42474250 // Here we borrow main package's table and will replace it with a fresh
42484251 // one after this process completes.
42494252 main_pkg.fetchAndAddDependencies(
......@@ -4257,6 +4260,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
42574260 &build_roots_source,
42584261 "",
42594262 color,
4263 &all_modules,
42604264 ) catch |err| switch (err) {
42614265 error.PackageFetchFailed => process.exit(1),
42624266 else => |e| return e,