ninja_writer/build.rs
1//! Implementation of the `build` keyword
2
3use alloc::string::String;
4use core::fmt::{Display, Formatter, Result};
5use core::ops::Deref;
6
7use crate::stmt::{Stmt, StmtRef};
8use crate::util::{AddOnlyVec, Indented, RefCounted};
9use crate::{Rule, RuleVariables, ToArg, Variable, Variables};
10
11/// A build edge, as defined by the `build` keyword
12///
13/// See <https://ninja-build.org/manual.html#_build_statements>
14///
15/// # Example
16/// Since build edges are tied to rules, use [`RuleRef::build`](crate::RuleRef::build) to create them.
17/// ```rust
18/// use ninja_writer::*;
19///
20/// let ninja = Ninja::new();
21/// let cc = ninja.rule("cc", "gcc $cflags -c $in -o $out");
22/// cc.build(["foo.o"]).with(["foo.c"]);
23///
24/// assert_eq!(ninja.to_string(), r###"
25/// rule cc
26/// command = gcc $cflags -c $in -o $out
27///
28/// build foo.o: cc foo.c
29/// "###);
30///
31/// ```
32#[derive(Debug)]
33pub struct Build {
34 /// The rule name
35 pub rule: RefCounted<String>,
36
37 /// The list of outputs, as defined by `build <outputs>:`
38 pub outputs: AddOnlyVec<String>,
39
40 /// The list of implicit outputs.
41 ///
42 /// See <https://ninja-build.org/manual.html#ref_outputs>
43 pub implicit_outputs: AddOnlyVec<String>,
44
45 /// The list of dependencies (inputs).
46 ///
47 /// See <https://ninja-build.org/manual.html#ref_dependencies>
48 pub dependencies: AddOnlyVec<String>,
49
50 /// The list of implicit dependencies (inputs).
51 ///
52 /// See <https://ninja-build.org/manual.html#ref_dependencies>
53 pub implicit_dependencies: AddOnlyVec<String>,
54
55 /// The list of order-only dependencies (inputs).
56 ///
57 /// See <https://ninja-build.org/manual.html#ref_dependencies>
58 pub order_only_dependencies: AddOnlyVec<String>,
59
60 /// The list of validations.
61 ///
62 /// See <https://ninja-build.org/manual.html#validations>
63 pub validations: AddOnlyVec<String>,
64
65 /// The list of variables, as an indented block
66 pub variables: AddOnlyVec<Variable>,
67}
68
69/// Trait for implementing build-specific variables
70pub trait BuildVariables: Variables {
71 /// Internal function for implementing variables for `build`
72 fn as_build(&self) -> &Build;
73
74 /// Specify dynamic dependency file
75 /// # Example
76 /// ```rust
77 /// use ninja_writer::*;
78 ///
79 /// let ninja = Ninja::new();
80 /// let rule = ninja.rule("example", "...");
81 /// rule.build(["foo"]).dyndep("bar");
82 ///
83 /// assert_eq!(ninja.to_string(), r###"
84 /// rule example
85 /// command = ...
86 ///
87 /// build foo: example
88 /// dyndep = bar
89 /// "###);
90 /// ```
91 #[inline]
92 fn dyndep(self, dyndep: impl ToArg) -> Self {
93 self.variable("dyndep", dyndep)
94 }
95
96 /// Add explicit dependencies (inputs)
97 ///
98 /// # Example
99 /// ```rust
100 /// use ninja_writer::*;
101 ///
102 /// let ninja = Ninja::new();
103 /// let rule = ninja.rule("example", "...");
104 /// rule.build(["foo"]).with(["bar", "baz"]);
105 ///
106 /// assert_eq!(ninja.to_string(), r###"
107 /// rule example
108 /// command = ...
109 ///
110 /// build foo: example bar baz
111 /// "###);
112 fn with(self, inputs: impl IntoIterator<Item = impl ToArg>) -> Self {
113 self.as_build()
114 .dependencies
115 .extend(inputs.into_iter().map(|s| s.to_arg()));
116 self
117 }
118
119 /// Add implicit dependencies
120 ///
121 /// See <https://ninja-build.org/manual.html#ref_dependencies>
122 ///
123 /// # Example
124 /// ```rust
125 /// use ninja_writer::*;
126 ///
127 /// let ninja = Ninja::new();
128 /// let rule = ninja.rule("example", "...");
129 /// rule.build(["foo"]).with(["bar", "baz"])
130 /// .with_implicit(["qux"]);
131 ///
132 /// assert_eq!(ninja.to_string(), r###"
133 /// rule example
134 /// command = ...
135 ///
136 /// build foo: example bar baz | qux
137 /// "###);
138 fn with_implicit(self, inputs: impl IntoIterator<Item = impl ToArg>) -> Self {
139 self.as_build()
140 .implicit_dependencies
141 .extend(inputs.into_iter().map(|s| s.to_arg()));
142 self
143 }
144
145 /// Add order-only dependencies
146 ///
147 /// See <https://ninja-build.org/manual.html#ref_dependencies>
148 ///
149 /// # Example
150 /// ```rust
151 /// use ninja_writer::*;
152 ///
153 /// let ninja = Ninja::new();
154 /// let rule = ninja.rule("example", "...");
155 /// rule.build(["foo"]).with(["bar", "baz"])
156 /// .with_order_only(["oo"])
157 /// .with_implicit(["qux"]);
158 ///
159 /// assert_eq!(ninja.to_string(), r###"
160 /// rule example
161 /// command = ...
162 ///
163 /// build foo: example bar baz | qux || oo
164 /// "###);
165 fn with_order_only(self, inputs: impl IntoIterator<Item = impl ToArg>) -> Self {
166 self.as_build()
167 .order_only_dependencies
168 .extend(inputs.into_iter().map(|s| s.to_arg()));
169 self
170 }
171
172 /// Add validations
173 ///
174 /// See <https://ninja-build.org/manual.html#validations>
175 ///
176 /// # Example
177 /// ```rust
178 /// use ninja_writer::*;
179 ///
180 /// let ninja = Ninja::new();
181 /// let rule = ninja.rule("example", "...");
182 /// rule.build(["foo"]).with(["bar", "baz"])
183 /// .with_order_only(["oo"])
184 /// .with_implicit(["qux"])
185 /// .validations(["quux"]);
186 ///
187 /// assert_eq!(ninja.to_string(), r###"
188 /// rule example
189 /// command = ...
190 ///
191 /// build foo: example bar baz | qux || oo |@ quux
192 /// "###);
193 fn validations(self, validations: impl IntoIterator<Item = impl ToArg>) -> Self {
194 self.as_build()
195 .validations
196 .extend(validations.into_iter().map(|s| s.to_arg()));
197 self
198 }
199
200 /// Add validations
201 ///
202 /// See <https://ninja-build.org/manual.html#validations>
203 ///
204 /// # Example
205 /// ```rust
206 /// use ninja_writer::*;
207 ///
208 /// let ninja = Ninja::new();
209 /// let rule = ninja.rule("example", "...");
210 /// rule.build(["foo"]).with(["bar", "baz"])
211 /// .with_order_only(["oo"])
212 /// .with_implicit(["qux"])
213 /// .validations(["quux"])
214 /// .output_implicit(["iii"]);
215 ///
216 /// assert_eq!(ninja.to_string(), r###"
217 /// rule example
218 /// command = ...
219 ///
220 /// build foo | iii: example bar baz | qux || oo |@ quux
221 /// "###);
222 fn output_implicit(self, outputs: impl IntoIterator<Item = impl ToArg>) -> Self {
223 self.as_build()
224 .implicit_outputs
225 .extend(outputs.into_iter().map(|s| s.to_arg()));
226 self
227 }
228}
229
230/// Reference to a build statement
231#[derive(Debug, Clone)]
232pub struct BuildRef(pub(crate) StmtRef);
233
234impl Deref for BuildRef {
235 type Target = Build;
236 fn deref(&self) -> &Self::Target {
237 match self.0.deref().deref() {
238 Stmt::Build(b) => b,
239 // safety: BuildRef is only constructable from this crate
240 _ => unreachable!(),
241 }
242 }
243}
244
245impl AsRef<Build> for BuildRef {
246 #[inline]
247 fn as_ref(&self) -> &Build {
248 self.deref()
249 }
250}
251
252impl Build {
253 /// Create a new build with the given explicit outputs and rule
254 pub fn new(rule: &Rule, outputs: impl IntoIterator<Item = impl ToArg>) -> Self {
255 let self_outputs = AddOnlyVec::new();
256 self_outputs.extend(outputs.into_iter().map(|s| s.to_arg()));
257 Self {
258 rule: RefCounted::clone(&rule.name),
259 outputs: self_outputs,
260 implicit_outputs: AddOnlyVec::new(),
261 dependencies: AddOnlyVec::new(),
262 implicit_dependencies: AddOnlyVec::new(),
263 order_only_dependencies: AddOnlyVec::new(),
264 validations: AddOnlyVec::new(),
265 variables: AddOnlyVec::new(),
266 }
267 }
268}
269
270impl Variables for Build {
271 #[inline]
272 fn add_variable_internal(&self, v: Variable) {
273 self.variables.add(v);
274 }
275}
276
277impl BuildVariables for Build {
278 fn as_build(&self) -> &Build {
279 self
280 }
281}
282
283impl RuleVariables for Build {}
284
285impl Variables for BuildRef {
286 #[inline]
287 fn add_variable_internal(&self, v: Variable) {
288 self.deref().variables.add(v);
289 }
290}
291
292impl BuildVariables for BuildRef {
293 fn as_build(&self) -> &Build {
294 self.deref()
295 }
296}
297
298impl RuleVariables for BuildRef {}
299
300impl Display for Build {
301 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
302 write!(f, "build")?;
303 for output in self.outputs.inner().iter() {
304 write!(f, " {}", output)?;
305 }
306 {
307 let implicit_outputs = self.implicit_outputs.inner();
308 if !implicit_outputs.is_empty() {
309 write!(f, " |")?;
310 for output in implicit_outputs.iter() {
311 write!(f, " {}", output)?;
312 }
313 }
314 }
315 write!(f, ": {}", self.rule)?;
316 for input in self.dependencies.inner().iter() {
317 write!(f, " {}", input)?;
318 }
319 {
320 let implicit_dependencies = self.implicit_dependencies.inner();
321 if !implicit_dependencies.is_empty() {
322 write!(f, " |")?;
323 for input in implicit_dependencies.iter() {
324 write!(f, " {}", input)?;
325 }
326 }
327 }
328 {
329 let order_only_dependencies = self.order_only_dependencies.inner();
330 if !order_only_dependencies.is_empty() {
331 write!(f, " ||")?;
332 for input in order_only_dependencies.iter() {
333 write!(f, " {}", input)?;
334 }
335 }
336 }
337 {
338 let validations = self.validations.inner();
339 if !validations.is_empty() {
340 write!(f, " |@")?;
341 for input in validations.iter() {
342 write!(f, " {}", input)?;
343 }
344 }
345 }
346 writeln!(f)?;
347 for variable in self.variables.inner().iter() {
348 Indented(variable).fmt(f)?;
349 writeln!(f)?;
350 }
351 Ok(())
352 }
353}