Conversation
|
It is great that you tackle this problem (I'm currently trying to convert Frama-C from pack to module-alias) and I appreciate the clean-up in
|
|
I am a bit worried by all this. There were interesting proposals to add namespaces in the language, that have been rejected in favor of the "minor modifications" required by module aliases to have something equivalent to namespaces. Now, you propose to add 4 different options to ocamldep. For me, it questions the "simplificity" of module aliases as a replacement for namespaces. |
|
@bobot: For the prefixing, being explicit seems indeed better. To have the full power, these should actually be file paths, so that there is no ambiguity. I think I'll have to rewrite most of that part. Fabrice is right at least on one point: it would be simpler to connect the prefixing to the directory hierarchy, like in Java. The interesting thing is that it could be done somehow in ocamldep alone (ocamlc only sees already prefixed names). Could be a good next step. |
|
We use It seems that the changes here are aimed at supporting using If we want people to use A more usable solution would be some kind of |
This is certainly OT. But for me module aliases have completely failed at solving the namespace problem. Even if you use them as a namespacing mechanism you still pollute the toplevel namespace, hence you still have to prefix your sources with ad-hoc prefixes and worse you actually have to expose these |
Still OT, but I agree, for a different reason: such "namespaces" are closed. You can't add more things in it. The fact that this is a problem is demonstrated by libraries such as |
|
@lpw25 -modules doesn't give you enough information if you are compiling more than one namespace together. That's one of the reason #146 have been created. But I'm not sure that it is even possible to fix without additional information about the namespace since after the opening of two namespaces you don't know from which the modules used after come. So at the the additions specifically for makefiles are not so big. |
|
I am not sure this is related to ocamldep, but just a clarification: @Drup Module aliases let you extend namespaces, but only at the granularity of modules, by creating new views. I think there is nothing you cannot do, but this is not a fine grain namespace mechanism. There is a limit on what one can do with one single construct (which doesn't even extend the implementation language!). |
|
@lpw25 Your statement is only correct for using module aliases as a replacement for -pack. And it only works if you use a single map file (precluding getting fine grain dependencies between libraries for instance). Also, my build tool of choice is make, and I have no plan to change that. You're not suggesting to deprecate make support in ocamldep I hope. If there is no really good idea for how to handle prefixing, I may just scrape it, and include only the map file mechanism. Then one can just handle prefixing through symbolic links for make, or copying to different names for ocamlbuild. Would it be useful to also allow the map file to be a cmi, like for #146 ? |
|
Le mercredi, 11 novembre 2015 à 02:07, Jacques Garrigue a écrit :
But then I'm afraid to say that as far as I'm concerned this doesn't really solve any problem and rather — by introducing more names for the same things — only introduces more noise in the system. I'm sure there are many reasons they are how they are now. But my initial naive expectations of them were that we would be able to write in the structuring module Super : module Sub : sig … end = My_sub and then only export super.cmi to the end user, hiding the My_sub.cmi so that they are not visible to the end user and compile the corresponding My_sub.cm{o,x} with some kind of mangling scheme so that their names are made unique in the toplevel name space. But this is only a naive view not rooted in any form or technical or theoretical knowledge. Best, Daniel |
There was demand for precisely that. Be able to add new names, without duplicating.
There is no mangling whatsoever. WYSIWYG. But you can of course do the following: in |
|
Please, it would be really helpful to keep this PR discussion focused the support for module aliases in ocamldep and the build systems using it (which is a non-trivial question). I will only look at it this week-end, and if it has by then degenarated into a fifty-message battlefield on all things namespace it will be much more time-consuming than it should be to review and discuss Jacques' proposal. For the record, there has been a discussion of support for module aliases in ocamlbuild/ocamldep on the caml-list back in January and I proposed a patch for ocamldep that is related: #146 . I am sympathetic to the remark that module aliases fail to be a satisfying solution to the namespace problem both on usability and technical grounds (but it is also the best we could agree on in a long and difficult discussion). Feel free to discuss this, but elsewhere. |
|
@gasche do you have some comment yourself? |
True, but is that a problem? I'm not aware of anyone who wants to use module aliases for anything other than replacing pack. It is not like |
This seems enough to justify a new feature. |
I admit I haven't read the actual patch. How precise is it with respect to calculating module aliases? I assume that any use of functors etc. to create aliases will fail since they require type information. |
This is not a problem, since you cannot create an alias of a functor |
|
I have removed the -oprefix and -no-prefix options. |
|
How are the error messages located in |
I was not thinking of that. |
|
I spent some time this morning reviewing the proposed change. I don't have a detailed understanding of the implementation (I think some points could be clarified once we agree on the overall design), but I think that it is rather complementary from my #146 design (ocamldep -paths), and the current PR discussion helped clarify the use-cases and overall context of the proposal. Below is a discussion and comparison of the current state and two patches, and some personal intuitions on where we could decide to go next. Internal representations and output representations.What is ocamldep about? ocamldep computes an internal representation of the dependency information of a module, and produces one of several output representations that are meant to be used by consumer willing to access an internal representation. Internal representations: the current internal representation is a set of free access module names (that occur as the first component of the module paths in a program). In my patch proposal, the internal representation is extended to be a set of free accessed module paths. In Jacques' patch, the internal representation adds to the set of free accessed module names a structured object with a non-trivial tree structure, that he calls the "module resolution map", allowing to resolve module aliases (seen so far in the module or its environment) even if they are at the leaves of a long module path. Output representations: the current output representations are the Makefile format, ready for consumption by Module binding structureLet me remark that there would exist a most general internal representation, of which all other representations are approximations. It is the module binding structure (in short, binding structure), of the program, which is an erasure of the parsed AST to retain only the structure of module operations. For example, the module binding structure of is something that can be represented as While ocamldep has traditionally been a very coarse approximation of this binding structure, Jacques' patch is going sensibly farther in this direction. On user interfacesModule aliases are difficult to support without complexifying the interface, because providing a reasonable approximation of dependencies requires more information about the current compilation environment (the modules we will be compiling against and, crucially, the module aliases they export) than previously. Ocamldep has always performed a vulgar approximation, but it could get away with it, and doing more complex things with module names makes us more demanding. I have seen or heard criticism of the complexity of the various flags added by Jacques in this PR, both here in the comments and in other conversations. It is important to understand that there are, in general, two approaches to a user interface in reaction to this need for external information: [richer output]: produce a more general output that is closer to the true binding structure, and lets post-processing tool compute a better approximation if they are given more information on the compilation environment (for example, ocamlbuild could know about specific [richer inputs]: give more information to ocamldep itself about the compilation environment, so that he can perform the refined approximation internally, and directly return better output representations in the same format as before. My patch was going the [richer output] way. Jacques is going the [richer inputs] way, with the As far as I can tell, the requirement that ocamldep keeps supporting Makefile users is fair and justified, and we should try to respect it in further evolution of the tools. Leo says "this is too complex, let's put the complexity in ocamlbuild instead", but ocamlbuild users will not pay for ocamldep's complexity anyway, and Makefile users may not have the luxury to avoid it. Going forwardI like Jacques' proposed design. Given the constraints to have a working Makefile output, I don't see how to do better, and in fact it is quite simple. I don't understand the details of the Re. the status of
If we want to have nice ocamlbuild support on top of Jacques work, we need to introduce a new output representation that reveals the internal representation in a nicely parseable way. One option would be to have In the future, we should also think of an output representation giving the full module binding structure, to experiment with pixel-perfect dependency computation in OCaml. |
That is not what I am saying. I am saying that the complexity of the "-oprefix" stuff is irrelevant to tools such as ocamlbuild which use the "-modules" argument, whilst the complexity of the "-map" stuff is not needed for the only use case I am aware of: replacing "-pack". The "-oprefix" stuff is gone now anyway so we can ignore that bit. I have warmed slightly to the "-map" and "-no-alias-deps" options. However, I think we should be clearer about what problem they actually solve. There is in fact no issue with using ocamlc's "-no-alias-deps" option with ocamldep -- it continues to give a conservative approximation of the dependencies which is correct and sufficient for a correct compilation order. The problem comes from two related options:
Turning off warning 49 gives ocamldep problems as it will over-approximate the dependencies and produce dependency cycles. Using the "-o" option gives ocamldep problems when producing makefile output because it gets the names of the ".mli" files wrong (but does not cause any problems if you are using "-modules"). The reason to use "-o" is so that you can have short source file names whilst still having long (and so more likely to be unique) module names. The reason to turn off warning 49 is to create a "map" module that aliases the short names to the long names, which can be used (via "-open") to keep all references between the modules using the short names. This allows you to keep your source files looking just like they do when using "-pack" whilst actually using module aliases. When compiling using the approach just described you do not need to process the "map" module with ocamldep since it is known to have no dependencies (and is probably automatically generated by the build system). Meanwhile ocamldep with "-modules" still produces correct output for the rest of the modules. Without "-modules" the output is not quite correct because it uses the short module names for the names of the .cmi and .cmo files. The "-map" and "-no-alias-deps" options aim to allow other (as yet unspecified) approaches based on allowing user-written "map" modules, which -- as with the "map" files in the approach above -- are to be compiled with warning 49 off and used via "-open" to provide some aliases to other modules. The "-no-alias-deps" option is used on the map module to avoid creating unnecessary dependencies. The "-map" option is used on the modules using the map to add additional dependencies which are needed to replace some of those taken away by "-no-alias-deps". It is still not clear to me what the practical use case for these two options is, but I agree that they at least make sense and are not a total hack. I would prefer them to have names that better reflect what they do -- in particular I think that "-no-alias-deps" is not an accurate name, perhaps "-for-map" would be better. I also think that their behaviour should match each other precisely -- "-no-alias-deps" should only remove aliases which will be correctly interpreted by the "-map" option. |
|
Leo's understanding is mostly right, but
Concerning the |
|
My question: for map |
|
@bobzhang: I think this is irrelevant. ocamldep is about computing dependencies for OCaml programs, so it parses OCaml code. The code which handles map files is exactly the same as the code which computes dependencies for normal files. |
|
I think the need to prefix the file using copy/link just for ocamldep is a lot too complicated. For Frama-c we can't switch from pack to module alias with this problem. We should be able in the I propose to reduce the amount of options to give by using the usual convention to separate files into directories: only one boolean options [edited for rephrasing the definition of the option] |
|
@bobot: For the -map-directories option, I don't think it should go into ocamldep. In general, there may be ways to make things simpler for conventional cases, but I don't think this should go into ocamldep, as this is not related to the language itself. It would be better to write a wrapper that calls ocamldep with the right options. |
|
Some further thought about -o used to rename the output. This was introduced in 4.02 to ease the transition, and it appears that Jane Street could use it successfully. However, I don't think this is a robust approach: requiring all tools to support it would be a pain (ocamlbrowser, ocamldoc, etc...) |
|
We have around one month to be in time for the feature freeze of 4.03. I would support a first patch series that does not handle the (This is not to say that @bobot 's point that My understanding is that Jacques' current proposal is such a proposal. Besides building better ocamlbuild support on top of it, I would like to better understand the internal details of the implementation (I think Jacques' current code is a bit too terse and more comments would help; his comments in the discussion above are already very helpful). If I find time to do a deeper code review I will try to contribute such clarification comments or maybe propose surface changes. This would also be helpful towards an output mode exporting the richer reprensation for other build system support.
If the |
|
OK, I hope we can converge. Concerning output-renaming, I've thought about it a bit more, and my conclusion is that if we add something, this should be something easily handled by all source handling tools (ocamldoc, ocamlbrowser, ocamlbuild, ...), and maybe even the compilers. There would be no extra option to read it: by default |
|
Did you read my argument for ocaml_srcmap ? Honestly, passing an extra argument might be an option for ocamldep (and it would still add complexity), but it is completely unreasonable for other tools. |
|
I would of course gladly accept there suggestion that it is urgent to do nothing. |
|
Indeed, I think that merging what you already have, and then trying to support this in
If the alternative is ugly implicit state, I would rather have nothing at all. |
|
Other people may have other opinions. In particular people working on large codebases. That's why I'm asking the question here. For ocamlbuild, I have never used it, and cannot understand a configuration file, so that's going to be hard... |
|
I think Frama-C and all the external plugins can be qualified of large code base. We are not migrating from pack (that have their own problems) to module alias if we have to prefix manually all the files with the name of the plugin. So we need renaming. However even if it is very needed, for us, it is not urgent enough for doing something that we will regret later. About
We already need to give a lot of options to ocamldoc (at least all the |
|
At Jane Street we already have our own approach to these issues, so the renaming features are not urgent for us. I think doing nothing for now is probably the best option. |
|
@garrigue I think an earlier question of mine has been skipped over in this discussion, and I think it should be resolved before merging:
|
|
@bobot This may be more important for ocamlbrowser than ocamldoc, because for ocamlbrowser you just give a list of directories. Merlin also could be an example. In general, if object files use names different from their source file, in a sane ecosystem there should be a stable way to map between them, without having to point to an explicit file. By the way, my use of a different format for the file was just pointing that its semantics is different from an ocaml file, but it could clearly use the same syntax. The difference in semantics is that an ocaml file can also express more complex namespace constructions, such as nesting, so there is no reason the source map and the module map shall be identical. @lpw25 I thought the renaming from |
|
I think it is not a problem for merlin,since it uses the compiler module resolution machinery and reads only |
Maybe we could store both a long/internal name and a short/external name in OCaml users are demanding more complex compilation environments (by compilation environments I mean the mapping from module paths to compilation units). If they want to use these richer features, they need to give more information to their tools. We should make it easy to give more informations, rather than trying to hack global conventions to pretend that this demanded sophistication do not exist -- or if we decide to do that, we could at least choose a sensible convention such as following the filesystem hierarchy, instead of a hastily-baked ad-hoc |
I can confirm that codoc (formally opam-doc) only reads .cmi and .cmt(i) files. |
Sorry, my comment was not clear. It was referring to the ocamldep option formally known as The concern is about whether dependencies removed by I'm assuming that it is possible for a module |
They will. As for aliases appearing in an unexpected way, without being detected, the only way I would see it happening is through module types, as they are not tracked explicitly. I.e., the idiom of, in an mli map, first writing a module type, and then including it, is not supported at this point. But it would have to be contrived (with module types coming from another file), because aliases in a module type declaration are added as immediate dependencies. For simple maps, including nesting and inclusion, I think that the current approach is more than sufficient. |
|
@gasche I completely agree with you that there is no hurry to work on file name mapping at this point. But I completely disagree on all the rest. We can restart this discussion later. |
|
@garrigue Thanks that answers my question perfectly. I support merging the |
|
(So do I.) |
06ed44b to
381328e
Compare
Add module alias support to ocamldep, and update documentation.
|
I think this is broken. Maybe the CI should test ocamldep? $ ocamldep.opt -modules -impl r.ml |
|
It does. And I just checked now that doing |
|
Sorry, there is indeed a problem with ocamldep.opt. Very strange, as this is just the native code version of the same program. |
|
The problem doesn't exist in bytecode, and goes away if you don't use |
|
The previous comment is not very clear. The discrepancy comes from the fact that ocamldep is built using boot/ocamlc (old compiler) while the native code version uses ../ocamlopt (new compiler). |
|
I will investigate further. I think the compiler I used had been bootstrapped. |
|
jdimino spotted this. It's an error in the ocamldep patch; it was parsing the .ml file as if it were an .mli. See commit f3ba667. |
|
Sorry. Thank you. (Looks like I was in a directory where ocamldep had not been recompiled... gah) |
(This description was edited. Some comments may refer to parts that have disappeared, such as support for prefixing through -oprefix / -no-prefix)
This pull request adds module alias support to ocamldep.
The idea is not necessarily to support everything, but to allow users to build their libraries using -no-alias-deps without too much hassle.
There are 2 new options added to ocamldep:
-map name.{ml,mli}Parse
name.mlorname.mliand build a dependency map used by other files, if they open the module Name.-no-alias-depsMatch the behavior of ocamlc's -no-alias-deps, i.e. do not add dependencies for module aliases when they are not accessed. The behavior should be conservative for interface files (all dependencies are detected), but may miss dependencies for implementation files if the interface coerces some of the exported module aliases.This is only useful if the file contains module aliases. In practice, using it only if you want to compute the dependencies of a map file seems sufficient.
There is no support for prefixing: one is supposed to have the source files name match the compiled version, using copying or symbolic links.
There is a small example in
testsuite/tests/no-alias-deps2.In particular, you can see there that a standard way to use it would be
This means that the bindings in the file
lib.mlare to be used as a map, and this map is enabled in all files by-open Lib(otherwise one would have to addopen Libmanually to each file where it is needed).Note that the map file is not a special file. For instance in the above example, the contents are:
Which demonstrates than
includeworks properly.Of course, one can alternatively write a
lib.mli, where the contents would be:If you have both a
lib.mland alib.mli, you may want to generate dependencies for them. In that case, you should write:which avoids creating a circular dependency for the cmx's.