#Invoke C function from Zig

1 messages · Page 1 of 1 (latest)

fresh pecan
#

I'm trying to invoke a C function that takes a pointer to a C string:

void glShaderSource(     GLuint shader,
      GLsizei count,
      const GLchar **string,
      const GLint *length);

I'm having trouble to cast a []const u8 to the string pointer. Some time ago I asked a similar question here, about how to pass a string literal, and the trick was to cast it like this:

&[_][*c]const u8{string_literal}

But if I try the same thing I get this error:

error: expected type '[*c]const u8', found '[]u8'

I tried the obvious thing (to me), which was a pointer to the contents of the slice:

&slice.ptr

That made the compiler happy, but passed garbage to the function, so I must be misunderstanding something...

What's the right way to do this?

lime marten
#

slice.ptr, &slice.ptr = *[*]T

#

[]const u8 to [*c]const u8 = removing the length from the slice, so slice.ptr is all you need

fresh pecan
#

with slice.ptr I get this error:

error: expected type '[*c]const [*c]const u8', found '[*]u8'
#

since the function takes a pointer to a string, not the string directly

lime marten
#

a pointer to the string pointer would be &slice.ptr yes

#

what do you mean by "garbage"? maybe you're missing a NUL terminator

fresh pecan
#

the string contains the code that will be compiled into a vertex shader, when I do it like this the compilation fails with:

0(7) : error C0000: syntax error, unexpected $undefined at token "<undefi
ned>"

If seen that error before when I passed dangling pointers, but in this case I know the slice contains the code I read from the file.

Maybe the null terminator could do that, not sure how to add it to an already allocated slice

tidal depot
#

is const GLchar **string being translated by translate-c?

lime marten
#

How are you getting the source?

fresh pecan
#

This is what I used:

fn slurp(path: []const u8, allocator: mem.Allocator) ![]u8 {
        const dir = std.fs.cwd();
        const file = try dir.openFile(path, .{});
        defer file.close();
        const max_size = 1024 * 1024; // 1Mb
        return try file.readToEndAlloc(allocator, max_size);
    }
#

about translate-c, I'm not sure? I'm doing the call manually

tidal depot
#

well how is it being called from Zig

lime marten
#

lol slurp

tidal depot
#

who defined the signature

#

is it cImport / translate-c / whatever

fresh pecan
#

cImport

tidal depot
lime marten
#

they said pointer to string

tidal depot
#

const GLchar **string

#

pointers to strings :)

lime marten
#

but you don't know N at compile time

tidal depot
#

I have no idea why &slice.ptr is not doing it for you

#

that should be correct

lime marten
#

it is to the type system

#

which is why I'm asking how they're getting their data

#

@fresh pecan what if you do this:

glFunc(&[_][]const u8{@embedFile("shader_code.thing")});```
tidal depot
#

not only that, but semantically too, references to immediates do exist at least until the function returns

lime marten
#

if that works, then the problem lies with your file reading code

tidal depot
#

yeah

fresh pecan
#

let me try!

tidal depot
#

although I'm not sure what's wrong there either - that slurp looks good to me

lime marten
#

the slice wouldn't contain a null terminator

#

I assume the c code wants a c string that has one

tidal depot
#

oh, wait, yeah, lol, oops

#

yes, it does

#

I think there's a function for this

#

let me have a look

lime marten
#

it's usually the Z suffixed ones

tidal depot
#

people are stopping the Z suffix because it's dumb

#

sentinel / options now

lime marten
#

better

fresh pecan
#

I tried this:

c.glShaderSource(vertex_shader, 1, &[_][]const u8{@embedFile("./shader.vs")}, null);

But the compiler didn't like it:

error: expected type '[*c]const [*c]const u8', found '*const [1][]const u8'
tidal depot
#

yes, make it [*c]const u8{ instead

lime marten
#

noooo

#

you aren't supposed to use that c pointer everrr

tidal depot
#

it's cImport so that's the correct type

lime marten
#

I typo'd you just need [_][]const u8

#

because the array will coerce to the c pointer

tidal depot
#

no they need &[_][*c]const u8{ ... }

#

that will coerce

lime marten
#

no

tidal depot
#

an array of slices does not coerce to an array of pointers that's different data

pseudo lance
#

This is a rare case where you do need to do that

lime marten
#

how

pseudo lance
#

Because coercion doesn't account for pointer child type

tidal depot
#

it also can't by the way

fresh pecan
#

ah, this:

c.glShaderSource(vertex_shader, 1, &[_][*c]const u8{@embedFile("./shader.vs")}, null);

worked!

#

why? 😕

lime marten
#

you're missing the null terminator when reading from your file

tidal depot
#

yep, so, it's just because your file needs a null terminator, and your readToEndAlloc is not adding one

#

it probably does strlen() and goes off the goop

#

file.readToEndAllocOptions(allocator, max_size, null, 1, 0)

tidal depot
# lime marten bug in zig

no, that's just not how the data works, you can't magically turn an array of struct { [*], usize } into an array of [*]

pseudo lance
#

And that

lime marten
#

you and your words

#

design flaw there are you happy

pseudo lance
#

Slices do not get along with the C ABI

tidal depot
#

I think us arguing about semantics is not helping OP here

#

maybe that's just me

lime marten
#

their problem is solved

#

they will be ok

fresh pecan
#

yes, I'll figure it out, thanks a lot for your help!

lime marten
#

viri posted your fix above

pseudo lance
#

Ideally, you would be able to use &[_][*:0]const u8 {...}

pseudo lance
tidal depot
pseudo lance
#

But unfortunately, the type system won't let you coerce from *const [_][*:0]const u8 to [*c]const [*c]const u8

#

Yes, ik viri

lime marten
#

&[N][]T = a pointer to an array (a pointer with a length) of slices
why can't the array coerce to the c pointer?

polar agate
#

@fresh pecan For clarity: you needed a pointer, to the first item, of an array of pointers, where those pointers are cstrings. (i.e: Null-terminated pointer to byte.)

pseudo lance
lime marten
#

I'm not talking about the child type I'm talking about the top most type

tidal depot
#
zig: ptr|len|ptr|len|ptr|len|ptr|len|ptr|len
c:   ptr|ptr|ptr|ptr|ptr

these are not compatible data structures

lime marten
#

i get that

#

you do not have to repeat yourself

tidal depot
#

DRY violation

#

😔

pseudo lance
#

That's just not something zig really does at a fundamental level

lime marten
#

hello comptime my beloved

#

I digress

fresh pecan
lime marten
fresh pecan
#

ah, brilliant, I missed that, thanks!