Every Mica compilation is described by two kinds of information, and telling them apart is the whole idea of this page.
The facts belong to the source tree itself: which files form the program, which string encoding they are written against, which libraries they consume. Move the tree to another machine and the facts travel with it — they were never about the machine.
The choices belong to one invocation: which architecture to target, which optimization tier, where the build artifacts go. The same tree builds for ARM64 at the debug tier this minute and for x86-64 fully optimized the next, and no fact changed.
Flags are the right home for choices. The project file is the home for facts.
A few lines
A mica.project sits beside the sources it describes. This is a typical
shape — a program consuming the
starter repository’s
Utilities library through the contract its build emits:
{
"version": "1.0.0",
"sources": ["Consumer.mica"],
"contracts": ["../build/Utilities"]
}Five kinds of entry. version is the one every project file states; the
other four are written where they have something to say:
sources— the files of the compilation, relative to the project file. A program built from several units lists them all.encoding—"utf-32"(the default) or"utf-8". This is a fact, not a flag: the sources are written against one encoding — their format strings say%lsor%saccordingly — so the file that owns the sources owns the encoding.contracts— the libraries this program consumes, each named by the location of the contract the compiler emitted when that library was built. Several entries mean several libraries, each imported through its own contract.version— the version of the program or library the sources are, as Semantic Versioning writes it:"2.0.0", or"2.1.0-rc.1"before a release. Every build from a project file states one, and so does every library. A program compiled from its sources with flags alone, or run as a script, is built without one.requires— the versions of the libraries it is built against that the program or library accepts, by library name:{"sqlite": "2.0"}.
The editor reads it — that is the point
Open any source file in VS Code and the Mica language server looks for a
mica.project, walking up from the file’s directory — the familiar
module-file convention. No settings, no configuration. Whatever it finds governs the
analysis: the companion sources are enrolled, the encoding is applied, the
contracts are loaded.
The consequence is simple to state: the diagnostics in your editor are the
diagnostics of your build. A program importing a library shows no false
namespace not found on lines that link fine. A utf-8 source is checked
under utf-8 rules while you type. Every example in the starter repository
carries its project file, so this is the behavior you meet from the first
git clone.
The file itself is checked while you type it, too. In VS Code, a
mica.project offers its five keys with what each one means, completes the
encodings, and underlines a key the compiler would refuse, or a version it
would not read, with the compiler’s own sentence. The rules come from the
compiler, which generates the file’s
JSON Schema
from its own reader, so any editor that reads JSON Schema can check a project
file the same way.
The build reads the same file
--project points the compiler at a project file or the directory holding
one, here from the example’s own directory:
cd mica-container/examples/MicaCallsLinux
mica --compile --project . --build ../build/MicaCallsLinux --platform linux,arm64Compiling source '.../MicaCallsLinux.mica' to assembly code for platform 'linux arm64 AArch64_V8 utf-8 AArch64_ELF_GNU_AAPCS64'Look at what happened there. The command named no source files — the project
supplied them. And --platform linux,arm64 named no encoding — the project’s
"encoding": "utf-8" completed it, and the platform line of the compile
confirms it.
The precedence rule is one sentence: explicit flags override project
entries, fact by fact. Pass --source and it wins over the project’s
sources; the other entries still apply. The file describes; the invocation
decides.
A library’s version
A library states its version once, in its own project file, and a library is linked only under one; a build that names no project file is answered with
A library as output binary states its version as "version" in the mica.project it is built from: linking abortedThe sqlite library in the starter repository says "version": "2.0.0", and
its build carries the version into the contract it emits:
Emitted interop contract '../build/sqlite/mica.external' for library 'sqlite' 2.0.0Every program built against that contract names the library with its version,
in its build and in its manifest, which
mica --inspect prints without starting the program:
Using library 'sqlite' 2.0.0
Using library 'sqlite3' 3.46.1"libraries":[{"name":"sqlite","language":"mica","version":"2.0.0"},{"name":"sqlite3","language":"c","version":"3.46.1"}]In the editor, the hover over a name the library brings ends with the same
line, Mica library sqlite 2.0.0. The C library beneath it is named with the
version the machine holds: its contract names the sqlite3 package, and the
build asks the machine’s pkg-config, so another machine names its own
version. A C library whose contract names no package and states no version is
named without one.
The versions a program accepts
A program states which versions of a library it accepts in its own project
file, under requires, and reads a requirement the way Cargo and npm read
one: "2.0" accepts every version from 2.0.0 up to, not including, 3.0.0 —
the releases Semantic Versioning promises compatible. Below 1.0.0 the
leftmost number that is not zero is the one a compatible release keeps, so
"0.2" accepts the 0.2 releases and "0.0.3" accepts 0.0.3 alone. A
pre-release is accepted only by a requirement that names a pre-release of
the same three numbers.
{
"sources": ["demo.mica"],
"contracts": ["../build/sqlite"],
"version": "1.0.0",
"requires": {"sqlite": "2.0"}
}The build checks every library its contracts bring against the requirement before it reads a source against them, and a library outside it answers with the range beside the version the contract states:
interop error 562: the project requires the library 'sqlite' at '2.0', which accepts the versions from 2.0.0 up to 3.0.0, and the library is at version '1.4.0'The editor shows the same sentence at the top of the file, and a script run
with mica --run beside the project answers it too.
The contract and the archive are checked against each other as well. A library’s build states its version and the digest of its interface in the archive’s manifest and in the contract it emits, and a program’s link compares them with the contract the program was built against, so a library rebuilt beside a program that still reads the old contract answers by name instead of linking:
Failed to link: the archive 'lib/Meter.a' is another build of the library 'Meter' than the contract the program was built against describes: the contract states the interface b9c78ed36ab7, the archive 38b4e6d6c348; rebuild the program against the contract the archive's build emittedTry it
Open examples/MicaCallsLinux/mica.project in the starter repository and
change "utf-8" to "utf-16". The editor reacts first: one error diagnostic
at the top of the file, carrying the message below — the language server
refuses to analyze under a project it cannot honor. Now ask the compiler
directly, from the example’s directory, where the build above ran:
mica --compile --project . --build ../build/MicaCallsLinux --platform linux,arm64project file mica.project: unknown encoding "utf-16" (valid: utf-32, utf-8)A project file that cannot be honored is refused loudly, in the editor and in the build alike — the compiler never falls back to defaults you did not ask for, because building something other than what the file describes would be worse than stopping. Change it back.
When you do not need one
A single file compiled with the default encoding and no libraries needs no
project file at all — examples/Hello would work without one. The file earns
its place the moment any fact departs from the trivial: a second source unit,
a utf-8 surface, a consumed library. The starter repository gives one to
every example anyway, so the editor’s behavior is uniform across the whole
learning path.
Where this is going
A file that both the build and the editor read is also the natural place for a future dependency description — that is the direction the project model is built to grow in, and the announcement article sketches it.
Next
- The shape of a Mica program — part 2 of the series, if you arrived here directly.
- The command line — every flag, including
--projectand the external-contract list. - The starter repository — clone it and every example’s project file is already in place.