Skip to content

Dependencies

Name the programs yours needs, and Roost flattens the graph so a client can write them in order without walking it.

Any repository-built program — a game as much as another library, in either library mode — may name the programs it needs.

.ceagle-flight
[program]
depends = ["demo-library", "usb-driver"]

Each entry is a Roost address, not a LibLoad name and not a URL. One list covers both jobs: what the build links against, and what Swoop installs alongside the program.

Pinning a version#

A bare address builds against whatever that program published most recently. Append @version to build against one release instead:

.ceagle-flight
[program]
depends = ["demo-library", "usb-driver@1.4.0"]

A pin fails the build if that release was never published, which is what to reach for when a library changes an ABI. It applies to the build only — a release records the address alone, because the install graph resolves to whatever is published when a calculator asks.

The rules#

Constraints
countat most 8

Per program. A program needing more than eight libraries is usually a program that wants one library that bundles them.

published firstRequired

Each dependency has to be published before the build that names it. A name nothing is published at fails the build.

a libraryRequired

A build can only link against a LibLoad library. Naming an ordinary program fails.

acyclicRequired

Cycles are refused, including a program that names itself.

listed onceRequired

The same address twice is an error, not a list quietly reduced to one.

repository projects only

TI-BASIC projects have no manifest and cannot declare dependencies.

What the build gets#

Nothing is rebuilt. Every library publishes a developer archive holding the appvar, the .lib stub and the public headers, and a build that depends on one is handed that archive.

The Flight builder does the work before the sandbox starts, because the sandbox has no network:

  1. Resolve

    It asks Roost what each address resolves to, and gets a version, a library name, a size and a checksum back.

  2. Fetch what is new

    Archives are cached by checksum. A repeat build downloads nothing, and a new release is simply a new key.

  3. Verify and unpack

    Each archive is checked against its checksum. The stub and the headers are unpacked; the appvar is dropped, since that is what a calculator installs and no part of what a build links against.

  4. Build

    The container sees them on a read-only mount, with the headers beside the toolchain's own and the stubs on the LibLoad search path.

An ordinary project makefile needs no changes for any of this. A dependency shipping a header the toolchain already provides — its own string.h — fails the build by name rather than quietly replacing it.

Reading the flattened graph#

Do not walk the graph yourself. Ask for it flattened:

GET/api/v1/programs/{slug}/requiresPublic
{
  "slug": "snake",
  "programs": [
    {
      "slug": "usb-driver",
      "title": "USB Driver",
      "version": "2.1.0",
      "checksum": "a3f1…",
      "size": 8412,
      "size_text": "8.2 KB",
      "var_name": "USBDRVCE",
      "var_type": "appvar",
      "archived": true,
      "language": "lib",
      "raw_url": "/d/usb-driver/raw"
    },
    {
      "slug": "demo-library",
      "title": "Demo Library",
      "version": "1.0.0",
      "checksum": "77c2…",
      "size": 3120,
      "size_text": "3.0 KB",
      "var_name": "DEMO",
      "var_type": "appvar",
      "archived": true,
      "language": "lib",
      "raw_url": "/d/demo-library/raw"
    }
  ]
}

Deepest dependency first. Write them in exactly that order, then write the program itself, which is not included in the list.

The same array rides along on the single-program endpoint as requires, so fetching a program page needs one call rather than two.

What a client does with it#

  1. Ask for the requirements

    One request, before downloading anything.

  2. Compare checksums

    Each entry carries its own checksum. Anything already on the calculator at the same checksum is already correct: skip it.

  3. Write what is left, in order

    Each entry says its variable name, its type, its size and whether it wants to be archived.

  4. Write the program

    Last.

That is exactly what Swoop does.

Installing with dependencies

The full client-side procedure, including the bulk version check.

Read on

When a dependency is archived#

Archiving a project suspends its program, and a suspended program is filtered out of the dependency graph. A program that depends on it keeps its declaration, but the requirement stops being returned.

That means an install can silently become incomplete. If you maintain a library other people depend on, archiving it is a decision about their programs as much as yours.

Choosing what to depend on#

Depend on a library

Published at a stable address, with an append-only export table. That is what libraries are for.

Do not depend on a program

Nothing stops it, but a program is not an interface. If two of your programs share code, make the shared part a library.

CEagle documentation