obazl / rules_ocaml

A Bazel Language Support Package for OCaml
https://obazl.github.io/docs_obazl
Apache License 2.0
32 stars 7 forks source link

ocaml_ns version 2 #6

Open mobileink opened 3 years ago

mobileink commented 3 years ago

Namespace support inescapably involves a circular dependency. On the one hand, submodules must depend on the ns module for two things:

On the other hand, the ns module depends on the submodules, since it needs to know which modules to alias.

Version 1 resolves this by having the submodules depend on the ns module via the ns attribute of ocaml_module, and by having the ns module depend on the submodule source files rather than the submodule build targets. This works, but it's inelegant and error prone, since the build developer must ensure the two sets of deps match up.

The goal is to have the ns module depend on the submodule targets, period. That way clients can just depend on the ns, which would function as an aggregate, like a library or archive. Currently the ns module and submodules need to be bundled into a library or archive.

The proposal is to use a transition function together with a label-valued build setting to support this. Sketch:

I think this will work, because the dependency of the ns module on its submodules is actually a pseudo-dependency. The ns module does not depend on the compiled submodules, it only depends on their names. So it should be possible for the transition function to obtain those names from the submodules attribute of ocaml_ns, write a source file containing the necessary aliases, compile it, and pass it along as the value of @ocaml//ns.

mobileink commented 3 years ago

Another possibility: always use the package name as the namespace prefix. That way both the ocaml_ns and the submodules know what the prefix is, so long as they are in the same package. Actually even if they are in different packages it would work, since the ocaml_ns would be able to extract the package name for all its deps.

The catch is that the submodules need to know that they should use the ns prefix. Simplest way to do this is to make the ns attribute a boolean. The drawback with this is just the need to add this attrib to each submodule. The alternative is to use a transition function to set the ns value.

mobileink commented 3 years ago

The main unresolved problem is how to make the compiled ns module available to the submodules, who need it for compilation. We may be able to use the transition function for this as described above. Not sure how efficient that is. Another possibility is to have each submodule have a hidden dependency on a hidden package-global ns module, whose only purpose is to support submodule compilation. It would contain an alias statement for every module in the package. But I'm not sure "hidden ns module" is even possible.

Maybe a hidden attribute whose default value is 'glob(["*.ml"])' ? If ns is True, compile the helper ns module. No, then each submod would compile it. We need them all to depend on one target. An ocaml_ns_helper rule?

Best solution would be to put the alias statments on the compiler command line.