Linking OCaml for Godot 4.2

Hi there – first time poster.

Short question: I’d like to link a .ml library program to a standalone C program into a shared library. (If it helps, I would happy to start with just gcc on linux). Is there documentation on how I might do this, or does anyone know?

Long question: I want to create a language interface for OCaml in the Godot game engine. To do this, you need to provide a function with the following signature:

GDExtensionBool
my_entry_function(
  GDInterfaceGetProcAddress p_get_proc_address /* pointer to function */,
  GDExtensionClassLibraryPtr p_lib /* ptr to Godot class library */,
  GDExtensionInitialization* r_initialization 
    /* ptr to a defined struct type that contains pointers to functions
       that do the actual initialization of your plugin at various
       "levels" of bringing up the Godot engine. */
  );

Which then I can tell Godot to load via a text file on startup.

Failure so Far

I am able to link an executable, but not a shared library with dune or manually. I feel like I’m close, however; Godot can find the startup function and dynamically links to the OCaml runtime (I can tell because it used to not!). However, it says it’s not a shared library (which I agree with) and so can’t load it. Alternatively, I can build it as an object file (seen below), and it claims it’s not dynamic (which I also agree with). Here is the actual error message in the second case [from Godot]:

ERROR: Can't open dynamic library: /home/fizzixnerd/src/toycaml/libhello-gdextension.so. Error: /home/fizzixnerd/src/toycaml/libhello-gdextension.so: only ET_DYN and ET_EXEC can be loaded.
   at: open_dynamic_library (drivers/unix/os_unix.cpp:660)
ERROR: GDExtension dynamic library not found: /home/fizzixnerd/src/toycaml/libhello-gdextension.so
   at: open_library (core/extension/gdextension.cpp:719)
ERROR: Failed loading resource: res://hello.gdextension. Make sure resources have been imported by opening the project in the editor at least once.
   at: _load (core/io/resource_loader.cpp:274)
ERROR: Error loading extension: res://hello.gdextension
   at: load_extensions (core/extension/gdextension_manager.cpp:234)
ERROR: Can't open dynamic library: /home/fizzixnerd/src/toycaml/ocaml/godotcaml/c/libhello-gdextension.so. Error: libcamlrun_shared.so: cannot open shared object file: No such file or directory.
   at: open_dynamic_library (drivers/unix/os_unix.cpp:660)
ERROR: GDExtension dynamic library not found: /home/fizzixnerd/src/toycaml/ocaml/godotcaml/c/libhello-gdextension.so
   at: open_library (core/extension/gdextension.cpp:719)
ERROR: Failed loading resource: res://ocaml/godotcaml/c/hello.gdextension. Make sure resources have been imported by opening the project in the editor at least once.
   at: _load (core/io/resource_loader.cpp:274)
ERROR: Error loading extension: res://ocaml/godotcaml/c/hello.gdextension
   at: load_extensions (core/extension/gdextension_manager.cpp:234)

Details of What I Have

I have something that looks like

  • godotcaml
    • dune-project
    • godotcaml.opam
    • bin
      • dune
      • gdextension_interface.h (* a C header I include in the C src below *)
      • hello-gdextension.c (* a C source file that contains the entry point the plugin expects; calls OCaml from here *)
      • main.ml (* Where I do all my real work in OCaml *)

My dune file looks like

(executable
 (name main)
 (modes (native object))
 (libraries godotcaml ctypes.foreign ctypes)
 (foreign_stubs (language c) (names hello-gdextension))
 (flags (:standard -g -cclib "-L/usr/lib/x86_64-linux-gnu/")))

the library godotcaml is the main library interface for OCaml for Godot I am writing; it shouldn’t really figure into this, I don’t think. It can be statically linked in.

dune build creates a file main.exe.o, and I copy that to where Godot can see it as libhello-gdextension.so. Yup.

So it’s not exactly surprising it doesn’t work, but I think I’m pretty close. Any help would be appreciated.

PS is there a matrix or IRC for ocaml I could join?

5 Likes

Do you have a demo?

I would start from this How to wrap C functions to OCaml and an official manual OCaml - Interfacing C with OCaml after that.

1 Like

I don’t have proper network connectivity to reply in full, but this is definitely doable. You should use (modes shared_object) in Dune to get it to produce a DLL from the OCaml code (and any included C stubs).

Cheers,
Nicolas

1 Like

This seems promising. Note the for future explorers, the actual stanza is (modes (native shared_object)), I believe, as the (modes shared_object) seems to complain (while the other does not). I will report back with experimentations. Thanks, Nicolas

That did the trick! Here is the output:

Initializing extension from OCaml!
ERROR: Can't open dynamic library: /home/fizzixnerd/src/toycaml/ocaml/godotcaml/c/libhello-gdextension.so. Error: libcamlrun_shared.so: cannot open shared object file: No such file or directory.
   at: open_dynamic_library (drivers/unix/os_unix.cpp:660)
ERROR: GDExtension dynamic library not found: /home/fizzixnerd/src/toycaml/ocaml/godotcaml/c/libhello-gdextension.so
   at: open_library (core/extension/gdextension.cpp:719)
ERROR: Failed loading resource: res://ocaml/godotcaml/c/hello.gdextension. Make sure resources have been imported by opening the project in the editor at least once.
   at: _load (core/io/resource_loader.cpp:274)
ERROR: Error loading extension: res://ocaml/godotcaml/c/hello.gdextension
   at: load_extensions (core/extension/gdextension_manager.cpp:234)
0
Done initializing from OCaml! Returning 1...Error: Can't run project: no main scene defined in the project.
0

I should be able to figure out the rest from here. Cheers again, Nicolas.

This thread got its answer already, but if anyone ends up here and doesn’t want to do the whole thing by hand, they could have a look at ctypes reverse bindings which I believe enable such use case.

1 Like

Has links to a Matrix Space & IRC. No XMPP MUC tho.