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}