8

我正在尝试使用混合的 C 和 Ocaml 源代码编译程序,C 中的应用程序的主要部分调用 OCaml 代码。好吧,这里没问题,这似乎是一个常见的操作,有完整的文档,使用标准的 Ocaml 工具很容易做到。

稍微解释一下,这种编译分为 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;
}

这就是全部。显然,我跳过了所有无意义的东西,因为这个简单的例子应该有效而无效。它必须是 my 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
4

1 回答 1

7

您的链接命令在两个方面不正确:

  1. 您需要链接-ldlfordlopen等。
  2. 您必须将库放在引用它们的对象之后(即您的-lcamlrun参数在链接行的错误位置)。链接线上的参数顺序很重要
于 2012-04-20T19:18:41.037 回答