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 #[cfg(not(any(windows, unix)))]
141 {
142 return false;
143 }
144
145 #[cfg(unix)]
149 {
150 let ptr_size = mem::size_of::<usize>();
151 let args_size = self.args.iter().fold(0usize, |acc, a| {
153 let arg = a.as_encoded_bytes().len();
154 let nul = 1;
155 acc.saturating_add(arg).saturating_add(nul).saturating_add(ptr_size)
156 });
157 let envs_size = self.env.iter().fold(0usize, |acc, (k, v)| {
159 let k = k.as_encoded_bytes().len();
160 let eq = 1;
161 let v = v.as_encoded_bytes().len();
162 let nul = 1;
163 acc.saturating_add(k)
164 .saturating_add(eq)
165 .saturating_add(v)
166 .saturating_add(nul)
167 .saturating_add(ptr_size)
168 });
169 let arg_max = match unsafe { libc::sysconf(libc::_SC_ARG_MAX) } {
170 -1 => return false, max => max as usize,
172 };
173 return args_size.saturating_add(envs_size) > arg_max;
174 }
175
176 #[cfg(windows)]
199 {
200 let estimated_command_line_len = self
201 .args
202 .iter()
203 .fold(0usize, |acc, a| acc.saturating_add(a.as_encoded_bytes().len()));
204 return estimated_command_line_len > 1024 * 6;
205 }
206 }
207}
208
209impl fmt::Debug for Command {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 self.command().fmt(f)
212 }
213}