Skip to content

The beans.pot manifest

beans.pot is the manifest file at the root of a Beans module. It names the module, says whether the module is an application or a library, pins Git dependencies, and passes native linker directives. It is parsed in src/module.b.

The manifest is line-based. It is not TOML and not JSON. Each line is one directive. Blank lines are ignored. A line starting with // is a comment and is ignored.

The smallest real manifests are one line. The example project ships a beans.pot that is just:

module shop

The compiler’s own manifest is just module compiler.

Create a minimal manifest in the current directory with beansc pot init <module-name>. The command does not overwrite an existing manifest.

Names the module. Exactly one module line is required. The name is the module path: the root that local packages and the lock file hang off of.

module shop

kind application or kind library (optional)

Section titled “kind application or kind library (optional)”

Says what the module builds. The default is application.

  • kind application: the module needs an fn main().
  • kind library: the module must not have a main.
module shop
kind application

See Building for how a library build produces a .a, a .dylib/.so, and an optional C header.

require <host/owner/repo> <ref> (repeatable)

Section titled “require <host/owner/repo> <ref> (repeatable)”

Pins one Git dependency. The path is a Git host path; the ref is a tag, branch, or commit-like reference.

require github.com/acme/http v1.2

Requiring the same path at two different refs is an error — anywhere in the graph, including a ref your dependency pinned. Full detail, and how this feeds beans.lock, is on Dependencies and the lock file.

Names another module on this machine, relative to this beans.pot. Nothing is fetched and nothing enters beans.lock.

require path "../shared"

It is for modules that travel together — a repository’s own sibling modules, or a checkout you are editing. A published package requires its dependencies from Git instead: a require path row in a package someone fetches names a directory that is not in their tree, and the failure arrives as an unknown package rather than as a manifest error.

Passes a compile flag to the C sources this module’s csrc rows declare.

cflags linux "-I/usr/include/gtk-4.0"
  • Selectors are the same as link: all, an OS name, or an exact triple.
  • One quoted word per flag, so a path with a space in it survives.
  • A flag that names a directory — -I, -iquote, -isystem, -idirafter, -F — resolves a relative value against the package that declared the row, exactly as that package’s csrc paths do. An absolute value passes through untouched.

beansc pot add --system <pkg> [<selector>] generates these rows from pkg-config --cflags on the build machine and writes them between markers it manages.

The package-relative rule is what lets a package vendor a C library that has its own include tree, without naming a path that exists on one machine:

cflags all "-Ivendor/postgresql/src/include"

-include and -imacros are not rewritten. They name a file the include search looks up, exactly as #include "name" in the source would, so a package that wants its own prelude writes the directory as -I and the file as -include name.h.

Section titled “link <selector> <search|library|framework> "<value>" (repeatable)”

Passes a native linker directive, for modules that link against C libraries.

  • selector is all, an OS name (for example macos, linux, windows), or an exact target triple (for example x86_64-unknown-linux-gnu).
  • The kind is one of:
    • search: a library search directory. Search paths are relative to the beans.pot file.
    • library: a library to link (by name).
    • framework: a framework to link (macOS).
  • The value is a quoted string.

Entries pass to the linker in the order you declare them.

Declares a C source file that ships with the package. The toolchain compiles it during the Beans build, without requiring a prebuilt binary or a separate build step from the consumer.

  • Selectors are the same as link: all, an OS name, or an exact triple.
  • The path is relative to the beans.pot that declares it, and the file must exist — a missing file is a manifest error.
  • Native builds compile each selected file with the build’s own Clang and flags into a content-hash-cached object that rides every emit path: linked into binaries and shared objects, archived into --emit static, placed beside --emit obj output.
  • beansc run compiles the selected set once into a host shared library, cached under $BEANS_HOME/cache/csrc, and resolves extern "C" symbols through it. The host-target link ... search, library, and framework rows are passed to this link too, so run mode and native builds resolve the same dependencies. Those selected link rows are part of the cache key.
  • Quoted #include "..." and #import "..." headers resolve beside each source file, and both count toward the object’s cache key.
  • Rows propagate from local and Git dependencies exactly like link rows.
module shop
kind application
require github.com/acme/http v1.2
link all search "native/lib"
link all library "shop_native"
link macos framework "CoreFoundation"
link x86_64-unknown-linux-gnu library "platform_helper"
csrc all "native/shim.c"

This module is an application, pulls in one Git dependency, links a native library it ships under native/lib plus a macOS framework and one Linux-only helper, and compiles its own C shim on every target.

See Dependencies and the lock file for how require feeds beans.lock, and the FFI guide for how link fits with C interop.