Skip to content

feat(features): Stage 2a — feature-activated optional dependencies (v0.0.71)#183

Merged
Sunrisepeak merged 3 commits into
mainfrom
feat/feature-optional-deps
Jun 29, 2026
Merged

feat(features): Stage 2a — feature-activated optional dependencies (v0.0.71)#183
Sunrisepeak merged 3 commits into
mainfrom
feat/feature-optional-deps

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

What

A dependency declared under a feature is pulled into resolution only when that feature is active. Optionality is expressed by where you declare it — no optional = true flag.

[features]
use_blas         = { defines = ["EIGEN_USE_BLAS"], requires = ["blas"] }
backend-openblas = { implies = ["use_blas"] }

[feature-deps.backend-openblas]   # pulled ONLY when backend-openblas is active
compat.openblas = "0.3.x"

This composes with Stage 3 capabilities: features = ["backend-openblas"] pulls the provider (compat.openblas, which provides = ["blas"]) and turns on the consumer switch (implies use_blas, which requires blas) → the capability binds automatically. One-line backend selection.

How

  • Manifest.featureDeps : map<feature, map<depKey, DependencySpec>>. Parsed from TOML [feature-deps.<name>] (reuses the dependency loader) and from a Lua descriptor feature's nested deps = { ["name"] = "ver" }. Lua feature implies is now parsed too (was TOML-only).
  • prepare_build: two local lambdas activateFeatures / mergeActiveFeatureDeps merge a manifest's active feature-deps into its dependencies map — root before the worklist seed, each dep right after its manifest loads. The existing worklist BFS then resolves them; no new resolution phase, no re-entrancy. Optional-by-default falls out for free.

The two helpers MUST be local lambdas, not file-scope functions: as exported (inline) functions in this module-interface unit their std::map instantiations leak into the BMI and trip a GCC-16 modules bug — another TU importing std then fails with failed to load pendings for __normal_iterator. (Diagnosed by bisecting: build is clean without these helpers; fails when they're file-scope.)

Deferred

S2b — feature unification (union feature requests per package identity across the graph; today first-requester wins) is the next stage — the one genuine resolver-semantics change.

Tests

  • e2e: 82_feature_optional_deps.sh (off → dep not pulled; on → pulled + compiled).
  • unit: Manifest.FeatureDepsTomlSection, SynthesizeFromXpkgLua.FeatureDepsAndImplies.
  • Full feature e2e (67/71/80/81/82) + unit suite green locally.

Design: .agents/docs/2026-06-29-feature-optional-dependencies-s2-design.md.

A dependency declared under a feature is pulled into resolution ONLY when that
feature is active; declared optionality (no `optional=true` flag needed).

- Manifest.featureDeps: map<feature, map<depKey, DependencySpec>>.
- Parsed from TOML [feature-deps.<name>] (reuses the dependency loader) and from
  a Lua descriptor feature's nested `deps = { ["name"] = "ver" }`. Lua feature
  `implies` is now parsed too (was TOML-only).
- prepare_build: local lambdas activateFeatures/mergeActiveFeatureDeps merge a
  manifest's active feature-deps into its `dependencies` map — root before the
  worklist seed, each dep right after its manifest loads — so the existing
  worklist BFS resolves them and Stage-3 capability binding finds a
  feature-pulled provider. Composes into a one-line `backend-openblas` feature
  that pulls a provider AND turns on the consumer switch.

Note: the two helpers MUST be local lambdas, not file-scope inline functions —
as exported functions in this module-interface unit their std::map
instantiations leak into the BMI and trip a GCC-16 modules bug (another TU
importing std then fails: 'failed to load pendings for __normal_iterator').

Tests: e2e/82_feature_optional_deps.sh, Manifest.FeatureDepsTomlSection,
SynthesizeFromXpkgLua.FeatureDepsAndImplies.

Design: .agents/docs/2026-06-29-feature-optional-dependencies-s2-design.md
Bump to 0.0.71. CHANGELOG + docs/05-mcpp-toml.md (§2.8.2 [feature-deps.<name>]).
Design doc Implementation Status updated (S2a done; S2b next).
@Sunrisepeak Sunrisepeak merged commit ea7e437 into main Jun 29, 2026
5 checks passed
@Sunrisepeak Sunrisepeak deleted the feat/feature-optional-deps branch June 29, 2026 06:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant