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