12.4. Module resolution
A Morloc program is assembled from modules: its own source files and
modules installed into the Morloc state. This section specifies how the
compiler finds the file an import names, how a module is identified and
installed, how versions are pinned, and how a module declares the foreign
packages it needs. The install-string syntax is given in
Installing modules.
12.4.1. Finding a module
An import names a module by dotted path. A leading dot makes it local:
import .foo.bar is looked up only under the project root, the directory
of the file being compiled, as foo/bar.loc and then foo/bar/main.loc. A
program read from standard input has no project root and may not use local
imports, and neither may an eval expression (Serving).
Without the leading dot the import is bare, and two lists of candidates
are built. The system list searches the installed modules of the active
plane (a named namespace of installed modules; default unless
configured), its core subdirectory (morloclib) first:
-
<plane>/morloclib/foo/bar/main.loc -
<plane>/morloclib/foo/bar.loc -
<plane>/foo/bar.loc -
<plane>/foo/bar/main.loc -
the same two forms directly under the module tree, outside any plane
The local list is the two local forms above. A bare import that matches
only a system candidate takes the first one. One that matches only a local
candidate is accepted with a warning to write import .foo.bar. One that
matches both is an error naming both files, because the meaning of the
program would otherwise depend on what happens to be installed. One that
matches nothing is an error listing every path tried and suggesting
morloc install.
A module named owner/name searches only the plane: owner/name/main.loc,
owner/name.loc, then name/main.loc and name.loc.
The last three components of a matched path must have the exact spelling of the import, so a module resolves the same way on case-insensitive and case-sensitive file systems.
12.4.2. Identity
A module is a directory. Its entry file is main.loc, or its only .loc
file. The entry file declares exactly one named module, and that name must
equal the directory’s name (for an installed module, the repository’s
name). A name is ASCII letters, digits and -, beginning with a letter or
digit.
A module’s metadata is the package.yaml beside its entry file. The fields
the ecosystem reads:
| Field | Meaning |
|---|---|
|
The module’s own version. |
|
The range of compiler versions the module accepts. A compiler outside it refuses to load the module. |
|
Pins for imported modules, each a name and a git hash. |
|
Foreign packages, each with a version constraint and a source (Dependencies ( |
|
Packages kept inside the project tree (Local packages ( |
|
Constraints on the language runtimes themselves. |
|
System libraries. |
|
Files copied where foreign code can include or import them (Exposing native resources). |
|
A script run after the module is installed. |
12.4.3. Installing
morloc install fetches a module into <plane>/<name> in the Morloc state.
Each install:
-
takes a lock for that module name, so two installs of one module never interleave;
-
fetches into a temporary directory beside the destination;
-
checks that the module’s declared name matches and that its
morloc-versionadmits this compiler; -
replaces the previous copy in one rename, so a failed install leaves the old one intact;
-
installs every module it imports that is not already present, the same way;
-
copies its
exposefiles and runs itssetupscript, with the module’s name, version and directory in the environment; -
typechecks it, unless told not to;
-
writes a record of the install: name, version, source and pinned hash.
A module that is already installed is left alone unless the install is
forced. morloc make installs missing imports the same way before it
compiles.
Pins. A pin fixes an imported module to a git hash. Pins come from the
morloc-deps of the modules being installed (a pin closer to the program
wins; two different pins at the same depth are an error) and from snapshot
files in the state, which list name hash pairs for a whole installation.
An installed module whose recorded hash differs from its pin is an error
until it is reinstalled.
12.4.4. Foreign dependencies
The compiler gathers the foreign requirements of a program from every
module it imports, transitively, and writes them beside the manifest as
envspec.json. Constraints on one package from several modules are
combined (all must hold), the C++ standard is the highest any module
asks for, and two modules naming different conda channels for one package
is an error. The file also lists the program’s languages and system
libraries. morloc envspec writes the same document without building. How
the document is solved is specified in Environment solving.