OBazl Toolsuite - tools for building OCaml with Bazel

I’ve put a lot of work into seamless OPAM integration, but only in one direction: make it easy to use OPAM resources in a Bazel build program. I have not put much thought into integrating Bazel itself into the OPAM ecosystem. For example publishing a Bazel-enabled package to OPAM. It looks like writing such a conf-bazel package would be pretty easy, but I’m not sure it would do us much good at the moment. What specific use cases do you have in mind?

There are two ways to integrate Bazel and OPAM. One is to automatically generate BUILD.bazel files for OPAM packages. Then Bazel would build everything, eliminating the need for the OPAM engine. This is the strategy followed by rust (tool: cargo_raze, evidently now supplanted by crate_universe) and go (tool: gazelle). Unfortunately a complete solution along these lines is not feasible for OCaml, since source files do not carry enough information to support inference to a build program, and OPAM packages may use a variety of build languages (Dune, Makefiles, OMake, etc.). On the other hand, Dune seems to be the most widely used build engine by a considerable margin, and the Dune language is easy to parse (if not so easy to interpret), so I’m working on a conversion tool that automatically converts Dune files to BUILD.bazel files.

The other strategy is to rely on OPAM to build dependencies and then “import” the built artifacts into Bazel. OBazl defines an opam_import rule for this purpose, and a tool that bazelizes OPAM switches, generating an OBazl ‘coswitch’. The mapping from OPAM package name to Bazel label is straightforward: ‘yojson’ to @yojson//lib/yojson, ‘lwt.unix’ to '@lwt//lib/unix`, etc.

So in practice OBazl supports a hybrid approach. Use Bazel to build your code, but import pre-built OPAM dependencies. To do that you run the opam conversion tool to generate a ‘coswitch’ which defines a local Bazel repo for each OPAM package, and configure your WORKSPACE.bazel to import those repos. Write your BUILD.bazel files using opam labels as above. If your project already uses dune, you can run the dune conversion tool to generate your BUILD.bazel files, which in some cases will need some tweaking, since some Dune stanzas lack sufficient information for conversion, and in others the conversion code needs complicated logic that I haven’t gotten around to writing, or that does not seem worth the bother.

The OPAM “import” conversion tool is fairly stable. It converts the META files in OPAM into BUILD.bazel files, which include dependency information. So when you depend on an opam_import target you get its entire dependency graph.

The Dune migration tool is another matter. Reverse-engineering the Dune language is a non-trivial task, lemme tell ya. The good news is that after what seems like eons of work the end is in sight. I’ve been running it against a semi-random set of projects (js_of_ocaml, ocaml-protoc, some ppx libs, etc.) and working through the quirks inch-by-inch. Rule stanzas are a real PITA, can I just say that? In any case, it looks like I should have an alpha release with documentation and some case studies within a week or so. I hope. At the very least I’ll convert my dev configuration into something usable by others so you can follow along if you want.

Cheers,

Gregg

3 Likes