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