问题
I wish to call OCaml code through C++ by compiling OCaml to a static or shared library that contains a C interface. This page seems to explain how to create a C interface for OCaml. But how do I do it and compile it? And how do I obtain the .h file to load in my C++ code?
Also, could someone explain to be this part:
The OCaml runtime system comprises three main parts: the bytecode interpreter, the memory manager, and a set of C functions that implement the primitive operations. Some bytecode instructions are provided to call these C functions, designated by their offset in a table of functions (the table of primitives).
I thougth OCaml could be compiled to native machine language. Why it is compiled to bytecode and interpreted at runtime? Is it always like that, or only for OCaml libraries compiled with C interface?
回答1:
Most of that page describes how to call C from OCaml. You want to do the reverse, which is described in Advanced Topics: callbacks from C to OCaml, closer to the bottom of the page.
When you do native compilation there is no bytecode involved, just as you say. The native compiler (ocamlopt) produces ordinary object (.o in Unix) files and extra files containing OCaml metadata.
If you look at Advanced Example with callbacks, you'll see an example where the main program is in C, with calls to two functions defined in OCaml. Things should work similarly in C++. (I have only done this in C myself, however.)
Update
Here is the worked-out example using the code from Advanced example with callbacks. I am running this code on Ubuntu 18.04.4 (x86_64).
The OCaml code looks like this:
$ cat mod.ml
let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 1)
let format_result n = Printf.sprintf "Result is: %d\n" n
let () = Callback.register "fib" fib
let () = Callback.register "format_result" format_result
Compile this code and ask for a complete object file:
$ ocamlopt -output-obj -o bigmod.o mod.ml
Rename the C code to modwrap.cc. (The code is given in the OCaml manual section.)
$ head -6 modwrap.cc
#include <stdio.h>
#include <string.h>
#include <caml/mlvalues.h>
#include <caml/callback.h>
int fib(int n)
Note that the OCaml include files are conditionalized as to whether they're being included from C or C++ (as are almost all header files these days).
The main function from the OCaml manual section is also valid C++; rename it to main.cc:
$ head -7 main.cc
#include <stdio.h>
#include <caml/callback.h>
extern int fib(int n);
extern char * format_result(int n);
int main(int argc, char ** argv)
Now compile and link everything:
$ g++ -c modwrap.cc
$ g++ -o myprog -I $(ocamlopt -where) \
main.cc modwrap.o bigmod.o $(ocamlopt -where)/libasmrun.a -ldl
$
Now run the program
$ ./myprog
fib(10) = Result is: 89
There is no automatic generation of header files. In this example the extern
lines of main.cc
are the header file in essence. If you want a header file you'll have to write something like this yourself.
Update 2
Here are the commands for creating an actual static library containing the OCaml functions and their wrappers. This assumes that you have done the compiles above to create bigmod.o and modwrap.o:
$ cp $(ocamlopt -where)/libasmrun.a libmyoc.a
$ ar r libmyoc.a bigmod.o modwrap.o
Now you can use this library in your C++ code (represented by main.cc):
$ g++ -o myprog -I $(ocamlopt -where) main.cc -L . -lmyoc -ldl
$ ./myprog
fib(10) = Result is: 89
Update 3
(I updated the above commands to work on Unbuntu.)
来源:https://stackoverflow.com/questions/61416259/ocaml-as-c-library-hello-world-example