Skip to content

Commit e393543

Browse files
committed
Support generating import libraries from mingw .def files without LLVM
For the supported COFF machine types of X64 (x86_64), I386 (x86), ARMNT (thumb), and ARM64 (aarch64), this new Zig implementation results in byte-for-byte identical .lib files when compared to the previous LLVM-backed implementation.
1 parent 900315a commit e393543

File tree

6 files changed

+2210
-98
lines changed

6 files changed

+2210
-98
lines changed

src/codegen/llvm/bindings.zig

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -338,14 +338,6 @@ extern fn ZigLLVMWriteArchive(
338338
pub const ParseCommandLineOptions = ZigLLVMParseCommandLineOptions;
339339
extern fn ZigLLVMParseCommandLineOptions(argc: usize, argv: [*]const [*:0]const u8) void;
340340

341-
pub const WriteImportLibrary = ZigLLVMWriteImportLibrary;
342-
extern fn ZigLLVMWriteImportLibrary(
343-
def_path: [*:0]const u8,
344-
coff_machine: c_uint,
345-
output_lib_path: [*:0]const u8,
346-
kill_at: bool,
347-
) bool;
348-
349341
pub const GetHostCPUName = LLVMGetHostCPUName;
350342
extern fn LLVMGetHostCPUName() ?[*:0]u8;
351343

src/libs/mingw.zig

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ const Compilation = @import("../Compilation.zig");
1010
const build_options = @import("build_options");
1111
const Cache = std.Build.Cache;
1212
const dev = @import("../dev.zig");
13+
const def = @import("mingw/def.zig");
14+
const implib = @import("mingw/implib.zig");
15+
16+
test {
17+
_ = def;
18+
_ = implib;
19+
}
1320

1421
pub const CrtFile = enum {
1522
crt2_o,
@@ -290,11 +297,6 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
290297
var o_dir = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{});
291298
defer o_dir.close();
292299

293-
const final_def_basename = try std.fmt.allocPrint(arena, "{s}.def", .{lib_name});
294-
const def_final_path = try comp.dirs.global_cache.join(arena, &[_][]const u8{
295-
"o", &digest, final_def_basename,
296-
});
297-
298300
const aro = @import("aro");
299301
var diagnostics: aro.Diagnostics = .{
300302
.output = .{ .to_list = .{ .arena = .init(gpa) } },
@@ -312,7 +314,6 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
312314
defer std.debug.unlockStderrWriter();
313315
nosuspend stderr.print("def file: {s}\n", .{def_file_path}) catch break :print;
314316
nosuspend stderr.print("include dir: {s}\n", .{include_dir}) catch break :print;
315-
nosuspend stderr.print("output path: {s}\n", .{def_final_path}) catch break :print;
316317
}
317318

318319
try aro_comp.include_dirs.append(gpa, include_dir);
@@ -339,32 +340,46 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
339340
}
340341
}
341342

342-
{
343-
// new scope to ensure definition file is written before passing the path to WriteImportLibrary
344-
const def_final_file = try o_dir.createFile(final_def_basename, .{ .truncate = true });
345-
defer def_final_file.close();
346-
var buffer: [1024]u8 = undefined;
347-
var file_writer = def_final_file.writer(&buffer);
348-
try pp.prettyPrintTokens(&file_writer.interface, .result_only);
349-
try file_writer.interface.flush();
350-
}
343+
const members = members: {
344+
var aw: std.Io.Writer.Allocating = .init(gpa);
345+
errdefer aw.deinit();
346+
try pp.prettyPrintTokens(&aw.writer, .result_only);
347+
348+
const input = try aw.toOwnedSliceSentinel(0);
349+
defer gpa.free(input);
350+
351+
const machine_type = target.toCoffMachine();
352+
var def_diagnostics: def.Diagnostics = undefined;
353+
var module_def = def.parse(gpa, input, machine_type, .mingw, &def_diagnostics) catch |err| switch (err) {
354+
error.OutOfMemory => |e| return e,
355+
error.ParseError => {
356+
var buffer: [64]u8 = undefined;
357+
const w = std.debug.lockStderrWriter(&buffer);
358+
defer std.debug.unlockStderrWriter();
359+
try w.writeAll("error: ");
360+
try def_diagnostics.writeMsg(w, input);
361+
try w.writeByte('\n');
362+
return error.WritingImportLibFailed;
363+
},
364+
};
365+
defer module_def.deinit();
366+
367+
module_def.fixupForImportLibraryGeneration(machine_type);
368+
369+
break :members try implib.getMembers(gpa, module_def, machine_type);
370+
};
371+
defer members.deinit();
351372

352373
const lib_final_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename });
353374
errdefer gpa.free(lib_final_path);
354375

355-
if (!build_options.have_llvm) return error.ZigCompilerNotBuiltWithLLVMExtensions;
356-
const llvm_bindings = @import("../codegen/llvm/bindings.zig");
357-
const def_final_path_z = try arena.dupeZ(u8, def_final_path);
358-
const lib_final_path_z = try comp.dirs.global_cache.joinZ(arena, &.{lib_final_path});
359-
if (llvm_bindings.WriteImportLibrary(
360-
def_final_path_z.ptr,
361-
@intFromEnum(target.toCoffMachine()),
362-
lib_final_path_z.ptr,
363-
true,
364-
)) {
365-
// TODO surface a proper error here
366-
log.err("unable to turn {s}.def into {s}.lib", .{ lib_name, lib_name });
367-
return error.WritingImportLibFailed;
376+
{
377+
const lib_final_file = try o_dir.createFile(final_lib_basename, .{ .truncate = true });
378+
defer lib_final_file.close();
379+
var buffer: [1024]u8 = undefined;
380+
var file_writer = lib_final_file.writer(&buffer);
381+
try implib.writeCoffArchive(gpa, &file_writer.interface, members);
382+
try file_writer.interface.flush();
368383
}
369384

370385
man.writeManifest() catch |err| {

0 commit comments

Comments
 (0)