OCaml使用链接的OCaml运行时生成共享对象

Gre*_*bet 1 python ocaml

我正在尝试从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 的能力.

Éti*_*lon 5

由于某种原因,-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.