1const std = @import("std");
2const Io = std.Io;
3const Dir = std.Io.Dir;
4
5pub fn main(init: std.process.Init) !void {
6 const arena = init.arena.allocator();
7 const io = init.io;
8 const args = try init.minimal.args.toSlice(arena);
9
10 const zig_src_lib_path = args[1];
11 const mingw_src_path = args[2];
12
13 const dest_mingw_crt_path = try Dir.path.join(arena, &.{
14 zig_src_lib_path, "libc", "mingw",
15 });
16 const src_mingw_crt_path = try Dir.path.join(arena, &.{
17 mingw_src_path, "mingw-w64-crt",
18 });
19
20 // Update only the set of existing files we have already chosen to include
21 // in zig's installation.
22
23 var dest_crt_dir = Dir.cwd().openDir(io, dest_mingw_crt_path, .{ .iterate = true }) catch |err| {
24 std.log.err("unable to open directory '{s}': {t}", .{ dest_mingw_crt_path, err });
25 std.process.exit(1);
26 };
27 defer dest_crt_dir.close(io);
28
29 var src_crt_dir = Dir.cwd().openDir(io, src_mingw_crt_path, .{ .iterate = true }) catch |err| {
30 std.log.err("unable to open directory '{s}': {t}", .{ src_mingw_crt_path, err });
31 std.process.exit(1);
32 };
33 defer src_crt_dir.close(io);
34
35 {
36 var walker = try dest_crt_dir.walk(arena);
37 defer walker.deinit();
38
39 var fail = false;
40
41 while (try walker.next(io)) |entry| {
42 if (entry.kind != .file) continue;
43
44 src_crt_dir.copyFile(entry.path, dest_crt_dir, entry.path, io, .{}) catch |err| switch (err) {
45 error.FileNotFound => {
46 const keep = for (kept_crt_files) |item| {
47 if (std.mem.eql(u8, entry.path, item)) break true;
48 if (std.mem.startsWith(u8, entry.path, "winpthreads/")) break true;
49 } else false;
50
51 if (!keep) {
52 std.log.warn("deleting {s}", .{entry.path});
53 try dest_crt_dir.deleteFile(io, entry.path);
54 }
55 },
56 else => {
57 std.log.err("unable to copy {s}: {t}", .{ entry.path, err });
58 fail = true;
59 },
60 };
61 }
62
63 if (fail) std.process.exit(1);
64 }
65
66 {
67 const dest_mingw_winpthreads_path = try Dir.path.join(arena, &.{
68 zig_src_lib_path, "libc", "mingw", "winpthreads",
69 });
70 const src_mingw_libraries_winpthreads_src_path = try Dir.path.join(arena, &.{
71 mingw_src_path, "mingw-w64-libraries", "winpthreads", "src",
72 });
73
74 var dest_winpthreads_dir = Dir.cwd().openDir(io, dest_mingw_winpthreads_path, .{ .iterate = true }) catch |err| {
75 std.log.err("unable to open directory '{s}': {s}", .{ dest_mingw_winpthreads_path, @errorName(err) });
76 std.process.exit(1);
77 };
78 defer dest_winpthreads_dir.close(io);
79
80 var src_winpthreads_dir = Dir.cwd().openDir(io, src_mingw_libraries_winpthreads_src_path, .{ .iterate = true }) catch |err| {
81 std.log.err("unable to open directory '{s}': {s}", .{ src_mingw_libraries_winpthreads_src_path, @errorName(err) });
82 std.process.exit(1);
83 };
84 defer src_winpthreads_dir.close(io);
85
86 {
87 var walker = try dest_winpthreads_dir.walk(arena);
88 defer walker.deinit();
89
90 var fail = false;
91
92 while (try walker.next(io)) |entry| {
93 if (entry.kind != .file) continue;
94
95 src_winpthreads_dir.copyFile(entry.path, dest_winpthreads_dir, entry.path, io, .{}) catch |err| switch (err) {
96 error.FileNotFound => {
97 std.log.warn("deleting {s}", .{entry.path});
98 try dest_winpthreads_dir.deleteFile(io, entry.path);
99 },
100 else => {
101 std.log.err("unable to copy {s}: {t}", .{ entry.path, err });
102 fail = true;
103 },
104 };
105 }
106
107 if (fail) std.process.exit(1);
108 }
109 }
110
111 {
112 // Also add all new def and def.in files.
113 var walker = try src_crt_dir.walkSelectively(arena);
114 defer walker.deinit();
115
116 var fail = false;
117
118 while (try walker.next(io)) |entry| {
119 switch (entry.kind) {
120 .directory => {
121 switch (entry.depth()) {
122 1 => if (def_dirs.has(entry.basename)) {
123 try walker.enter(io, entry);
124 continue;
125 },
126 else => {
127 // The top-level directory was already validated
128 try walker.enter(io, entry);
129 continue;
130 },
131 }
132 },
133 .file => {},
134 else => continue,
135 }
136
137 const ok_ext = for (def_exts) |ext| {
138 if (std.mem.endsWith(u8, entry.path, ext)) break true;
139 } else false;
140
141 if (!ok_ext) continue;
142
143 const blacklisted = for (blacklisted_defs) |item| {
144 if (std.mem.eql(u8, entry.basename, item)) break true;
145 } else false;
146
147 if (blacklisted) continue;
148
149 if (std.mem.endsWith(u8, entry.basename, "_windowsapp.def"))
150 continue;
151
152 if (std.mem.endsWith(u8, entry.basename, "_onecore.def"))
153 continue;
154
155 src_crt_dir.copyFile(entry.path, dest_crt_dir, entry.path, io, .{}) catch |err| {
156 std.log.err("unable to copy {s}: {t}", .{ entry.path, err });
157 fail = true;
158 };
159 }
160 if (fail) std.process.exit(1);
161 }
162
163 return std.process.cleanExit(io);
164}
165
166const kept_crt_files = [_][]const u8{
167 "COPYING",
168 "include" ++ Dir.path.sep_str ++ "config.h",
169};
170
171const def_exts = [_][]const u8{
172 ".def",
173 ".def.in",
174};
175
176const def_dirs = std.StaticStringMap(void).initComptime(.{
177 .{"lib32"},
178 .{"lib64"},
179 .{"libarm32"},
180 .{"libarm64"},
181 .{"lib-common"},
182 .{"def-include"},
183});
184
185const blacklisted_defs = [_][]const u8{
186 "crtdll.def.in",
187
188 "msvcp60.def",
189 "msvcp110.def",
190 "msvcp120_app.def.in",
191 "msvcp120_clr0400.def",
192
193 "msvcr40d.def.in",
194 "msvcr70.def.in",
195 "msvcr70d.def.in",
196 "msvcr71.def.in",
197 "msvcr71d.def.in",
198 "msvcr80.def.in",
199 "msvcr80d.def.in",
200 "msvcr90.def.in",
201 "msvcr90d.def.in",
202 "msvcr100.def.in",
203 "msvcr100d.def.in",
204 "msvcr110.def.in",
205 "msvcr110d.def.in",
206 "msvcr120.def.in",
207 "msvcr120d.def.in",
208 "msvcr120_app.def.in",
209
210 "msvcrt.def.in",
211 "msvcrtd.def.in",
212 "msvcrt10.def.in",
213 "msvcrt20.def.in",
214 "msvcrt40.def.in",
215};