machdocs
Home GitHub

Project layout

A mach project is a tree of .mach files under a source directory, anchored by a mach.toml manifest at the root. The project's id is the root of every module path the project exposes.

Source files

Source files use the .mach extension. Two conventional entry files name a project's surface:

These names are convention only: the compiler never looks for a function called main. An entry is simply the source file a [bin.*] or [lib.*] artifact names with its entry key; what marks a function as the program's entry point is its exported symbol and signature, covered in Hello world. The artifact table fixes the role - a [bin.*] links an executable, a [lib.*] produces a library. A project may carry both files.

The project root

Every project has a mach.toml at its root. The compiler finds it by walking up from the working directory until one is seen, so any subcommand run inside the tree resolves the same manifest.

[project]
id      = "myproj"      # root of every module path
version = "0.1.0"
src     = "src"         # source dir (default "src")

[target.linux]
isa = "x86_64"
os  = "linux"
abi = "sysv64"

[bin.app]
entry = "main.mach"   # executable entry, relative to src

Only id and version are required. src (default "src") is where module paths resolve; vendored dependencies live under dep (default "dep"). The full schema - targets, profiles, artifacts, dependencies, output templates - lives on the Manifest page.

Files map to module paths

The path separator is .. A file at <src>/foo/bar.mach in a project with id = "myproj" is reachable as myproj.foo.bar.

myproj/
  mach.toml
  src/
    main.mach          # myproj.main
    foo/
      bar.mach         # myproj.foo.bar

There is no this. self-prefix. Within a project, modules always reference each other by their full project-rooted path, so every reference is syntactically uniform no matter where it appears.

Surface and split modules

A file foo.mach may co-exist with a directory foo/. The file is the surface module - the public face of foo. The directory holds split implementations that the surface loads and re-exports.

src/
  foo.mach             # surface: myproj.foo
  foo/
    a.mach             # split: myproj.foo.a
    b.mach             # split: myproj.foo.b

The surface loads each split with use and re-exports its public symbols with fwd. Consumers use myproj.foo and reach symbols through the surface; they never name the split files directly.

use myproj.foo.a;
fwd a.X;             # re-export a's public symbol through the surface

Topical splits

Organize a large module by topic. Every split is forwarded unconditionally, keeping one logical module spread across readable files.

Multiplatform splits

Keep one implementation per target and select it with $if on $mach.build.os or $mach.build.arch, so the surface forwards only the split that matches the build.

Importing a project by id

A one-segment use/fwd path equal to a resolvable project id - a dependency's id or the current project's own - resolves to that project's declared [project].module. A library that sets module = "glfw.mach" is imported by its id instead of by the full path to its surface file.

# in glfw's manifest
[project]
id     = "glfw"
module = "glfw.mach"   # the surface a bare use glfw binds
# in a consumer
use glfw;             # binds glfw's [project].module
Note

A bare import of a project that declares no module is a resolution error naming the fix: import a full path, or add a module key. A declared module that names no file is a manifest error at build start. Longer paths are unaffected, so this is purely additive.

See also