2012-04-20 39 views
8

我想编译一个程序,使用混合的C和Ocaml来源,与应用程序在C中的主要调用一些OCaml代码段。 好吧,这里没问题,这似乎是一个常见的操作,易于使用标准的Ocaml工具。嵌入OCaml在C:链接错误

让我解释一下,这种编译分4步进行:Caml编译为Caml对象,然后编译Caml到C对象,然后编译C文件,最后将所有C对象编译在一起并获取可执行文件。

的理论是,OCaml的编译器会自动嵌入CAML运行时,GC,和所有的东西,我们只是要指出,如果我们使用的任何OCaml的字节码(参考-lcamlrun)或本机二进制(参考-lasmrun) 。

所以,它看起来很简单,让我们来做吧。步骤1,2和3按预期行进,好! 只有第四步是有问题的。只要看一看:

cc -o /home/thomas/Documents/projects/ocaml/GogoGame/bin/GogoPlayer.exe \ 
     -L/usr/lib/ocaml -lcamlrun \ 
     /home/thomas/Documents/projects/ocaml/GogoGame/src/init_camlcode.o \ 
      /home/thomas/Documents/projects/ocaml/GogoGame/src/init.o \ 
      /home/thomas/Documents/projects/ocaml/GogoGame/src/interface.o \ 
      /home/thomas/Documents/projects/ocaml/GogoGame/src/caml_func.oo 
/home/thomas/Documents/projects/ocaml/GogoGame/src/interface.o: In function `main': 
interface.c:(.text+0x0): multiple definition of `main' 
/usr/lib/ocaml/libcamlrun.a(main.o):(.text+0x0): first defined here 
/usr/lib/ocaml/libcamlrun.a(floats.o): In function `caml_exp_float': 
(.text+0x488): undefined reference to `exp' 
/usr/lib/ocaml/libcamlrun.a(floats.o): In function `caml_fmod_float': 
(.text+0x4f9): undefined reference to `fmod' 
/usr/lib/ocaml/libcamlrun.a(floats.o): In function `caml_log_float': 
(…) 
/usr/lib/ocaml/libcamlrun.a(unix.o): In function `caml_dlopen': 
(.text+0x2ed): undefined reference to `dlopen' 
/usr/lib/ocaml/libcamlrun.a(unix.o): In function `caml_dlclose': 
(.text+0x300): undefined reference to `dlclose' 
/usr/lib/ocaml/libcamlrun.a(unix.o): In function `caml_dlsym': 
(.text+0x31b): undefined reference to `dlsym' 
/usr/lib/ocaml/libcamlrun.a(unix.o): In function `caml_dlerror': 
(.text+0x342): undefined reference to `dlerror' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init_camlcode.o:(.data.rel+0xc): undefined reference to `caml_array_get_addr' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init_camlcode.o:(.data.rel+0x10): undefined reference to `caml_array_get_float' 
(...) 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init_camlcode.o:(.data.rel+0x31c): undefined reference to `caml_lazy_make_forward' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init_camlcode.o:(.data.rel+0x320): undefined reference to `caml_get_public_method' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init_camlcode.o:(.data.rel+0x3ac): undefined reference to `caml_terminfo_setup' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init_camlcode.o:(.data.rel+0x3b0): undefined reference to `caml_terminfo_backup' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init_camlcode.o:(.data.rel+0x3b4): undefined reference to `caml_terminfo_standout' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init_camlcode.o:(.data.rel+0x3b8): undefined reference to `caml_terminfo_resume' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init.o: In function `camlInit__f_1030': 
(.text+0xc): undefined reference to `camlPervasives' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init.o: In function `camlInit__f_1030': 
(.text+0x11): undefined reference to `camlPervasives__output_string_1191' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init.o: In function `camlInit__f_1030': 
(.text+0x19): undefined reference to `camlPervasives__string_of_int_1130' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init.o: In function `camlInit__f_1030': 
(.text+0x20): undefined reference to `camlPervasives' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init.o: In function `camlInit__f_1030': 
(.text+0x25): undefined reference to `camlPervasives__output_string_1191' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init.o: In function `camlInit__format_result_1034': 
(.text+0x9c): undefined reference to `camlPrintf__sprintf_1414' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init.o: In function `camlInit__entry': 
(.text+0xe1): undefined reference to `caml_c_call' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init.o: In function `camlInit__entry': 
(.text+0xfb): undefined reference to `caml_c_call' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init.o: In function `camlInit__entry': 
(.text+0x115): undefined reference to `caml_c_call' 
/home/thomas/Documents/projects/ocaml/GogoGame/src/init.o: In function `camlInit__f_1030': 
(.text+0x32): undefined reference to `camlPervasives__print_newline_1276' 
collect2: ld returned 1 exit status 
make: *** [GogoPlayer] Error 1 

恕我直言,似乎有两个错误:

  • main
  • 链接器多次定义没有找到模块Pervasive

我真的不知道如何解决这个问题,也许我必须链接另一个文件。 有人有想法吗?

如问,我把代码给出这些错误。这将非常简单,因为代码非常少,大部分代码都是在文档中的示例中给出的。

init.ml

let f x = print_string "f is applied to "; print_int x; print_newline() 
let rec fib n = if n < 2 then 1 else fib(n-1) + fib(n-2) 
let format_result n = Printf.sprintf "Result is: %d\n" 

let _ = 
    Callback.register "Arbitrary Name" f; 
    Callback.register "fib" fib; 
    Callback.register "format_result" format_result 

caml_func.c

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

void call_caml_f(int x) 
{ 
    static value * closure_f = NULL; 
    if (closure_f == NULL) /* First time around, look up by name */ 
     closure_f = caml_named_value("Arbitrary Name"); 

    caml_callback(*closure_f, Val_int(x)); 
} 

int fib(int n) 
{ 
    static value * fib_closure = NULL; 
    if (fib_closure == NULL) fib_closure = caml_named_value("fib"); 
    return Int_val(caml_callback(*fib_closure, Val_int(n))); 
} 

char * format_result(int n) 
{ 
    static value * format_result_closure = NULL; 
    if (format_result_closure == NULL) 
     format_result_closure = caml_named_value("format_result"); 
    return strdup(String_val(caml_callback(*format_result_closure, Val_int(n)))); 
    /* We copy the C string returned by String_val to the C heap 
    so that it remains valid after garbage collection. */ 
} 

interface.c

#include <stdio.h> 
#include "caml_func.c" 

#define BYTECODE 

int main(int argc, char **argv) 
{ 
#ifdef BYTECODE 
    caml_startup(argv); 
#else 
    caml_main(argv); 
#endif 

    /* Make sure that stdout is not block buffered. */ 
    setbuf(stdout, NULL); 

    /* Process GTP commands. */ 
    //gtp_main_loop(commands, stdin, NULL); 
    // CAML code here ? 

    return 0; 
} 

这就是全部。显然,我跳过所有无意义的东西,因为这个简单的例子应该工作,没有。它必须是我的Makefile,如下所示。

顺便说一句,这是相当丑陋的。如果您有针对这种应用程序的建议(内部为 C中的Caml )或重构建议,我将全部采用。

Makefile.ocaml

.PHONY: all clean mrproper 

# RULES and EXEC are magically set in Makefile.magic 
all: depend $(RULES) $(EXE) 
    @echo [DONE] 

mli: $(CAML_ONLY:.ml=.mli) 
ml-byte: $(CAML_ONLY:.ml=.cmo) 
ml-called-byte: $(CAML_CALLED_BY_C:.ml=.$(OBJ)) 
ml-nativ: $(CAML_ONLY:.ml=.cmx) 
ml-called-nativ: $(CAML_CALLED_BY_C:.ml=.$(OBJ)) 
c-wrapper: $(C_WRAPPERS:.c=.oo) 
c-only: $(C_ONLY:.c=.o) 

$(EXE): 
    $(CC) -o $(BIN)/$(EXE).exe \ 
     $(FLAGS) \ 
     -L$(OCAMLLIB) $(LINKED) -l$(RUNLIB) \ 
     $(wildcard $(SRC)/*.$(OBJ)) $(wildcard $(SRC)/*.oo) # */ 

%.o: %.c 
    $(CC) $(FLAGS_C) -c $< -o $(SRC)/$(*F).o 
%.mli: %.ml 
    $(OCAMLC) $(FLAGS_ML) -i $< > $(SRC)/$(*F).mli 
%.cmi: %.mli 
    $(OCAMLC) $(FLAGS_ML) -c $< -o $(SRC)/$(*F).cmi 
%.cmo: %.ml 
    $(CAMLC) $(FLAGS_ML) -c $< -o $(SRC)/$(*F).cmo 
%.cmx: %.ml 
    $(CAMLOPT) $(FLAGSOPT) -c $< -o $(SRC)/$(*F).cmx 
# native 
%.o: %.ml 
    $(cd $(SRC)) 
    $(OCAMLC) -output-obj -o $(*F)_camlcode.o \ 
     $(FLAGS_MLC) \ 
     $< 
# bytecode 
%.ob: %.ml 
    $(cd $(SRC)) 
    $(OCAMLOPT) -output-obj -o $(*F)_camlcode.ob \ 
     $(FLAGS_MLC) \ 
     $< 
%.oo: %.c 
    $(CC) $(FLAGS_WRAP) -c $< -o $(SRC)/$(*F).oo 


clean_mli: 
    rm -f $(SRC)/*.mli # */ 
clean: 
    rm -f $(BIN)/*.{a,o,oo,cmi,cmo,cmx} # */ 
    rm -f $(SRC)/*.{a,o,oo,cmi,cmo,cmx} # */ 

mrproper: clean, clean_mli 
    rm -f $(BIN)/$(EXE) 

depend: 
    $(OCAMLDEP) $(INCLUDES) $(SRC)/*.ml $(SRC)/*.mli > .depend # */ 

include .depend 
+0

我想你不想与stdlib.a链接(因为它应该默认由-lasmrun和-lcamlrun加载) – Thomas 2012-04-20 11:02:18

+0

是的,你说得对,它是一个测试版本的日志。删除。 – 2012-04-20 11:08:01

+0

如果没有看到您的代码,很难进行调试。你有一个小例子来重现错误吗? – Thomas 2012-04-20 15:20:06

回答

6

您的链接命令有两种方式不正确:

  1. 您需要-ldldlopen链接等
  2. 你必须把图书馆后引用它们的对象(即您的-lcamlrun参数在第在链接线上有错误的地方)。链接行matters上的参数顺序。