Hello and may your day be nice.
TLDR; could not compile (link) example from ocaml manual for embedding ocaml into c program. (no ctypes)
My setup: opam with default cygwin configuration and ocaml 5.3 on Windows 10.
Some details from ocamlc -config:
version: 5.3.0
c_compiler: x86_64-w64-mingw32-gcc
Ocaml code used in code.ml:
let rec fib n = if n < 2 then 1 else fib(n-1) + fib(n-2)
let _ = Callback.register "fib" fib
C code in main.c:
#include <wchar.h>
#include <stdio.h>
#include "caml/misc.h"
#include "caml/mlvalues.h"
#include "caml/sys.h"
#include "caml/osdeps.h"
#include <caml/callback.h>
#include <windows.h>
int fib(int n)
{
static const value * fib_closure = NULL;
if (fib_closure == NULL) fib_closure = caml_named_value("fib");
return Int_val(caml_callback(*fib_closure, Val_int(n)));
}
int main() {
// fake argv for now since I don't know how to convert windows arguments to argv
char_os argv0[] = { (unsigned short int)'x', 0 };
char_os** argv = malloc(sizeof(char_os*) * 2);
argv[0] = argv0;
argv[1] = NULL; // ocaml probably uses a null terminator for its argv since there's no argc?
caml_main(argv);
int result = fib(10);
return 0;
}
With build commands like:
ocamlopt -output-obj caml.ml -o caml_with_extras.o
ar r caml_final.a D:/opam/default/lib/ocaml/libasmrun.a caml_with_extras.o
gcc -I D:/opam/default/lib/ocaml -o main.exe main.c caml_final.a
Errors look suspiciously similar:
undefined reference to `__imp_caml_named_value’
undefined reference to `__imp_caml_callback’
undefined reference to `__imp_caml_main’
From my understanding this _impl prefix situation is some gcc behavior to (here my understanding is limited) link to DLLs which can be found related to __declspec(dllimport).
On Windows, you must use flexlink to link your final executable. Also, you can use -output-complete-obj instead of -output-obj to include the runtime code in the resulting object (avoiding the need for your ar invocation). Something like:
# use -output-complete-obj to also include the runtime in the resulting object
ocamlopt -output-complete-obj caml.ml -o caml_with_extras.o
# compile only, do not yet link
gcc -I D:/opam/default/lib/ocaml -c main.c
# now link
flexlink -exe -chain mingw64 -o main.exe -LD:/opam/default/lib/ocaml/flexdll -LD:/opam/default/lib/ocaml main.o caml_with_extras.o -lpthread -lws2_32 -lole32 -luuid -lversion -lshlwapi -lsynchronization -l:libpthread.a -lgcc_eh
To get the exact list of support libraries needed to link the final executable you can look at ocamlopt -config (the native_c_libraries field).
Short reply: you sir are amazing and with your response I linked final execuatable in no time. May your day be great and programming activites pleasant.
I modified C code to include simple printing and this is main.c:
#include <wchar.h>
#include <stdio.h>
#include "caml/misc.h"
#include "caml/mlvalues.h"
#include "caml/sys.h"
#include "caml/osdeps.h"
#include <caml/callback.h>
#include <windows.h>
int fib(int n)
{
static const value * fib_closure = NULL;
if (fib_closure == NULL) fib_closure = caml_named_value("fib");
return Int_val(caml_callback(*fib_closure, Val_int(n)));
}
int main() {
// fake argv for now since I don't know how to convert windows arguments to argv
char_os argv0[] = { (unsigned short int)'x', 0 };
char_os** argv = malloc(sizeof(char_os*) * 2);
argv[0] = argv0;
argv[1] = NULL; // ocaml probably uses a null terminator for its argv since there's no argc?
caml_main(argv);
int result = fib(10);
printf("%d\n", result);
return 0;
}
And these instructions are used for compiling and linking (-l:libpthread.a -lgcc_eh are not necessary for my c code):