Skip to content

Commit 18e211f

Browse files
committed
Document some filesystem conventions of WIT
I've been meaning to write these down for awhile, and now I've gotten around to them! The goal is to outline some preexisting conventions for specifying WIT to bindings generators in a location that isn't buried in any implementation but instead in a shared location that can be iterated on as well.
1 parent 31256b8 commit 18e211f

1 file changed

Lines changed: 142 additions & 0 deletions

File tree

design/mvp/WIT.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,148 @@ same syntax with the same restrictions as the first, but prefixed with '%':
799799

800800
[kebab-case]: https://en.wikipedia.org/wiki/Letter_case#Kebab_case
801801

802+
# Filesystem structure
803+
804+
WIT supports multiple `package`s and the ability to define a single package
805+
across many files, and this section is intended to set a number of conventions
806+
for WIT-processing tooling to conform to.
807+
808+
This won't go into the specific details of any one particular tool and you
809+
should consult tooling-specific documentation for more detailed information
810+
about exactly how to configure a WIT parser. This will, however use the Rust
811+
guest `wit-bindgen` crate as an example to have a concrete example to link to,
812+
but this is intended to be translatable to other examples and bindings
813+
generators as well.
814+
815+
## Specifying a "Root Package"
816+
817+
To start out when processing WIT a package needs to be conceptually considered
818+
the "root package". This is used down below in `world` selection and the
819+
conventional processing of WIT is intended to currently generally have a package
820+
as the "default" for lookups. A root package is specified via a path on the
821+
filesystem to either a file or directory. Lookup of dependencies and of this
822+
package happen differently depending if it's a file or directory.
823+
824+
### Root Package: A File
825+
826+
When the root package is a single file then it means that file contains all WIT
827+
that is going to be parsed. No further file discovery on the filesystem will
828+
happen and after the file is read then no more filesystem interaction will be
829+
happening.
830+
831+
```rust
832+
wit_bindgen::generate!("./my.wit");
833+
```
834+
835+
To be a valid WIT file the file being parsed must have a leading `package ...;`
836+
statement meaning that it's now the "root package". Dependencies of this package
837+
must be specified inline with `package ... { ... }` blocks when using this
838+
format.
839+
840+
Some tooling may support the ability to load multiple "roots" which means that
841+
the final root is used for `world` selection and the other roots are used to
842+
load dependencies. This can be used when you don't necessarily have full control
843+
over filesystem structure and need to load dependencies from a possibly
844+
non-standard location.
845+
846+
```rust
847+
// here `deps.wit` will be available when parsing `my.wit` for dependency
848+
// resolution.
849+
wit_bindgen::generate!({
850+
path: ["./deps.wit", "./my.wit"],
851+
});
852+
```
853+
854+
Note that specifying a file is not the only option for organizing WIT bindings.
855+
Below can be a more maintainable strategy with WIT files separate from each
856+
other. A single file can be useful when tooling manages WIT for you, but
857+
handwritten WIT may often prefer to use a directory.
858+
859+
### Root Package: A Directory
860+
861+
When the root package is a directory then it means the filesystem structure of
862+
that directory will be traversed to look for WIT to load. A directory not only
863+
supports splitting a single package across multiple files on the filesystem but
864+
it also enables having all dependencies located within the directory as well.
865+
866+
```rust
867+
wit_bindgen::generate!("./wit");
868+
```
869+
870+
This example will parse the directory `./wit` and look for WIT files. The
871+
parsing process first looks at all `*.wit` files inside the directory itself.
872+
This collection of `*.wit` files will be combined together to form the "root
873+
package". No other files will be considered for the "root package". For example
874+
though you could have this filesystem structure.
875+
876+
```rust
877+
wit/
878+
types.wit
879+
world.wit
880+
my-interface.wit
881+
```
882+
883+
Here `types.wit`, `world.wit`, and `my-interface.wit` would all be parsed
884+
together as a single package.
885+
886+
Dependencies in the directory format of the filesystem are specified in a `deps`
887+
folder within the root folder. Above for example dependencies would be specified
888+
in `wit/deps`. Dependencies are specified in a flat format where each dependency
889+
may itself be a file or a directory, but directories do not have recursive
890+
`deps` folders. The name of files/folders used for organization within a
891+
directory are not used during parsing and are purely meant for human-read
892+
organization.
893+
894+
For example we can extend our above `wit/` folder like so:
895+
896+
```rust
897+
wit/
898+
types.wit
899+
world.wit
900+
my-interface.wit
901+
902+
deps/
903+
my-dependency.wit
904+
wasi:clocks/
905+
types.wit
906+
world.wit
907+
wasi:clocks@0.3.0-pre/
908+
types.wit
909+
world.wit
910+
```
911+
912+
The name `my-dependency` in `my-dependency.wit`, as well as `wasi:clocks` in
913+
`wasi:clocks/`, is arbitrary. This distinguishes one dependency from another but
914+
is only used for uniqueness on the filesystem.
915+
916+
All dependencies in `deps` will be loaded and processed in topological order.
917+
The `my-dependency.wit` file may, for example, depend on `wasi:clocks/`.
918+
Additionally `my-dependency.wit` may have its own inline `package .. { ... }`
919+
blocks too which define packages available for dependency resolution. Any
920+
package which is duplicated across dependencies must have the same contents.
921+
922+
## Specifying a World
923+
924+
The primary unit of bindings generation for WIT tooling is a `world` which means
925+
that various phases of the process must take a `world` input. For example when
926+
generating guest bindings within a language you'll be specifying a `world` as
927+
the unit of bindings generation. WIT tooling should follow these conventions for
928+
selecting a world:
929+
930+
* Inputs to world selection are a "root package" (what was parsed from the WIT
931+
path specified) as well as an optional world string.
932+
* If the world string is not present, then the root package must have a single
933+
world in it. If so that world is used for bindings generation.
934+
* If the world string is a WIT identifier, then it specifies the name of a world
935+
in the root package to use for bindings generation.
936+
* If the world string is a WIT path, such as `a:b/c`, then that is a
937+
fully-qualified path which can be used to select a world in the dependencies
938+
for bindings generation as well.
939+
940+
If the above heuristics all fail then bindings generation fails and a different
941+
combination of arguments must be passed to select a world for bindings
942+
generation.
943+
802944
# Lexical structure
803945
[lexical-structure]: #lexical-structure
804946

0 commit comments

Comments
 (0)