rustc_codegen_ssa/back/
command.rs
1use std::ffi::{OsStr, OsString};
5use std::process::{self, Output};
6use std::{fmt, io, mem};
7
8use rustc_target::spec::LldFlavor;
9
10#[derive(Clone)]
11pub(crate) struct Command {
12 program: Program,
13 args: Vec<OsString>,
14 env: Vec<(OsString, OsString)>,
15 env_remove: Vec<OsString>,
16 env_clear: bool,
17}
18
19#[derive(Clone)]
20enum Program {
21 Normal(OsString),
22 CmdBatScript(OsString),
23 Lld(OsString, LldFlavor),
24}
25
26impl Command {
27 pub(crate) fn new<P: AsRef<OsStr>>(program: P) -> Command {
28 Command::_new(Program::Normal(program.as_ref().to_owned()))
29 }
30
31 pub(crate) fn bat_script<P: AsRef<OsStr>>(program: P) -> Command {
32 Command::_new(Program::CmdBatScript(program.as_ref().to_owned()))
33 }
34
35 pub(crate) fn lld<P: AsRef<OsStr>>(program: P, flavor: LldFlavor) -> Command {
36 Command::_new(Program::Lld(program.as_ref().to_owned(), flavor))
37 }
38
39 fn _new(program: Program) -> Command {
40 Command {
41 program,
42 args: Vec::new(),
43 env: Vec::new(),
44 env_remove: Vec::new(),
45 env_clear: false,
46 }
47 }
48
49 pub(crate) fn arg<P: AsRef<OsStr>>(&mut self, arg: P) -> &mut Command {
50 self._arg(arg.as_ref());
51 self
52 }
53
54 pub(crate) fn args<I>(&mut self, args: I) -> &mut Command
55 where
56 I: IntoIterator<Item: AsRef<OsStr>>,
57 {
58 for arg in args {
59 self._arg(arg.as_ref());
60 }
61 self
62 }
63
64 fn _arg(&mut self, arg: &OsStr) {
65 self.args.push(arg.to_owned());
66 }
67
68 pub(crate) fn env<K, V>(&mut self, key: K, value: V) -> &mut Command
69 where
70 K: AsRef<OsStr>,
71 V: AsRef<OsStr>,
72 {
73 self._env(key.as_ref(), value.as_ref());
74 self
75 }
76
77 fn _env(&mut self, key: &OsStr, value: &OsStr) {
78 self.env.push((key.to_owned(), value.to_owned()));
79 }
80
81 pub(crate) fn env_remove<K>(&mut self, key: K) -> &mut Command
82 where
83 K: AsRef<OsStr>,
84 {
85 self._env_remove(key.as_ref());
86 self
87 }
88
89 pub(crate) fn env_clear(&mut self) -> &mut Command {
90 self.env_clear = true;
91 self
92 }
93
94 fn _env_remove(&mut self, key: &OsStr) {
95 self.env_remove.push(key.to_owned());
96 }
97
98 pub(crate) fn output(&mut self) -> io::Result<Output> {
99 self.command().output()
100 }
101
102 pub(crate) fn command(&self) -> process::Command {
103 let mut ret = match self.program {
104 Program::Normal(ref p) => process::Command::new(p),
105 Program::CmdBatScript(ref p) => {
106 let mut c = process::Command::new("cmd");
107 c.arg("/c").arg(p);
108 c
109 }
110 Program::Lld(ref p, flavor) => {
111 let mut c = process::Command::new(p);
112 c.arg("-flavor").arg(flavor.as_str());
113 c
114 }
115 };
116 ret.args(&self.args);
117 ret.envs(self.env.clone());
118 for k in &self.env_remove {
119 ret.env_remove(k);
120 }
121 if self.env_clear {
122 ret.env_clear();
123 }
124 ret
125 }
126
127 pub(crate) fn get_args(&self) -> &[OsString] {
130 &self.args
131 }
132
133 pub(crate) fn take_args(&mut self) -> Vec<OsString> {
134 mem::take(&mut self.args)
135 }
136
137 pub(crate) fn very_likely_to_exceed_some_spawn_limit(&self) -> bool {
140 if cfg!(unix) {
143 return false;
144 }
145
146 if let Program::Lld(..) = self.program {
150 return false;
151 }
152
153 let estimated_command_line_len = self.args.iter().map(|a| a.len()).sum::<usize>();
177 estimated_command_line_len > 1024 * 6
178 }
179}
180
181impl fmt::Debug for Command {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 self.command().fmt(f)
184 }
185}