diff --git a/build.zig b/build.zig
index 461b9868..b513f1d4 100644
--- a/build.zig
+++ b/build.zig
@@ -4,26 +4,53 @@ pub fn build(b: *std.build.Builder) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
- const arocc_dep = b.anonymousDependency("arocc", @import("arocc/build.zig"), .{
- .target = target,
- .optimize = optimize,
- });
+ const textual = true;
+ if (!textual) {
+ const arocc_dep = b.anonymousDependency("arocc", @import("arocc/build.zig"), .{
+ .target = target,
+ .optimize = optimize,
+ });
- const exe = b.addExecutable(.{
- .name = "universal-headers",
- .root_source_file = .{ .path = "src/main.zig" },
- .target = target,
- .optimize = optimize,
- });
- exe.addModule("arocc", arocc_dep.module("aro"));
- b.installArtifact(exe);
+ const exe = b.addExecutable(.{
+ .name = "universal-headers",
+ .root_source_file = .{ .path = "src/main.zig" },
+ .target = target,
+ .optimize = optimize,
+ });
+ exe.addModule("arocc", arocc_dep.module("aro"));
+ b.installArtifact(exe);
- const run_cmd = b.addRunArtifact(exe);
- run_cmd.step.dependOn(b.getInstallStep());
- if (b.args) |args| {
- run_cmd.addArgs(args);
- }
+ const run_cmd = b.addRunArtifact(exe);
+ run_cmd.step.dependOn(b.getInstallStep());
+ if (b.args) |args| {
+ run_cmd.addArgs(args);
+ }
+
+ const run_step = b.step("run", "Run the app");
+ run_step.dependOn(&run_cmd.step);
+ } else {
+ const addHeaders = b.addExecutable(.{
+ .name = "addHeaders",
+ .root_source_file = .{ .path = "src/textdiff/addHeaders.zig" },
+ .target = target,
+ .optimize = optimize,
+ });
+ b.installArtifact(addHeaders);
- const run_step = b.step("run", "Run the app");
- run_step.dependOn(&run_cmd.step);
+ const outputHeaders = b.addExecutable(.{
+ .name = "outputHeaders",
+ .root_source_file = .{ .path = "src/textdiff/outputHeaders.zig" },
+ .target = target,
+ .optimize = optimize,
+ });
+ b.installArtifact(outputHeaders);
+
+ const testHeaders = b.addExecutable(.{
+ .name = "testHeaders",
+ .root_source_file = .{ .path = "src/textdiff/testHeaders.zig" },
+ .target = target,
+ .optimize = optimize,
+ });
+ b.installArtifact(testHeaders);
+ }
}
diff --git a/src/textdiff/HOWTO.txt b/src/textdiff/HOWTO.txt
new file mode 100644
index 00000000..d9159a2a
--- /dev/null
+++ b/src/textdiff/HOWTO.txt
@@ -0,0 +1,31 @@
+
+zig build
+- should give you (in zig-out/bin): addHeaders, outputHeaders, testHeaders
+- also shells out to diff
+
+
+for the whole thing, run (for me this takes ~30min):
+./src/textdiff/compile.bash headers/*
+
+then to test (takes ~5min):
+./src/textdiff/test.bash headers/*
+
+
+What's going on:
+
+1. addHeaders headers/foo
+- takes files from foo
+- normalizes them into uh_norm
+- for each file:
+ - adds context prefix to each line
+ - outputs to uh_workfile
+ - diffs with file in uh_workspace and modifies uh_workspace
+
+2. outputHeaders uh_headers
+- reads files from uh_workspace and outputs universal headers in uh_headers
+- uses reductions.zig to reduce #if statements
+
+3. testHeaders headers/foo
+- partially evaluates uh_headers for version foo and outputs to uh_test
+- can then diff uh_test uh_norm/foo
+
diff --git a/src/textdiff/addHeaders.zig b/src/textdiff/addHeaders.zig
new file mode 100644
index 00000000..279cf688
--- /dev/null
+++ b/src/textdiff/addHeaders.zig
@@ -0,0 +1,504 @@
+const std = @import("std");
+
+const debug = false;
+
+pub fn main() !void {
+ var arena_allocator = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ const arena = arena_allocator.allocator();
+
+ var args = try std.process.argsWithAllocator(arena);
+
+ {
+ var i: usize = 0;
+ while (args.skip()) {
+ i += 1;
+ }
+
+ if (i != 2) {
+ std.debug.print("usage: addHeaders
\n", .{});
+ std.debug.print("normalizes headers from into uh_norm/\n", .{});
+ std.debug.print("adds headers from uh_norm/ into uh_workspace\n", .{});
+ return;
+ }
+ }
+
+ args = try std.process.argsWithAllocator(arena);
+ _ = args.skip();
+ const headerDir = args.next() orelse return;
+
+ var buf = try arena.alloc(u8, 1000);
+
+ const normalized_dir = try std.fmt.bufPrint(buf, "uh_norm/{s}", .{std.fs.path.basename(headerDir)});
+ std.fs.cwd().makePath(normalized_dir) catch {};
+
+ buf = try arena.alloc(u8, 1000);
+ const versionStr = try std.fmt.bufPrint(buf, "{s}|", .{std.fs.path.basename(headerDir)});
+
+ var dir = try std.fs.cwd().openIterableDir(headerDir, .{});
+ defer dir.close();
+
+ std.fs.cwd().makeDir("uh_workspace") catch {};
+
+ var walker = try dir.walk(arena);
+ while (try walker.next()) |entry| {
+
+ // only process files and sym links - right now we copy the sym links into regular files
+ if (entry.kind != .file and entry.kind != .sym_link) {
+ continue;
+ }
+
+ //if (!std.mem.eql(u8, entry.basename, "ucontext.h")) continue;
+
+ //std.debug.print("entry: base {s} path {s}\n", .{ entry.basename, entry.path });
+
+ // file extension for our sidecar version information
+ const extra = ".uhversion.txt";
+
+ var filepath = try std.fs.path.join(arena, &.{ headerDir, entry.path });
+ var workpath = try std.fs.path.join(arena, &.{ "uh_workspace", entry.path });
+ var normalized_path = try std.fs.path.join(arena, &.{ normalized_dir, entry.path });
+
+ // read all the lines of our work-in-progress file
+ var worklines = std.ArrayList([]const u8).init(arena);
+ {
+ if (debug) std.debug.print("createFile {s}\n", .{workpath});
+ if (std.fs.path.dirname(workpath)) |dirname| {
+ try std.fs.cwd().makePath(dirname);
+ }
+ var file = try std.fs.cwd().createFile(workpath, .{ .read = true, .truncate = false });
+ defer file.close();
+ var contents = try file.reader().readAllAlloc(arena, 100 * 1024 * 1024);
+
+ while (contents.len > 0 and contents[contents.len - 1] == '\n') {
+ contents = contents[0 .. contents.len - 1];
+ }
+
+ if (contents.len > 0) {
+ var it = std.mem.splitScalar(u8, contents, '\n');
+
+ while (it.next()) |line| {
+ try worklines.append(line);
+ }
+ }
+ }
+
+ // read all the lines of our work-in-progress sidecar version file
+ buf = try arena.alloc(u8, 1000);
+ const versionpath = try std.fmt.bufPrint(buf, "{s}{s}", .{ workpath, extra });
+ var versionlines = std.ArrayList([]const u8).init(arena);
+ {
+ var file = try std.fs.cwd().createFile(versionpath, .{ .read = true, .truncate = false });
+ defer file.close();
+ var contents = try file.reader().readAllAlloc(arena, 100 * 1024 * 1024);
+ while (contents.len > 0 and contents[contents.len - 1] == '\n') {
+ contents = contents[0 .. contents.len - 1];
+ }
+
+ if (contents.len > 0) {
+ var it = std.mem.splitScalar(u8, contents, '\n');
+ while (it.next()) |line| {
+ try versionlines.append(line);
+ }
+ }
+ }
+
+ // read all the lines of the new file we are going to merge
+ var filelines = std.ArrayList([]const u8).init(arena);
+ {
+ var file = try std.fs.cwd().openFile(filepath, .{});
+ defer file.close();
+ var contents = try file.reader().readAllAlloc(arena, 100 * 1024 * 1024);
+
+ // filter out comments (both /**/ and // styles)
+ var i: usize = 0;
+ var k: usize = 0;
+ var in_comment = false;
+ while (i < contents.len) {
+ if (i + 1 < contents.len) {
+ if (!in_comment and std.mem.eql(u8, contents[i..][0..2], "/*")) {
+ in_comment = true;
+ i += 2;
+ continue;
+ }
+
+ if (in_comment and std.mem.eql(u8, contents[i..][0..2], "*/")) {
+ in_comment = false;
+ i += 2;
+ continue;
+ }
+
+ if (!in_comment and std.mem.eql(u8, contents[i..][0..2], "//")) {
+ // skip until we get to a newline
+ while (contents[i] != '\n') {
+ i += 1;
+ }
+ continue;
+ }
+ }
+
+ if (!in_comment) {
+ contents[k] = contents[i];
+ k += 1;
+ }
+
+ i += 1;
+ }
+
+ contents.len = k;
+
+ while (contents.len > 0 and contents[contents.len - 1] == '\n') {
+ contents = contents[0 .. contents.len - 1];
+ }
+
+ if (contents.len > 0) {
+ var it = std.mem.splitScalar(u8, contents, '\n');
+ while (it.next()) |line| {
+ // normalize whitespace (replace tabs with spaces)
+ buf = try arena.alloc(u8, line.len);
+ _ = std.mem.replace(u8, line, "\t", " ", buf);
+
+ // filter out empty lines
+ var empty = true;
+ for (buf) |ch| {
+ if (ch != ' ') {
+ empty = false;
+ break;
+ }
+ }
+
+ if (!empty) {
+ try filelines.append(buf);
+ }
+ }
+ }
+
+ // write out normalized file back to disk for debugging
+ {
+ if (std.fs.path.dirname(normalized_path)) |dirname| {
+ try std.fs.cwd().makePath(dirname);
+ }
+ var nfile = try std.fs.cwd().createFile(normalized_path, .{});
+ defer nfile.close();
+ var writer = nfile.writer();
+ for (filelines.items) |line| {
+ try writer.print("{s}\n", .{line});
+ }
+ }
+ }
+
+ // first add context to the new file
+ // - this prepends each line with a hash value
+ // - solves diff problems later by keeping #if-#endif blocks and comment blocks together
+ try addContext(arena, &filelines);
+
+ // write out the new file with added context to a temp file
+ {
+ var file = try std.fs.cwd().createFile("uh_workfile", .{});
+ defer file.close();
+ var writer = file.writer();
+ for (filelines.items) |line| {
+ try writer.print("{s}\n", .{line});
+ }
+ }
+
+ //std.debug.print("filepath: {s}, workpath: {s}\n", .{ filepath, workpath });
+
+ // run diff and get the output
+ var diff_stdout = std.ArrayList(u8).init(arena);
+ var diff_stderr = std.ArrayList(u8).init(arena);
+ var diff_child = std.process.Child.init(&.{ "diff", "-wdN", workpath, "uh_workfile" }, arena);
+ diff_child.stdout_behavior = .Pipe;
+ diff_child.stderr_behavior = .Pipe;
+ try diff_child.spawn();
+ try diff_child.collectOutput(&diff_stdout, &diff_stderr, 20 * 1024 * 1024);
+ _ = try diff_child.wait();
+
+ //std.debug.print("diff says:\n{s}\n", .{diff_stdout.items});
+
+ // worklines has all lines accumulated from headers so far
+ // versionlines has versions for all lines in worklines
+ // filelines has new header lines
+
+ // go through diff output and adjust worklines and versionlines
+ var line_adj: isize = 0;
+ var ignore: usize = 0;
+ var last_line: usize = 0;
+
+ var it = std.mem.splitScalar(u8, diff_stdout.items, '\n');
+ while (it.next()) |line| {
+ if (ignore > 0) {
+ if (debug) std.debug.print("ignore {d} {s}\n", .{ ignore, line });
+ ignore -= 1;
+ continue;
+ }
+
+ if (std.mem.eql(u8, line, "")) {
+ // diff might be empty or end with an empty line
+ } else if (std.mem.indexOfScalar(u8, line, 'a')) |p| {
+ const before = line[0..p];
+ const after = line[p + 1 ..];
+ const addafter = try std.fmt.parseInt(usize, before, 10);
+ var start: usize = undefined;
+ var end: usize = undefined;
+ if (std.mem.indexOfScalar(u8, after, ',')) |pc| {
+ start = try std.fmt.parseInt(usize, after[0..pc], 10);
+ end = try std.fmt.parseInt(usize, after[pc + 1 ..], 10);
+ } else {
+ start = try std.fmt.parseInt(usize, after, 10);
+ end = start;
+ }
+
+ start -= 1;
+
+ if (debug) std.debug.print("diff a says {s} -> {d}-{d}\n", .{ line, start, end });
+
+ // from line_adj to addafter, the lines were the same, so add the version
+ for (last_line..@intCast(line_adj + @as(isize, @intCast(addafter)))) |i| {
+ const old = versionlines.items[i];
+ buf = try arena.alloc(u8, old.len + versionStr.len);
+ versionlines.items[i] = try std.fmt.bufPrint(buf, "{s}{s}", .{ old, versionStr });
+ }
+
+ // add lines start..end from new header after line addafter
+ const where: usize = @intCast(line_adj + @as(isize, @intCast(addafter)));
+ try worklines.insertSlice(where, filelines.items[start..end]);
+ //std.debug.print("versionlines.len {d}\n", .{versionlines.items.len});
+ for (0..end - start) |_| {
+ try versionlines.insert(where, versionStr);
+ }
+
+ //std.debug.print("versionlines.len {d}\n", .{versionlines.items.len});
+
+ last_line = where + end - start;
+ line_adj += @intCast(end - start);
+ ignore = end - start;
+ } else if (std.mem.indexOfScalar(u8, line, 'c')) |p| {
+ var start1: usize = undefined;
+ var end1: usize = undefined;
+ var start2: usize = undefined;
+ var end2: usize = undefined;
+
+ const before = line[0..p];
+ if (std.mem.indexOfScalar(u8, before, ',')) |pc| {
+ start1 = try std.fmt.parseInt(usize, before[0..pc], 10);
+ end1 = try std.fmt.parseInt(usize, before[pc + 1 ..], 10);
+ } else {
+ start1 = try std.fmt.parseInt(usize, before, 10);
+ end1 = start1;
+ }
+ start1 -= 1;
+
+ const after = line[p + 1 ..];
+ if (std.mem.indexOfScalar(u8, after, ',')) |pc| {
+ start2 = try std.fmt.parseInt(usize, after[0..pc], 10);
+ end2 = try std.fmt.parseInt(usize, after[pc + 1 ..], 10);
+ } else {
+ start2 = try std.fmt.parseInt(usize, after, 10);
+ end2 = start2;
+ }
+ start2 -= 1;
+
+ if (debug) std.debug.print("diff c says {s} -> {d}-{d} to {d}-{d}\n", .{ line, start1, end1, start2, end2 });
+
+ // from line_adj to start1, the lines were the same, so add the version
+ for (last_line..@intCast(line_adj + @as(isize, @intCast(start1)))) |i| {
+ const old = versionlines.items[i];
+ buf = try arena.alloc(u8, old.len + versionStr.len);
+ versionlines.items[i] = try std.fmt.bufPrint(buf, "{s}{s}", .{ old, versionStr });
+ }
+
+ const where: usize = @intCast(line_adj + @as(isize, @intCast(end1)));
+ try worklines.insertSlice(where, filelines.items[start2..end2]);
+ for (0..end2 - start2) |_| {
+ try versionlines.insert(where, versionStr);
+ }
+ last_line = where + end2 - start2;
+ line_adj += @intCast(end2 - start2);
+ ignore = end1 - start1 + end2 - start2 + 1;
+ //std.debug.print("setting ignore to {d} {d} {d} {d} {d}\n", .{ ignore, start1, end1, start2, end2 });
+ } else if (std.mem.indexOfScalar(u8, line, 'd')) |p| {
+ const before = line[0..p];
+
+ var start: usize = undefined;
+ var end: usize = undefined;
+ if (std.mem.indexOfScalar(u8, before, ',')) |pc| {
+ start = try std.fmt.parseInt(usize, before[0..pc], 10);
+ end = try std.fmt.parseInt(usize, before[pc + 1 ..], 10);
+ } else {
+ start = try std.fmt.parseInt(usize, before, 10);
+ end = start;
+ }
+
+ start -= 1;
+
+ if (debug) std.debug.print("diff d says {s} -> {d}-{d}\n", .{ line, start, end });
+
+ for (last_line..@intCast(line_adj + @as(isize, @intCast(start)))) |i| {
+ const old = versionlines.items[i];
+ buf = try arena.alloc(u8, old.len + versionStr.len);
+ versionlines.items[i] = try std.fmt.bufPrint(buf, "{s}{s}", .{ old, versionStr });
+ }
+
+ // we just skip over the lines
+ ignore = end - start;
+ last_line = @intCast(line_adj + @as(isize, @intCast(end)));
+ } else {
+ //std.debug.print("diff says {s}\n", .{line});
+ return error.asdf;
+ }
+ }
+
+ // from line_adj to the end, the lines must have been the same
+ //std.debug.print("last_line {d} {d}\n", .{ last_line, versionlines.items.len });
+ for (last_line..versionlines.items.len) |i| {
+ const old = versionlines.items[i];
+ buf = try arena.alloc(u8, old.len + versionStr.len);
+ versionlines.items[i] = try std.fmt.bufPrint(buf, "{s}{s}", .{ old, versionStr });
+ }
+
+ // write out work-in-progress file back to disk
+ {
+ var file = try std.fs.cwd().createFile(workpath, .{});
+ defer file.close();
+ var writer = file.writer();
+ for (worklines.items) |line| {
+ try writer.print("{s}\n", .{line});
+ }
+ }
+
+ // write out work-in-progress sidecar version file back to disk
+ {
+ var file = try std.fs.cwd().createFile(versionpath, .{});
+ defer file.close();
+ var writer = file.writer();
+ for (versionlines.items) |line| {
+ try writer.print("{s}\n", .{line});
+ }
+ }
+ }
+}
+
+// Prepend each line of this file with a hash to prevent the diff from splitting #if/#endif into separate versions
+pub fn addContext(arena: std.mem.Allocator, lines: *std.ArrayList([]const u8)) !void {
+ var seen_contexts = std.ArrayList(u32).init(arena);
+ var context = std.ArrayList(u32).init(arena);
+ try context.append(0);
+ var in_comment: bool = false;
+ for (lines.items, 0..) |line, i| {
+ if ((i + 1) == lines.items.len and std.mem.eql(u8, line, "")) {
+ // don't add a line after last newline
+ break;
+ }
+
+ var pop_context: bool = false;
+
+ var com = in_comment;
+ if (!in_comment and std.mem.indexOf(u8, line, "/*") != null and std.mem.indexOf(u8, line, "*/") == null) {
+ in_comment = true;
+ } else if (in_comment and std.mem.indexOf(u8, line, "/*") == null and std.mem.indexOf(u8, line, "*/") != null) {
+ in_comment = false; // next line will be out of comment
+ pop_context = true;
+ }
+
+ if (!com) {
+ // could be spaces between # and directive
+ var trimmed = std.mem.trimLeft(u8, line, " ");
+ if (std.mem.startsWith(u8, trimmed, "#")) {
+ trimmed = trimmed[1..];
+ trimmed = std.mem.trimLeft(u8, trimmed, " ");
+ if (std.mem.startsWith(u8, trimmed, "if")) {
+ var ctx = newContext(lines.items, i, context.items[context.items.len - 1]);
+ for (seen_contexts.items) |sc| {
+ if (ctx == sc) {
+ ctx += 1;
+ }
+ }
+ try context.append(ctx);
+ try seen_contexts.append(ctx);
+ } else if (std.mem.startsWith(u8, trimmed, "endif")) {
+ pop_context = true;
+ }
+ }
+ }
+
+ if (!com and in_comment) {
+ // just transitioned into a comment
+ // need to context the comments as well otherwise it might break into two pieces
+ var ii = i;
+ const fnv = std.hash.Fnv1a_32;
+ var h = fnv.init();
+ h.value = context.items[context.items.len - 1];
+ while (true) : (ii += 1) {
+ h.update(lines.items[ii]);
+ h.update("1"); // update even on an empty line
+ if (std.mem.indexOf(u8, lines.items[ii], "/*") == null and std.mem.indexOf(u8, lines.items[ii], "*/") != null) {
+ break;
+ }
+ }
+ var ctx = h.final();
+ for (seen_contexts.items) |sc| {
+ if (ctx == sc) {
+ ctx += 1;
+ }
+ }
+ try context.append(ctx);
+ try seen_contexts.append(ctx);
+ }
+
+ var buf = try arena.alloc(u8, 9 + line.len);
+ lines.items[i] = try std.fmt.bufPrint(buf, "{x:0<8} {s}", .{ context.items[context.items.len - 1], line });
+
+ if (pop_context) {
+ _ = context.pop();
+ }
+ }
+}
+
+// We are given the line containing the first #if
+// - hash that line, any #elif, and the #endif line together
+// - must skip over any nested #if blocks (and comments)
+pub fn newContext(lines: [][]const u8, i: usize, ctx: u32) u32 {
+ const fnv = std.hash.Fnv1a_32;
+ var h = fnv.init();
+ h.value = ctx;
+ if (debug) std.debug.print("updating hash: {s}\n", .{lines[i]});
+ h.update(lines[i]);
+ var ii = i + 1;
+ var depth: usize = 0;
+ var in_comment: bool = false;
+ while (ii < lines.len) : (ii += 1) {
+ const line = lines[ii];
+ var com = in_comment;
+ if (!in_comment and std.mem.indexOf(u8, line, "/*") != null and std.mem.indexOf(u8, line, "*/") == null) {
+ in_comment = true;
+ } else if (in_comment and std.mem.indexOf(u8, line, "/*") == null and std.mem.indexOf(u8, line, "*/") != null) {
+ in_comment = false; // next line will be out of comment
+ }
+ if (debug) std.debug.print("{s} {d} {s}\n", .{ if (com) "c" else " ", depth, line });
+ if (com) {
+ continue;
+ }
+ var trimmed = std.mem.trimLeft(u8, line, " ");
+ if (std.mem.startsWith(u8, trimmed, "#")) {
+ trimmed = trimmed[1..];
+ trimmed = std.mem.trimLeft(u8, trimmed, " ");
+ if (std.mem.startsWith(u8, trimmed, "if")) {
+ depth += 1;
+ } else if (std.mem.startsWith(u8, trimmed, "elif")) {
+ if (depth == 0) {
+ if (debug) std.debug.print("updating hash: {s}\n", .{line});
+ h.update(line);
+ }
+ } else if (std.mem.startsWith(u8, trimmed, "endif")) {
+ if (depth == 0) {
+ if (debug) std.debug.print("updating hash: {s}\n", .{line});
+ h.update(line);
+ break;
+ }
+ depth -|= 1;
+ }
+ }
+ }
+
+ return h.final();
+}
diff --git a/src/textdiff/compile.bash b/src/textdiff/compile.bash
new file mode 100755
index 00000000..5b69735b
--- /dev/null
+++ b/src/textdiff/compile.bash
@@ -0,0 +1,32 @@
+
+# example: ./src/textdiff/compile.bash headers/*
+#
+# then run ./src/textdiff/test.bash headers/*
+
+HEADER_LIST="$@"
+
+# check that all headers exist somewhere in reductions.zig - this check is to
+# make sure when new headers are added reductions.zig is updated
+for i in $HEADER_LIST;
+do
+ grep -q `basename $i` src/textdiff/reductions.zig || { echo "couldn't find '`basename $i`' in reductions.zig, is it new?"; exit 1; }
+done
+
+if [ -d uh_workspace ];
+then
+ echo "directory uh_workspace already exists, need to remove it - rm -r uh_* ?"
+ exit 1
+fi
+
+for i in $HEADER_LIST;
+do
+ echo "addHeaders $i"
+ ./zig-out/bin/addHeaders $i || exit 1
+done
+
+
+echo "outputHeaders"
+./zig-out/bin/outputHeaders uh_headers || exit 1
+
+
+exit 0
diff --git a/src/textdiff/outputHeaders.zig b/src/textdiff/outputHeaders.zig
new file mode 100644
index 00000000..872436bd
--- /dev/null
+++ b/src/textdiff/outputHeaders.zig
@@ -0,0 +1,220 @@
+const std = @import("std");
+const reductions = @import("reductions.zig"){};
+
+pub fn main() !void {
+ var arena_allocator = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ const arena = arena_allocator.allocator();
+
+ var args = try std.process.argsWithAllocator(arena);
+
+ {
+ var i: usize = 0;
+ while (args.skip()) {
+ i += 1;
+ }
+
+ if (i != 2 and i != 3) {
+ std.debug.print("usage: outputHeaders [version]\n", .{});
+ std.debug.print("takes headers from uh_workspace and outputs to \n", .{});
+ std.debug.print("if version is given, only output lines matching that version (for testing)\n", .{});
+ return;
+ }
+ }
+
+ args = try std.process.argsWithAllocator(arena);
+ _ = args.skip();
+ const outDir = args.next() orelse return;
+ const versionStr = args.next();
+
+ var dir = try std.fs.cwd().openIterableDir("uh_workspace", .{});
+ defer dir.close();
+
+ var walker = try dir.walk(arena);
+ while (try walker.next()) |entry| {
+ if (entry.kind != .file) {
+ continue;
+ }
+
+ const extra = ".uhversion.txt";
+
+ if (std.mem.endsWith(u8, entry.path, extra)) {
+ continue;
+ }
+
+ //if (!std.mem.eql(u8, entry.basename, "features.h")) continue;
+
+ //std.debug.print("entry: base {s} path {s}\n", .{ entry.basename, entry.path });
+
+ // read work-in-progress file into memory
+ var workpath = try std.fs.path.join(arena, &.{ "uh_workspace", entry.path });
+ var worklines = std.ArrayList([]const u8).init(arena);
+ {
+ var file = try std.fs.cwd().openFile(workpath, .{});
+ defer file.close();
+ var contents = try file.reader().readAllAlloc(arena, 100 * 1024 * 1024);
+ while (contents.len > 0 and contents[contents.len - 1] == '\n') {
+ contents = contents[0 .. contents.len - 1];
+ }
+
+ if (contents.len > 0) {
+ var it = std.mem.splitScalar(u8, contents, '\n');
+ while (it.next()) |line| {
+ try worklines.append(line);
+ }
+ }
+ }
+
+ // read work-in-progress sidecar version file into memory
+ var buf = try arena.alloc(u8, 1000);
+ const versionpath = try std.fmt.bufPrint(buf, "{s}{s}", .{ workpath, extra });
+ var versionlines = std.ArrayList([]const u8).init(arena);
+ {
+ var file = try std.fs.cwd().openFile(versionpath, .{});
+ defer file.close();
+ var contents = try file.reader().readAllAlloc(arena, 100 * 1024 * 1024);
+ while (contents.len > 0 and contents[contents.len - 1] == '\n') {
+ contents = contents[0 .. contents.len - 1];
+ }
+
+ if (contents.len > 0) {
+ var it = std.mem.splitScalar(u8, contents, '\n');
+ while (it.next()) |line| {
+ try versionlines.append(line);
+ }
+ }
+ }
+
+ // make writer to output file that will be our universal header
+ var filepath = try std.fs.path.join(arena, &.{ outDir, entry.path });
+ if (std.fs.path.dirname(filepath)) |dirname| {
+ try std.fs.cwd().makePath(dirname);
+ }
+ //std.debug.print("createFile {s}\n", .{filepath});
+ var outfile = try std.fs.cwd().createFile(filepath, .{});
+ defer outfile.close();
+ var outwriter = outfile.writer();
+
+ if (versionStr) |version| {
+ // this is for debugging
+ for (worklines.items, versionlines.items) |workline, versionline| {
+ if (std.mem.indexOf(u8, versionline, version) != null) {
+ try outwriter.print("{s}\n", .{workline[9..]});
+ }
+ }
+ } else {
+ // output the universal header
+ // - we maintain a stack of the version #if blocks we are inside of
+ // - if the version changes, then either:
+ // - - it is a subset of the previous version, so we can add a new nested #if block
+ // - - it is not a subset, so #endif the block and start a new one
+ var versionstack = std.ArrayList([]const u8).init(arena);
+ for (worklines.items, versionlines.items) |workline, versionline| {
+ if (versionstack.items.len > 0 and std.mem.eql(u8, versionline, versionstack.items[versionstack.items.len - 1])) {
+ // line is a continuation
+ try outwriter.print("{s}\n", .{workline[9..]});
+ } else {
+ // version changed
+
+ // are we changing to a subset?
+ var subset: bool = false;
+ while (versionstack.items.len > 0) {
+ subset = true;
+ var vit = std.mem.splitScalar(u8, versionline, '|');
+ while (vit.next()) |version| {
+ if (std.mem.eql(u8, version, "")) {
+ continue;
+ }
+
+ if (std.mem.indexOf(u8, versionstack.items[versionstack.items.len - 1], version) == null) {
+ subset = false;
+ break;
+ }
+ }
+
+ if (subset) {
+ break;
+ } else {
+ _ = versionstack.pop();
+ try outwriter.print("#endif /*_ZIG_UH_*/\n", .{});
+ }
+ }
+
+ if (versionstack.items.len > 0 and std.mem.eql(u8, versionline, versionstack.items[versionstack.items.len - 1])) {
+ // we popped to an exact match of our version, so can continue without a new #if
+ try outwriter.print("{s}\n", .{workline[9..]});
+ } else {
+
+ // we've put any #endif we need, now start a new #if
+ try outputIfLine(arena, outwriter, versionline);
+
+ try versionstack.append(versionline);
+
+ //for (versionstack.items) |vline| {
+ // try outwriter.print("//vline {s}\n", .{vline});
+ //}
+
+ try outwriter.print("{s}\n", .{workline[9..]});
+ }
+ }
+ }
+
+ while (versionstack.items.len > 0) {
+ _ = versionstack.pop();
+ try outwriter.print("#endif /*_ZIG_UH_*/\n", .{});
+ }
+ }
+ }
+}
+
+pub fn outputIfLine(arena: std.mem.Allocator, writer: anytype, versionline: []const u8) !void {
+ var vit = std.mem.splitScalar(u8, versionline, '|');
+ var versions = std.StringArrayHashMap(void).init(arena);
+ while (vit.next()) |version| {
+ if (std.mem.eql(u8, version, "")) {
+ continue;
+ }
+
+ try versions.put(version, {});
+ }
+
+ var replacements = std.ArrayList([]const u8).init(arena);
+
+ inline for (@typeInfo(@TypeOf(reductions)).Struct.fields) |f| {
+ const field = @field(reductions, f.name);
+ var found_all = true;
+ for (0..field.len - 1) |i| {
+ // are all of this reduction's versions here?
+ if (!versions.contains(field[i])) {
+ found_all = false;
+ break;
+ }
+ }
+
+ if (found_all) {
+ // we can replace all these versions with the reduction
+ for (0..field.len - 1) |i| {
+ _ = versions.orderedRemove(field[i]);
+ }
+
+ try replacements.append(field[field.len - 1]);
+ }
+ }
+
+ try writer.print("#if ", .{});
+ var first_v: bool = true;
+ for (replacements.items) |rep| {
+ if (!first_v) {
+ try writer.print(" OR ", .{});
+ }
+ first_v = false;
+ try writer.print("{s}", .{rep});
+ }
+ for (versions.keys()) |version| {
+ if (!first_v) {
+ try writer.print(" OR ", .{});
+ }
+ first_v = false;
+ try writer.print("defined {s}", .{version});
+ }
+ try writer.print(" OR _ZIG_UH_\n", .{});
+}
diff --git a/src/textdiff/reductions.zig b/src/textdiff/reductions.zig
new file mode 100644
index 00000000..020feccf
--- /dev/null
+++ b/src/textdiff/reductions.zig
@@ -0,0 +1,1352 @@
+/// For each field in this file, if all of the given versions are in the same
+/// #if line, we replace it with the final line
+aarch64_linux_gnu: []const []const u8 = &[_][]const u8{
+ "aarch64_be-linux-gnu.2.32",
+ "aarch64_be-linux-gnu.2.33",
+ "aarch64_be-linux-gnu.2.34",
+ "aarch64_be-linux-gnu.2.35",
+ "aarch64_be-linux-gnu.2.36",
+ "aarch64_be-linux-gnu.2.37",
+ "aarch64_be-linux-gnu.2.38",
+ "aarch64-linux-gnu.2.32",
+ "aarch64-linux-gnu.2.33",
+ "aarch64-linux-gnu.2.34",
+ "aarch64-linux-gnu.2.35",
+ "aarch64-linux-gnu.2.36",
+ "aarch64-linux-gnu.2.37",
+ "aarch64-linux-gnu.2.38",
+ "(defined __aarch64__ AND defined __GLIBC__)", // FIXME
+},
+
+arc_linux_gnu: []const []const u8 = &[_][]const u8{
+ "arc-linux-gnu.2.32",
+ "arc-linux-gnu.2.33",
+ "arc-linux-gnu.2.34",
+ "arc-linux-gnu.2.35",
+ "arc-linux-gnu.2.36",
+ "arc-linux-gnu.2.37",
+ "arc-linux-gnu.2.38",
+ "arc-linux-gnuhf.2.32",
+ "arc-linux-gnuhf.2.33",
+ "arc-linux-gnuhf.2.34",
+ "arc-linux-gnuhf.2.35",
+ "arc-linux-gnuhf.2.36",
+ "arc-linux-gnuhf.2.37",
+ "arc-linux-gnuhf.2.38",
+ "(defined __arc__ AND defined __GLIBC__)", // FIXME
+},
+
+arm_linux_gnu: []const []const u8 = &[_][]const u8{
+ "armeb-linux-gnueabi.2.32",
+ "armeb-linux-gnueabi.2.33",
+ "armeb-linux-gnueabi.2.34",
+ "armeb-linux-gnueabi.2.35",
+ "armeb-linux-gnueabi.2.36",
+ "armeb-linux-gnueabi.2.37",
+ "armeb-linux-gnueabi.2.38",
+ "armeb-linux-gnueabihf.2.32",
+ "armeb-linux-gnueabihf.2.33",
+ "armeb-linux-gnueabihf.2.34",
+ "armeb-linux-gnueabihf.2.35",
+ "armeb-linux-gnueabihf.2.36",
+ "armeb-linux-gnueabihf.2.37",
+ "armeb-linux-gnueabihf.2.38",
+ "arm-linux-gnueabi.2.32",
+ "arm-linux-gnueabi.2.33",
+ "arm-linux-gnueabi.2.34",
+ "arm-linux-gnueabi.2.35",
+ "arm-linux-gnueabi.2.36",
+ "arm-linux-gnueabi.2.37",
+ "arm-linux-gnueabi.2.38",
+ "arm-linux-gnueabihf.2.32",
+ "arm-linux-gnueabihf.2.33",
+ "arm-linux-gnueabihf.2.34",
+ "arm-linux-gnueabihf.2.35",
+ "arm-linux-gnueabihf.2.36",
+ "arm-linux-gnueabihf.2.37",
+ "arm-linux-gnueabihf.2.38",
+ "arm-linux-gnueabihf-v7a.2.32",
+ "arm-linux-gnueabihf-v7a.2.33",
+ "arm-linux-gnueabihf-v7a.2.34",
+ "arm-linux-gnueabihf-v7a.2.35",
+ "arm-linux-gnueabihf-v7a.2.36",
+ "arm-linux-gnueabihf-v7a.2.37",
+ "arm-linux-gnueabihf-v7a.2.38",
+ "arm-linux-gnueabi-v4t.2.32",
+ "arm-linux-gnueabi-v4t.2.33",
+ "arm-linux-gnueabi-v4t.2.34",
+ "arm-linux-gnueabi-v4t.2.35",
+ "arm-linux-gnueabi-v4t.2.36",
+ "arm-linux-gnueabi-v4t.2.37",
+ "arm-linux-gnueabi-v4t.2.38",
+ "(defined __arm__ AND defined __GLIBC__)", // FIXME
+},
+
+csky_linux_gnu: []const []const u8 = &[_][]const u8{
+ "csky-linux-gnuabiv2.2.33",
+ "csky-linux-gnuabiv2.2.34",
+ "csky-linux-gnuabiv2.2.35",
+ "csky-linux-gnuabiv2.2.36",
+ "csky-linux-gnuabiv2.2.37",
+ "csky-linux-gnuabiv2.2.38",
+ "csky-linux-gnuabiv2-soft.2.33",
+ "csky-linux-gnuabiv2-soft.2.34",
+ "csky-linux-gnuabiv2-soft.2.35",
+ "csky-linux-gnuabiv2-soft.2.36",
+ "csky-linux-gnuabiv2-soft.2.37",
+ "csky-linux-gnuabiv2-soft.2.38",
+ "(defined __csky__ AND defined __GLIBC__)", // FIXME
+},
+
+i_linux_gnu: []const []const u8 = &[_][]const u8{
+ "i486-linux-gnu.2.32",
+ "i486-linux-gnu.2.33",
+ "i486-linux-gnu.2.34",
+ "i486-linux-gnu.2.35",
+ "i486-linux-gnu.2.36",
+ "i486-linux-gnu.2.37",
+ "i486-linux-gnu.2.38",
+ "i586-linux-gnu.2.32",
+ "i586-linux-gnu.2.33",
+ "i586-linux-gnu.2.34",
+ "i586-linux-gnu.2.35",
+ "i586-linux-gnu.2.36",
+ "i586-linux-gnu.2.37",
+ "i586-linux-gnu.2.38",
+ "i686-linux-gnu.2.32",
+ "i686-linux-gnu.2.33",
+ "i686-linux-gnu.2.34",
+ "i686-linux-gnu.2.35",
+ "i686-linux-gnu.2.36",
+ "i686-linux-gnu.2.37",
+ "i686-linux-gnu.2.38",
+ "ia64-linux-gnu.2.32",
+ "ia64-linux-gnu.2.33",
+ "ia64-linux-gnu.2.34",
+ "ia64-linux-gnu.2.35",
+ "ia64-linux-gnu.2.36",
+ "ia64-linux-gnu.2.37",
+ "ia64-linux-gnu.2.38",
+ "(defined __ISOME__ AND defined __GLIBC__)", // FIXME
+},
+
+m68k_linux_gnu: []const []const u8 = &[_][]const u8{
+ "m68k-linux-gnu.2.32",
+ "m68k-linux-gnu.2.33",
+ "m68k-linux-gnu.2.34",
+ "m68k-linux-gnu.2.35",
+ "m68k-linux-gnu.2.36",
+ "m68k-linux-gnu.2.37",
+ "m68k-linux-gnu.2.38",
+ "(defined __M68K__ AND defined __GLIBC__)", // FIXME
+},
+
+mips64_linux_gnu: []const []const u8 = &[_][]const u8{
+ "mips64el-linux-gnu-n32.2.32",
+ "mips64el-linux-gnu-n32.2.33",
+ "mips64el-linux-gnu-n32.2.34",
+ "mips64el-linux-gnu-n32.2.35",
+ "mips64el-linux-gnu-n32.2.36",
+ "mips64el-linux-gnu-n32.2.37",
+ "mips64el-linux-gnu-n32.2.38",
+ "mips64el-linux-gnu-n32-nan2008.2.32",
+ "mips64el-linux-gnu-n32-nan2008.2.33",
+ "mips64el-linux-gnu-n32-nan2008.2.34",
+ "mips64el-linux-gnu-n32-nan2008.2.35",
+ "mips64el-linux-gnu-n32-nan2008.2.36",
+ "mips64el-linux-gnu-n32-nan2008.2.37",
+ "mips64el-linux-gnu-n32-nan2008.2.38",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.32",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.33",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.34",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.35",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.36",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.37",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.38",
+ "mips64el-linux-gnu-n32-soft.2.32",
+ "mips64el-linux-gnu-n32-soft.2.33",
+ "mips64el-linux-gnu-n32-soft.2.34",
+ "mips64el-linux-gnu-n32-soft.2.35",
+ "mips64el-linux-gnu-n32-soft.2.36",
+ "mips64el-linux-gnu-n32-soft.2.37",
+ "mips64el-linux-gnu-n32-soft.2.38",
+ "mips64el-linux-gnu-n64.2.32",
+ "mips64el-linux-gnu-n64.2.33",
+ "mips64el-linux-gnu-n64.2.34",
+ "mips64el-linux-gnu-n64.2.35",
+ "mips64el-linux-gnu-n64.2.36",
+ "mips64el-linux-gnu-n64.2.37",
+ "mips64el-linux-gnu-n64.2.38",
+ "mips64el-linux-gnu-n64-nan2008.2.32",
+ "mips64el-linux-gnu-n64-nan2008.2.33",
+ "mips64el-linux-gnu-n64-nan2008.2.34",
+ "mips64el-linux-gnu-n64-nan2008.2.35",
+ "mips64el-linux-gnu-n64-nan2008.2.36",
+ "mips64el-linux-gnu-n64-nan2008.2.37",
+ "mips64el-linux-gnu-n64-nan2008.2.38",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.32",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.33",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.34",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.35",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.36",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.37",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.38",
+ "mips64el-linux-gnu-n64-soft.2.32",
+ "mips64el-linux-gnu-n64-soft.2.33",
+ "mips64el-linux-gnu-n64-soft.2.34",
+ "mips64el-linux-gnu-n64-soft.2.35",
+ "mips64el-linux-gnu-n64-soft.2.36",
+ "mips64el-linux-gnu-n64-soft.2.37",
+ "mips64el-linux-gnu-n64-soft.2.38",
+ "mips64-linux-gnu-n32.2.32",
+ "mips64-linux-gnu-n32.2.33",
+ "mips64-linux-gnu-n32.2.34",
+ "mips64-linux-gnu-n32.2.35",
+ "mips64-linux-gnu-n32.2.36",
+ "mips64-linux-gnu-n32.2.37",
+ "mips64-linux-gnu-n32.2.38",
+ "mips64-linux-gnu-n32-nan2008.2.32",
+ "mips64-linux-gnu-n32-nan2008.2.33",
+ "mips64-linux-gnu-n32-nan2008.2.34",
+ "mips64-linux-gnu-n32-nan2008.2.35",
+ "mips64-linux-gnu-n32-nan2008.2.36",
+ "mips64-linux-gnu-n32-nan2008.2.37",
+ "mips64-linux-gnu-n32-nan2008.2.38",
+ "mips64-linux-gnu-n32-nan2008-soft.2.32",
+ "mips64-linux-gnu-n32-nan2008-soft.2.33",
+ "mips64-linux-gnu-n32-nan2008-soft.2.34",
+ "mips64-linux-gnu-n32-nan2008-soft.2.35",
+ "mips64-linux-gnu-n32-nan2008-soft.2.36",
+ "mips64-linux-gnu-n32-nan2008-soft.2.37",
+ "mips64-linux-gnu-n32-nan2008-soft.2.38",
+ "mips64-linux-gnu-n32-soft.2.32",
+ "mips64-linux-gnu-n32-soft.2.33",
+ "mips64-linux-gnu-n32-soft.2.34",
+ "mips64-linux-gnu-n32-soft.2.35",
+ "mips64-linux-gnu-n32-soft.2.36",
+ "mips64-linux-gnu-n32-soft.2.37",
+ "mips64-linux-gnu-n32-soft.2.38",
+ "mips64-linux-gnu-n64.2.32",
+ "mips64-linux-gnu-n64.2.33",
+ "mips64-linux-gnu-n64.2.34",
+ "mips64-linux-gnu-n64.2.35",
+ "mips64-linux-gnu-n64.2.36",
+ "mips64-linux-gnu-n64.2.37",
+ "mips64-linux-gnu-n64.2.38",
+ "mips64-linux-gnu-n64-nan2008.2.32",
+ "mips64-linux-gnu-n64-nan2008.2.33",
+ "mips64-linux-gnu-n64-nan2008.2.34",
+ "mips64-linux-gnu-n64-nan2008.2.35",
+ "mips64-linux-gnu-n64-nan2008.2.36",
+ "mips64-linux-gnu-n64-nan2008.2.37",
+ "mips64-linux-gnu-n64-nan2008.2.38",
+ "mips64-linux-gnu-n64-nan2008-soft.2.32",
+ "mips64-linux-gnu-n64-nan2008-soft.2.33",
+ "mips64-linux-gnu-n64-nan2008-soft.2.34",
+ "mips64-linux-gnu-n64-nan2008-soft.2.35",
+ "mips64-linux-gnu-n64-nan2008-soft.2.36",
+ "mips64-linux-gnu-n64-nan2008-soft.2.37",
+ "mips64-linux-gnu-n64-nan2008-soft.2.38",
+ "mips64-linux-gnu-n64-soft.2.32",
+ "mips64-linux-gnu-n64-soft.2.33",
+ "mips64-linux-gnu-n64-soft.2.34",
+ "mips64-linux-gnu-n64-soft.2.35",
+ "mips64-linux-gnu-n64-soft.2.36",
+ "mips64-linux-gnu-n64-soft.2.37",
+ "mips64-linux-gnu-n64-soft.2.38",
+ "(defined __MIPS64__ AND defined __GLIBC__)", // FIXME
+},
+
+mipsel_linux_gnu: []const []const u8 = &[_][]const u8{
+ "mipsel-linux-gnu.2.32",
+ "mipsel-linux-gnu.2.33",
+ "mipsel-linux-gnu.2.34",
+ "mipsel-linux-gnu.2.35",
+ "mipsel-linux-gnu.2.36",
+ "mipsel-linux-gnu.2.37",
+ "mipsel-linux-gnu.2.38",
+ "mipsel-linux-gnu-nan2008.2.32",
+ "mipsel-linux-gnu-nan2008.2.33",
+ "mipsel-linux-gnu-nan2008.2.34",
+ "mipsel-linux-gnu-nan2008.2.35",
+ "mipsel-linux-gnu-nan2008.2.36",
+ "mipsel-linux-gnu-nan2008.2.37",
+ "mipsel-linux-gnu-nan2008.2.38",
+ "mipsel-linux-gnu-nan2008-soft.2.32",
+ "mipsel-linux-gnu-nan2008-soft.2.33",
+ "mipsel-linux-gnu-nan2008-soft.2.34",
+ "mipsel-linux-gnu-nan2008-soft.2.35",
+ "mipsel-linux-gnu-nan2008-soft.2.36",
+ "mipsel-linux-gnu-nan2008-soft.2.37",
+ "mipsel-linux-gnu-nan2008-soft.2.38",
+ "mipsel-linux-gnu-soft.2.32",
+ "mipsel-linux-gnu-soft.2.33",
+ "mipsel-linux-gnu-soft.2.34",
+ "mipsel-linux-gnu-soft.2.35",
+ "mipsel-linux-gnu-soft.2.36",
+ "mipsel-linux-gnu-soft.2.37",
+ "mipsel-linux-gnu-soft.2.38",
+ "mipsisa32r6el-linux-gnu.2.32",
+ "mipsisa32r6el-linux-gnu.2.33",
+ "mipsisa32r6el-linux-gnu.2.34",
+ "mipsisa32r6el-linux-gnu.2.35",
+ "mipsisa32r6el-linux-gnu.2.36",
+ "mipsisa32r6el-linux-gnu.2.37",
+ "mipsisa32r6el-linux-gnu.2.38",
+ "mipsisa64r6el-linux-gnu-n32.2.32",
+ "mipsisa64r6el-linux-gnu-n32.2.33",
+ "mipsisa64r6el-linux-gnu-n32.2.34",
+ "mipsisa64r6el-linux-gnu-n32.2.35",
+ "mipsisa64r6el-linux-gnu-n32.2.36",
+ "mipsisa64r6el-linux-gnu-n32.2.37",
+ "mipsisa64r6el-linux-gnu-n32.2.38",
+ "mipsisa64r6el-linux-gnu-n64.2.32",
+ "mipsisa64r6el-linux-gnu-n64.2.33",
+ "mipsisa64r6el-linux-gnu-n64.2.34",
+ "mipsisa64r6el-linux-gnu-n64.2.35",
+ "mipsisa64r6el-linux-gnu-n64.2.36",
+ "mipsisa64r6el-linux-gnu-n64.2.37",
+ "mipsisa64r6el-linux-gnu-n64.2.38",
+ "(defined __MIPSEL__ AND defined __GLIBC__)", // FIXME
+},
+
+mips_linux_gnu: []const []const u8 = &[_][]const u8{
+ "mips-linux-gnu.2.32",
+ "mips-linux-gnu.2.33",
+ "mips-linux-gnu.2.34",
+ "mips-linux-gnu.2.35",
+ "mips-linux-gnu.2.36",
+ "mips-linux-gnu.2.37",
+ "mips-linux-gnu.2.38",
+ "mips-linux-gnu-nan2008.2.32",
+ "mips-linux-gnu-nan2008.2.33",
+ "mips-linux-gnu-nan2008.2.34",
+ "mips-linux-gnu-nan2008.2.35",
+ "mips-linux-gnu-nan2008.2.36",
+ "mips-linux-gnu-nan2008.2.37",
+ "mips-linux-gnu-nan2008.2.38",
+ "mips-linux-gnu-nan2008-soft.2.32",
+ "mips-linux-gnu-nan2008-soft.2.33",
+ "mips-linux-gnu-nan2008-soft.2.34",
+ "mips-linux-gnu-nan2008-soft.2.35",
+ "mips-linux-gnu-nan2008-soft.2.36",
+ "mips-linux-gnu-nan2008-soft.2.37",
+ "mips-linux-gnu-nan2008-soft.2.38",
+ "mips-linux-gnu-soft.2.32",
+ "mips-linux-gnu-soft.2.33",
+ "mips-linux-gnu-soft.2.34",
+ "mips-linux-gnu-soft.2.35",
+ "mips-linux-gnu-soft.2.36",
+ "mips-linux-gnu-soft.2.37",
+ "mips-linux-gnu-soft.2.38",
+ "(defined __MIPS__ AND defined __GLIBC__)", // FIXME
+},
+
+powerpc64_linux_gnu: []const []const u8 = &[_][]const u8{
+ "powerpc64le-linux-gnu.2.32",
+ "powerpc64le-linux-gnu.2.33",
+ "powerpc64le-linux-gnu.2.34",
+ "powerpc64le-linux-gnu.2.35",
+ "powerpc64le-linux-gnu.2.36",
+ "powerpc64le-linux-gnu.2.37",
+ "powerpc64le-linux-gnu.2.38",
+ "powerpc64-linux-gnu.2.32",
+ "powerpc64-linux-gnu.2.33",
+ "powerpc64-linux-gnu.2.34",
+ "powerpc64-linux-gnu.2.35",
+ "powerpc64-linux-gnu.2.36",
+ "powerpc64-linux-gnu.2.37",
+ "powerpc64-linux-gnu.2.38",
+ "(defined __PPC64__ AND defined __GLIBC__)", // FIXME
+},
+
+powerpc_linux_gnu: []const []const u8 = &[_][]const u8{
+ "powerpc-linux-gnu.2.32",
+ "powerpc-linux-gnu.2.33",
+ "powerpc-linux-gnu.2.34",
+ "powerpc-linux-gnu.2.35",
+ "powerpc-linux-gnu.2.36",
+ "powerpc-linux-gnu.2.37",
+ "powerpc-linux-gnu.2.38",
+ "powerpc-linux-gnu-power4.2.32",
+ "powerpc-linux-gnu-power4.2.33",
+ "powerpc-linux-gnu-power4.2.34",
+ "powerpc-linux-gnu-power4.2.35",
+ "powerpc-linux-gnu-power4.2.36",
+ "powerpc-linux-gnu-power4.2.37",
+ "powerpc-linux-gnu-power4.2.38",
+ "powerpc-linux-gnu-soft.2.32",
+ "powerpc-linux-gnu-soft.2.33",
+ "powerpc-linux-gnu-soft.2.34",
+ "powerpc-linux-gnu-soft.2.35",
+ "powerpc-linux-gnu-soft.2.36",
+ "powerpc-linux-gnu-soft.2.37",
+ "powerpc-linux-gnu-soft.2.38",
+ "(defined __PPC__ AND defined __GLIBC__)", // FIXME
+},
+
+riscv32_linux_gnu: []const []const u8 = &[_][]const u8{
+ "riscv32-linux-gnu-rv32imac-ilp32.2.33",
+ "riscv32-linux-gnu-rv32imac-ilp32.2.34",
+ "riscv32-linux-gnu-rv32imac-ilp32.2.35",
+ "riscv32-linux-gnu-rv32imac-ilp32.2.36",
+ "riscv32-linux-gnu-rv32imac-ilp32.2.37",
+ "riscv32-linux-gnu-rv32imac-ilp32.2.38",
+ "riscv32-linux-gnu-rv32imafdc-ilp32.2.33",
+ "riscv32-linux-gnu-rv32imafdc-ilp32.2.34",
+ "riscv32-linux-gnu-rv32imafdc-ilp32.2.35",
+ "riscv32-linux-gnu-rv32imafdc-ilp32.2.36",
+ "riscv32-linux-gnu-rv32imafdc-ilp32.2.37",
+ "riscv32-linux-gnu-rv32imafdc-ilp32.2.38",
+ "riscv32-linux-gnu-rv32imafdc-ilp32d.2.33",
+ "riscv32-linux-gnu-rv32imafdc-ilp32d.2.34",
+ "riscv32-linux-gnu-rv32imafdc-ilp32d.2.35",
+ "riscv32-linux-gnu-rv32imafdc-ilp32d.2.36",
+ "riscv32-linux-gnu-rv32imafdc-ilp32d.2.37",
+ "riscv32-linux-gnu-rv32imafdc-ilp32d.2.38",
+ "(defined __RISCV32__ AND defined __GLIBC__)", // FIXME
+},
+
+riscv64_linux_gnu: []const []const u8 = &[_][]const u8{
+ "riscv64-linux-gnu-rv64imac-lp64.2.32",
+ "riscv64-linux-gnu-rv64imac-lp64.2.33",
+ "riscv64-linux-gnu-rv64imac-lp64.2.34",
+ "riscv64-linux-gnu-rv64imac-lp64.2.35",
+ "riscv64-linux-gnu-rv64imac-lp64.2.36",
+ "riscv64-linux-gnu-rv64imac-lp64.2.37",
+ "riscv64-linux-gnu-rv64imac-lp64.2.38",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.32",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.33",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.34",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.35",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.36",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.37",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.38",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.32",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.33",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.34",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.35",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.36",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.37",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.38",
+ "(defined __RISCV64__ AND defined __GLIBC__)", // FIXME
+},
+
+s390x_linux_gnu: []const []const u8 = &[_][]const u8{
+ "s390x-linux-gnu.2.32",
+ "s390x-linux-gnu.2.33",
+ "s390x-linux-gnu.2.34",
+ "s390x-linux-gnu.2.35",
+ "s390x-linux-gnu.2.36",
+ "s390x-linux-gnu.2.37",
+ "s390x-linux-gnu.2.38",
+ "(defined __S390X__ AND defined __GLIBC__)", // FIXME
+},
+
+sparc64_linux_gnu: []const []const u8 = &[_][]const u8{
+ "sparc64-linux-gnu.2.32",
+ "sparc64-linux-gnu.2.33",
+ "sparc64-linux-gnu.2.34",
+ "sparc64-linux-gnu.2.35",
+ "sparc64-linux-gnu.2.36",
+ "sparc64-linux-gnu.2.37",
+ "sparc64-linux-gnu.2.38",
+ "(defined __SPARC64__ AND defined __GLIBC__)", // FIXME
+},
+
+sparcv8_linux_gnu: []const []const u8 = &[_][]const u8{
+ "sparcv8-linux-gnu-leon3.2.32",
+ "sparcv8-linux-gnu-leon3.2.33",
+ "sparcv8-linux-gnu-leon3.2.34",
+ "sparcv8-linux-gnu-leon3.2.35",
+ "sparcv8-linux-gnu-leon3.2.36",
+ "sparcv8-linux-gnu-leon3.2.37",
+ "sparcv8-linux-gnu-leon3.2.38",
+ "(defined __SPARCV8__ AND defined __GLIBC__)", // FIXME
+},
+
+sparcv9_linux_gnu: []const []const u8 = &[_][]const u8{
+ "sparcv9-linux-gnu.2.32",
+ "sparcv9-linux-gnu.2.33",
+ "sparcv9-linux-gnu.2.34",
+ "sparcv9-linux-gnu.2.35",
+ "sparcv9-linux-gnu.2.36",
+ "sparcv9-linux-gnu.2.37",
+ "sparcv9-linux-gnu.2.38",
+ "(defined __SPARCV9__ AND defined __GLIBC__)", // FIXME
+},
+
+x86_64_linux_gnu: []const []const u8 = &[_][]const u8{
+ "x86_64-linux-gnu.2.32",
+ "x86_64-linux-gnu.2.33",
+ "x86_64-linux-gnu.2.34",
+ "x86_64-linux-gnu.2.35",
+ "x86_64-linux-gnu.2.36",
+ "x86_64-linux-gnu.2.37",
+ "x86_64-linux-gnu.2.38",
+ "x86_64-linux-gnu-x32.2.32",
+ "x86_64-linux-gnu-x32.2.33",
+ "x86_64-linux-gnu-x32.2.34",
+ "x86_64-linux-gnu-x32.2.35",
+ "x86_64-linux-gnu-x32.2.36",
+ "x86_64-linux-gnu-x32.2.37",
+ "x86_64-linux-gnu-x32.2.38",
+ "(defined __X86_64__ AND defined __GLIBC__)", // FIXME
+},
+
+freebsd_gnu: []const []const u8 = &[_][]const u8{
+ "aarch64-freebsd.12.3-gnu",
+ "aarch64-freebsd.13.1-gnu",
+ "powerpc64-freebsd.12.3-gnu",
+ "powerpc64-freebsd.13.1-gnu",
+ "powerpc64le-freebsd.13.1-gnu",
+ "powerpc-freebsd.12.3-gnu",
+ "powerpc-freebsd.13.1-gnu",
+ "riscv64-freebsd.13.1-gnu",
+ "sparc64-freebsd.12.3-gnu",
+ "x86_64-freebsd.12.3-gnu",
+ "x86_64-freebsd.13.1-gnu",
+ "x86-freebsd.12.3-gnu",
+ "x86-freebsd.13.1-gnu",
+ "(defined __FreeBSD__ AND defined __GLIBC__)", // FIXME
+},
+
+freebsd_12_3: []const []const u8 = &[_][]const u8{
+ "aarch64-freebsd.12.3-gnu",
+ "powerpc64-freebsd.12.3-gnu",
+ "powerpc-freebsd.12.3-gnu",
+ "sparc64-freebsd.12.3-gnu",
+ "x86_64-freebsd.12.3-gnu",
+ "x86-freebsd.12.3-gnu",
+ "(__FreeBSD__ > 1203500 AND __FreeBSD__ < 1204000)",
+},
+
+freebsd_13_1: []const []const u8 = &[_][]const u8{
+ "aarch64-freebsd.13.1-gnu",
+ "powerpc64-freebsd.13.1-gnu",
+ "powerpc64le-freebsd.13.1-gnu",
+ "powerpc-freebsd.13.1-gnu",
+ "riscv64-freebsd.13.1-gnu",
+ "x86_64-freebsd.13.1-gnu",
+ "x86-freebsd.13.1-gnu",
+ "(__FreeBSD__ > 1301000 AND __FreeBSD__ < 1302000)",
+},
+
+macos: []const []const u8 = &[_][]const u8{
+ "aarch64-macos.11-none",
+ "aarch64-macos.12-none",
+ "aarch64-macos.13-none",
+ "x86_64-macos.11-none",
+ "x86_64-macos.12-none",
+ "x86_64-macos.13-none",
+ "defined __MACOS__", // FIXME
+},
+
+musl: []const []const u8 = &[_][]const u8{
+ "aarch64-linux-musl",
+ "arm-linux-musl",
+ "i386-linux-musl",
+ "mips64-linux-musl",
+ "mips-linux-musl",
+ "powerpc64-linux-musl",
+ "powerpc-linux-musl",
+ "riscv64-linux-musl",
+ "x86_64-linux-musl",
+ "defined __MUSL__", // FIXME
+},
+
+gnu_2_32: []const []const u8 = &[_][]const u8{
+ "aarch64_be-linux-gnu.2.32",
+ "aarch64-linux-gnu.2.32",
+ "arc-linux-gnu.2.32",
+ "arc-linux-gnuhf.2.32",
+ "armeb-linux-gnueabi.2.32",
+ "armeb-linux-gnueabihf.2.32",
+ "arm-linux-gnueabi.2.32",
+ "arm-linux-gnueabihf.2.32",
+ "arm-linux-gnueabihf-v7a.2.32",
+ "arm-linux-gnueabi-v4t.2.32",
+ "i486-linux-gnu.2.32",
+ "i586-linux-gnu.2.32",
+ "i686-linux-gnu.2.32",
+ "ia64-linux-gnu.2.32",
+ "m68k-linux-gnu.2.32",
+ "mips64el-linux-gnu-n32.2.32",
+ "mips64el-linux-gnu-n32-nan2008.2.32",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.32",
+ "mips64el-linux-gnu-n32-soft.2.32",
+ "mips64el-linux-gnu-n64.2.32",
+ "mips64el-linux-gnu-n64-nan2008.2.32",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.32",
+ "mips64el-linux-gnu-n64-soft.2.32",
+ "mips64-linux-gnu-n32.2.32",
+ "mips64-linux-gnu-n32-nan2008.2.32",
+ "mips64-linux-gnu-n32-nan2008-soft.2.32",
+ "mips64-linux-gnu-n32-soft.2.32",
+ "mips64-linux-gnu-n64.2.32",
+ "mips64-linux-gnu-n64-nan2008.2.32",
+ "mips64-linux-gnu-n64-nan2008-soft.2.32",
+ "mips64-linux-gnu-n64-soft.2.32",
+ "mipsel-linux-gnu.2.32",
+ "mipsel-linux-gnu-nan2008.2.32",
+ "mipsel-linux-gnu-nan2008-soft.2.32",
+ "mipsel-linux-gnu-soft.2.32",
+ "mipsisa32r6el-linux-gnu.2.32",
+ "mipsisa64r6el-linux-gnu-n32.2.32",
+ "mipsisa64r6el-linux-gnu-n64.2.32",
+ "mips-linux-gnu.2.32",
+ "mips-linux-gnu-nan2008.2.32",
+ "mips-linux-gnu-nan2008-soft.2.32",
+ "mips-linux-gnu-soft.2.32",
+ "powerpc64le-linux-gnu.2.32",
+ "powerpc64-linux-gnu.2.32",
+ "powerpc-linux-gnu.2.32",
+ "powerpc-linux-gnu-power4.2.32",
+ "powerpc-linux-gnu-soft.2.32",
+ "riscv64-linux-gnu-rv64imac-lp64.2.32",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.32",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.32",
+ "s390x-linux-gnu.2.32",
+ "sparc64-linux-gnu.2.32",
+ "sparcv8-linux-gnu-leon3.2.32",
+ "sparcv9-linux-gnu.2.32",
+ "x86_64-linux-gnu.2.32",
+ "x86_64-linux-gnu-x32.2.32",
+ "__GLIBC_MINOR__ == 32",
+},
+
+gnu_2_33: []const []const u8 = &[_][]const u8{
+ "aarch64_be-linux-gnu.2.33",
+ "aarch64-linux-gnu.2.33",
+ "arc-linux-gnu.2.33",
+ "arc-linux-gnuhf.2.33",
+ "armeb-linux-gnueabi.2.33",
+ "armeb-linux-gnueabihf.2.33",
+ "arm-linux-gnueabi.2.33",
+ "arm-linux-gnueabihf.2.33",
+ "arm-linux-gnueabihf-v7a.2.33",
+ "arm-linux-gnueabi-v4t.2.33",
+ "csky-linux-gnuabiv2.2.33",
+ "csky-linux-gnuabiv2-soft.2.33",
+ "i486-linux-gnu.2.33",
+ "i586-linux-gnu.2.33",
+ "i686-linux-gnu.2.33",
+ "ia64-linux-gnu.2.33",
+ "m68k-linux-gnu.2.33",
+ "mips64el-linux-gnu-n32.2.33",
+ "mips64el-linux-gnu-n32-nan2008.2.33",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.33",
+ "mips64el-linux-gnu-n32-soft.2.33",
+ "mips64el-linux-gnu-n64.2.33",
+ "mips64el-linux-gnu-n64-nan2008.2.33",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.33",
+ "mips64el-linux-gnu-n64-soft.2.33",
+ "mips64-linux-gnu-n32.2.33",
+ "mips64-linux-gnu-n32-nan2008.2.33",
+ "mips64-linux-gnu-n32-nan2008-soft.2.33",
+ "mips64-linux-gnu-n32-soft.2.33",
+ "mips64-linux-gnu-n64.2.33",
+ "mips64-linux-gnu-n64-nan2008.2.33",
+ "mips64-linux-gnu-n64-nan2008-soft.2.33",
+ "mips64-linux-gnu-n64-soft.2.33",
+ "mipsel-linux-gnu.2.33",
+ "mipsel-linux-gnu-nan2008.2.33",
+ "mipsel-linux-gnu-nan2008-soft.2.33",
+ "mipsel-linux-gnu-soft.2.33",
+ "mipsisa32r6el-linux-gnu.2.33",
+ "mipsisa64r6el-linux-gnu-n32.2.33",
+ "mipsisa64r6el-linux-gnu-n64.2.33",
+ "mips-linux-gnu.2.33",
+ "mips-linux-gnu-nan2008.2.33",
+ "mips-linux-gnu-nan2008-soft.2.33",
+ "mips-linux-gnu-soft.2.33",
+ "powerpc64le-linux-gnu.2.33",
+ "powerpc64-linux-gnu.2.33",
+ "powerpc-linux-gnu.2.33",
+ "powerpc-linux-gnu-power4.2.33",
+ "powerpc-linux-gnu-soft.2.33",
+ "riscv32-linux-gnu-rv32imac-ilp32.2.33",
+ "riscv32-linux-gnu-rv32imafdc-ilp32.2.33",
+ "riscv32-linux-gnu-rv32imafdc-ilp32d.2.33",
+ "riscv64-linux-gnu-rv64imac-lp64.2.33",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.33",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.33",
+ "s390x-linux-gnu.2.33",
+ "sparc64-linux-gnu.2.33",
+ "sparcv8-linux-gnu-leon3.2.33",
+ "sparcv9-linux-gnu.2.33",
+ "x86_64-linux-gnu.2.33",
+ "x86_64-linux-gnu-x32.2.33",
+ "__GLIBC_MINOR__ == 33",
+},
+
+gnu_2_34: []const []const u8 = &[_][]const u8{
+ "aarch64_be-linux-gnu.2.34",
+ "aarch64-linux-gnu.2.34",
+ "arc-linux-gnu.2.34",
+ "arc-linux-gnuhf.2.34",
+ "armeb-linux-gnueabi.2.34",
+ "armeb-linux-gnueabihf.2.34",
+ "arm-linux-gnueabi.2.34",
+ "arm-linux-gnueabihf.2.34",
+ "arm-linux-gnueabihf-v7a.2.34",
+ "arm-linux-gnueabi-v4t.2.34",
+ "csky-linux-gnuabiv2.2.34",
+ "csky-linux-gnuabiv2-soft.2.34",
+ "i486-linux-gnu.2.34",
+ "i586-linux-gnu.2.34",
+ "i686-linux-gnu.2.34",
+ "ia64-linux-gnu.2.34",
+ "m68k-linux-gnu.2.34",
+ "mips64el-linux-gnu-n32.2.34",
+ "mips64el-linux-gnu-n32-nan2008.2.34",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.34",
+ "mips64el-linux-gnu-n32-soft.2.34",
+ "mips64el-linux-gnu-n64.2.34",
+ "mips64el-linux-gnu-n64-nan2008.2.34",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.34",
+ "mips64el-linux-gnu-n64-soft.2.34",
+ "mips64-linux-gnu-n32.2.34",
+ "mips64-linux-gnu-n32-nan2008.2.34",
+ "mips64-linux-gnu-n32-nan2008-soft.2.34",
+ "mips64-linux-gnu-n32-soft.2.34",
+ "mips64-linux-gnu-n64.2.34",
+ "mips64-linux-gnu-n64-nan2008.2.34",
+ "mips64-linux-gnu-n64-nan2008-soft.2.34",
+ "mips64-linux-gnu-n64-soft.2.34",
+ "mipsel-linux-gnu.2.34",
+ "mipsel-linux-gnu-nan2008.2.34",
+ "mipsel-linux-gnu-nan2008-soft.2.34",
+ "mipsel-linux-gnu-soft.2.34",
+ "mipsisa32r6el-linux-gnu.2.34",
+ "mipsisa64r6el-linux-gnu-n32.2.34",
+ "mipsisa64r6el-linux-gnu-n64.2.34",
+ "mips-linux-gnu.2.34",
+ "mips-linux-gnu-nan2008.2.34",
+ "mips-linux-gnu-nan2008-soft.2.34",
+ "mips-linux-gnu-soft.2.34",
+ "powerpc64le-linux-gnu.2.34",
+ "powerpc64-linux-gnu.2.34",
+ "powerpc-linux-gnu.2.34",
+ "powerpc-linux-gnu-power4.2.34",
+ "powerpc-linux-gnu-soft.2.34",
+ "riscv32-linux-gnu-rv32imac-ilp32.2.34",
+ "riscv32-linux-gnu-rv32imafdc-ilp32.2.34",
+ "riscv32-linux-gnu-rv32imafdc-ilp32d.2.34",
+ "riscv64-linux-gnu-rv64imac-lp64.2.34",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.34",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.34",
+ "s390x-linux-gnu.2.34",
+ "sparc64-linux-gnu.2.34",
+ "sparcv8-linux-gnu-leon3.2.34",
+ "sparcv9-linux-gnu.2.34",
+ "x86_64-linux-gnu.2.34",
+ "x86_64-linux-gnu-x32.2.34",
+ "__GLIBC_MINOR__ == 34",
+},
+
+gnu_2_35: []const []const u8 = &[_][]const u8{
+ "aarch64_be-linux-gnu.2.35",
+ "aarch64-linux-gnu.2.35",
+ "arc-linux-gnu.2.35",
+ "arc-linux-gnuhf.2.35",
+ "armeb-linux-gnueabi.2.35",
+ "armeb-linux-gnueabihf.2.35",
+ "arm-linux-gnueabi.2.35",
+ "arm-linux-gnueabihf.2.35",
+ "arm-linux-gnueabihf-v7a.2.35",
+ "arm-linux-gnueabi-v4t.2.35",
+ "csky-linux-gnuabiv2.2.35",
+ "csky-linux-gnuabiv2-soft.2.35",
+ "i486-linux-gnu.2.35",
+ "i586-linux-gnu.2.35",
+ "i686-linux-gnu.2.35",
+ "ia64-linux-gnu.2.35",
+ "m68k-linux-gnu.2.35",
+ "mips64el-linux-gnu-n32.2.35",
+ "mips64el-linux-gnu-n32-nan2008.2.35",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.35",
+ "mips64el-linux-gnu-n32-soft.2.35",
+ "mips64el-linux-gnu-n64.2.35",
+ "mips64el-linux-gnu-n64-nan2008.2.35",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.35",
+ "mips64el-linux-gnu-n64-soft.2.35",
+ "mips64-linux-gnu-n32.2.35",
+ "mips64-linux-gnu-n32-nan2008.2.35",
+ "mips64-linux-gnu-n32-nan2008-soft.2.35",
+ "mips64-linux-gnu-n32-soft.2.35",
+ "mips64-linux-gnu-n64.2.35",
+ "mips64-linux-gnu-n64-nan2008.2.35",
+ "mips64-linux-gnu-n64-nan2008-soft.2.35",
+ "mips64-linux-gnu-n64-soft.2.35",
+ "mipsel-linux-gnu.2.35",
+ "mipsel-linux-gnu-nan2008.2.35",
+ "mipsel-linux-gnu-nan2008-soft.2.35",
+ "mipsel-linux-gnu-soft.2.35",
+ "mipsisa32r6el-linux-gnu.2.35",
+ "mipsisa64r6el-linux-gnu-n32.2.35",
+ "mipsisa64r6el-linux-gnu-n64.2.35",
+ "mips-linux-gnu.2.35",
+ "mips-linux-gnu-nan2008.2.35",
+ "mips-linux-gnu-nan2008-soft.2.35",
+ "mips-linux-gnu-soft.2.35",
+ "powerpc64le-linux-gnu.2.35",
+ "powerpc64-linux-gnu.2.35",
+ "powerpc-linux-gnu.2.35",
+ "powerpc-linux-gnu-power4.2.35",
+ "powerpc-linux-gnu-soft.2.35",
+ "riscv32-linux-gnu-rv32imac-ilp32.2.35",
+ "riscv32-linux-gnu-rv32imafdc-ilp32.2.35",
+ "riscv32-linux-gnu-rv32imafdc-ilp32d.2.35",
+ "riscv64-linux-gnu-rv64imac-lp64.2.35",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.35",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.35",
+ "s390x-linux-gnu.2.35",
+ "sparc64-linux-gnu.2.35",
+ "sparcv8-linux-gnu-leon3.2.35",
+ "sparcv9-linux-gnu.2.35",
+ "x86_64-linux-gnu.2.35",
+ "x86_64-linux-gnu-x32.2.35",
+ "__GLIBC_MINOR__ == 35",
+},
+
+gnu_2_36: []const []const u8 = &[_][]const u8{
+ "aarch64_be-linux-gnu.2.36",
+ "aarch64-linux-gnu.2.36",
+ "arc-linux-gnu.2.36",
+ "arc-linux-gnuhf.2.36",
+ "armeb-linux-gnueabi.2.36",
+ "armeb-linux-gnueabihf.2.36",
+ "arm-linux-gnueabi.2.36",
+ "arm-linux-gnueabihf.2.36",
+ "arm-linux-gnueabihf-v7a.2.36",
+ "arm-linux-gnueabi-v4t.2.36",
+ "csky-linux-gnuabiv2.2.36",
+ "csky-linux-gnuabiv2-soft.2.36",
+ "i486-linux-gnu.2.36",
+ "i586-linux-gnu.2.36",
+ "i686-linux-gnu.2.36",
+ "ia64-linux-gnu.2.36",
+ "m68k-linux-gnu.2.36",
+ "mips64el-linux-gnu-n32.2.36",
+ "mips64el-linux-gnu-n32-nan2008.2.36",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.36",
+ "mips64el-linux-gnu-n32-soft.2.36",
+ "mips64el-linux-gnu-n64.2.36",
+ "mips64el-linux-gnu-n64-nan2008.2.36",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.36",
+ "mips64el-linux-gnu-n64-soft.2.36",
+ "mips64-linux-gnu-n32.2.36",
+ "mips64-linux-gnu-n32-nan2008.2.36",
+ "mips64-linux-gnu-n32-nan2008-soft.2.36",
+ "mips64-linux-gnu-n32-soft.2.36",
+ "mips64-linux-gnu-n64.2.36",
+ "mips64-linux-gnu-n64-nan2008.2.36",
+ "mips64-linux-gnu-n64-nan2008-soft.2.36",
+ "mips64-linux-gnu-n64-soft.2.36",
+ "mipsel-linux-gnu.2.36",
+ "mipsel-linux-gnu-nan2008.2.36",
+ "mipsel-linux-gnu-nan2008-soft.2.36",
+ "mipsel-linux-gnu-soft.2.36",
+ "mipsisa32r6el-linux-gnu.2.36",
+ "mipsisa64r6el-linux-gnu-n32.2.36",
+ "mipsisa64r6el-linux-gnu-n64.2.36",
+ "mips-linux-gnu.2.36",
+ "mips-linux-gnu-nan2008.2.36",
+ "mips-linux-gnu-nan2008-soft.2.36",
+ "mips-linux-gnu-soft.2.36",
+ "powerpc64le-linux-gnu.2.36",
+ "powerpc64-linux-gnu.2.36",
+ "powerpc-linux-gnu.2.36",
+ "powerpc-linux-gnu-power4.2.36",
+ "powerpc-linux-gnu-soft.2.36",
+ "riscv32-linux-gnu-rv32imac-ilp32.2.36",
+ "riscv32-linux-gnu-rv32imafdc-ilp32.2.36",
+ "riscv32-linux-gnu-rv32imafdc-ilp32d.2.36",
+ "riscv64-linux-gnu-rv64imac-lp64.2.36",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.36",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.36",
+ "s390x-linux-gnu.2.36",
+ "sparc64-linux-gnu.2.36",
+ "sparcv8-linux-gnu-leon3.2.36",
+ "sparcv9-linux-gnu.2.36",
+ "x86_64-linux-gnu.2.36",
+ "x86_64-linux-gnu-x32.2.36",
+ "__GLIBC_MINOR__ == 36",
+},
+
+gnu_2_37: []const []const u8 = &[_][]const u8{
+ "aarch64_be-linux-gnu.2.37",
+ "aarch64-linux-gnu.2.37",
+ "arc-linux-gnu.2.37",
+ "arc-linux-gnuhf.2.37",
+ "armeb-linux-gnueabi.2.37",
+ "armeb-linux-gnueabihf.2.37",
+ "arm-linux-gnueabi.2.37",
+ "arm-linux-gnueabihf.2.37",
+ "arm-linux-gnueabihf-v7a.2.37",
+ "arm-linux-gnueabi-v4t.2.37",
+ "csky-linux-gnuabiv2.2.37",
+ "csky-linux-gnuabiv2-soft.2.37",
+ "i486-linux-gnu.2.37",
+ "i586-linux-gnu.2.37",
+ "i686-linux-gnu.2.37",
+ "ia64-linux-gnu.2.37",
+ "m68k-linux-gnu.2.37",
+ "mips64el-linux-gnu-n32.2.37",
+ "mips64el-linux-gnu-n32-nan2008.2.37",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.37",
+ "mips64el-linux-gnu-n32-soft.2.37",
+ "mips64el-linux-gnu-n64.2.37",
+ "mips64el-linux-gnu-n64-nan2008.2.37",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.37",
+ "mips64el-linux-gnu-n64-soft.2.37",
+ "mips64-linux-gnu-n32.2.37",
+ "mips64-linux-gnu-n32-nan2008.2.37",
+ "mips64-linux-gnu-n32-nan2008-soft.2.37",
+ "mips64-linux-gnu-n32-soft.2.37",
+ "mips64-linux-gnu-n64.2.37",
+ "mips64-linux-gnu-n64-nan2008.2.37",
+ "mips64-linux-gnu-n64-nan2008-soft.2.37",
+ "mips64-linux-gnu-n64-soft.2.37",
+ "mipsel-linux-gnu.2.37",
+ "mipsel-linux-gnu-nan2008.2.37",
+ "mipsel-linux-gnu-nan2008-soft.2.37",
+ "mipsel-linux-gnu-soft.2.37",
+ "mipsisa32r6el-linux-gnu.2.37",
+ "mipsisa64r6el-linux-gnu-n32.2.37",
+ "mipsisa64r6el-linux-gnu-n64.2.37",
+ "mips-linux-gnu.2.37",
+ "mips-linux-gnu-nan2008.2.37",
+ "mips-linux-gnu-nan2008-soft.2.37",
+ "mips-linux-gnu-soft.2.37",
+ "powerpc64le-linux-gnu.2.37",
+ "powerpc64-linux-gnu.2.37",
+ "powerpc-linux-gnu.2.37",
+ "powerpc-linux-gnu-power4.2.37",
+ "powerpc-linux-gnu-soft.2.37",
+ "riscv32-linux-gnu-rv32imac-ilp32.2.37",
+ "riscv32-linux-gnu-rv32imafdc-ilp32.2.37",
+ "riscv32-linux-gnu-rv32imafdc-ilp32d.2.37",
+ "riscv64-linux-gnu-rv64imac-lp64.2.37",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.37",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.37",
+ "s390x-linux-gnu.2.37",
+ "sparc64-linux-gnu.2.37",
+ "sparcv8-linux-gnu-leon3.2.37",
+ "sparcv9-linux-gnu.2.37",
+ "x86_64-linux-gnu.2.37",
+ "x86_64-linux-gnu-x32.2.37",
+ "__GLIBC_MINOR__ == 37",
+},
+
+gnu_2_38: []const []const u8 = &[_][]const u8{
+ "aarch64_be-linux-gnu.2.38",
+ "aarch64-linux-gnu.2.38",
+ "arc-linux-gnu.2.38",
+ "arc-linux-gnuhf.2.38",
+ "armeb-linux-gnueabi.2.38",
+ "armeb-linux-gnueabihf.2.38",
+ "arm-linux-gnueabi.2.38",
+ "arm-linux-gnueabihf.2.38",
+ "arm-linux-gnueabihf-v7a.2.38",
+ "arm-linux-gnueabi-v4t.2.38",
+ "csky-linux-gnuabiv2.2.38",
+ "csky-linux-gnuabiv2-soft.2.38",
+ "i486-linux-gnu.2.38",
+ "i586-linux-gnu.2.38",
+ "i686-linux-gnu.2.38",
+ "ia64-linux-gnu.2.38",
+ "m68k-linux-gnu.2.38",
+ "mips64el-linux-gnu-n32.2.38",
+ "mips64el-linux-gnu-n32-nan2008.2.38",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.38",
+ "mips64el-linux-gnu-n32-soft.2.38",
+ "mips64el-linux-gnu-n64.2.38",
+ "mips64el-linux-gnu-n64-nan2008.2.38",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.38",
+ "mips64el-linux-gnu-n64-soft.2.38",
+ "mips64-linux-gnu-n32.2.38",
+ "mips64-linux-gnu-n32-nan2008.2.38",
+ "mips64-linux-gnu-n32-nan2008-soft.2.38",
+ "mips64-linux-gnu-n32-soft.2.38",
+ "mips64-linux-gnu-n64.2.38",
+ "mips64-linux-gnu-n64-nan2008.2.38",
+ "mips64-linux-gnu-n64-nan2008-soft.2.38",
+ "mips64-linux-gnu-n64-soft.2.38",
+ "mipsel-linux-gnu.2.38",
+ "mipsel-linux-gnu-nan2008.2.38",
+ "mipsel-linux-gnu-nan2008-soft.2.38",
+ "mipsel-linux-gnu-soft.2.38",
+ "mipsisa32r6el-linux-gnu.2.38",
+ "mipsisa64r6el-linux-gnu-n32.2.38",
+ "mipsisa64r6el-linux-gnu-n64.2.38",
+ "mips-linux-gnu.2.38",
+ "mips-linux-gnu-nan2008.2.38",
+ "mips-linux-gnu-nan2008-soft.2.38",
+ "mips-linux-gnu-soft.2.38",
+ "powerpc64le-linux-gnu.2.38",
+ "powerpc64-linux-gnu.2.38",
+ "powerpc-linux-gnu.2.38",
+ "powerpc-linux-gnu-power4.2.38",
+ "powerpc-linux-gnu-soft.2.38",
+ "riscv32-linux-gnu-rv32imac-ilp32.2.38",
+ "riscv32-linux-gnu-rv32imafdc-ilp32.2.38",
+ "riscv32-linux-gnu-rv32imafdc-ilp32d.2.38",
+ "riscv64-linux-gnu-rv64imac-lp64.2.38",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.38",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.38",
+ "s390x-linux-gnu.2.38",
+ "sparc64-linux-gnu.2.38",
+ "sparcv8-linux-gnu-leon3.2.38",
+ "sparcv9-linux-gnu.2.38",
+ "x86_64-linux-gnu.2.38",
+ "x86_64-linux-gnu-x32.2.38",
+ "__GLIBC_MINOR__ == 38",
+},
+
+gnu_not_2_32: []const []const u8 = &[_][]const u8{
+ "aarch64_be-linux-gnu.2.33",
+ "aarch64_be-linux-gnu.2.34",
+ "aarch64_be-linux-gnu.2.35",
+ "aarch64_be-linux-gnu.2.36",
+ "aarch64_be-linux-gnu.2.37",
+ "aarch64_be-linux-gnu.2.38",
+ "aarch64-linux-gnu.2.33",
+ "aarch64-linux-gnu.2.34",
+ "aarch64-linux-gnu.2.35",
+ "aarch64-linux-gnu.2.36",
+ "aarch64-linux-gnu.2.37",
+ "aarch64-linux-gnu.2.38",
+ "arc-linux-gnu.2.33",
+ "arc-linux-gnu.2.34",
+ "arc-linux-gnu.2.35",
+ "arc-linux-gnu.2.36",
+ "arc-linux-gnu.2.37",
+ "arc-linux-gnu.2.38",
+ "arc-linux-gnuhf.2.33",
+ "arc-linux-gnuhf.2.34",
+ "arc-linux-gnuhf.2.35",
+ "arc-linux-gnuhf.2.36",
+ "arc-linux-gnuhf.2.37",
+ "arc-linux-gnuhf.2.38",
+ "armeb-linux-gnueabi.2.33",
+ "armeb-linux-gnueabi.2.34",
+ "armeb-linux-gnueabi.2.35",
+ "armeb-linux-gnueabi.2.36",
+ "armeb-linux-gnueabi.2.37",
+ "armeb-linux-gnueabi.2.38",
+ "armeb-linux-gnueabihf.2.33",
+ "armeb-linux-gnueabihf.2.34",
+ "armeb-linux-gnueabihf.2.35",
+ "armeb-linux-gnueabihf.2.36",
+ "armeb-linux-gnueabihf.2.37",
+ "armeb-linux-gnueabihf.2.38",
+ "arm-linux-gnueabi.2.33",
+ "arm-linux-gnueabi.2.34",
+ "arm-linux-gnueabi.2.35",
+ "arm-linux-gnueabi.2.36",
+ "arm-linux-gnueabi.2.37",
+ "arm-linux-gnueabi.2.38",
+ "arm-linux-gnueabihf.2.33",
+ "arm-linux-gnueabihf.2.34",
+ "arm-linux-gnueabihf.2.35",
+ "arm-linux-gnueabihf.2.36",
+ "arm-linux-gnueabihf.2.37",
+ "arm-linux-gnueabihf.2.38",
+ "arm-linux-gnueabihf-v7a.2.33",
+ "arm-linux-gnueabihf-v7a.2.34",
+ "arm-linux-gnueabihf-v7a.2.35",
+ "arm-linux-gnueabihf-v7a.2.36",
+ "arm-linux-gnueabihf-v7a.2.37",
+ "arm-linux-gnueabihf-v7a.2.38",
+ "arm-linux-gnueabi-v4t.2.33",
+ "arm-linux-gnueabi-v4t.2.34",
+ "arm-linux-gnueabi-v4t.2.35",
+ "arm-linux-gnueabi-v4t.2.36",
+ "arm-linux-gnueabi-v4t.2.37",
+ "arm-linux-gnueabi-v4t.2.38",
+ "i486-linux-gnu.2.33",
+ "i486-linux-gnu.2.34",
+ "i486-linux-gnu.2.35",
+ "i486-linux-gnu.2.36",
+ "i486-linux-gnu.2.37",
+ "i486-linux-gnu.2.38",
+ "i586-linux-gnu.2.33",
+ "i586-linux-gnu.2.34",
+ "i586-linux-gnu.2.35",
+ "i586-linux-gnu.2.36",
+ "i586-linux-gnu.2.37",
+ "i586-linux-gnu.2.38",
+ "i686-linux-gnu.2.33",
+ "i686-linux-gnu.2.34",
+ "i686-linux-gnu.2.35",
+ "i686-linux-gnu.2.36",
+ "i686-linux-gnu.2.37",
+ "i686-linux-gnu.2.38",
+ "ia64-linux-gnu.2.33",
+ "ia64-linux-gnu.2.34",
+ "ia64-linux-gnu.2.35",
+ "ia64-linux-gnu.2.36",
+ "ia64-linux-gnu.2.37",
+ "ia64-linux-gnu.2.38",
+ "m68k-linux-gnu.2.33",
+ "m68k-linux-gnu.2.34",
+ "m68k-linux-gnu.2.35",
+ "m68k-linux-gnu.2.36",
+ "m68k-linux-gnu.2.37",
+ "m68k-linux-gnu.2.38",
+ "mips64el-linux-gnu-n32.2.33",
+ "mips64el-linux-gnu-n32.2.34",
+ "mips64el-linux-gnu-n32.2.35",
+ "mips64el-linux-gnu-n32.2.36",
+ "mips64el-linux-gnu-n32.2.37",
+ "mips64el-linux-gnu-n32.2.38",
+ "mips64el-linux-gnu-n32-nan2008.2.33",
+ "mips64el-linux-gnu-n32-nan2008.2.34",
+ "mips64el-linux-gnu-n32-nan2008.2.35",
+ "mips64el-linux-gnu-n32-nan2008.2.36",
+ "mips64el-linux-gnu-n32-nan2008.2.37",
+ "mips64el-linux-gnu-n32-nan2008.2.38",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.33",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.34",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.35",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.36",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.37",
+ "mips64el-linux-gnu-n32-nan2008-soft.2.38",
+ "mips64el-linux-gnu-n32-soft.2.33",
+ "mips64el-linux-gnu-n32-soft.2.34",
+ "mips64el-linux-gnu-n32-soft.2.35",
+ "mips64el-linux-gnu-n32-soft.2.36",
+ "mips64el-linux-gnu-n32-soft.2.37",
+ "mips64el-linux-gnu-n32-soft.2.38",
+ "mips64el-linux-gnu-n64.2.33",
+ "mips64el-linux-gnu-n64.2.34",
+ "mips64el-linux-gnu-n64.2.35",
+ "mips64el-linux-gnu-n64.2.36",
+ "mips64el-linux-gnu-n64.2.37",
+ "mips64el-linux-gnu-n64.2.38",
+ "mips64el-linux-gnu-n64-nan2008.2.33",
+ "mips64el-linux-gnu-n64-nan2008.2.34",
+ "mips64el-linux-gnu-n64-nan2008.2.35",
+ "mips64el-linux-gnu-n64-nan2008.2.36",
+ "mips64el-linux-gnu-n64-nan2008.2.37",
+ "mips64el-linux-gnu-n64-nan2008.2.38",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.33",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.34",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.35",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.36",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.37",
+ "mips64el-linux-gnu-n64-nan2008-soft.2.38",
+ "mips64el-linux-gnu-n64-soft.2.33",
+ "mips64el-linux-gnu-n64-soft.2.34",
+ "mips64el-linux-gnu-n64-soft.2.35",
+ "mips64el-linux-gnu-n64-soft.2.36",
+ "mips64el-linux-gnu-n64-soft.2.37",
+ "mips64el-linux-gnu-n64-soft.2.38",
+ "mips64-linux-gnu-n32.2.33",
+ "mips64-linux-gnu-n32.2.34",
+ "mips64-linux-gnu-n32.2.35",
+ "mips64-linux-gnu-n32.2.36",
+ "mips64-linux-gnu-n32.2.37",
+ "mips64-linux-gnu-n32.2.38",
+ "mips64-linux-gnu-n32-nan2008.2.33",
+ "mips64-linux-gnu-n32-nan2008.2.34",
+ "mips64-linux-gnu-n32-nan2008.2.35",
+ "mips64-linux-gnu-n32-nan2008.2.36",
+ "mips64-linux-gnu-n32-nan2008.2.37",
+ "mips64-linux-gnu-n32-nan2008.2.38",
+ "mips64-linux-gnu-n32-nan2008-soft.2.33",
+ "mips64-linux-gnu-n32-nan2008-soft.2.34",
+ "mips64-linux-gnu-n32-nan2008-soft.2.35",
+ "mips64-linux-gnu-n32-nan2008-soft.2.36",
+ "mips64-linux-gnu-n32-nan2008-soft.2.37",
+ "mips64-linux-gnu-n32-nan2008-soft.2.38",
+ "mips64-linux-gnu-n32-soft.2.33",
+ "mips64-linux-gnu-n32-soft.2.34",
+ "mips64-linux-gnu-n32-soft.2.35",
+ "mips64-linux-gnu-n32-soft.2.36",
+ "mips64-linux-gnu-n32-soft.2.37",
+ "mips64-linux-gnu-n32-soft.2.38",
+ "mips64-linux-gnu-n64.2.33",
+ "mips64-linux-gnu-n64.2.34",
+ "mips64-linux-gnu-n64.2.35",
+ "mips64-linux-gnu-n64.2.36",
+ "mips64-linux-gnu-n64.2.37",
+ "mips64-linux-gnu-n64.2.38",
+ "mips64-linux-gnu-n64-nan2008.2.33",
+ "mips64-linux-gnu-n64-nan2008.2.34",
+ "mips64-linux-gnu-n64-nan2008.2.35",
+ "mips64-linux-gnu-n64-nan2008.2.36",
+ "mips64-linux-gnu-n64-nan2008.2.37",
+ "mips64-linux-gnu-n64-nan2008.2.38",
+ "mips64-linux-gnu-n64-nan2008-soft.2.33",
+ "mips64-linux-gnu-n64-nan2008-soft.2.34",
+ "mips64-linux-gnu-n64-nan2008-soft.2.35",
+ "mips64-linux-gnu-n64-nan2008-soft.2.36",
+ "mips64-linux-gnu-n64-nan2008-soft.2.37",
+ "mips64-linux-gnu-n64-nan2008-soft.2.38",
+ "mips64-linux-gnu-n64-soft.2.33",
+ "mips64-linux-gnu-n64-soft.2.34",
+ "mips64-linux-gnu-n64-soft.2.35",
+ "mips64-linux-gnu-n64-soft.2.36",
+ "mips64-linux-gnu-n64-soft.2.37",
+ "mips64-linux-gnu-n64-soft.2.38",
+ "mipsel-linux-gnu.2.33",
+ "mipsel-linux-gnu.2.34",
+ "mipsel-linux-gnu.2.35",
+ "mipsel-linux-gnu.2.36",
+ "mipsel-linux-gnu.2.37",
+ "mipsel-linux-gnu.2.38",
+ "mipsel-linux-gnu-nan2008.2.33",
+ "mipsel-linux-gnu-nan2008.2.34",
+ "mipsel-linux-gnu-nan2008.2.35",
+ "mipsel-linux-gnu-nan2008.2.36",
+ "mipsel-linux-gnu-nan2008.2.37",
+ "mipsel-linux-gnu-nan2008.2.38",
+ "mipsel-linux-gnu-nan2008-soft.2.33",
+ "mipsel-linux-gnu-nan2008-soft.2.34",
+ "mipsel-linux-gnu-nan2008-soft.2.35",
+ "mipsel-linux-gnu-nan2008-soft.2.36",
+ "mipsel-linux-gnu-nan2008-soft.2.37",
+ "mipsel-linux-gnu-nan2008-soft.2.38",
+ "mipsel-linux-gnu-soft.2.33",
+ "mipsel-linux-gnu-soft.2.34",
+ "mipsel-linux-gnu-soft.2.35",
+ "mipsel-linux-gnu-soft.2.36",
+ "mipsel-linux-gnu-soft.2.37",
+ "mipsel-linux-gnu-soft.2.38",
+ "mipsisa32r6el-linux-gnu.2.33",
+ "mipsisa32r6el-linux-gnu.2.34",
+ "mipsisa32r6el-linux-gnu.2.35",
+ "mipsisa32r6el-linux-gnu.2.36",
+ "mipsisa32r6el-linux-gnu.2.37",
+ "mipsisa32r6el-linux-gnu.2.38",
+ "mipsisa64r6el-linux-gnu-n32.2.33",
+ "mipsisa64r6el-linux-gnu-n32.2.34",
+ "mipsisa64r6el-linux-gnu-n32.2.35",
+ "mipsisa64r6el-linux-gnu-n32.2.36",
+ "mipsisa64r6el-linux-gnu-n32.2.37",
+ "mipsisa64r6el-linux-gnu-n32.2.38",
+ "mipsisa64r6el-linux-gnu-n64.2.33",
+ "mipsisa64r6el-linux-gnu-n64.2.34",
+ "mipsisa64r6el-linux-gnu-n64.2.35",
+ "mipsisa64r6el-linux-gnu-n64.2.36",
+ "mipsisa64r6el-linux-gnu-n64.2.37",
+ "mipsisa64r6el-linux-gnu-n64.2.38",
+ "mips-linux-gnu.2.33",
+ "mips-linux-gnu.2.34",
+ "mips-linux-gnu.2.35",
+ "mips-linux-gnu.2.36",
+ "mips-linux-gnu.2.37",
+ "mips-linux-gnu.2.38",
+ "mips-linux-gnu-nan2008.2.33",
+ "mips-linux-gnu-nan2008.2.34",
+ "mips-linux-gnu-nan2008.2.35",
+ "mips-linux-gnu-nan2008.2.36",
+ "mips-linux-gnu-nan2008.2.37",
+ "mips-linux-gnu-nan2008.2.38",
+ "mips-linux-gnu-nan2008-soft.2.33",
+ "mips-linux-gnu-nan2008-soft.2.34",
+ "mips-linux-gnu-nan2008-soft.2.35",
+ "mips-linux-gnu-nan2008-soft.2.36",
+ "mips-linux-gnu-nan2008-soft.2.37",
+ "mips-linux-gnu-nan2008-soft.2.38",
+ "mips-linux-gnu-soft.2.33",
+ "mips-linux-gnu-soft.2.34",
+ "mips-linux-gnu-soft.2.35",
+ "mips-linux-gnu-soft.2.36",
+ "mips-linux-gnu-soft.2.37",
+ "mips-linux-gnu-soft.2.38",
+ "powerpc64le-linux-gnu.2.33",
+ "powerpc64le-linux-gnu.2.34",
+ "powerpc64le-linux-gnu.2.35",
+ "powerpc64le-linux-gnu.2.36",
+ "powerpc64le-linux-gnu.2.37",
+ "powerpc64le-linux-gnu.2.38",
+ "powerpc64-linux-gnu.2.33",
+ "powerpc64-linux-gnu.2.34",
+ "powerpc64-linux-gnu.2.35",
+ "powerpc64-linux-gnu.2.36",
+ "powerpc64-linux-gnu.2.37",
+ "powerpc64-linux-gnu.2.38",
+ "powerpc-linux-gnu.2.33",
+ "powerpc-linux-gnu.2.34",
+ "powerpc-linux-gnu.2.35",
+ "powerpc-linux-gnu.2.36",
+ "powerpc-linux-gnu.2.37",
+ "powerpc-linux-gnu.2.38",
+ "powerpc-linux-gnu-power4.2.33",
+ "powerpc-linux-gnu-power4.2.34",
+ "powerpc-linux-gnu-power4.2.35",
+ "powerpc-linux-gnu-power4.2.36",
+ "powerpc-linux-gnu-power4.2.37",
+ "powerpc-linux-gnu-power4.2.38",
+ "powerpc-linux-gnu-soft.2.33",
+ "powerpc-linux-gnu-soft.2.34",
+ "powerpc-linux-gnu-soft.2.35",
+ "powerpc-linux-gnu-soft.2.36",
+ "powerpc-linux-gnu-soft.2.37",
+ "powerpc-linux-gnu-soft.2.38",
+ "riscv64-linux-gnu-rv64imac-lp64.2.33",
+ "riscv64-linux-gnu-rv64imac-lp64.2.34",
+ "riscv64-linux-gnu-rv64imac-lp64.2.35",
+ "riscv64-linux-gnu-rv64imac-lp64.2.36",
+ "riscv64-linux-gnu-rv64imac-lp64.2.37",
+ "riscv64-linux-gnu-rv64imac-lp64.2.38",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.33",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.34",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.35",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.36",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.37",
+ "riscv64-linux-gnu-rv64imafdc-lp64.2.38",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.33",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.34",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.35",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.36",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.37",
+ "riscv64-linux-gnu-rv64imafdc-lp64d.2.38",
+ "s390x-linux-gnu.2.33",
+ "s390x-linux-gnu.2.34",
+ "s390x-linux-gnu.2.35",
+ "s390x-linux-gnu.2.36",
+ "s390x-linux-gnu.2.37",
+ "s390x-linux-gnu.2.38",
+ "sparc64-linux-gnu.2.33",
+ "sparc64-linux-gnu.2.34",
+ "sparc64-linux-gnu.2.35",
+ "sparc64-linux-gnu.2.36",
+ "sparc64-linux-gnu.2.37",
+ "sparc64-linux-gnu.2.38",
+ "sparcv8-linux-gnu-leon3.2.33",
+ "sparcv8-linux-gnu-leon3.2.34",
+ "sparcv8-linux-gnu-leon3.2.35",
+ "sparcv8-linux-gnu-leon3.2.36",
+ "sparcv8-linux-gnu-leon3.2.37",
+ "sparcv8-linux-gnu-leon3.2.38",
+ "sparcv9-linux-gnu.2.33",
+ "sparcv9-linux-gnu.2.34",
+ "sparcv9-linux-gnu.2.35",
+ "sparcv9-linux-gnu.2.36",
+ "sparcv9-linux-gnu.2.37",
+ "sparcv9-linux-gnu.2.38",
+ "x86_64-linux-gnu.2.33",
+ "x86_64-linux-gnu.2.34",
+ "x86_64-linux-gnu.2.35",
+ "x86_64-linux-gnu.2.36",
+ "x86_64-linux-gnu.2.37",
+ "x86_64-linux-gnu.2.38",
+ "x86_64-linux-gnu-x32.2.33",
+ "x86_64-linux-gnu-x32.2.34",
+ "x86_64-linux-gnu-x32.2.35",
+ "x86_64-linux-gnu-x32.2.36",
+ "x86_64-linux-gnu-x32.2.37",
+ "x86_64-linux-gnu-x32.2.38",
+ "__GLIBC_MINOR__ > 32",
+},
+
+// The rest of these are not duplicated enough so far to warrant a reduction,
+// but they are listed in the file so that we can show an error when running
+// compile.bash to make sure a new version gets added to this file.
+
+//any-windows-any
diff --git a/src/textdiff/test.bash b/src/textdiff/test.bash
new file mode 100755
index 00000000..636b2926
--- /dev/null
+++ b/src/textdiff/test.bash
@@ -0,0 +1,16 @@
+
+HEADER_LIST="$@"
+
+for i in $HEADER_LIST;
+do
+ echo "testHeaders $i"
+ ./zig-out/bin/testHeaders uh_headers uh_test $i
+ diff -uBwr uh_norm/$(basename $i) uh_test | grep -v "Only in" > uh_diff
+ if [ -s uh_diff ]
+ then
+ echo "failed: diff -uBwr uh_norm/$(basename $i) uh_test"
+ exit 1
+ fi
+done
+
+exit 0
diff --git a/src/textdiff/testHeaders.zig b/src/textdiff/testHeaders.zig
new file mode 100644
index 00000000..f854dafb
--- /dev/null
+++ b/src/textdiff/testHeaders.zig
@@ -0,0 +1,145 @@
+const std = @import("std");
+const reductions = @import("reductions.zig"){};
+
+const debug = false;
+
+// This utility goes through universal headers and only evaluates the #if blocks that we added to make them universal
+// - what comes out can be diffed against the original headers for testing
+pub fn main() !void {
+ var arena_allocator = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ const arena = arena_allocator.allocator();
+
+ var args = try std.process.argsWithAllocator(arena);
+
+ {
+ var i: usize = 0;
+ while (args.skip()) {
+ i += 1;
+ }
+
+ if (i != 4) {
+ std.debug.print("usage: testHeaders \n", .{});
+ std.debug.print("takes universal headers from , partially evaluates, and outputs to \n", .{});
+ std.debug.print("output files should match originals from that version (maybe whitespace differences)\n", .{});
+ return;
+ }
+ }
+
+ args = try std.process.argsWithAllocator(arena);
+ _ = args.skip();
+ const inDir = args.next() orelse return;
+ const outDir = args.next() orelse return;
+ const versionStr = std.fs.path.basename(args.next() orelse return);
+
+ var dir = try std.fs.cwd().openIterableDir(inDir, .{});
+ defer dir.close();
+
+ var walker = try dir.walk(arena);
+ while (try walker.next()) |entry| {
+ if (entry.kind != .file) {
+ continue;
+ }
+
+ //if (!std.mem.eql(u8, entry.basename, "e_os2.h")) continue;
+
+ //std.debug.print("entry: base {s} path {s}\n", .{ entry.basename, entry.path });
+
+ // read universal header into memory
+ var inpath = try std.fs.path.join(arena, &.{ inDir, entry.path });
+ var inlines = std.ArrayList([]const u8).init(arena);
+ {
+ var file = try std.fs.cwd().openFile(inpath, .{});
+ defer file.close();
+ var contents = try file.reader().readAllAlloc(arena, 20 * 1024 * 1024);
+ while (contents.len > 0 and contents[contents.len - 1] == '\n') {
+ contents = contents[0 .. contents.len - 1];
+ }
+
+ if (contents.len > 0) {
+ var it = std.mem.splitScalar(u8, contents, '\n');
+ while (it.next()) |line| {
+ try inlines.append(line);
+ }
+ }
+ }
+
+ var outpath = try std.fs.path.join(arena, &.{ outDir, entry.path });
+ if (std.fs.path.dirname(outpath)) |dirname| {
+ try std.fs.cwd().makePath(dirname);
+ }
+ if (debug) std.debug.print("createFile {s}\n", .{outpath});
+ var outfile = try std.fs.cwd().createFile(outpath, .{});
+ defer outfile.close();
+ var outwriter = outfile.writer();
+
+ // maintain a stack corresponding to #if blocks we are inside of
+ // - bit 1 is if we should be outputting these lines (because the version matches)
+ // - bit 2 is if this #if block is one we added to make the universal header (we don't want to output those)
+ var outputing = std.ArrayList(u2).init(arena);
+
+ var in_comment: bool = false;
+ for (inlines.items) |line| {
+ if (debug) std.debug.print("{d} {s}\n", .{ outputing.items.len, line });
+ var com = in_comment;
+ if (!in_comment and std.mem.indexOf(u8, line, "/*") != null and std.mem.indexOf(u8, line, "*/") == null) {
+ in_comment = true;
+ } else if (in_comment and std.mem.indexOf(u8, line, "/*") == null and std.mem.indexOf(u8, line, "*/") != null) {
+ in_comment = false; // next line will be out of comment
+ }
+ var trimmed = std.mem.trimLeft(u8, line, " ");
+ if (!com and std.mem.startsWith(u8, trimmed, "#")) {
+ trimmed = trimmed[1..];
+ trimmed = std.mem.trimLeft(u8, trimmed, " ");
+ if (debug) std.debug.print("trimmed {s}\n", .{trimmed});
+ if (std.mem.startsWith(u8, trimmed, "if")) {
+ if (debug) std.debug.print("- if\n", .{});
+ if (std.mem.indexOf(u8, trimmed, "_ZIG_UH_") != null) {
+ var found = false;
+ if (std.mem.indexOf(u8, trimmed, versionStr) != null) {
+ found = true;
+ } else {
+ // look for versionStr in each reduction, and see
+ // if that reduction matches
+ inline for (@typeInfo(@TypeOf(reductions)).Struct.fields) |f| blk: {
+ const field = @field(reductions, f.name);
+ for (0..field.len - 1) |i| {
+ if (std.mem.eql(u8, versionStr, field[i])) {
+ if (std.mem.indexOf(u8, trimmed, field[field.len - 1]) != null) {
+ found = true;
+ break :blk;
+ }
+ }
+ }
+ }
+ }
+
+ if (found) {
+ try outputing.append(3);
+ } else {
+ try outputing.append(2);
+ }
+ continue;
+ } else {
+ const currently_outputting = (outputing.items.len == 0 or outputing.items[outputing.items.len - 1] & 1 > 0);
+ try outputing.append(if (currently_outputting) 1 else 0);
+ }
+ } else if (std.mem.startsWith(u8, trimmed, "endif")) {
+ if (outputing.items.len == 0) {
+ return error.dangling_endif;
+ }
+
+ if (outputing.items[outputing.items.len - 1] & 2 > 0) {
+ _ = outputing.pop();
+ continue;
+ } else {
+ _ = outputing.pop();
+ }
+ }
+ }
+
+ if (outputing.items.len == 0 or outputing.items[outputing.items.len - 1] & 1 > 0) {
+ try outwriter.print("{s}\n", .{line});
+ }
+ }
+ }
+}