ninja_build/
graph.rs

1// Copyright 2011 Google Inc. All Rights Reserved.
2// Copyright 2017 The Ninja-rs Project Developers. All Rights Reserved.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16
17use std::rc::Rc;
18use std::cell::{Cell, RefCell};
19use std::borrow::Cow;
20use std::ops::Range;
21
22use super::state::{Pool, State, NodeState};
23use super::build_log::BuildLog;
24use super::deps_log::DepsLog;
25use super::disk_interface::DiskInterface;
26use super::state::{PHONY_RULE, CONSOLE_POOL};
27use super::eval_env::{Env, Rule, BindingEnv};
28use super::timestamp::TimeStamp;
29use super::utils::WINDOWS_PATH;
30use super::utils::{decanonicalize_path, pathbuf_from_bytes};
31use super::utils::{ExtendFromEscapedSlice, RangeContains};
32
33#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)]
34pub struct NodeIndex(pub(crate) usize);
35
36#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)]
37pub struct EdgeIndex(pub(crate) usize);
38
39/// Information about a node in the dependency graph: the file, whether
40/// it's dirty, mtime, etc.
41pub struct Node {
42    path: Vec<u8>,
43
44    /// Set bits starting from lowest for backslashes that were normalized to
45    /// forward slashes by CanonicalizePath. See |PathDecanonicalized|.
46    slash_bits: u64,
47
48    /// The Edge that produces this Node, or NULL when there is no
49    /// known edge to produce it.
50    in_edge: Option<EdgeIndex>,
51
52    /// All Edges that use this Node as an input.
53    out_edges: Vec<EdgeIndex>,
54
55    /// A dense integer id for the node, assigned and used by DepsLog.
56    id: isize,
57
58    /// Possible values of mtime_:
59    ///   -1: file hasn't been examined
60    ///   0:  we looked, and file doesn't exist
61    ///   >0: actual file's mtime
62    mtime: TimeStamp,
63
64    /// Dirty is true when the underlying file is out-of-date.
65    /// But note that Edge::outputs_ready_ is also used in judging which
66    /// edges to build.
67    dirty: bool,
68}
69
70impl Node {
71    pub fn new(path: &[u8], slash_bits: u64) -> Self {
72        Node {
73            path: path.to_owned(),
74            slash_bits,
75            in_edge: None,
76            out_edges: Vec::new(),
77            id: -1,
78            mtime: TimeStamp(-1),
79            dirty: false,
80        }
81    }
82
83    pub fn id(&self) -> isize {
84        self.id
85    }
86
87    pub fn set_id(&mut self, id: isize) {
88        self.id = id;
89    }
90
91    pub fn path(&self) -> &[u8] {
92        &self.path
93    }
94
95    pub fn slash_bits(&self) -> u64 {
96        self.slash_bits
97    }
98
99    pub fn mtime(&self) -> TimeStamp {
100        self.mtime
101    }
102
103    pub fn is_dirty(&self) -> bool {
104        self.dirty
105    }
106
107    pub fn set_dirty(&mut self, dirty: bool) {
108        self.dirty = dirty;
109    }
110
111    pub fn mark_dirty(&mut self) {
112        self.dirty = true;
113    }
114
115    /// Mark as not-yet-stat()ed and not dirty.
116    pub fn reset_state(&mut self) {
117        self.mtime = TimeStamp(-1);
118        self.dirty = false;
119    }
120
121    /// Mark the Node as already-stat()ed and missing.
122    pub fn mark_missing(&mut self) {
123        self.mtime = TimeStamp(0);
124    }
125
126    pub fn exists(&self) -> bool {
127        self.mtime.0 != 0
128    }
129
130    pub fn status_known(&self) -> bool {
131        self.mtime.0 != -1
132    }
133
134    pub fn in_edge(&self) -> Option<EdgeIndex> {
135        self.in_edge
136    }
137
138    pub fn set_in_edge(&mut self, edge: Option<EdgeIndex>) {
139        self.in_edge = edge;
140    }
141
142    pub fn out_edges(&self) -> &[EdgeIndex] {
143        &self.out_edges
144    }
145
146    pub fn add_out_edge(&mut self, edge: EdgeIndex) {
147        self.out_edges.push(edge);
148    }
149
150    /// Get |path()| but use slash_bits to convert back to original slash styles.
151    pub fn path_decanonicalized(&self) -> Vec<u8> {
152        decanonicalize_path(&self.path, self.slash_bits)
153    }
154
155    /// Return false on error.
156    pub fn stat(&mut self, disk_interface: &DiskInterface) -> Result<(), String> {
157        self.mtime = TimeStamp(-1);
158
159        let pathbuf = pathbuf_from_bytes(self.path.clone()).map_err(|e| {
160            format!("invalid utf-8 pathname: {}", String::from_utf8_lossy(&e))
161        })?;
162
163        self.mtime = disk_interface.stat(&pathbuf)?;
164        Ok(())
165    }
166
167    /// Return false on error.
168    pub fn stat_if_necessary(&mut self, disk_interface: &DiskInterface) -> Result<(), String> {
169        if self.status_known() {
170            return Ok(());
171        }
172
173        self.stat(disk_interface)
174    }
175}
176
177/*
178
179struct Node {
180
181  void Dump(const char* prefix="") const;
182
183private:
184};
185*/
186
187#[derive(Clone, Copy)]
188pub enum EdgeVisitMark {
189    VisitNone,
190    VisitInStack,
191    VisitDone,
192}
193
194/// An edge in the dependency graph; links between Nodes using Rules.
195pub struct Edge {
196    rule: Rc<Rule>,
197    pub pool: Rc<RefCell<Pool>>,
198    pub inputs: Vec<NodeIndex>,
199    pub outputs: Vec<NodeIndex>,
200    pub env: Rc<RefCell<BindingEnv>>,
201    pub mark: EdgeVisitMark,
202    pub outputs_ready: bool,
203    pub deps_missing: bool,
204    pub implicit_deps: usize,
205    pub order_only_deps: usize,
206    pub implicit_outs: usize,
207}
208
209impl Edge {
210    pub fn new(rule: Rc<Rule>, pool: Rc<RefCell<Pool>>, env: Rc<RefCell<BindingEnv>>) -> Self {
211        Edge {
212            rule,
213            pool,
214            inputs: Vec::new(),
215            outputs: Vec::new(),
216            env,
217            mark: EdgeVisitMark::VisitNone,
218            outputs_ready: false,
219            deps_missing: false,
220            implicit_deps: 0,
221            order_only_deps: 0,
222            implicit_outs: 0,
223        }
224    }
225
226    pub fn rule(&self) -> &Rc<Rule> {
227        &self.rule
228    }
229
230    pub fn pool(&self) -> &Rc<RefCell<Pool>> {
231        &self.pool
232    }
233
234    pub fn weight(&self) -> usize {
235        1
236    }
237
238    pub fn outputs_ready(&self) -> bool {
239        self.outputs_ready
240    }
241
242    // There are three types of inputs.
243    // 1) explicit deps, which show up as $in on the command line;
244    // 2) implicit deps, which the target depends on implicitly (e.g. C headers),
245    //                   and changes in them cause the target to rebuild;
246    // 3) order-only deps, which are needed before the target builds but which
247    //                     don't cause the target to rebuild.
248    // These are stored in inputs_ in that order, and we keep counts of
249    // #2 and #3 when we need to access the various subsets.
250    pub fn explicit_deps_range(&self) -> Range<usize> {
251        0..(self.inputs.len() - self.implicit_deps - self.order_only_deps)
252    }
253
254    pub fn implicit_deps_range(&self) -> Range<usize> {
255        (self.inputs.len() - self.implicit_deps - self.order_only_deps)..
256            (self.inputs.len() - self.order_only_deps)
257    }
258
259    pub fn non_order_only_deps_range(&self) -> Range<usize> {
260        0..(self.inputs.len() - self.order_only_deps)
261    }
262
263    pub fn order_only_deps_range(&self) -> Range<usize> {
264        (self.inputs.len() - self.order_only_deps)..(self.inputs.len())
265    }
266
267    // There are two types of outputs.
268    // 1) explicit outs, which show up as $out on the command line;
269    // 2) implicit outs, which the target generates but are not part of $out.
270    // These are stored in outputs_ in that order, and we keep a count of
271    // #2 to use when we need to access the various subsets.
272    pub fn explicit_outs_range(&self) -> Range<usize> {
273        0..(self.outputs.len() - self.implicit_outs)
274    }
275
276    pub fn implicit_outs_range(&self) -> Range<usize> {
277        (self.outputs.len() - self.implicit_outs)..(self.outputs.len())
278    }
279
280    /// Returns the shell-escaped value of |key|.
281    pub fn get_binding(&self, node_state: &NodeState, key: &[u8]) -> Cow<[u8]> {
282        let env = EdgeEnv::new(self, node_state, EdgeEnvEscapeKind::ShellEscape);
283        env.lookup_variable(key).into_owned().into()
284    }
285
286    pub fn get_binding_bool(&self, node_state: &NodeState, key: &[u8]) -> bool {
287        !self.get_binding(node_state, key).is_empty()
288    }
289
290    /// Like GetBinding("depfile"), but without shell escaping.
291    pub fn get_unescaped_depfile(&self, node_state: &NodeState) -> Cow<[u8]> {
292        let env = EdgeEnv::new(self, node_state, EdgeEnvEscapeKind::DoNotEscape);
293        env.lookup_variable(b"depfile").into_owned().into()
294    }
295
296    /// Like GetBinding("rspfile"), but without shell escaping.
297    pub fn get_unescaped_rspfile(&self, node_state: &NodeState) -> Cow<[u8]> {
298        let env = EdgeEnv::new(self, node_state, EdgeEnvEscapeKind::DoNotEscape);
299        env.lookup_variable(b"rspfile").into_owned().into()
300    }
301
302    pub fn is_phony(&self) -> bool {
303        self.rule.as_ref() as *const Rule == PHONY_RULE.with(|x| x.as_ref() as *const Rule)
304    }
305
306    pub fn use_console(&self) -> bool {
307        &*self.pool().borrow() as *const Pool == CONSOLE_POOL.with(|x| &*x.borrow() as *const Pool)
308    }
309
310    /// Expand all variables in a command and return it as a string.
311    /// If incl_rsp_file is enabled, the string will also contain the
312    /// full contents of a response file (if applicable)
313    pub fn evaluate_command(&self, node_state: &NodeState) -> Vec<u8> {
314        self.evaluate_command_with_rsp_file(node_state, false)
315    }
316
317    pub fn evaluate_command_with_rsp_file(
318        &self,
319        node_state: &NodeState,
320        incl_rsp_file: bool,
321    ) -> Vec<u8> {
322        let mut command = self.get_binding(node_state, b"command").into_owned();
323        if incl_rsp_file {
324            let rspfile_content = self.get_binding(node_state, b"rspfile_content");
325            if !rspfile_content.is_empty() {
326                command.extend_from_slice(b";rspfile=");
327                command.extend_from_slice(rspfile_content.as_ref());
328            }
329        }
330        command
331    }
332
333    pub fn maybe_phonycycle_diagnostic(&self) -> bool {
334        // CMake 2.8.12.x and 3.0.x produced self-referencing phony rules
335        // of the form "build a: phony ... a ...".   Restrict our
336        // "phonycycle" diagnostic option to the form it used.
337        self.is_phony() && self.outputs.len() == 1 && self.implicit_outs == 0 &&
338            self.implicit_deps == 0
339    }
340
341    /// Return true if all inputs' in-edges are ready.
342    pub fn all_inputs_ready(&self, state: &State) -> bool {
343        for input_idx in self.inputs.iter() {
344            let input = state.node_state.get_node(*input_idx);
345            if let Some(in_edge) = input.in_edge() {
346                if !state.edge_state.get_edge(in_edge).outputs_ready() {
347                    return false;
348                }
349            }
350        }
351        return true;
352    }
353
354    pub fn dump(&self) {
355        unimplemented!();
356    }
357}
358
359
360/*
361
362struct Edge {
363
364  void Dump(const char* prefix="") const;
365};
366
367*/
368/// ImplicitDepLoader loads implicit dependencies, as referenced via the
369/// "depfile" attribute in build files.
370struct ImplicitDepLoader<'b, 'c> {
371    disk_interface: &'c DiskInterface,
372    deps_log: &'b DepsLog,
373}
374
375impl<'b, 'c> ImplicitDepLoader<'b, 'c> {
376    pub fn new(deps_log: &'b DepsLog, disk_interface: &'c DiskInterface) -> Self {
377        ImplicitDepLoader {
378            deps_log,
379            disk_interface,
380        }
381    }
382
383    pub fn deps_log(&self) -> &'b DepsLog {
384        self.deps_log
385    }
386
387    /// Load implicit dependencies for \a edge.
388    /// @return false on error (without filling \a err if info is just missing
389    //                          or out of date).
390    pub fn load_deps(&self, state: &State, edge_idx: EdgeIndex) -> Result<bool, String> {
391        let edge = state.edge_state.get_edge(edge_idx);
392        let deps_type = edge.get_binding(&state.node_state, b"deps");
393        if !deps_type.is_empty() {
394            return self.load_deps_from_log(state, edge_idx);
395        }
396
397        let depfile = edge.get_unescaped_depfile(&state.node_state);
398        if !depfile.is_empty() {
399            return self.load_dep_file(state, edge_idx, &depfile);
400        }
401
402        // No deps to load.
403        return Ok(true);
404    }
405
406    /// Load implicit dependencies for \a edge from a depfile attribute.
407    /// @return false on error (without filling \a err if info is just missing).
408    pub fn load_dep_file(
409        &self,
410        state: &State,
411        edge_idx: EdgeIndex,
412        path: &[u8],
413    ) -> Result<bool, String> {
414        unimplemented!{}
415    }
416
417    /// Load implicit dependencies for \a edge from the DepsLog.
418    /// @return false on error (without filling \a err if info is just missing).
419    pub fn load_deps_from_log(&self, state: &State, edge_idx: EdgeIndex) -> Result<bool, String> {
420        return Ok(false);
421        unimplemented!{}
422    }
423}
424
425/*
426struct ImplicitDepLoader {
427  ImplicitDepLoader(State* state, DepsLog* deps_log,
428                    DiskInterface* disk_interface)
429      : state_(state), disk_interface_(disk_interface), deps_log_(deps_log) {}
430
431  /// Load implicit dependencies for \a edge.
432  /// @return false on error (without filling \a err if info is just missing
433  //                          or out of date).
434  bool LoadDeps(Edge* edge, string* err);
435
436  DepsLog* deps_log() const {
437    return deps_log_;
438  }
439
440 private:
441
442  /// Preallocate \a count spaces in the input array on \a edge, returning
443  /// an iterator pointing at the first new space.
444  vector<Node*>::iterator PreallocateSpace(Edge* edge, int count);
445
446  /// If we don't have a edge that generates this input already,
447  /// create one; this makes us not abort if the input is missing,
448  /// but instead will rebuild in that circumstance.
449  void CreatePhonyInEdge(Node* node);
450
451  State* state_;
452  DiskInterface* disk_interface_;
453  DepsLog* deps_log_;
454};
455
456*/
457
458/// DependencyScan manages the process of scanning the files in a graph
459/// and updating the dirty/outputs_ready state of all the nodes and edges.
460pub struct DependencyScan<'s, 'a, 'b, 'c>
461where
462    's: 'a,
463{
464    build_log: Option<&'a BuildLog<'s>>,
465    deps_log: &'b DepsLog,
466    disk_interface: &'c DiskInterface,
467    dep_loader: ImplicitDepLoader<'b, 'c>,
468}
469
470impl<'s, 'a, 'b, 'c> DependencyScan<'s, 'a, 'b, 'c>
471where
472    's: 'a,
473{
474    pub fn new(
475        build_log: &'a BuildLog<'s>,
476        deps_log: &'b DepsLog,
477        disk_interface: &'c DiskInterface,
478    ) -> Self {
479        DependencyScan {
480            build_log: Some(build_log),
481            deps_log,
482            disk_interface,
483            dep_loader: ImplicitDepLoader::new(deps_log, disk_interface),
484        }
485    }
486
487    pub fn build_log(&self) -> Option<&'a BuildLog<'s>> {
488        self.build_log.clone()
489    }
490
491    pub fn deps_log(&self) -> &'b DepsLog {
492        self.dep_loader.deps_log()
493    }
494
495    /// Update the |dirty_| state of the given node by inspecting its input edge.
496    /// Examine inputs, outputs, and command lines to judge whether an edge
497    /// needs to be re-run, and update outputs_ready_ and each outputs' |dirty_|
498    /// state accordingly.
499    /// Returns false on failure.
500    pub fn recompute_dirty(&self, state: &mut State, node_idx: NodeIndex) -> Result<(), String> {
501        let mut stack = Vec::new();
502        return self.recompute_dirty_inner(state, node_idx, &mut stack);
503    }
504
505    fn recompute_dirty_inner(
506        &self,
507        state: &mut State,
508        node_idx: NodeIndex,
509        stack: &mut Vec<NodeIndex>,
510    ) -> Result<(), String> {
511        match state.node_state.get_node(node_idx).in_edge.as_ref() {
512            None => {
513                let node = state.node_state.get_node_mut(node_idx);
514                // If we already visited this leaf node then we are done.
515                if node.status_known() {
516                    return Ok(());
517                };
518                // This node has no in-edge; it is dirty if it is missing.
519                node.stat_if_necessary(self.disk_interface)?;
520                if !node.exists() {
521                    explain!(
522                        "{} has no in-edge and is missing",
523                        String::from_utf8_lossy(node.path())
524                    );
525                }
526                let dirty = !node.exists();
527                node.set_dirty(dirty);
528                Ok(())
529            }
530            Some(&edge_idx) => {
531                // If we already finished this edge then we are done.
532                match state.edge_state.get_edge(edge_idx).mark {
533                    EdgeVisitMark::VisitDone => {
534                        return Ok(());
535                    }
536                    _ => {}
537                };
538
539                // If we encountered this edge earlier in the call stack we have a cycle.
540                self.verify_dag(state, node_idx, stack)?;
541
542                let mut dirty = false;
543                let mut outputs_ready = true;
544                let mut deps_missing = false;
545
546                // Mark the edge temporarily while in the call stack.
547                state.edge_state.get_edge_mut(edge_idx).mark = EdgeVisitMark::VisitInStack;
548
549                stack.push(node_idx);
550                // Load output mtimes so we can compare them to the most recent input below.
551                for o_idx in state.edge_state.get_edge(edge_idx).outputs.iter().cloned() {
552                    state.node_state.get_node_mut(o_idx).stat_if_necessary(
553                        self.disk_interface,
554                    )?;
555                }
556
557                if !self.dep_loader.load_deps(state, edge_idx)? {
558                    // Failed to load dependency info: rebuild to regenerate it.
559                    // LoadDeps() did EXPLAIN() already, no need to do it here.
560                    dirty = true;
561                    deps_missing = true;
562                }
563
564                let mut most_recent_input = None;
565                {
566                    let (order_only_range, inputs) = {
567                        let edge = state.edge_state.get_edge(edge_idx);
568                        (edge.order_only_deps_range(), edge.inputs.clone())
569                    };
570
571                    for (i, i_idx) in inputs.into_iter().enumerate() {
572                        // Visit this input.
573                        self.recompute_dirty_inner(state, i_idx, stack)?;
574
575                        // If an input is not ready, neither are our outputs.
576                        if let Some(in_edge) = state.node_state.get_node(i_idx).in_edge() {
577                            if !state.edge_state.get_edge(in_edge).outputs_ready {
578                                outputs_ready = false;
579                            }
580                        }
581
582                        if !order_only_range.contains_stable(i) {
583                            // If a regular input is dirty (or missing), we're dirty.
584                            // Otherwise consider mtime.
585                            let i_node = state.node_state.get_node(i_idx);
586                            if i_node.is_dirty() {
587                                explain!("{} is dirty", String::from_utf8_lossy(i_node.path()));
588                                dirty = true;
589                            } else {
590                                if most_recent_input
591                                    .as_ref()
592                                    .map(|&prev_idx| {
593                                        let prev_node = state.node_state.get_node(prev_idx);
594                                        i_node.mtime() > prev_node.mtime()
595                                    })
596                                    .unwrap_or(true)
597                                {
598                                    most_recent_input = Some(i_idx);
599                                }
600                            }
601                        }
602                    }
603                }
604                // We may also be dirty due to output state: missing outputs, out of
605                // date outputs, etc.  Visit all outputs and determine whether they're dirty.
606                if !dirty {
607                    dirty = self.recompute_outputs_dirty(
608                        state,
609                        edge_idx,
610                        most_recent_input,
611                    )?;
612                }
613
614                if dirty {
615                    let edge = state.edge_state.get_edge(edge_idx);
616
617                    // Finally, visit each output and update their dirty state if necessary.
618                    for o_idx in edge.outputs.iter().cloned() {
619                        state.node_state.get_node_mut(o_idx).mark_dirty();
620                    }
621
622                    // If an edge is dirty, its outputs are normally not ready.  (It's
623                    // possible to be clean but still not be ready in the presence of
624                    // order-only inputs.)
625                    // But phony edges with no inputs have nothing to do, so are always
626                    // ready.
627
628                    if !(edge.is_phony() && edge.inputs.is_empty()) {
629                        outputs_ready = false;
630                    }
631                }
632
633                let edge = state.edge_state.get_edge_mut(edge_idx);
634                edge.deps_missing = deps_missing;
635                edge.outputs_ready = outputs_ready;
636
637                // Mark the edge as finished during this walk now that it will no longer
638                // be in the call stack.
639                edge.mark = EdgeVisitMark::VisitDone;
640                debug_assert!(stack.last() == Some(&node_idx));
641                stack.pop();
642                Ok(())
643            }
644        }
645    }
646
647    fn verify_dag(
648        &self,
649        state: &State,
650        node_idx: NodeIndex,
651        stack: &mut Vec<NodeIndex>,
652    ) -> Result<(), String> {
653        let edge_idx = state.node_state.get_node(node_idx).in_edge().unwrap();
654
655        // If we have no temporary mark on the edge then we do not yet have a cycle.
656        match state.edge_state.get_edge(edge_idx).mark {
657            EdgeVisitMark::VisitInStack => {}
658            _ => {
659                return Ok(());
660            }
661        };
662
663        // We have this edge earlier in the call stack.  Find it.
664        let mut start = 0;
665        while start < stack.len() {
666            let item = stack[start];
667            if state.node_state.get_node(item).in_edge() == Some(edge_idx) {
668                break;
669            }
670            start += 1;
671        }
672        assert!(start < stack.len());
673
674        // Make the cycle clear by reporting its start as the node at its end
675        // instead of some other output of the starting edge.  For example,
676        // running 'ninja b' on
677        //   build a b: cat c
678        //   build c: cat a
679        // should report a -> c -> a instead of b -> c -> a.
680        stack[start] = node_idx;
681
682        // Construct the error message rejecting the cycle.
683        let mut err = "dependency cycle: ".to_owned();
684        for iter_idx in stack[start..].iter() {
685            err += String::from_utf8_lossy(state.node_state.get_node(*iter_idx).path()).as_ref();
686            err += " -> ";
687        }
688
689        err += String::from_utf8_lossy(state.node_state.get_node(node_idx).path()).as_ref();
690
691        if start + 1 == stack.len() &&
692            state
693                .edge_state
694                .get_edge(edge_idx)
695                .maybe_phonycycle_diagnostic()
696        {
697            // The manifest parser would have filtered out the self-referencing
698            // input if it were not configured to allow the error.
699            err += " [-w phonycycle=err]";
700        }
701
702        return Err(err);
703    }
704
705    /// Recompute whether any output of the edge is dirty, if so sets |*dirty|.
706    /// Returns false on failure.
707    fn recompute_outputs_dirty(
708        &self,
709        state: &State,
710        edge_idx: EdgeIndex,
711        most_recent_input: Option<NodeIndex>,
712    ) -> Result<bool, String> {
713        let edge = state.edge_state.get_edge(edge_idx);
714        let command = edge.evaluate_command_with_rsp_file(&state.node_state, true);
715        for output in edge.outputs.iter() {
716            if self.recompute_output_dirty(state, edge_idx, most_recent_input, &command, *output) {
717                return Ok(true);
718            }
719        }
720        return Ok(false);
721    }
722
723    /// Recompute whether a given single output should be marked dirty.
724    /// Returns true if so.
725    fn recompute_output_dirty(
726        &self,
727        state: &State,
728        edge_idx: EdgeIndex,
729        most_recent_input: Option<NodeIndex>,
730        command: &[u8],
731        output_node_idx: NodeIndex,
732    ) -> bool {
733
734        let edge = state.edge_state.get_edge(edge_idx);
735        let output = state.node_state.get_node(output_node_idx);
736        let mut entry = None;
737
738        if edge.is_phony() {
739            // Phony edges don't write any output.  Outputs are only dirty if
740            // there are no inputs and we're missing the output.
741            if edge.inputs.is_empty() && !output.exists() {
742                explain!(
743                    "output {} of phony edge with no inputs doesn't exist",
744                    String::from_utf8_lossy(output.path())
745                );
746
747                return true;
748            }
749            return false;
750        }
751
752        // Dirty if we're missing the output.
753        if !output.exists() {
754            explain!(
755                "output {} doesn't exist",
756                String::from_utf8_lossy(output.path())
757            );
758            return true;
759        }
760
761        // Dirty if the output is older than the input.
762        if let Some(ref most_recent_input_idx) = most_recent_input {
763            let most_recent_input = state.node_state.get_node(*most_recent_input_idx);
764            if output.mtime() < most_recent_input.mtime() {
765                let mut output_mtime = output.mtime();
766
767                // If this is a restat rule, we may have cleaned the output with a restat
768                // rule in a previous run and stored the most recent input mtime in the
769                // build log.  Use that mtime instead, so that the file will only be
770                // considered dirty if an input was modified since the previous run.
771                let mut used_restat = false;
772
773                if edge.get_binding_bool(&state.node_state, b"restat") {
774                    if let Some(build_log) = self.build_log() {
775                        if entry.is_none() {
776                            entry = build_log.lookup_by_output(output.path());
777                        }
778                        if let Some(found_entry) = entry {
779                            output_mtime = found_entry.mtime;
780                            used_restat = true;
781                        }
782                    }
783                }
784
785
786                if output_mtime < most_recent_input.mtime() {
787                    explain!(
788                        "{}output {} older than most recent input {} ({} vs {})",
789                        if used_restat { "restat of " } else { "" },
790                        String::from_utf8_lossy(output.path()),
791                        String::from_utf8_lossy(most_recent_input.path()),
792                        output_mtime,
793                        most_recent_input.mtime
794                    );
795                    return true;
796                }
797            }
798        }
799
800        if let Some(build_log) = self.build_log() {
801            let generator = edge.get_binding_bool(&state.node_state, b"generator");
802            if entry.is_none() {
803                entry = build_log.lookup_by_output(output.path());
804            }
805            if let Some(found_entry) = entry {
806                unimplemented!()
807                /*
808      if (!generator &&
809          BuildLog::LogEntry::HashCommand(command) != entry->command_hash) {
810        // May also be dirty due to the command changing since the last build.
811        // But if this is a generator rule, the command changing does not make us
812        // dirty.
813        EXPLAIN("command line changed for %s", output->path().c_str());
814        return true;
815      }
816      if (most_recent_input && entry->mtime < most_recent_input->mtime()) {
817        // May also be dirty due to the mtime in the log being older than the
818        // mtime of the most recent input.  This can occur even when the mtime
819        // on disk is newer if a previous run wrote to the output file but
820        // exited with an error or was interrupted.
821        EXPLAIN("recorded mtime of %s older than most recent input %s (%d vs %d)",
822                output->path().c_str(), most_recent_input->path().c_str(),
823                entry->mtime, most_recent_input->mtime());
824        return true;
825      }
826*/
827            }
828
829            if entry.is_none() && !generator {
830                explain!(
831                    "command line not found in log for {}",
832                    String::from_utf8_lossy(output.path())
833                );
834                return true;
835            }
836        }
837
838        return false;
839    }
840}
841
842/*
843
844struct DependencyScan {
845  DependencyScan(State* state, BuildLog* build_log, DepsLog* deps_log,
846                 DiskInterface* disk_interface)
847      : build_log_(build_log),
848        disk_interface_(disk_interface),
849        dep_loader_(state, deps_log, disk_interface) {}
850
851  BuildLog* build_log() const {
852    return build_log_;
853  }
854  void set_build_log(BuildLog* log) {
855    build_log_ = log;
856  }
857
858  DepsLog* deps_log() const {
859    return dep_loader_.deps_log();
860  }
861
862 private:
863  bool RecomputeDirty(Node* node, vector<Node*>* stack, string* err);
864  bool VerifyDAG(Node* node, vector<Node*>* stack, string* err);
865
866
867
868  BuildLog* build_log_;
869  DiskInterface* disk_interface_;
870  ImplicitDepLoader dep_loader_;
871};
872
873#endif  // NINJA_GRAPH_H_
874
875*/
876
877
878
879/*
880
881bool DependencyScan::RecomputeOutputDirty(Edge* edge,
882                                          Node* most_recent_input,
883                                          const string& command,
884                                          Node* output) {
885}
886
887*/
888
889#[derive(Clone, Copy)]
890enum EdgeEnvEscapeKind {
891    ShellEscape,
892    DoNotEscape,
893}
894
895/// An Env for an Edge, providing $in and $out.
896struct EdgeEnv<'a, 'b> {
897    lookups: RefCell<Vec<Vec<u8>>>,
898    edge: &'a Edge,
899    node_state: &'b NodeState,
900    escape_in_out: EdgeEnvEscapeKind,
901    recursive: Cell<bool>,
902}
903
904impl<'a, 'b> EdgeEnv<'a, 'b> {
905    pub fn new(edge: &'a Edge, node_state: &'b NodeState, escape: EdgeEnvEscapeKind) -> Self {
906        EdgeEnv {
907            lookups: RefCell::new(Vec::new()),
908            edge,
909            node_state,
910            escape_in_out: escape,
911            recursive: Cell::new(false),
912        }
913    }
914
915    /// Given a span of Nodes, construct a list of paths suitable for a command
916    /// line.
917    pub fn make_path_list(
918        node_state: &NodeState,
919        nodes: &[NodeIndex],
920        sep: u8,
921        escape_in_out: EdgeEnvEscapeKind,
922    ) -> Vec<u8> {
923
924        let mut result = Vec::new();
925        for node_idx in nodes {
926            if !result.is_empty() {
927                result.push(sep);
928            };
929            let node = node_state.get_node(*node_idx);
930            let path = node.path_decanonicalized();
931            match escape_in_out {
932                EdgeEnvEscapeKind::ShellEscape => {
933                    if WINDOWS_PATH {
934                        result.extend_from_win32_escaped_slice(&path);
935                    } else {
936                        result.extend_from_shell_escaped_slice(&path);
937                    }
938                }
939                EdgeEnvEscapeKind::DoNotEscape => {
940                    result.extend_from_slice(&path);
941                }
942            }
943        }
944        result
945    }
946}
947
948impl<'a, 'b> Env for EdgeEnv<'a, 'b> {
949    fn lookup_variable(&self, var: &[u8]) -> Cow<[u8]> {
950        if var == b"in".as_ref() || var == b"in_newline".as_ref() {
951            let sep = if var == b"in".as_ref() { b' ' } else { b'\n' };
952            let explicit_deps_range = self.edge.explicit_deps_range();
953            return Cow::Owned(EdgeEnv::make_path_list(
954                self.node_state,
955                &self.edge.inputs[explicit_deps_range],
956                sep,
957                self.escape_in_out,
958            ));
959        } else if var == b"out".as_ref() {
960            let explicit_outs_range = self.edge.explicit_outs_range();
961            return Cow::Owned(EdgeEnv::make_path_list(
962                self.node_state,
963                &self.edge.outputs[explicit_outs_range],
964                b' ',
965                self.escape_in_out,
966            ));
967        }
968
969        if self.recursive.get() {
970            let lookups = self.lookups.borrow();
971            let mut lookups_iter = lookups.iter().skip_while(|v| var != v as &[u8]).peekable();
972            if lookups_iter.peek().is_some() {
973                let mut cycle = Vec::new();
974                for it in lookups_iter {
975                    cycle.extend_from_slice(&it);
976                    cycle.extend_from_slice(b" -> ");
977                }
978                cycle.extend_from_slice(var);
979                fatal!(
980                    "cycle in rule variables: {}",
981                    String::from_utf8_lossy(&cycle)
982                )
983            }
984        }
985
986        // See notes on BindingEnv::LookupWithFallback.
987        let eval = self.edge.rule.get_binding(var);
988        if self.recursive.get() && eval.is_some() {
989            self.lookups.borrow_mut().push(var.to_owned());
990        }
991
992        // In practice, variables defined on rules never use another rule variable.
993        // For performance, only start checking for cycles after the first lookup.
994        self.recursive.set(true);
995        return Cow::Owned(
996            self.edge
997                .env
998                .borrow()
999                .lookup_with_fallback(var, eval, self)
1000                .into_owned(),
1001        );
1002    }
1003}
1004/*
1005
1006void Edge::Dump(const char* prefix) const {
1007  printf("%s[ ", prefix);
1008  for (vector<Node*>::const_iterator i = inputs_.begin();
1009       i != inputs_.end() && *i != NULL; ++i) {
1010    printf("%s ", (*i)->path().c_str());
1011  }
1012  printf("--%s-> ", rule_->name().c_str());
1013  for (vector<Node*>::const_iterator i = outputs_.begin();
1014       i != outputs_.end() && *i != NULL; ++i) {
1015    printf("%s ", (*i)->path().c_str());
1016  }
1017  if (pool_) {
1018    if (!pool_->name().empty()) {
1019      printf("(in pool '%s')", pool_->name().c_str());
1020    }
1021  } else {
1022    printf("(null pool?)");
1023  }
1024  printf("] 0x%p\n", this);
1025}
1026
1027
1028void Node::Dump(const char* prefix) const {
1029  printf("%s <%s 0x%p> mtime: %d%s, (:%s), ",
1030         prefix, path().c_str(), this,
1031         mtime(), mtime() ? "" : " (:missing)",
1032         dirty() ? " dirty" : " clean");
1033  if (in_edge()) {
1034    in_edge()->Dump("in-edge: ");
1035  } else {
1036    printf("no in-edge\n");
1037  }
1038  printf(" out edges:\n");
1039  for (vector<Edge*>::const_iterator e = out_edges().begin();
1040       e != out_edges().end() && *e != NULL; ++e) {
1041    (*e)->Dump(" +- ");
1042  }
1043}
1044
1045bool ImplicitDepLoader::LoadDeps(Edge* edge, string* err) {
1046  string deps_type = edge->GetBinding("deps");
1047  if (!deps_type.empty())
1048    return LoadDepsFromLog(edge, err);
1049
1050  string depfile = edge->GetUnescapedDepfile();
1051  if (!depfile.empty())
1052    return LoadDepFile(edge, depfile, err);
1053
1054  // No deps to load.
1055  return true;
1056}
1057
1058bool ImplicitDepLoader::LoadDepFile(Edge* edge, const string& path,
1059                                    string* err) {
1060  METRIC_RECORD("depfile load");
1061  // Read depfile content.  Treat a missing depfile as empty.
1062  string content;
1063  switch (disk_interface_->ReadFile(path, &content, err)) {
1064  case DiskInterface::Okay:
1065    break;
1066  case DiskInterface::NotFound:
1067    err->clear();
1068    break;
1069  case DiskInterface::OtherError:
1070    *err = "loading '" + path + "': " + *err;
1071    return false;
1072  }
1073  // On a missing depfile: return false and empty *err.
1074  if (content.empty()) {
1075    EXPLAIN("depfile '%s' is missing", path.c_str());
1076    return false;
1077  }
1078
1079  DepfileParser depfile;
1080  string depfile_err;
1081  if (!depfile.Parse(&content, &depfile_err)) {
1082    *err = path + ": " + depfile_err;
1083    return false;
1084  }
1085
1086  uint64_t unused;
1087  if (!CanonicalizePath(const_cast<char*>(depfile.out_.str_),
1088                        &depfile.out_.len_, &unused, err)) {
1089    *err = path + ": " + *err;
1090    return false;
1091  }
1092
1093  // Check that this depfile matches the edge's output, if not return false to
1094  // mark the edge as dirty.
1095  Node* first_output = edge->outputs_[0];
1096  StringPiece opath = StringPiece(first_output->path());
1097  if (opath != depfile.out_) {
1098    EXPLAIN("expected depfile '%s' to mention '%s', got '%s'", path.c_str(),
1099            first_output->path().c_str(), depfile.out_.AsString().c_str());
1100    return false;
1101  }
1102
1103  // Preallocate space in edge->inputs_ to be filled in below.
1104  vector<Node*>::iterator implicit_dep =
1105      PreallocateSpace(edge, depfile.ins_.size());
1106
1107  // Add all its in-edges.
1108  for (vector<StringPiece>::iterator i = depfile.ins_.begin();
1109       i != depfile.ins_.end(); ++i, ++implicit_dep) {
1110    uint64_t slash_bits;
1111    if (!CanonicalizePath(const_cast<char*>(i->str_), &i->len_, &slash_bits,
1112                          err))
1113      return false;
1114
1115    Node* node = state_->GetNode(*i, slash_bits);
1116    *implicit_dep = node;
1117    node->AddOutEdge(edge);
1118    CreatePhonyInEdge(node);
1119  }
1120
1121  return true;
1122}
1123
1124bool ImplicitDepLoader::LoadDepsFromLog(Edge* edge, string* err) {
1125  // NOTE: deps are only supported for single-target edges.
1126  Node* output = edge->outputs_[0];
1127  DepsLog::Deps* deps = deps_log_->GetDeps(output);
1128  if (!deps) {
1129    EXPLAIN("deps for '%s' are missing", output->path().c_str());
1130    return false;
1131  }
1132
1133  // Deps are invalid if the output is newer than the deps.
1134  if (output->mtime() > deps->mtime) {
1135    EXPLAIN("stored deps info out of date for '%s' (%d vs %d)",
1136            output->path().c_str(), deps->mtime, output->mtime());
1137    return false;
1138  }
1139
1140  vector<Node*>::iterator implicit_dep =
1141      PreallocateSpace(edge, deps->node_count);
1142  for (int i = 0; i < deps->node_count; ++i, ++implicit_dep) {
1143    Node* node = deps->nodes[i];
1144    *implicit_dep = node;
1145    node->AddOutEdge(edge);
1146    CreatePhonyInEdge(node);
1147  }
1148  return true;
1149}
1150
1151vector<Node*>::iterator ImplicitDepLoader::PreallocateSpace(Edge* edge,
1152                                                            int count) {
1153  edge->inputs_.insert(edge->inputs_.end() - edge->order_only_deps_,
1154                       (size_t)count, 0);
1155  edge->implicit_deps_ += count;
1156  return edge->inputs_.end() - edge->order_only_deps_ - count;
1157}
1158
1159void ImplicitDepLoader::CreatePhonyInEdge(Node* node) {
1160  if (node->in_edge())
1161    return;
1162
1163  Edge* phony_edge = state_->AddEdge(&State::kPhonyRule);
1164  node->set_in_edge(phony_edge);
1165  phony_edge->outputs_.push_back(node);
1166
1167  // RecomputeDirty might not be called for phony_edge if a previous call
1168  // to RecomputeDirty had caused the file to be stat'ed.  Because previous
1169  // invocations of RecomputeDirty would have seen this node without an
1170  // input edge (and therefore ready), we have to set outputs_ready_ to true
1171  // to avoid a potential stuck build.  If we do call RecomputeDirty for
1172  // this node, it will simply set outputs_ready_ to the correct value.
1173  phony_edge->outputs_ready_ = true;
1174}
1175
1176*/
1177
1178/*
1179// Copyright 2011 Google Inc. All Rights Reserved.
1180//
1181// Licensed under the Apache License, Version 2.0 (the "License");
1182// you may not use this file except in compliance with the License.
1183// You may obtain a copy of the License at
1184//
1185//     http://www.apache.org/licenses/LICENSE-2.0
1186//
1187// Unless required by applicable law or agreed to in writing, software
1188// distributed under the License is distributed on an "AS IS" BASIS,
1189// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1190// See the License for the specific language governing permissions and
1191// limitations under the License.
1192
1193#include "graph.h"
1194#include "build.h"
1195
1196#include "test.h"
1197
1198struct GraphTest : public StateTestWithBuiltinRules {
1199  GraphTest() : scan_(&state_, NULL, NULL, &fs_) {}
1200
1201  VirtualFileSystem fs_;
1202  DependencyScan scan_;
1203};
1204
1205TEST_F(GraphTest, MissingImplicit) {
1206  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1207"build out: cat in | implicit\n"));
1208  fs_.Create("in", "");
1209  fs_.Create("out", "");
1210
1211  string err;
1212  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), &err));
1213  ASSERT_EQ("", err);
1214
1215  // A missing implicit dep *should* make the output dirty.
1216  // (In fact, a build will fail.)
1217  // This is a change from prior semantics of ninja.
1218  EXPECT_TRUE(GetNode("out")->dirty());
1219}
1220
1221TEST_F(GraphTest, ModifiedImplicit) {
1222  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1223"build out: cat in | implicit\n"));
1224  fs_.Create("in", "");
1225  fs_.Create("out", "");
1226  fs_.Tick();
1227  fs_.Create("implicit", "");
1228
1229  string err;
1230  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), &err));
1231  ASSERT_EQ("", err);
1232
1233  // A modified implicit dep should make the output dirty.
1234  EXPECT_TRUE(GetNode("out")->dirty());
1235}
1236
1237TEST_F(GraphTest, FunkyMakefilePath) {
1238  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1239"rule catdep\n"
1240"  depfile = $out.d\n"
1241"  command = cat $in > $out\n"
1242"build out.o: catdep foo.cc\n"));
1243  fs_.Create("foo.cc",  "");
1244  fs_.Create("out.o.d", "out.o: ./foo/../implicit.h\n");
1245  fs_.Create("out.o", "");
1246  fs_.Tick();
1247  fs_.Create("implicit.h", "");
1248
1249  string err;
1250  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), &err));
1251  ASSERT_EQ("", err);
1252
1253  // implicit.h has changed, though our depfile refers to it with a
1254  // non-canonical path; we should still find it.
1255  EXPECT_TRUE(GetNode("out.o")->dirty());
1256}
1257
1258TEST_F(GraphTest, ExplicitImplicit) {
1259  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1260"rule catdep\n"
1261"  depfile = $out.d\n"
1262"  command = cat $in > $out\n"
1263"build implicit.h: cat data\n"
1264"build out.o: catdep foo.cc || implicit.h\n"));
1265  fs_.Create("implicit.h", "");
1266  fs_.Create("foo.cc", "");
1267  fs_.Create("out.o.d", "out.o: implicit.h\n");
1268  fs_.Create("out.o", "");
1269  fs_.Tick();
1270  fs_.Create("data", "");
1271
1272  string err;
1273  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), &err));
1274  ASSERT_EQ("", err);
1275
1276  // We have both an implicit and an explicit dep on implicit.h.
1277  // The implicit dep should "win" (in the sense that it should cause
1278  // the output to be dirty).
1279  EXPECT_TRUE(GetNode("out.o")->dirty());
1280}
1281
1282TEST_F(GraphTest, ImplicitOutputParse) {
1283  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1284"build out | out.imp: cat in\n"));
1285
1286  Edge* edge = GetNode("out")->in_edge();
1287  EXPECT_EQ(2, edge->outputs_.size());
1288  EXPECT_EQ("out", edge->outputs_[0]->path());
1289  EXPECT_EQ("out.imp", edge->outputs_[1]->path());
1290  EXPECT_EQ(1, edge->implicit_outs_);
1291  EXPECT_EQ(edge, GetNode("out.imp")->in_edge());
1292}
1293
1294TEST_F(GraphTest, ImplicitOutputMissing) {
1295  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1296"build out | out.imp: cat in\n"));
1297  fs_.Create("in", "");
1298  fs_.Create("out", "");
1299
1300  string err;
1301  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), &err));
1302  ASSERT_EQ("", err);
1303
1304  EXPECT_TRUE(GetNode("out")->dirty());
1305  EXPECT_TRUE(GetNode("out.imp")->dirty());
1306}
1307
1308TEST_F(GraphTest, ImplicitOutputOutOfDate) {
1309  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1310"build out | out.imp: cat in\n"));
1311  fs_.Create("out.imp", "");
1312  fs_.Tick();
1313  fs_.Create("in", "");
1314  fs_.Create("out", "");
1315
1316  string err;
1317  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out"), &err));
1318  ASSERT_EQ("", err);
1319
1320  EXPECT_TRUE(GetNode("out")->dirty());
1321  EXPECT_TRUE(GetNode("out.imp")->dirty());
1322}
1323
1324TEST_F(GraphTest, ImplicitOutputOnlyParse) {
1325  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1326"build | out.imp: cat in\n"));
1327
1328  Edge* edge = GetNode("out.imp")->in_edge();
1329  EXPECT_EQ(1, edge->outputs_.size());
1330  EXPECT_EQ("out.imp", edge->outputs_[0]->path());
1331  EXPECT_EQ(1, edge->implicit_outs_);
1332  EXPECT_EQ(edge, GetNode("out.imp")->in_edge());
1333}
1334
1335TEST_F(GraphTest, ImplicitOutputOnlyMissing) {
1336  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1337"build | out.imp: cat in\n"));
1338  fs_.Create("in", "");
1339
1340  string err;
1341  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.imp"), &err));
1342  ASSERT_EQ("", err);
1343
1344  EXPECT_TRUE(GetNode("out.imp")->dirty());
1345}
1346
1347TEST_F(GraphTest, ImplicitOutputOnlyOutOfDate) {
1348  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1349"build | out.imp: cat in\n"));
1350  fs_.Create("out.imp", "");
1351  fs_.Tick();
1352  fs_.Create("in", "");
1353
1354  string err;
1355  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.imp"), &err));
1356  ASSERT_EQ("", err);
1357
1358  EXPECT_TRUE(GetNode("out.imp")->dirty());
1359}
1360
1361TEST_F(GraphTest, PathWithCurrentDirectory) {
1362  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1363"rule catdep\n"
1364"  depfile = $out.d\n"
1365"  command = cat $in > $out\n"
1366"build ./out.o: catdep ./foo.cc\n"));
1367  fs_.Create("foo.cc", "");
1368  fs_.Create("out.o.d", "out.o: foo.cc\n");
1369  fs_.Create("out.o", "");
1370
1371  string err;
1372  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), &err));
1373  ASSERT_EQ("", err);
1374
1375  EXPECT_FALSE(GetNode("out.o")->dirty());
1376}
1377
1378TEST_F(GraphTest, RootNodes) {
1379  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1380"build out1: cat in1\n"
1381"build mid1: cat in1\n"
1382"build out2: cat mid1\n"
1383"build out3 out4: cat mid1\n"));
1384
1385  string err;
1386  vector<Node*> root_nodes = state_.RootNodes(&err);
1387  EXPECT_EQ(4u, root_nodes.size());
1388  for (size_t i = 0; i < root_nodes.size(); ++i) {
1389    string name = root_nodes[i]->path();
1390    EXPECT_EQ("out", name.substr(0, 3));
1391  }
1392}
1393
1394TEST_F(GraphTest, VarInOutPathEscaping) {
1395  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1396"build a$ b: cat no'space with$ space$$ no\"space2\n"));
1397
1398  Edge* edge = GetNode("a b")->in_edge();
1399#if _WIN32
1400  EXPECT_EQ("cat no'space \"with space$\" \"no\\\"space2\" > \"a b\"",
1401      edge->EvaluateCommand());
1402#else
1403  EXPECT_EQ("cat 'no'\\''space' 'with space$' 'no\"space2' > 'a b'",
1404      edge->EvaluateCommand());
1405#endif
1406}
1407
1408// Regression test for https://github.com/ninja-build/ninja/issues/380
1409TEST_F(GraphTest, DepfileWithCanonicalizablePath) {
1410  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1411"rule catdep\n"
1412"  depfile = $out.d\n"
1413"  command = cat $in > $out\n"
1414"build ./out.o: catdep ./foo.cc\n"));
1415  fs_.Create("foo.cc", "");
1416  fs_.Create("out.o.d", "out.o: bar/../foo.cc\n");
1417  fs_.Create("out.o", "");
1418
1419  string err;
1420  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), &err));
1421  ASSERT_EQ("", err);
1422
1423  EXPECT_FALSE(GetNode("out.o")->dirty());
1424}
1425
1426// Regression test for https://github.com/ninja-build/ninja/issues/404
1427TEST_F(GraphTest, DepfileRemoved) {
1428  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1429"rule catdep\n"
1430"  depfile = $out.d\n"
1431"  command = cat $in > $out\n"
1432"build ./out.o: catdep ./foo.cc\n"));
1433  fs_.Create("foo.h", "");
1434  fs_.Create("foo.cc", "");
1435  fs_.Tick();
1436  fs_.Create("out.o.d", "out.o: foo.h\n");
1437  fs_.Create("out.o", "");
1438
1439  string err;
1440  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), &err));
1441  ASSERT_EQ("", err);
1442  EXPECT_FALSE(GetNode("out.o")->dirty());
1443
1444  state_.Reset();
1445  fs_.RemoveFile("out.o.d");
1446  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("out.o"), &err));
1447  ASSERT_EQ("", err);
1448  EXPECT_TRUE(GetNode("out.o")->dirty());
1449}
1450
1451// Check that rule-level variables are in scope for eval.
1452TEST_F(GraphTest, RuleVariablesInScope) {
1453  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1454"rule r\n"
1455"  depfile = x\n"
1456"  command = depfile is $depfile\n"
1457"build out: r in\n"));
1458  Edge* edge = GetNode("out")->in_edge();
1459  EXPECT_EQ("depfile is x", edge->EvaluateCommand());
1460}
1461
1462// Check that build statements can override rule builtins like depfile.
1463TEST_F(GraphTest, DepfileOverride) {
1464  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1465"rule r\n"
1466"  depfile = x\n"
1467"  command = unused\n"
1468"build out: r in\n"
1469"  depfile = y\n"));
1470  Edge* edge = GetNode("out")->in_edge();
1471  EXPECT_EQ("y", edge->GetBinding("depfile"));
1472}
1473
1474// Check that overridden values show up in expansion of rule-level bindings.
1475TEST_F(GraphTest, DepfileOverrideParent) {
1476  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1477"rule r\n"
1478"  depfile = x\n"
1479"  command = depfile is $depfile\n"
1480"build out: r in\n"
1481"  depfile = y\n"));
1482  Edge* edge = GetNode("out")->in_edge();
1483  EXPECT_EQ("depfile is y", edge->GetBinding("command"));
1484}
1485
1486// Verify that building a nested phony rule prints "no work to do"
1487TEST_F(GraphTest, NestedPhonyPrintsDone) {
1488  AssertParse(&state_,
1489"build n1: phony \n"
1490"build n2: phony n1\n"
1491  );
1492  string err;
1493  EXPECT_TRUE(scan_.RecomputeDirty(GetNode("n2"), &err));
1494  ASSERT_EQ("", err);
1495
1496  Plan plan_;
1497  EXPECT_TRUE(plan_.AddTarget(GetNode("n2"), &err));
1498  ASSERT_EQ("", err);
1499
1500  EXPECT_EQ(0, plan_.command_edge_count());
1501  ASSERT_FALSE(plan_.more_to_do());
1502}
1503
1504TEST_F(GraphTest, PhonySelfReferenceError) {
1505  ManifestParserOptions parser_opts;
1506  parser_opts.phony_cycle_action_ = kPhonyCycleActionError;
1507  AssertParse(&state_,
1508"build a: phony a\n",
1509  parser_opts);
1510
1511  string err;
1512  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("a"), &err));
1513  ASSERT_EQ("dependency cycle: a -> a [-w phonycycle=err]", err);
1514}
1515
1516TEST_F(GraphTest, DependencyCycle) {
1517  AssertParse(&state_,
1518"build out: cat mid\n"
1519"build mid: cat in\n"
1520"build in: cat pre\n"
1521"build pre: cat out\n");
1522
1523  string err;
1524  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("out"), &err));
1525  ASSERT_EQ("dependency cycle: out -> mid -> in -> pre -> out", err);
1526}
1527
1528TEST_F(GraphTest, CycleInEdgesButNotInNodes1) {
1529  string err;
1530  AssertParse(&state_,
1531"build a b: cat a\n");
1532  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("b"), &err));
1533  ASSERT_EQ("dependency cycle: a -> a", err);
1534}
1535
1536TEST_F(GraphTest, CycleInEdgesButNotInNodes2) {
1537  string err;
1538  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1539"build b a: cat a\n"));
1540  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("b"), &err));
1541  ASSERT_EQ("dependency cycle: a -> a", err);
1542}
1543
1544TEST_F(GraphTest, CycleInEdgesButNotInNodes3) {
1545  string err;
1546  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1547"build a b: cat c\n"
1548"build c: cat a\n"));
1549  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("b"), &err));
1550  ASSERT_EQ("dependency cycle: a -> c -> a", err);
1551}
1552
1553TEST_F(GraphTest, CycleInEdgesButNotInNodes4) {
1554  string err;
1555  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1556"build d: cat c\n"
1557"build c: cat b\n"
1558"build b: cat a\n"
1559"build a e: cat d\n"
1560"build f: cat e\n"));
1561  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("f"), &err));
1562  ASSERT_EQ("dependency cycle: a -> d -> c -> b -> a", err);
1563}
1564
1565// Verify that cycles in graphs with multiple outputs are handled correctly
1566// in RecomputeDirty() and don't cause deps to be loaded multiple times.
1567TEST_F(GraphTest, CycleWithLengthZeroFromDepfile) {
1568  AssertParse(&state_,
1569"rule deprule\n"
1570"   depfile = dep.d\n"
1571"   command = unused\n"
1572"build a b: deprule\n"
1573  );
1574  fs_.Create("dep.d", "a: b\n");
1575
1576  string err;
1577  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("a"), &err));
1578  ASSERT_EQ("dependency cycle: b -> b", err);
1579
1580  // Despite the depfile causing edge to be a cycle (it has outputs a and b,
1581  // but the depfile also adds b as an input), the deps should have been loaded
1582  // only once:
1583  Edge* edge = GetNode("a")->in_edge();
1584  EXPECT_EQ(1, edge->inputs_.size());
1585  EXPECT_EQ("b", edge->inputs_[0]->path());
1586}
1587
1588// Like CycleWithLengthZeroFromDepfile but with a higher cycle length.
1589TEST_F(GraphTest, CycleWithLengthOneFromDepfile) {
1590  AssertParse(&state_,
1591"rule deprule\n"
1592"   depfile = dep.d\n"
1593"   command = unused\n"
1594"rule r\n"
1595"   command = unused\n"
1596"build a b: deprule\n"
1597"build c: r b\n"
1598  );
1599  fs_.Create("dep.d", "a: c\n");
1600
1601  string err;
1602  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("a"), &err));
1603  ASSERT_EQ("dependency cycle: b -> c -> b", err);
1604
1605  // Despite the depfile causing edge to be a cycle (|edge| has outputs a and b,
1606  // but c's in_edge has b as input but the depfile also adds |edge| as
1607  // output)), the deps should have been loaded only once:
1608  Edge* edge = GetNode("a")->in_edge();
1609  EXPECT_EQ(1, edge->inputs_.size());
1610  EXPECT_EQ("c", edge->inputs_[0]->path());
1611}
1612
1613// Like CycleWithLengthOneFromDepfile but building a node one hop away from
1614// the cycle.
1615TEST_F(GraphTest, CycleWithLengthOneFromDepfileOneHopAway) {
1616  AssertParse(&state_,
1617"rule deprule\n"
1618"   depfile = dep.d\n"
1619"   command = unused\n"
1620"rule r\n"
1621"   command = unused\n"
1622"build a b: deprule\n"
1623"build c: r b\n"
1624"build d: r a\n"
1625  );
1626  fs_.Create("dep.d", "a: c\n");
1627
1628  string err;
1629  EXPECT_FALSE(scan_.RecomputeDirty(GetNode("d"), &err));
1630  ASSERT_EQ("dependency cycle: b -> c -> b", err);
1631
1632  // Despite the depfile causing edge to be a cycle (|edge| has outputs a and b,
1633  // but c's in_edge has b as input but the depfile also adds |edge| as
1634  // output)), the deps should have been loaded only once:
1635  Edge* edge = GetNode("a")->in_edge();
1636  EXPECT_EQ(1, edge->inputs_.size());
1637  EXPECT_EQ("c", edge->inputs_[0]->path());
1638}
1639
1640#ifdef _WIN32
1641TEST_F(GraphTest, Decanonicalize) {
1642  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
1643"build out\\out1: cat src\\in1\n"
1644"build out\\out2/out3\\out4: cat mid1\n"
1645"build out3 out4\\foo: cat mid1\n"));
1646
1647  string err;
1648  vector<Node*> root_nodes = state_.RootNodes(&err);
1649  EXPECT_EQ(4u, root_nodes.size());
1650  EXPECT_EQ(root_nodes[0]->path(), "out/out1");
1651  EXPECT_EQ(root_nodes[1]->path(), "out/out2/out3/out4");
1652  EXPECT_EQ(root_nodes[2]->path(), "out3");
1653  EXPECT_EQ(root_nodes[3]->path(), "out4/foo");
1654  EXPECT_EQ(root_nodes[0]->PathDecanonicalized(), "out\\out1");
1655  EXPECT_EQ(root_nodes[1]->PathDecanonicalized(), "out\\out2/out3\\out4");
1656  EXPECT_EQ(root_nodes[2]->PathDecanonicalized(), "out3");
1657  EXPECT_EQ(root_nodes[3]->PathDecanonicalized(), "out4\\foo");
1658}
1659#endif
1660
1661*/