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};