authorgravatar for inkryption07@gmail.comInKryption <inkryption07@gmail.com> 2024-10-05 00:58:48+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-06 12:39:35-07:00
log3284d1ffb125c460ec8c19323cb53a7b0cea5e5e
tree1ed2a4d64fa416e95349df47575748b4059dda44
parent148b5b4c7806a694084f1e6f9514b0333cb75c6a

Build: Add `option(LazyPath, ...)` support

Also adds support for `[]const LazyPath` in a similar vein, and refactors a few other bits of code.

1 files changed, 166 insertions(+), 29 deletions(-)

lib/std/Build.zig+166-29
......@@ -217,6 +217,8 @@ const UserValue = union(enum) {
217217 scalar: []const u8,
218218 list: ArrayList([]const u8),
219219 map: StringHashMap(*const UserValue),
220 lazy_path: LazyPath,
221 lazy_path_list: ArrayList(LazyPath),
220222};
221223
222224const TypeId = enum {
......@@ -228,6 +230,8 @@ const TypeId = enum {
228230 string,
229231 list,
230232 build_id,
233 lazy_path,
234 lazy_path_list,
231235};
232236
233237const TopLevelStep = struct {
......@@ -433,6 +437,22 @@ fn userInputOptionsFromArgs(allocator: Allocator, args: anytype) UserInputOption
433437 .used = false,
434438 }) catch @panic("OOM");
435439 },
440 LazyPath => {
441 user_input_options.put(field.name, .{
442 .name = field.name,
443 .value = .{ .lazy_path = v.dupeInner(allocator) },
444 .used = false,
445 }) catch @panic("OOM");
446 },
447 []const LazyPath => {
448 var list = ArrayList(LazyPath).initCapacity(allocator, v.len) catch @panic("OOM");
449 for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(allocator));
450 user_input_options.put(field.name, .{
451 .name = field.name,
452 .value = .{ .lazy_path_list = list },
453 .used = false,
454 }) catch @panic("OOM");
455 },
436456 []const u8 => {
437457 user_input_options.put(field.name, .{
438458 .name = field.name,
......@@ -492,6 +512,8 @@ const OrderedUserValue = union(enum) {
492512 scalar: []const u8,
493513 list: ArrayList([]const u8),
494514 map: ArrayList(Pair),
515 lazy_path: LazyPath,
516 lazy_path_list: ArrayList(LazyPath),
495517
496518 const Pair = struct {
497519 name: []const u8,
......@@ -502,6 +524,7 @@ const OrderedUserValue = union(enum) {
502524 };
503525
504526 fn hash(val: OrderedUserValue, hasher: *std.hash.Wyhash) void {
527 hasher.update(&std.mem.toBytes(std.meta.activeTag(val)));
505528 switch (val) {
506529 .flag => {},
507530 .scalar => |scalar| hasher.update(scalar),
......@@ -512,6 +535,31 @@ const OrderedUserValue = union(enum) {
512535 hasher.update(map_entry.name);
513536 map_entry.value.hash(hasher);
514537 },
538 .lazy_path => |lp| hashLazyPath(lp, hasher),
539 .lazy_path_list => |lp_list| for (lp_list.items) |lp| {
540 hashLazyPath(lp, hasher);
541 },
542 }
543 }
544
545 fn hashLazyPath(lp: LazyPath, hasher: *std.hash.Wyhash) void {
546 switch (lp) {
547 .src_path => |sp| {
548 hasher.update(sp.owner.pkg_hash);
549 hasher.update(sp.sub_path);
550 },
551 .generated => |gen| {
552 hasher.update(gen.file.step.owner.pkg_hash);
553 hasher.update(std.mem.asBytes(&gen.up));
554 hasher.update(gen.sub_path);
555 },
556 .cwd_relative => |rel_path| {
557 hasher.update(rel_path);
558 },
559 .dependency => |dep| {
560 hasher.update(dep.dependency.builder.pkg_hash);
561 hasher.update(dep.sub_path);
562 },
515563 }
516564 }
517565
......@@ -535,6 +583,8 @@ const OrderedUserValue = union(enum) {
535583 .scalar => |scalar| .{ .scalar = scalar },
536584 .list => |list| .{ .list = list },
537585 .map => |map| .{ .map = OrderedUserValue.mapFromUnordered(allocator, map) },
586 .lazy_path => |lp| .{ .lazy_path = lp },
587 .lazy_path_list => |list| .{ .lazy_path_list = list },
538588 };
539589 }
540590};
......@@ -1023,7 +1073,11 @@ pub fn addConfigHeader(
10231073
10241074/// Allocator.dupe without the need to handle out of memory.
10251075pub fn dupe(b: *Build, bytes: []const u8) []u8 {
1026 return b.allocator.dupe(u8, bytes) catch @panic("OOM");
1076 return dupeInner(b.allocator, bytes);
1077}
1078
1079pub fn dupeInner(allocator: std.mem.Allocator, bytes: []const u8) []u8 {
1080 return allocator.dupe(u8, bytes) catch @panic("OOM");
10271081}
10281082
10291083/// Duplicates an array of strings without the need to handle out of memory.
......@@ -1035,7 +1089,11 @@ pub fn dupeStrings(b: *Build, strings: []const []const u8) [][]u8 {
10351089
10361090/// Duplicates a path and converts all slashes to the OS's canonical path separator.
10371091pub fn dupePath(b: *Build, bytes: []const u8) []u8 {
1038 const the_copy = b.dupe(bytes);
1092 return dupePathInner(b.allocator, bytes);
1093}
1094
1095fn dupePathInner(allocator: std.mem.Allocator, bytes: []const u8) []u8 {
1096 const the_copy = dupeInner(allocator, bytes);
10391097 for (the_copy) |*byte| {
10401098 switch (byte.*) {
10411099 '/', '\\' => byte.* = fs.path.sep,
......@@ -1149,7 +1207,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
11491207 return null;
11501208 }
11511209 },
1152 .list, .map => {
1210 .list, .map, .lazy_path, .lazy_path_list => {
11531211 log.err("Expected -D{s} to be a boolean, but received a {s}.", .{
11541212 name, @tagName(option_ptr.value),
11551213 });
......@@ -1158,7 +1216,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
11581216 },
11591217 },
11601218 .int => switch (option_ptr.value) {
1161 .flag, .list, .map => {
1219 .flag, .list, .map, .lazy_path, .lazy_path_list => {
11621220 log.err("Expected -D{s} to be an integer, but received a {s}.", .{
11631221 name, @tagName(option_ptr.value),
11641222 });
......@@ -1182,7 +1240,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
11821240 },
11831241 },
11841242 .float => switch (option_ptr.value) {
1185 .flag, .map, .list => {
1243 .flag, .map, .list, .lazy_path, .lazy_path_list => {
11861244 log.err("Expected -D{s} to be a float, but received a {s}.", .{
11871245 name, @tagName(option_ptr.value),
11881246 });
......@@ -1199,7 +1257,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
11991257 },
12001258 },
12011259 .@"enum" => switch (option_ptr.value) {
1202 .flag, .map, .list => {
1260 .flag, .map, .list, .lazy_path, .lazy_path_list => {
12031261 log.err("Expected -D{s} to be an enum, but received a {s}.", .{
12041262 name, @tagName(option_ptr.value),
12051263 });
......@@ -1217,7 +1275,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
12171275 },
12181276 },
12191277 .string => switch (option_ptr.value) {
1220 .flag, .list, .map => {
1278 .flag, .list, .map, .lazy_path, .lazy_path_list => {
12211279 log.err("Expected -D{s} to be a string, but received a {s}.", .{
12221280 name, @tagName(option_ptr.value),
12231281 });
......@@ -1227,7 +1285,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
12271285 .scalar => |s| return s,
12281286 },
12291287 .build_id => switch (option_ptr.value) {
1230 .flag, .map, .list => {
1288 .flag, .map, .list, .lazy_path, .lazy_path_list => {
12311289 log.err("Expected -D{s} to be an enum, but received a {s}.", .{
12321290 name, @tagName(option_ptr.value),
12331291 });
......@@ -1245,7 +1303,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
12451303 },
12461304 },
12471305 .list => switch (option_ptr.value) {
1248 .flag, .map => {
1306 .flag, .map, .lazy_path, .lazy_path_list => {
12491307 log.err("Expected -D{s} to be a list, but received a {s}.", .{
12501308 name, @tagName(option_ptr.value),
12511309 });
......@@ -1258,7 +1316,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
12581316 .list => |lst| return lst.items,
12591317 },
12601318 .enum_list => switch (option_ptr.value) {
1261 .flag, .map => {
1319 .flag, .map, .lazy_path, .lazy_path_list => {
12621320 log.err("Expected -D{s} to be a list, but received a {s}.", .{
12631321 name, @tagName(option_ptr.value),
12641322 });
......@@ -1276,19 +1334,48 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
12761334 },
12771335 .list => |lst| {
12781336 const Child = @typeInfo(T).pointer.child;
1279 var new_list = b.allocator.alloc(Child, lst.items.len) catch @panic("OOM");
1280 for (lst.items, 0..) |str, i| {
1281 const value = std.meta.stringToEnum(Child, str) orelse {
1337 const new_list = b.allocator.alloc(Child, lst.items.len) catch @panic("OOM");
1338 for (new_list, lst.items) |*new_item, str| {
1339 new_item.* = std.meta.stringToEnum(Child, str) orelse {
12821340 log.err("Expected -D{s} to be of type {s}.", .{ name, @typeName(Child) });
12831341 b.markInvalidUserInput();
12841342 b.allocator.free(new_list);
12851343 return null;
12861344 };
1287 new_list[i] = value;
12881345 }
12891346 return new_list;
12901347 },
12911348 },
1349 .lazy_path => switch (option_ptr.value) {
1350 .scalar => |s| return .{ .cwd_relative = s },
1351 .lazy_path => |lp| return lp,
1352 .flag, .map, .list, .lazy_path_list => {
1353 log.err("Expected -D{s} to be a path, but received a {s}.", .{
1354 name, @tagName(option_ptr.value),
1355 });
1356 b.markInvalidUserInput();
1357 return null;
1358 },
1359 },
1360 .lazy_path_list => switch (option_ptr.value) {
1361 .scalar => |s| return b.allocator.dupe(LazyPath, &[_]LazyPath{.{ .cwd_relative = s }}) catch @panic("OOM"),
1362 .lazy_path => |lp| return b.allocator.dupe(LazyPath, &[_]LazyPath{lp}) catch @panic("OOM"),
1363 .list => |lst| {
1364 const new_list = b.allocator.alloc(LazyPath, lst.items.len) catch @panic("OOM");
1365 for (new_list, lst.items) |*new_item, str| {
1366 new_item.* = .{ .cwd_relative = str };
1367 }
1368 return new_list;
1369 },
1370 .lazy_path_list => |lp_list| return lp_list.items,
1371 .flag, .map => {
1372 log.err("Expected -D{s} to be a path, but received a {s}.", .{
1373 name, @tagName(option_ptr.value),
1374 });
1375 b.markInvalidUserInput();
1376 return null;
1377 },
1378 },
12921379 }
12931380}
12941381
......@@ -1508,6 +1595,10 @@ pub fn addUserInputOption(b: *Build, name_raw: []const u8, value_raw: []const u8
15081595 log.warn("TODO maps as command line arguments is not implemented yet.", .{});
15091596 return true;
15101597 },
1598 .lazy_path, .lazy_path_list => {
1599 log.warn("the lazy path value type isn't added from the CLI, but somehow '{s}' is a .{}", .{ name, std.zig.fmtId(@tagName(gop.value_ptr.value)) });
1600 return true;
1601 },
15111602 }
15121603 return false;
15131604}
......@@ -1530,10 +1621,15 @@ pub fn addUserInputFlag(b: *Build, name_raw: []const u8) !bool {
15301621 log.err("Flag '-D{s}' conflicts with option '-D{s}={s}'.", .{ name, name, s });
15311622 return true;
15321623 },
1533 .list, .map => {
1624 .list, .map, .lazy_path_list => {
15341625 log.err("Flag '-D{s}' conflicts with multiple options of the same name.", .{name});
15351626 return true;
15361627 },
1628 .lazy_path => |lp| {
1629 log.err("Flag '-D{s}' conflicts with option '-D{s}={s}'.", .{ name, name, lp.getDisplayName() });
1630 return true;
1631 },
1632
15371633 .flag => {},
15381634 }
15391635 return false;
......@@ -1542,6 +1638,7 @@ pub fn addUserInputFlag(b: *Build, name_raw: []const u8) !bool {
15421638fn typeToEnum(comptime T: type) TypeId {
15431639 return switch (T) {
15441640 std.zig.BuildId => .build_id,
1641 LazyPath => .lazy_path,
15451642 else => return switch (@typeInfo(T)) {
15461643 .int => .int,
15471644 .float => .float,
......@@ -1550,6 +1647,7 @@ fn typeToEnum(comptime T: type) TypeId {
15501647 .pointer => |pointer| switch (pointer.child) {
15511648 u8 => .string,
15521649 []const u8 => .list,
1650 LazyPath => .lazy_path_list,
15531651 else => switch (@typeInfo(pointer.child)) {
15541652 .@"enum" => .enum_list,
15551653 else => @compileError("Unsupported type: " ++ @typeName(T)),
......@@ -2065,22 +2163,17 @@ pub fn dependencyFromBuildZig(
20652163}
20662164
20672165fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool {
2166 if (std.meta.activeTag(lhs) != rhs) return false;
20682167 switch (lhs) {
20692168 .flag => {},
20702169 .scalar => |lhs_scalar| {
2071 const rhs_scalar = switch (rhs) {
2072 .scalar => |scalar| scalar,
2073 else => return false,
2074 };
2170 const rhs_scalar = rhs.scalar;
20752171
20762172 if (!std.mem.eql(u8, lhs_scalar, rhs_scalar))
20772173 return false;
20782174 },
20792175 .list => |lhs_list| {
2080 const rhs_list = switch (rhs) {
2081 .list => |list| list,
2082 else => return false,
2083 };
2176 const rhs_list = rhs.list;
20842177
20852178 if (lhs_list.items.len != rhs_list.items.len)
20862179 return false;
......@@ -2091,10 +2184,7 @@ fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool {
20912184 }
20922185 },
20932186 .map => |lhs_map| {
2094 const rhs_map = switch (rhs) {
2095 .map => |map| map,
2096 else => return false,
2097 };
2187 const rhs_map = rhs.map;
20982188
20992189 if (lhs_map.count() != rhs_map.count())
21002190 return false;
......@@ -2106,11 +2196,54 @@ fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool {
21062196 return false;
21072197 }
21082198 },
2199 .lazy_path => |lhs_lp| {
2200 const rhs_lp = rhs.lazy_path;
2201 return userLazyPathsAreTheSame(lhs_lp, rhs_lp);
2202 },
2203 .lazy_path_list => |lhs_lp_list| {
2204 const rhs_lp_list = rhs.lazy_path_list;
2205 if (lhs_lp_list.items.len != rhs_lp_list.items.len) return false;
2206 for (lhs_lp_list.items, rhs_lp_list.items) |lhs_lp, rhs_lp| {
2207 if (!userLazyPathsAreTheSame(lhs_lp, rhs_lp)) return false;
2208 }
2209 return true;
2210 },
21092211 }
21102212
21112213 return true;
21122214}
21132215
2216fn userLazyPathsAreTheSame(lhs_lp: LazyPath, rhs_lp: LazyPath) bool {
2217 if (std.meta.activeTag(lhs_lp) != rhs_lp) return false;
2218 switch (lhs_lp) {
2219 .src_path => |lhs_sp| {
2220 const rhs_sp = rhs_lp.src_path;
2221
2222 if (lhs_sp.owner != rhs_sp.owner) return false;
2223 if (std.mem.eql(u8, lhs_sp.sub_path, rhs_sp.sub_path)) return false;
2224 },
2225 .generated => |lhs_gen| {
2226 const rhs_gen = rhs_lp.generated;
2227
2228 if (lhs_gen.file != rhs_gen.file) return false;
2229 if (lhs_gen.up != rhs_gen.up) return false;
2230 if (std.mem.eql(u8, lhs_gen.sub_path, rhs_gen.sub_path)) return false;
2231 },
2232 .cwd_relative => |lhs_rel_path| {
2233 const rhs_rel_path = rhs_lp.cwd_relative;
2234
2235 if (!std.mem.eql(u8, lhs_rel_path, rhs_rel_path)) return false;
2236 },
2237 .dependency => |lhs_dep| {
2238 const rhs_dep = rhs_lp.dependency;
2239
2240 if (lhs_dep.dependency != rhs_dep.dependency) return false;
2241 if (!std.mem.eql(u8, lhs_dep.sub_path, rhs_dep.sub_path)) return false;
2242 },
2243 }
2244 return true;
2245}
2246
21142247fn dependencyInner(
21152248 b: *Build,
21162249 name: []const u8,
......@@ -2435,16 +2568,20 @@ pub const LazyPath = union(enum) {
24352568 /// The `b` parameter is only used for its allocator. All *Build instances
24362569 /// share the same allocator.
24372570 pub fn dupe(lazy_path: LazyPath, b: *Build) LazyPath {
2571 return lazy_path.dupeInner(b.allocator);
2572 }
2573
2574 fn dupeInner(lazy_path: LazyPath, allocator: std.mem.Allocator) LazyPath {
24382575 return switch (lazy_path) {
24392576 .src_path => |sp| .{ .src_path = .{
24402577 .owner = sp.owner,
24412578 .sub_path = sp.owner.dupePath(sp.sub_path),
24422579 } },
2443 .cwd_relative => |p| .{ .cwd_relative = b.dupePath(p) },
2580 .cwd_relative => |p| .{ .cwd_relative = dupePathInner(allocator, p) },
24442581 .generated => |gen| .{ .generated = .{
24452582 .file = gen.file,
24462583 .up = gen.up,
2447 .sub_path = b.dupePath(gen.sub_path),
2584 .sub_path = dupePathInner(allocator, gen.sub_path),
24482585 } },
24492586 .dependency => |dep| .{ .dependency = dep },
24502587 };