Skip to content
FutureBlitz

    Install

    Modules and packages, 5 of 6

    Using packages

    Depend on a package from a folder or from the registry, pin its version in fb.lock, and update it.

    What you’ll build

    A program, planner, that uses a library package, geometry, for its shapes and units. First the library is a folder beside the program’s code, then it comes from the registry with fb add, and fb.lock records the exact version the program builds with.

    A package from a folder

    A dependency goes in [dependencies], under the name code imports it by. path names its folder, from the folder project.toml is in. Here geometry is a library in a folder inside the program’s, with a shapes/ folder of its own.

    project.toml
    [project]
    name = "planner"
    version = "0.1.0"
    
    [dependencies]
    geometry = { path = "geometry" }
    geometry/project.toml
    [project]
    name = "geometry"
    version = "1.2.0"
    type = "library"
    geometry/units.fb
    Import std.core
    
    Public Const CM_PER_INCH = 2.54
    
    Public Function ToInches(cm: Float): Float => cm / CM_PER_INCH
    geometry/shapes/rect.fb
    Import std.core
    
    Public Struct Rect
        Public Field Width: Float
        Public Field Height: Float
    
        Public Method Area(): Float => Width * Height
    End Struct
    main.fb
    Import std.core
    Import geometry
    Import geometry.shapes
    
    Local desk = Rect(120, 60)
    Print("{desk.Area()} square cm")
    Print("{ToInches(desk.Width)} inches wide")
    Output
    7200 square cm
    47.244095 inches wide

    Import geometry brings in the modules directly in the package’s folder, here units.fb, and Import geometry.shapes the ones in its shapes/ folder. Only a package that lists geometry in its [dependencies] can import it. The program’s own files can’t import the library’s by path either: a folder with a project.toml of its own is another package, reached only by its name.

    A dependency is a library. Listing a package that has a main file, an executable, is an error that says so.

    A package from the registry

    A package published to the registry is added by its name, here in a new package:

    fb add geometry
    Output
          Adding geometry v1.2.0
           Added geometry v1.2.0 to dependencies

    fb add finds the newest version, adds it to [dependencies] as a version range, and leaves the rest of project.toml as it was:

    [dependencies]
    geometry = "1.2.0"

    "1.2.0" is a range: 1.2.0 or any later version below 2.0.0, which semantic versioning says is compatible. Below 1.0, the second number counts as the major one, so "0.4" means 0.4.0 up to 0.5.0, and below 0.1, the third does, so "0.0.3" means exactly 0.0.3. A few other forms:

    RangeMeans
    "1.2"1.2.0 up to, but not including, 2.0.0
    "~1.2.3"1.2.3 up to 1.3.0
    "=1.2.3"exactly 1.2.3
    ">=1.2, <1.5"1.2.0 up to 1.5.0

    fb add geometry@1.1 adds a range of your own, and the code doesn’t change: Import geometry works the same whichever way the package arrives.

    fb.lock

    A program is built with one exact version of each registry package it uses, its dependencies’ own dependencies included. For each, fb picks the newest version that every range on it allows, skipping versions that were yanked, and writes the versions to fb.lock beside project.toml, with each archive’s SHA-256. Packages from folders aren’t in it. An entry looks like this, beside the index it came from, which is left out here:

    fb.lock
    [[package]]
    name = "geometry"
    version = "1.2.0"
    checksum = "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
    dependencies = []

    Commit fb.lock with the program, so every machine builds the same versions.

    A build reads fb.lock and changes it only when project.toml asks for what it doesn’t have: a new dependency, a range its locked version is outside, or another registry. Then fb picks again, keeping every locked version it can. A download whose hash isn’t the one fb.lock recorded is an error, and nothing of it is used.

    When two packages ask for ranges no one version meets, fb says which ranges conflict, and who asks for each.

    Updating

    Here geometry 1.1.0 was the newest when the program was locked, and 1.2.0 is out now:

    fb update geometry
    fb update
    Output
        Updating geometry v1.1.0 -> v1.2.0

    fb update picks the newest versions that the ranges allow, for every package, and fb update geometry changes only geometry and what it has to. Downloaded packages are kept in a cache in your home folder, so a build that has everything it needs works offline.

    What you learned

    • [dependencies] lists a program’s packages, by a folder’s path or by a version range.
    • fb add name adds the newest version from the registry, as a range.
    • Import name imports a dependency’s modules by its name, wherever it came from.
    • fb.lock pins the exact version of every registry package, and belongs in version control.
    • fb update moves to newer versions within the ranges.

    Report an issue with this page or with FutureBlitz on GitHub.