2012-04-20 21 views
8

私はCとOcamlソースを混在させてプログラムをコンパイルしようとしています.CのアプリケーションのメインはOCamlコードのいくつかを呼び出しています。 いいえ、ここに問題はありません。標準的なOcamlツールを使って簡単に行えるのは、一般的な操作fully documentedのようです。OCamlをCに埋め込む:リンクエラー

CamlオブジェクトにCamlをコンパイルし、CamlオブジェクトをCオブジェクトにコンパイルし、次にCファイルをコンパイルし、最後にすべてのCオブジェクトをまとめてコンパイルするという4つのステップで少し説明します。実行可能ファイル

理論があり、OCamlのコンパイラはCamlのランタイム、GCを埋め込み、そのすべてのものを自動的に、そして私達はちょうど私たちはocamlのバイトコード(-lcamlrunを参照)、またはネイティブバイナリ(-lasmrunを参照)どちらを使用するかどうかを示す必要があります。

だから、それはやってみましょう。ステップ1,2および3は期待通りに行った、良い! 第4ステップだけが問題になります。ただ、見て取る:モジュールPervasive

に見つけることができなかったmain

  • リンカーの

    • 複数の定義:

      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 
      

      私見を、2つのエラーがあるようです私は本当にそれを修正する方法は考えていない、多分私は他のファイルをリンクする必要があります。 誰かがアイデアを持っていますか?

      尋ねるように、私はこれらのエラーを与えるコードを書いています。非常にシンプルなコードです。そのほとんどはドキュメントの例で与えられています。

      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でなければなりません。

      ところで、それはかなり醜いです。この種のアプリケーション(Caml C)の提案やリファクタリングの提案がある場合は、それらをすべて取り上げます。

      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

    +0

    そうです、それはテストビルドのログでした。削除されました。 –

    +0

    コードを見ずにデバッグするのはかなり難しいです。バグを再現する小さな例がありますか? – Thomas

    答えて

    6

    あなたのリンクコマンド二つの方法で間違っています:

    1. あなたはdlopenため-ldlとリンクする必要がある、など
    2. あなたは後のライブラリを置く必要がありますそれらを参照するオブジェクト(つまり、-lcamlrun引数はth番目にありますリンク線の間違った場所)。リンク線の引数の順序はmattersです。
    関連する問題