Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Are variadic functions supported? #116

Open
craig65535 opened this issue Mar 24, 2023 · 11 comments
Open

Are variadic functions supported? #116

craig65535 opened this issue Mar 24, 2023 · 11 comments
Labels
enhancement New feature or request

Comments

@craig65535
Copy link

The source has a comment about a special case for variadic functions -

// There is a special case when the last argument of fptr is a variadic interface (or []interface}
// it will be expanded into a call to the C function as if it had the arguments in that slice.
// This means that using arg ...interface{} is like a cast to the function with the arguments inside arg.
// This is not the same as C variadic.

Does this mean they are not supported? I made my own library in C and am unable to find a way to get my function to see any of the variadic parameters.

void printSomething(int a, const char *fmt, ...)
{
    va_list ap;
    printf("start %d\n", a);
    printf("fmt %s\n", fmt);
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
    printf("\n");
    printf("end %d\n", a);
}

Calling code:

	var printSomething func(int, string, []interface{})
	purego.RegisterLibFunc(&printSomething, libcraig, `printSomething`)
	printSomething(5, `%s`, []interface{}{`foo`})

This prints:

start 5
fmt %s
(null)
end 5
@craig65535
Copy link
Author

I should mention I'm using macOS (darwin/arm64).

@TotallyGamerJet
Copy link
Collaborator

That is correct. Variadic functions are not supported and there are currently no plans to add them.

@craig65535
Copy link
Author

Thanks for the response.

I think the documentation for RegisterFunc/RegisterLibFunc could be improved because that wasn't clear to me. But I'm not sure what to change it to, as there is probably some use for the current arrangement with []interface{} that I'm not aware of.

@TotallyGamerJet
Copy link
Collaborator

TotallyGamerJet commented Mar 25, 2023

The current implementation is used to implement the Send method in the objc package. This way the user of the method can call any objc method without having to create a func variable, link it to the C function and then call it.

@hajimehoshi hajimehoshi added the enhancement New feature or request label Jul 5, 2023
@lsy88
Copy link

lsy88 commented Nov 30, 2023

How do I convert Go []string to C char **

@TotallyGamerJet
Copy link
Collaborator

Create a slice of *byte. Convert each string to null terminated *byte. Then pass the address of the slice to the function. So the signature would be &slice[0] and the type **byte

@lsy88
Copy link

lsy88 commented Dec 1, 2023

Please understand that I may be a little unclear in the description, for the case of a C function parameter char **, what type should be used in Go?

@TotallyGamerJet
Copy link
Collaborator

**byte like I said

@lsy88
Copy link

lsy88 commented Dec 1, 2023

I'm sorry that I can't solve this matter according to your suggestion
C:

int test(char *path, char **result, int *len)

Go:

var test func(path string, result **byte, rlen *int) int32
...
purego.RegisterLibFunc(&test, lic, "test")
...
func Test(path string) {
  var lenRes int
  result := make([]*byte, 0)
  _ = test(path, &result[0], &lenRes)
}
...

I'm not sure if that's what you said, but I still haven't gotten the correct data return, The correct result data should be a string, but I only got one byte, what should I do to get the returned string

@TotallyGamerJet
Copy link
Collaborator

TotallyGamerJet commented Dec 1, 2023

You actually got all the code right so far. You just need to turn the *byte back into a string. There's no easy way to do this atm. There's discussion in #121 about making it more accessible. You can also just copy the code that's inside purego/internal/strings. Ofc you'll have to do that for each pointer in the slice

EDIT:
Oh it's a result no a parameter. So instead of using a slice just create a *byte and take the address of that.


I don't really want to busy up this issue more as your question doesn't relate to variadic functions. If you have more questions about this please ask on the discord.

@JupiterRider
Copy link
Contributor

@craig65535 @TotallyGamerJet
My libffi wrapper supports variadic functions now. See ffi.PrepCifVar.

Unfortunately ffi doesn't support MacOS yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants