trident
Dependencies
Declaring local and repository dependencies, renaming a dependency's namespace with as, development-only dependencies, and the rule that you may only use what you declared.
since 0.1.0-alpha.1linux
Description
A dependency is another project that your project uses. You declare it with a [[dep]] table in
trident.toml, and trident finds its sources and hands them to the compiler along with your own.
The compiler sees one program made of all the files; a dependency is simply more source.
[[dep]]
path = "../jsonlib"
as = "Json"
version = "1.0.0"
dev = false
| Key | Meaning |
|---|---|
path |
Where the dependency is. A directory next to your project (a local dependency), or the name of a repository (a repository dependency). Required. |
version |
Required for a repository dependency, optional for a local one. |
as |
A namespace name through which your code reaches the dependency; see below. Optional. |
dev |
true for a dependency only needed during development. Optional; default false. |
Local and repository dependencies
trident decides which kind a path is by looking at it. If it is a relative path to an existing
directory, resolved against the directory of your trident.toml, the dependency is local: that
directory must contain its own trident.toml, and its sources and its own dependencies are gathered
into your build. Any other path, including an absolute path, is the name of a repository such as
github.com/acme/json, and it must have a version; the dependency is fetched from its git
repository at that version tag. Versions, the lock file and the checksum record belong to repository
dependencies and are described in trident.versions-and-integrity.
A path that is meant to be local but does not exist is read as a repository name, so a typo shows
up as the error is not a local directory, so it is treated as a VCS dependency, which requires 'version'.
Using a dependency's code
A dependency declares its code in namespaces, and you bring the namespaces you want into scope with
uses, as with your own code. If the dependency's namespace is called JsonLib, your files write
uses JsonLib;.
The as key gives you a name of your choosing: trident creates a namespace with that name that
brings in everything the dependency declares. With as = "Json" your file can write uses Json;
and call the dependency's functions by their bare names, without knowing what the dependency calls
its own namespaces. A dependency's namespaces can still be named directly.
This program stands for a project and its dependency after trident has gathered both into one
build. The JsonLib namespace is what the dependency's json.lev contributes, and the last
three lines are the project's own main.lev:
What a dependency contributes
namespace JsonLib {
string render(int n) => "{\"n\": ${n}}";
}
uses JsonLib;
console.writeln(render(1));
console.writeln(JsonLib::render(2));
{"n": 1}
{"n": 2}
Development-only dependencies
dev = true marks a dependency that the shipped program does not need, such as a test helper. For a
repository dependency, trident build, run and emit-llvm leave it out entirely, while check
and plan include it. For a local dependency the flag is recorded but every command still includes
it.
You may only use what you declared
A file may uses namespaces from its own project and from the dependencies you declared directly.
Reaching into a dependency of a dependency is a compile error, even though the code is present in the
build. It would make your project depend on something you never declared and cannot control:
error: namespace 'Inner' comes from an indirect dependency not declared by this project; declare it as a direct dependency to use it
If your project needs Inner, add it as a dependency of its own. trident records which project
each source file belongs to and which dependencies that project declared, and the compiler checks
the uses statements against that.
Rules
- A relative
paththat names an existing directory is a local dependency and needs its owntrident.toml. Any otherpathis a repository dependency and needs aversion. - A dependency's own dependencies are resolved and gathered too.
- A file may only
usesnamespaces declared by its own project or by a direct dependency. A namespace that is only reachable through another dependency is an error. asadds a namespace that brings in the dependency's namespaces. It does not remove the original names.trident add,removeandupdateedit the[[dep]]tables for you; seetrident.commands.
Examples
A project with one local dependency and one repository dependency that is only needed for tests:
name = "app"
entry = "main.lev"
sources = ["main.lev"]
[[dep]]
path = "../jsonlib"
as = "Json"
[[dep]]
path = "github.com/acme/testkit"
version = "1.4.0"
dev = true
With that manifest, trident run builds the project with jsonlib only, and trident check also
brings in testkit.
Notes
- To see which namespaces each file declares, uses and can see, run
leviathan --imports --plan build/plan.lvplanaftertrident plan(seelang.compiler-cli).
See also
- The manifest: trident.toml — Every key of
trident.toml, how sources and assets are listed, and the three ways a project can choose its entry point. - Versions, the lock file, and integrity — How trident picks versions of repository dependencies, what
trident.lockand the checksum record guarantee, and how to build without the network. - Two tools: trident and leviathan — How the package manager and the compiler divide the work, what the build plan between them is, and the commands that build and run a project.
- Imports — uses and use — Bring a namespace's names into scope in bulk with
uses, or one name at a time withuse ... as ....