feat(features): propagate active-feature defines to consumers (interface defines); v0.0.72#184
Merged
Merged
Conversation
…ace defines); v0.0.72 A dependency's active-feature `defines` are interface requirements: a header-only library's feature switch only takes effect in the translation unit that includes its headers. The canonical case is Eigen's `use_blas` feature, whose `EIGEN_USE_BLAS` macro must be defined when the *consumer* compiles `a * b` — not only when Eigen's own anchor TU compiles. Previously feature defines landed only on the owning package's private build flags, so the switch was inert for header-only providers and the consumer silently used the library's built-in path. Feature defines now flow into every consumer's compile flags along Public/Interface dependency edges, mirroring `include_dirs`: they are recorded on `PackageRoot::publicUsage` (cflags/cxxflags) during feature activation, and the `computeUsageRequirements()` fixpoint propagates them into each consumer's `privateBuild`. The fixpoint is re-run after feature activation (the first pass precedes it). The automatic `MCPP_FEATURE_<NAME>` macro stays private to the owning package — it is a build signal, not a public contract. This completes the eigen[backend-openblas] closed loop: the produced binary now links and calls OpenBLAS `dgemm_` instead of Eigen's built-in GEMM. Tests: tests/e2e/83_feature_defines_propagate.sh (consumer observes a dependency's feature define). Regression: 80/81/82, transitive-dep 09/31/55/56, full unit suite.
… interface-define rationale The 83_feature_defines_propagate.sh runtime check assumed a POSIX binary name (`app`); on Windows the artifact is `app.exe`, so `find -name app` returned empty and `"$BIN"` ran as an empty command (exit 127). Match both names and assert the binary was found. The build-time assertion (the #error guard) already passed on Windows, confirming interface-define propagation is cross-platform; only the test's runtime lookup was non-portable. Doc: record that a feature's `defines` are interface requirements (propagated to consumers along Public/Interface edges) — the realization of the "package-owned namespaced define" rule for header-only providers, with the ODR-safety, visibility-bounding, and MCPP_FEATURE_* non-propagation rationale.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A dependency's active-feature
definesare now interface requirements: they propagate to every consumer's own compile flags along Public/Interface dependency edges, mirroringinclude_dirs.Motivation
For a header-only library, a feature's preprocessor switch only takes effect in the translation unit that includes the headers. The canonical case is Eigen's
use_blasfeature →EIGEN_USE_BLAS, which must be defined when the consumer compilesa * b, not only when Eigen's own anchor TU compiles. Previously feature defines landed solely on the owning package's private build flags, so the switch was inert for header-only providers — the consumer silently fell back to the library's built-in code path.Change
definesare recorded onPackageRoot::publicUsage(cflags/cxxflags) during feature activation (prepare.cppm).computeUsageRequirements()is extended to propagatecflags/cxxflags(not onlyincludeDirs) into each consumer'sprivateBuildalong Public/Interface edges, and is re-run after feature activation (the first pass precedes it).MCPP_FEATURE_<NAME>macro stays private to the owning package — it is a build signal, not a public contract.Impact
Completes the
eigen[backend-openblas]ecosystem closed loop: the produced binary now links and calls OpenBLASdgemm_instead of Eigen's built-in GEMM.Tests
tests/e2e/83_feature_defines_propagate.sh— a consumer observes a dependency's feature define (compile-time#errorguard + runtime check).80/81/82, transitive-dep09/31/55/56, full unit/integration suite (all green locally).Version
0.0.71→0.0.72.