rust-lang / cargo

The Rust package manager
https://doc.rust-lang.org/cargo
Apache License 2.0
12.75k stars 2.42k forks source link

Different default targets for `cargo build` and `cargo test`? #6784

Open phil-opp opened 5 years ago

phil-opp commented 5 years ago

Describe the problem you are trying to solve

Cargo currently provides a build.target configuration key that allows to change the default target triple. This changes the default target for all cargo commands, including cargo build, cargo run, cargo test and cargo bench. For embedded/OS crates it often makes sense to set that key so that the project is automatically built for the bare-metal target system instead of the host system.

The problem is that one might still want to run the cargo test and cargo bench commands on the host architecture because they depend on std (and thus don't work on the embedded target). Currently the only way to do this is to specify the full host triple on each cargo test invocation, which is not portable across different host systems.

Describe the solution you'd like

It would be nice if there would be an additional build.build-target configuration key that overrides the target only for cargo build, cargo check, and cargo run, but not for cargo test and cargo bench.

Notes

I'm happy to create a PR for this if something like this is desired.

fluffysquirrels commented 5 years ago

In case it helps, I personally solved this issue for embedded development with shell scripts or make files for each scenario, so one for running tests on the host, one for flashing the microcontroller, and so on.

phil-opp commented 5 years ago

Thanks for the suggestion! I want to avoid Makefiles and external scripts when possible, since they are not really portable across OSs. However, I found a different solution to my problem in the custom test framework feature, which allows me to run my tests on the target system.

If nobody else is interested in this issue I will close it in a week.

SomeoneToIgnore commented 5 years ago

Not sure if it helps you to find the motivation to submit the actual PR, but I totally agree that this feature is nice to have. I think at least reopening the issue would be a good thing to do.

phil-opp commented 5 years ago

@SomeoneToIgnore As noted above, I found a better solution to my problem and I don't have the time for implementing a solution to this problem at the moment. However, I already opened a draft PR at https://github.com/rust-lang/cargo/pull/6825, which might be useful if someone wants to implement it (but please consider the review comments in the PR thread).

I'm happy to reopen this issue, though!

torkeldanielsson commented 4 years ago

I would very much like this feature! My target is severely memory constrained so running tests on it is not such a nice proposition.

josephlr commented 4 years ago

We would also find this useful for https://github.com/cloud-hypervisor/rust-hypervisor-firmware.

We want our firmware to be built with one target, and then for our integration tests to be built for the host target.

seanybaggins commented 4 years ago

I am working on this issue. Expect a pull request in the near future.

josephlr commented 4 years ago

@seanybaggins one issue that came up in #6825, is that having a build.build-target key is a little strange. It might make more sense to have a build.test-on-host boolean which will run the cargo test stuff with the host target, while running cargo build uses built.target. Or perhaps a build.test-target key that takes either a triple or "host".

I'm actually not sure which approach is best here, but for both my and @phil-opp's use case, we want to build binaries on the custom target, and then run tests on the host.

EDIT:

Here's a better version of the above idea. Have build.lib-target, build.bin-target, build.test-target, etc... that would essentially be like setting build.target but for only a subset of things cargo builds. Then, we could just set build.lib-target and build.bin-target to be the custom target, while leaving build.test-target blank so the tests could be built for and run on the host. This makes things work like build.target which would essentially act like setting lib-target/bin-target/etc.. all to the same value.

seanybaggins commented 4 years ago

@josephlr This is way better than what I was going to implement. I was going to have a [test] section within the .cargo/config.toml file. This led to some issues for getting the context for when to know to use the [test] config or the [build] config. I will work on just implementing your suggestions.

seanybaggins commented 4 years ago

Just want to double check... we want the .cargo/config.toml build options to be the following?

[build]
jobs = 1                  # number of parallel jobs, defaults to # of CPUs
rustc = "rustc"           # the rust compiler tool
rustc-wrapper = "…"       # run this wrapper instead of `rustc`
rustdoc = "rustdoc"       # the doc generator tool

# Still wondering if this should be just `target` or `build-target`
target = "triple"         # build for the target triple (ignored by `cargo install`)

# Build configs to be added
lib-target = "triple"
bin-target = "triple"
test-target = "triple"

target-dir = "target"     # path of where to place all generated artifacts
rustflags = ["…", "…"]    # custom flags to pass to all compiler invocations
rustdocflags = ["…", "…"] # custom flags to pass to rustdoc
incremental = true        # whether or not to enable incremental compilation
dep-info-basedir = "…"    # path for the base directory for targets in depfiles
pipelining = true         # rustc pipelining
seanybaggins commented 4 years ago

Actually, now that I am looking back through this, is having all of these configuration options necessary? My big motivation is to use the build.target configuration when cargo build or cargo run is invoked by the user. If the user invokes cargo test or cargo bench then I want to use the build.test-target configuration.

When the user invokes cargo build --bin some_binary then you still would want to use the build.target configuration correct?

What if the user invokes cargo test --lib or cargo build --lib? I am not sure lib-target or bin-target are appropriate fields within the configuration file.

seanybaggins commented 4 years ago

So I ended up implementing this and ended up really disliking my implementation. See comments in pull request #8761. I think that cargo-make tool may be the best to achieve the desired behavior.