链接Ocaml和C时无法解决的外部功能

时间:2019-07-14 16:57:12

标签: gcc linker ocaml

我正在尝试包装C代码以将其与OCaml链接。

让代码可以正常编译,但是链接不起作用。

我的ML测试代码:

external deal: int * int -> bool = "caml_deal"

let (bool) =
  deal(1, 1)

我也有一个存根:

#include <stdio.h>
#define CAML_NAME_SPACE
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include "clang_deal.h"

CAMLprim value
caml_deal(value ml_tuple)
{
    CAMLparam1( ml_tuple );
    int players = Int_val(Field(ml_tuple, 0));
    int treshold = Int_val(Field(ml_tuple, 1));
    int res = deal(players, treshold);
    return Val_bool(players);
}

我的交易定义为:

#include "utils.h"

int deal(int players, int treshold) {
  dealer d{};
  return d.deal(players, treshold);
};

我能够很好地编译代码。喜欢:

$ ocamlc -c test_stubs.c
$ gcc -c clang_deal.cpp -std=c++17 -I./pbc/include
$ ocamlc -c test.ml

当我尝试链接时,它会引发错误:

$ ocamlc -o dealer test.cmo test_stubs.o clang_deal.o
File "_none_", line 1:
Error: Error while linking test.cmo:
The external function `caml_deal' is not available

nm(1)显示caml_deal是在文本段中定义的。

$ nm test_stubs.o
0000000000000000 T _caml_deal
                 U _caml_local_roots
                 U _deal

有什么建议吗?

2 个答案:

答案 0 :(得分:2)

通常,您必须按“拓扑”顺序列出模块。即,您需要在使用该模块的其他模块之前列出该模块。我会测试一下是否可以解决您的问题。

更新

仔细观察,我会发现一些问题,或者至少是我不希望的事情。

您的存根代码是用C编写的,但它调用了用C ++编写的函数。 C ++是专门为能够调用C函数而设计的,但是据我所知,通常情况并非如此。

您的最终编译使用ocamlc来产生字节码。我认为您无法轻松地将字节码与任意外部本机代码链接。如果生成的不是您想要的“自定义”字节码解释器,则可以这样做。

如果我将代码更改为全部C,如果将一些顶级代码添加到test.ml,并且如果我使用ocamlopt进行最终的编译和链接,则对我来说工作如下。 / p>

$ cat clang_deal.c
int deal (int players, int threshold)
{
    return !!(players + threshold);
}

$ cat test.ml
external deal: int * int -> bool = "caml_deal"

let (bool) = deal (1, 1)

let main () = Printf.printf "%b\n" bool

let ()  = main ()

$ ocamlopt -o deal clang_deal.c test_stubs.c test.ml
$ ./deal
true

这似乎不完全是您想要做的,但是也许它可以使您克服第一个或两个问题。

作为附带说明,尚不清楚您是否意识到bool只是test.ml中的普通变量名称。不需要将其放在括号中,并且不会更改含义(例如,与类型名称相对应)。

答案 1 :(得分:0)

感谢您的所有帮助。我找出了问题所在。

我的导出函数caml_deal()已定义,因此文本段中有_caml_deal。但是,我无法链接依赖C ++代码的库之一(是的,我的头中有extern "C")。事实证明,如果C / C ++代码缺少一个或多个符号,ocamlopt将该问题报告为顶级功能不可用。从某种意义上说,这甚至是有意义的。但是,对于像我这样的新手,更详细的错误将更具有洞察力。