我正在尝试从OCaml库中构建一个共享对象,我可以Python使用该cdll接口在其中运行ctypes.
有没有办法在OCaml工具链中引导一些东西来生成一个链接在其中的依赖项的共享对象?
我开始怀疑OCaml根本不支持我正在尝试做的事情.我想调用一个OCaml函数,但是它会产生某种结果并将控制权返回到调用它的位置.
这是我的OCaml库
(* foo.ml *)
let add x y = x + y
Run Code Online (Sandbox Code Playgroud)
我用来在OS X上编译它的命令.(使用.so而不是.dylib略微违反平台的命名约定,但ocamlopt只接受.o或的扩展名.so.)
$ ocamlopt -output-obj -fPIC -o foo.so foo.ml
Run Code Online (Sandbox Code Playgroud)
成功并产生foo.so.
这是我第一次尝试将共享对象加载到python程序(python 3.6).
# foo.py
import ctypes
lib = ctypes.cdll.LoadLibrary('./foo.so')
print("Loaded")
Run Code Online (Sandbox Code Playgroud)
运行时会产生以下错误
摘抄:
self._handle = _dlopen(self._name, mode)
OSError: dlopen(./foo.so, 6): Symbol not found: _caml_code_area_end
Run Code Online (Sandbox Code Playgroud)
完整错误:
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
Run Code Online (Sandbox Code Playgroud)
我四处寻找编译器目录中的符号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
Run Code Online (Sandbox Code Playgroud)
并尝试/usr/local/lib/ocaml/libasmrun_shared.so先加载,给予
import ctypes
lib = ctypes.cdll.LoadLibrary('/usr/local/lib/ocaml/libasmrun_shared.so')
lib = ctypes.cdll.LoadLibrary('./foo.so')
print("Loaded")
Run Code Online (Sandbox Code Playgroud)
产生错误:
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
Run Code Online (Sandbox Code Playgroud)
该_caml_apply2符号在OCaml的运行时很深,我无法使用.so扩展名找到它的文件...并且cdll似乎没有公开加载.as 的能力.
由于某种原因,-fPIC标志是不够的,您还需要PIC运行时.以前,这需要一个特殊的开关(例如4.04.1+fPIC),但现在您可以选择要链接的运行时.
以下适用于我(Debian buster,opam 4.06.1 + rc2开关):
% ocamlopt -output-obj -runtime-variant _pic -o foo.so foo.ml
% python foo.py
Loaded
Run Code Online (Sandbox Code Playgroud)
我正在尝试从OCaml库中构建一个共享对象,我可以使用ctypes中的cdll接口在Python下运行.
请注意,您将无法从Python(或其他接口)调用OCaml符号,您需要编写一些C来设置运行时并管理OCaml对象.一种简单的方法是在这部分中使用Cstubs_inverted.