See also
https://peter-kehl.github.io/embedded_low_level_rust
for building and testing no_std/no_std_heap/std
libraries on desktop. That
also shows any source code included below.
Rust macros for ergonomic conditional compilation based on no_std
,
no_std_heap
and std
features.
The feature names used/referred-to by these macros are not, and cannot be, configurable. The above three feature names had to be hard-coded. (Explanation of those features is later in this document.)
TODO include Cargo.toml
Basic conditional feature-based compilation is easy. It can be as simple as using:
TODO EXAMPLE
But if you depend on compound conditions, it gets repetitive. It clutters the code. Hence suggest using macros.
New to Rust? Any identifier following by an exclamation mark !
indicates a
macro invocation. (Another type of macros, called attribute macros, start with a
hash #
.)
TODO EXAMPLE
- any heap-less
no_std
library will work for any purpose:no_std
without heap, with heap orstd
- but some
no_std
libraries may have both heap-less and heap parts. For example: extra functions orenum
variants that work withalloc::boxed::Box
,alloc::vec::Vec
,alloc::string::String
... - We could have heap functions defined in separate traits in a separate (heap)
library, but that makes types complicated. And we can't add variants to an
existing
enum
from another crate. - If you provide functionality for both heap and heap-less, have a
feature
called
no_std_heap
(or similar). Then conditionally compile such functionality (see later in this document).
- "Controversial," but proactive & clear
- If your library can provide extra functionality in
std
, (like usingHashMap
)- have a feature for that (called, for example,
std
) - have a feature for
no_std
, too - Make those two features mutually exclusive (by a compile-time check). That is against the cargo book's general recommendation, but they do mention this option.
- require maximum one of those two features to be used
- this makes any consumer crate explicit about whether they require
std
orno_std
- benefits
- any conflicts between dependencies (one using
std
but another usingno_std
of the same crate) are reported clearly - it simplifies troubleshooting of consumer crates and also of your library
- it allows to differentiate (a small set of) consumer mid/higher level
libraries that are
std/no_std
-agnostic. They import anstd/no_std
-aware library, but thestd
/no_std
choice is left for the higher consumer. Such a consumer library would use thestd/no_std
aware library through abstractions that arestd/no_std
-independent. This differentiation is not possible under the cargo book's general recommendation. Seeslicing_any_std_test
later in this document.
- any conflicts between dependencies (one using
- of course, all
no_std
functionality is available understd
feature, too no_std_heap
extends functionality ofno_std
. You could makeno_std_heap
implyno_std
and be usable even withoutno_std
, but then your documentation and compile checks (no_std_heap
vsstd
) would get complicated. Instead, may I suggest to haveno_std_heap
requireno_std
. Then the exclusion checks are betweenno_std
andstd
only.
- have a feature for that (called, for example,
- If your library can provide extra functionality in
If your no_std_heap
or std
code needs extra dependencies, use
Features >
Optional
dependencies.
TODO ranging -> slicing example