3
votes

I want to compile an OCaml program interfacing with C code, using a MinGW-based GCC, and using separate compilation (GCC produces the .o, then ocamlopt produces the final executable).

It's not clear to me if (1) this should work on Windows and, if so, (2) which command-line arguments are necessary.

I'm using Jonathan Protzenko's OCaml on Windows installer to install OCaml 4.02.1 along with a Cygwin shell (note that it uses a native windows OCaml compiler, not a Cygwin-based one). I installed gcc using Nuwen's MinGW (but had the same issue when using Strawberry Perl's gcc).

Here's my source code:

C file (tc.c):

#include <stdio.h>
#include "caml/mlvalues.h"

value print(value unused) {
  printf("hello from C\n");
  return Val_unit;
}

OCaml file (t.ml):

external print : unit -> unit = "print"

let () =
  Printf.printf "platform: %s\n" (Sys.os_type);
  print ();

The following works just fine:

and@win7 $ ocamlopt t.ml tc.c -o t.exe
and@win7 $ ./t.exe
platform: Win32
hello from C

However, if I use a .o instead of a .c, it doesn't work:

and@win7 $ gcc tc.c -c -I c:/OCaml/lib -o tc.o
and@win7 $ ocamlopt t.ml tc.o -o t.exe
** Cannot resolve symbols for tc.o:
 puts
** Fatal error: Unsupported relocation kind 0004 for puts in tc.o
File "caml_startup", line 1:
Error: Error during linking

Both versions work fine on Linux.

I wonder if it's just some silly mistake that I can quickly fix by giving the right arguments to gcc/ocamlc/ocamlopt, or if it's a current limitation of OCaml's native compilation on Windows.

Edit: camlspotter identified the cause, so in retrospect, I did not need Nuwen's MinGW at all. OCaml on Windows already includes a MinGW-based C compiler, except that it is called i686-w64-mingw32-gcc and not gcc.

1
Just for the record: Nuwen's is not a MinGW distribution! To describe it as such is an infringement of the trademark granted to SPI-Inc, on behalf of MinGW.org.Keith Marshall
Thanks for the remark, should I edit the question to clarify it or is your comment sufficient?anol
You should edit the question, to make it clear that you have chosen a derived fork of MinGW, (which is legitimate, but not supported by the trademark owner). You should also remove the mingw tag; mingw-w64 may be an acceptable alternative, (but nuwen isn't strictly that fork either).Keith Marshall

1 Answers

2
votes

You are probably using a wrong C compiler or without appropriate options. The best way is to use the same C compiler + options used to build OCaml. You can check it by ocamlc -config:

$ ocamlc -config
version: 4.02.3
standard_library_default: C:/ocamlmgw64/lib
standard_library: C:/ocamlmgw64/lib
standard_runtime: ocamlrun
ccomp_type: cc
bytecomp_c_compiler: x86_64-w64-mingw32-gcc -O -mms-bitfields -Wall -Wno-unused
bytecomp_c_libraries: -lws2_32
native_c_compiler: x86_64-w64-mingw32-gcc -O -mms-bitfields -Wall -Wno-unused
native_c_libraries: -lws2_32
native_pack_linker: x86_64-w64-mingw32-ld -r  -o 
ranlib: x86_64-w64-mingw32-ranlib
...

For example, the above shows that my OCaml compiler is built over Cygwin 32 bit environment with x86_64-w64-mingw32-gcc. The same applies for the linker and ranlib. Since you can compile C with OCaml code with ocamlopt, the same C compiler must be already installed in your environment.

Building OCaml compiler by yourself to make sure the same C compiler is used both for C and OCaml may be the best way to avoid this sort of C compiler mismatch.