Skip to content

feat(features): propagate active-feature defines to consumers (interface defines); v0.0.72#184

Merged
Sunrisepeak merged 3 commits into
mainfrom
feat/interface-define-propagation
Jun 29, 2026
Merged

feat(features): propagate active-feature defines to consumers (interface defines); v0.0.72#184
Sunrisepeak merged 3 commits into
mainfrom
feat/interface-define-propagation

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

Summary

A dependency's active-feature defines are now interface requirements: they propagate to every consumer's own compile flags along Public/Interface dependency edges, mirroring include_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_blas feature → EIGEN_USE_BLAS, which must be defined when the consumer compiles a * 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

  • Feature defines are recorded on PackageRoot::publicUsage (cflags/cxxflags) during feature activation (prepare.cppm).
  • computeUsageRequirements() is extended to propagate cflags/cxxflags (not only includeDirs) into each consumer's privateBuild along Public/Interface edges, and 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.

Impact

Completes the eigen[backend-openblas] ecosystem closed loop: the produced binary now links and calls OpenBLAS dgemm_ instead of Eigen's built-in GEMM.

Tests

  • New: tests/e2e/83_feature_defines_propagate.sh — a consumer observes a dependency's feature define (compile-time #error guard + runtime check).
  • Regression: feature e2e 80/81/82, transitive-dep 09/31/55/56, full unit/integration suite (all green locally).

Version

0.0.710.0.72.

…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.
@Sunrisepeak Sunrisepeak merged commit f3ac1a0 into main Jun 29, 2026
5 checks passed
@Sunrisepeak Sunrisepeak deleted the feat/interface-define-propagation branch June 29, 2026 09:11
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