Skip to content

Commit 900b821

Browse files
authored
Document some filesystem conventions of WIT (#507)
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 900b821

File tree

1 file changed

+142
-0
lines changed

1 file changed

+142
-0
lines changed

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)