|
| 1 | +Cargo Features |
| 2 | +============== |
| 3 | + |
| 4 | +On the surface, `cargo`'s |
| 5 | +[features](https://doc.rust-lang.org/cargo/reference/features.html) mechanism |
| 6 | +looks great for `libtock-rs`. Process binary crates can depend on `libtock-rs`, |
| 7 | +and use `cargo` features to specify which optional `libtock-rs` functionality |
| 8 | +they want. |
| 9 | + |
| 10 | +However, `cargo` assumes that it can compile a crate with features that a binary |
| 11 | +does not need. This isn't necessarily true for embedded crates, where process |
| 12 | +binary authors care about the app size. |
| 13 | + |
| 14 | +## Process Binaries in a Workspace |
| 15 | + |
| 16 | +When used with workspaces, `cargo` features can result in excess code being |
| 17 | +built into a repository. |
| 18 | + |
| 19 | +For example, suppose that `libtock` exposes a `malloc` feature, which adds a |
| 20 | +dynamic memory allocator. Then if a `libtock` user creates a `cargo` workspace |
| 21 | +with the following process binaries in it: |
| 22 | + |
| 23 | +1. `no_malloc`, which depends on `libtock` and does not depend on the `malloc` |
| 24 | + feature. |
| 25 | +2. `malloc`, which depends on `libtock` and the `malloc` feature. |
| 26 | + |
| 27 | +With this setup, `malloc` will always work correctly. Also, if you run `cargo |
| 28 | +build -p no_malloc`, then `no_malloc` will correctly build without a memory |
| 29 | +allocation. |
| 30 | + |
| 31 | +Seems optimal, right? |
| 32 | + |
| 33 | +It's not: if you build the entire workspace with `cargo build --workspace`, |
| 34 | +`libtock` will only be built once, with the `malloc` feature! That will result |
| 35 | +in a `no_malloc` process binary that contains a memory allocator, which is not |
| 36 | +what the author desired. |
| 37 | + |
| 38 | +## Alternative to `cargo` Features |
| 39 | + |
| 40 | +In many cases, `cargo` features can be replaced by splitting a crate up into |
| 41 | +smaller crates, and letting process binaries choose what to depend on. For |
| 42 | +example, memory allocation can be in a separate crate that process binaries |
| 43 | +depend on if and only if they need memory allocation. |
| 44 | + |
| 45 | +Here are some questions to help guide the decision between using a `cargo` |
| 46 | +feature and separate crates: |
| 47 | + |
| 48 | +1. Do you forsee a single user writing multiple process binaries, some of which |
| 49 | + use this feature? If yes, then maybe it should not be a `cargo` feature. |
| 50 | +2. Will the compiler optimize the feature away entirely if it is included but |
| 51 | + unused? If yes, then making it a `cargo` feature is probably fine. |
| 52 | + |
| 53 | +In many cases, it will make sense to add a `cargo` feature to `libtock` but use |
| 54 | +optional crates to implement the feature internally. This way, users with |
| 55 | +multiple process binaries in a workspace can choose whether each process binary |
| 56 | +depends on the optimal crate. |
0 commit comments