Modules and packages, 4 of 6
project.toml
Make a package with fb new, name its modules by its name, and set what project.toml controls.
What you’ll build
A package called shop, made with fb new, with a module of prices beside its main file. You’ll
see what project.toml holds, how a package’s modules are named, where fb build puts the
executable, and what fb says when project.toml is wrong.
A new package
fb new makes a package in a new folder, named after the folder:
fb new shopThe folder has three files: main.fb, which prints a greeting; a .gitignore that leaves out
build/; and project.toml:
[project]
name = "shop"
version = "0.1.0"A package is a folder with a project.toml. name is an identifier other than std, and
version is three numbers, like 0.1.0. Inside the folder, fb run builds the package and runs
it, and fb build writes the executable to build/shop, or build\shop.exe on Windows.
Modules named by the package
A package’s files are modules named by its name and their paths, so prices.fb in shop is
shop.prices, and money/tax.fb would be shop.money.tax. Other files of the package import it
by that name.
[project]
name = "shop"
version = "0.1.0"Import std.core
Public Const TAX_PERCENT = 8
Public Function WithTax(cents: Int): Int => cents + cents * TAX_PERCENT / 100
Public Function Dollars(cents: Int): String
Local rest = cents % 100
Return "${cents / 100}.{rest < 10 ? "0" : ""}{rest}"
End FunctionImport std.core
Import shop.prices
Local price = 1999
Print("{Dollars(price)} is {Dollars(WithTax(price))} with {TAX_PERCENT}% tax")$19.99 is $21.58 with 8% tax
Import "./prices" works too, by path. The package’s name is the usual way, since it reads the
same from every file, however deep in folders.
The main file
The main file is main.fb unless main names another, by its path in the package’s folder.
Its top-level code is the program.
[project]
name = "shop"
version = "0.1.0"
main = "src/app.fb"A package without a main file is a library: its modules are for other packages to use, and it
builds no program. type = "library" says so, and is the default for a package with no main
file; type = "executable" is the default for one with a main file. Publishing a
package makes a library.
The formatter’s width
[format] holds one key, width, the line width fb fmt formats the package’s code to. It’s
100 columns without it, and can be 40 to 1000.
[project]
name = "shop"
version = "0.1.0"
[format]
width = 80When project.toml is wrong
fb reads project.toml before any code, and reports its mistakes at their lines, as it does the
code’s. A key it doesn’t use is a warning, so a misspelling doesn’t go unnoticed, and a value it
can’t use is an error, which stops the build. This project.toml has one of each:
[project]
name = "shop"
version = "1.0"
author = "Ada"Import std.core
Print("open")Compiling . project.toml:3:11: error: a package's version is three numbers, like "0.1.0", and maybe a pre-release, like "1.0.0-beta.1", not "1.0" | 3 | version = "1.0" | ^^^^^ project.toml:4:1: warning: [project] doesn't use 'author' | 4 | author = "Ada" | ^^^^^^ error: couldn't build . because of 1 error
What you learned
fb newmakes a package: a folder withproject.tomlandmain.fb.[project]needsnameandversion, and can setmainandtype.- A package’s modules are named by its name and their paths, as
shop.prices. fb buildwrites the executable tobuild/, named after the package.[format] widthsets the line width forfb fmt.
The rules are in the language reference.
Report an issue with this page or with FutureBlitz on GitHub.