1use std::ffi::OsString;
2use std::iter;
3use std::path::Path;
45use crate::core::compiler::UnitOutput;
6use crate::core::{TargetKind, Workspace};
7use crate::ops;
8use crate::util::CargoResult;
910pub fn run(
11 ws: &Workspace<'_>,
12 options: &ops::CompileOptions,
13 args: &[OsString],
14) -> CargoResult<()> {
15let gctx = ws.gctx();
1617if options.filter.contains_glob_patterns() {
18anyhow::bail!("`cargo run` does not support glob patterns on target selection")
19 }
2021// We compute the `bins` here *just for diagnosis*. The actual set of
22 // packages to be run is determined by the `ops::compile` call below.
23let packages = options.spec.get_packages(ws)?;
24let 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();
3839if bins.is_empty() {
40if !options.filter.is_specific() {
41anyhow::bail!("a bin target must be available for `cargo run`")
42 } else {
43// This will be verified in `cargo_compile`.
44}
45 }
4647if bins.len() == 1 {
48let target = bins[0].1;
49if let TargetKind::ExampleLib(..) = target.kind() {
50anyhow::bail!(
51"example target `{}` is a library and cannot be executed",
52 target.name()
53 )
54 }
55 }
5657if bins.len() > 1 {
58if !options.filter.is_specific() {
59let mut names: Vec<&str> = bins
60 .into_iter()
61 .map(|(_pkg, target)| target.name())
62 .collect();
63 names.sort();
64anyhow::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 {
72anyhow::bail!(
73"`cargo run` can run at most one executable, but \
74 multiple were specified"
75)
76 }
77 }
7879// `cargo run` is only compatible with one `--target` flag at most
80options.build_config.single_requested_kind()?;
8182let compile = ops::compile(ws, options)?;
83assert_eq!(compile.binaries.len(), 1);
84let UnitOutput {
85 unit,
86 path,
87 script_meta,
88 } = &compile.binaries[0];
89let exe = match path.strip_prefix(gctx.cwd()) {
90Ok(path) if path.file_name() == Some(path.as_os_str()) => Path::new(".").join(path),
91Ok(path) => path.to_path_buf(),
92Err(_) => path.to_path_buf(),
93 };
94let pkg = bins[0].0;
95let mut process = compile.target_process(exe, unit.kind, pkg, *script_meta)?;
9697// Sets the working directory of the child process to the current working
98 // directory of the parent process.
99 // Overrides the default working directory of the `ProcessBuilder` returned
100 // by `compile.target_process` (the package's root directory)
101process.args(args).cwd(gctx.cwd());
102103if gctx.extra_verbose() {
104 process.display_env_vars();
105 }
106107 gctx.shell().status("Running", process.to_string())?;
108109 process.exec_replace()
110}