OCaml nesting in C: binding error

I am trying to compile a program using mixed sources of C and Ocaml, with most of the application in C invoking some pieces of OCaml code. Everything is in order, there are no problems. This seems to be a normal operation, fully documented , which is easy to do with standard Ocaml tools.

Let me explain a bit that this compilation is divided into 4 stages: compiling Caml to Caml objects, compiling Caml objects to C, compiling C files, and finally compiling all C objects together and getting the executable.

The theory is that the Ocaml compiler will implement the Caml, GC runtime and all its materials automatically, and we just need to indicate whether we will use any -lcamlrun bytecode (link -lcamlrun ) or our own binary file (link -lasmrun ).

So it seems pretty simple, let it do it. Steps 1, 2, and 3 went as expected, fine! Only the 4th step is problematic. Just take a look:

 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 

IMHO, it seems that there are two errors:

  • Several definitions of main
  • The compiler does not find the Pervasive module

I really don't know how to fix this, maybe I need to link another file. Does anyone have an idea?

As I said, I put code that gives these errors. It will be quite simple, because the code is very small, most of it was given in the example in the documentation.

init.ml

 let fx = 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; } 

And it's all. Obviously, I missed all the pointless things, as this simple example should work and not work. This should be my Makefile that follows.

By the way, this is pretty ugly. If you have any suggestions for this type of application (Caml inside C) or refactoring suggestions, I'll take them all.

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 
+8
c linker ocaml
source share
1 answer

Your link is incorrect in two ways:

  • You need to associate with -ldl for dlopen , etc.
  • You should put the libraries after the objects that reference them (i.e. your -lcamlrun arguments are in the wrong place in the link line). The order of the arguments on the link line matters .
+6
source share

All Articles