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(...@@ -225,6 +225,7 @@ pub fn fetchAndAddDependencies(
225 build_roots_source: *std.ArrayList(u8),225 build_roots_source: *std.ArrayList(u8),
226 name_prefix: []const u8,226 name_prefix: []const u8,
227 color: main.Color,227 color: main.Color,
228 all_modules: *AllModules,
228) !void {229) !void {
229 const max_bytes = 10 * 1024 * 1024;230 const max_bytes = 10 * 1024 * 1024;
230 const gpa = thread_pool.allocator;231 const gpa = thread_pool.allocator;
...@@ -291,6 +292,7 @@ pub fn fetchAndAddDependencies(...@@ -291,6 +292,7 @@ pub fn fetchAndAddDependencies(
291 report,292 report,
292 build_roots_source,293 build_roots_source,
293 fqn,294 fqn,
295 all_modules,
294 );296 );
295297
296 try pkg.fetchAndAddDependencies(298 try pkg.fetchAndAddDependencies(
...@@ -304,6 +306,7 @@ pub fn fetchAndAddDependencies(...@@ -304,6 +306,7 @@ pub fn fetchAndAddDependencies(
304 build_roots_source,306 build_roots_source,
305 sub_prefix,307 sub_prefix,
306 color,308 color,
309 all_modules,
307 );310 );
308311
309 try add(pkg, gpa, fqn, sub_pkg);312 try add(pkg, gpa, fqn, sub_pkg);
...@@ -402,6 +405,11 @@ const Report = struct {...@@ -402,6 +405,11 @@ const Report = struct {
402 }405 }
403};406};
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
405fn fetchAndUnpack(413fn fetchAndUnpack(
406 thread_pool: *ThreadPool,414 thread_pool: *ThreadPool,
407 http_client: *std.http.Client,415 http_client: *std.http.Client,
...@@ -410,6 +418,7 @@ fn fetchAndUnpack(...@@ -410,6 +418,7 @@ fn fetchAndUnpack(
410 report: Report,418 report: Report,
411 build_roots_source: *std.ArrayList(u8),419 build_roots_source: *std.ArrayList(u8),
412 fqn: []const u8,420 fqn: []const u8,
421 all_modules: *AllModules,
413) !*Package {422) !*Package {
414 const gpa = http_client.allocator;423 const gpa = http_client.allocator;
415 const s = fs.path.sep_str;424 const s = fs.path.sep_str;
...@@ -417,9 +426,24 @@ fn fetchAndUnpack(...@@ -417,9 +426,24 @@ fn fetchAndUnpack(
417 // Check if the expected_hash is already present in the global package426 // Check if the expected_hash is already present in the global package
418 // cache, and thereby avoid both fetching and unpacking.427 // cache, and thereby avoid both fetching and unpacking.
419 if (dep.hash) |h| cached: {428 if (dep.hash) |h| cached: {
420 const hex_multihash_len = 2 * Manifest.multihash_len;
421 const hex_digest = h[0..hex_multihash_len];429 const hex_digest = h[0..hex_multihash_len];
422 const pkg_dir_sub_path = "p" ++ s ++ hex_digest;430 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
423 var pkg_dir = global_cache_directory.handle.openDir(pkg_dir_sub_path, .{}) catch |err| switch (err) {447 var pkg_dir = global_cache_directory.handle.openDir(pkg_dir_sub_path, .{}) catch |err| switch (err) {
424 error.FileNotFound => break :cached,448 error.FileNotFound => break :cached,
425 else => |e| return e,449 else => |e| return e,
...@@ -432,13 +456,6 @@ fn fetchAndUnpack(...@@ -432,13 +456,6 @@ fn fetchAndUnpack(
432 const owned_src_path = try gpa.dupe(u8, build_zig_basename);456 const owned_src_path = try gpa.dupe(u8, build_zig_basename);
433 errdefer gpa.free(owned_src_path);457 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
442 ptr.* = .{459 ptr.* = .{
443 .root_src_directory = .{460 .root_src_directory = .{
444 .path = build_root,461 .path = build_root,
...@@ -448,6 +465,7 @@ fn fetchAndUnpack(...@@ -448,6 +465,7 @@ fn fetchAndUnpack(
448 .root_src_path = owned_src_path,465 .root_src_path = owned_src_path,
449 };466 };
450467
468 gop.value_ptr.* = ptr;
451 return ptr;469 return ptr;
452 }470 }
453471
src/main.zig+4
...@@ -4244,6 +4244,9 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -4244,6 +4244,9 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
4244 var build_roots_source = std.ArrayList(u8).init(gpa);4244 var build_roots_source = std.ArrayList(u8).init(gpa);
4245 defer build_roots_source.deinit();4245 defer build_roots_source.deinit();
42464246
4247 var all_modules: Package.AllModules = .{};
4248 defer all_modules.deinit(gpa);
4249
4247 // Here we borrow main package's table and will replace it with a fresh4250 // Here we borrow main package's table and will replace it with a fresh
4248 // one after this process completes.4251 // one after this process completes.
4249 main_pkg.fetchAndAddDependencies(4252 main_pkg.fetchAndAddDependencies(
...@@ -4257,6 +4260,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -4257,6 +4260,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
4257 &build_roots_source,4260 &build_roots_source,
4258 "",4261 "",
4259 color,4262 color,
4263 &all_modules,
4260 ) catch |err| switch (err) {4264 ) catch |err| switch (err) {
4261 error.PackageFetchFailed => process.exit(1),4265 error.PackageFetchFailed => process.exit(1),
4262 else => |e| return e,4266 else => |e| return e,