| ... | @@ -9,7 +9,6 @@ const mem = std.mem; | ... | @@ -9,7 +9,6 @@ const mem = std.mem; |
| 9 | const panic = std.debug.panic; | 9 | const panic = std.debug.panic; |
| 10 | const assert = std.debug.assert; | 10 | const assert = std.debug.assert; |
| 11 | const log = std.log; | 11 | const log = std.log; |
| 12 | const StringHashMap = std.StringHashMap; | | |
| 13 | const Allocator = std.mem.Allocator; | 12 | const Allocator = std.mem.Allocator; |
| 14 | const Target = std.Target; | 13 | const Target = std.Target; |
| 15 | const process = std.process; | 14 | const process = std.process; |
| ... | @@ -32,9 +31,6 @@ graph: *Graph, | ... | @@ -32,9 +31,6 @@ graph: *Graph, |
| 32 | install_tls: Step.TopLevel, | 31 | install_tls: Step.TopLevel, |
| 33 | uninstall_tls: Step.TopLevel, | 32 | uninstall_tls: Step.TopLevel, |
| 34 | allocator: Allocator, | 33 | allocator: Allocator, |
| 35 | user_input_options: UserInputOptionsMap, | | |
| 36 | available_options_map: std.array_hash_map.String(AvailableOption) = .empty, | | |
| 37 | invalid_user_input: bool, | | |
| 38 | default_step: *Step, | 34 | default_step: *Step, |
| 39 | top_level_steps: std.array_hash_map.String(*Step.TopLevel), | 35 | top_level_steps: std.array_hash_map.String(*Step.TopLevel), |
| 40 | /// Path to the directory containing build.zig. | 36 | /// Path to the directory containing build.zig. |
| ... | @@ -45,6 +41,10 @@ debug_log_scopes: []const []const u8 = &.{}, | ... | @@ -45,6 +41,10 @@ debug_log_scopes: []const []const u8 = &.{}, |
| 45 | /// Set to 0 to disable stack collection. | 41 | /// Set to 0 to disable stack collection. |
| 46 | debug_stack_frames_count: u8 = 8, | 42 | debug_stack_frames_count: u8 = 8, |
| 47 | | 43 | |
| | 44 | user_input_options: PackageOptions.Map, |
| | 45 | available_options_map: std.array_hash_map.String(AvailableOption) = .empty, |
| | 46 | invalid_user_input: bool, |
| | 47 | |
| 48 | dep_prefix: []const u8 = "", | 48 | dep_prefix: []const u8 = "", |
| 49 | | 49 | |
| 50 | modules: std.array_hash_map.String(*Module), | 50 | modules: std.array_hash_map.String(*Module), |
| ... | @@ -82,7 +82,7 @@ pub const Graph = struct { | ... | @@ -82,7 +82,7 @@ pub const Graph = struct { |
| 82 | needed_lazy_dependencies: std.array_hash_map.String(void) = .empty, | 82 | needed_lazy_dependencies: std.array_hash_map.String(void) = .empty, |
| 83 | /// Information about the native target. Computed before build() is invoked. | 83 | /// Information about the native target. Computed before build() is invoked. |
| 84 | host: ResolvedTarget, | 84 | host: ResolvedTarget, |
| 85 | dependency_cache: InitializedDepMap = .empty, | 85 | dependency_cache: PackageInstanceMap = .empty, |
| 86 | allow_so_scripts: ?bool = null, | 86 | allow_so_scripts: ?bool = null, |
| 87 | time_report: bool = false, | 87 | time_report: bool = false, |
| 88 | verbose: bool = false, | 88 | verbose: bool = false, |
| ... | @@ -238,65 +238,123 @@ pub const SystemLibraryMode = enum { | ... | @@ -238,65 +238,123 @@ pub const SystemLibraryMode = enum { |
| 238 | declared_enabled, | 238 | declared_enabled, |
| 239 | }; | 239 | }; |
| 240 | | 240 | |
| 241 | const InitializedDepMap = std.HashMapUnmanaged(InitializedDepKey, *Dependency, InitializedDepContext, std.hash_map.default_max_load_percentage); | 241 | const PackageInstanceMap = std.array_hash_map.Custom(PackageInstanceKey, *Dependency, struct { |
| 242 | const InitializedDepKey = struct { | 242 | pub fn hash(_: @This(), k: PackageInstanceKey) u32 { |
| 243 | build_root_string: []const u8, | | |
| 244 | user_input_options: UserInputOptionsMap, | | |
| 245 | }; | | |
| 246 | | | |
| 247 | const InitializedDepContext = struct { | | |
| 248 | allocator: Allocator, | | |
| 249 | | | |
| 250 | pub fn hash(ctx: @This(), k: InitializedDepKey) u64 { | | |
| 251 | var hasher = std.hash.Wyhash.init(0); | 243 | var hasher = std.hash.Wyhash.init(0); |
| 252 | hasher.update(k.build_root_string); | 244 | hasher.update(k.pkg_hash); |
| 253 | hashUserInputOptionsMap(ctx.allocator, k.user_input_options, &hasher); | 245 | for (k.options.keys(), k.options.values()) |option_key, option_value| { |
| 254 | return hasher.final(); | 246 | hasher.update(option_key); |
| | 247 | option_value.hash(&hasher); |
| | 248 | } |
| | 249 | return @truncate(hasher.final()); |
| | 250 | } |
| | 251 | |
| | 252 | pub fn eql(_: @This(), a: PackageInstanceKey, b: PackageInstanceKey, _: usize) bool { |
| | 253 | if (!mem.eql(u8, a.pkg_hash, b.pkg_hash)) return false; |
| | 254 | if (a.options.count() != b.options.count()) return false; |
| | 255 | for ( |
| | 256 | a.options.keys(), |
| | 257 | b.options.keys(), |
| | 258 | a.options.values(), |
| | 259 | b.options.values(), |
| | 260 | ) |a_key, b_key, a_val, b_val| { |
| | 261 | if (!mem.eql(u8, a_key, b_key)) return false; |
| | 262 | if (!a_val.eql(b_val)) return false; |
| | 263 | } |
| | 264 | return true; |
| 255 | } | 265 | } |
| | 266 | }, true); |
| 256 | | 267 | |
| 257 | pub fn eql(_: @This(), lhs: InitializedDepKey, rhs: InitializedDepKey) bool { | 268 | const PackageInstanceKey = struct { |
| 258 | if (!std.mem.eql(u8, lhs.build_root_string, rhs.build_root_string)) | 269 | pkg_hash: []const u8, |
| 259 | return false; | 270 | options: *const PackageOptions.Map, |
| | 271 | }; |
| 260 | | 272 | |
| 261 | if (lhs.user_input_options.count() != rhs.user_input_options.count()) | 273 | /// Build system implementation details. |
| 262 | return false; | 274 | pub const PackageOptions = struct { |
| | 275 | pub const Map = std.array_hash_map.String(UserProvided); |
| | 276 | |
| | 277 | pub const UserProvided = union(enum) { |
| | 278 | flag: void, |
| | 279 | scalar: []const u8, |
| | 280 | list: std.ArrayList([]const u8), |
| | 281 | map: std.array_hash_map.String(*const UserProvided), |
| | 282 | lazy_path: LazyPath, |
| | 283 | lazy_path_list: std.ArrayList(LazyPath), |
| | 284 | |
| | 285 | fn eql(a: UserProvided, b: UserProvided) bool { |
| | 286 | if (std.meta.activeTag(a) != b) return false; |
| | 287 | return switch (a) { |
| | 288 | .flag => true, |
| | 289 | .scalar => |a_scalar| return mem.eql(u8, a_scalar, b.scalar), |
| | 290 | .list => |a_list| { |
| | 291 | if (a_list.items.len != b.list.items.len) return false; |
| | 292 | for (a_list.items, b.list.items) |a_elem, b_elem| { |
| | 293 | if (!mem.eql(u8, a_elem, b_elem)) |
| | 294 | return false; |
| | 295 | } |
| | 296 | return true; |
| | 297 | }, |
| | 298 | .map => |a_map| { |
| | 299 | if (a_map.count() != b.map.count()) return false; |
| | 300 | for (a_map.keys(), a_map.values(), b.map.keys(), b.map.values()) |a_key, a_val, b_key, b_val| { |
| | 301 | if (!mem.eql(u8, a_key, b_key)) return false; |
| | 302 | if (!a_val.eql(b_val.*)) return false; |
| | 303 | } |
| | 304 | return true; |
| | 305 | }, |
| | 306 | .lazy_path => |a_lazy_path| return a_lazy_path.eql(b.lazy_path), |
| | 307 | .lazy_path_list => |a_lazy_path_list| { |
| | 308 | if (a_lazy_path_list.items.len != b.lazy_path_list.items.len) return false; |
| | 309 | for (a_lazy_path_list.items, b.lazy_path_list.items) |a_lp, b_lp| { |
| | 310 | if (!a_lp.eql(b_lp)) return false; |
| | 311 | } |
| | 312 | return true; |
| | 313 | }, |
| | 314 | }; |
| | 315 | } |
| | 316 | |
| | 317 | fn hash(a: UserProvided, hasher: *std.hash.Wyhash) void { |
| | 318 | hasher.update(&mem.toBytes(std.meta.activeTag(a))); |
| | 319 | switch (a) { |
| | 320 | .flag => {}, |
| | 321 | .scalar => |scalar| hasher.update(scalar), |
| | 322 | .list => |*list| for (list.items) |elem| hasher.update(elem), |
| | 323 | .map => |*map| for (map.keys(), map.values()) |key, val| { |
| | 324 | hasher.update(key); |
| | 325 | val.hash(hasher); |
| | 326 | }, |
| | 327 | .lazy_path => |lp| lp.hash(hasher), |
| | 328 | .lazy_path_list => |*list| for (list.items) |lp| lp.hash(hasher), |
| | 329 | } |
| | 330 | } |
| | 331 | }; |
| 263 | | 332 | |
| 264 | var it = lhs.user_input_options.iterator(); | 333 | fn fromArgs(arena: Allocator, map: *PackageOptions.Map, args: anytype) void { |
| 265 | while (it.next()) |lhs_entry| { | 334 | const args_info = @typeInfo(@TypeOf(args)).@"struct"; |
| 266 | const rhs_value = rhs.user_input_options.get(lhs_entry.key_ptr.*) orelse return false; | 335 | inline for (args_info.field_names, args_info.field_types) |field_name, field_type| { |
| 267 | if (!userValuesAreSame(lhs_entry.value_ptr.*.value, rhs_value.value)) | 336 | if (field_type == @TypeOf(null)) continue; |
| 268 | return false; | 337 | addPackageOptionFromArg(arena, map, field_name, field_type, @field(args, field_name)); |
| 269 | } | 338 | } |
| | 339 | } |
| 270 | | 340 | |
| 271 | return true; | 341 | pub fn sort(map: *Map) void { |
| | 342 | map.sortUnstable(@as(struct { |
| | 343 | keys: []const []const u8, |
| | 344 | pub fn lessThan(this: @This(), a_index: usize, b_index: usize) bool { |
| | 345 | return mem.lessThan(u8, this.keys[a_index], this.keys[b_index]); |
| | 346 | } |
| | 347 | }, .{ .keys = map.keys() })); |
| 272 | } | 348 | } |
| 273 | }; | 349 | }; |
| 274 | | 350 | |
| 275 | pub const UserInputOptionsMap = StringHashMap(UserInputOption); | | |
| 276 | | | |
| 277 | const AvailableOption = struct { | 351 | const AvailableOption = struct { |
| 278 | name: []const u8, | | |
| 279 | type_id: Configuration.AvailableOption.Type, | 352 | type_id: Configuration.AvailableOption.Type, |
| 280 | description: []const u8, | 353 | description: []const u8, |
| 281 | /// If the `type_id` is `enum` or `enum_list` this provides the list of enum options | 354 | /// If the `type_id` is `enum` or `enum_list` this provides the list of enum options |
| 282 | enum_options: ?[]const []const u8, | 355 | enum_options: ?[]const []const u8, |
| 283 | }; | 356 | }; |
| 284 | | 357 | |
| 285 | pub const UserInputOption = struct { | | |
| 286 | name: []const u8, | | |
| 287 | value: UserValue, | | |
| 288 | used: bool, | | |
| 289 | }; | | |
| 290 | | | |
| 291 | pub const UserValue = union(enum) { | | |
| 292 | flag: void, | | |
| 293 | scalar: []const u8, | | |
| 294 | list: std.array_list.Managed([]const u8), | | |
| 295 | map: StringHashMap(*const UserValue), | | |
| 296 | lazy_path: LazyPath, | | |
| 297 | lazy_path_list: std.array_list.Managed(LazyPath), | | |
| 298 | }; | | |
| 299 | | | |
| 300 | /// Build system implementation detail. | 358 | /// Build system implementation detail. |
| 301 | pub fn create( | 359 | pub fn create( |
| 302 | graph: *Graph, | 360 | graph: *Graph, |
| ... | @@ -311,7 +369,7 @@ pub fn create( | ... | @@ -311,7 +369,7 @@ pub fn create( |
| 311 | .root = root, | 369 | .root = root, |
| 312 | .invalid_user_input = false, | 370 | .invalid_user_input = false, |
| 313 | .allocator = arena, | 371 | .allocator = arena, |
| 314 | .user_input_options = UserInputOptionsMap.init(arena), | 372 | .user_input_options = .empty, |
| 315 | .top_level_steps = .{}, | 373 | .top_level_steps = .{}, |
| 316 | .default_step = undefined, | 374 | .default_step = undefined, |
| 317 | .install_tls = .{ | 375 | .install_tls = .{ |
| ... | @@ -348,7 +406,7 @@ fn createChild( | ... | @@ -348,7 +406,7 @@ fn createChild( |
| 348 | root: Cache.Path, | 406 | root: Cache.Path, |
| 349 | pkg_hash: []const u8, | 407 | pkg_hash: []const u8, |
| 350 | pkg_deps: AvailableDeps, | 408 | pkg_deps: AvailableDeps, |
| 351 | user_input_options: UserInputOptionsMap, | 409 | user_input_options: PackageOptions.Map, |
| 352 | ) error{OutOfMemory}!*Build { | 410 | ) error{OutOfMemory}!*Build { |
| 353 | const arena = parent.graph.arena; | 411 | const arena = parent.graph.arena; |
| 354 | const child = try arena.create(Build); | 412 | const child = try arena.create(Build); |
| ... | @@ -390,167 +448,96 @@ fn createChild( | ... | @@ -390,167 +448,96 @@ fn createChild( |
| 390 | return child; | 448 | return child; |
| 391 | } | 449 | } |
| 392 | | 450 | |
| 393 | fn userInputOptionsFromArgs(arena: Allocator, args: anytype) UserInputOptionsMap { | 451 | fn addPackageOptionFromArg( |
| 394 | var map = UserInputOptionsMap.init(arena); | | |
| 395 | const args_info = @typeInfo(@TypeOf(args)).@"struct"; | | |
| 396 | inline for (args_info.field_names, args_info.field_types) |field_name, field_type| { | | |
| 397 | if (field_type == @TypeOf(null)) continue; | | |
| 398 | addUserInputOptionFromArg(arena, &map, field_name, field_type, @field(args, field_name)); | | |
| 399 | } | | |
| 400 | return map; | | |
| 401 | } | | |
| 402 | | | |
| 403 | fn addUserInputOptionFromArg( | | |
| 404 | arena: Allocator, | 452 | arena: Allocator, |
| 405 | map: *UserInputOptionsMap, | 453 | map: *PackageOptions.Map, |
| 406 | field_name: [:0]const u8, | 454 | field_name: [:0]const u8, |
| 407 | comptime T: type, | 455 | comptime T: type, |
| 408 | /// If null, the value won't be added, but `T` will still be type-checked. | 456 | /// If null, the value won't be added, but `T` will still be type-checked. |
| 409 | maybe_value: ?T, | 457 | maybe_value: ?T, |
| 410 | ) void { | 458 | ) void { |
| | 459 | map.ensureUnusedCapacity(arena, 2) catch @panic("OOM"); |
| 411 | switch (T) { | 460 | switch (T) { |
| 412 | Target.Query => return if (maybe_value) |v| { | 461 | Target.Query => return if (maybe_value) |v| { |
| 413 | map.put(field_name, .{ | 462 | map.putAssumeCapacity(field_name, .{ .scalar = v.zigTriple(arena) catch @panic("OOM") }); |
| 414 | .name = field_name, | 463 | map.putAssumeCapacity("cpu", .{ .scalar = v.serializeCpuAlloc(arena) catch @panic("OOM") }); |
| 415 | .value = .{ .scalar = v.zigTriple(arena) catch @panic("OOM") }, | | |
| 416 | .used = false, | | |
| 417 | }) catch @panic("OOM"); | | |
| 418 | map.put("cpu", .{ | | |
| 419 | .name = "cpu", | | |
| 420 | .value = .{ .scalar = v.serializeCpuAlloc(arena) catch @panic("OOM") }, | | |
| 421 | .used = false, | | |
| 422 | }) catch @panic("OOM"); | | |
| 423 | }, | 464 | }, |
| 424 | ResolvedTarget => return if (maybe_value) |v| { | 465 | ResolvedTarget => return if (maybe_value) |v| { |
| 425 | map.put(field_name, .{ | 466 | map.putAssumeCapacity(field_name, .{ .scalar = v.query.zigTriple(arena) catch @panic("OOM") }); |
| 426 | .name = field_name, | 467 | map.putAssumeCapacity("cpu", .{ .scalar = v.query.serializeCpuAlloc(arena) catch @panic("OOM") }); |
| 427 | .value = .{ .scalar = v.query.zigTriple(arena) catch @panic("OOM") }, | | |
| 428 | .used = false, | | |
| 429 | }) catch @panic("OOM"); | | |
| 430 | map.put("cpu", .{ | | |
| 431 | .name = "cpu", | | |
| 432 | .value = .{ .scalar = v.query.serializeCpuAlloc(arena) catch @panic("OOM") }, | | |
| 433 | .used = false, | | |
| 434 | }) catch @panic("OOM"); | | |
| 435 | }, | 468 | }, |
| 436 | std.zig.BuildId => return if (maybe_value) |v| { | 469 | std.zig.BuildId => return if (maybe_value) |v| { |
| 437 | map.put(field_name, .{ | 470 | map.putAssumeCapacity(field_name, .{ |
| 438 | .name = field_name, | 471 | .scalar = std.fmt.allocPrint(arena, "{f}", .{v}) catch @panic("OOM"), |
| 439 | .value = .{ .scalar = std.fmt.allocPrint(arena, "{f}", .{v}) catch @panic("OOM") }, | 472 | }); |
| 440 | .used = false, | | |
| 441 | }) catch @panic("OOM"); | | |
| 442 | }, | 473 | }, |
| 443 | LazyPath => return if (maybe_value) |v| { | 474 | LazyPath => return if (maybe_value) |v| { |
| 444 | map.put(field_name, .{ | 475 | map.putAssumeCapacity(field_name, .{ .lazy_path = v.dupeInner(arena) }); |
| 445 | .name = field_name, | | |
| 446 | .value = .{ .lazy_path = v.dupeInner(arena) }, | | |
| 447 | .used = false, | | |
| 448 | }) catch @panic("OOM"); | | |
| 449 | }, | 476 | }, |
| 450 | []const LazyPath => return if (maybe_value) |v| { | 477 | []const LazyPath => return if (maybe_value) |v| { |
| 451 | var list = std.array_list.Managed(LazyPath).initCapacity(arena, v.len) catch @panic("OOM"); | 478 | var list: std.ArrayList(LazyPath) = .empty; |
| 452 | for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(arena)); | 479 | const elems = list.addManyAsSlice(arena, v.len) catch @panic("OOM"); |
| 453 | map.put(field_name, .{ | 480 | for (v, elems) |lp, *elem| elem.* = lp.dupeInner(arena); |
| 454 | .name = field_name, | 481 | map.putAssumeCapacity(field_name, .{ .lazy_path_list = list }); |
| 455 | .value = .{ .lazy_path_list = list }, | | |
| 456 | .used = false, | | |
| 457 | }) catch @panic("OOM"); | | |
| 458 | }, | 482 | }, |
| 459 | []const u8 => return if (maybe_value) |v| { | 483 | []const u8 => return if (maybe_value) |v| { |
| 460 | map.put(field_name, .{ | 484 | map.putAssumeCapacity(field_name, .{ .scalar = arena.dupe(u8, v) catch @panic("OOM") }); |
| 461 | .name = field_name, | | |
| 462 | .value = .{ .scalar = arena.dupe(u8, v) catch @panic("OOM") }, | | |
| 463 | .used = false, | | |
| 464 | }) catch @panic("OOM"); | | |
| 465 | }, | 485 | }, |
| 466 | []const []const u8 => return if (maybe_value) |v| { | 486 | []const []const u8 => return if (maybe_value) |v| { |
| 467 | var list = std.array_list.Managed([]const u8).initCapacity(arena, v.len) catch @panic("OOM"); | 487 | var list: std.ArrayList([]const u8) = .empty; |
| 468 | for (v) |s| list.appendAssumeCapacity(arena.dupe(u8, s) catch @panic("OOM")); | 488 | const elems = list.addManyAsSlice(arena, v.len) catch @panic("OOM"); |
| 469 | map.put(field_name, .{ | 489 | for (v, elems) |s, *elem| elem.* = arena.dupe(u8, s) catch @panic("OOM"); |
| 470 | .name = field_name, | 490 | map.putAssumeCapacity(field_name, .{ .list = list }); |
| 471 | .value = .{ .list = list }, | | |
| 472 | .used = false, | | |
| 473 | }) catch @panic("OOM"); | | |
| 474 | }, | 491 | }, |
| 475 | else => switch (@typeInfo(T)) { | 492 | else => switch (@typeInfo(T)) { |
| 476 | .bool => return if (maybe_value) |v| { | 493 | .bool => return if (maybe_value) |v| { |
| 477 | map.put(field_name, .{ | 494 | map.putAssumeCapacity(field_name, .{ .scalar = if (v) "true" else "false" }); |
| 478 | .name = field_name, | | |
| 479 | .value = .{ .scalar = if (v) "true" else "false" }, | | |
| 480 | .used = false, | | |
| 481 | }) catch @panic("OOM"); | | |
| 482 | }, | 495 | }, |
| 483 | .@"enum", .enum_literal => return if (maybe_value) |v| { | 496 | .@"enum", .enum_literal => return if (maybe_value) |v| { |
| 484 | map.put(field_name, .{ | 497 | map.putAssumeCapacity(field_name, .{ .scalar = @tagName(v) }); |
| 485 | .name = field_name, | | |
| 486 | .value = .{ .scalar = @tagName(v) }, | | |
| 487 | .used = false, | | |
| 488 | }) catch @panic("OOM"); | | |
| 489 | }, | 498 | }, |
| 490 | .comptime_int, .int => return if (maybe_value) |v| { | 499 | .comptime_int, .int => return if (maybe_value) |v| { |
| 491 | map.put(field_name, .{ | 500 | map.putAssumeCapacity(field_name, .{ |
| 492 | .name = field_name, | 501 | .scalar = std.fmt.allocPrint(arena, "{d}", .{v}) catch @panic("OOM"), |
| 493 | .value = .{ .scalar = std.fmt.allocPrint(arena, "{d}", .{v}) catch @panic("OOM") }, | 502 | }); |
| 494 | .used = false, | | |
| 495 | }) catch @panic("OOM"); | | |
| 496 | }, | 503 | }, |
| 497 | .comptime_float, .float => return if (maybe_value) |v| { | 504 | .comptime_float, .float => return if (maybe_value) |v| { |
| 498 | map.put(field_name, .{ | 505 | map.putAssumeCapacity(field_name, .{ |
| 499 | .name = field_name, | 506 | .scalar = std.fmt.allocPrint(arena, "{x}", .{v}) catch @panic("OOM"), |
| 500 | .value = .{ .scalar = std.fmt.allocPrint(arena, "{x}", .{v}) catch @panic("OOM") }, | 507 | }); |
| 501 | .used = false, | | |
| 502 | }) catch @panic("OOM"); | | |
| 503 | }, | 508 | }, |
| 504 | .pointer => |ptr_info| switch (ptr_info.size) { | 509 | .pointer => |ptr_info| switch (ptr_info.size) { |
| 505 | .one => switch (@typeInfo(ptr_info.child)) { | 510 | .one => switch (@typeInfo(ptr_info.child)) { |
| 506 | .array => |array_info| { | 511 | .array => |array_info| return addPackageOptionFromArg( |
| 507 | addUserInputOptionFromArg( | 512 | arena, |
| 508 | arena, | 513 | map, |
| 509 | map, | 514 | field_name, |
| 510 | field_name, | 515 | @Pointer(.slice, .{ .@"const" = true }, array_info.child, null), |
| 511 | @Pointer(.slice, .{ .@"const" = true }, array_info.child, null), | 516 | maybe_value orelse null, |
| 512 | maybe_value orelse null, | 517 | ), |
| 513 | ); | | |
| 514 | return; | | |
| 515 | }, | | |
| 516 | else => {}, | 518 | else => {}, |
| 517 | }, | 519 | }, |
| 518 | .slice => switch (@typeInfo(ptr_info.child)) { | 520 | .slice => switch (@typeInfo(ptr_info.child)) { |
| 519 | .@"enum" => return if (maybe_value) |v| { | 521 | .@"enum" => return if (maybe_value) |v| { |
| 520 | var list = std.array_list.Managed([]const u8).initCapacity(arena, v.len) catch @panic("OOM"); | 522 | var list: std.ArrayList([]const u8) = .empty; |
| 521 | for (v) |tag| list.appendAssumeCapacity(@tagName(tag)); | 523 | const elems = list.addManyAsSlice(arena, v.len) catch @panic("OOM"); |
| 522 | map.put(field_name, .{ | 524 | for (elems, v) |*elem, tag| elem.* = @tagName(tag); |
| 523 | .name = field_name, | 525 | map.putAssumeCapacity(field_name, .{ .list = list }); |
| 524 | .value = .{ .list = list }, | | |
| 525 | .used = false, | | |
| 526 | }) catch @panic("OOM"); | | |
| 527 | }, | | |
| 528 | else => { | | |
| 529 | addUserInputOptionFromArg( | | |
| 530 | arena, | | |
| 531 | map, | | |
| 532 | field_name, | | |
| 533 | @Pointer(ptr_info.size, .{ .@"const" = true }, ptr_info.child, null), | | |
| 534 | maybe_value orelse null, | | |
| 535 | ); | | |
| 536 | return; | | |
| 537 | }, | 526 | }, |
| | 527 | else => return addPackageOptionFromArg( |
| | 528 | arena, |
| | 529 | map, |
| | 530 | field_name, |
| | 531 | @Pointer(ptr_info.size, .{ .@"const" = true }, ptr_info.child, null), |
| | 532 | maybe_value orelse null, |
| | 533 | ), |
| 538 | }, | 534 | }, |
| 539 | else => {}, | 535 | else => {}, |
| 540 | }, | 536 | }, |
| 541 | .null => unreachable, | 537 | .null => unreachable, |
| 542 | .optional => |info| switch (@typeInfo(info.child)) { | 538 | .optional => |info| switch (@typeInfo(info.child)) { |
| 543 | .optional => {}, | 539 | .optional => {}, |
| 544 | else => { | 540 | else => return addPackageOptionFromArg(arena, map, field_name, info.child, maybe_value orelse null), |
| 545 | addUserInputOptionFromArg( | | |
| 546 | arena, | | |
| 547 | map, | | |
| 548 | field_name, | | |
| 549 | info.child, | | |
| 550 | maybe_value orelse null, | | |
| 551 | ); | | |
| 552 | return; | | |
| 553 | }, | | |
| 554 | }, | 541 | }, |
| 555 | else => {}, | 542 | else => {}, |
| 556 | }, | 543 | }, |
| ... | @@ -558,130 +545,6 @@ fn addUserInputOptionFromArg( | ... | @@ -558,130 +545,6 @@ fn addUserInputOptionFromArg( |
| 558 | @compileError("option '" ++ field_name ++ "' has unsupported type: " ++ @typeName(T)); | 545 | @compileError("option '" ++ field_name ++ "' has unsupported type: " ++ @typeName(T)); |
| 559 | } | 546 | } |
| 560 | | 547 | |
| 561 | const OrderedUserValue = union(enum) { | | |
| 562 | flag: void, | | |
| 563 | scalar: []const u8, | | |
| 564 | list: std.array_list.Managed([]const u8), | | |
| 565 | map: std.array_list.Managed(Pair), | | |
| 566 | lazy_path: LazyPath, | | |
| 567 | lazy_path_list: std.array_list.Managed(LazyPath), | | |
| 568 | | | |
| 569 | const Pair = struct { | | |
| 570 | name: []const u8, | | |
| 571 | value: OrderedUserValue, | | |
| 572 | fn lessThan(_: void, lhs: Pair, rhs: Pair) bool { | | |
| 573 | return std.ascii.lessThanIgnoreCase(lhs.name, rhs.name); | | |
| 574 | } | | |
| 575 | }; | | |
| 576 | | | |
| 577 | fn hash(val: OrderedUserValue, hasher: *std.hash.Wyhash) void { | | |
| 578 | hasher.update(&std.mem.toBytes(std.meta.activeTag(val))); | | |
| 579 | switch (val) { | | |
| 580 | .flag => {}, | | |
| 581 | .scalar => |scalar| hasher.update(scalar), | | |
| 582 | // lists are already ordered | | |
| 583 | .list => |list| for (list.items) |list_entry| | | |
| 584 | hasher.update(list_entry), | | |
| 585 | .map => |map| for (map.items) |map_entry| { | | |
| 586 | hasher.update(map_entry.name); | | |
| 587 | map_entry.value.hash(hasher); | | |
| 588 | }, | | |
| 589 | .lazy_path => |lp| hashLazyPath(lp, hasher), | | |
| 590 | .lazy_path_list => |lp_list| for (lp_list.items) |lp| { | | |
| 591 | hashLazyPath(lp, hasher); | | |
| 592 | }, | | |
| 593 | } | | |
| 594 | } | | |
| 595 | | | |
| 596 | fn hashLazyPath(lp: LazyPath, hasher: *std.hash.Wyhash) void { | | |
| 597 | switch (lp) { | | |
| 598 | .src_path => |sp| { | | |
| 599 | hasher.update(sp.owner.pkg_hash); | | |
| 600 | hasher.update(sp.sub_path); | | |
| 601 | }, | | |
| 602 | .generated => |gen| { | | |
| 603 | hasher.update(@ptrCast(&gen.index)); | | |
| 604 | hasher.update(@ptrCast(&gen.up)); | | |
| 605 | hasher.update(gen.sub_path); | | |
| 606 | }, | | |
| 607 | .cwd_relative => |rel_path| { | | |
| 608 | hasher.update(rel_path); | | |
| 609 | }, | | |
| 610 | .relative => |r| { | | |
| 611 | hasher.update(@ptrCast(&r.base)); | | |
| 612 | hasher.update(@ptrCast(&r.sub_path)); | | |
| 613 | }, | | |
| 614 | .dependency => |dep| { | | |
| 615 | hasher.update(dep.dependency.builder.pkg_hash); | | |
| 616 | hasher.update(dep.sub_path); | | |
| 617 | }, | | |
| 618 | } | | |
| 619 | } | | |
| 620 | | | |
| 621 | fn mapFromUnordered(allocator: Allocator, unordered: std.StringHashMap(*const UserValue)) std.array_list.Managed(Pair) { | | |
| 622 | var ordered = std.array_list.Managed(Pair).init(allocator); | | |
| 623 | var it = unordered.iterator(); | | |
| 624 | while (it.next()) |entry| { | | |
| 625 | ordered.append(.{ | | |
| 626 | .name = entry.key_ptr.*, | | |
| 627 | .value = OrderedUserValue.fromUnordered(allocator, entry.value_ptr.*.*), | | |
| 628 | }) catch @panic("OOM"); | | |
| 629 | } | | |
| 630 | | | |
| 631 | std.mem.sortUnstable(Pair, ordered.items, {}, Pair.lessThan); | | |
| 632 | return ordered; | | |
| 633 | } | | |
| 634 | | | |
| 635 | fn fromUnordered(allocator: Allocator, unordered: UserValue) OrderedUserValue { | | |
| 636 | return switch (unordered) { | | |
| 637 | .flag => .{ .flag = {} }, | | |
| 638 | .scalar => |scalar| .{ .scalar = scalar }, | | |
| 639 | .list => |list| .{ .list = list }, | | |
| 640 | .map => |map| .{ .map = OrderedUserValue.mapFromUnordered(allocator, map) }, | | |
| 641 | .lazy_path => |lp| .{ .lazy_path = lp }, | | |
| 642 | .lazy_path_list => |list| .{ .lazy_path_list = list }, | | |
| 643 | }; | | |
| 644 | } | | |
| 645 | }; | | |
| 646 | | | |
| 647 | const OrderedUserInputOption = struct { | | |
| 648 | name: []const u8, | | |
| 649 | value: OrderedUserValue, | | |
| 650 | used: bool, | | |
| 651 | | | |
| 652 | fn hash(opt: OrderedUserInputOption, hasher: *std.hash.Wyhash) void { | | |
| 653 | hasher.update(opt.name); | | |
| 654 | opt.value.hash(hasher); | | |
| 655 | } | | |
| 656 | | | |
| 657 | fn fromUnordered(allocator: Allocator, user_input_option: UserInputOption) OrderedUserInputOption { | | |
| 658 | return OrderedUserInputOption{ | | |
| 659 | .name = user_input_option.name, | | |
| 660 | .used = user_input_option.used, | | |
| 661 | .value = OrderedUserValue.fromUnordered(allocator, user_input_option.value), | | |
| 662 | }; | | |
| 663 | } | | |
| 664 | | | |
| 665 | fn lessThan(_: void, lhs: OrderedUserInputOption, rhs: OrderedUserInputOption) bool { | | |
| 666 | return std.ascii.lessThanIgnoreCase(lhs.name, rhs.name); | | |
| 667 | } | | |
| 668 | }; | | |
| 669 | | | |
| 670 | // The hash should be consistent with the same values given a different order. | | |
| 671 | // This function takes a user input map, orders it, then hashes the contents. | | |
| 672 | fn hashUserInputOptionsMap(allocator: Allocator, user_input_options: UserInputOptionsMap, hasher: *std.hash.Wyhash) void { | | |
| 673 | var ordered = std.array_list.Managed(OrderedUserInputOption).init(allocator); | | |
| 674 | var it = user_input_options.iterator(); | | |
| 675 | while (it.next()) |entry| | | |
| 676 | ordered.append(OrderedUserInputOption.fromUnordered(allocator, entry.value_ptr.*)) catch @panic("OOM"); | | |
| 677 | | | |
| 678 | std.mem.sortUnstable(OrderedUserInputOption, ordered.items, {}, OrderedUserInputOption.lessThan); | | |
| 679 | | | |
| 680 | // juice it | | |
| 681 | for (ordered.items) |user_option| | | |
| 682 | user_option.hash(hasher); | | |
| 683 | } | | |
| 684 | | | |
| 685 | /// Create a set of key-value pairs that can be converted into a Zig source | 548 | /// Create a set of key-value pairs that can be converted into a Zig source |
| 686 | /// file and then inserted into a Zig compilation's module table for importing. | 549 | /// file and then inserted into a Zig compilation's module table for importing. |
| 687 | /// | 550 | /// |
| ... | @@ -1107,31 +970,20 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw | ... | @@ -1107,31 +970,20 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw |
| 1107 | const name = graph.dupeString(name_raw); | 970 | const name = graph.dupeString(name_raw); |
| 1108 | const description = graph.dupeString(description_raw); | 971 | const description = graph.dupeString(description_raw); |
| 1109 | const type_id = comptime typeToEnum(T); | 972 | const type_id = comptime typeToEnum(T); |
| 1110 | const enum_options = if (type_id == .@"enum" or type_id == .enum_list) blk: { | 973 | const available_option: AvailableOption = .{ |
| 1111 | const EnumType = if (type_id == .enum_list) @typeInfo(T).pointer.child else T; | | |
| 1112 | const field_names = @typeInfo(EnumType).@"enum".field_names; | | |
| 1113 | var options = std.array_list.Managed([]const u8).initCapacity(b.allocator, field_names.len) catch @panic("OOM"); | | |
| 1114 | | | |
| 1115 | inline for (field_names) |field_name| { | | |
| 1116 | options.appendAssumeCapacity(field_name); | | |
| 1117 | } | | |
| 1118 | | | |
| 1119 | break :blk options.toOwnedSlice() catch @panic("OOM"); | | |
| 1120 | } else null; | | |
| 1121 | const available_option = AvailableOption{ | | |
| 1122 | .name = name, | | |
| 1123 | .type_id = type_id, | 974 | .type_id = type_id, |
| 1124 | .description = description, | 975 | .description = description, |
| 1125 | .enum_options = enum_options, | 976 | .enum_options = if (type_id == .@"enum" or type_id == .enum_list) blk: { |
| | 977 | const E = if (type_id == .enum_list) @typeInfo(T).pointer.child else T; |
| | 978 | break :blk @typeInfo(E).@"enum".field_names; |
| | 979 | } else null, |
| 1126 | }; | 980 | }; |
| 1127 | if ((b.available_options_map.fetchPut(arena, name, available_option) catch @panic("OOM")) != null) { | 981 | if ((b.available_options_map.fetchPut(arena, name, available_option) catch @panic("OOM")) != null) { |
| 1128 | panic("option {q} declared twice", .{name}); | 982 | panic("option {q} declared twice", .{name}); |
| 1129 | } | 983 | } |
| 1130 | | 984 | const user_provided = b.user_input_options.get(name) orelse return null; |
| 1131 | const option_ptr = b.user_input_options.getPtr(name) orelse return null; | | |
| 1132 | option_ptr.used = true; | | |
| 1133 | switch (type_id) { | 985 | switch (type_id) { |
| 1134 | .bool => switch (option_ptr.value) { | 986 | .bool => switch (user_provided) { |
| 1135 | .flag => return true, | 987 | .flag => return true, |
| 1136 | .scalar => |s| { | 988 | .scalar => |s| { |
| 1137 | if (mem.eql(u8, s, "true")) { | 989 | if (mem.eql(u8, s, "true")) { |
| ... | @@ -1145,14 +997,14 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw | ... | @@ -1145,14 +997,14 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw |
| 1145 | } | 997 | } |
| 1146 | }, | 998 | }, |
| 1147 | .list, .map, .lazy_path, .lazy_path_list => { | 999 | .list, .map, .lazy_path, .lazy_path_list => { |
| 1148 | log.err("expected -D{s} to be a boolean; received: {t}", .{ name, option_ptr.value }); | 1000 | log.err("expected -D{s} to be a boolean; received: {t}", .{ name, user_provided }); |
| 1149 | b.markInvalidUserInput(); | 1001 | b.markInvalidUserInput(); |
| 1150 | return null; | 1002 | return null; |
| 1151 | }, | 1003 | }, |
| 1152 | }, | 1004 | }, |
| 1153 | .int => switch (option_ptr.value) { | 1005 | .int => switch (user_provided) { |
| 1154 | .flag, .list, .map, .lazy_path, .lazy_path_list => { | 1006 | .flag, .list, .map, .lazy_path, .lazy_path_list => { |
| 1155 | log.err("expected -D{s} to be an integer; received: {t}", .{ name, option_ptr.value }); | 1007 | log.err("expected -D{s} to be an integer; received: {t}", .{ name, user_provided }); |
| 1156 | b.markInvalidUserInput(); | 1008 | b.markInvalidUserInput(); |
| 1157 | return null; | 1009 | return null; |
| 1158 | }, | 1010 | }, |
| ... | @@ -1172,9 +1024,9 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw | ... | @@ -1172,9 +1024,9 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw |
| 1172 | return n; | 1024 | return n; |
| 1173 | }, | 1025 | }, |
| 1174 | }, | 1026 | }, |
| 1175 | .float => switch (option_ptr.value) { | 1027 | .float => switch (user_provided) { |
| 1176 | .flag, .map, .list, .lazy_path, .lazy_path_list => { | 1028 | .flag, .map, .list, .lazy_path, .lazy_path_list => { |
| 1177 | log.err("expected -D{s} to be a float; received: {t}", .{ name, option_ptr.value }); | 1029 | log.err("expected -D{s} to be a float; received: {t}", .{ name, user_provided }); |
| 1178 | b.markInvalidUserInput(); | 1030 | b.markInvalidUserInput(); |
| 1179 | return null; | 1031 | return null; |
| 1180 | }, | 1032 | }, |
| ... | @@ -1187,9 +1039,9 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw | ... | @@ -1187,9 +1039,9 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw |
| 1187 | return n; | 1039 | return n; |
| 1188 | }, | 1040 | }, |
| 1189 | }, | 1041 | }, |
| 1190 | .@"enum" => switch (option_ptr.value) { | 1042 | .@"enum" => switch (user_provided) { |
| 1191 | .flag, .map, .list, .lazy_path, .lazy_path_list => { | 1043 | .flag, .map, .list, .lazy_path, .lazy_path_list => { |
| 1192 | log.err("expected -D{s} to be an enum; received: {t}.", .{ name, option_ptr.value }); | 1044 | log.err("expected -D{s} to be an enum; received: {t}.", .{ name, user_provided }); |
| 1193 | b.markInvalidUserInput(); | 1045 | b.markInvalidUserInput(); |
| 1194 | return null; | 1046 | return null; |
| 1195 | }, | 1047 | }, |
| ... | @@ -1206,17 +1058,17 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw | ... | @@ -1206,17 +1058,17 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw |
| 1206 | return null; | 1058 | return null; |
| 1207 | }, | 1059 | }, |
| 1208 | }, | 1060 | }, |
| 1209 | .string => switch (option_ptr.value) { | 1061 | .string => switch (user_provided) { |
| 1210 | .flag, .list, .map, .lazy_path, .lazy_path_list => { | 1062 | .flag, .list, .map, .lazy_path, .lazy_path_list => { |
| 1211 | log.err("expected -D{s} to be a string; received: {t}", .{ name, option_ptr.value }); | 1063 | log.err("expected -D{s} to be a string; received: {t}", .{ name, user_provided }); |
| 1212 | b.markInvalidUserInput(); | 1064 | b.markInvalidUserInput(); |
| 1213 | return null; | 1065 | return null; |
| 1214 | }, | 1066 | }, |
| 1215 | .scalar => |s| return s, | 1067 | .scalar => |s| return s, |
| 1216 | }, | 1068 | }, |
| 1217 | .build_id => switch (option_ptr.value) { | 1069 | .build_id => switch (user_provided) { |
| 1218 | .flag, .map, .list, .lazy_path, .lazy_path_list => { | 1070 | .flag, .map, .list, .lazy_path, .lazy_path_list => { |
| 1219 | log.err("expected -D{s} to be an enum; received: {t}.", .{ name, option_ptr.value }); | 1071 | log.err("expected -D{s} to be an enum; received: {t}.", .{ name, user_provided }); |
| 1220 | b.markInvalidUserInput(); | 1072 | b.markInvalidUserInput(); |
| 1221 | return null; | 1073 | return null; |
| 1222 | }, | 1074 | }, |
| ... | @@ -1230,9 +1082,9 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw | ... | @@ -1230,9 +1082,9 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw |
| 1230 | } | 1082 | } |
| 1231 | }, | 1083 | }, |
| 1232 | }, | 1084 | }, |
| 1233 | .list => switch (option_ptr.value) { | 1085 | .list => switch (user_provided) { |
| 1234 | .flag, .map, .lazy_path, .lazy_path_list => { | 1086 | .flag, .map, .lazy_path, .lazy_path_list => { |
| 1235 | log.err("expected -D{s} to be a list; received: {t}", .{ name, option_ptr.value }); | 1087 | log.err("expected -D{s} to be a list; received: {t}", .{ name, user_provided }); |
| 1236 | b.markInvalidUserInput(); | 1088 | b.markInvalidUserInput(); |
| 1237 | return null; | 1089 | return null; |
| 1238 | }, | 1090 | }, |
| ... | @@ -1241,9 +1093,9 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw | ... | @@ -1241,9 +1093,9 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw |
| 1241 | }, | 1093 | }, |
| 1242 | .list => |lst| return lst.items, | 1094 | .list => |lst| return lst.items, |
| 1243 | }, | 1095 | }, |
| 1244 | .enum_list => switch (option_ptr.value) { | 1096 | .enum_list => switch (user_provided) { |
| 1245 | .flag, .map, .lazy_path, .lazy_path_list => { | 1097 | .flag, .map, .lazy_path, .lazy_path_list => { |
| 1246 | log.err("expected -D{s} to be a list; received: {t}", .{ name, option_ptr.value }); | 1098 | log.err("expected -D{s} to be a list; received: {t}", .{ name, user_provided }); |
| 1247 | b.markInvalidUserInput(); | 1099 | b.markInvalidUserInput(); |
| 1248 | return null; | 1100 | return null; |
| 1249 | }, | 1101 | }, |
| ... | @@ -1283,16 +1135,16 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw | ... | @@ -1283,16 +1135,16 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw |
| 1283 | return new_list; | 1135 | return new_list; |
| 1284 | }, | 1136 | }, |
| 1285 | }, | 1137 | }, |
| 1286 | .lazy_path => switch (option_ptr.value) { | 1138 | .lazy_path => switch (user_provided) { |
| 1287 | .scalar => |s| return .{ .cwd_relative = s }, | 1139 | .scalar => |s| return .{ .cwd_relative = s }, |
| 1288 | .lazy_path => |lp| return lp, | 1140 | .lazy_path => |lp| return lp, |
| 1289 | .flag, .map, .list, .lazy_path_list => { | 1141 | .flag, .map, .list, .lazy_path_list => { |
| 1290 | log.err("expected -D{s} to be a path; received: {t}", .{ name, option_ptr.value }); | 1142 | log.err("expected -D{s} to be a path; received: {t}", .{ name, user_provided }); |
| 1291 | b.markInvalidUserInput(); | 1143 | b.markInvalidUserInput(); |
| 1292 | return null; | 1144 | return null; |
| 1293 | }, | 1145 | }, |
| 1294 | }, | 1146 | }, |
| 1295 | .lazy_path_list => switch (option_ptr.value) { | 1147 | .lazy_path_list => switch (user_provided) { |
| 1296 | .scalar => |s| return arena.dupe(LazyPath, &[_]LazyPath{.{ .cwd_relative = s }}) catch @panic("OOM"), | 1148 | .scalar => |s| return arena.dupe(LazyPath, &[_]LazyPath{.{ .cwd_relative = s }}) catch @panic("OOM"), |
| 1297 | .lazy_path => |lp| return arena.dupe(LazyPath, &[_]LazyPath{lp}) catch @panic("OOM"), | 1149 | .lazy_path => |lp| return arena.dupe(LazyPath, &[_]LazyPath{lp}) catch @panic("OOM"), |
| 1298 | .list => |lst| { | 1150 | .list => |lst| { |
| ... | @@ -1304,7 +1156,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw | ... | @@ -1304,7 +1156,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw |
| 1304 | }, | 1156 | }, |
| 1305 | .lazy_path_list => |lp_list| return lp_list.items, | 1157 | .lazy_path_list => |lp_list| return lp_list.items, |
| 1306 | .flag, .map => { | 1158 | .flag, .map => { |
| 1307 | log.err("expected -D{s} to be a path; received: {t}", .{ name, option_ptr.value }); | 1159 | log.err("expected -D{s} to be a path; received: {t}", .{ name, user_provided }); |
| 1308 | b.markInvalidUserInput(); | 1160 | b.markInvalidUserInput(); |
| 1309 | return null; | 1161 | return null; |
| 1310 | }, | 1162 | }, |
| ... | @@ -1497,88 +1349,63 @@ pub fn standardTargetOptionsQueryOnly(b: *Build, args: StandardTargetOptionsArgs | ... | @@ -1497,88 +1349,63 @@ pub fn standardTargetOptionsQueryOnly(b: *Build, args: StandardTargetOptionsArgs |
| 1497 | } | 1349 | } |
| 1498 | | 1350 | |
| 1499 | /// Build system implementation detail. | 1351 | /// Build system implementation detail. |
| 1500 | pub fn addUserInputOption(b: *Build, name_raw: []const u8, value_raw: []const u8) error{OutOfMemory}!bool { | 1352 | pub fn addUserInputOption(b: *Build, name: []const u8, value_raw: []const u8) error{OutOfMemory}!bool { |
| 1501 | const graph = b.graph; | 1353 | const graph = b.graph; |
| 1502 | const arena = graph.arena; | 1354 | const arena = graph.arena; |
| 1503 | const name = graph.dupeString(name_raw); | | |
| 1504 | const value = graph.dupeString(value_raw); | 1355 | const value = graph.dupeString(value_raw); |
| 1505 | const gop = try b.user_input_options.getOrPut(name); | 1356 | const gop = try b.user_input_options.getOrPut(arena, name); |
| | 1357 | |
| 1506 | if (!gop.found_existing) { | 1358 | if (!gop.found_existing) { |
| 1507 | gop.value_ptr.* = UserInputOption{ | 1359 | gop.key_ptr.* = graph.dupeString(name); |
| 1508 | .name = name, | 1360 | gop.value_ptr.* = .{ .scalar = value }; |
| 1509 | .value = .{ .scalar = value }, | | |
| 1510 | .used = false, | | |
| 1511 | }; | | |
| 1512 | return false; | 1361 | return false; |
| 1513 | } | 1362 | } |
| 1514 | | 1363 | |
| 1515 | // option already exists | 1364 | // Option already exists. |
| 1516 | switch (gop.value_ptr.value) { | 1365 | switch (gop.value_ptr.*) { |
| 1517 | .scalar => |s| { | 1366 | .scalar => |s| { |
| 1518 | // turn it into a list | 1367 | // Turn it into a list. |
| 1519 | var list = std.array_list.Managed([]const u8).init(arena); | 1368 | var list: std.ArrayList([]const u8) = .empty; |
| 1520 | try list.append(s); | 1369 | (try list.addManyAsArray(arena, 2)).* = .{ s, value }; |
| 1521 | try list.append(value); | 1370 | gop.value_ptr.* = .{ .list = list }; |
| 1522 | try b.user_input_options.put(name, .{ | | |
| 1523 | .name = name, | | |
| 1524 | .value = .{ .list = list }, | | |
| 1525 | .used = false, | | |
| 1526 | }); | | |
| 1527 | }, | | |
| 1528 | .list => |*list| { | | |
| 1529 | // append to the list | | |
| 1530 | try list.append(value); | | |
| 1531 | try b.user_input_options.put(name, .{ | | |
| 1532 | .name = name, | | |
| 1533 | .value = .{ .list = list.* }, | | |
| 1534 | .used = false, | | |
| 1535 | }); | | |
| 1536 | }, | 1371 | }, |
| | 1372 | .list => |*list| try list.append(arena, value), |
| 1537 | .flag => { | 1373 | .flag => { |
| 1538 | log.warn("option '-D{s}={s}' conflicts with flag '-D{s}'.", .{ name, value, name }); | 1374 | log.err("option -D{s}={s} conflicts with flag -D{s}", .{ name, value, name }); |
| 1539 | return true; | 1375 | return true; |
| 1540 | }, | 1376 | }, |
| 1541 | .map => |*map| { | 1377 | .map => |*map| { |
| 1542 | _ = map; | 1378 | _ = map; |
| 1543 | log.warn("TODO maps as command line arguments is not implemented yet.", .{}); | 1379 | unreachable; // TODO implement maps as command line arguments |
| 1544 | return true; | | |
| 1545 | }, | | |
| 1546 | .lazy_path, .lazy_path_list => { | | |
| 1547 | log.warn("the lazy path value type isn't added from the CLI, but somehow {q} is a .{f}", .{ | | |
| 1548 | name, std.zig.fmtId(@tagName(gop.value_ptr.value)), | | |
| 1549 | }); | | |
| 1550 | return true; | | |
| 1551 | }, | 1380 | }, |
| | 1381 | .lazy_path => unreachable, |
| | 1382 | .lazy_path_list => unreachable, |
| 1552 | } | 1383 | } |
| 1553 | return false; | 1384 | return false; |
| 1554 | } | 1385 | } |
| 1555 | | 1386 | |
| 1556 | /// Build system implementation detail. | 1387 | /// Build system implementation detail. |
| 1557 | pub fn addUserInputFlag(b: *Build, name_raw: []const u8) error{OutOfMemory}!bool { | 1388 | pub fn addUserInputFlag(b: *Build, name: []const u8) error{OutOfMemory}!bool { |
| 1558 | const graph = b.graph; | 1389 | const graph = b.graph; |
| 1559 | const name = graph.dupeString(name_raw); | 1390 | const arena = graph.arena; |
| 1560 | const gop = try b.user_input_options.getOrPut(name); | 1391 | const gop = try b.user_input_options.getOrPut(arena, name); |
| 1561 | if (!gop.found_existing) { | 1392 | if (!gop.found_existing) { |
| 1562 | gop.value_ptr.* = .{ | 1393 | gop.key_ptr.* = graph.dupeString(name); |
| 1563 | .name = name, | 1394 | gop.value_ptr.* = .{ .flag = {} }; |
| 1564 | .value = .{ .flag = {} }, | | |
| 1565 | .used = false, | | |
| 1566 | }; | | |
| 1567 | return false; | 1395 | return false; |
| 1568 | } | 1396 | } |
| 1569 | | 1397 | // Option already exists. |
| 1570 | // option already exists | 1398 | switch (gop.value_ptr.*) { |
| 1571 | switch (gop.value_ptr.value) { | | |
| 1572 | .scalar => |s| { | 1399 | .scalar => |s| { |
| 1573 | log.err("Flag '-D{s}' conflicts with option '-D{s}={s}'.", .{ name, name, s }); | 1400 | log.err("flag -D{s} conflicts with option -D{s}={s}", .{ name, name, s }); |
| 1574 | return true; | 1401 | return true; |
| 1575 | }, | 1402 | }, |
| 1576 | .list, .map, .lazy_path_list => { | 1403 | .list, .map, .lazy_path_list => { |
| 1577 | log.err("Flag '-D{s}' conflicts with multiple options of the same name.", .{name}); | 1404 | log.err("flag -D{s} conflicts with multiple options of the same name", .{name}); |
| 1578 | return true; | 1405 | return true; |
| 1579 | }, | 1406 | }, |
| 1580 | .lazy_path => |lp| { | 1407 | .lazy_path => |lp| { |
| 1581 | log.err("Flag '-D{s}' conflicts with option '-D{s}={f}'.", .{ name, name, lp }); | 1408 | log.err("flag -D{s} conflicts with option -D{s}={f}", .{ name, name, lp }); |
| 1582 | return true; | 1409 | return true; |
| 1583 | }, | 1410 | }, |
| 1584 | | 1411 | |
| ... | @@ -1614,17 +1441,16 @@ fn markInvalidUserInput(b: *Build) void { | ... | @@ -1614,17 +1441,16 @@ fn markInvalidUserInput(b: *Build) void { |
| 1614 | b.invalid_user_input = true; | 1441 | b.invalid_user_input = true; |
| 1615 | } | 1442 | } |
| 1616 | | 1443 | |
| 1617 | /// Build system implementation detail. | 1444 | fn validateUserInputDidItFail(b: *Build) bool { |
| 1618 | pub fn validateUserInputDidItFail(b: *Build) bool { | 1445 | for (b.user_input_options.keys()) |name| { |
| 1619 | // Make sure all args are used. | 1446 | if (!b.available_options_map.contains(name)) { |
| 1620 | var it = b.user_input_options.iterator(); | 1447 | for (b.available_options_map.keys(), b.available_options_map.values()) |available_name, *available| { |
| 1621 | while (it.next()) |entry| { | 1448 | log.info("available option: {q}: {s}", .{ available_name, available.description }); |
| 1622 | if (!entry.value_ptr.used) { | 1449 | } |
| 1623 | log.err("invalid option: -D{s}", .{entry.key_ptr.*}); | 1450 | log.err("invalid option: {q}", .{name}); |
| 1624 | b.markInvalidUserInput(); | 1451 | b.markInvalidUserInput(); |
| 1625 | } | 1452 | } |
| 1626 | } | 1453 | } |
| 1627 | | | |
| 1628 | return b.invalid_user_input; | 1454 | return b.invalid_user_input; |
| 1629 | } | 1455 | } |
| 1630 | | 1456 | |
| ... | @@ -2092,14 +1918,14 @@ inline fn findImportPkgHashOrFatal(b: *Build, comptime asking_build_zig: type, c | ... | @@ -2092,14 +1918,14 @@ inline fn findImportPkgHashOrFatal(b: *Build, comptime asking_build_zig: type, c |
| 2092 | const pkg = @field(deps.packages, pkg_hash); | 1918 | const pkg = @field(deps.packages, pkg_hash); |
| 2093 | if (@hasDecl(pkg, "build_zig") and pkg.build_zig == asking_build_zig) break .{ pkg_hash, pkg.deps }; | 1919 | if (@hasDecl(pkg, "build_zig") and pkg.build_zig == asking_build_zig) break .{ pkg_hash, pkg.deps }; |
| 2094 | } else .{ "", deps.root_deps }; | 1920 | } else .{ "", deps.root_deps }; |
| 2095 | if (!std.mem.eql(u8, b_pkg_hash, b.pkg_hash)) { | 1921 | if (!mem.eql(u8, b_pkg_hash, b.pkg_hash)) { |
| 2096 | const build_zig_path = b.root.join(arena, "build.zig") catch @panic("OOM"); | 1922 | const build_zig_path = b.root.join(arena, "build.zig") catch @panic("OOM"); |
| 2097 | panic("{} is not the struct that corresponds to {f}", .{ | 1923 | panic("{} is not the struct that corresponds to {f}", .{ |
| 2098 | asking_build_zig, build_zig_path, | 1924 | asking_build_zig, build_zig_path, |
| 2099 | }); | 1925 | }); |
| 2100 | } | 1926 | } |
| 2101 | comptime for (b_pkg_deps) |dep| { | 1927 | comptime for (b_pkg_deps) |dep| { |
| 2102 | if (std.mem.eql(u8, dep[0], dep_name)) return dep[1]; | 1928 | if (mem.eql(u8, dep[0], dep_name)) return dep[1]; |
| 2103 | }; | 1929 | }; |
| 2104 | | 1930 | |
| 2105 | const full_path = b.root.join(arena, "build.zig.zon") catch @panic("OOM"); | 1931 | const full_path = b.root.join(arena, "build.zig.zon") catch @panic("OOM"); |
| ... | @@ -2141,7 +1967,9 @@ pub fn dependencyLazy(b: *Build, name: []const u8, args: anytype) error{LazyDepe | ... | @@ -2141,7 +1967,9 @@ pub fn dependencyLazy(b: *Build, name: []const u8, args: anytype) error{LazyDepe |
| 2141 | markNeededLazyDep(b, pkg_hash); | 1967 | markNeededLazyDep(b, pkg_hash); |
| 2142 | return error.LazyDependencyNeeded; | 1968 | return error.LazyDependencyNeeded; |
| 2143 | } | 1969 | } |
| 2144 | return dependencyResolved(b, name, entry, userInputOptionsFromArgs(b.graph.arena, args)); | 1970 | var map: PackageOptions.Map = .empty; |
| | 1971 | PackageOptions.fromArgs(b.graph.arena, &map, args); |
| | 1972 | return dependencyResolved(b, name, entry, &map); |
| 2145 | } | 1973 | } |
| 2146 | | 1974 | |
| 2147 | pub const PackageEntry = struct { | 1975 | pub const PackageEntry = struct { |
| ... | @@ -2232,12 +2060,14 @@ pub inline fn lazyImport( | ... | @@ -2232,12 +2060,14 @@ pub inline fn lazyImport( |
| 2232 | comptime unreachable; // Bad @dependencies source | 2060 | comptime unreachable; // Bad @dependencies source |
| 2233 | } | 2061 | } |
| 2234 | | 2062 | |
| 2235 | fn pkgHashFromBuildZig(comptime build_zig: type) ?[]const u8 { | 2063 | inline fn pkgHashFromBuildZig(comptime build_zig: type) ?[]const u8 { |
| 2236 | const deps = @import("root").dependencies; | 2064 | comptime { |
| 2237 | return comptime for (@typeInfo(deps.packages).@"struct".decl_names) |pkg_hash| { | 2065 | const deps = @import("root").dependencies; |
| 2238 | const pkg = @field(deps.packages, pkg_hash); | 2066 | return for (@typeInfo(deps.packages).@"struct".decl_names) |pkg_hash| { |
| 2239 | if (@hasDecl(pkg, "build_zig") and pkg.build_zig == build_zig) break pkg_hash; | 2067 | const pkg = @field(deps.packages, pkg_hash); |
| 2240 | } else null; | 2068 | if (@hasDecl(pkg, "build_zig") and pkg.build_zig == build_zig) break pkg_hash; |
| | 2069 | } else null; |
| | 2070 | } |
| 2241 | } | 2071 | } |
| 2242 | | 2072 | |
| 2243 | /// Build system implementation detail. | 2073 | /// Build system implementation detail. |
| ... | @@ -2251,114 +2081,37 @@ pub fn dependencyFromBuildZig( | ... | @@ -2251,114 +2081,37 @@ pub fn dependencyFromBuildZig( |
| 2251 | const arena = b.graph.arena; | 2081 | const arena = b.graph.arena; |
| 2252 | | 2082 | |
| 2253 | find_dep: { | 2083 | find_dep: { |
| 2254 | const pkg_hash = comptime pkgHashFromBuildZig(build_zig) orelse break :find_dep; | 2084 | const pkg_hash = pkgHashFromBuildZig(build_zig) orelse break :find_dep; |
| 2255 | const dep_name = for (b.available_deps) |dep| { | 2085 | const dep_name = for (b.available_deps) |dep| { |
| 2256 | if (mem.eql(u8, dep[1], pkg_hash)) break dep[1]; | 2086 | if (mem.eql(u8, dep[1], pkg_hash)) break dep[1]; |
| 2257 | } else break :find_dep; | 2087 | } else break :find_dep; |
| 2258 | const entry = package_map.get(pkg_hash) orelse break :find_dep; | 2088 | const entry = package_map.get(pkg_hash) orelse break :find_dep; |
| 2259 | return dependencyResolved(b, dep_name, entry, userInputOptionsFromArgs(arena, args)); | 2089 | var map: PackageOptions.Map = .empty; |
| | 2090 | PackageOptions.fromArgs(arena, &map, args); |
| | 2091 | return dependencyResolved(b, dep_name, entry, &map); |
| 2260 | } | 2092 | } |
| 2261 | | 2093 | |
| 2262 | const full_path = b.root.join(arena, "build.zig.zon") catch @panic("OOM"); | 2094 | const full_path = b.root.join(arena, "build.zig.zon") catch @panic("OOM"); |
| 2263 | panic("{} is not a build.zig struct of a dependency in {f}", .{ build_zig, full_path }); | 2095 | panic("{} is not a build.zig struct of a dependency in {f}", .{ build_zig, full_path }); |
| 2264 | } | 2096 | } |
| 2265 | | 2097 | |
| 2266 | fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool { | 2098 | /// Takes ownership of `package_options`, which may be unsorted. |
| 2267 | if (std.meta.activeTag(lhs) != rhs) return false; | | |
| 2268 | switch (lhs) { | | |
| 2269 | .flag => {}, | | |
| 2270 | .scalar => |lhs_scalar| { | | |
| 2271 | const rhs_scalar = rhs.scalar; | | |
| 2272 | | | |
| 2273 | if (!std.mem.eql(u8, lhs_scalar, rhs_scalar)) | | |
| 2274 | return false; | | |
| 2275 | }, | | |
| 2276 | .list => |lhs_list| { | | |
| 2277 | const rhs_list = rhs.list; | | |
| 2278 | | | |
| 2279 | if (lhs_list.items.len != rhs_list.items.len) | | |
| 2280 | return false; | | |
| 2281 | | | |
| 2282 | for (lhs_list.items, rhs_list.items) |lhs_list_entry, rhs_list_entry| { | | |
| 2283 | if (!std.mem.eql(u8, lhs_list_entry, rhs_list_entry)) | | |
| 2284 | return false; | | |
| 2285 | } | | |
| 2286 | }, | | |
| 2287 | .map => |lhs_map| { | | |
| 2288 | const rhs_map = rhs.map; | | |
| 2289 | | | |
| 2290 | if (lhs_map.count() != rhs_map.count()) | | |
| 2291 | return false; | | |
| 2292 | | | |
| 2293 | var lhs_it = lhs_map.iterator(); | | |
| 2294 | while (lhs_it.next()) |lhs_entry| { | | |
| 2295 | const rhs_value = rhs_map.get(lhs_entry.key_ptr.*) orelse return false; | | |
| 2296 | if (!userValuesAreSame(lhs_entry.value_ptr.*.*, rhs_value.*)) | | |
| 2297 | return false; | | |
| 2298 | } | | |
| 2299 | }, | | |
| 2300 | .lazy_path => |lhs_lp| { | | |
| 2301 | const rhs_lp = rhs.lazy_path; | | |
| 2302 | return userLazyPathsAreTheSame(lhs_lp, rhs_lp); | | |
| 2303 | }, | | |
| 2304 | .lazy_path_list => |lhs_lp_list| { | | |
| 2305 | const rhs_lp_list = rhs.lazy_path_list; | | |
| 2306 | if (lhs_lp_list.items.len != rhs_lp_list.items.len) return false; | | |
| 2307 | for (lhs_lp_list.items, rhs_lp_list.items) |lhs_lp, rhs_lp| { | | |
| 2308 | if (!userLazyPathsAreTheSame(lhs_lp, rhs_lp)) return false; | | |
| 2309 | } | | |
| 2310 | return true; | | |
| 2311 | }, | | |
| 2312 | } | | |
| 2313 | | | |
| 2314 | return true; | | |
| 2315 | } | | |
| 2316 | | | |
| 2317 | fn userLazyPathsAreTheSame(lhs_lp: LazyPath, rhs_lp: LazyPath) bool { | | |
| 2318 | if (std.meta.activeTag(lhs_lp) != rhs_lp) return false; | | |
| 2319 | switch (lhs_lp) { | | |
| 2320 | .src_path => |lhs_sp| { | | |
| 2321 | const rhs_sp = rhs_lp.src_path; | | |
| 2322 | | | |
| 2323 | if (lhs_sp.owner != rhs_sp.owner) return false; | | |
| 2324 | if (std.mem.eql(u8, lhs_sp.sub_path, rhs_sp.sub_path)) return false; | | |
| 2325 | }, | | |
| 2326 | .generated => |*lhs_gen| { | | |
| 2327 | const rhs_gen = &rhs_lp.generated; | | |
| 2328 | | | |
| 2329 | if (lhs_gen.index != rhs_gen.index) return false; | | |
| 2330 | if (lhs_gen.up != rhs_gen.up) return false; | | |
| 2331 | if (std.mem.eql(u8, lhs_gen.sub_path, rhs_gen.sub_path)) return false; | | |
| 2332 | }, | | |
| 2333 | .cwd_relative => |lhs_rel_path| { | | |
| 2334 | const rhs_rel_path = rhs_lp.cwd_relative; | | |
| 2335 | | | |
| 2336 | if (!std.mem.eql(u8, lhs_rel_path, rhs_rel_path)) return false; | | |
| 2337 | }, | | |
| 2338 | .relative => |lhs| return lhs.eql(rhs_lp.relative), | | |
| 2339 | .dependency => |lhs_dep| { | | |
| 2340 | const rhs_dep = rhs_lp.dependency; | | |
| 2341 | | | |
| 2342 | if (lhs_dep.dependency != rhs_dep.dependency) return false; | | |
| 2343 | if (!std.mem.eql(u8, lhs_dep.sub_path, rhs_dep.sub_path)) return false; | | |
| 2344 | }, | | |
| 2345 | } | | |
| 2346 | return true; | | |
| 2347 | } | | |
| 2348 | | | |
| 2349 | fn dependencyResolved( | 2099 | fn dependencyResolved( |
| 2350 | b: *Build, | 2100 | b: *Build, |
| 2351 | name: []const u8, | 2101 | name: []const u8, |
| 2352 | entry: PackageEntry, | 2102 | entry: PackageEntry, |
| 2353 | user_input_options: UserInputOptionsMap, | 2103 | package_options: *PackageOptions.Map, |
| 2354 | ) *Dependency { | 2104 | ) *Dependency { |
| 2355 | const graph = b.graph; | 2105 | const graph = b.graph; |
| 2356 | const io = graph.io; | 2106 | const io = graph.io; |
| 2357 | const arena = graph.arena; | 2107 | const arena = graph.arena; |
| | 2108 | |
| | 2109 | PackageOptions.sort(package_options); |
| | 2110 | |
| 2358 | if (graph.dependency_cache.getContext(.{ | 2111 | if (graph.dependency_cache.getContext(.{ |
| 2359 | .build_root_string = entry.build_root, | 2112 | .pkg_hash = entry.hash, |
| 2360 | .user_input_options = user_input_options, | 2113 | .options = package_options, |
| 2361 | }, .{ .allocator = arena })) |dep| return dep; | 2114 | }, .{})) |dep| return dep; |
| 2362 | | 2115 | |
| 2363 | const dep_root: Cache.Path = .{ | 2116 | const dep_root: Cache.Path = .{ |
| 2364 | .root_dir = .{ | 2117 | .root_dir = .{ |
| ... | @@ -2368,7 +2121,7 @@ fn dependencyResolved( | ... | @@ -2368,7 +2121,7 @@ fn dependencyResolved( |
| 2368 | }, | 2121 | }, |
| 2369 | }; | 2122 | }; |
| 2370 | | 2123 | |
| 2371 | const sub_builder = b.createChild(name, dep_root, entry.hash, entry.deps, user_input_options) catch @panic("OOM"); | 2124 | const sub_builder = b.createChild(name, dep_root, entry.hash, entry.deps, package_options.*) catch @panic("OOM"); |
| 2372 | if (entry.run_build) |run_build| { | 2125 | if (entry.run_build) |run_build| { |
| 2373 | run_build(sub_builder); | 2126 | run_build(sub_builder); |
| 2374 | | 2127 | |
| ... | @@ -2381,9 +2134,9 @@ fn dependencyResolved( | ... | @@ -2381,9 +2134,9 @@ fn dependencyResolved( |
| 2381 | dep.* = .{ .builder = sub_builder }; | 2134 | dep.* = .{ .builder = sub_builder }; |
| 2382 | | 2135 | |
| 2383 | graph.dependency_cache.putContext(arena, .{ | 2136 | graph.dependency_cache.putContext(arena, .{ |
| 2384 | .build_root_string = entry.build_root, | 2137 | .pkg_hash = entry.hash, |
| 2385 | .user_input_options = user_input_options, | 2138 | .options = &sub_builder.user_input_options, |
| 2386 | }, dep, .{ .allocator = arena }) catch @panic("OOM"); | 2139 | }, dep, .{}) catch @panic("OOM"); |
| 2387 | return dep; | 2140 | return dep; |
| 2388 | } | 2141 | } |
| 2389 | | 2142 | |
| ... | @@ -2650,6 +2403,59 @@ pub const LazyPath = union(enum) { | ... | @@ -2650,6 +2403,59 @@ pub const LazyPath = union(enum) { |
| 2650 | } }, | 2403 | } }, |
| 2651 | }; | 2404 | }; |
| 2652 | } | 2405 | } |
| | 2406 | |
| | 2407 | fn eql(a: LazyPath, b: LazyPath) bool { |
| | 2408 | if (std.meta.activeTag(a) != b) return false; |
| | 2409 | switch (a) { |
| | 2410 | .src_path => |a_sp| { |
| | 2411 | const b_sp = b.src_path; |
| | 2412 | if (a_sp.owner != b_sp.owner) return false; |
| | 2413 | if (mem.eql(u8, a_sp.sub_path, b_sp.sub_path)) return false; |
| | 2414 | }, |
| | 2415 | .generated => |*a_gen| { |
| | 2416 | const b_gen = &b.generated; |
| | 2417 | if (a_gen.index != b_gen.index) return false; |
| | 2418 | if (a_gen.up != b_gen.up) return false; |
| | 2419 | if (mem.eql(u8, a_gen.sub_path, b_gen.sub_path)) return false; |
| | 2420 | }, |
| | 2421 | .cwd_relative => |a_rel_path| { |
| | 2422 | const b_rel_path = b.cwd_relative; |
| | 2423 | if (!mem.eql(u8, a_rel_path, b_rel_path)) return false; |
| | 2424 | }, |
| | 2425 | .relative => |a_relative| return a_relative.eql(b.relative), |
| | 2426 | .dependency => |a_dep| { |
| | 2427 | const b_dep = b.dependency; |
| | 2428 | if (a_dep.dependency != b_dep.dependency) return false; |
| | 2429 | if (!mem.eql(u8, a_dep.sub_path, b_dep.sub_path)) return false; |
| | 2430 | }, |
| | 2431 | } |
| | 2432 | return true; |
| | 2433 | } |
| | 2434 | |
| | 2435 | fn hash(lp: LazyPath, hasher: *std.hash.Wyhash) void { |
| | 2436 | switch (lp) { |
| | 2437 | .src_path => |sp| { |
| | 2438 | hasher.update(sp.owner.pkg_hash); |
| | 2439 | hasher.update(sp.sub_path); |
| | 2440 | }, |
| | 2441 | .generated => |gen| { |
| | 2442 | hasher.update(@ptrCast(&gen.index)); |
| | 2443 | hasher.update(@ptrCast(&gen.up)); |
| | 2444 | hasher.update(gen.sub_path); |
| | 2445 | }, |
| | 2446 | .cwd_relative => |rel_path| { |
| | 2447 | hasher.update(rel_path); |
| | 2448 | }, |
| | 2449 | .relative => |r| { |
| | 2450 | hasher.update(@ptrCast(&r.base)); |
| | 2451 | hasher.update(@ptrCast(&r.sub_path)); |
| | 2452 | }, |
| | 2453 | .dependency => |dep| { |
| | 2454 | hasher.update(dep.dependency.builder.pkg_hash); |
| | 2455 | hasher.update(dep.sub_path); |
| | 2456 | }, |
| | 2457 | } |
| | 2458 | } |
| 2653 | }; | 2459 | }; |
| 2654 | | 2460 | |
| 2655 | fn dumpBadDirnameHelp( | 2461 | fn dumpBadDirnameHelp( |