stage1 C ABI compatibility
andrewrk opened this issue Β· 79 comments
This issue is to track C ABI compatibility support in the stage1 compiler.
Here's what support looks like currently:
- integers, floats, pointers, enums, bools work on every target, as parameters and return values
- x86_64: struct & union parameters & return values larger than 16 bytes
- x86_64: struct & union parameters that have at least 1 integer in them
- x86_64: struct & union parameters <= 16 bytes which break structs into parameters
- x86_64: struct & union parameters <= 16 bytes which are all floats
- x86_64: struct & union return values <= 16 bytes
- ARM: struct & union return values
- ARM: struct & union parameters
- C ABI for parameters that is unsupported gives a compile error linking to this issue
- C ABI for return values that is unsupported gives a compile error linking to this issue
- other architectures structs & unions parameters & return values
For those who find this issue from the compile error, leave a comment detailing your specific needs and I'll see if I can code those up for you to unblock you, so you don't have to wait for this issue to be 100% solved.
Update:
I just merged a branch into master which does the following things:
- Unsupported C ABI gives a compile error, like this:
const ASmallUnion = extern union {
r: u8,
};
extern fn foo(x: ASmallUnion) void;
pub fn main() void {
const x = ASmallUnion{ .r = 0x12 };
foo(col);
}
/home/andy/downloads/zig/build/test.zig:4:8: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
extern fn foo(x: ASmallUnion) void;
^
/home/andy/downloads/zig/build/test.zig:4:8: note: pointers, integers, floats, bools, and enums work on all targets
extern fn foo(x: ASmallUnion) void;
^
- There is a new type of test, C ABI tests, which covers the C ABI that we do suport. See
test/stage1/c_abi/*
for the source.
Test 1/9 C importing Zig ABI Tests...OK
Test 2/9 C ABI integers...OK
Test 3/9 C ABI floats...OK
Test 4/9 C ABI pointer...OK
Test 5/9 C ABI bool...OK
Test 6/9 C ABI array...OK
Test 7/9 C ABI big struct...OK
Test 8/9 C ABI big union...OK
Test 9/9 C ABI small struct of ints...OK
- Added all targets C ABI support for integers, floats, bools, enums, and pointers
- Added x86_64 C ABI support for big structs and unions (which are passed by memory)
- Added x86_64 C ABI support for small structs which contain at least one integer
Zig will now either panic or emit a compile error when C ABI compatibility is required that it doesn't support yet. Therefore this issue is now an enhancement in order to provide additional C ABI compatibility and not a bug.
For those who find this issue from the compile error, leave a comment detailing your specific needs and I'll see if I can code those up for you to unblock you, so you don't have to wait for this issue to be 100% solved.
Running into this issue when trying to work with the godot native headers.
"TODO implement C ABI for x86_64 return types. type 'godot_string'"
Running into this when bringing up the BGFX rendering library on 64-bit Linux.
My code calls the following function:
bgfx_create_vertex_buffer()
Error message:
TODO implement C ABI for x86_64 return types. type 'struct_bgfx_vertex_buffer_handle_s'
bgfx_vertex_buffer_handle_s
is defined in this header, using a macro.
The macro evaluates to the following struct definition:
typedef struct bgfx_vertex_buffer_handle_s {
uint16_t idx;
} bgfx_vertex_buffer_handle_t
This seems to correspond to "x86_64: struct & union return values <= 16 bytes," above.
Please advise on how to get unblocked. π
Thanks much for your hard work!
I'm using BGFX as well - not sure if @DavidYKay 's issue will affect me as well, but it will most likely end up blocking me too.
Trying to use the CSFML Network API -
const std = @import("std");
const defines = @import("defines.zig");
const ZealErrors = @import("error.zig").ZealErrors;
const sfml = @cImport({
// See https://github.com/zig-lang/zig/issues/515
@cDefine("_NO_CRT_STDIO_INLINE", "1");
@cInclude("SFML/Network.h");
});
var listener: ?*sfml.sfTcpListener = undefined;
pub fn init() u8 {
listener = sfml.sfTcpListener_create();
if (listener == null) {
return defines.QUIT_FAILURE;
}
var socket_status = sfml.sfTcpListener_listen(listener, 8080, sfml.sfIpAddress_Any);
return defines.QUIT_SUCCESS;
}
I'm using the CSFML library - csfml: stable 2.4 (bottled), HEAD
I installed via homebrew on macOS High Sierra 10.13.6 (17G65)
Here is the related header file(s) - https://github.com/SFML/CSFML/blob/master/include/SFML/Network/TcpListener.h
Here's the offending function signature written in Zig - pub extern fn sfTcpListener_listen(listener: ?*sfTcpListener, port: c_ushort, address: sfIpAddress) sfSocketStatus;
And the error -
/Users/zachcarter/projects/zeal_zig/src/console_server.zig:23:5: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
pub extern fn sfTcpListener_listen(listener: ?*sfTcpListener, port: c_ushort, address: sfIpAddress) sfSocketStatus;
^
/Users/zachcarter/projects/zeal_zig/src/console_server.zig:23:5: note: pointers, integers, floats, bools, and enums work on all targets
pub extern fn sfTcpListener_listen(listener: ?*sfTcpListener, port: c_ushort, address: sfIpAddress) sfSocketStatus;
And here's the above example, without using @cimport
-
const std = @import("std");
const defines = @import("defines.zig");
const ZealErrors = @import("error.zig").ZealErrors;
pub const struct_sfTcpListener = @OpaqueType();
pub const sfTcpListener = struct_sfTcpListener;
pub const sfIpAddress = extern struct {
address: [16]u8,
};
pub const sfSocketStatus = extern enum {
sfSocketDone = 0,
sfSocketNotReady = 1,
sfSocketPartial = 2,
sfSocketDisconnected = 3,
sfSocketError = 4,
};
pub extern const sfIpAddress_Any: sfIpAddress;
pub extern fn sfTcpListener_create() ?*sfTcpListener;
pub extern fn sfTcpListener_listen(listener: ?*sfTcpListener, port: c_ushort, address: sfIpAddress) sfSocketStatus;
var listener: ?*sfTcpListener = undefined;
pub fn init() u8 {
listener = sfTcpListener_create();
if (listener == null) {
return defines.QUIT_FAILURE;
}
var socket_status = sfTcpListener_listen(listener, 8080, sfIpAddress_Any);
return defines.QUIT_SUCCESS;
}
Trying to run @sizeof builtin on packed structs from 2 bytes to 8 bytes, compiler emits the following: error: TODO: support C ABI for more targets. #1481
This is the relevant code (from x86_64.zig):
// Segment Selector
pub const SegmentSelector = packed struct {
rpl: u2,
ti: u1,
index: u13,
};
From kzig.zig:
const m1 = "sizeof(SegmentSelector) == %lu\n";
efi_result = klib.uefi.AsciiPrint(&m1, @sizeOf(x86.SegmentSelector));
I'm trying to use XCB, translating this hello world program into Zig.
Here's what I have so far:
const std = @import("std");
const xcb = @cImport({
@cInclude("xcb/xcb.h");
});
pub fn main() error!void {
std.debug.warn("Starting...\n");
const connection = xcb.xcb_connect(null, null);
defer xcb.xcb_disconnect(connection);
const screen = xcb
.xcb_setup_roots_iterator(xcb.xcb_get_setup(connection)).data;
const window = xcb.xcb_generate_id(connection);
xcb.xcb_create_window(connection,
xcb.XCB_COPY_FROM_PARENT,
window,
screen.root,
0, 0,
150, 150,
10,
xcb.XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen.root_visual,
0, null);
xcb.xcb_map_window(connection, window);
xcb.xcb_flush(connection);
const stdin = try std.io.getStdIn();
stdin.readByte();
}
And the error message:
TODO implement C ABI for x86_64 return types. type 'struct_xcb_screen_iterator_t'
Referring to the type of screen
.
Also, I am a newcomer to Zig, so it's possible I'm doing something wrong.
Thank you for your time!
trying to use https://github.com/cimgui/cimgui
many functions take a struct parameter:
struct ImVec2
{
float x, y;
};
Vector ABI depends on the compiler flags on x86_64, and current the c_abi tests have the compiler flags mixed up so that the zig version expects arguments to be passed in registers (such as %ymm0 and %zmm0 that don't exist on earlier CPUs, which only have %xmm0 et cetera) and the c version expects things to be passed on the stack.
But clearly the C can also pass on the stack with certain arguments https://godbolt.org/z/RCPb2c , we are passing -march=native so I don't know what we get the stack behavior https://godbolt.org/z/DzE_Px
just got here for the same reason as @xxxbxxx (also wrapping cimgui... ;))
I only hit this error when I define my own extern
function with ImVec2
parameters, return values and calling functions taking ImVec2
work fine.
/my_module.zig:37:24: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
linux.panic(c"%s", message);
This was me trying to use a variadic C function in x86_64-freestanding-gnu
x86_64: struct & union parameters <= 16 bytes which break structs into parameters
x86_64: struct & union parameters <= 16 bytes which are all floats
x86_64: struct & union return values <= 16 bytes
These would all be useful for C interop with the Chipmunk 2D game physics library: https://chipmunk-physics.net/
trying to use raylib but getting the error
TODO: support C ABI for more targets. #1481
pub extern fn DrawTextureV(texture: Texture2D, position: Vector2, tint: Color) void;
^
but calling the alternaitve (below) is valid -
void DrawTexture(Texture2D texture, int posX, int posY, Color tint);
matching the case
x86_64: struct & union parameters <= 16 bytes which are all floats
Vector2 defined as
typedef struct Vector2 {
float x;
float y;
} Vector2;
is there any way to bypass this? the issue makes the library unusable for now
I ran into this trying to use nuklear on x86_64.
[nix-shell:~/focus/memory]$ zig build run
Semantic Analysis [471/920] ./zig-cache/o/F6E4YJLCwGgr0e72_U8NRW-v320p6TKiGBLNKFajH8JlnEOq7xa_ZZvQhFtoC0mn/cimport.zig:19400:5: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
pub extern fn nk_begin(ctx: [*c]struct_nk_context, title: [*c]const u8, bounds: struct_nk_rect, flags: nk_flags) c_int;
^
./zig-cache/o/F6E4YJLCwGgr0e72_U8NRW-v320p6TKiGBLNKFajH8JlnEOq7xa_ZZvQhFtoC0mn/cimport.zig:19400:5: note: pointers, integers, floats, bools, and enums work on all targets
pub extern fn nk_begin(ctx: [*c]struct_nk_context, title: [*c]const u8, bounds: struct_nk_rect, flags: nk_flags) c_int;
^
focus...The following command exited with error code 1:
/home/jamie/zig-linux-x86_64-0.5.0+732c0cb58/zig build-exe /home/jamie/focus/memory/src/main.zig --library c --library GL --library GLU --library GL --library SDL2 --c-source -std=c99 -fno-sanitize=undefined /home/jamie/focus/memory/src/nk_main.c --cache-dir /home/jamie/focus/memory/zig-cache --name focus -I /nix/store/70ls7xnvbhwzl0w2ks9h860ipjkifjra-mesa-19.3.3-dev/include -I /nix/store/i8wrbvvya4s86jwi1w5jwzzp9rrlzadr-libglvnd-1.2.0-dev/include -I /nix/store/70ls7xnvbhwzl0w2ks9h860ipjkifjra-mesa-19.3.3-dev/include -I /nix/store/i8wrbvvya4s86jwi1w5jwzzp9rrlzadr-libglvnd-1.2.0-dev/include -I /nix/store/d8n81xp7v423d1sc8ch28k54rqfnn4wq-glu-9.0.1-dev/include -I /nix/store/gw3mxrhynd9lyr3qcvghg4sqxq9lrjcy-SDL2-2.0.10-dev/include/SDL2 -I /home/jamie/focus/memory/include -L /nix/store/nqv1gpi9q8gqxkgy1kr6gwqly77v4vnr-libglvnd-1.2.0/lib -L /nix/store/nqv1gpi9q8gqxkgy1kr6gwqly77v4vnr-libglvnd-1.2.0/lib -L /nix/store/1c4f4gjzxpmqfmaxwzyq4hxgi8pxy2qc-glu-9.0.1/lib -L /nix/store/2jjwgcqpacdla7iwhwd4l4zmjw655ljw-SDL2-2.0.10/lib -D _REENTRANT --cache on
Build failed. The following command failed:
/home/jamie/focus/memory/zig-cache/o/Zr_C4R3GWir39zYwLrc_1cF1pueVmKYZRPELZhdNl2-asepcvvWs-CYZate2cW3u/build /home/jamie/zig-linux-x86_64-0.5.0+732c0cb58/zig /home/jamie/focus/memory /home/jamie/focus/memory/zig-cache run
I suppose the problem is:
struct nk_rect {float x,y,w,h;};
For now I can maybe just add a dummy field to the struct to make it bigger.
Also calling nk_rgb
(which returns nk_color
) does compile but produces a different result on each call. If I change the definition to struct nk_color {nk_byte r,g,b,a; nk_byte dummy[16];};
then I get the expected result.
Lmk if you need more details to repro, I can try to isolate it.
Hello, I stumbled upon this when needing to call variadic C functions. I worked around this by defining a simple C wrapper in a header that accepts the parameters I need but is not variadic, and use this wrapper instead of the variadic function.
Hey there, just as tglanz I'm trying to work with raylib and zig. Indeed I've released some manually tweaked bindings for it (shameless plug) and I'm trying to hack my way around this. Now, I was wondering what the difference between x86_64: struct & union parameters <= 16 bytes which break structs into parameters
and x86_64: struct & union parameters <= 16 bytes which are all floats
is. The first one is pretty clear, but I couldn't find any information on the second one.
I'm seeing this with Dear ImGui as well on macOS:
pub extern fn igButton(label: [*c]const u8, size: ImVec2) bool;
Trying to use libcurl, abstracting the C-ness away, but can't do it because C functions can't take the Zig strings.
fn make_request(url: []const u8) void {
var curl = c.curl_easy_init();
if(curl != null) {
_ = c.curl_easy_setopt(curl, .CURLOPT_URL, url); // <- problem here
var res = c.curl_easy_perform(curl);
c.curl_easy_cleanup(curl);
}
}
@matthewp This isn't an abi compatibility problem, it comes from curl_easy_setopt
accepting varargs. Though we should probably validate that varargs parameters on ABI boundaries are ABI-compatible types.
You can use sentinel-terminated pointers or slices to solve your problem.
For a slice, url: [:0]const u8
and curl_easy_setopt(curl, .CURLOPT_URL, url.ptr)
For a pointer, url: [*:0]const u8
and curl_easy_setopt(curl, .CURLOPT_URL, url)
Discussion on the LLVM mailing list about this: http://lists.llvm.org/pipermail/llvm-dev/2020-June/142055.html
Hi, I'm trying to add support for powerpc64-linux target.
After adding the bits and os files, building zig errors with this message:
[ 98%] Built target zig0
make[2]: Entering directory '/home/koakuma/zig/src/zig/out'
make[2]: Leaving directory '/home/koakuma/zig/src/zig/out'
make[2]: Entering directory '/home/koakuma/zig/src/zig/out'
TODO implement C ABI for this architecture. See https://github.com/ziglang/zig/issues/1481
Aborted
make[2]: *** [CMakeFiles/zig_build_libstage2.dir/build.make:57: CMakeFiles/zig_build_libstage2] Error 134
make[2]: Leaving directory '/home/koakuma/zig/src/zig/out'
make[1]: *** [CMakeFiles/Makefile2:119: CMakeFiles/zig_build_libstage2.dir/all] Error 2
make[1]: Leaving directory '/home/koakuma/zig/src/zig/out'
make: *** [Makefile:130: all] Error 2
@koachan You have to read the code of the file with that error. PowerPC is easier than the other targets, but you still can't support "homogenous aggregates"/"non-homogenous aggreegates" easily, and look at the llvm-dev list above.
For those who find this issue from the compile error, leave a comment detailing your specific needs
I've come here for al_put_pixel(int, int, ALLEGRO_COLOR)
where ALLEGRO_COLOR
https://github.com/liballeg/allegro5/blob/d7757184d335d400460808eff8e0d19c9f557673/include/allegro5/color.h#L15-L18
is an example of 'x86_64: struct & union parameters <= 16 bytes which are all floats' I suppose.
Thanks!
I'm running into this on macos.
Zig cimport:
pub extern fn c2CircletoCircle(A: c2Circle, B: c2Circle) c_int;
pub extern fn c2CircletoAABB(A: c2Circle, B: c2AABB) c_int;
pub extern fn c2CircletoCapsule(A: c2Circle, B: c2Capsule) c_int;
...
pub const struct_c2v = extern struct {
x: f32,
y: f32,
};
pub const c2v = struct_c2v;
pub const struct_c2Circle = extern struct {
p: c2v,
r: f32,
};
pub const c2Circle = struct_c2Circle;
pub const struct_c2AABB = extern struct {
min: c2v,
max: c2v,
};
pub const c2AABB = struct_c2AABB;
pub const struct_c2Capsule = extern struct {
a: c2v,
b: c2v,
r: f32,
};
pub const c2Capsule = struct_c2Capsule;
C:
CUTE_C2_API int c2CircletoCircle(c2Circle A, c2Circle B);
CUTE_C2_API int c2CircletoAABB(c2Circle A, c2AABB B);
CUTE_C2_API int c2CircletoCapsule(c2Circle A, c2Capsule B);
typedef struct c2v
{
float x;
float y;
} c2v;
typedef struct c2Circle
{
c2v p;
float r;
} c2Circle;
typedef struct c2AABB
{
c2v min;
c2v max;
} c2AABB;
typedef struct c2Capsule
{
c2v a;
c2v b;
float r;
} c2Capsule;
I am calling a function with the following signature:
pub export var RedisModule_Call: ?fn (?*RedisModuleCtx, [*c]const u8, [*c]const u8, ...) callconv(.C) ?*RedisModuleCallReply = undefined;
Like this:
const replyRemove = RedisModule_Call.?(ctx, "LREM", "sls", activeKey, -1, jobId);
zig complains with the following error:
/src/qdone.zig:94:79: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
const replyRemove = RedisModule_Call.?(ctx, "LREM", "sls", activeKey, -1, jobId);
^
./src/qdone.zig:94:79: note: pointers, integers, floats, bools, and enums work on all targets
const replyRemove = RedisModule_Call.?(ctx, "LREM", "sls", activeKey, -1, jobId);
It is passing an integer which is supposed to be supported, what gives?
@manast from looking at other reports in this thread it seems there may be a problem with variadic functions. The comment from @doppioandante (here) may be useful?
Working on translating some basic hello-world type serial code to zig.
Trying to open a serial port and set F_SETFL:
const clibs = @cImport({
@cInclude("stdio.h");
@cInclude("string.h");
@cInclude("fcntl.h");
@cInclude("errno.h");
@cInclude("termios.h");
@cInclude("unistd.h");
});
const std = @import("std");
pub fn main() void {
var serial_port = clibs.open("/dev/ttyUSB3", clibs.O_RDWR| clibs.O_NOCTTY | clibs.O_NDELAY);
if (-1 == clibs.fcntl(serial_port, clibs.F_SETFL, clibs.FNDELAY)) {
@panic("Problem with FNDELAY setting");
}
var tty : clibs.termios = undefined;
if(clibs.tcgetattr(serial_port, &tty) != 0) {
@panic("Problem with tcgetattr");
}
}
Results in compile error:
./d.zig:14:58: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
if (-1 == clibs.fcntl(serial_port, clibs.F_SETFL, clibs.FNDELAY)) {
^
./d.zig:14:58: note: pointers, integers, floats, bools, and enums work on all targets
if (-1 == clibs.fcntl(serial_port, clibs.F_SETFL, clibs.FNDELAY)) {
On x86_64 musl libc/alpine linux, 0.7.0+98d5bfbd4
.
I ran into this while playing with zig bindings for The Machinery.
We pass lots of small structs that are all floats by value, such as tm_vec3_t
, tm_rect_t
, etc -- both as parameters and return values. This blocked me from using Zig with The Machinery.
@niklas-ourmachinery it's a bit of a PITA, but you can hook zig up to The Machinery by adding wrapper C methods that take in a pointer to the tm_*_t
types and then just call through to the real methods. I didn't make a full binding but was able to get things working back in beta 1.
@prime31 It's a bit more involved in this case, because I'm actually implementing a callback function. But yes, I could probably do something similar, create a C forwarding function that acts as the callback for the C code and in turn calls the zig function. I might try it just for proof of concept... but it becomes a bit tedious to do for all the API code.
Got it working for the callback too, code here for reference:
@niklas-ourmachinery nice! By the way, The Machinery is really coming along nicely. I'm loving watching the progress.
I'm a bit confused. I can pass <= 16 byte structs to C functions, the compiler doesn't error and it actually works. The exact example is over at #9. Even for OP one of the draw calls work, so the DrawTextureRec
isn't the problem of his issue. The function has this beautiful signature extern fn DrawTextureRec(texture: Texture2D, sourceRec: Rectangle, position: Vector2, tint: Color) void;
. Texture2D
has 20 bytes assuming that c_uint
and c_int
are both 4 bytes, so no problem here. Rectangle
, Vector2
and Color
are all pretty surely <= 16 bytes so the compiler should complain when calling functions using them, but it doesn't. Is there any undocumented progress on this issue?
it seems strange to me, but probably I'm running into this problem while trying to use auto-generated functions from raymath.h
:
const ray = @cImport({
@cInclude("raylib.h");
@cInclude("raymath.h");
});
// copied from output of cimport.zig
fn Vector2Length(arg_v: ray.Vector2) callconv(.C) f32 {
var v = arg_v;
var result: f32 = ray.sqrtf((v.x * v.x) + (v.y * v.y));
return result;
}
pub fn main() void {
const point = ray.Vector2{
.x = 2.0,
.y = 2.0,
};
const length = Vector2Length(point);
}
build command: zig build-exe --verbose-cimport src/problem.zig -lc -lraylib -target x86_64-native-gnu
compiler output:
info(compilation): C import source: src/zig-cache/o/f8fe7bce06f4fc88770211d7fb0198d1/cimport.h
info(compilation): C import .d file: src/zig-cache/o/f8fe7bce06f4fc88770211d7fb0198d1/cimport.h.d
info(compilation): C import output: src/zig-cache/o/c20efa29fcf81f9a052c221f07dffd2a/cimport.zig
./src/problem.zig:6:18: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
fn Vector2Length(arg_v: ray.Vector2) callconv(.C) f32 {
^
./src/problem.zig:6:18: note: pointers, integers, floats, bools, and enums work on all targets
fn Vector2Length(arg_v: ray.Vector2) callconv(.C) f32 {
os: Debian 5.9.15-1 (2020-12-17) x86_64 GNU/Linux
Just FYI, I ran into this today when working with the generated win32 Zig bindings (https://github.com/marlersoft/zigwin32).
The function CorePrinterDriverInstalled
(see https://docs.microsoft.com/en-us/windows/win32/printdocs/coreprinterdriverinstalled) takes a 16-byte GUID
as a parameter which is what is causing the issue. I believe this would fall under the unfinished checkbox "x86_64: struct & union return values <= 16 bytes".
Ran into this again today with the generated win32 bindings. I'm calling a function from the d2d1 library that returns extern struct { width: f32, height: f32 }
(see https://docs.microsoft.com/en-us/windows/win32/api/d2d1/nf-d2d1-id2d1rendertarget-getsize).
On i386-windows
the fields in the return value are always NaN
, on x86_64-windows
one value works and the other is always 0. It can also cause a segfault afterwards depending on what I do.
One thing to note, in this case I didn't get a compile-error like in other cases. Things just got messed up at runtime.
Running into this now working with Raylib. It appears only occasionally during runtime, where for example GetMousePosition()
which returns a struct by value with two floats. The x value is correct by the y value is always exactly equal to the x value. Seems to happen with other functions that return Vector2's as well.
On macOS Big Sur.
Edit: Appending .ptr
to s_3
and s_4
got the behavior I wanted.
Tested on zig-linux-x86_64-0.8.0-dev.1557+3bf72f2b3
:
const c = @cImport({
@cInclude("stdio.h");
});
pub fn main() void {
// These work
const s_0 = "Hello World!";
_ = c.printf("0: %s\n", s_0);
const s_1: *const [12:0]u8 = "Hello World!";
_ = c.printf("1: %s\n", s_1);
const s_2: [*:0]const u8 = "Hello World!";
_ = c.printf("2: %s\n", s_2);
// These don't
const s_3: [:0]const u8 = "Hello World!";
//_ = c.printf("3: %s\n", s_3);
const s_4: []const u8 = "Hello World!";
//_ = c.printf("4: %s\n", s_4);
}
Building with zig build-exe src/main.zig -lc
returns:
./src/main.zig:18:29: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
_ = c.printf("3: %s\n", s_3);
^
./src/main.zig:18:29: note: pointers, integers, floats, bools, and enums work on all targets
_ = c.printf("3: %s\n", s_3);
^
Sorry if this has already been addressed before.
I presume #1481 (comment) is relevant?
s_3
and s_4
are slices which are not C ABI compatible types and are not supposed to work, it's just the error message that is not correct.
For those who find this issue from the compile error, leave a comment detailing your specific needs and I'll see if I can code those up for you to unblock you, so you don't have to wait for this issue to be 100% solved.
I'm personally using Raylibs raymath.h. Many of those return Vector3's that are 3 f32's. It's not a massive inconvenience since it takes a couple of minutes to :s/
my way into porting it to Zig, which is better anyway, but yeah :) I'd rather be lazy!
Regarding the issues with variadic / varargs functions - it's a pretty straightforward problem and there's an easy way around it. Here's a simple example with some explanations (tested on Compiler Explorer with Zig 0.8.0):
// Some vararg function from C
extern fn foo(...) c_int;
pub fn main() void
{
// If the type of the int is specified, everything works just fine,
// because the compiler knows exactly what to do
const testInt32: i32 = 5;
_ = foo(testInt32); // compiles, calls foo(i32)
// If the type of the int is unspecified or you're passing an integer literal (aka comptime_int),
// you're leaving it up to the compiler to decide what C type to pass into foo.
// Seems like, instead of making an arbitrary decision for you, the compiler just errors out.
const testComptimeInt = 5;
_ = foo(testComptimeInt); // compile error
_ = foo(5); // compile error
}
It seems weird/misleading for this case to be showing this error, though... I feel the compiler should be able to detect this more specifically. In the long term, either comptime_int
s should have a default C type when passed into a vararg function, or the compiler should throw a more specific compile error.
I'm working with raylib, and I hit the issue very consistently with DrawMesh if I compile the C sources with zig.
However, if I compile raylib using make
and gcc
, then link my zig exe to libraylib.a
, I don't notice any issues. Is that expected, or am I just getting lucky?
Edit: this was unrelated to the ABI. Zig's debug settings were enabling sanitizers and catching undefined behavior in the C library.
Vulkan's debug utilities use a callback of the type fn (VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, *const VkDebugUtilsMessengerCallbackDataEXT, ?*c_void) callconv(.C) u32
which doesn't compile
So, I found this project for for generating ABI-compliant LLVM IR
https://github.com/scrossuk/llvm-abi
LLVMValueRef has no "struct" type, I don't think it can be upstream in LLVM.
Anyways, the Zig stage 1 compiler needs a refactor.
For those who find this issue from the compile error, leave a comment detailing your specific needs and I'll see if I can code those up for you to unblock you, so you don't have to wait for this issue to be 100% solved.
I'm personally using Raylibs raymath.h. Many of those return Vector3's that are 3 f32's. It's not a massive inconvenience since it takes a couple of minutes to
:s/
my way into porting it to Zig, which is better anyway, but yeah :) I'd rather be lazy!
I am also hitting this, is there something that a person new to Zig could do to fix this or is it too difficult to do? Who should I ask if I wanted to try?
(I am having the issue with everything from raymath.h
, starting with Vector3...
functions, but now also with the various Matrix...
functions, which I'd prefer not to copy.)
I'm not sure if this matches the known issues around raymath.h
, but I ran into issues with DrawCircleV
in rshapes.c
of raylib, which doesn't error, but also doesn't draw a circle when being supplied a Vector2
:
https://github.com/LostKobrakai/raylib-4-zig/blob/main/src/main.zig. This is running 0.9.0-dev.1622+71388b980
on M1 mac.
@LostKobrakai I see two blue circles when running that example on Linux with raylib 4.0.0-34-g864e3ee9
. (I don't know my exact verion of zig
, I installed it from the AUR a while back and zig version
just says 0.9.0
).
Yeah, it's probably caused by being on arm given this is unchecked above:
ARM: struct & union parameters
Ran into the issue when integrating nanovg
(api is translated from header with zig translate-c
), function nvgFillColor
reports:
./src/nanovg/api.zig:133:5: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
pub extern fn nvgFillColor(ctx: ?*NVGcontext, color: NVGcolor) void;
^
./src/nanovg/api.zig:133:5: note: pointers, integers, floats, bools, and enums work on all targets
pub extern fn nvgFillColor(ctx: ?*NVGcontext, color: NVGcolor) void;
^
BTW, I'm using 0.9.0-dev.1700+b644d4936 on Linux x64 machine.
hit it in Lua:
pub extern fn lua_gc(L: ?*lua_State, what: c_int, ...) c_int;
C:\Projects\meshula\src\LabCart\LabCartLua.zig:41:44: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
_ = lua.lua_gc(s.state, lua.LUA_GCGEN, 0, 0); // gc into generational mode
^
C:\Projects\meshula\src\LabCart\LabCartLua.zig:41:44: note: pointers, integers, floats, bools, and enums work on all targets
_ = lua.lua_gc(s.state, lua.LUA_GCGEN, 0, 0); // gc into generational mode
@meshula That is not the correct function signature of that function, and the Lua API does not use variadic functions (because arguments are passed on the Lua stack, which is manually managed from C, and the Lua VM does not use the C stack at all).
That is not the correct function signature of that function,
It is in 5.4. https://www.lua.org/manual/5.4/manual.html#lua_gc
For context, yes, I'm using latest Lua, and the function signature is copied from the cimport.zig
file that was generated by @cImport({@cInclude("lua.h");});
.
hit it in Lua:
pub extern fn lua_gc(L: ?*lua_State, what: c_int, ...) c_int;C:\Projects\meshula\src\LabCart\LabCartLua.zig:41:44: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481 _ = lua.lua_gc(s.state, lua.LUA_GCGEN, 0, 0); // gc into generational mode ^ C:\Projects\meshula\src\LabCart\LabCartLua.zig:41:44: note: pointers, integers, floats, bools, and enums work on all targets _ = lua.lua_gc(s.state, lua.LUA_GCGEN, 0, 0); // gc into generational mode
I am not sure, maybe type casting can solve this error:
_ = lua.lua_gc(s.state, lua.LUA_GCGEN, @as(c_int, 0), @as(c_int, 0));
Hit in wasm freestanding (for wasm4). lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
:
wasm4.h:
void tracef (const char* fmt, ...);
My code:
const c = @cImport({
@cInclude("/path/to/wasm4.h");
});
export fn start() void {
c.tracef("tracef d:%d", 42);
}
$ zig build
./src/main.zig:31:29: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
c.tracef("tracef d:%d", 42);
^
./src/main.zig:31:29: note: pointers, integers, floats, bools, and enums work on all targets
c.tracef("tracef d:%d", 42);
EDIT: replacing the 42
with @as(i32, 42)
as @Vexu suggested fixes it. A slightly more precise error message might help here. (Thanks @Vexu !)
You need to cast 42
into a runtime integer type e.g. @as(i32, 42)
.
I think I bumped into similar issue when passing small structs as value and compiling to WASM32 arch. (Not sure, didn't get the nice TODO:
message π€). Got:
zig build -Dtarget=wasm32-freestanding
warning(link): unexpected LLD stderr:
wasm-ld: warning: function signature mismatch: foo
>>> defined as (f64, f64) -> i32 in W:\dev\zig\zig_wasm_bug\zig-cache\o\5ba67070f7283479e2e114419c28bd30\test.o
>>> defined as (i32) -> i32 in W:\dev\zig\zig_wasm_bug\zig-cache\o\d03f473609874e0bcb4300e9dd7a0ad9\test.o
And produced output was crashing/broken as the generated function was:
(func $signature_mismatch:foo (type $t1) (param $p0 f64) (param $p1 f64) (result i32)
unreachable)
When doing libexe.addCSourceFile("test.c")
:
#include "test.h"
extern int foo(struct rect r) {
return r.x + r.y;
};
And @cImport({@cInclude("test.h");})
:
struct rect {
float x, y, w, h;
};
extern int foo(struct rect r);
Ran into the issue when integrating
nanovg
(api is translated from header withzig translate-c
), functionnvgFillColor
reports:./src/nanovg/api.zig:133:5: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481 pub extern fn nvgFillColor(ctx: ?*NVGcontext, color: NVGcolor) void; ^ ./src/nanovg/api.zig:133:5: note: pointers, integers, floats, bools, and enums work on all targets pub extern fn nvgFillColor(ctx: ?*NVGcontext, color: NVGcolor) void; ^
BTW, I'm using 0.9.0-dev.1700+b644d4936 on Linux x64 machine.
I ran into the same issue. This seems to be the result of NVGcolor
having an array in the struct. Calling an extern function with as argument a struct or union with an array in it seems to not be implemented yet.
This snippet generates the same issue:
// test.zig
const Color = extern struct {
rgba: [4]f32,
};
extern fn printColor(c: Color) void;
pub fn main() void {
const c: Color = undefined;
printColor(c);
}
Compiled with zig build-exe test.zig
./test.zig:4:1: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
extern fn printColor(c: Color) void;
I'm getting this error with my minifb
wrapper on Linux on x86_64:
./src/main.zig:192:1: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
fn handleMouseScroll(win: mfb.Window(State), key_mod: mfb.KeyMod, delta_x: f32, delta_y: f32) callconv(.C) void {
^
It compiles and runs on Windows.
Window
is working fine in my other callbacks, so the problem is with KeyMod
:
pub const KeyMod = packed struct {
shift: bool = false,
control: bool = false,
alt: bool = false,
super: bool = false,
caps_lock: bool = false,
num_lock: bool = false,
_reserved: u26 = 0,
};
when will these goals be achieved?
when stage2/0.10.0 is released
Getting this using zig-imgui (project code here):
./src/positions.zig:89:39: error: TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481
_ = ig.Text("%s", position.ticker);
^
Where:
pub const Holding = struct {
name: []const u8,
ticker: []const u8,
[...]
Builds on Windows but not on Linux, both running Zig 0.10.0-dev.3559+d2342370f.
Edit Working around this circumstance with position.ticker.ptr
:)
No longer relevant, test coverage in zig build test-c-abi
.
No longer relevant, test coverage in zig build test-c-abi.
Hey @Vexu , I didn't get why you've closed this issue, is the stage1 fully compatible now? I'm especially interested in the ARM: struct & union parameters
issue.
Stage1 no longer exists.
π³
@andrewrk ARM: struct & union parameters
fixed now? In stage2 compiller?
All but complex number tests are passing for arm, if you find some case that doesn't work report it as a new bug.
Ok
All but complex number tests are passing for arm, if you find some case that doesn't work report it as a new bug.
You are talking about the master
version, right? Thanks
Most of the ABI improvements should have already landed in 0.10.0 (for self-hosted).