Skip to content

Commit 6893e7f

Browse files
authored
Merge pull request #25414 from squeek502/mingw-def-implib
Support generating import libraries from mingw .def files without LLVM
2 parents 9bfd4c3 + e393543 commit 6893e7f

File tree

7 files changed

+2231
-105
lines changed

7 files changed

+2231
-105
lines changed

lib/std/coff.zig

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -528,13 +528,11 @@ pub const SectionHeader = extern struct {
528528

529529
/// Applicable only to section headers in COFF objects.
530530
pub fn getAlignment(self: SectionHeader) ?u16 {
531-
if (self.flags.ALIGN == 0) return null;
532-
return std.math.powi(u16, 2, self.flags.ALIGN - 1) catch unreachable;
531+
return self.flags.ALIGN.toByteUnits();
533532
}
534533

535534
pub fn setAlignment(self: *SectionHeader, new_alignment: u16) void {
536-
assert(new_alignment > 0 and new_alignment <= 8192);
537-
self.flags.ALIGN = @intCast(std.math.log2(new_alignment));
535+
self.flags.ALIGN = .fromByteUnits(new_alignment);
538536
}
539537

540538
pub fn isCode(self: SectionHeader) bool {
@@ -651,6 +649,16 @@ pub const SectionHeader = extern struct {
651649
@"4096BYTES" = 13,
652650
@"8192BYTES" = 14,
653651
_,
652+
653+
pub fn toByteUnits(a: Align) ?u16 {
654+
if (a == .NONE) return null;
655+
return @as(u16, 1) << (@intFromEnum(a) - 1);
656+
}
657+
658+
pub fn fromByteUnits(n: u16) Align {
659+
std.debug.assert(std.math.isPowerOfTwo(n));
660+
return @enumFromInt(@ctz(n) + 1);
661+
}
654662
};
655663
};
656664
};
@@ -925,6 +933,10 @@ pub const WeakExternalDefinition = struct {
925933
flag: WeakExternalFlag,
926934

927935
unused: [10]u8,
936+
937+
pub fn sizeOf() usize {
938+
return 18;
939+
}
928940
};
929941

930942
// https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/km/ntimage.h
@@ -1338,14 +1350,16 @@ pub const Strtab = struct {
13381350
};
13391351

13401352
pub const ImportHeader = extern struct {
1341-
sig1: IMAGE.FILE.MACHINE,
1342-
sig2: u16,
1353+
/// Must be IMAGE_FILE_MACHINE_UNKNOWN
1354+
sig1: IMAGE.FILE.MACHINE = .UNKNOWN,
1355+
/// Must be 0xFFFF
1356+
sig2: u16 = 0xFFFF,
13431357
version: u16,
13441358
machine: IMAGE.FILE.MACHINE,
13451359
time_date_stamp: u32,
13461360
size_of_data: u32,
13471361
hint: u16,
1348-
types: packed struct(u32) {
1362+
types: packed struct(u16) {
13491363
type: ImportType,
13501364
name_type: ImportNameType,
13511365
reserved: u11,

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)