System dependencies
System dependencies are external libraries that Cabin does not
fetch, build, or install. Users provide them through their OS
package manager (or any other local installation mechanism) and
Cabin discovers their compile / link flags by querying
pkg-config.
See docs/dependency-kinds.md for the
dependency kinds and the declaration syntax; this page covers
the build-time behavior of system-sourced (system = true)
entries specifically.
Manifest declaration
A system-sourced dependency lives in one of the regular
dependency tables ([dependencies], [dev-dependencies]) with
system = true set:
[dependencies]
zlib = { version = ">=1.2", system = true }
fmt = { version = "^9.0", system = true }
Every declared system = true dependency is required. There is
no required field; declaring required on any dependency
entry is rejected with a clear "unknown field" diagnostic.
Per-kind activation matches the Cabin-package rule for the table the entry lives in:
| Table | Probed by cabin build / run / metadata |
Probed by cabin test |
|---|---|---|
[dependencies] |
always | always |
[dev-dependencies] |
no | selected primaries |
A test-only system dep (e.g. gtest) is declared under
[dev-dependencies] with system = true, so an ordinary
cabin build does not require it to be installed.
Conditional declarations work the same way as the other dependency kinds:
[target.'cfg(os = "linux")'.dependencies]
systemd = { version = ">=240", system = true }
A conditional system dependency is probed only when its condition matches the host platform.
What Cabin does with system-sourced entries
When the selected primary packages declare at least one active
system dependency, Cabin invokes pkg-config (once per
dependency) to:
- verify the library is present
(
pkg-config --exists 'name op version'), - retrieve compile-time flags
(
pkg-config --cflags name), - retrieve link-time flags
(
pkg-config --libs name).
Discovered include directories from --cflags are added to the
package's include-dir set. All other --cflags tokens are
appended verbatim to the package's language-neutral compile
argument bucket.
All --libs tokens are appended verbatim to the package's
ldflags list, preserving the order pkg-config emitted them
so C / C++ link semantics are not disturbed.
Probe scope is intentionally primary-only. For a single-package
project, the root package is primary; for a workspace, the
members selected by the command are primary. Local path
dependencies and registry / extracted dependencies may preserve
system = true declarations in metadata, package archives, and
index entries, but those dependency manifests do not trigger
pkg-config probing for the downstream build.
Probing happens for every command that produces compile or link
commands (cabin build, cabin run, cabin test,
cabin tidy) and for cabin metadata and
cabin explain build-config so the build-configuration
fingerprint stays consistent across those commands. Other
cabin explain subcommands (package, target, source,
feature) do not invoke pkg-config because they never
materialize a build configuration.
Version requirements
Cabin tries to convert each Cabin / npm-flavored SemVer
requirement into a list of pkg-config-native operator pairs:
| Cabin requirement | pkg-config form |
|---|---|
^1.2 |
>= 1.2, < 2.0.0 |
~1.2.3 |
>= 1.2.3, < 1.3.0 |
>=1.2 <2 |
>= 1.2, < 2 |
=1.0.0 |
= 1.0.0 |
Requirements that do not parse as SemVer are forwarded to
pkg-config verbatim provided they include an explicit
operator. A bare non-SemVer token (e.g. vendor-special)
produces a clear error rather than being silently dropped.
pkg-config itself does the version comparison.
Missing dependency semantics
A declared system = true dependency that fails to probe stops
the build with an actionable diagnostic that names the package,
the requirement Cabin attempted, and the installed version when
available. Cabin never silently drops a missing system
dependency from the build graph.
Executable resolution
Cabin uses the pkg-config executable from PATH by default.
The CABIN_PKG_CONFIG environment variable overrides the
default with a verbatim executable path or command name:
CABIN_PKG_CONFIG=/opt/pkgconf/bin/pkg-config cabin build
If a project declares no system = true entries, Cabin never
spawns pkg-config and the executable is not required. When
the project does declare system dependencies and the resolved
executable is missing, Cabin produces a single diagnostic
suggesting the install / override fix.
Pkg-config environment
Cabin does not sanitize the standard pkg-config environment.
Variables PKG_CONFIG_PATH, PKG_CONFIG_LIBDIR, and
PKG_CONFIG_SYSROOT_DIR are inherited by the child process,
so users can point Cabin at custom .pc search paths the same
way they would for any other pkg-config consumer.
Fingerprint and rebuild
Discovered compile / link flags participate in
cabin_core::BuildConfiguration::fingerprint through the
per-package ResolvedProfileFlags. When pkg-config reports
different flags (for example because the user upgraded the
system library or changed PKG_CONFIG_PATH), the build
configuration fingerprint moves; Ninja then rebuilds from the
changed command lines.
Output / diagnostics
Normal mode: Cabin prints no probe-specific output on successful runs.
Verbose mode (cabin -v ...): Cabin prints one line per
probed dependency naming the resolved version, and one summary
line per workspace identifying the pkg-config executable
that was used.
Very-verbose mode (cabin -vv ...): Cabin also prints the
per-dependency probe request (name, version requirement)
before the probe runs.
All probe-related output is written to stderr so that
machine-readable stdout (cabin metadata, cabin explain
--format json) stays a parseable document.
Quiet mode (cabin -q ...): probe status output is suppressed.
Errors are not.
Diagnostics
| Code | When |
|---|---|
cabin::system_deps::executable_not_found |
Cabin tried to spawn pkg-config but the binary was missing. |
cabin::system_deps::package_not_found |
pkg-config --exists reported the package as absent. |
cabin::system_deps::version_mismatch |
The installed version does not satisfy the manifest requirement. |
cabin::system_deps::invalid_version_requirement |
The requirement string could not be interpreted. |
cabin::system_deps::pkg_config_failed |
pkg-config exited non-zero for --cflags / --libs. |
cabin::system_deps::invocation_failed |
A pkg-config invocation failed for a reason other than not-found. |
cabin::system_deps::malformed_output |
pkg-config produced output Cabin could not split into argv tokens. |
What Cabin does not do
Cabin does not install system packages. Use your OS package
manager (apt, dnf, brew, pacman, ...), an external
toolchain manager, or a manual install. Cabin does not bundle
or wrap any third-party package manager.
Cabin does not integrate with vcpkg, Conan, or Cargo-style
system probes beyond the pkg-config query path described
above.