如何编译相互依赖的OCaml和CC++代码。

问题描述 投票:1回答:1

我在定义一个C语言的void函数的签名时遇到了问题,这个函数接受一个 uint64_t 和a char*. 我试过 int64 -> string -> _.

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

事件.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

接口.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);
}

main.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 接口。也许可以把.ml编译成一个.so对象,然后把它和带有C接口的.cc连接起来?

无论如何,我确实修改了 interface.ccinterface.c 并补充说 interface.cocamlopt 命令。

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

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

我不知道为什么它抱怨的是 Lwt_unix 的东西,因为我已经与它们一起在 ocamlopt.

c++ c ocaml
1个回答
2
投票

ocamlopt 实用程序所做的不仅仅是链接指定的编译单元和库,它还嵌入了架构启动代码,而这些代码并不包含在 asmrun 库。可以使用 -output-obj但我发现它有点容易出错,而且很难维护,因为它并不是真正的可合成的。1.

因此,它是更好地依靠ocamlopt建立最终的二进制,这将包括不同语言编写的模块。每一个单元都会用相应的语言工具来构建。让我们来构建 events.ml 编译单元。

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

现在,让我们构建接口(我们可以使用 cc 在这里,但使用ocamlopt可以让我们省去提供includes位置的麻烦。)

ocamlfind ocamlopt -c interface.c 

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

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) 对多个编译单元使用这个选项可能很容易导致符号冲突。


1
投票

你应该对 "警告 "信息更加小心,不要依赖那些将构建过程与你的配置绑定的东西。请避免使用root控制台!

[WARNING] Running as root is not recommended

在根环境中,通往库的路径可能很复杂。

根据你的 pastebin,我看到 linker 无法定位 lwt_unix_stubs 库。请不要将'.a'和'.so'库混合使用 (/root/.opam/4.10.0/lib/lwt/unix/liblwt_unix_stubs.a /root/.opam/4.10.0/lib/stublibs/dlllwt_unix_stubs.so)! '.a'是静态构建,'.so'是动态构建。

对我来说是一个工作的例子(Ubuntu Linux, ocaml 4.05.0)。

ocamlfind ocamlopt -output-obj -dstartup -linkpkg -package lwt.unix -thread -o s.o event_emitter.ml
g++ -o event_emitter_program -I`ocamlfind c -where` -I $(ocamlopt -where) s.o interface.o main.cc -L `ocamlc -where` -L`ocamlfind query lwt.unix` -L`ocamlfind query threads` -lasmrun -llwt_unix_stubs -lunix -lbigarray -lcamlstr -lthreadsnat -lpthread -ldl

使用 $(ocamlopt -where)/libasmrun.a 是个坏主意。使用-lasmrun和-L来表示库的路径是比较迂腐的方式。

如果你有一些未定义的符号的问题,最好用-lasmrun和-L来表示库的路径。自读 找出哪个图书馆丢失。

© www.soinside.com 2019 - 2024. All rights reserved.