How to statically link archive files with dune?

How do I statically link some .a files with Dune? How do I write my OCaml bindings to them?

Background

I’m creating an OCaml libsql client. To interface with libsql, I’m taking the same approach as their Go client where the client statically links precompiled native client libs for libsql. Go has the ability to link archive files, and with cgo, automatically generate bindings to the c api. You can see how it’s done here in Go.

Attempt so far
I want to take the same approach with dune. I have copies of the precompiled libs. In my dune file, I’ve included the macos-specific lib via dune’s foreign_archives API. Because I haven’t learned how to conditionally build for different archs and systems, my dune file references just the macos lib for expediency.

I have some ctypes bindings to the libsql.h header file.

I also have a test to execute my bindings. On test run, I encounter an error where I’m unable to find the symbols. It looks like dune is still expecting the libsql bindings to be dynamically loaded. What am I missing?

$ dune runtest

File "test/dune", line 2, characters 7-18:
2 |  (name test_libsql)
           ^^^^^^^^^^^
Fatal error: exception Dl.DL_error("dlsym(RTLD_DEFAULT, libsql_enable_internal_tracing): symbol not found")

My dune file

(library
 (name libsql)
 (modes native)
 (public_name libsql)
 (modules libsql libsql_bindings)
 (libraries ctypes ctypes.foreign)
 (foreign_archives libsql_macosx_arm64))

I’m quite unfamiliar with dynamic/static linking in general.

Dune does not intervene in any way at runtime to load symbols, so this is not coming from Dune. It is probably coming from ctypes, which I believe has two modes of operation, one of which uses dynamic loading. I am not familiar with libsql, but perhaps it is not meant to by dynamically linked, so it may not export the needed symbols so that they can be found via dlsym. You could confirm this by playing around with nm -D or similar tools (slight adjustments may be needed on macOS).

In any case, you may have better luck if you switch to the “stubs” mode of operation of ctypes, which does not rely on dynamic loading.

Link does not seem accessible.

Cheers,
Nicolas

Dune does not intervene in any way at runtime to load symbols, so this is not coming from Dune.

Thank you @nojb. I did not know OCaml itself was doing this work, and that Dune merely passes along compiler args.

I finally read more into how OCaml compiles and links C code at OCaml - Interfacing C with OCaml. Really enlightening. I was able to demonstrate linking libsql statically and dynamically in a separate test repo.

Now I only need to translate the same work into Dune’s DSL.

1 Like

You may be interested in this blog post: Generating static and portable executables with OCaml | OCamlPro

2 Likes