# Supporting header installation > Supporting luv and similar packages. ## Context Some opam packages ship C headers (`.h` files). Two common use cases are: - a library with a C part in its API (e.g. `ctypes`) - an OCaml library acting as a wrapper for a C library, but which embeds the source code for this library instead of relying on depexts (ex: `luv` which embeds `libuv`). Then, some other packages that depend on these can use these headers while building their C stubs. A common convention is to install these `.h` files in the package's `lib` directory and to refer to them as e.g. `%{lib:ctypes:ctypes_cstubs_internals.h}` or to the directory as `%{lib:ctypes:.}`. ## Problem This works when the package is installed, but this breaks in other cases. The reason is that `%{lib:...}` refers to the installed path (more or less the output of `opam var pkg:lib`). The problematic cases include: - using `opam-monorepo` (the sources are unpacked and not installed) - developing several packages in a single repository (it might be necessary to pin or install first one library) - even when developing a single package this can cause issues, since the "installed" (pinned) version might drift from the version under development. What dune is lacking is a mechanism to refer to these headers that would work in the source tree as well. ## Solution The solution proposed here consists in adding a first class notion of installed headers attached to libraries: a library can have a tree of headers attached to it. This generalizes the notion of `(install_c_headers)`. At install time, this directory is installed by opam (with preserved structure). This directory can be accessed by dependencies: if the library is found installed in opam, the installed directory is used, otherwise the directory in the workspace is used. ## Implementation ### Syntax - the existing `(install_c_headers)` field is now recorded in the lib db - `(foreign_stubs (include))` gets extended with a new `(headers <lib>)` constructor. - a new pform `${headers:<lib>}` is added - (optional) `(install_c_headers)` gets a new `(dir <path>)` constructor to install a directory of headers, with preserved structure ### Semantics On the "provider" side, `(install_c_headers)` are now recorded in the lib db, either as plain headers (individual `.h` files) or as structured directories. Install rules are updated so that both kinds of headers are can be turned into an implicit `(install)` stanza. On the "user" side, `(headers <lib>)` gets evaluated to the corresponding directories: the directories where the files are installed, or the right directories in case the provider is found in the workspace. In case of a plain header in a workspace, the source directory is passed as `-I` so there might be overapproximation if this mechanism is not sandboxed (if `x.h` and `y.h` are present in the same directory, `y.h` might be available to the C compiler even if not explicitly depended on). The `%{headers:<lib>}` pform is expanded using the same semantics. This is useful for when C code is compiled using lower level stanzas. ### Open questions / remarks on implementation - when there are several headers directories for a given library, it's not clear how to expand `%{headers:<lib>}`. A list of directories is not useful, since it is usually used with `-I`. A possible solution could be to expand with the `-I` part. - should we make the mechanism more automatic? for example, foreign stubs built for a library that depends on a library could be built with its headers added. - what should be the installed path in opam? several packages use the `%{lib:<lib>:.}` location, even though it's not the "right" one. A specific `include` section in opam could be useful. - could we rely on some of the work on `sites` to support this?