carrier.toml
When we compose a (re)usable codes to be shared as a library, one must contain a file that declares the metadata, including the info of the authors, the required version, and package dependencies the library used. Composing a {box}-{carrier} module library requires one file: carrier.toml. This metadata file sits at the root of a module project, one level above the source directory. It may contain up to five tables:
| Table | Required | Purpose |
|---|---|---|
[module] |
yes | Module identity and source location |
[package_deps] |
no | Runtime R package dependencies |
[module_deps] |
no | Other carrier modules this module depends on |
[native] |
no | Location(s) of compiled code and build-time-only package deps |
[test] |
no | Test framework configuration (currently advisory only) |
[module]
This block is always required. As what the table below said, this contains the info of the author of {box}-{carrier} module library
| Field | Type | Required | Notes |
|---|---|---|---|
name |
string | yes | Module name. Also the default source-directory name when src is omitted. |
version |
string | yes | Free-form version string. carrier bundle embeds it verbatim in the archive filename. |
description |
string | yes | May be empty. |
authors |
array | yes | See Authors below. |
license |
string | yes | SPDX identifier or free-form text. |
r_version |
string | yes | Declarative minimum R version (e.g. ">=4.0.0"). See note below. |
src |
string | no | Path to the source directory, relative to the project root. Defaults to a directory named exactly name. The chosen directory must contain __init__.r or __init__.R. |
r_versionis recorded in the archive manifest but is not currently enforced against the R installation that runscarrier install/carrier compile.- Both
__init__.rand__init__.Rare accepted (case-insensitive entry-point detection). This matches{box}’s own behaviour.
[package_deps]
If you write R packages before, this is just like Imports in R packages’ DESCRIPTION. In this block, it maps an R package name to a version requirement. A value may be a bare string (CRAN, default mirror) or an inline table that also specifies a repository:
[package_deps]
dplyr = "*"
ggplot2 = ">=3.4.0"
fable = { version = "*", repo = "https://tidyverts.r-universe.dev/" }When it is just a single string, not in a table {} syntax, the repo refers to the default mirror which is https://cloud.r-project.org.
Version-spec syntax
The idea behind the declaration of the version takes from how Cargo.toml package dependencies version must be declared, and they are always in strings. The table below summarizes the syntax of the version declaration.
| Syntax | Meaning |
|---|---|
"*" |
Any version |
">=1.0.0" |
Lower bound only |
">=1.0.0, <2.0.0" |
Inclusive range (comma-separated bounds) |
"^1.2.0" |
SemVer-compatible with 1.2.0 |
"=1.2.3" |
Exact pin |
CRAN version strings that use dashes (e.g. 4.0-3) are normalised to dots before parsing.
[module_deps]
Maps another carrier module to a version requirement, using the same version-spec syntax as [package_deps]. Unlike package dependencies, there is no default registry…yet. Every resolvable entry must therefore supply a source:
[module_deps]
other_module = { version = "*", source = "gh:user/repo" }
# pin a tag / branch / commit and optional sub-directory:
utils = { version = ">=0.2", source = "gh:user/repo/tree/v0.3.1/modules/utils" }source accepts the same forms as the <source> argument of carrier install (currently gh:user/repo and the /tree/<ref>/<subpath> variant). See CLI reference.
A bare-string form is accepted by the parser but cannot be resolved:
[module_deps]
other_module = "*" # will fail at resolution timeAs of current version, an entry without a source (whether written as a bare string or as an inline table that omits the field) produces an explicit resolution error. There is deliberately no silent fallback. It has to have the source to be declared, since there’s no default registry for {box}-{carrier} modules, yet.
[native]
Declares the location(s) of compiled code belonging to the module and any build-time-only R packages whose headers are needed by Makevars / R CMD SHLIB (most commonly Rcpp or cpp11).
[native]
path = "cpp/" # single directory, relative to the module's source dir
# path = ["cpp/", "extra/"] # or an array, for multiple directories
build_deps = { Rcpp = "*" } # installed before compilation; not a runtime dependency| Field | Type | Required | Notes |
|---|---|---|---|
path |
string or array of strings | between yes and no | Directory, or directories, containing native sources + Makevars. Relative to the module’s own source directory (the same base used by src). A single location can be written as a plain string; more than one as an array. |
build_deps |
table | no | Map of package name → version requirement (same syntax as [package_deps]). These packages are resolved and installed before R CMD SHLIB runs. They do not become runtime dependencies; list them again under [package_deps] if the compiled code also needs them loaded at runtime. |
Resolution rules
- If
pathis set, those directories (relative to the module source dir) are used, whether it’s written as a single string or an array. - Else, carrier scans the whole module source tree for directories that contain a
Makevars(or recognised C/C++ sources). This is the behaviour you get when the[native]table is omitted entirely.
The directory name itself is free (c/, cpp/, fortran/, src/, …). Detection is driven by the presence of build artefacts, not by a fixed folder name. See also the native-code scaffolding produced by carrier init --native.
- Fortran scaffolding is recognised by the language parser but is not yet supported by the build pipeline (
R CMD SHLIBis only invoked for.c/.cpp/.cc/.cxxsources). - Compiled artefacts are placed in
<module>/.lib/(next to__init__.R) so thatbox::file()resolves them correctly. - Build results are cached by source hash + R platform + R version.
[test]
Advisory configuration for a future test runner. Carrier does not yet execute tests.
| Field | Type | Required | Notes |
|---|---|---|---|
framework |
string | yes | e.g. "testthat" |
dir |
string | no | Directory containing tests (default "tests") |
Full template
This is the exact text written by carrier init (the [native] block appears only when --native is supplied):
[module]
name = "convert"
version = "0.1.0"
description = ""
authors = [
{ name = "Your Name", email = "you@example.com" },
]
license = "Unknown"
r_version = ">=4.0.0"
# src = "convert" # path to the source directory containing __init__.R
# defaults to a directory named after the module
[package_deps]
# dplyr = "*"
# ggplot2 = ">=3.4.0"
# fable = { version = "*", repo = "https://tidyverts.r-universe.dev/" }
[module_deps]
# other_module = "*"
[native]
# Only needed if native code doesn't live in the default location
# (src/ under this module's source dir), or if `src/Makevars`
# references headers from another R package (e.g. Rcpp).
# path = "native/"
# path can also be an array: path = ["native/", "extra/src"]
# build_deps = { Rcpp = "*" }
# build_deps is resolved and installed before compiling.
# Does not imply a runtime dependency; list in [package_deps]
# too if the compiled code also needs it loaded at runtime
[test]
framework = "testthat"
dir = "tests"When carrier init --native cpp (or --native c, etc.) is used, the [native] block is un-commented and populated with the appropriate path and build_deps for the chosen language / backend.