6

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.

Christian Lindig
  • 1,216
  • 1
  • 9
  • 24
  • Oasis can generate suitable `myocamlbuild.m` and `_tags` files. Have you tried it? – Kakadu Oct 29 '13 at 08:00
  • 1
    No, I haven't tried to use Oasis. The main reason is that I would prefer not to rely on tools outside the OCaml distribution if possible. If necessary, I would implement a `myocamlbuild.ml` that adds the required dependency. – Christian Lindig Oct 29 '13 at 12:16
  • Oasis generates `myocamlbuild.ml` and other files. The result seems to be compilable without oasis installed . – Kakadu Oct 29 '13 at 13:28

2 Answers2

6

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"]);
Community
  • 1
  • 1
nlucaroni
  • 47,556
  • 6
  • 64
  • 86
  • Thanks for going into the details. I guess this also means: `myocamlbuild.ml` is required and the problem can't be solved with `_tags` alone. – Christian Lindig Oct 29 '13 at 17:07
  • 1
    The [second resource](http://l-lang.blogspot.de/2012/08/incorporating-c-code-in-ocaml-project.html) was very helpful. It provides a minimal plugin that implements a parametrized flag `linkdep()` that can be used to include link dependencies into a `_tags` file. – Christian Lindig Oct 29 '13 at 18:34
2

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).

Christian Lindig
  • 1,216
  • 1
  • 9
  • 24