Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make OCamlbuild compile and link a C file into an OCaml project?

I'm trying to build an OCaml binary main.native from main.ml that also relies on a single C file custom.c to implement a new primitive. This C file needs to be compiled and linked. Is there a way to do this just with a _tags file? The obvious problem is that OCamlbuild does not detect the dependency when scanning main.ml and hence needs to be told explicitly about the dependency.

ocamlbuild main.native

OCamlbuild knows a rule to compile a *.c file to a *.o file but I don't know how to add the dependency.

like image 311
Christian Lindig Avatar asked Oct 28 '13 20:10

Christian Lindig


2 Answers

There are a number of resources out there.

The first thing is that you need to tag the main.native as to create a dependency on the c-stubs and link accordingly. (By the way, this assumes the c-library is called cstub, but it can be anything you'd like).

_tags :

<*.{byte,native}> : use_cstub
<**/*.cm{x,}a>    : use_cstub

Then, in myocamlbuild.ml create a dependency of a c-library to the things tagged,

dep ["link";"ocaml";"use_cstub"] ["libcstub.a"]

OCamlbuild has rules for creating library files (*.so and *.a), but you would need to add a listing of the files to be built against in a .clib file,

cstub.clib :

cobjfile1.o
cobjfile2.o
...

Any header files also need to be copied over from the main directory to the _build/ directory. This is done by specifying they are a dependency on compilation in c (in myocamlbuild.ml, where headers is a list of strings naming the header files in the project.

dep ["c"; "compile"] headers;

and finally, adding flags to when we link the project with the c-stub library (also in myocamlbuild.ml),

flag ["link";"ocaml";"use_cstub"] (S[A"-dllib";A"-lcstub";A"-cclib";A"-lcstub"]);
like image 199
nlucaroni Avatar answered Nov 20 '22 11:11

nlucaroni


I have accepted the answer above but would like to document the solution. As mentioned in a comment, I have created a new parametrized tag linkdep() using myocamlbuild.ml:

open Ocamlbuild_plugin;;

dispatch 
    ( function 
    | After_rules -> pdep ["link"] "linkdep" (fun param -> [param])
    | _           -> ()
    )

The newly created tag is used in _tags to add a link dependency:

<*.ml>:     annot
<*.byte>:   linkdep(custom_unix_stubs.o),custom
<*.native>: linkdep(custom_unix_stubs.o)

This relies on built-in rules to compile a C file to an object file. However, this would still miss dependencies on header files (which I don't have).

like image 26
Christian Lindig Avatar answered Nov 20 '22 11:11

Christian Lindig