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

2

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.

Zucchetto answered 28/10, 2013 at 20:26 Comment(3)
Oasis can generate suitable myocamlbuild.m and _tags files. Have you tried it?Indoxyl
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.Zucchetto
Oasis generates myocamlbuild.ml and other files. The result seems to be compilable without oasis installed .Indoxyl
J
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"]);
Janeyjangle answered 29/10, 2013 at 15:14 Comment(2)
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.Zucchetto
The second resource 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.Zucchetto
Z
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).

Zucchetto answered 1/11, 2013 at 9:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.