A proposal by Alain Frisch: > Here is my current proposal (not including Jacques' suggestion to > allow using internal names as file names locally): > > > Main ideas and goals > -------------------- > > * Primary goal: Allow several libraries (maybe parts of the same > build tree) to expose modules with the same name from the point of > view of client code. > > * Main idea: Add an intermediate layer of indirection (called > "namespace maps" or "namespaces") between (1) module names that > refer to compilation units, used in source code and (2) concrete > files. > > * Secondary goals: > > > ** Keep the burden on external tools as small as possible, and try > to maintain existing properties of the system, in order to ensure a > smooth transition path for users and tools. > > ** Never force a user to use the new features. > > > Namespace map files > ------------------- > > A namespace map file foo.cmn is a sequence of lines of the form: > > ModuleName: filename > where ModuleName is an uppercase identifier (which defines how a > module is to referenced from a source file) and filename is a > lowercase or uppercase identifier (the real module > name). Typically, filename would include a prefix to identify its > library. > > (Empty lines and lines starting with a #-character are ignored, etc.) > > Conceptually, a line as above tells the compiler that resolving > ModuleName as a toplevel module name should be done by looking for > filename.cmi in the filesystem. > > It is an error if a given .cmn file contains two bindings for the same ModuleName. > > Bindings in .cmn files are not transitive. They map module names > used in source files directly into file names. > > A .cmn file can also be seen as a way to obtain internal ModuleNames from filenames (reverse mapping). > > > Extensions to the source language > --------------------------------- > > Syntactically, a namespace is an uppercase identifiers. > > open namespace Foo (* in structures and signatures *) > > let open namespace Foo in expr (* in expressions *) > > Foo..ModuleName (* head of module paths *) > > > > Behavior of the compiler > ------------------------ > > To interpret a namespace Foo, the compiler looks for a file called > foo.cmn (or Foo.cmn) in the load path (the first matching file is > used). > > Foo..ModuleName is interpreted by looking for a mapping > "ModuleName: filename" in foo.cmn, and the resolution continues > with Filename (without using namespace maps), i.e. the compiler > looks for a file filename.cmi on the load path. "Filename" is > called the external module name corresponding to the local > reference ModuleName. > > The two other constructions bring all the bindings from the .cmn > file into a mapping maintained by the typing environment. This > mapping is used to resolve a toplevel module name not explicitly > qualified with a namespace. > > The internal representation (dumped in .cmi files, and later in > binary dumps of typedtrees) contain the external module name for > toplevel module references. (It could also keep track of the > internal name used in the source file, but interpreting such a name > depend on the context, so it might be better if tools which process > .cmi/binannot files do a reverse mapping themselves, based on > explicit user decisions.) > > > The .annot files produced by the compiler contain external module > names (which correspond directly to filenames). It is the > responsibility of tools which consume .annot files to read .cnm > files (passed to them explicitly) and apply the reverse mapping if > one wants these tools to produce reports with internal names. > > > > Behavior of ocamldep > -------------------- > > A new mode "ocamldep -namespaces" returns the list of namespaces > found in the source file (same spirit as "ocamldep -modules", > i.e. in this mode, ocamldep does not resolve namespace references to > concrete .cmn files). > > In normal "Makefile" mode, ocamldep reads the .cmn files as the > compiler would do (and fails if it cannot find a .cmn file), and > apply them to resolve toplevel module names (or what it believe > are/might be toplevel module names). The external module names are > then translated to files with path (as today). > > "ocamldep -modules" is similar, but it outputs external module names > (after the mapping described in .cmd files) directly. > > Something to be noted is that "ocamldep -modules" now reads other > files than the source file on which it is applied (only if the new > language features are used; and it doesn't need to read or look for > the existence of other files than .cmn files). > > > Impact on build systems > ----------------------- > > Makefiles should not require any significant change. Dependency > scanning is triggered manually, so it is not really necessary to > maintain exact dependencies on .cmn files. > > OMakefile rules could be slightly adapted to know about dependencies > on .cmn files and force these files to be refreshed > (generated/preprocessed/copied around) before calling > "ocamldep -modules". That said, people could probably live some > time without this change, if they use only static .cmn files or > empty the dependency cache manually when these files change. > > ocamlbuild: I'm not familiar enough with this system to comment > seriously on it. I assume it needs to know about all the > dependencies in order to decide what to copy in the dedicated build > directory, and "ocamldep -namespaces" should be useful for it. > > > > Behavior of ocamldoc > -------------------- > > By default, ocamldoc would produce documentation with external module > names all over the place. It is extended to accept .cmn files on its > command-line. These files are used as a reverse mapping from external > names to internal names. (In case when several internal names exist > for the same external name, one can specify for instance that the > first instance is used.) The exact way how internal/external names > are used in the output of ocamldoc is to be decided by the backend. > (For instance, an HTML backend could show the internal name, with the > external name displayed in a tooltip when hovering the reference.)