M
Modular3mo ago
MM

Accessing C struct members from external_call

Does Mojo's Foreign Function Interface already support calling C functions that return C structs? If so, how to access the struct's members? Isaiah Norton's call_div example (https://github.com/ihnorton/mojo-ffi/blob/ffi-demo/mojo-call-c/call_div.mojo) seems to show it is possible, but I'm unable to get the value of the latter member in Mojo 24.2.1 although running the same code. The value of the first member seems to return correctly.
GitHub
mojo-ffi/mojo-call-c/call_div.mojo at ffi-demo · ihnorton/mojo-ffi
Contribute to ihnorton/mojo-ffi development by creating an account on GitHub.
5 Replies
Three chickens in the green bag
Greeeaaaat question! Unfortunately the docs don’t have nearly any info but I believe the repo may have something.
Three chickens in the green bag
GitHub
mojo/stdlib/src/sys/ffi.mojo at main · modularml/mojo
The Mojo Programming Language. Contribute to modularml/mojo development by creating an account on GitHub.
Three chickens in the green bag
You may want to try DLHandle instead
MM
MM3mo ago
Thanks a lot! I have tried both DLHandle and external_call, but cannot get either one work. A good idea to check the source code of the ffi now that the std library is OS. I tried to read it through, but my grasp of mlir and C and low-level stuff is non-existant, so I'm afraid I was not able to find the answer to the question yet. I'm sure it must be possible though – it's hard to believe that the CPython integration could work with limited interoperability. For the record, here's how I tested the localeconv function of the C standard library. I only manage to print the decimal_point member all the other members are blank.
from sys.ffi import external_call

alias c_char = UInt8
alias LC_MONETARY = 4
var locale = "it_IT".data()._as_scalar_pointer()

# Return type struct lconv

@register_passable("trivial")
struct lconv:
var decimal_point: Pointer[c_char]
var thousands_sep: Pointer[c_char]
var grouping: Pointer[c_char]
var int_curr_symbol: Pointer[c_char]
var currency_symbol: Pointer[c_char]
var mon_decimal_point: Pointer[c_char]
var mon_thousands_sep: Pointer[c_char]
var mon_grouping: Pointer[c_char]
var positive_sign: Pointer[c_char]
var negative_sign: Pointer[c_char]
var int_frac_digits: c_char
var frac_digits: c_char
var p_cs_precedes: c_char
var p_sep_by_space: c_char
var n_cs_precedes: c_char
var n_sep_by_space: c_char
var p_sign_posn: c_char
var n_sign_posn: c_char

var lc = external_call["localeconv", Pointer[lconv]]()
print(chr(lc[].decimal_point[0].to_int()))
from sys.ffi import external_call

alias c_char = UInt8
alias LC_MONETARY = 4
var locale = "it_IT".data()._as_scalar_pointer()

# Return type struct lconv

@register_passable("trivial")
struct lconv:
var decimal_point: Pointer[c_char]
var thousands_sep: Pointer[c_char]
var grouping: Pointer[c_char]
var int_curr_symbol: Pointer[c_char]
var currency_symbol: Pointer[c_char]
var mon_decimal_point: Pointer[c_char]
var mon_thousands_sep: Pointer[c_char]
var mon_grouping: Pointer[c_char]
var positive_sign: Pointer[c_char]
var negative_sign: Pointer[c_char]
var int_frac_digits: c_char
var frac_digits: c_char
var p_cs_precedes: c_char
var p_sep_by_space: c_char
var n_cs_precedes: c_char
var n_sep_by_space: c_char
var p_sign_posn: c_char
var n_sign_posn: c_char

var lc = external_call["localeconv", Pointer[lconv]]()
print(chr(lc[].decimal_point[0].to_int()))
Three chickens in the green bag
Sorry I couldn’t help 😅 @sora Any thoughts here?