mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +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
6 changed files with 2210 additions and 98 deletions
|
|
@ -338,14 +338,6 @@ extern fn ZigLLVMWriteArchive(
|
||||||
pub const ParseCommandLineOptions = ZigLLVMParseCommandLineOptions;
|
pub const ParseCommandLineOptions = ZigLLVMParseCommandLineOptions;
|
||||||
extern fn ZigLLVMParseCommandLineOptions(argc: usize, argv: [*]const [*:0]const u8) void;
|
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;
|
pub const GetHostCPUName = LLVMGetHostCPUName;
|
||||||
extern fn LLVMGetHostCPUName() ?[*:0]u8;
|
extern fn LLVMGetHostCPUName() ?[*:0]u8;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,13 @@ const Compilation = @import("../Compilation.zig");
|
||||||
const build_options = @import("build_options");
|
const build_options = @import("build_options");
|
||||||
const Cache = std.Build.Cache;
|
const Cache = std.Build.Cache;
|
||||||
const dev = @import("../dev.zig");
|
const dev = @import("../dev.zig");
|
||||||
|
const def = @import("mingw/def.zig");
|
||||||
|
const implib = @import("mingw/implib.zig");
|
||||||
|
|
||||||
|
test {
|
||||||
|
_ = def;
|
||||||
|
_ = implib;
|
||||||
|
}
|
||||||
|
|
||||||
pub const CrtFile = enum {
|
pub const CrtFile = enum {
|
||||||
crt2_o,
|
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, .{});
|
var o_dir = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{});
|
||||||
defer o_dir.close();
|
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");
|
const aro = @import("aro");
|
||||||
var diagnostics: aro.Diagnostics = .{
|
var diagnostics: aro.Diagnostics = .{
|
||||||
.output = .{ .to_list = .{ .arena = .init(gpa) } },
|
.output = .{ .to_list = .{ .arena = .init(gpa) } },
|
||||||
|
|
@ -312,7 +314,6 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||||
defer std.debug.unlockStderrWriter();
|
defer std.debug.unlockStderrWriter();
|
||||||
nosuspend stderr.print("def file: {s}\n", .{def_file_path}) catch break :print;
|
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("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);
|
try aro_comp.include_dirs.append(gpa, include_dir);
|
||||||
|
|
@ -339,32 +340,46 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
const members = members: {
|
||||||
// new scope to ensure definition file is written before passing the path to WriteImportLibrary
|
var aw: std.Io.Writer.Allocating = .init(gpa);
|
||||||
const def_final_file = try o_dir.createFile(final_def_basename, .{ .truncate = true });
|
errdefer aw.deinit();
|
||||||
defer def_final_file.close();
|
try pp.prettyPrintTokens(&aw.writer, .result_only);
|
||||||
var buffer: [1024]u8 = undefined;
|
|
||||||
var file_writer = def_final_file.writer(&buffer);
|
const input = try aw.toOwnedSliceSentinel(0);
|
||||||
try pp.prettyPrintTokens(&file_writer.interface, .result_only);
|
defer gpa.free(input);
|
||||||
try file_writer.interface.flush();
|
|
||||||
}
|
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 });
|
const lib_final_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename });
|
||||||
errdefer gpa.free(lib_final_path);
|
errdefer gpa.free(lib_final_path);
|
||||||
|
|
||||||
if (!build_options.have_llvm) return error.ZigCompilerNotBuiltWithLLVMExtensions;
|
{
|
||||||
const llvm_bindings = @import("../codegen/llvm/bindings.zig");
|
const lib_final_file = try o_dir.createFile(final_lib_basename, .{ .truncate = true });
|
||||||
const def_final_path_z = try arena.dupeZ(u8, def_final_path);
|
defer lib_final_file.close();
|
||||||
const lib_final_path_z = try comp.dirs.global_cache.joinZ(arena, &.{lib_final_path});
|
var buffer: [1024]u8 = undefined;
|
||||||
if (llvm_bindings.WriteImportLibrary(
|
var file_writer = lib_final_file.writer(&buffer);
|
||||||
def_final_path_z.ptr,
|
try implib.writeCoffArchive(gpa, &file_writer.interface, members);
|
||||||
@intFromEnum(target.toCoffMachine()),
|
try file_writer.interface.flush();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
man.writeManifest() catch |err| {
|
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/Passes/StandardInstrumentations.h>
|
||||||
#include <llvm/Object/Archive.h>
|
#include <llvm/Object/Archive.h>
|
||||||
#include <llvm/Object/ArchiveWriter.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/PassRegistry.h>
|
||||||
#include <llvm/Support/CommandLine.h>
|
#include <llvm/Support/CommandLine.h>
|
||||||
#include <llvm/Support/FileSystem.h>
|
#include <llvm/Support/FileSystem.h>
|
||||||
|
|
@ -475,62 +472,6 @@ void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {
|
||||||
cl::ParseCommandLineOptions(argc, 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,
|
bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count,
|
||||||
ZigLLVMArchiveKind archive_kind)
|
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,
|
ZIG_EXTERN_C bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count,
|
||||||
ZigLLVMArchiveKind archive_kind);
|
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
|
#endif
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue