I am developing a code for my school's rocketry team and I have two programs, one meant to flash the on-board computer and another to run some data analysis on the flight data. The chip code uses no_std while the data analysis program uses std. The data-analysis code will run on my PC, and the chip code will run on the chip.
Here is my workspace root Cargo.toml and my project graph:
[workspace]
members = [
"chip",
"data-analysis",
]
.
├── Cargo.lock
├── Cargo.toml
├── chip
│ ├── Cargo.toml
│ ├── memory.x
│ ├── openocd.cfg
│ ├── openocd.gdb
│ └── src
│ └── main.rs
├── data-analysis
│ ├── Cargo.toml
│ └── src
│ └── main.rs
├── README.md
└── resources
├── 3m.mkd
├── data-stm32f103c8t6.pdf
├── links.txt
├── reference-stm32f103xx.pdf
├── schematic-stm32f103c8t6.png
└── todo.txt
I have decided to use a workspace to organize my code. When I attempt to build the workspace, I get the error:
error[E0463]: can't find crate for `std`
|
= note: the `thumbv7m-none-eabi` target may not support the standard library
= note: `std` is required by `data_analysis` because it does not declare `#![no_std]`
= help: consider building the standard library from source with `cargo build -Zbuild-std`
When I compile with cargo build -Zbuild-std I get the error:
error[E0463]: can't find crate for `panic_abort`
error[E0658]: use of unstable library feature 'restricted_std'
|
= help: add `#![feature(restricted_std)]` to the crate attributes to enable
However I need no_std and not restricted_std.
I understand that dependencies for all files are stored in Cargo.lock and presumably that's why it is producing this error. My question is, how do I express to the compiler that I need std for data_analysis but not for chip code? Should I even be using workspaces over just using one package with multiple binaries and using [features] in the Cargo.toml?
It seems like you're trying to complile data_analysis with the same target as chip. I recommend just getting rid of the root Cargo.toml and compiling the respective ones in the folders. You could make a Makefile to automate this easily
Related
I have a Cargo workspaces project with the structure:
├── src
├── lib
│ └── Cargo.toml
├── tools
│ ├── src/bin/foo.rs
│ └── Cargo.toml
└── Cargo.toml
., lib and tools are my three workspace members. lib has a feature that enables tracing of the execution of a performance-sensitive function. As this feature adds performance overhead, the main binary should not enable it, but the foo binary is a testing tool which uses it.
However, Cargo workspaces take the union of the features of the two binaries, so the main binary ends up including the feature anyway.
How can I fix this?
I'm developing a library. For internal development experiments I need a bunch of binary command line entry points that I can execute. I'm using a standard project layout like described in this answer under "Flexible".
What I'd like to achieve: Certain functionality in my command line tools is similar, and I'd like to move that out into its own module. Ideally I'd like to introduce a cli_common.rs module containing some helper functions here in the package structure:
.
├── Cargo.toml
└── src
├── bin
│ ├── cli_common.rs
│ ├── run_foo.rs (uses cli_common)
│ └── run_bar.rs (uses cli_common)
├── lib.rs
└── <various-lib-related-sub-modules>
This doesn't seem to be possible, because the compiler expects every module under bin to have a main function.
This suggest that I have to move the functionality of cli_common.rs into the library itself. This doesn't feel great, because it mixes "peripheral" logic with "core" logic, and I'd like to avoid having this functionality as part of the public interface of the library.
Is there a trick to have such a cli_commons.rs without having to move it into the library?
I found a solution based on this answer.
For simple cases, an extra crate can be avoided by moving the cli_common.rs somewhere, where the compiler doesn't expect a main. In my example I modified the structure for instance to:
.
├── Cargo.toml
└── src
├── bin
│ ├── cli_common.rs
│ │ └── cli_common.rs
│ ├── run_foo.rs
│ └── run_bar.rs
├── lib.rs
└── <various-lib-related-sub-modules>
Within run_foo.rs and run_bar.rs, I can now use mod combined with a #[path] attribute:
#[path="cli_common/cli_common.rs"]
mod cli_common;
For more complex scenarios, going for a separate crate may be preferred.
I have a barebones workspace project:
.
├── build-debug.sh
├── Cargo.lock
├── Cargo.toml
├── common
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
├── rs-test.iml
├── server
│ ├── Cargo.toml
│ └── src
│ └── main.rs
└── wui
├── Cargo.toml
└── src
└── lib.rs
The rs files either empty or just an empty main function.
The server and the wui depends on common: common = { path = "../common" }.
The common project has one crates.io dependency with I suppose build script or proc macro dependency.
The build script:
cargo build -p wui --target wasm32-unknown-unknown
cargo build -p server
The problem:
When I rebuild the unchanged project, some wui dependencies are getting invalidated/rebuilt, then the same for server.
Either:
remove the wasm32 target flag
replace the dependency with a simple crate without build time compiled dependencies
It does not rebuild the subprojects anymore.
Is this a cargo bug? What can I do?
It's probably not a cargo bug. What is likely happening here is that your crates.io dependency (you don't mention what it is, which might have been useful) has different dependencies or features depending on the target architecture. Thus, as you alternate between building the WASM target and your host target, stuff is being rebuilt.
Perhaps it would be better in this case to stop using the Cargo workspace and build the server and wui separately; this way you'll have separate target directories for the server and wui, which takes some extra disk space and takes longer for non-incremental compilation, but will prevent you from having to rebuild that stuff all the time as you build both.
Let's say there is a vendored third-party cargo project consisting of a library plem and a binary plem_main that I want to extend with some functionality of my own. Crucially, the functionality needs to go in the library plem, not the binary plem_main (which can stay the same). I could write a wrapper my_plem around the library that offers the same interface to the binary, but with the extra functionality included. The project would be set up like this:
.
├── Cargo.toml
├── my_plem
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
└── third-party
├── plem
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
└── plem_main
├── Cargo.toml
└── src
└── main.rs
my_plem/src/lib.rs would depend on things in third-party/plem/src/lib.rs and reexport or overwrite the functions exported by the latter. Is there a good way to get cargo to build the binary plem_main on top of my_plem instead of plem?
"Best" here means that the solution has no or minimal merge conflicts when updating plem in my project and doesn't duplicate the code of plem_main. Ideally it does not touch third-party at all.
The directory layout of a Rust project should look like this (source)
.
├── Cargo.lock
├── Cargo.toml
├── benches
│ └── large-input.rs
├── examples
│ └── simple.rs
├── src
│ ├── bin
│ │ └── another_executable.rs
│ ├── lib.rs
│ └── main.rs
└── tests
└── some-integration-tests.rs
What is the file simple.rs under examples? How do I execute it? How should the file look like?
Examples are useful in library crates to show how the crate is used.
An example can be an executable with a main method or a library; it can either be in a single file examples/example-name.rs or consist of several files in a subdirectory examples/example-name/, with the main method in main.rs. To compile a library example you need to specify its crate type in Cargo.toml:
[[example]]
name = "example-name"
crate-type = ["lib"]
Examples are compiled by cargo test to ensure that they are up to date with the crate. You can run a specific executable example by
cargo run --example <example-name>
and selectively build any example with
cargo build --example <example-name>
This is documented in the Cargo Reference.