Provides two macros to assist with managing conditional compilation in Rust.
no_std
- No
build.rs
- Zero features
- Zero dependencies
- No
proc-macros
Instead, this crate defines 4 macro_rules
macros:
switch
alias
enabled
disabled
crossfig::alias! {
/// Indicates whether the `std` feature is enabled.
pub std: { #[cfg(feature = "std")] }
}
crossfig::switch! {
std => {
extern crate std;
std::println!("Can use std!");
}
_ => {
// no_std
}
}
enabled
and disabled
are the simplest to explain: they either pass their contents unchanged or suppress them.
crossfig::enabled! {
println!("I will print!");
}
crossfig::disabled! {
compile_error!("I won't be triggered!");
}
If no content is provided to either macro, an appropriate bool
value will be returned, allowing use in if
statements and other logical operations.
if crossfig::enabled!() {
println!("I will print!");
}
if crossfig::disabled!() {
println!("I won't print!");
}
On their own, these macros aren't very helpful.
That's where alias
comes in.
The alias
macro will use
either enabled
or disabled
with a new provided identifier based on an arbitrary conditional compilation configuration.
crossfig::alias! {
std: { #[cfg(feature = "std")] }
}
// Is roughly equivalent to:
#[cfg(feature = "std")]
use crossfig::enabled as std;
#[cfg(not(feature = "std"))]
use crossfig::disabled as std;
Since the aliases created by alias
are macro_rules
items, they can be documented and even publicly exported.
crossfig::alias! {
/// Indicates the log feature is enabled.
pub log: { #[cfg(feature = "log")] }
}
When publicly exported, it's important to understand that an alias is evaluated as either enabled
or disabled
at the definition site, not the call site.
This means aliases can be used to determine what features are enabled in dependencies.
// In a crate `foo`
crossfig::alias! {
/// Indicates the log feature is enabled.
pub log: { #[cfg(feature = "log")] }
}
// In a consuming crate
if foo::log!() {
// `foo`'s `log` feature has been enabled!
}
Note that aliases and standard #[cfg(...)]
attributes can be mixed and matched within definitions, and combined with not
, any
and all
operators:
crossfig::alias! {
a: { #[cfg(feature = "a")] }
b: { #[cfg(feature = "b")] }
c: { all(a, not(b), #[cfg(feature = "c")]) }
}
While aliases are powerful, they still don't solve a common issue: ranked choice.
It's common to have multiple features in a crate which all contribute to a single choice.
For example, you may have a parking_lot
, std
and spin
set of features to choose what Mutex
implementation is used internally.
To make this particular problem nicer, we use the final macro in this crate, switch
:
crossfig::alias! {
parking_lot: { #[cfg(feature = "parking_lot")] }
std: { #[cfg(feature = "std")] }
spin: { #[cfg(feature = "spin")] }
}
crossfig::switch! {
parking_lot => {
use parking_lot::Mutex;
}
std => {
use std::sync::Mutex;
}
spin => {
use spin::Mutex;
}
_ => {
compile_error!("Must select a `Mutex` provider!");
}
}
The minimum supported Rust version for this crate is 1.54.0, with the 2015 edition, allowing it to be used in virtually any Rust project.
Note that support for earlier versions are blocked by the unavailability of #![no_std]
, vis
types in macro_rules
, and concat!
in documentation.
If support for earlier versions of Rust would help you, please create an issue!
Refer to the git history for detailed changes. This crate is intending on hitting 1.0 in the near-term, so don't expect major changes between now and then.