Open mobileink opened 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.
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.
Namespace support inescapably involves a circular dependency. On the one hand, submodules must depend on the ns module for two things:
-open
the namespace moduleOn 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 ofocaml_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:
. But this is not a requirement. We can give the submodule file any name we please, so long as the alias statement points to it. In particular, we can use the package name to construct a prefix for the submodule filename. So if foo.ml and bar.ml are in package
//a/b/c, we can rename bar.ml to
ABCBar.mland alias it thusly:
module Bar = ABCBar. In other words, there is no necessary relation between submodule name paths (e.g.
Foo.Bar) and filesystem names (
Foo.Barmaps to
ABC__Bar`).submodules
attribute of ruleocaml_ns
to notify submodules that they are being namespaced. Transition functions set build settings, which are in effect global variables. When a transition function on an attribute sets a build setting, it converts it to a kind of local variable; the setting becomes visible only to the transitive dependency graph rooted at the attribute. So theocaml_ns
instance will assign a value to build setting@ocaml//ns
, and the submodules (ocaml_module
instances) will read it to determine whether or not they are being used as submodules. If so, they will construct their filenames using their package names as a prefixes, as noted above.-open
it. The proposal - and I'm not yet sure this will work - is to have the transition function compile the ns module and pass it as the value of@ocaml//ns
.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 ofocaml_ns
, write a source file containing the necessary aliases, compile it, and pass it along as the value of@ocaml//ns
.