Skip to content

Add cargo run --example and cargo run --bin #702

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 29, 2014

Conversation

tomassedovic
Copy link
Contributor

This lets users run any executable from the examples or bin directories by
passing its name with --example or --bin flag.

If neither is specified, we fall back to the old behaviour (running the only bin
target in the project, failing if there are more).

Closes #538

@tomassedovic
Copy link
Contributor Author

Hm, the Travis failures seem to be unrelated to this change and I've seen them it other PRs as well. What's the protocol here?

@alexcrichton you suggested this in #538, r?

@alexcrichton
Copy link
Member

Ah yes sorry, I've been meaning to get around to this! I think it's safe to ignore the travis failures.

This is quite similar to #685 (cc @LexxFedoroff) in its goal of "run just one specific target", and I'd like to consider both together to make sure that we've got a consistent story across all the cargo commands. This PR, for example, only modifies cargo run, while #685 also adds selective ability to cargo {bench,build,test}. The strategy taken in #685 is to name everything -t, while here it takes the strategy --bin and --example.

I think I might pefer the --foo over --target-name or -t slightly because it allows us to add more in the future, and it prevents clashes between namespaces (both an example and a bin named foo for example).

So all in all, @LexxFedoroff, how do you feel about moving from --target-name/-t to --bin and --example as necessary? I suppose one of the odd ones out is cargo test --test foo to run only a specific test.

cc @wycats, I'm curious if you have an opinion here.

@tomassedovic
Copy link
Contributor Author

Sorry, I thought that pull request was about the target triples.

Yeah, being able to build/run a specific command, test or benchmark would be great. I prefer specifying the binary type (example, bin, test), too. At least in cargo run and build.

Maybe we could use something like -t for the cases where you're only ever expected to deal with one type of executable, though. I.e. cargo test / bench today. That would let us avoid the awkwardness of cargo test --test foo.

@alexcrichton
Copy link
Member

I was chatting with @wycats about this, and I think your intuitions is right @tomassedovic, the common case should be the same. We ended up realizing that the "odd one out" are examples, so how about:

  • cargo run accepts --name (for bins) and --example (for examples)
  • cargo {test,bench} accepts --name (for tests/benches), and --example (for examples, maybe only test?)

We may want to avoid cargo build for now, though, as you could build any number of targets. We could always add --<type> later!

Does that sound ok?

@tomassedovic
Copy link
Contributor Author

Sounds good to me! Not quite sure about having --example in test/bench. I'd just add --name there, we can add examples later if they're needed.

@LexxFedoroff, I don't want to step on your toes (your patch came first, I should have noticed). If this makes sense to you, do you want to pick it up?

@LexxFedoroff
Copy link

@tomassedovic I like your approach, I do not mind if you do this.

@tomassedovic
Copy link
Contributor Author

Allright, will do!

@vhbit
Copy link
Contributor

vhbit commented Oct 20, 2014

@tomassedovic please add also --lib option - it's quite useful for cross-compiling when binaries are used only on host and don't need to be built for target.

@tomassedovic
Copy link
Contributor Author

@vhbit where do you want to add it?

If I understand it correctly, the current plan is this:

  • cargo run --name foo will compile & run src/bin/foo.rs (or [[bin]] with name = foo)
  • cargo run --example foo will compile & run examples/foo.rs
  • cargo test --name foo will compile & run tests/foo.rs
  • cargo bench --name foo will compile &run tests/foo.rs and pass --bench to the executable

I'm not sure I understand what should --lib do to any of these commands. Can you be a bit more specific, please?

@vhbit
Copy link
Contributor

vhbit commented Oct 20, 2014

@tomassedovic I though of cargo build --lib

@vhbit
Copy link
Contributor

vhbit commented Oct 20, 2014

sorry I wasn't clear enough, I see this PR as a way to get a "focused" output out of all possibilities and in my use case getting just lib without binaries at all perfectly fits it.

@tomassedovic
Copy link
Contributor Author

Ah, I see. That would be better as a separate change, I think.

This PR is more about being able to run stuff (where stuff = test, example and "normal" binaries). Adding --lib to cargo-build would touch different parts of the codebase.

@alexcrichton
Copy link
Member

@vhbit could you open an issue on that as well to track it? Seems like something good to have!

@vhbit
Copy link
Contributor

vhbit commented Oct 20, 2014

@alexcrichton here it is #724

@alexcrichton
Copy link
Member

Thanks!

@tomassedovic
Copy link
Contributor Author

Oops, I meant to squash the fixup commit up. Will fix that in a later revision.

Anyway, this is pretty much what we agreed on. There seems to be an issue when we have a bin and an example with the same name, but everything else seems to be working.

I rebased the --example changes on top of @LexxFedoroff's stuff since they did most of the work.

}).collect::<Vec<&Target>>();
let targets = to_build.get_targets().iter()
.filter(|target| {
let name_eq = name.is_none() || (name.unwrap() == target.get_name());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could avoid an unwrap with name.is_none() || name == Some(target.get_name())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some(target.get_name()) results in a lifetime error in a seemingly unrelated bit of code above ("packages does not live long enough" in line 121).

map_or works fine though, so I haven't bothered to investigate it:

 let name_eq = name.map_or(true, |name| name == target.get_name());

(FWIW, I don't mind switching to a full match, if map_or is too cryptic)

@alexcrichton
Copy link
Member

This looks fantastic, thanks so much @tomassedovic!

The test failure on travis looks somewhat worrying, can you reproduce it locally?

@tomassedovic
Copy link
Contributor Author

Oh interesting. I've seen the same error Travis reports once but then it went away. Removing the target directory and running make test from a clean slate reproduced it locally again. I'll investigate this later.

@tomassedovic
Copy link
Contributor Author

Hm, this is bizarre. So with your suggestions applied, the last test that was failing for me is fixed and I can no longer reproduce the Travis failure with make test.

However, when I created a cargo project with identically-named bin and example executables, I'm hitting a multitude of issues.

$ cat Cargo.toml:
[package]

name = "binex"
version = "0.0.1"
authors = ["Tomas Sedovic <[email protected]>"]
$ tree
.
├── Cargo.lock
├── Cargo.toml
├── examples
│   └── foo.rs
└── src
    ├── bin
    │   └── foo.rs
    └── main.rs

The problems only seems to happen on a clean checkout and only if we run the example first. A race condition of some kind seems to be involved since I'm getting four different behaviours:

  1. unlink failures, but the example gets compiled and executed:
$ rm -rf target/ && cargo run --verbose --example foo
   Compiling binex v0.0.1 (file:///home/thomas/tmp/binex)
     Running `rustc /home/thomas/tmp/binex/src/bin/foo.rs --crate-name foo --crate-type bin -g --test -C metadata=4e533bdbd69b0b27 -C extra-filename=-4e533bdbd69b0b27 --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-test-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
     Running `rustc /home/thomas/tmp/binex/src/bin/foo.rs --crate-name foo --crate-type bin -g --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
     Running `rustc /home/thomas/tmp/binex/examples/foo.rs --crate-name foo --crate-type bin -g --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
/home/thomas/tmp/binex/src/bin/foo.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
/home/thomas/tmp/binex/src/bin/foo.rs:1 fn main() {
/home/thomas/tmp/binex/src/bin/foo.rs:2     println!("this is a binary");
/home/thomas/tmp/binex/src/bin/foo.rs:3 }
error: failed to remove /home/thomas/tmp/binex/target/foo.o: couldn't unlink path (no such file or directory (No such file or directory); path=/home/thomas/tmp/binex/target/foo.o)
error: failed to remove /home/thomas/tmp/binex/target/foo.metadata.o: couldn't unlink path (no such file or directory (No such file or directory); path=/home/thomas/tmp/binex/target/foo.metadata.o)
     Running `target/foo`
This is an example
  1. the same as above but the binary is run instead:
$ rm -rf target/ && cargo run --verbose --example foo
   Compiling binex v0.0.1 (file:///home/thomas/tmp/binex)
     Running `rustc /home/thomas/tmp/binex/src/bin/foo.rs --crate-name foo --crate-type bin -g --test -C metadata=4e533bdbd69b0b27 -C extra-filename=-4e533bdbd69b0b27 --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-test-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
     Running `rustc /home/thomas/tmp/binex/src/bin/foo.rs --crate-name foo --crate-type bin -g --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
     Running `rustc /home/thomas/tmp/binex/examples/foo.rs --crate-name foo --crate-type bin -g --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
/home/thomas/tmp/binex/src/bin/foo.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
/home/thomas/tmp/binex/src/bin/foo.rs:1 fn main() {
/home/thomas/tmp/binex/src/bin/foo.rs:2     println!("this is a binary");
/home/thomas/tmp/binex/src/bin/foo.rs:3 }
error: failed to remove /home/thomas/tmp/binex/target/foo.o: couldn't unlink path (no such file or directory (No such file or directory); path=/home/thomas/tmp/binex/target/foo.o)
error: failed to remove /home/thomas/tmp/binex/target/foo.metadata.o: couldn't unlink path (no such file or directory (No such file or directory); path=/home/thomas/tmp/binex/target/foo.metadata.o)
     Running `target/foo`
this is a binary
  1. The ICE which Travis exposed:
$ rm -rf target/ && cargo run --verbose --example foo
   Compiling binex v0.0.1 (file:///home/thomas/tmp/binex)
     Running `rustc /home/thomas/tmp/binex/src/bin/foo.rs --crate-name foo --crate-type bin -g --test -C metadata=4e533bdbd69b0b27 -C extra-filename=-4e533bdbd69b0b27 --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-test-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
     Running `rustc /home/thomas/tmp/binex/src/bin/foo.rs --crate-name foo --crate-type bin -g --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
     Running `rustc /home/thomas/tmp/binex/examples/foo.rs --crate-name foo --crate-type bin -g --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
/home/thomas/tmp/binex/src/bin/foo.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
/home/thomas/tmp/binex/src/bin/foo.rs:1 fn main() {
/home/thomas/tmp/binex/src/bin/foo.rs:2     println!("this is a binary");
/home/thomas/tmp/binex/src/bin/foo.rs:3 }
error: internal compiler error: unexpected failure
note: the compiler hit an unexpected failure path. this is a bug.
note: we would appreciate a bug report: http://doc.rust-lang.org/complement-bugreport.html
note: run with `RUST_BACKTRACE=1` for a backtrace
task 'rustc' failed at 'called `Result::unwrap()` on an `Err` value: couldn't copy path (the source path is not an existing file; from=/home/thomas/tmp/binex/target/foo.0.o; to=/home/thomas/tmp/binex/target/foo.o)', /home/rustbuild/src/rust-buildbot/slave/nightly-linux/build/src/libcore/result.rs:808


Build failed, waiting for other jobs to finish...
Could not compile `binex`.

Caused by:
  Process didn't exit successfully: `rustc /home/thomas/tmp/binex/examples/foo.rs --crate-name foo --crate-type bin -g --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps` (status=101)
$ rm -rf target/ && cargo run --verbose --example foo
   Compiling binex v0.0.1 (file:///home/thomas/tmp/binex)
     Running `rustc /home/thomas/tmp/binex/src/bin/foo.rs --crate-name foo --crate-type bin -g --test -C metadata=4e533bdbd69b0b27 -C extra-filename=-4e533bdbd69b0b27 --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-test-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
     Running `rustc /home/thomas/tmp/binex/src/bin/foo.rs --crate-name foo --crate-type bin -g --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
     Running `rustc /home/thomas/tmp/binex/examples/foo.rs --crate-name foo --crate-type bin -g --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
/home/thomas/tmp/binex/src/bin/foo.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
/home/thomas/tmp/binex/src/bin/foo.rs:1 fn main() {
/home/thomas/tmp/binex/src/bin/foo.rs:2     println!("this is a binary");
/home/thomas/tmp/binex/src/bin/foo.rs:3 }
error: internal compiler error: unexpected failure
note: the compiler hit an unexpected failure path. this is a bug.
note: we would appreciate a bug report: http://doc.rust-lang.org/complement-bugreport.html
note: run with `RUST_BACKTRACE=1` for a backtrace
task 'rustc' failed at 'called `Result::unwrap()` on an `Err` value: couldn't copy path (the source path is not an existing file; from=/home/thomas/tmp/binex/target/foo.0.o; to=/home/thomas/tmp/binex/target/foo.o)', /home/rustbuild/src/rust-buildbot/slave/nightly-linux/build/src/libcore/result.rs:808


Build failed, waiting for other jobs to finish...
Could not compile `binex`.

Caused by:
  Process didn't exit successfully: `rustc /home/thomas/tmp/binex/examples/foo.rs --crate-name foo --crate-type bin -g --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps` (status=101)
  1. The same ICE but now we also get linking errors:
$ rm -rf target/ && cargo run --verbose --example foo
   Compiling binex v0.0.1 (file:///home/thomas/tmp/binex)
     Running `rustc /home/thomas/tmp/binex/src/bin/foo.rs --crate-name foo --crate-type bin -g --test -C metadata=4e533bdbd69b0b27 -C extra-filename=-4e533bdbd69b0b27 --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-test-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
     Running `rustc /home/thomas/tmp/binex/src/bin/foo.rs --crate-name foo --crate-type bin -g --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
     Running `rustc /home/thomas/tmp/binex/examples/foo.rs --crate-name foo --crate-type bin -g --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps`
/home/thomas/tmp/binex/src/bin/foo.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
/home/thomas/tmp/binex/src/bin/foo.rs:1 fn main() {
/home/thomas/tmp/binex/src/bin/foo.rs:2     println!("this is a binary");
/home/thomas/tmp/binex/src/bin/foo.rs:3 }
error: linking with `cc` failed: exit code: 1
error: internal compiler error: unexpected failure
note: the compiler hit an unexpected failure path. this is a bug.
note: we would appreciate a bug report: http://doc.rust-lang.org/complement-bugreport.html
note: run with `RUST_BACKTRACE=1` for a backtrace
note: task 'rustc' failed at 'called `Result::unwrap()` on an `Err` value: couldn't copy path (the source path is not an existing file; from=/home/thomas/tmp/binex/target/foo.0.o; to=/home/thomas/tmp/binex/target/foo.o)', /home/rustbuild/src/rust-buildbot/slave/nightly-linux/build/src/libcore/result.rs:808


cc '-m64' '-L' '/usr/local/rust-nightlies/2014-10-19/lib/rustlib/x86_64-unknown-linux-gnu/lib' '-o' '/home/thomas/tmp/binex/target/foo' '/home/thomas/tmp/binex/target/foo.o' '-Wl,--whole-archive' '-lmorestack' '-Wl,--no-whole-archive' '-nodefaultlibs' '-fno-lto' '-Wl,--gc-sections' '-pie' '-Wl,--as-needed' '/usr/local/rust-nightlies/2014-10-19/lib/rustlib/x86_64-unknown-linux-gnu/lib/libnative-4e7c5e5c.rlib' '/usr/local/rust-nightlies/2014-10-19/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-4e7c5e5c.rlib' '/usr/local/rust-nightlies/2014-10-19/lib/rustlib/x86_64-unknown-linux-gnu/lib/libsync-4e7c5e5c.rlib' '/usr/local/rust-nightlies/2014-10-19/lib/rustlib/x86_64-unknown-linux-gnu/lib/librand-4e7c5e5c.rlib' '/usr/local/rust-nightlies/2014-10-19/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustrt-4e7c5e5c.rlib' '/usr/local/rust-nightlies/2014-10-19/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcollections-4e7c5e5c.rlib' '/usr/local/rust-nightlies/2014-10-19/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunicode-4e7c5e5c.rlib' '/usr/local/rust-nightlies/2014-10-19/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-4e7c5e5c.rlib' '/usr/local/rust-nightlies/2014-10-19/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-4e7c5e5c.rlib' '/usr/local/rust-nightlies/2014-10-19/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-4e7c5e5c.rlib' '-L' '/home/thomas/tmp/binex/target' '-L' '/home/thomas/tmp/binex/target/deps' '-L' '/home/thomas/tmp/binex/.rust' '-L' '/home/thomas/tmp/binex' '-Wl,--whole-archive' '-Wl,-Bstatic' '-Wl,--no-whole-archive' '-Wl,-Bdynamic' '-ldl' '-lpthread' '-lgcc_s' '-lpthread' '-lc' '-lm' '-lcompiler-rt'
note: /home/thomas/tmp/binex/target/foo.o: file not recognized: File truncated
collect2: error: ld returned 1 exit status

error: aborting due to previous error
Build failed, waiting for other jobs to finish...
Could not compile `binex`.

Caused by:
  Process didn't exit successfully: `rustc /home/thomas/tmp/binex/examples/foo.rs --crate-name foo --crate-type bin -g --out-dir /home/thomas/tmp/binex/target --dep-info /home/thomas/tmp/binex/target/.fingerprint/binex-b1251a4d3a989eef/dep-bin-foo -L /home/thomas/tmp/binex/target -L /home/thomas/tmp/binex/target/deps` (status=101)

However, when I try to run (and compile) the bin first, running the example succeeds every time:

$ rm -rf target/ && cargo run --name foo && cargo run --example foo
   Compiling binex v0.0.1 (file:///home/thomas/tmp/binex)
     Running `target/foo`
this is a binary
   Compiling binex v0.0.1 (file:///home/thomas/tmp/binex)
/home/thomas/tmp/binex/src/bin/foo.rs:1:1: 3:2 warning: function is never used: `main`, #[warn(dead_code)] on by default
/home/thomas/tmp/binex/src/bin/foo.rs:1 fn main() {
/home/thomas/tmp/binex/src/bin/foo.rs:2     println!("this is a binary");
/home/thomas/tmp/binex/src/bin/foo.rs:3 }
     Running `target/foo`
This is an example

Although as the warning suggests, we seem to be compiling the bin again in a test environment.

This also suggests a possibility that the reason make test worked for me was just that I've been lucky the few times I tried it.

I'll upload the code I have now and will return to this later. Though if anything jumps out at you, please point it out. I've no idea what's going on here.

@alexcrichton
Copy link
Member

That definitely looks like a race, and I think it has to do with two targets having the same output filename, and you're right in that it looks like src/bin/foo.rs is being compiled twice (once for a test and once without).

I'll take a look at the patch again to see if I can tell what's going on.

All of the trailing arguments are passed as to the binary to run.
";

pub fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
shell.set_verbose(options.flag_verbose);
let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
let env = if options.flag_example.is_some() {
"test"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be one point of failure for the race. If you're filtering for all targets with the name "foo" with the "test" environment you'll get the example "foo" as well as the test case for "foo" itself. To help weed this out, could you add -v to your test cases to make sure the compiler is invoked only once when you request just one example? That should help ensure that only one target is actually compiled.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes and the other case is happening because there's a Target for each binary with test env because the examples and/or tests could actually rely on the binaries themselves.

So what should happen here is:

  • When I run cargo run --name foo, it should only compile the binary target named foo.
  • When I run cargo run --example foo, it should compile all binaries, and then compile the example named foo, but none of the test binaries should be built.

Does that make sense? I do think that the usage of many many Targets is somewhat confusing, sorry about that!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. Also, I've just noticed that cargo run --name or --example fails if the file contains extern crate project_name.

Looks like the modification to cargo_compile.rs in the first commit is not behaving as desired. I'll give this some more thought.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I think that would indeed make sense! You may want to alter cargo_compile to have a bit of a two-phase filtering strategy. The first pass would be the same as today (filtering based on the environment), and the second pass would be filtering based off the name requested. If --name was requested with cargo run then the only thing that should be filtered out is other binaries (and the same for tests), but libraries should stick around.

Could you add tests for these cases as well? Thanks for being so thorough with this!

@tomassedovic
Copy link
Contributor Author

Good points, thanks.

Looks like Cargo isn't currently geared towards different things (tests, bins, examples) having the same name.

  1. The race is present in master, too
  2. Do we even want to support multiple things of the same name? Even if we do manage to run the build deterministically (tough with parallel building on), multiple targets will end up having the same destination which means they'll keep overwriting each other.

I've opened issue #751 to track that and I'll update this PR based on how it turns out.

@alexcrichton
Copy link
Member

Now that #758 has landed, I think this just needs a rebase and its good to go!

@tomassedovic
Copy link
Contributor Author

Okay, this seems to survive everything I throw at it.

It's a bit different from the previous versions: I dropped the modifications to cargo_compile. When the user passes --name or --example to cargo run/test/bench, the corresponding run function will pick and run the executable.

I did that because the logic for picking the right target is a bit different for cargo run and cargo test and it means we don't have to update all the other subcommands.

"#)
.file("src/bin/b.rs", r#"
fn main() { println!("hello b.rs"); }
"#);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a couple of extern crate foo in here to ensure that the lib is built for the bins?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, done.

@alexcrichton
Copy link
Member

Are the semantics here that if you have 100 bins that cargo run --name foo actually builds all 100, but only runs one? (same for tests, etc). For tests this could be an extreme pain point as to run a subset of the tests you may want to run cargo test --name foo but that'll still end up building all the tests.


assert_that(prj.cargo_process("test").arg("--name").arg("bin2"),
execs().with_status(0).with_stdout(expected_stdout.as_slice()));
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add a test for tests/a.rs and tests/b.rs and run cargo test --name a? It may also be worth adding src/bin/a.rs and tests/a.rs and make sure that --name doesn't generate an error, running both is ok to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

@tomassedovic
Copy link
Contributor Author

You're right that this compiles all the targets, not just the one being run. I was originally thinking of this as: cargo build && ./target/foo with dynamic libraries and everything else set up correctly.

But yeah, if you have a bunch of targets, this can take longer than necessary.

On the other hand, can we merge this in the meantime (if you're happy with the code) and add the optimization as a separate change? It'll probably take me some more time to figure out what needs to be changed, add the right tests, etc.

@alexcrichton
Copy link
Member

On the other hand, can we merge this in the meantime

Sure! Thanks again for this, this is great!

This lets us compile and run examples using `cargo run --example NAME`.
Selecting the other binary targets is now done using the `--name` flag.

`cargo run` falls back to the old behaviour (running the only bin target
in the project, failing if there are more) in neither `--name` nor
`--example` are present.

Closes rust-lang#538

assert_that(prj.cargo_process("test").arg("--name").arg("b"),
execs().with_status(0).with_stdout(expected_stdout.as_slice()));
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this tests is failing because either the bin or test is running first (nondeterministically). I'm also curious, shouldn't this have a {running} target[..]b-[..] for the second command that's being run?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the nondeterminism is caused by the suffix (e.g. b-5ceb27d70f3864a2 vs. b-f1d1a5ae2be55cf5) that gets added to the file name. The paths are being sorted:

https://github.com/rust-lang/cargo/pull/702/files#diff-417e085367d0ce027505dfaa26a089d3R22

I'm not sure where the suffix comes from -- is that something we can control so the order is consistent? Good point about the missing {running} section. When I just tried it manually, it's there, but the tests didn't complain.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm weird, maybe our matching algorithm for the tests isn't quite up to par... I suppose the metadata (the extra stem of the filename) could be different across platforms, so it could probably run out of order yeah. Could you modify it so that both the test and the bin b have one test of the same name so the output is the same? that way we don't have to worry about sorting

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha, that's neat. Done.

You can now run a single test/bench file by passing its name to `cargo
test` or `cargo bench`.
bors added a commit that referenced this pull request Oct 29, 2014
This lets users run any executable from the `examples` or `bin` directories by
passing its name with `--example` or `--bin` flag.

If neither is specified, we fall back to the old behaviour (running the only bin
target in the project, failing if there are more).

Closes #538
@bors bors merged commit f93506a into rust-lang:master Oct 29, 2014
@tomassedovic tomassedovic deleted the run-examples branch October 29, 2014 21:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

cargo should be able to run examples
5 participants