【问题标题】:OCaml produce shared object with OCaml runtime linked inOCaml 生成与 OCaml 运行时链接的共享对象
【发布时间】:2018-02-15 06:45:50
【问题描述】:

我正在尝试从 OCaml 库中构建一个共享对象,我可以使用 ctypes 中的 cdll 接口在 Python 下运行该共享对象。

有没有办法让 OCaml 工具链中的某些东西生成一个共享对象,并链接其依赖项?

我开始怀疑 OCaml 根本不支持我正在尝试做的事情。我想调用一个 OCaml 函数,然后让它产生某种结果并将控制权返回到调用它的位置。

这是我的 OCaml 库

(* foo.ml *)
let add x y = x + y

而我用来在 OS X 上编译它的命令。(使用.so 而不是.dylib 稍微违反了平台的命名约定,但ocamlopt 将只接受.o 或@ 的扩展名987654329@.)

$ ocamlopt -output-obj -fPIC -o foo.so foo.ml

成功并产生foo.so

这是我第一次尝试将共享对象加载到 python 程序(python 3.6)中。

# foo.py
import ctypes

lib = ctypes.cdll.LoadLibrary('./foo.so')

print("Loaded")

运行时出现如下错误

摘录:

self._handle = _dlopen(self._name, mode)
OSError: dlopen(./foo.so, 6): Symbol not found: _caml_code_area_end

完全错误:

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

我在编译器目录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

并尝试先加载/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")

产生错误的原因:

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

_caml_apply2 符号在 OCaml 的运行时中很深,我无法为它找到带有 .so 扩展名的文件...而 cdll 似乎没有公开以下功能加载.as.

【问题讨论】:

    标签: python ocaml


    【解决方案1】:

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

    我正在尝试从 OCaml 库中构建一个共享对象,我可以使用 ctypes 中的 cdll 接口在 Python 下运行该库。

    请注意,您不能只从 Python(或其他接口)调用 OCaml 符号,您需要编写一些 C 来设置运行时并管理 OCaml 对象。一个简单的方法是在这部分使用Cstubs_inverted

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多