#cargo-manifest #group #features #exclusive #mutually #combination

macro featurecomb

Define feature groups and enforce relations between Cargo features from your manifest

2 releases

0.1.1 Nov 28, 2024
0.1.0 Nov 27, 2024

#602 in Configuration

Download history 262/week @ 2024-11-25 7/week @ 2024-12-02 12/week @ 2024-12-09

281 downloads per month

MPL-2.0 license

27KB
351 lines

featurecomb

Define feature groups and enforce relations between Cargo features from your manifest

Documentation

The documentation is available on docs.rs.

Example

In examples/featurecomb-example/featurecomb-example-dependent/Cargo.toml try enabling/disabling the various features of examples/featurecomb-example/featurecomb-example-lib. Run cargo run in examples/featurecomb-example to check the effect.

Licensed

Copyright 2024 AudaciousAxiom

This project is licensed under MPL-2.0, except for the featurecomb-schema crate which is licensed under MIT OR Apache-2.0.


lib.rs:

featurecomb allows you to define groups of Cargo features and define different kinds of relations between features and these feature groups from your crate's manifest, and enforce them at compile time.

Installation

Simply add featurecomb as a dependency to your crate.

Usage

Define feature groups and feature relations in your manifest metadata table as explained below, and use the #[featurecomb::comb] attribute macro in your crate top module to have these checked automatically at compile time.

How it works

featurecomb generates compile-time checks using #[cfg]-gated compile_error! statements so that the requirements defined are checked by the compiler.

Feature groups

Feature groups are defined in the [package.metadata.feature-groups] table. They do not live in the same namespace as features, i.e., feature groups can be named the same as existing features and will not conflict with them.

Marking features as mutually exclusive: $group.xor

Features of a group can be marked as mutually exclusive using the xor table:

#
[package.metadata.feature-groups]
openssl.xor = { features = ["native-openssl", "vendored-openssl"] }

Performance note: the number of generated checks increases quadratically with the number of features in the group.

Requiring exactly one feature: $group.exactly-one

When features of a group are mutually exclusive but one must always be enabled, the exactly-one table is to be used instead:

#
[package.metadata.feature-groups]
llvm-version.exactly-one = { features = ["llvm-16", "llvm-17", "llvm-18"] }

Performance note: the number of generated checks increases quadratically with the number of features in the group.

Defining a feature group with no relations

A feature group can also be defined without enforcing any relations between the features of that group:

#
[package.metadata.feature-groups]
ip-version = { features = ["ipv4", "ipv6"] }

This is useful so that the group can be required by a feature, to express an "at least one" relation.

Features

Feature relations are defined in the [package.metadata.feature-groups.features] table. They define relations for features already existing in the standard [features] table.

Requiring groups and features: $feature.requires

The requires table on a feature requires that the features and features groups listed be enabled when that feature is enabled:

#
[package.metadata.feature-groups.features]
tls.requires = { groups = ["openssl", "tls-version"] }
#
[package.metadata.feature-groups.features]
usb-hid.requires = { features = ["usb"] }

It is possible to use the groups and features keys at the same time, in which case all features and feature groups listed are required.

Example

See the examples directory in the repository, which contains a playground to try out the following example:

#
[package.metadata.feature-groups]
ip-version = { features = ["ipv4", "ipv6"] }
llvm-version.exactly-one = { features = ["llvm-16", "llvm-17", "llvm-18"] }
openssl.xor = { features = ["native-openssl", "vendored-openssl"] }
tls-version = { features = ["tls-12", "tls-13"] }

[package.metadata.feature-groups.features]
tls.requires = { groups = ["openssl", "tls-version"] }
usb-hid.requires = { features = ["usb"] }

[features]
ipv4 = []
ipv6 = []

llvm-16 = []
llvm-17 = []
llvm-18 = []

usb = []
usb-hid = []

tls = []
tls-12 = []
tls-13 = []
native-openssl = []
vendored-openssl = []

Compatibility

The error messages generated by this crate should not be considered stable.

Dependencies

~2.4–3MB
~64K SLoC