We’d like to install the tree-sitter runtime library in a specific version, in a way that works on all platforms where opam is supported. This would allow us to publish parsers for various programming languages as opam packages (e.g. PHP, Go, and many more). The tree-sitter runtime is a pure C library. Note that the tree-sitter executable is a C code generator written in Rust that we don’t want to install in this context.
The library we want to install is normally installed with pkg-config in an ordinary way. It doesn’t make any weird system calls and is expected to work everywhere. However, we want to be sure the correct and possibly the very latest version is available when building our application. This is why managing the package ourselves as a single opam package is appealing. We also want to avoid requiring superuser privileges during installation.
Additionally, we could bundle the C library with OCaml bindings (original or simplified). The package would then guarantee the OCaml interface but offer fewer guarantees about the C interface. I’m not sure if it would simplify things overall.
Are there examples of pure C libraries installed with opam inside an opam switch (i.e. not system-wide) that we could imitate?
Isn’t the tree-sitter runtime library a single pure C file with headers? You could vendor that C file and synchronize the tree-sitter version with the opam version.
Also, if you do provide discovery via pkg-config, could you also provide discovery with an alternative way? Perhaps an environment variable override? pkg-config is, for many reasons, not viable on Windows.
Obviously you have the runtime system libraries in opam var ocaml:lib (I wish upstream would actually install a pkg-config file for them to streamline this workflow).
So I guess it’s just a matter of installing your C libraries in your package prefix opam var $PKG:lib and the corresponding pkg-config file in $(opam var lib)/pkgconfig.
I think the opam package lbfgs from Christophe Troestler vendors a C library
for maximum portability of the package.
May it inspire you and the force be with you.
Another example is Luv, which vendors libuv completely and installs it whenever you install Luv. Luv then builds against the vendored libuv, so you don’t have to maintain a system installation, although it can also be told to build against an external libuv.