c++ - 如何编译相互依赖的 OCaml 和 C/C++ 代码

标签 c++ c ocaml

我在定义接受 uint64_tchar* 的 C void 函数的签名时遇到问题。我尝试了 int64 -> string -> _

我也不知道如何一起编译我的C++文件(带有C接口(interface))

events.ml

open Lwt.Infix

external call: int64 -> string -> _ = "function_pointer_caller"

let begin_event pointer = 
    Lwt_unix.sleep 5.0 >>= fun () ->
        call pointer "message"

let () = Callback.register "begin_event" begin_event

接口(interface).c:

#include <stdio.h>
#include <string.h>
#include <caml/mlvalues.h>
#include <caml/callback.h>
#include <caml/alloc.h>
#include <caml/bigarray.h>

extern void register_function_callback();

void print_from_event(char* message) {
    printf("OCaml event: %s\n", message);
}

void function_pointer_caller(uint64_t pointer, char* message)
{
    void (*f)(char *);
    f = pointer;
}

void register_function_callback() {
    static const value *begin_event_closure = NULL;
    if (begin_event_closure == NULL)
    {
        begin_event_closure = caml_named_value("begin_event");
        if (begin_event_closure == NULL)
        {
            printf("couldn't find OCaml function\n");
            exit(1);
        }
    }
    uint64_t pointer = (uint64_t) &function_pointer_caller;
    caml_callback(*begin_event_closure, (int64_t) &pointer);
}

ma​​in.cc

#include <stdio.h>
#include <caml/callback.h>

extern "C" void register_function_callback();

int main(int argc, char **argv)
{
  caml_startup(argv);
  register_function_callback();
  while (true)
  {
  }
  return 0;
}

我认为没有办法将.cc 与.ml 一起编译,因为.cc 不一定有C 接口(interface)。也许可以将 .ml 编译为 .so 对象并使用 C 接口(interface)将其链接到 .cc ?

无论如何,我确实将 interface.cc 更改为 interface.c 并将 interface.c 添加到 ocamlopt > 命令:

ocamlfind ocamlopt -o s -linkpkg -package lwt.unix -thread event_emitter.ml interface.c

g++ -o event_emitter_program -I $(ocamlopt -where) \
    s.o interface.o main.cc event_emitter.o $(ocamlopt -where)/libasmrun.a -ldl

第一个命令编译正常,但 g++ 给出

event_emitter.o: In function `camlEvent_emitter__begin_event_90':
:(.text+0x3f): undefined reference to `camlLwt_unix__sleep_695'
:(.text+0x4c): undefined reference to `camlLwt__bind_1276'
collect2: error: ld returned 1 exit status

请注意,我插入了上一个命令 (ocamlopt) 中的 interface.o 并在 g++ 中链接,因为 ocamlopt 实际上传递了 C 文件到 C 编译器。

我不知道为什么它会提示 Lwt_unix 的事情,因为我已经在 ocamlopt 中使用它们进行了编译。

最佳答案

ocamlopt 实用程序不仅仅是链接指定的编译单元和库,它还嵌入了架构启动代码,该代码未包含在 asmrun 中图书馆。可以使用 -output-obj 获取此代码,但我发现它有点容易出错并且难以维护,因为它并不是真正可组合的1

因此,最好依靠 ocamlopt 来构建最终的二进制文件,该二进制文件将由用不同语言编写的模块组成。每个单元都将使用适合其编写语言的工具来构建。让我们构建 events.ml 编译单元:

ocamlfind ocamlopt -c -package lwt.unix events.ml

现在,让我们构建界面(我们可以在这里使用 cc,但使用 ocamlopt 将为我们省去一些提供包含位置的麻烦)

ocamlfind ocamlopt -c interface.c 

现在,让我们构建 C++ 部分(但首先修复它并使用 caml_main 而不是 caml_startup,因为我们需要 native 运行时)。

g++ -c main.cc -o main.o -I `ocamlc -where`

现在,当我们拥有所有单元后,我们就可以执行最终的链接命令了:

ocamlfind ocamlopt events.cmx interface.o main.o -package lwt.unix -package lwt -thread -linkpkg -o emitter

瞧,我们可以使用 ./emitter 运行我们的程序。


1) 对多个编译单元使用此选项可能很容易导致符号冲突。

关于c++ - 如何编译相互依赖的 OCaml 和 C/C++ 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61602290/

相关文章:

c++ - 在 Boost Phoenix 表达式中转换函数体

c++ - 继承破坏了 C++ 中的多态性?

c - 使用 cygwin 在 c 中编程

functional-programming - 具有多个文件的记录的可变字段

ocaml - OCaml 中的 toString() 等效项

ocaml - OCaml 中是否有中缀函数组合运算符?

c++ - 如何在 Messagebox 中显示变量+文本? Winapi32 C++

C++将函数指针指向的函数分配给另一个函数指针

Mac 终端上的 CTRL-D 输出一个 D 字符

c - Xcode 4.6 是否可以添加 C11 支持?