我想編譯一個程序,使用混合的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
我想你不想與stdlib.a鏈接(因爲它應該默認由-lasmrun和-lcamlrun加載) – Thomas 2012-04-20 11:02:18
是的,你說得對,它是一個測試版本的日誌。刪除。 – 2012-04-20 11:08:01
如果沒有看到您的代碼,很難進行調試。你有一個小例子來重現錯誤嗎? – Thomas 2012-04-20 15:20:06