I'm trying to build a shared object out of an OCaml library that I can run under Python using the cdll interface in ctypes.
Is there a way to direct something in the OCaml toolchain to produce a shared object with its dependencies linked in?
I'm starting to suspect that OCaml simply does not support what I'm trying to do. I want to call an OCaml function, but then have it produce some kind of result and return control back to where it was called from.
Here's my OCaml library
(* foo.ml *)
let add x y = x + y
And the command I used to compile it on OS X. (using .so instead of .dylib is slightly violating the naming conventions of the platform, but ocamlopt will only accept an extension of .o or .so.)
$ ocamlopt -output-obj -fPIC -o foo.so foo.ml
succeeds and produces foo.so.
Here's my first attempt to load the shared object into a python program (python 3.6).
# foo.py
import ctypes
lib = ctypes.cdll.LoadLibrary('./foo.so')
print("Loaded")
It produces the following error when run
excerpt:
self._handle = _dlopen(self._name, mode)
OSError: dlopen(./foo.so, 6): Symbol not found: _caml_code_area_end
Full error:
Traceback (most recent call last):
File "foo.py", line 3, in <module>
lib = ctypes.cdll.LoadLibrary('./foo.so')
File "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ctypes/__init__.py", line 426, in LoadLibrary
return self._dlltype(name)
File "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ctypes/__init__.py", line 348, in __init__
self._handle = _dlopen(self._name, mode)
OSError: dlopen(./foo.so, 6): Symbol not found: _caml_code_area_end
Referenced from: ./foo.so
Expected in: flat namespace
in ./foo.so
I looked around for the symbol in the compiler's directory ocamlopt -where.
$ find `ocamlopt -where` | xargs -I% bash -c 'nm % | sed -e "s|^|%:|"' | & grep _caml_code_area_end
/usr/local/lib/ocaml/libasmrun_pic.a: 0000000000000008 C _caml_code_area_end
/usr/local/lib/ocaml/libasmrun_pic.a: U _caml_code_area_end
/usr/local/lib/ocaml/libasmrunp.a: 0000000000000008 C _caml_code_area_end
/usr/local/lib/ocaml/libasmrunp.a: U _caml_code_area_end
/usr/local/lib/ocaml/libasmrun_shared.so: 000000000001ded0 S _caml_code_area_end
/usr/local/lib/ocaml/libasmrun.a: 0000000000000008 C _caml_code_area_end
/usr/local/lib/ocaml/libasmrun.a: U _caml_code_area_end
/usr/local/lib/ocaml/libasmrund.a: 0000000000000008 C _caml_code_area_end
/usr/local/lib/ocaml/libasmrund.a: U _caml_code_area_end
And tried loading /usr/local/lib/ocaml/libasmrun_shared.so first, giving
import ctypes
lib = ctypes.cdll.LoadLibrary('/usr/local/lib/ocaml/libasmrun_shared.so')
lib = ctypes.cdll.LoadLibrary('./foo.so')
print("Loaded")
which produced the error:
OSError: dlopen(/usr/local/lib/ocaml/libasmrun_shared.so, 6): Symbol not found: _caml_apply2
Referenced from: /usr/local/lib/ocaml/libasmrun_shared.so
Expected in: flat namespace
in /usr/local/lib/ocaml/libasmrun_shared.so
The _caml_apply2 symbol is deep in the runtime of OCaml, and I wasn't able to find a file for it with the .so extension ... and cdll doesn't seem to expose the ability to load .as.