Multi Files

Multi files end in .wants. Unlike a unit file, a multi file declares a list of Targets, and each Target must declare the paths it is allowed to write.

A multi file is a Spore body with a single export, .targets:

build = (#import "want:build")
paths = (#import "want:build/paths")

.targets = [
  {
    .input = [
      (paths.unit "./input.txt")
    ]
    .output = [
      (paths.suffix ".out.txt")
    ]
    .do = \(ctx: build.Ctx) build.FS {
        // generate a bunch of files ending in ".out.txt"
    }
  }
]
  • .input is a list of PathSets the target reads, exactly as for a unit file.
  • .output is a list of PathSets the target may write to. The FS returned from do is filtered through this set: writing to an undeclared path fails the build.
  • .do is the proc that produces the build, the same as for a unit file.

Rooting

Every target in a multi file is rooted at the parent directory of the .wants file. The FS returned by do is positioned there, and .output is interpreted there too.

A protobuf.wants file at the root of a module produces files at the module root. If it were at a/b/c/protobuf.wants, and its do returned a filesystem containing messages.pb.go and api.pb.go, the resulting output would be:

a/b/c/messages.pb.go
a/b/c/api.pb.go

The .output declaration does not need to repeat the prefix. Either of these would accept the files above:

.output = [
  (paths.unit "messages.pb.go")
  (paths.unit "api.pb.go")
]

or, more flexibly, allowing the names to change as long as they keep the suffix:

.output = [
  (paths.suffix ".pb.go")
]

Why declare outputs?

A unit file's output path is fixed by its name, so conflicts with other targets are impossible. A multi file can write anywhere under its directory, so declaring .output lets Want check, before anything runs, that no two targets claim overlapping outputs, and that a target only writes where it said it would.