How do you statically link stubs in a cma?

Hello everyone, I’m a little stuck with ocamlmklib… I’ve got a stub and a module and i want to produce a .cma like that of unix.cma etc… that means just the .cma loaded in a repl should be enough (without needing to load any shared objects), but doing that seems to just not work.

It doesn’t seem like unix loads any dlls, I made sure by removing ocaml/stublibs entirely and it still worked. I tried to follow both the makefile in otherlibs and this page in the manual and both still produced an executable that’s reliant on its respective shared object for loading stub functions. What am I doing wrong?

Steps:

  1. ocamlc -c test_stub.c
  2. ocamlc -c test.ml
  3. ocamlmklib -o test -custom test.cmo test_stub.o

I also tried with other variations like sprinkling -custom and -a and -ccopt -static everywhere and I still couldn’t produce a standalone .cma no matter what.

I also asked the community channel on IRC, no one seems to notice anything off.

Some stuff that may be asked:

  • I want ocamlc not ocamlopt, ocamlopt seems to cause no linking problems. But cmxas don’t work in the repl
  • I want to use the library both in repl and in the project for loading in other modules

It is not possible to produce a “standalone” .cma because .cma is just a collection of bytecode .cmo files. Rather, when producing an executable, you can make it standalone by using -custom. This will link the C stubs of your .cma archives statically into the executable (together with the runtime system). You can do the same with the toplevel itself (see ocamlmktop).

Cheers,
Nicolas

1 Like

So does that mean the unix stubs are simply linked to the bundled standard toplevel? allowing unix.cma to load without a dynlink process?

No. I suspect you did something wrong. It shouldn’t work. Did you actually try to invoke a function from Unix ?

The bytecode interpreter (which is used to execute the standard toplevel) loads the stubs at runtime using usual shared library machinery. The name of the stub is recorded in the unix.cma file (as you can see by using the ocamlobjinfo tool) and these stubs are looked for in the “standard library directory” which is hard-coded in the bytecode interpreter.

Cheers,
Nicolas

yeah, Unix.sleep, worked fine… IDK how if it’s loaded
The exact steps:

  • mv `ocamlc -where`/stublibs{,-}
  • ocaml
  • #load "unix.cma"
  • Unix.sleep 1

Now that I retried them, they don’t work haha weird… probably was doing this with another switch loaded or something idk

To complement @nojb’s answer, the actual lookup procedure is described here in the manual.

1 Like

the manual could probably use some cross-referencing between those

This is what I did, seems to work, thanks all

ocamlc -c test_stub.c test.ml
ocamlmktop -o test.top -custom test.cmo test_stub.o

and then load like this:

./test.top
#use "test.ml"

I tried to use ocamlmklib together with -custom but I’m not sure what cocktail of options makes ld happy because it keeps insisting it needs to link dlltest.so.

That instructs to automatically link in -custom mode when your library is linked into a bytecode excutable.

But of course if you are just loading a library in the toplevel you are not creating a new executable.

See the docs under option -a here in the manual.