1const std = @import("std");
2const Io = std.Io;
3const Dir = Io.Dir;
4const Preprocessor = @import("preprocessor");
5
6pub fn main(init: std.process.Init) !void {
7 const arena = init.arena.allocator();
8 const io = init.io;
9 const args = try init.minimal.args.toSlice(arena);
10
11 const zig_src_mingw_lib_path = args[1];
12
13 const mingw_include_path = try Dir.path.join(arena, &.{
14 zig_src_mingw_lib_path, "def-include",
15 });
16 const mingw_libcommon_path = try Dir.path.join(arena, &.{
17 zig_src_mingw_lib_path, "lib-common",
18 });
19
20 var mingw_libcommon_dir = Dir.cwd().openDir(io, mingw_libcommon_path, .{ .iterate = true }) catch |err| {
21 std.log.err("unable to open directory {s}: {t}", .{ mingw_libcommon_path, err });
22 std.process.exit(1);
23 };
24 defer mingw_libcommon_dir.close(io);
25
26 var walker = try mingw_libcommon_dir.walk(arena);
27 defer walker.deinit();
28
29 while (try walker.next(io)) |entry| {
30 if (entry.kind != .file) continue;
31 // Only .def.in files need preprocessing
32 if (!std.mem.endsWith(u8, entry.basename, ".def.in")) continue;
33
34 var fail = false;
35 for (&targets) |*target| {
36 var target_arena: std.heap.ArenaAllocator = .init(init.gpa);
37 defer target_arena.deinit();
38
39 const pp_arena = target_arena.allocator();
40 const file_path = try Dir.path.join(pp_arena, &.{ mingw_libcommon_path, entry.path });
41
42 const aro = pp: {
43 const target_triple = try target.zigTriple(pp_arena);
44 const target_arg = try std.fmt.allocPrint(pp_arena, "--target={s}", .{target_triple});
45 const result = std.process.run(pp_arena, io, .{
46 .argv = &.{
47 "arocc",
48 "-E",
49 target_arg,
50 "--no-line-commands",
51 "-nostdinc",
52 "-I",
53 mingw_include_path,
54 file_path,
55 },
56 }) catch |err| {
57 std.log.err("unable to execute arocc: {t}", .{err});
58 std.process.exit(1);
59 };
60 if (result.term.exited != 0) {
61 std.log.err("error executing arocc: {s}", .{result.stderr});
62 std.process.exit(result.term.exited);
63 }
64 break :pp result.stdout;
65 };
66
67 const native = pp: {
68 var aw: Io.Writer.Allocating = .init(pp_arena);
69 errdefer aw.deinit();
70
71 var pp: Preprocessor = .{
72 .io = io,
73 .arena = pp_arena,
74 .include_dir = .initCwd(mingw_include_path),
75 .target = target,
76 };
77
78 pp.preprocess(.initCwd(file_path)) catch |err| {
79 std.log.err("error preprocessing file {s} for target {t}: {t}", .{ entry.path, target.cpu.arch, err });
80 fail = true;
81 continue;
82 };
83 pp.prettyPrintTokens(&aw.writer) catch |err| {
84 std.log.err("error printing tokens for file {s} for target {t}: {t}", .{ entry.path, target.cpu.arch, err });
85 fail = true;
86 continue;
87 };
88
89 break :pp try aw.toOwnedSliceSentinel(0);
90 };
91
92 try std.testing.expectEqualStrings(aro, native);
93 }
94
95 if (fail) std.process.exit(1);
96 }
97}
98
99const targets = [_]std.Target{
100 .{
101 .ofmt = .coff,
102 .abi = .gnu,
103 .os = .{ .tag = .windows, .version_range = .default(.thumb, .windows, .gnu) },
104 .cpu = .{ .arch = .thumb, .model = .generic(.thumb), .features = .empty },
105 },
106 .{
107 .ofmt = .coff,
108 .abi = .gnu,
109 .os = .{ .tag = .windows, .version_range = .default(.aarch64, .windows, .gnu) },
110 .cpu = .{ .arch = .aarch64, .model = .generic(.aarch64), .features = .empty },
111 },
112 .{
113 .ofmt = .coff,
114 .abi = .gnu,
115 .os = .{ .tag = .windows, .version_range = .default(.x86, .windows, .gnu) },
116 .cpu = .{ .arch = .x86, .model = .generic(.x86), .features = .empty },
117 },
118 .{
119 .ofmt = .coff,
120 .abi = .gnu,
121 .os = .{ .tag = .windows, .version_range = .default(.x86_64, .windows, .gnu) },
122 .cpu = .{ .arch = .x86_64, .model = .generic(.x86_64), .features = .empty },
123 },
124};