mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-10-28 10:45:48 +08:00
implement package instances
a way to to specifically allow a particular dependency to create multiple instances of packages by supplying unique sets of options.
This commit is contained in:
1 parent
5179c695c0
commit
0aec429522
2 files changed
+62
-17
No files matched your search
@@ -208,6 +208,10 @@ pub const JobQueue = struct {
|
||||
/// Identifies paths that override all packages in the tree with matching
|
||||
/// project ids.
|
||||
fork_set: ForkSet = .empty,
|
||||
/// Set of package paths into the dependency tree that are exempt from the rule that prevents
|
||||
/// packages from being instantiated with multiple different sets of options. Package names in
|
||||
/// the path are separated by '.'.
|
||||
instances: InstanceSet = .empty,
|
||||
|
||||
pub const Mode = enum {
|
||||
/// Non-lazy dependencies are always fetched.
|
||||
@@ -220,6 +224,8 @@ pub const JobQueue = struct {
|
||||
pub const UnlazySet = std.array_hash_map.Auto(Package.Hash, void);
|
||||
pub const ForkSet = std.array_hash_map.Custom(Fork, void, Fork.Context, false);
|
||||
|
||||
pub const InstanceSet = std.array_hash_map.String(void);
|
||||
|
||||
pub const Fork = struct {
|
||||
path: Path,
|
||||
manifest_ast: std.zig.Ast,
|
||||
@@ -257,6 +263,7 @@ pub const JobQueue = struct {
|
||||
if (jq.all_fetches.items.len == 0) return;
|
||||
const gpa = jq.all_fetches.items[0].arena.child_allocator;
|
||||
jq.table.deinit(gpa);
|
||||
jq.instances.deinit(gpa);
|
||||
// These must be deinitialized in reverse order because subsequent
|
||||
// `Fetch` instances are allocated in prior ones' arenas.
|
||||
// Sorry, I know it's a bit weird, but it slightly simplifies the
|
||||
@@ -405,6 +412,10 @@ pub const JobQueue = struct {
|
||||
.{ std.zig.fmtString(name), std.zig.fmtString(h.toSlice()) },
|
||||
);
|
||||
}
|
||||
try w.writeAll("};\n\npub const instances: []const []const u8 = &.{\n");
|
||||
for (jq.instances.keys()) |pkg_path| {
|
||||
try w.print(" {q},\n", .{pkg_path});
|
||||
}
|
||||
try w.writeAll("};\n");
|
||||
}
|
||||
|
||||
@@ -413,6 +424,7 @@ pub const JobQueue = struct {
|
||||
\\pub const Dep = struct { []const u8, []const u8 };
|
||||
\\pub const packages = struct {};
|
||||
\\pub const root_deps: []const Dep = &.{};
|
||||
\\pub const instances: []const []const u8 = &.{};
|
||||
\\
|
||||
);
|
||||
}
|
||||
@@ -916,7 +928,7 @@ pub fn computedPackageHash(f: *const Fetch) Package.Hash {
|
||||
if (f.parentDep()) |dep| {
|
||||
if (dep.version_tok != .none) {
|
||||
const v = std.mem.print(&version_buffer, "{f}", .{dep.version}) catch unreachable;
|
||||
return .init(f.computed_hash.digest, f.name, v, no_fingerprint, saturated_size);
|
||||
return .init(f.computed_hash.digest, f.depName(), v, no_fingerprint, saturated_size);
|
||||
}
|
||||
}
|
||||
return .init(f.computed_hash.digest, "N", "V", no_fingerprint, saturated_size);
|
||||
@@ -1029,6 +1041,17 @@ fn queueJobsForDeps(f: *Fetch) RunError!void {
|
||||
|
||||
for (dep_names, deps, 0..) |dep_name, dep, dep_index_usize| {
|
||||
const dep_index: u32 = @intCast(dep_index_usize);
|
||||
const full_dep_name = if (f.name.len == 0)
|
||||
dep_name
|
||||
else
|
||||
try std.mem.join(parent_arena, ".", &.{ f.name, dep_name });
|
||||
|
||||
try f.job_queue.instances.ensureUnusedCapacity(gpa, dep.instances.count());
|
||||
for (dep.instances.keys()) |pkg_path| {
|
||||
const full_pkg_path = try std.mem.join(parent_arena, ".", &.{ full_dep_name, pkg_path });
|
||||
f.job_queue.instances.putAssumeCapacity(full_pkg_path, {});
|
||||
}
|
||||
|
||||
var unversioned = dep.unversioned;
|
||||
const new_fetch = &new_fetches[new_fetch_index];
|
||||
const location: Location = switch (dep.location) {
|
||||
@@ -1073,7 +1096,7 @@ fn queueJobsForDeps(f: *Fetch) RunError!void {
|
||||
break :l .{ .relative_path = new_root };
|
||||
},
|
||||
};
|
||||
prog_names[new_fetch_index] = dep_name;
|
||||
prog_names[new_fetch_index] = full_dep_name;
|
||||
new_fetch_index += 1;
|
||||
f.job_queue.all_fetches.appendAssumeCapacity(new_fetch);
|
||||
new_fetch.* = .{
|
||||
@@ -1084,7 +1107,7 @@ fn queueJobsForDeps(f: *Fetch) RunError!void {
|
||||
.selected_projects = .empty,
|
||||
.arena = std.heap.ArenaAllocator.init(gpa),
|
||||
.location = location,
|
||||
.name = dep_name,
|
||||
.name = full_dep_name,
|
||||
.lazy_status = switch (f.job_queue.mode) {
|
||||
.needed => if (dep.lazy) .available else .eager,
|
||||
.all => .eager,
|
||||
@@ -2179,6 +2202,11 @@ fn hashTok(f: *const Fetch) ?std.zig.Ast.TokenIndex {
|
||||
return dep.hash_tok.unwrap();
|
||||
}
|
||||
|
||||
fn depName(f: *const Fetch) []const u8 {
|
||||
const start = std.mem.findLastScalar(u8, f.name, '.') orelse 0;
|
||||
return f.name[start..];
|
||||
}
|
||||
|
||||
// Detects executable header: ELF or Macho-O magic header or shebang line.
|
||||
const FileHeader = struct {
|
||||
header: [4]u8 = undefined,
|
||||
|
||||
+31
-14
@@ -472,7 +472,7 @@ pub fn create(
|
||||
|
||||
fn createChild(
|
||||
parent: *Build,
|
||||
dep_name: []const u8,
|
||||
dep_prefix: []const u8,
|
||||
root: Cache.Path,
|
||||
pkg_hash: []const u8,
|
||||
pkg_deps: AvailableDeps,
|
||||
@@ -505,7 +505,7 @@ fn createChild(
|
||||
.default_step = undefined,
|
||||
.top_level_steps = .{},
|
||||
.debug_log_scopes = parent.debug_log_scopes,
|
||||
.dep_prefix = parent.fmt("{s}{s}.", .{ parent.dep_prefix, dep_name }),
|
||||
.dep_prefix = dep_prefix,
|
||||
.modules = .empty,
|
||||
.named_writefiles = .empty,
|
||||
.named_lazy_paths = .empty,
|
||||
@@ -2123,15 +2123,15 @@ pub const PackageEntry = struct {
|
||||
};
|
||||
|
||||
/// Build system implementation detail.
|
||||
pub const package_map: std.StaticStringMap(PackageEntry) = blk: {
|
||||
pub const package_map: std.StaticStringMap(PackageEntry) = map: {
|
||||
const deps = @import("root").dependencies;
|
||||
const decl_names = @typeInfo(deps.packages).@"struct".decl_names;
|
||||
var kvs: [decl_names.len]struct { []const u8, PackageEntry } = undefined;
|
||||
@setEvalBranchQuota(decl_names.len + 100);
|
||||
for (decl_names, 0..) |decl_name, i| {
|
||||
@setEvalBranchQuota(decl_names.len + 1);
|
||||
for (decl_names, &kvs) |decl_name, *kv| {
|
||||
const pkg = @field(deps.packages, decl_name);
|
||||
const available = !@hasDecl(pkg, "available") or pkg.available;
|
||||
kvs[i] = .{ decl_name, .{
|
||||
kv.* = .{ decl_name, .{
|
||||
.hash = decl_name,
|
||||
.available = available,
|
||||
.build_root = if (available) pkg.build_root else "",
|
||||
@@ -2146,7 +2146,16 @@ pub const package_map: std.StaticStringMap(PackageEntry) = blk: {
|
||||
} };
|
||||
}
|
||||
const frozen = kvs;
|
||||
break :blk .initComptime(&frozen);
|
||||
break :map .initComptime(&frozen);
|
||||
};
|
||||
|
||||
pub const instance_map: std.StaticStringMap(void) = map: {
|
||||
const instances = @import("root").dependencies.instances;
|
||||
var kvs: [instances.len]struct { []const u8 } = undefined;
|
||||
@setEvalBranchQuota(instances.len + 1);
|
||||
for (&kvs, instances) |*kv, pkg_path| kv.* = .{pkg_path};
|
||||
const frozen = kvs;
|
||||
break :map .initComptime(&frozen);
|
||||
};
|
||||
|
||||
/// Declares that the current configuration does in fact require a potentially
|
||||
@@ -2259,13 +2268,21 @@ fn dependencyResolved(
|
||||
.unversioned = entry.unversioned,
|
||||
.options = package_options,
|
||||
};
|
||||
const child_dep_prefix = std.fmt.allocPrint(arena, "{s}{s}.", .{ b.dep_prefix, name }) catch @panic("OOM");
|
||||
|
||||
const dedup = if (graph.deduplicated_dependencies.getEntry(package_instance)) |kv| dedup: {
|
||||
const dep_dependency = kv.value_ptr.*;
|
||||
const dep_pkg_hash = kv.key_ptr.pkg_hash;
|
||||
const dep_options = kv.key_ptr.options;
|
||||
const old_dep_prefix = dep_dependency.builder.dep_prefix[0 .. dep_dependency.builder.dep_prefix.len - 1];
|
||||
const new_dep_prefix = child_dep_prefix[0 .. child_dep_prefix.len - 1];
|
||||
|
||||
if (kv.key_ptr.unversioned or entry.unversioned) {
|
||||
log.debug("checking {q} and {q}", .{ old_dep_prefix, new_dep_prefix });
|
||||
|
||||
if (kv.key_ptr.unversioned or entry.unversioned or
|
||||
instance_map.has(old_dep_prefix) or
|
||||
instance_map.has(new_dep_prefix))
|
||||
{
|
||||
// Opting out of version conflict resolution. Use the other map instead. We only
|
||||
// bother to populate the other map if this one doesn't contain it however.
|
||||
if (mem.eql(u8, dep_pkg_hash, entry.hash) and PackageOptions.eql(dep_options, package_options)) {
|
||||
@@ -2277,16 +2294,15 @@ fn dependencyResolved(
|
||||
break :dedup false;
|
||||
}
|
||||
|
||||
const dep_prefix = dep_dependency.builder.dep_prefix[0 .. dep_dependency.builder.dep_prefix.len - 1];
|
||||
if (!mem.eql(u8, dep_pkg_hash, entry.hash)) {
|
||||
log.err("package version conflict: {s} ({s})", .{ dep_pkg_hash, dep_prefix });
|
||||
log.err("package version conflict: {s} ({s}{s})", .{ entry.hash, b.dep_prefix, name });
|
||||
log.err("package version conflict: {s} ({s})", .{ dep_pkg_hash, old_dep_prefix });
|
||||
log.err("package version conflict: {s} ({s})", .{ entry.hash, new_dep_prefix });
|
||||
std.debug.dumpCurrentStackTrace(.{ .first_address = first_return_address });
|
||||
process.exit(1);
|
||||
}
|
||||
if (!PackageOptions.eql(dep_options, package_options)) {
|
||||
log.err("package {s} ({s} vs {s}{s}) reinstantiated with non-matching options", .{
|
||||
dep_pkg_hash, dep_prefix, b.dep_prefix, name,
|
||||
log.err("package {s} ({s} vs {s}) reinstantiated with non-matching options", .{
|
||||
dep_pkg_hash, old_dep_prefix, new_dep_prefix,
|
||||
});
|
||||
PackageOptions.logDifferences(dep_options, package_options);
|
||||
std.debug.dumpCurrentStackTrace(.{ .first_address = first_return_address });
|
||||
@@ -2303,7 +2319,8 @@ fn dependencyResolved(
|
||||
},
|
||||
};
|
||||
|
||||
const sub_builder = b.createChild(name, dep_root, entry.hash, entry.deps, package_options.*) catch @panic("OOM");
|
||||
const sub_builder = b.createChild(child_dep_prefix, dep_root, entry.hash, entry.deps, package_options.*) catch
|
||||
@panic("OOM");
|
||||
if (entry.run_build) |run_build| {
|
||||
run_build(sub_builder);
|
||||
|
||||
|
||||
Reference in new issue
Block a user