Linkin a C library for C-Types bindings

Hello,

I’m trying to learn how to write bindings using C-Types. As a project I’m writing bindings for tree-sitter (I am aware of the existence of reason-tree-sitter, I’m just writing my own for fun).

However, I don’t really know how c linking work and I’ve tried several flags but I haven’t manage to link the tree-sitter c library.
I am using the esy-packaged tree-sitter. At compilation time, there are two environment variables already set up :

  • TREESITTER_INCLUDE_PATH
  • TREESITTER_LIB_PATH

I’ve been trying a lot of different things in the dune file, my last attempt is

(library
 (public_name tree_sitter)
 (name tree_sitter)
 (libraries ctypes.foreign)
 (flags :standard -cclib -ltree-sitter -cclib -I%{env:TREESITTER_INCLUDE_PATH=} -cclib -I%{env:TREESITTER_LIB_PATH=} -cclib -L%{env:TREESITTER_LIB_PATH=}))

But it is still not working.

When I try to load my library in utop, i get
Fatal error: exception Dl.DL_error("dlsym(RTLD_DEFAULT, ts_new_parser): symbol not found").

I’m kinda navigating blindly there. I’m following the beautiful real-world-ocaml example, but it’s linking a globally installed c library, and I’m trying to specify the lib and include paths myself.

I’m thankful for any help :smile:

You need to add the location to your C library dll to your LD_LIBRARY_PATH.

I think that I’m trying to link statically and not dynamically. I have a libtree-sitter.a in the TREESITTER_LIB_PATH, no dll.

You can’t link statically for the toplevel unless you make your own toplevel with ocamlmktop. See here and here.

Or maybe you can pass -l$(LIB) to ocamlmklib (note, not via -cclib), I think that this put C code in the stub library dll, see here. Mentioning the archive directly on the cli might also work.

Ok so first, I didn’t know that I couldn’t statically link for toplevel just like that, but it makes sense :sweat_smile:
I am no really trying to build for toplevel I was just trying to see if it works. I want to build statically for a binary now, but I still get this Fatal error: exception Dl.DL_error("dlsym(RTLD_DEFAULT, ts_new_parser): symbol not found").

If I pass -l$(LIB) to ocamlmklib (through c_library_flags, as follows), I still get the DL_error.

(library
 (public_name tree_sitter)
 (name tree_sitter)
 (libraries ctypes.foreign)
 (c_library_flags (-ltree-sitter) (-I%{env:TREESITTER_INCLUDE_PATH=}) (-I%{env:TREESITTER_LIB_PATH=}) (-L%{env:TREESITTER_LIB_PATH=})))

it seems to be understanding that I want to link dynamically, although, if the compilation goes through, I guess it does find the .a file ?

It’s difficult to investigate the problem without seing the actual invocations. But trying to make it first work on an executable (rather than in the toplevel) is a good idea.

Ok, so I simply added the -static flag, and ended up with the ld: library not found for -lcrt0.o.
Grom another answer of yours on this forum, I understand that I just can’t do that on MacOs.

Statically linking by passing with -static to gcc on macOS has been “forbidden” for quite some time.

May not be the best idea (if multiple libs do that for the same lib) but your problem should remain solvable by passing the archive directly on the cli to have them in the stub library that is used by ocamlrun.