modularml / mojo

The Mojo Programming Language
https://docs.modular.com/mojo/manual/
Other
23.21k stars 2.59k forks source link

[Feature Request]Enhanced external_call #3712

Open andr1972 opened 1 week ago

andr1972 commented 1 week ago

Review Mojo's priorities

What is your request?

I need method like ffi.external_call with parameter "handle" to enable calling methods from any C libraries, not only libc.

What is your motivation for this change?

I want write PostgreSQL library for Mojo - libpq.so wrapper.

Any other details?

Some example of using:

from sys import ffi

fn main():
    handle = ffi.DLHandle("libpq.so")
    conninfo = "dbname = moj_guest_test user = guest password = pass hostaddr = 127.0.0.1 port = 5432"
    ffi.external_call[handle, "PQconnectdb", Int, UnsafePointer[Int8]](conninfo)
martinvuyk commented 5 days ago

Hi, I'm not sure if external_call is only for statically linked libraries (can be the case, I just don't know). I see 2 little problems with your example:

Other than that, until we have a nice interface like what you're asking (which should be the goal), you can have a look at how things for Python interop are currently done. An example:

        self.lib = DLHandle(python_lib)
        self.total_ref_count = UnsafePointer[Int].alloc(1)
        self.dict_type = PyObjectPtr()
        self.logging_enabled = logging_enabled
        if not self.init_error:
            if not self.lib.check_symbol("Py_Initialize"):
                self.init_error = "compatible Python library not found"
            self.lib.get_function[fn () -> None]("Py_Initialize")()
            self.version = PythonVersion(_py_get_version(self.lib))

You can define some more complicated function signatures:

    fn PyDict_SetItem(
        inout self, dict_obj: PyObjectPtr, key: PyObjectPtr, value: PyObjectPtr
    ) -> c_int:
        """See https://docs.python.org/3/c-api/dict.html#c.PyDict_SetItem."""

        var r = self.lib.get_function[
            fn (PyObjectPtr, PyObjectPtr, PyObjectPtr) -> c_int
        ](StringRef("PyDict_SetItem"))(dict_obj, key, value)

But I definitely agree that this should be able to be handled by external_call and/or have nicer ergonomics