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