| author | |
| committer | |
| log | 6925a57d2fd4e4b1330d980cbfb84f7007f117ef |
| tree | 6c88e9d892c081e4ee53cf5ca4463fe006dc7538 |
| parent | b04818644c958e05de9b0d5fb4a8a2a3da6d2164 |
5 files changed, 301 insertions(+), 66 deletions(-)
lib/compiler/Maker/ScannedConfig.zig+3| ... | ... | @@ -15,6 +15,7 @@ pub fn print(sc: *const ScannedConfig, w: *Writer) Writer.Error!void { |
| 15 | 15 | std.log.err("TODO also print unlazy deps", .{}); |
| 16 | 16 | std.log.err("TODO also print system integrations", .{}); |
| 17 | 17 | std.log.err("TODO also print available options", .{}); |
| 18 | std.log.err("TODO also print modules", .{}); | |
| 18 | 19 | const c = &sc.configuration; |
| 19 | 20 | var serializer: Serializer = .{ .writer = w }; |
| 20 | 21 | var s = try serializer.beginStruct(.{}); |
| ... | ... | @@ -83,6 +84,7 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi |
| 83 | 84 | .flag_optional => comptime unreachable, |
| 84 | 85 | .flag_length_prefixed_list => comptime unreachable, |
| 85 | 86 | .enum_optional => comptime unreachable, |
| 87 | .union_list => comptime unreachable, | |
| 86 | 88 | } else if (std.enums.tagName(Field, field_value)) |name| { |
| 87 | 89 | try s.ident(name); |
| 88 | 90 | } else { |
| ... | ... | @@ -105,6 +107,7 @@ fn printValue(sc: *const ScannedConfig, s: *Serializer, comptime Field: type, fi |
| 105 | 107 | try printValue(sc, s, @TypeOf(field_value.slice), field_value.slice); |
| 106 | 108 | }, |
| 107 | 109 | .extended => @compileError("TODO"), |
| 110 | .union_list => @compileError("TODO"), | |
| 108 | 111 | }, |
| 109 | 112 | else => @compileError("not implemented: " ++ @typeName(Field)), |
| 110 | 113 | }, |
lib/compiler/configurer.zig+101-19| ... | ... | @@ -224,6 +224,8 @@ const Serialize = struct { |
| 224 | 224 | wc: *Configuration.Wip, |
| 225 | 225 | module_map: std.AutoArrayHashMapUnmanaged(*std.Build.Module, Configuration.Module.Index) = .empty, |
| 226 | 226 | package_map: std.AutoArrayHashMapUnmanaged(*std.Build, Configuration.Package.Index) = .empty, |
| 227 | /// Index corresponds to `Configuration.steps` index. | |
| 228 | step_map: std.AutoArrayHashMapUnmanaged(*Step, void) = .empty, | |
| 227 | 229 | |
| 228 | 230 | fn builderToPackage(s: *Serialize, b: *std.Build) !Configuration.Package.Index { |
| 229 | 231 | if (b.pkg_hash.len == 0) return .root; |
| ... | ... | @@ -291,6 +293,56 @@ const Serialize = struct { |
| 291 | 293 | return if (opt_slice) |slice| try s.wc.addString(slice) else null; |
| 292 | 294 | } |
| 293 | 295 | |
| 296 | fn addSystemLib(s: *Serialize, sl: *const std.Build.Module.SystemLib) !Configuration.SystemLib.Index { | |
| 297 | log.err("TODO deduplicate addSystemLib", .{}); | |
| 298 | const wc = s.wc; | |
| 299 | return @enumFromInt(try wc.addExtra(@as(Configuration.SystemLib, .{ | |
| 300 | .flags = .{ | |
| 301 | .needed = sl.needed, | |
| 302 | .weak = sl.weak, | |
| 303 | .use_pkg_config = sl.use_pkg_config, | |
| 304 | .preferred_link_mode = sl.preferred_link_mode, | |
| 305 | .search_strategy = sl.search_strategy, | |
| 306 | }, | |
| 307 | .name = try wc.addString(sl.name), | |
| 308 | }))); | |
| 309 | } | |
| 310 | ||
| 311 | fn addCSourceFile(s: *Serialize, csf: *const std.Build.Module.CSourceFile) !Configuration.CSourceFile.Index { | |
| 312 | log.err("TODO addCSourceFile trailing data", .{}); | |
| 313 | const wc = s.wc; | |
| 314 | return @enumFromInt(try wc.addExtra(@as(Configuration.CSourceFile, .{ | |
| 315 | .flags = .{ | |
| 316 | .args_len = @intCast(csf.flags.len), | |
| 317 | .lang = .init(csf.language), | |
| 318 | }, | |
| 319 | .file = try addLazyPath(s, csf.file), | |
| 320 | }))); | |
| 321 | } | |
| 322 | ||
| 323 | fn addCSourceFiles(s: *Serialize, csf: *const std.Build.Module.CSourceFiles) !Configuration.CSourceFiles.Index { | |
| 324 | log.err("TODO addCSourceFiles trailing data", .{}); | |
| 325 | const wc = s.wc; | |
| 326 | return @enumFromInt(try wc.addExtra(@as(Configuration.CSourceFiles, .{ | |
| 327 | .flags = .{ | |
| 328 | .args_len = @intCast(csf.flags.len), | |
| 329 | .lang = .init(csf.language), | |
| 330 | }, | |
| 331 | .root = try addLazyPath(s, csf.root), | |
| 332 | .files_len = @intCast(csf.files.len), | |
| 333 | }))); | |
| 334 | } | |
| 335 | ||
| 336 | fn addRcSourceFile(s: *Serialize, rsf: *const std.Build.Module.RcSourceFile) !Configuration.RcSourceFile.Index { | |
| 337 | log.err("TODO addRcSourceFile trailing data", .{}); | |
| 338 | const wc = s.wc; | |
| 339 | return @enumFromInt(try wc.addExtra(@as(Configuration.RcSourceFile, .{ | |
| 340 | .file = try addLazyPath(s, rsf.file), | |
| 341 | .args_len = @intCast(rsf.flags.len), | |
| 342 | .include_paths_len = @intCast(rsf.include_paths.len), | |
| 343 | }))); | |
| 344 | } | |
| 345 | ||
| 294 | 346 | fn initStringList(s: *Serialize, list: []const []const u8) ![]const Configuration.String { |
| 295 | 347 | const wc = s.wc; |
| 296 | 348 | const result = try s.arena.alloc(Configuration.String, list.len); |
| ... | ... | @@ -312,6 +364,35 @@ const Serialize = struct { |
| 312 | 364 | const arena = s.arena; |
| 313 | 365 | const gpa = wc.gpa; |
| 314 | 366 | |
| 367 | const include_dirs = try arena.alloc(Configuration.Module.IncludeDir, m.include_dirs.items.len); | |
| 368 | for (include_dirs, m.include_dirs.items) |*dest, src| dest.* = switch (src) { | |
| 369 | .path => |lp| .{ .path = try addLazyPath(s, lp) }, | |
| 370 | .path_system => |lp| .{ .path_system = try addLazyPath(s, lp) }, | |
| 371 | .path_after => |lp| .{ .path_after = try addLazyPath(s, lp) }, | |
| 372 | .framework_path => |lp| .{ .framework_path = try addLazyPath(s, lp) }, | |
| 373 | .framework_path_system => |lp| .{ .framework_path_system = try addLazyPath(s, lp) }, | |
| 374 | .embed_path => |lp| .{ .embed_path = try addLazyPath(s, lp) }, | |
| 375 | .other_step => |cs| .{ .other_step = stepIndex(s, &cs.step) }, | |
| 376 | .config_header_step => |chs| .{ .config_header_step = stepIndex(s, &chs.step) }, | |
| 377 | }; | |
| 378 | ||
| 379 | const rpaths = try arena.alloc(Configuration.Module.RPath, m.rpaths.items.len); | |
| 380 | for (rpaths, m.rpaths.items) |*dest, src| dest.* = switch (src) { | |
| 381 | .lazy_path => |lp| .{ .lazy_path = try addLazyPath(s, lp) }, | |
| 382 | .special => |slice| .{ .special = try wc.addString(slice) }, | |
| 383 | }; | |
| 384 | ||
| 385 | const link_objects = try arena.alloc(Configuration.Module.LinkObject, m.link_objects.items.len); | |
| 386 | for (link_objects, m.link_objects.items) |*dest, *src| dest.* = switch (src.*) { | |
| 387 | .static_path => |lp| .{ .static_path = try addLazyPath(s, lp) }, | |
| 388 | .other_step => |cs| .{ .other_step = stepIndex(s, &cs.step) }, | |
| 389 | .system_lib => |*sl| .{ .system_lib = try addSystemLib(s, sl) }, | |
| 390 | .assembly_file => |lp| .{ .assembly_file = try addLazyPath(s, lp) }, | |
| 391 | .c_source_file => |csf| .{ .c_source_file = try addCSourceFile(s, csf) }, | |
| 392 | .c_source_files => |csf| .{ .c_source_files = try addCSourceFiles(s, csf) }, | |
| 393 | .win32_resource_file => |wrf| .{ .win32_resource_file = try addRcSourceFile(s, wrf) }, | |
| 394 | }; | |
| 395 | ||
| 315 | 396 | const lib_paths = try arena.alloc(Configuration.LazyPath, m.lib_paths.items.len); |
| 316 | 397 | for (lib_paths, m.lib_paths.items) |*dest, src| dest.* = try addLazyPath(s, src); |
| 317 | 398 | |
| ... | ... | @@ -352,11 +433,11 @@ const Serialize = struct { |
| 352 | 433 | .fuzz = .init(m.strip), |
| 353 | 434 | .code_model = m.code_model, |
| 354 | 435 | .c_macros = c_macros.len != 0, |
| 355 | .include_dirs = m.include_dirs.items.len != 0, | |
| 436 | .include_dirs = include_dirs.len != 0, | |
| 356 | 437 | .lib_paths = lib_paths.len != 0, |
| 357 | .rpaths = m.rpaths.items.len != 0, | |
| 438 | .rpaths = rpaths.len != 0, | |
| 358 | 439 | .frameworks = m.frameworks.entries.len != 0, |
| 359 | .link_objects = m.link_objects.items.len != 0, | |
| 440 | .link_objects = link_objects.len != 0, | |
| 360 | 441 | .export_symbol_names = export_symbol_names.len != 0, |
| 361 | 442 | }, |
| 362 | 443 | .flags2 = .{ |
| ... | ... | @@ -376,6 +457,9 @@ const Serialize = struct { |
| 376 | 457 | .c_macros = .{ .slice = c_macros }, |
| 377 | 458 | .lib_paths = .{ .slice = lib_paths }, |
| 378 | 459 | .export_symbol_names = .{ .slice = export_symbol_names }, |
| 460 | .include_dirs = .init(include_dirs), | |
| 461 | .rpaths = .init(rpaths), | |
| 462 | .link_objects = .init(link_objects), | |
| 379 | 463 | }))); |
| 380 | 464 | |
| 381 | 465 | log.err("TODO serialize the trailing Module data", .{}); |
| ... | ... | @@ -384,6 +468,10 @@ const Serialize = struct { |
| 384 | 468 | |
| 385 | 469 | return module_index; |
| 386 | 470 | } |
| 471 | ||
| 472 | fn stepIndex(s: *const Serialize, step: *Step) Configuration.Step.Index { | |
| 473 | return @enumFromInt(s.step_map.getIndex(step).?); | |
| 474 | } | |
| 387 | 475 | }; |
| 388 | 476 | |
| 389 | 477 | fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { |
| ... | ... | @@ -396,34 +484,32 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { |
| 396 | 484 | // Starting from all top-level steps in `b`, traverse the entire step graph |
| 397 | 485 | // and add all step dependencies implied by module graphs. |
| 398 | 486 | const top_level_steps = b.top_level_steps.values(); |
| 399 | // Index corresponds to `Configuration.steps` index. | |
| 400 | var step_map: std.AutoArrayHashMapUnmanaged(*Step, void) = .empty; | |
| 401 | try step_map.ensureUnusedCapacity(arena, top_level_steps.len); | |
| 487 | try s.step_map.ensureUnusedCapacity(arena, top_level_steps.len); | |
| 402 | 488 | for (top_level_steps) |tls| { |
| 403 | step_map.putAssumeCapacityNoClobber(&tls.step, {}); | |
| 489 | s.step_map.putAssumeCapacityNoClobber(&tls.step, {}); | |
| 404 | 490 | } |
| 405 | 491 | { |
| 406 | while (wc.steps.items.len < step_map.count()) { | |
| 407 | const step = step_map.keys()[wc.steps.items.len]; | |
| 492 | while (wc.steps.items.len < s.step_map.count()) { | |
| 493 | const step = s.step_map.keys()[wc.steps.items.len]; | |
| 408 | 494 | |
| 409 | 495 | // Set up any implied dependencies for this step. It's important that we do this first, so |
| 410 | 496 | // that the loop below discovers steps implied by the module graph. |
| 411 | 497 | try createModuleDependenciesForStep(step); |
| 412 | 498 | |
| 413 | try step_map.ensureUnusedCapacity(arena, step.dependencies.items.len); | |
| 499 | try s.step_map.ensureUnusedCapacity(arena, step.dependencies.items.len); | |
| 414 | 500 | for (step.dependencies.items) |other_step| { |
| 415 | step_map.putAssumeCapacity(other_step, {}); | |
| 501 | s.step_map.putAssumeCapacity(other_step, {}); | |
| 416 | 502 | } |
| 417 | 503 | |
| 418 | 504 | // Add and then de-duplicate dependencies. |
| 419 | 505 | const deps = d: { |
| 420 | 506 | const deps: Configuration.Deps = @enumFromInt(wc.extra.items.len); |
| 421 | 507 | for (try wc.reserveLengthPrefixed(step.dependencies.items.len), step.dependencies.items) |*dep, dep_step| |
| 422 | dep.* = @intCast(step_map.getIndex(dep_step).?); | |
| 508 | dep.* = @intCast(s.step_map.getIndex(dep_step).?); | |
| 423 | 509 | break :d try wc.dedupeDeps(deps); |
| 424 | 510 | }; |
| 425 | 511 | |
| 426 | try wc.steps.ensureTotalCapacity(gpa, step_map.entries.capacity); | |
| 512 | try wc.steps.ensureTotalCapacity(gpa, s.step_map.entries.capacity); | |
| 427 | 513 | wc.steps.appendAssumeCapacity(.{ |
| 428 | 514 | .name = try wc.addString(step.name), |
| 429 | 515 | .owner = try s.builderToPackage(step.owner), |
| ... | ... | @@ -613,7 +699,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { |
| 613 | 699 | .emitted_pdb = try s.addOptionalLazyPathEnum(ia.emitted_pdb), |
| 614 | 700 | .h_dir = try addInstallDir(wc, ia.h_dir), |
| 615 | 701 | .emitted_h = try s.addOptionalLazyPathEnum(ia.emitted_h), |
| 616 | .artifact = stepIndex(&step_map, &ia.artifact.step), | |
| 702 | .artifact = s.stepIndex(&ia.artifact.step), | |
| 617 | 703 | }))); |
| 618 | 704 | }, |
| 619 | 705 | .install_file => @panic("TODO"), |
| ... | ... | @@ -688,7 +774,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { |
| 688 | 774 | } |
| 689 | 775 | |
| 690 | 776 | try wc.write(writer, .{ |
| 691 | .default_step = stepIndex(&step_map, b.default_step), | |
| 777 | .default_step = s.stepIndex(b.default_step), | |
| 692 | 778 | }); |
| 693 | 779 | } |
| 694 | 780 | |
| ... | ... | @@ -714,10 +800,6 @@ fn addInstallDir(wc: *Configuration.Wip, install_dir: ?std.Build.InstallDir) !Co |
| 714 | 800 | } |
| 715 | 801 | } |
| 716 | 802 | |
| 717 | fn stepIndex(step_map: *const std.AutoArrayHashMapUnmanaged(*Step, void), step: *Step) Configuration.Step.Index { | |
| 718 | return @enumFromInt(step_map.getIndex(step).?); | |
| 719 | } | |
| 720 | ||
| 721 | 803 | /// If the given `Step` is a `Step.Compile`, adds any dependencies for that step which |
| 722 | 804 | /// are implied by the module graph rooted at `step.cast(Step.Compile).?.root_module`. |
| 723 | 805 | fn createModuleDependenciesForStep(step: *Step) Allocator.Error!void { |
lib/std/Build/Module.zig+2-12| ... | ... | @@ -73,18 +73,8 @@ pub const SystemLib = struct { |
| 73 | 73 | preferred_link_mode: std.builtin.LinkMode, |
| 74 | 74 | search_strategy: SystemLib.SearchStrategy, |
| 75 | 75 | |
| 76 | pub const UsePkgConfig = enum { | |
| 77 | /// Don't use pkg-config, just pass -lfoo where foo is name. | |
| 78 | no, | |
| 79 | /// Try to get information on how to link the library from pkg-config. | |
| 80 | /// If that fails, fall back to passing -lfoo where foo is name. | |
| 81 | yes, | |
| 82 | /// Try to get information on how to link the library from pkg-config. | |
| 83 | /// If that fails, error out. | |
| 84 | force, | |
| 85 | }; | |
| 86 | ||
| 87 | pub const SearchStrategy = enum { paths_first, mode_first, no_fallback }; | |
| 76 | pub const UsePkgConfig = std.Build.Configuration.SystemLib.UsePkgConfig; | |
| 77 | pub const SearchStrategy = std.Build.Configuration.SystemLib.SearchStrategy; | |
| 88 | 78 | }; |
| 89 | 79 | |
| 90 | 80 | pub const CSourceLanguage = enum { |
lib/std/lang.zig+1-1| ... | ... | @@ -873,7 +873,7 @@ pub const OutputMode = enum { |
| 873 | 873 | |
| 874 | 874 | /// This data structure is used by the Zig language code generation and |
| 875 | 875 | /// therefore must be kept in sync with the compiler implementation. |
| 876 | pub const LinkMode = enum { | |
| 876 | pub const LinkMode = enum(u1) { | |
| 877 | 877 | static, |
| 878 | 878 | dynamic, |
| 879 | 879 | }; |
lib/std/zig/Configuration.zig+194-34| ... | ... | @@ -1071,9 +1071,6 @@ pub const Package = struct { |
| 1071 | 1071 | |
| 1072 | 1072 | /// Trailing: |
| 1073 | 1073 | /// * frameworks: FlagsPrefixedList(FrameworkFlags), // if flag is set |
| 1074 | /// * include_dirs: UnionList(IncludeDir), // if flag is set | |
| 1075 | /// * rpaths: UnionList(RPath), // if flag is set | |
| 1076 | /// * link_objects: UnionList(LinkObject), // if flag is set | |
| 1077 | 1074 | pub const Module = struct { |
| 1078 | 1075 | flags: Flags, |
| 1079 | 1076 | flags2: Flags2, |
| ... | ... | @@ -1084,6 +1081,9 @@ pub const Module = struct { |
| 1084 | 1081 | c_macros: Storage.FlagLengthPrefixedList(.flags, .c_macros, String), |
| 1085 | 1082 | lib_paths: Storage.FlagLengthPrefixedList(.flags, .lib_paths, LazyPath), |
| 1086 | 1083 | export_symbol_names: Storage.FlagLengthPrefixedList(.flags, .export_symbol_names, String), |
| 1084 | include_dirs: Storage.UnionList(.flags, .include_dirs, IncludeDir), | |
| 1085 | rpaths: Storage.UnionList(.flags, .rpaths, RPath), | |
| 1086 | link_objects: Storage.UnionList(.flags, .link_objects, LinkObject), | |
| 1087 | 1087 | |
| 1088 | 1088 | pub const Optimize = enum(u3) { |
| 1089 | 1089 | debug, |
| ... | ... | @@ -1204,7 +1204,7 @@ pub const Module = struct { |
| 1204 | 1204 | static_path: LazyPath, |
| 1205 | 1205 | /// Always `Step.Tag.compile`. |
| 1206 | 1206 | other_step: Step.Index, |
| 1207 | system_lib: SystemLib, | |
| 1207 | system_lib: SystemLib.Index, | |
| 1208 | 1208 | assembly_file: LazyPath, |
| 1209 | 1209 | c_source_file: CSourceFile.Index, |
| 1210 | 1210 | c_source_files: CSourceFiles.Index, |
| ... | ... | @@ -1328,8 +1328,18 @@ pub const SystemLib = struct { |
| 1328 | 1328 | _, |
| 1329 | 1329 | }; |
| 1330 | 1330 | |
| 1331 | pub const UsePkgConfig = enum(u2) { no, yes, force }; | |
| 1332 | pub const LinkMode = enum { static, dynamic }; | |
| 1331 | pub const UsePkgConfig = enum(u2) { | |
| 1332 | /// Don't use pkg-config, just pass -lfoo where foo is name. | |
| 1333 | no, | |
| 1334 | /// Try to get information on how to link the library from pkg-config. | |
| 1335 | /// If that fails, fall back to passing -lfoo where foo is name. | |
| 1336 | yes, | |
| 1337 | /// Try to get information on how to link the library from pkg-config. | |
| 1338 | /// If that fails, error out. | |
| 1339 | force, | |
| 1340 | }; | |
| 1341 | ||
| 1342 | pub const LinkMode = std.builtin.LinkMode; | |
| 1333 | 1343 | |
| 1334 | 1344 | pub const Flags = packed struct(u32) { |
| 1335 | 1345 | needed: bool, |
| ... | ... | @@ -1337,18 +1347,19 @@ pub const SystemLib = struct { |
| 1337 | 1347 | use_pkg_config: UsePkgConfig, |
| 1338 | 1348 | preferred_link_mode: LinkMode, |
| 1339 | 1349 | search_strategy: SearchStrategy, |
| 1350 | _: u25 = 0, | |
| 1340 | 1351 | }; |
| 1341 | 1352 | |
| 1342 | 1353 | pub const SearchStrategy = enum(u2) { paths_first, mode_first, no_fallback }; |
| 1343 | 1354 | }; |
| 1344 | 1355 | |
| 1345 | 1356 | /// Trailing: |
| 1346 | /// * flag: String, // for each flags_len | |
| 1357 | /// * arg: String, // for each args_len | |
| 1347 | 1358 | /// * sub_path: String, // for each files_len |
| 1348 | 1359 | pub const CSourceFiles = struct { |
| 1360 | flags: Flags, | |
| 1349 | 1361 | root: LazyPath, |
| 1350 | 1362 | files_len: u32, |
| 1351 | flags: Flags, | |
| 1352 | 1363 | |
| 1353 | 1364 | pub const Index = enum(u32) { |
| 1354 | 1365 | _, |
| ... | ... | @@ -1356,16 +1367,16 @@ pub const CSourceFiles = struct { |
| 1356 | 1367 | |
| 1357 | 1368 | pub const Flags = packed struct(u32) { |
| 1358 | 1369 | /// C compiler CLI flags. |
| 1359 | flags_len: u29, | |
| 1370 | args_len: u29, | |
| 1360 | 1371 | lang: OptionalCSourceLanguage, |
| 1361 | 1372 | }; |
| 1362 | 1373 | }; |
| 1363 | 1374 | |
| 1364 | 1375 | /// Trailing: |
| 1365 | /// * flag: String, // for each flags_len | |
| 1376 | /// * arg: String, // for each args_len | |
| 1366 | 1377 | pub const CSourceFile = struct { |
| 1367 | file: LazyPath, | |
| 1368 | 1378 | flags: Flags, |
| 1379 | file: LazyPath, | |
| 1369 | 1380 | |
| 1370 | 1381 | pub const Index = enum(u32) { |
| 1371 | 1382 | _, |
| ... | ... | @@ -1373,11 +1384,24 @@ pub const CSourceFile = struct { |
| 1373 | 1384 | |
| 1374 | 1385 | pub const Flags = packed struct(u32) { |
| 1375 | 1386 | /// C compiler CLI flags. |
| 1376 | flags_len: u29, | |
| 1387 | args_len: u29, | |
| 1377 | 1388 | lang: OptionalCSourceLanguage, |
| 1378 | 1389 | }; |
| 1379 | 1390 | }; |
| 1380 | 1391 | |
| 1392 | /// Trailing: | |
| 1393 | /// * arg: String, // for each args_len | |
| 1394 | /// * include_path: String, // for each include_paths_len | |
| 1395 | pub const RcSourceFile = struct { | |
| 1396 | file: LazyPath, | |
| 1397 | args_len: u32, | |
| 1398 | include_paths_len: u32, | |
| 1399 | ||
| 1400 | pub const Index = enum(u32) { | |
| 1401 | _, | |
| 1402 | }; | |
| 1403 | }; | |
| 1404 | ||
| 1381 | 1405 | pub const OptionalCSourceLanguage = enum(u3) { |
| 1382 | 1406 | c, |
| 1383 | 1407 | cpp, |
| ... | ... | @@ -1386,29 +1410,17 @@ pub const OptionalCSourceLanguage = enum(u3) { |
| 1386 | 1410 | assembly, |
| 1387 | 1411 | assembly_with_preprocessor, |
| 1388 | 1412 | default, |
| 1389 | }; | |
| 1390 | 1413 | |
| 1391 | pub const RcSourceFile = struct { | |
| 1392 | file: LazyPath, | |
| 1393 | /// Any option that rc.exe accepts will work here, with the exception of: | |
| 1394 | /// - `/fo`: The output filename is set by the build system | |
| 1395 | /// - `/p`: Only running the preprocessor is not supported in this context | |
| 1396 | /// - `/:no-preprocess` (non-standard option): Not supported in this context | |
| 1397 | /// - Any MUI-related option | |
| 1398 | /// https://learn.microsoft.com/en-us/windows/win32/menurc/using-rc-the-rc-command-line- | |
| 1399 | /// | |
| 1400 | /// Implicitly defined options: | |
| 1401 | /// /x (ignore the INCLUDE environment variable) | |
| 1402 | /// /D_DEBUG or /DNDEBUG depending on the optimization mode | |
| 1403 | flags: []const []const u8 = &.{}, | |
| 1404 | /// Include paths that may or may not exist yet and therefore need to be | |
| 1405 | /// specified as a LazyPath. Each path will be appended to the flags | |
| 1406 | /// as `/I <resolved path>`. | |
| 1407 | include_paths: []const LazyPath = &.{}, | |
| 1408 | ||
| 1409 | pub const Index = enum(u32) { | |
| 1410 | _, | |
| 1411 | }; | |
| 1414 | pub fn init(x: ?std.Build.Module.CSourceLanguage) @This() { | |
| 1415 | return switch (x orelse return .default) { | |
| 1416 | .c => .c, | |
| 1417 | .cpp => .cpp, | |
| 1418 | .objective_c => .objective_c, | |
| 1419 | .objective_cpp => .objective_cpp, | |
| 1420 | .assembly => .assembly, | |
| 1421 | .assembly_with_preprocessor => .assembly_with_preprocessor, | |
| 1422 | }; | |
| 1423 | } | |
| 1412 | 1424 | }; |
| 1413 | 1425 | |
| 1414 | 1426 | pub const ResolvedTarget = struct { |
| ... | ... | @@ -1691,6 +1703,7 @@ pub const Storage = enum { |
| 1691 | 1703 | enum_optional, |
| 1692 | 1704 | extended, |
| 1693 | 1705 | flag_length_prefixed_list, |
| 1706 | union_list, | |
| 1694 | 1707 | |
| 1695 | 1708 | /// The presence of the field is determined by a boolean within a packed |
| 1696 | 1709 | /// struct. |
| ... | ... | @@ -1769,6 +1782,63 @@ pub const Storage = enum { |
| 1769 | 1782 | }; |
| 1770 | 1783 | } |
| 1771 | 1784 | |
| 1785 | /// `UnionArg` is a tagged union with a small integer for the enum tag. | |
| 1786 | /// | |
| 1787 | /// A field in flags determines whether the metadata is present. | |
| 1788 | /// | |
| 1789 | /// The metadata is bit-packed consecutive packed struct which is the | |
| 1790 | /// `UnionArg` enum tag combined with a "last" marker boolean field. | |
| 1791 | /// When "last" is true, the element is the last one, providing | |
| 1792 | /// the length of the list. | |
| 1793 | /// | |
| 1794 | /// Following is each element of the list; each bitcastable to u32. | |
| 1795 | pub fn UnionList( | |
| 1796 | comptime flags_arg: @EnumLiteral(), | |
| 1797 | comptime flag_arg: @EnumLiteral(), | |
| 1798 | comptime UnionArg: type, | |
| 1799 | ) type { | |
| 1800 | return struct { | |
| 1801 | /// When serializing it is UnionArg slice pointer. | |
| 1802 | /// When deserializing it is extra index of first UnionArg element. | |
| 1803 | data: ?*const anyopaque, | |
| 1804 | len: usize, | |
| 1805 | ||
| 1806 | pub const storage: Storage = .union_list; | |
| 1807 | pub const flags = flags_arg; | |
| 1808 | pub const flag = flag_arg; | |
| 1809 | pub const Union = UnionArg; | |
| 1810 | ||
| 1811 | pub const Tag = @typeInfo(Union).@"union".tag_type.?; | |
| 1812 | pub const MetaInt = @Int(.unsigned, @bitSizeOf(Tag) + 1); | |
| 1813 | pub const Meta = packed struct(MetaInt) { | |
| 1814 | tag: Tag, | |
| 1815 | last: bool, | |
| 1816 | }; | |
| 1817 | ||
| 1818 | /// Valid to call only when serializing. | |
| 1819 | pub fn init(slice: []const Union) @This() { | |
| 1820 | return .{ .data = slice.ptr, .len = slice.len }; | |
| 1821 | } | |
| 1822 | ||
| 1823 | /// Valid to call only when deserializing. | |
| 1824 | pub fn get(this: *const @This(), extra: []const u32) []const u32 { | |
| 1825 | return extra[@intFromPtr(this.data)..][0..this.len]; | |
| 1826 | } | |
| 1827 | ||
| 1828 | /// Valid to call only when deserializing. | |
| 1829 | pub fn tag(this: *const @This(), extra: []const u32, i: usize) Tag { | |
| 1830 | _ = this; | |
| 1831 | _ = extra; | |
| 1832 | _ = i; | |
| 1833 | @panic("TODO implement UnionList.tag"); | |
| 1834 | } | |
| 1835 | ||
| 1836 | fn extraLen(len: usize) usize { | |
| 1837 | return len + (len * @bitSizeOf(Meta) + 31) / 32; | |
| 1838 | } | |
| 1839 | }; | |
| 1840 | } | |
| 1841 | ||
| 1772 | 1842 | pub fn dataLength(buffer: []const u32, i: usize, comptime S: type) usize { |
| 1773 | 1843 | var end = i; |
| 1774 | 1844 | _ = data(buffer, &end, S); |
| ... | ... | @@ -1848,6 +1918,23 @@ pub const Storage = enum { |
| 1848 | 1918 | defer i.* = data_start + len; |
| 1849 | 1919 | return .{ .slice = @ptrCast(buffer[data_start..][0..len]) }; |
| 1850 | 1920 | }, |
| 1921 | .union_list => { | |
| 1922 | const flags = @field(container, @tagName(Field.flags)); | |
| 1923 | const flag = @field(flags, @tagName(Field.flag)); | |
| 1924 | if (!flag) return .{ .data = null, .len = 0 }; | |
| 1925 | const meta_start = i.*; | |
| 1926 | const meta_buffer = buffer[meta_start..]; | |
| 1927 | var len: u32 = 0; | |
| 1928 | var bit_offset: usize = 0; | |
| 1929 | while (true) : (bit_offset += @bitSizeOf(Field.Meta)) { | |
| 1930 | const meta = loadBits(u32, meta_buffer, bit_offset, Field.Meta); | |
| 1931 | len += 1; | |
| 1932 | if (meta.last) break; | |
| 1933 | } | |
| 1934 | const end = meta_start + Field.extraLen(len); | |
| 1935 | i.* = end; | |
| 1936 | return .{ .data = end - len, .len = len }; | |
| 1937 | }, | |
| 1851 | 1938 | }, |
| 1852 | 1939 | }, |
| 1853 | 1940 | .@"extern" => comptime unreachable, |
| ... | ... | @@ -1884,6 +1971,7 @@ pub const Storage = enum { |
| 1884 | 1971 | .auto => switch (Field.storage) { |
| 1885 | 1972 | .flag_optional, .enum_optional, .extended => 1, |
| 1886 | 1973 | .flag_length_prefixed_list => field.slice.len + 1, |
| 1974 | .union_list => Field.extraLen(field.len), | |
| 1887 | 1975 | }, |
| 1888 | 1976 | .@"extern" => comptime unreachable, |
| 1889 | 1977 | }, |
| ... | ... | @@ -1947,6 +2035,33 @@ pub const Storage = enum { |
| 1947 | 2035 | @memcpy(buffer[i + 1 ..][0..len], @as([]const u32, @ptrCast(value.slice))); |
| 1948 | 2036 | return len + 1; |
| 1949 | 2037 | }, |
| 2038 | .union_list => { | |
| 2039 | if (value.len == 0) return 0; | |
| 2040 | const Tag = @typeInfo(Field.Union).@"union".tag_type.?; | |
| 2041 | const slice_ptr: [*]const Field.Union = @ptrCast(@alignCast(value.data)); | |
| 2042 | const slice = slice_ptr[0..value.len]; | |
| 2043 | const meta_buffer = buffer[i..][0 .. (slice.len * @bitSizeOf(Field.Meta) + 31) / 32]; | |
| 2044 | for (slice[0 .. slice.len - 1], 0..) |elem, elem_index| { | |
| 2045 | const union_tag: Tag = elem; | |
| 2046 | storeBits(u32, meta_buffer, elem_index * @bitSizeOf(Field.Meta), @as(Field.Meta, .{ | |
| 2047 | .tag = union_tag, | |
| 2048 | .last = false, | |
| 2049 | })); | |
| 2050 | } else { | |
| 2051 | const elem_index = slice.len - 1; | |
| 2052 | const elem = slice[elem_index]; | |
| 2053 | const union_tag: Tag = elem; | |
| 2054 | storeBits(u32, meta_buffer, elem_index * @bitSizeOf(Field.Meta), @as(Field.Meta, .{ | |
| 2055 | .tag = union_tag, | |
| 2056 | .last = true, | |
| 2057 | })); | |
| 2058 | } | |
| 2059 | var total: usize = meta_buffer.len; | |
| 2060 | for (i + meta_buffer.len.., slice) |elem_index, src| switch (src) { | |
| 2061 | inline else => |x| total += setExtraField(buffer, elem_index, @TypeOf(x), x), | |
| 2062 | }; | |
| 2063 | return total; | |
| 2064 | }, | |
| 1950 | 2065 | }, |
| 1951 | 2066 | }, |
| 1952 | 2067 | .@"extern" => comptime unreachable, |
| ... | ... | @@ -2000,3 +2115,48 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration { |
| 2000 | 2115 | try reader.readVecAll(&vecs); |
| 2001 | 2116 | return result; |
| 2002 | 2117 | } |
| 2118 | ||
| 2119 | pub fn loadBits(comptime Int: type, buffer: []const Int, bit_offset: usize, comptime Result: type) Result { | |
| 2120 | const index = bit_offset / @bitSizeOf(Int); | |
| 2121 | const small_bit_offset = bit_offset % @bitSizeOf(Int); | |
| 2122 | const ResultInt = @Int(.unsigned, @bitSizeOf(Result)); | |
| 2123 | const result: ResultInt = @truncate(buffer[index] >> @intCast(small_bit_offset)); | |
| 2124 | const available_bits = @bitSizeOf(Int) - small_bit_offset; | |
| 2125 | if (available_bits >= @bitSizeOf(ResultInt)) return @bitCast(result); | |
| 2126 | const missing_bits = @bitSizeOf(ResultInt) - available_bits; | |
| 2127 | const upper: ResultInt = @truncate(buffer[index + 1] & ((@as(usize, 1) << @intCast(missing_bits)) - 1)); | |
| 2128 | return @bitCast(result | (upper << @intCast(available_bits))); | |
| 2129 | } | |
| 2130 | ||
| 2131 | pub fn storeBits(comptime Int: type, buffer: []Int, bit_offset: usize, value: anytype) void { | |
| 2132 | const Value = @TypeOf(value); | |
| 2133 | const ValueInt = @Int(.unsigned, @bitSizeOf(Value)); | |
| 2134 | const value_int: ValueInt = @bitCast(value); | |
| 2135 | const index = bit_offset / @bitSizeOf(Int); | |
| 2136 | const small_bit_offset = bit_offset % @bitSizeOf(Int); | |
| 2137 | const available_bits = @bitSizeOf(Int) - small_bit_offset; | |
| 2138 | if (available_bits >= @bitSizeOf(ValueInt)) { | |
| 2139 | buffer[index] &= ~(((@as(Int, 1) << @intCast(@bitSizeOf(Value))) - 1) << @intCast(small_bit_offset)); | |
| 2140 | buffer[index] |= @as(Int, value_int) << @intCast(small_bit_offset); | |
| 2141 | } else { | |
| 2142 | const DoubleInt = @Int(.unsigned, @bitSizeOf(Int) * 2); | |
| 2143 | const ptr: *align(@alignOf(Int)) DoubleInt = @ptrCast(buffer[index..][0..2]); | |
| 2144 | ptr.* &= ~(((@as(DoubleInt, 1) << @intCast(@bitSizeOf(Value))) - 1) << @intCast(small_bit_offset)); | |
| 2145 | ptr.* |= @as(DoubleInt, value_int) << @intCast(small_bit_offset); | |
| 2146 | } | |
| 2147 | } | |
| 2148 | ||
| 2149 | test "loadBits and storeBits" { | |
| 2150 | var buffer: [2]u32 = .{ | |
| 2151 | 0b01111111000000001111111100000000, | |
| 2152 | 0b11111111000000001111111100000100, | |
| 2153 | }; | |
| 2154 | try std.testing.expectEqual(0b100, loadBits(u32, &buffer, 6, u3)); | |
| 2155 | try std.testing.expectEqual(0b100011, loadBits(u32, &buffer, 29, u6)); | |
| 2156 | ||
| 2157 | storeBits(u32, &buffer, 6, @as(u3, 0b010)); | |
| 2158 | storeBits(u32, &buffer, 29, @as(u6, 0b010010)); | |
| 2159 | ||
| 2160 | try std.testing.expectEqual(0b010, loadBits(u32, &buffer, 6, u3)); | |
| 2161 | try std.testing.expectEqual(0b010010, loadBits(u32, &buffer, 29, u6)); | |
| 2162 | } |