Gcc 链接Ocaml和C时未解析的外部函数

Gcc 链接Ocaml和C时未解析的外部函数,gcc,linker,ocaml,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> #

我正在尝试包装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);
}
我能够很好地编译代码。比如:

$ 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\u交易
在文本段中定义

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

有什么建议吗?

通常,您必须按“拓扑”顺序列出模块。也就是说,您需要在使用它的其他模块之前列出一个模块。我将进行测试,看看这是否解决了您的问题

更新

仔细观察,我发现了一些问题,或者至少是一些我不希望解决的问题

你的存根代码是用C编写的,但是它调用了C++编写的函数。C++是专门设计的,能够调用C函数,但反过来,在我听到的情况下,它一般不是真的。 最终编译使用产生字节码的

ocamlc
。我认为你不能轻易地将字节码与任意外部本机代码链接起来。如果您生成一个“自定义”字节码解释器,那么您可能可以这样做,而这不是您想要的

如果我将代码更改为全部C,如果我将一些顶级代码添加到test.ml,如果我使用
ocamlopt
进行最终编译和链接,我的工作如下

$ 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
中的一个普通变量名。将其放在括号中不是必需的,也不会改变其含义(例如,与类型名之间的含义)。

感谢您的帮助。我知道问题出在哪里了


我导出的函数caml\u deal()已定义,因此文本段中存在
\u caml\u deal
。但是,我没有链接一个C++代码依赖的库(是的,我在代码中有<代码>外部的”C“< /代码>”。如果C/C++代码缺少一个或多个符号,
ocamlopt
会将问题报告为顶级函数不可用。在某种程度上,这甚至是有道理的。不过,对于像我这样的新手来说,一个更详细的错误会更有见地。

Ocaml支持在字节码中使用C代码,但有一些区别。具体来说,具有5个以上参数的函数对字节码和本机代码遵循不同的调用约定。详细说明见手册。C++代码也可从OCAML中使用,但需要使用“代码>外部“C”<代码>或使用OcAML文件或存根中的C++损坏名称。由于名称mangling依赖于体系结构,这是一个坏主意。在我的代码中,我把存根声明为代码>外部“C”<代码>,并将它们编译成C++。这是在Windows上吗?我认为您对问题的解释是正确的。否
ocamlopt
不会只是随机选择一个函数并将其报告为不可用。此外,ocamlopt将使用您的系统链接器,因此这里没有什么意外。我相信,真正的原因是您指定对象文件的顺序。在OCaml中,它应该是拓扑顺序的,正如Jeffrey已经告诉过的——它应该是
test\u stub.cmo test.cmo
而不是相反。
$ 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