From 20f91e0bc5e7cfa983e0f413a5e95f37f01782f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 17 Jul 2024 01:38:02 +0200 Subject: [PATCH] Add Zig bindings. --- README.md | 66 ++++++--------- build.zig | 43 +++++----- build.zig.zon | 1 + lib/aarch64.zig | 43 ++++++++++ lib/arc.zig | 12 +++ lib/arm.zig | 30 +++++++ lib/avr32.zig | 18 ++++ lib/csky.zig | 7 ++ lib/default.zig | 23 +++++ lib/ffi.zig | 199 ++++++++++++++++++++++++++++++++++++++++++++ lib/function.zig | 34 ++++++++ lib/loongarch64.zig | 28 +++++++ lib/m68k.zig | 7 ++ lib/mips.zig | 52 ++++++++++++ lib/powerpc.zig | 63 ++++++++++++++ lib/riscv.zig | 19 +++++ lib/s390.zig | 9 ++ lib/sparc.zig | 32 +++++++ lib/utils.zig | 13 +++ lib/x86.zig | 65 +++++++++++++++ lib/xtensa.zig | 7 ++ 21 files changed, 708 insertions(+), 63 deletions(-) create mode 100644 lib/aarch64.zig create mode 100644 lib/arc.zig create mode 100644 lib/arm.zig create mode 100644 lib/avr32.zig create mode 100644 lib/csky.zig create mode 100644 lib/default.zig create mode 100644 lib/ffi.zig create mode 100644 lib/function.zig create mode 100644 lib/loongarch64.zig create mode 100644 lib/m68k.zig create mode 100644 lib/mips.zig create mode 100644 lib/powerpc.zig create mode 100644 lib/riscv.zig create mode 100644 lib/s390.zig create mode 100644 lib/sparc.zig create mode 100644 lib/utils.zig create mode 100644 lib/x86.zig create mode 100644 lib/xtensa.zig diff --git a/README.md b/README.md index 78f6ed4cd..102b9c504 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,14 @@ # Vezel libffi Fork This is a friendly fork of [libffi](https://sourceware.org/libffi). The notable -change made in this fork is the addition of a [Zig](https://ziglang.org) build -script, making it easy to integrate libffi into Zig projects using the Zig -package manager. Additionally, to reduce the package download size, we have -removed a large number of files that are unnecessary when using libffi in a Zig -project. Importantly, **all library source code is identical to upstream**, so -in terms of API/ABI compatibility, using this fork is no different from linking -to a system libffi package. +changes made in this fork are the additions of a [Zig](https://ziglang.org) +build script, making it easy to integrate libffi into Zig projects using the Zig +package manager, and a set of idiomatic Zig bindings for libffi's main API. +Additionally, to reduce the package download size, we have removed a large +number of files that are unnecessary when using libffi in a Zig project. +Importantly, **all library source code is identical to upstream**, so in terms +of API/ABI compatibility, using this fork is no different from linking to a +system libffi package. ## Usage @@ -24,65 +25,50 @@ zig fetch --save=ffi https://github.com/vezel-dev/libffi/archive/vX.Y.Z-B.tar.gz zig fetch --save=ffi git+https://github.com/vezel-dev/libffi.git#vX.Y.Z-B ``` -(You can find the latest libffi version on the +(You can find the latest version on the [releases page](https://github.com/vezel-dev/libffi/releases).) -Then, in your `build.zig`: +Consume the library in your `build.zig`: ```zig -const ffi = b.dependency("ffi", .{}); -exe.linkLibrary(ffi.artifact("ffi")); +const ffi = b.dependency("ffi", .{ + .target = target, + .optimize = optimize, +}); + +exe.root_module.addImport("ffi", ffi.module("ffi")); -// Or, if you want to be able to integrate with a system package: if (b.systemIntegrationOption("ffi", .{})) { exe.linkSystemLibrary("ffi"); } else { - const ffi = b.dependency("ffi", .{ - .target = target, - .optimize = optimize, - }); exe.linkLibrary(ffi.artifact("ffi")); } ``` -You can then use the C header in your Zig code: +You can now use the Zig bindings in your code: ```zig const builtin = @import("builtin"); const std = @import("std"); const stdio = @cImport(@cInclude("stdio.h")); -const ffi = @cImport(@cInclude("ffi.h")); +const ffi = @import("ffi"); pub fn main() !void { std.debug.print("Calling C puts() on {s}.\n", .{builtin.cpu.arch.genericName()}); - var cif: ffi.ffi_cif = undefined; - var params = [_]?*ffi.ffi_type{ - &ffi.ffi_type_pointer, + var func: ffi.Function = undefined; + var params = [_]*ffi.Type{ + ffi.types.pointer, }; - switch (ffi.ffi_prep_cif( - &cif, - ffi.FFI_DEFAULT_ABI, - params.len, - &ffi.ffi_type_sint32, - params[0..params.len], - )) { - ffi.FFI_OK => {}, - else => |e| return switch (e) { - ffi.FFI_BAD_TYPEDEF => error.BadTypeDefinition, - ffi.FFI_BAD_ABI => error.BadAbi, - ffi.FFI_BAD_ARGTYPE => error.BadArgumentType, - else => unreachable, - }, - } - - var result: ffi.ffi_arg = undefined; - var args = [params.len]?*anyopaque{ + try func.prepare(ffi.Abi.default, params.len, ffi.types.sint32, params[0..params.len]); + + var result: ffi.uarg = undefined; + var args = [params.len]*anyopaque{ @ptrCast(@constCast(&"Hello World")), }; - ffi.ffi_call(&cif, @ptrCast(&stdio.puts), &result, args[0..args.len]); + func.call(@ptrCast(&stdio.puts), &result, args[0..args.len]); if (result == stdio.EOF) return error.IOError; diff --git a/build.zig b/build.zig index d34736dca..99be11ab0 100644 --- a/build.zig +++ b/build.zig @@ -1,29 +1,34 @@ const std = @import("std"); -const name = "libffi"; const version = "3.4.6"; // TODO: https://github.com/ziglang/zig/issues/14531 pub fn build(b: *std.Build) anyerror!void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); - const check = b.step("check", "Run source code checks"); - const fmt = b.step("fmt", "Fix source code formatting"); + const check_tls = b.step("check", "Run source code checks"); + const fmt_tls = b.step("fmt", "Fix source code formatting"); const fmt_paths = &[_][]const u8{ "build.zig", "build.zig.zon", }; - check.dependOn(&b.addFmt(.{ + check_tls.dependOn(&b.addFmt(.{ .paths = fmt_paths, .check = true, }).step); - fmt.dependOn(&b.addFmt(.{ + fmt_tls.dependOn(&b.addFmt(.{ .paths = fmt_paths, }).step); + _ = b.addModule("ffi", .{ + .root_source_file = b.path(b.pathJoin(&.{ "lib", "ffi.zig" })), + .target = target, + .optimize = optimize, + }); + const lib = b.addStaticLibrary(.{ .name = "ffi", .target = target, @@ -222,13 +227,6 @@ pub fn build(b: *std.Build) anyerror!void { "v9.S", }; }, - .wasm32 => { - arch_name = "wasm32"; - arch_target = "wasm32"; - arch_sources = &.{ - "ffi.c", - }; - }, .xtensa => { arch_name = "xtensa"; arch_target = "XTENSA"; @@ -258,7 +256,11 @@ pub fn build(b: *std.Build) anyerror!void { .linux => t.cpu.arch.isPPC() or t.cpu.arch.isPPC64(), else => false, }; - const long_double: LongDouble = if (t.cpu.arch.isMIPS() and (t.os.tag == .freebsd or t.os.tag == .linux or t.os.tag == .openbsd)) + const long_double: enum { + false, + true, + mips64, + } = if (t.cpu.arch.isMIPS() and (t.os.tag == .freebsd or t.os.tag == .linux or t.os.tag == .openbsd)) .mips64 else if (long_double_variant or long_double_size > double_size) .true @@ -329,11 +331,11 @@ pub fn build(b: *std.Build) anyerror!void { .HAVE_UNISTD_H = true, .LIBFFI_GNU_SYMBOL_VERSIONING = null, .LT_OBJDIR = null, // Not used. - .PACKAGE = name, + .PACKAGE = "libffi", .PACKAGE_BUGREPORT = "http://github.com/libffi/libffi/issues", - .PACKAGE_NAME = name, - .PACKAGE_STRING = name ++ " " ++ version, - .PACKAGE_TARNAME = name, + .PACKAGE_NAME = "libffi", + .PACKAGE_STRING = "libffi " ++ version, + .PACKAGE_TARNAME = "libffi", .PACKAGE_URL = "", .PACKAGE_VERSION = version, .SIZEOF_DOUBLE = double_size, @@ -357,12 +359,7 @@ pub fn build(b: *std.Build) anyerror!void { lib.addConfigHeader(h); } + // libffi has historically put its header files directly in the include path, rather than a subdirectory. lib.installConfigHeader(ffi_h); lib.installHeader(b.path(b.pathJoin(&.{ "src", arch_name, "ffitarget.h" })), "ffitarget.h"); } - -const LongDouble = enum { - false, - true, - mips64, -}; diff --git a/build.zig.zon b/build.zig.zon index 4bb424894..97b9fb4c2 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -9,6 +9,7 @@ "build.zig.zon", "fficonfig.zig.h", "include", + "lib", "src", }, .dependencies = .{}, diff --git a/lib/aarch64.zig b/lib/aarch64.zig new file mode 100644 index 000000000..177546a99 --- /dev/null +++ b/lib/aarch64.zig @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT + +const builtin = @import("builtin"); + +const ffi = @import("ffi.zig"); +const default = @import("default.zig"); + +pub const have_complex_type = builtin.os.tag != .windows; + +const arg_longlong = builtin.cpu.arch == .aarch64_32 or builtin.os.tag == .windows; + +pub const uarg = if (arg_longlong) c_ulonglong else c_ulong; +pub const sarg = if (arg_longlong) c_longlong else c_long; + +pub const Abi = enum(i32) { + sysv = 1, + win64 = 2, + _, + + pub const default: Abi = if (builtin.os.tag == .windows) .win64 else .sysv; +}; + +pub const Function = if (builtin.os.tag.isDarwin()) extern struct { + abi: Abi, + nargs: c_uint, + arg_types: ?[*]*ffi.Type, + rtype: *ffi.Type, + bytes: c_uint, + flags: c_uint, + aarch64_nfixedargs: c_uint, + + pub usingnamespace @import("function.zig"); +} else if (builtin.os.tag == .windows) extern struct { + abi: Abi, + nargs: c_uint, + arg_types: ?[*]*ffi.Type, + rtype: *ffi.Type, + bytes: c_uint, + flags: c_uint, + is_variadic: c_uint, + + pub usingnamespace @import("function.zig"); +} else default.Function(Abi); diff --git a/lib/arc.zig b/lib/arc.zig new file mode 100644 index 000000000..b31c53aac --- /dev/null +++ b/lib/arc.zig @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +const default = @import("default.zig"); + +pub const Abi = enum(i32) { + arcompact = 1, + _, + + pub const default: Abi = .arcompact; +}; + +pub const Function = default.Function(Abi); diff --git a/lib/arm.zig b/lib/arm.zig new file mode 100644 index 000000000..8cc554905 --- /dev/null +++ b/lib/arm.zig @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT + +const builtin = @import("builtin"); + +const ffi = @import("ffi.zig"); + +pub const have_complex_type = builtin.os.tag != .windows; + +pub const Abi = enum(i32) { + sysv = 1, + vfp = 2, + _, + + pub const default: Abi = if (builtin.abi.floatAbi() != .soft or builtin.os.tag == .windows) .vfp else .sysv; +}; + +pub const Function = extern struct { + abi: Abi, + nargs: c_uint, + arg_types: ?[*]*ffi.Type, + rtype: *ffi.Type, + bytes: c_uint, + flags: c_uint, + vfp_used: c_int, + vfp_reg_free: c_ushort, + vfp_nargs: c_ushort, + vfp_args: [16]i8, + + pub usingnamespace @import("function.zig"); +}; diff --git a/lib/avr32.zig b/lib/avr32.zig new file mode 100644 index 000000000..5683edee4 --- /dev/null +++ b/lib/avr32.zig @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +const ffi = @import("ffi.zig"); +const default = @import("default.zig"); + +pub const Abi = default.Abi; + +pub const Function = extern struct { + abi: Abi, + nargs: c_uint, + arg_types: ?[*]*ffi.Type, + rtype: *ffi.Type, + bytes: c_uint, + flags: c_uint, + rstruct_flag: c_uint, + + pub usingnamespace @import("function.zig"); +}; diff --git a/lib/csky.zig b/lib/csky.zig new file mode 100644 index 000000000..032f323b8 --- /dev/null +++ b/lib/csky.zig @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +const default = @import("default.zig"); + +pub const Abi = default.Abi; + +pub const Function = default.Function(Abi); diff --git a/lib/default.zig b/lib/default.zig new file mode 100644 index 000000000..717937f55 --- /dev/null +++ b/lib/default.zig @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +const ffi = @import("ffi.zig"); + +pub const Abi = enum(i32) { + sysv = 1, + _, + + pub const default: Abi = .sysv; +}; + +pub fn Function(TAbi: type) type { + return extern struct { + abi: TAbi, + nargs: c_uint, + arg_types: ?[*]*ffi.Type, + rtype: *ffi.Type, + bytes: c_uint, + flags: c_uint, + + pub usingnamespace @import("function.zig"); + }; +} diff --git a/lib/ffi.zig b/lib/ffi.zig new file mode 100644 index 000000000..54f404aa8 --- /dev/null +++ b/lib/ffi.zig @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: MIT + +const builtin = @import("builtin"); +const std = @import("std"); + +const utils = @import("utils.zig"); +const target = switch (builtin.cpu.arch) { + .aarch64, .aarch64_be, .aarch64_32 => @import("aarch64.zig"), + .arc => @import("arc.zig"), + .arm, .armeb => @import("arm.zig"), + .avr => @import("avr32.zig"), + .csky => @import("csky.zig"), + .x86, .x86_64 => @import("x86.zig"), + .loongarch64 => @import("loongarch64.zig"), + .m68k => @import("m68k.zig"), + .mips, .mipsel, .mips64, .mips64el => @import("mips.zig"), + .powerpc, .powerpcle, .powerpc64, .powerpc64le => @import("powerpc.zig"), + .riscv32, .riscv64 => @import("riscv.zig"), + .s390x => @import("s390.zig"), + .sparc, .sparc64, .sparcel => @import("sparc.zig"), + .xtensa => @import("xtensa.zig"), + else => @compileError("This target is not supported by libffi."), +}; + +pub const have_long_double = if (@hasDecl(target, "have_long_double")) + target.have_long_double +else + builtin.target.c_type_byte_size(.longdouble) > builtin.target.c_type_byte_size(.double); +pub const have_complex_type = if (@hasDecl(target, "have_complex_type")) target.have_complex_type else false; + +pub const uarg = if (@hasDecl(target, "uarg")) target.uarg else c_ulong; +pub const sarg = if (@hasDecl(target, "sarg")) target.sarg else c_long; + +pub const Status = enum(i32) { + ok = 0, + bad_type_definition = 1, + bad_abi = 2, + bad_argument_type = 3, + _, +}; + +pub const Error = error{ + BadTypeDefinition, + BadAbi, + BadArgumentType, + Unexpected, +}; + +pub const TypeId = if (have_long_double) enum(c_ushort) { + void = 0, + int = 1, + float = 2, + double = 3, + long_double = 4, + uint8 = 5, + sint8 = 6, + uint16 = 7, + sint16 = 8, + uint32 = 9, + sint32 = 10, + uint64 = 11, + sint64 = 12, + @"struct" = 13, + pointer = 14, + complex = 15, + _, +} else enum(c_ushort) { + void = 0, + int = 1, + float = 2, + double = 3, + uint8 = 5, + sint8 = 6, + uint16 = 7, + sint16 = 8, + uint32 = 9, + sint32 = 10, + uint64 = 11, + sint64 = 12, + @"struct" = 13, + pointer = 14, + complex = 15, + _, +}; + +pub const Type = extern struct { + size: usize, + alignment: c_ushort, + type: TypeId, + elements: ?[*:null]?*Type, + + pub fn getElementOffsets(self: *Type, abi: Abi, offsets: [*]usize) Error!void { + return utils.wrap(ffi_get_struct_offsets(self, abi, offsets)); + } +}; + +pub const Abi = target.Abi; + +pub const Function = target.Function; + +pub extern var ffi_type_void: Type; +pub extern var ffi_type_uint8: Type; +pub extern var ffi_type_sint8: Type; +pub extern var ffi_type_uint16: Type; +pub extern var ffi_type_sint16: Type; +pub extern var ffi_type_uint32: Type; +pub extern var ffi_type_sint32: Type; +pub extern var ffi_type_uint64: Type; +pub extern var ffi_type_sint64: Type; +pub extern var ffi_type_float: Type; +pub extern var ffi_type_double: Type; +pub extern var ffi_type_pointer: Type; +pub extern var ffi_type_longdouble: Type; +pub extern var ffi_type_complex_float: Type; +pub extern var ffi_type_complex_double: Type; +pub extern var ffi_type_complex_longdouble: Type; + +pub const types = struct { + pub const @"void" = &ffi_type_void; + pub const uint8 = &ffi_type_uint8; + pub const sint8 = &ffi_type_sint8; + pub const uint16 = &ffi_type_uint16; + pub const sint16 = &ffi_type_sint16; + pub const uint32 = &ffi_type_uint32; + pub const sint32 = &ffi_type_sint32; + pub const uint64 = &ffi_type_uint64; + pub const sint64 = &ffi_type_sint64; + pub const float = &ffi_type_float; + pub const double = &ffi_type_double; + pub const pointer = &ffi_type_pointer; + pub const longDouble = &ffi_type_longdouble; + pub const complexFloat = if (have_complex_type) + &ffi_type_complex_float + else + @compileError("This target does not support complex types."); + pub const complexDouble = if (have_complex_type) + &ffi_type_complex_double + else + @compileError("This target does not support complex types."); + pub const complexLongDouble = if (have_complex_type) + &ffi_type_complex_longdouble + else + @compileError("This target does not support complex types."); + + pub const uchar = &ffi_type_uint8; + pub const schar = &ffi_type_sint8; + pub const ushort = &ffi_type_uint16; + pub const sshort = &ffi_type_sint16; + pub const uint = switch (builtin.target.c_type_bit_size(.uint)) { + 16 => &ffi_type_uint16, + 32 => &ffi_type_uint32, + else => unreachable, + }; + pub const sint = switch (builtin.target.c_type_bit_size(.int)) { + 16 => &ffi_type_sint16, + 32 => &ffi_type_sint32, + else => unreachable, + }; + pub const ulong = switch (builtin.target.c_type_bit_size(.ulong)) { + 32 => &ffi_type_uint32, + 64 => &ffi_type_uint64, + else => unreachable, + }; + pub const long = switch (builtin.target.c_type_bit_size(.long)) { + 32 => &ffi_type_sint32, + 64 => &ffi_type_sint64, + else => unreachable, + }; +}; + +pub extern fn ffi_prep_cif( + cif: *Function, + abi: Abi, + nargs: c_uint, + rtype: *Type, + atypes: ?[*]*Type, +) Status; + +pub extern fn ffi_prep_cif_var( + cif: *Function, + abi: Abi, + nfixedargs: c_uint, + ntotalargs: c_uint, + rtype: *Type, + atypes: ?[*]*Type, +) Status; + +pub extern fn ffi_call( + cif: *Function, + @"fn": *const fn () callconv(.C) void, + rvalue: ?*anyopaque, + avalue: ?[*]*anyopaque, +) void; + +pub extern fn ffi_get_struct_offsets( + abi: Abi, + struct_type: *Type, + offsets: [*]usize, +) Status; diff --git a/lib/function.zig b/lib/function.zig new file mode 100644 index 000000000..6bd1f5711 --- /dev/null +++ b/lib/function.zig @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +const ffi = @import("ffi.zig"); +const utils = @import("utils.zig"); + +pub fn prepare( + self: *ffi.Function, + abi: ffi.Abi, + nargs: c_uint, + rtype: *ffi.Type, + atypes: ?[*]*ffi.Type, +) ffi.Error!void { + return utils.wrap(ffi.ffi_prep_cif(self, abi, nargs, rtype, atypes)); +} + +pub fn prepareVarArgs( + self: *ffi.Function, + abi: ffi.Abi, + nfixedargs: c_uint, + ntotalargs: c_uint, + rtype: *ffi.Type, + atypes: ?[*]*ffi.Type, +) ffi.Error!void { + return utils.wrap(ffi.ffi_prep_cif_var(self, abi, nfixedargs, ntotalargs, rtype, atypes)); +} + +pub fn call( + self: *ffi.Function, + @"fn": *const fn () callconv(.C) void, + rvalue: ?*anyopaque, + avalue: ?[*]*anyopaque, +) void { + ffi.ffi_call(self, @"fn", rvalue, avalue); +} diff --git a/lib/loongarch64.zig b/lib/loongarch64.zig new file mode 100644 index 000000000..a83a7a6ee --- /dev/null +++ b/lib/loongarch64.zig @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +const builtin = @import("builtin"); + +const ffi = @import("ffi.zig"); + +pub const Abi = enum(i32) { + lp64s = 1, + lp64f = 2, + lp64d = 3, + _, + + // TODO: https://github.com/ziglang/zig/pull/20389 + pub const default: Abi = if (builtin.abi.floatAbi() == .soft) .lp64s else .lp64d; +}; + +pub const Function = extern struct { + abi: Abi, + nargs: c_uint, + arg_types: ?[*]*ffi.Type, + rtype: *ffi.Type, + bytes: c_uint, + flags: c_uint, + loongarch_nfixedargs: c_uint, + loongarch_unused: c_uint, + + pub usingnamespace @import("function.zig"); +}; diff --git a/lib/m68k.zig b/lib/m68k.zig new file mode 100644 index 000000000..032f323b8 --- /dev/null +++ b/lib/m68k.zig @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +const default = @import("default.zig"); + +pub const Abi = default.Abi; + +pub const Function = default.Function(Abi); diff --git a/lib/mips.zig b/lib/mips.zig new file mode 100644 index 000000000..61d67ca20 --- /dev/null +++ b/lib/mips.zig @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT + +const builtin = @import("builtin"); + +const ffi = @import("ffi.zig"); + +pub const have_long_double = switch (builtin.cpu.arch) { + .mips64, .mips64el => switch (builtin.os.tag) { + .freebsd, .linux, .openbsd => true, + else => false, + }, + else => false, +}; +pub const have_complex_type = true; + +const arg_64 = switch (builtin.cpu.arch) { + .mips, .mipsel => false, + .mips64, .mips64el => true, + else => unreachable, +}; + +pub const uarg = if (arg_64) u64 else u32; +pub const sarg = if (arg_64) i64 else i32; + +pub const Abi = enum(i32) { + o32 = 1, + n32 = 2, + n64 = 3, + o32_soft_float = 4, + n32_soft_float = 5, + n64_soft_float = 6, + _, + + pub const default: Abi = switch (builtin.cpu.arch) { + .mips, .mipsel => .o32, + .mips64, .mips64el => if (builtin.abi == .gnuabi64) .n64 else .n32, + else => unreachable, + }; +}; + +pub const Function = extern struct { + abi: Abi, + nargs: c_uint, + arg_types: ?[*]*ffi.Type, + rtype: *ffi.Type, + bytes: c_uint, + flags: c_uint, + rstruct_flag: c_uint, + mips_nfixedargs: c_uint, + + pub usingnamespace @import("function.zig"); +}; diff --git a/lib/powerpc.zig b/lib/powerpc.zig new file mode 100644 index 000000000..55d6eb786 --- /dev/null +++ b/lib/powerpc.zig @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT + +const builtin = @import("builtin"); + +const ffi = @import("ffi.zig"); +const default = @import("default.zig"); + +pub const have_long_double = switch (builtin.os.tag) { + .freebsd, .netbsd, .openbsd => builtin.cpu.arch == .powerpc, + .linux => true, + else => false, +}; + +pub const Abi = if (builtin.os.tag.isDarwin() or builtin.os.tag == .aix) enum(i32) { + aix = 1, + darwin = 2, + _, + + pub const default: Abi = if (builtin.os.tag.isDarwin()) .darwin else .aix; +} else if (builtin.cpu.arch.isPPC64()) packed struct(i32) { + linux_struct_align: bool, + linux_long_double_128: bool, + linux_long_double_ieee128: bool, + linux: bool, + _pad: i28 = 0, + + pub const default: Abi = .{ + .linux_struct_align = !(builtin.cpu.arch == .powerpc64 and builtin.abi == .gnu), + .linux_long_double_128 = builtin.abi != .musl, + .linux_long_double_ieee128 = false, + .linux = true, + }; +} else packed struct(i32) { + sysv_soft_float: bool, + sysv_struct_ret: bool, + sysv_ibm_long_double: bool, + sysv: bool, + sysv_long_double_128: bool, + _pad: i27 = 0, + + pub const default: Abi = .{ + .sysv_soft_float = false, + .sysv_struct_ret = switch (builtin.os.tag) { + .freebsd, .netbsd, .openbsd => true, + else => false, + }, + .sysv_ibm_long_double = builtin.abi != .musl, + .sysv = true, + .sysv_long_double_128 = builtin.abi != .musl, + }; +}; + +pub const Function = if (!builtin.os.tag.isDarwin() and builtin.os.tag != .aix) extern struct { + abi: Abi, + nargs: c_uint, + arg_types: ?[*]*ffi.Type, + rtype: *ffi.Type, + bytes: c_uint, + flags: c_uint, + nfixedargs: c_uint, + + pub usingnamespace @import("function.zig"); +} else default.Function(Abi); diff --git a/lib/riscv.zig b/lib/riscv.zig new file mode 100644 index 000000000..4b4defaf4 --- /dev/null +++ b/lib/riscv.zig @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +const ffi = @import("ffi.zig"); +const default = @import("default.zig"); + +pub const Abi = default.Abi; + +pub const Function = extern struct { + abi: Abi, + nargs: c_uint, + arg_types: ?[*]*ffi.Type, + rtype: *ffi.Type, + bytes: c_uint, + flags: c_uint, + riscv_nfixedargs: c_uint, + riscv_unused: c_uint, + + pub usingnamespace @import("function.zig"); +}; diff --git a/lib/s390.zig b/lib/s390.zig new file mode 100644 index 000000000..58a7f0f9d --- /dev/null +++ b/lib/s390.zig @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +const default = @import("default.zig"); + +pub const have_complex_type = true; + +pub const Abi = default.Abi; + +pub const Function = default.Function(Abi); diff --git a/lib/sparc.zig b/lib/sparc.zig new file mode 100644 index 000000000..b0349c868 --- /dev/null +++ b/lib/sparc.zig @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT + +const builtin = @import("builtin"); + +const ffi = @import("ffi.zig"); +const default = @import("default.zig"); + +pub const have_complex_type = true; + +pub const Abi = if (builtin.cpu.arch == .sparc64) enum(i32) { + v9 = 1, + _, + + pub const default: Abi = .v9; +} else enum(i32) { + v8 = 1, + _, + + pub const default: Abi = .v8; +}; + +pub const Function = if (builtin.cpu.arch == .sparc64) extern struct { + abi: Abi, + nargs: c_uint, + arg_types: ?[*]*ffi.Type, + rtype: *ffi.Type, + bytes: c_uint, + flags: c_uint, + nfixedargs: c_uint, + + pub usingnamespace @import("function.zig"); +} else default.Function(Abi); diff --git a/lib/utils.zig b/lib/utils.zig new file mode 100644 index 000000000..42e8591b3 --- /dev/null +++ b/lib/utils.zig @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +const ffi = @import("ffi.zig"); + +pub fn wrap(status: ffi.Status) ffi.Error!void { + return switch (status) { + .ok => {}, + .bad_type_definition => error.BadTypeDefinition, + .bad_abi => error.BadAbi, + .bad_argument_type => error.BadArgumentType, + _ => error.Unexpected, + }; +} diff --git a/lib/x86.zig b/lib/x86.zig new file mode 100644 index 000000000..6c36b24a6 --- /dev/null +++ b/lib/x86.zig @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT + +const builtin = @import("builtin"); + +const default = @import("default.zig"); + +pub const have_complex_type = true; + +const arg_longlong = r: { + if (builtin.cpu.arch == .x86_64) { + if (builtin.os.tag == .windows) { + break :r true; + } + + switch (builtin.abi) { + .gnux32, .muslx32 => break :r true, + else => {}, + } + } + + break :r false; +}; + +pub const uarg = if (arg_longlong) c_ulonglong else c_ulong; +pub const sarg = if (arg_longlong) c_longlong else c_long; + +pub const Abi = if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows) enum(i32) { + win64 = 1, + gnuw64 = 2, + _, + + pub const default: Abi = if (builtin.abi == .msvc) .win64 else .gnuw64; +} else if (builtin.cpu.arch == .x86_64) enum(i32) { + unix64 = 2, + win64 = 3, + gnuw64 = 4, + _, + + pub const efi64: Abi = .efi64; + pub const default: Abi = .unix64; +} else if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) enum(i32) { + sysv = 1, + stdcall = 2, + thiscall = 3, + fastcall = 4, + ms_cdecl = 5, + pascal = 6, + register = 7, + _, + + pub const default: Abi = .ms_cdecl; +} else if (builtin.cpu.arch == .x86) enum(i32) { + sysv = 1, + thiscall = 3, + fastcall = 4, + stdcall = 5, + pascal = 6, + register = 7, + ms_cdecl = 8, + _, + + pub const default: Abi = .sysv; +}; + +pub const Function = default.Function(Abi); diff --git a/lib/xtensa.zig b/lib/xtensa.zig new file mode 100644 index 000000000..032f323b8 --- /dev/null +++ b/lib/xtensa.zig @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +const default = @import("default.zig"); + +pub const Abi = default.Abi; + +pub const Function = default.Function(Abi);