How does a library B
express its internal dependency on library A
, so that a user C
can use B
without knowing about A
?
The case at hand is ocaml-ctypes, which depends on ocaml-integers. A public header in ocaml-ctypes
includes a public header from ocaml-integers
(ctypes_primitives.h
includes ocaml_integers.h
).
Then there is luv, which uses ocaml-ctypes
directly (by including ctypes_cstubs_internals.h
in some C source file.), but not ocaml-integers
- because that is an internal dependency of ocaml-ctypes
.
Since dune
is apparently not aware of the dependency of B to A, the C stubs build includes only the include path to B, the include path to A is missing.
A workaround in user C
may look like this:
--- ocaml-luv-0.5.7.orig/src/c/dune
+++ ocaml-luv-0.5.7/src/c/dune
@@ -117,6 +117,7 @@ let () = Jbuild_plugin.V1.send @@ {|
(deps (:c generate_types_step_2.c) helpers.h shims.h)
(action (bash "\
%{cc} %{c} \
+ -I '%{lib:integers:.}' \
-I '%{lib:ctypes:.}' \
-I %{ocaml_where} \
|}^ i_option ^{| -o %{targets}")))
But, now that I look at the patch, this cmdline is all manually constructed, so little dune can actually do.
The question still stands: does dune actually know that B
depends on A
, and would it add the include path to A
when B
is used?
2 Likes
I’m far from an expert on this, but can relate what I do know.
The OCaml compiler has a built-in mechanism for libraries to record the C flags that they require, so that consumers of the library can pick them up. (See the documentation of ocamlc -a
for more.) This information is stored in .cm(x)a
files, and sure enough we can see the dependendency on integers
is recorded in ctypes
:
; ocamlobjinfo ~/.opam/default/lib/ctypes/ctypes.cmxa | head -n 4
File /home/craigfe/.opam/default/lib/ctypes/ctypes.cmxa
Extra C object files: -lctypes_stubs -lintegers_stubs -Wl,--no-as-needed
Extra C options: -I/home/craigfe/.opam/default/lib/integers
Name: Ctypes_ptr
Dune supports this mechanism, and will ensure that libraries / executables that it builds get the right includes (see the documentation of include_dirs
here.). As you rightly point out, it can’t do this for opaque bash
actions. I suspect a non-ad-hoc fix requires a Dune equivalent of ocamlfind query -i-format -recursive ctypes
, and AFAIK this isn’t exposed in dune
files yet. This is perhaps why @antron ended up hand-rolling a build rule here
Thank you. This seems to be missing in my build of ctypes
.
ls -1 /usr/lib64/ocaml/ctypes*/*.cmxa|xargs -n1 ocamlobjinfo|grep -w C
Extra C object files: -lctypes_foreign_stubs -L/usr/lib64/../lib64 -lffi -Wl,--no-as-needed
Extra C options:
Extra C object files: -lctypes_stubs
Extra C options:
What are the required knobs in a dune file to express such dependency? None of the packages seem to need this feature. This command lists just two compiler core files.
for i in $(find `ocamlc -where` -name "*.cmxa")
do
ocamlobjinfo $i | grep "^Extra C options:." && echo $i
done
The required includes are added by ocaml-ctypes
own homegrown build system, that’s why it happens to work for everyone else.