cargo/ops/
cargo_run.rs
1use std::ffi::OsString;
2use std::fmt::Write as _;
3use std::iter;
4use std::path::Path;
5
6use crate::core::compiler::UnitOutput;
7use crate::core::{TargetKind, Workspace};
8use crate::ops;
9use crate::util::CargoResult;
10
11pub fn run(
12 ws: &Workspace<'_>,
13 options: &ops::CompileOptions,
14 args: &[OsString],
15) -> CargoResult<()> {
16 let gctx = ws.gctx();
17
18 if options.filter.contains_glob_patterns() {
19 anyhow::bail!("`cargo run` does not support glob patterns on target selection")
20 }
21
22 let packages = options.spec.get_packages(ws)?;
25 let bins: Vec<_> = packages
26 .into_iter()
27 .flat_map(|pkg| {
28 iter::repeat(pkg).zip(pkg.manifest().targets().iter().filter(|target| {
29 !target.is_lib()
30 && !target.is_custom_build()
31 && if !options.filter.is_specific() {
32 target.is_bin()
33 } else {
34 options.filter.target_run(target)
35 }
36 }))
37 })
38 .collect();
39
40 if bins.is_empty() {
41 if !options.filter.is_specific() {
42 anyhow::bail!("a bin target must be available for `cargo run`")
43 } else {
44 }
46 }
47
48 if bins.len() == 1 {
49 let target = bins[0].1;
50 if let TargetKind::ExampleLib(..) = target.kind() {
51 anyhow::bail!(
52 "example target `{}` is a library and cannot be executed",
53 target.name()
54 )
55 }
56 }
57
58 if bins.len() > 1 {
59 if !options.filter.is_specific() {
60 let mut names: Vec<&str> = bins
61 .into_iter()
62 .map(|(_pkg, target)| target.name())
63 .collect();
64 names.sort();
65 anyhow::bail!(
66 "`cargo run` could not determine which binary to run. \
67 Use the `--bin` option to specify a binary, \
68 or the `default-run` manifest key.\n\
69 available binaries: {}",
70 names.join(", ")
71 )
72 } else {
73 let mut message = "`cargo run` can run at most one executable, but \
74 multiple were specified"
75 .to_owned();
76 write!(&mut message, "\nhelp: available targets:")?;
77 for (pkg, bin) in &bins {
78 write!(
79 &mut message,
80 "\n {} `{}` in package `{}`",
81 bin.kind().description(),
82 bin.name(),
83 pkg.name()
84 )?;
85 }
86 anyhow::bail!(message)
87 }
88 }
89
90 options.build_config.single_requested_kind()?;
92
93 let compile = ops::compile(ws, options)?;
94 assert_eq!(compile.binaries.len(), 1);
95 let UnitOutput {
96 unit,
97 path,
98 script_meta,
99 } = &compile.binaries[0];
100 let exe = match path.strip_prefix(gctx.cwd()) {
101 Ok(path) if path.file_name() == Some(path.as_os_str()) => Path::new(".").join(path),
102 Ok(path) => path.to_path_buf(),
103 Err(_) => path.to_path_buf(),
104 };
105 let pkg = bins[0].0;
106 let mut process = compile.target_process(exe, unit.kind, pkg, *script_meta)?;
107
108 process.args(args).cwd(gctx.cwd());
113
114 if gctx.extra_verbose() {
115 process.display_env_vars();
116 }
117
118 gctx.shell().status("Running", process.to_string())?;
119
120 process.exec_replace()
121}