mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
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.
This commit is contained in:
parent
900315a3f3
commit
e393543e63
@ -338,14 +338,6 @@ extern fn ZigLLVMWriteArchive(
|
||||
pub const ParseCommandLineOptions = ZigLLVMParseCommandLineOptions;
|
||||
extern fn ZigLLVMParseCommandLineOptions(argc: usize, argv: [*]const [*:0]const u8) void;
|
||||
|
||||
pub const WriteImportLibrary = ZigLLVMWriteImportLibrary;
|
||||
extern fn ZigLLVMWriteImportLibrary(
|
||||
def_path: [*:0]const u8,
|
||||
coff_machine: c_uint,
|
||||
output_lib_path: [*:0]const u8,
|
||||
kill_at: bool,
|
||||
) bool;
|
||||
|
||||
pub const GetHostCPUName = LLVMGetHostCPUName;
|
||||
extern fn LLVMGetHostCPUName() ?[*:0]u8;
|
||||
|
||||
|
||||
@ -10,6 +10,13 @@ const Compilation = @import("../Compilation.zig");
|
||||
const build_options = @import("build_options");
|
||||
const Cache = std.Build.Cache;
|
||||
const dev = @import("../dev.zig");
|
||||
const def = @import("mingw/def.zig");
|
||||
const implib = @import("mingw/implib.zig");
|
||||
|
||||
test {
|
||||
_ = def;
|
||||
_ = implib;
|
||||
}
|
||||
|
||||
pub const CrtFile = enum {
|
||||
crt2_o,
|
||||
@ -290,11 +297,6 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||
var o_dir = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{});
|
||||
defer o_dir.close();
|
||||
|
||||
const final_def_basename = try std.fmt.allocPrint(arena, "{s}.def", .{lib_name});
|
||||
const def_final_path = try comp.dirs.global_cache.join(arena, &[_][]const u8{
|
||||
"o", &digest, final_def_basename,
|
||||
});
|
||||
|
||||
const aro = @import("aro");
|
||||
var diagnostics: aro.Diagnostics = .{
|
||||
.output = .{ .to_list = .{ .arena = .init(gpa) } },
|
||||
@ -312,7 +314,6 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||
defer std.debug.unlockStderrWriter();
|
||||
nosuspend stderr.print("def file: {s}\n", .{def_file_path}) catch break :print;
|
||||
nosuspend stderr.print("include dir: {s}\n", .{include_dir}) catch break :print;
|
||||
nosuspend stderr.print("output path: {s}\n", .{def_final_path}) catch break :print;
|
||||
}
|
||||
|
||||
try aro_comp.include_dirs.append(gpa, include_dir);
|
||||
@ -339,32 +340,46 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// new scope to ensure definition file is written before passing the path to WriteImportLibrary
|
||||
const def_final_file = try o_dir.createFile(final_def_basename, .{ .truncate = true });
|
||||
defer def_final_file.close();
|
||||
var buffer: [1024]u8 = undefined;
|
||||
var file_writer = def_final_file.writer(&buffer);
|
||||
try pp.prettyPrintTokens(&file_writer.interface, .result_only);
|
||||
try file_writer.interface.flush();
|
||||
}
|
||||
const members = members: {
|
||||
var aw: std.Io.Writer.Allocating = .init(gpa);
|
||||
errdefer aw.deinit();
|
||||
try pp.prettyPrintTokens(&aw.writer, .result_only);
|
||||
|
||||
const input = try aw.toOwnedSliceSentinel(0);
|
||||
defer gpa.free(input);
|
||||
|
||||
const machine_type = target.toCoffMachine();
|
||||
var def_diagnostics: def.Diagnostics = undefined;
|
||||
var module_def = def.parse(gpa, input, machine_type, .mingw, &def_diagnostics) catch |err| switch (err) {
|
||||
error.OutOfMemory => |e| return e,
|
||||
error.ParseError => {
|
||||
var buffer: [64]u8 = undefined;
|
||||
const w = std.debug.lockStderrWriter(&buffer);
|
||||
defer std.debug.unlockStderrWriter();
|
||||
try w.writeAll("error: ");
|
||||
try def_diagnostics.writeMsg(w, input);
|
||||
try w.writeByte('\n');
|
||||
return error.WritingImportLibFailed;
|
||||
},
|
||||
};
|
||||
defer module_def.deinit();
|
||||
|
||||
module_def.fixupForImportLibraryGeneration(machine_type);
|
||||
|
||||
break :members try implib.getMembers(gpa, module_def, machine_type);
|
||||
};
|
||||
defer members.deinit();
|
||||
|
||||
const lib_final_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename });
|
||||
errdefer gpa.free(lib_final_path);
|
||||
|
||||
if (!build_options.have_llvm) return error.ZigCompilerNotBuiltWithLLVMExtensions;
|
||||
const llvm_bindings = @import("../codegen/llvm/bindings.zig");
|
||||
const def_final_path_z = try arena.dupeZ(u8, def_final_path);
|
||||
const lib_final_path_z = try comp.dirs.global_cache.joinZ(arena, &.{lib_final_path});
|
||||
if (llvm_bindings.WriteImportLibrary(
|
||||
def_final_path_z.ptr,
|
||||
@intFromEnum(target.toCoffMachine()),
|
||||
lib_final_path_z.ptr,
|
||||
true,
|
||||
)) {
|
||||
// TODO surface a proper error here
|
||||
log.err("unable to turn {s}.def into {s}.lib", .{ lib_name, lib_name });
|
||||
return error.WritingImportLibFailed;
|
||||
{
|
||||
const lib_final_file = try o_dir.createFile(final_lib_basename, .{ .truncate = true });
|
||||
defer lib_final_file.close();
|
||||
var buffer: [1024]u8 = undefined;
|
||||
var file_writer = lib_final_file.writer(&buffer);
|
||||
try implib.writeCoffArchive(gpa, &file_writer.interface, members);
|
||||
try file_writer.interface.flush();
|
||||
}
|
||||
|
||||
man.writeManifest() catch |err| {
|
||||
|
||||
1079
src/libs/mingw/def.zig
Normal file
1079
src/libs/mingw/def.zig
Normal file
File diff suppressed because it is too large
Load Diff
1088
src/libs/mingw/implib.zig
Normal file
1088
src/libs/mingw/implib.zig
Normal file
File diff suppressed because it is too large
Load Diff
@ -39,9 +39,6 @@
|
||||
#include <llvm/Passes/StandardInstrumentations.h>
|
||||
#include <llvm/Object/Archive.h>
|
||||
#include <llvm/Object/ArchiveWriter.h>
|
||||
#include <llvm/Object/COFF.h>
|
||||
#include <llvm/Object/COFFImportFile.h>
|
||||
#include <llvm/Object/COFFModuleDefinition.h>
|
||||
#include <llvm/PassRegistry.h>
|
||||
#include <llvm/Support/CommandLine.h>
|
||||
#include <llvm/Support/FileSystem.h>
|
||||
@ -475,62 +472,6 @@ void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {
|
||||
cl::ParseCommandLineOptions(argc, argv);
|
||||
}
|
||||
|
||||
bool ZigLLVMWriteImportLibrary(const char *def_path, unsigned int coff_machine,
|
||||
const char *output_lib_path, bool kill_at)
|
||||
{
|
||||
COFF::MachineTypes machine = static_cast<COFF::MachineTypes>(coff_machine);
|
||||
|
||||
auto bufOrErr = MemoryBuffer::getFile(def_path);
|
||||
if (!bufOrErr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MemoryBuffer& buf = *bufOrErr.get();
|
||||
Expected<object::COFFModuleDefinition> def =
|
||||
object::parseCOFFModuleDefinition(buf, machine, /* MingwDef */ true);
|
||||
|
||||
if (!def) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The exports-juggling code below is ripped from LLVM's DlltoolDriver.cpp
|
||||
|
||||
// If ExtName is set (if the "ExtName = Name" syntax was used), overwrite
|
||||
// Name with ExtName and clear ExtName. When only creating an import
|
||||
// library and not linking, the internal name is irrelevant. This avoids
|
||||
// cases where writeImportLibrary tries to transplant decoration from
|
||||
// symbol decoration onto ExtName.
|
||||
for (object::COFFShortExport& E : def->Exports) {
|
||||
if (!E.ExtName.empty()) {
|
||||
E.Name = E.ExtName;
|
||||
E.ExtName.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (kill_at) {
|
||||
for (object::COFFShortExport& E : def->Exports) {
|
||||
if (!E.ImportName.empty() || (!E.Name.empty() && E.Name[0] == '?'))
|
||||
continue;
|
||||
if (machine == COFF::IMAGE_FILE_MACHINE_I386) {
|
||||
// By making sure E.SymbolName != E.Name for decorated symbols,
|
||||
// writeImportLibrary writes these symbols with the type
|
||||
// IMPORT_NAME_UNDECORATE.
|
||||
E.SymbolName = E.Name;
|
||||
}
|
||||
// Trim off the trailing decoration. Symbols will always have a
|
||||
// starting prefix here (either _ for cdecl/stdcall, @ for fastcall
|
||||
// or ? for C++ functions). Vectorcall functions won't have any
|
||||
// fixed prefix, but the function base name will still be at least
|
||||
// one char.
|
||||
E.Name = E.Name.substr(0, E.Name.find('@', 1));
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<bool>(
|
||||
object::writeImportLibrary(def->OutputFile, output_lib_path,
|
||||
def->Exports, machine, /* MinGW */ true));
|
||||
}
|
||||
|
||||
bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count,
|
||||
ZigLLVMArchiveKind archive_kind)
|
||||
{
|
||||
|
||||
@ -124,7 +124,4 @@ ZIG_EXTERN_C bool ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_earl
|
||||
ZIG_EXTERN_C bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count,
|
||||
ZigLLVMArchiveKind archive_kind);
|
||||
|
||||
ZIG_EXTERN_C bool ZigLLVMWriteImportLibrary(const char *def_path, unsigned int coff_machine,
|
||||
const char *output_lib_path, bool kill_at);
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user