ninja_build/build.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
16use std::cell::{Cell, RefCell};
17use std::collections::{BTreeMap, BTreeSet, btree_map};
18
19use super::state::State;
20use super::deps_log::DepsLog;
21use super::build_log::BuildLog;
22use super::disk_interface::DiskInterface;
23use super::graph::{NodeIndex, EdgeIndex, DependencyScan};
24use super::exit_status::ExitStatus;
25use super::metrics::Stopwatch;
26use super::metrics::get_time_millis;
27use super::debug_flags::KEEP_RSP;
28use super::timestamp::TimeStamp;
29use super::subprocess::SubprocessSet;
30use super::utils::{get_load_average, pathbuf_from_bytes};
31use super::line_printer::{LinePrinter, LinePrinterLineType};
32
33pub enum EdgeResult {
34 EdgeFailed,
35 EdgeSucceeded,
36}
37
38/// Plan stores the state of a build plan: what we intend to build,
39/// which steps we're ready to execute.
40pub struct Plan {
41 wanted_edges: usize,
42 command_edges: usize,
43
44 /// Keep track of which edges we want to build in this plan. If this map does
45 /// not contain an entry for an edge, we do not want to build the entry or its
46 /// dependents. If an entry maps to false, we do not want to build it, but we
47 /// might want to build one of its dependents. If the entry maps to true, we
48 /// want to build it.
49 want: BTreeMap<EdgeIndex, bool>,
50 ready: BTreeSet<EdgeIndex>,
51}
52
53trait IsVacant {
54 fn is_vacant(&self) -> bool;
55}
56
57impl<'a, K, V> IsVacant for btree_map::Entry<'a, K, V> {
58 fn is_vacant(&self) -> bool {
59 match self {
60 &btree_map::Entry::Vacant(_) => true,
61 _ => false,
62 }
63 }
64}
65
66
67impl Plan {
68 pub fn new() -> Self {
69 Plan {
70 wanted_edges: 0usize,
71 command_edges: 0usize,
72 want: BTreeMap::new(),
73 ready: BTreeSet::new(),
74 }
75 }
76
77 /// Add a target to our plan (including all its dependencies).
78 /// Returns false if we don't need to build this target; may
79 /// fill in |err| with an error message if there's a problem.
80 pub fn add_target(&mut self, state: &State, node: NodeIndex) -> Result<bool, String> {
81 self.add_sub_target(state, node, None)
82 }
83
84 pub fn add_sub_target(
85 &mut self,
86 state: &State,
87 node_idx: NodeIndex,
88 dependent: Option<NodeIndex>,
89 ) -> Result<bool, String> {
90 let node = state.node_state.get_node(node_idx);
91 let edge_idx = node.in_edge();
92 if edge_idx.is_none() {
93 if node.is_dirty() {
94 let mut err = format!("'{}'", String::from_utf8_lossy(node.path()));
95 if let Some(dependent) = dependent {
96 err += &format!(
97 ", needed by '{}',",
98 String::from_utf8_lossy(state.node_state.get_node(dependent).path())
99 );
100 }
101 err += " missing and no known rule to make it";
102 return Err(err);
103 }
104 return Ok(false);
105 }
106 let edge_idx = edge_idx.unwrap();
107 let edge = state.edge_state.get_edge(edge_idx);
108 if edge.outputs_ready() {
109 return Ok(false); // Don't need to do anything.
110 }
111
112 // If an entry in want_ does not already exist for edge, create an entry which
113 // maps to false, indicating that we do not want to build this entry itself.
114 let want = self.want.get(&edge_idx).cloned();
115 let vacant = want.is_none();
116
117 if node.is_dirty() && want.unwrap_or(false) == false {
118 self.want.insert(edge_idx, true);
119 self.wanted_edges += 1;
120 if edge.all_inputs_ready(state) {
121 self.schedule_work(state, edge_idx);
122 }
123 if !edge.is_phony() {
124 self.command_edges += 1;
125 }
126 }
127
128 if vacant {
129 for input_node_idx in edge.inputs.iter() {
130 self.add_sub_target(state, *input_node_idx, Some(node_idx))?;
131 }
132 }
133
134 return Ok(true);
135 }
136
137 /// Number of edges with commands to run.
138 fn command_edge_count(&self) -> usize {
139 return self.command_edges;
140 }
141
142 /// Reset state. Clears want and ready sets.
143 fn reset(&mut self) {
144 self.command_edges = 0;
145 self.wanted_edges = 0;
146 self.ready.clear();
147 self.want.clear();
148 }
149
150 /// Returns true if there's more work to be done.
151 pub fn more_to_do(&self) -> bool {
152 self.wanted_edges > 0 && self.command_edges > 0
153 }
154
155 /// Submits a ready edge as a candidate for execution.
156 /// The edge may be delayed from running, for example if it's a member of a
157 /// currently-full pool.
158 pub fn schedule_work(&mut self, state: &State, edge_idx: EdgeIndex) {
159 if self.ready.get(&edge_idx).is_some() {
160 // This edge has already been scheduled. We can get here again if an edge
161 // and one of its dependencies share an order-only input, or if a node
162 // duplicates an out edge (see https://github.com/ninja-build/ninja/pull/519).
163 // Avoid scheduling the work again.
164 return;
165 }
166
167 let edge = state.edge_state.get_edge(edge_idx);
168 let mut pool = edge.pool.borrow_mut();
169 if pool.should_delay_edge() {
170 pool.delay_edge(state, edge_idx);
171 pool.retrieve_ready_edges(state, &mut self.ready);
172 } else {
173 pool.edge_scheduled(state, edge_idx);
174 self.ready.insert(edge_idx);
175 }
176 }
177
178 // Pop a ready edge off the queue of edges to build.
179 // Returns NULL if there's no work to do.
180 pub fn find_work(&mut self) -> Option<EdgeIndex> {
181 match self.ready.iter().next().cloned() {
182 Some(idx) => {
183 self.ready.remove(&idx);
184 Some(idx)
185 }
186 None => None,
187 }
188 }
189
190 /// Mark an edge as done building (whether it succeeded or failed).
191 pub fn edge_finished(&mut self, state: &mut State, edge_idx: EdgeIndex, result: EdgeResult) {
192 let directly_wanted = self.want.get(&edge_idx).unwrap().clone();
193
194 {
195 let edge = state.edge_state.get_edge(edge_idx);
196
197 // See if this job frees up any delayed jobs.
198 if directly_wanted {
199 edge.pool.borrow_mut().edge_finished(state, edge_idx);
200 }
201
202 edge.pool.borrow_mut().retrieve_ready_edges(
203 state,
204 &mut self.ready,
205 );
206 }
207
208
209 match result {
210 EdgeResult::EdgeSucceeded => {
211 if directly_wanted {
212 self.wanted_edges -= 1;
213 }
214 self.want.remove(&edge_idx);
215
216 state.edge_state.get_edge_mut(edge_idx).outputs_ready = true;
217
218 // Check off any nodes we were waiting for with this edge.
219 for output_node_idx in state
220 .edge_state
221 .get_edge_mut(edge_idx)
222 .outputs
223 .clone()
224 .into_iter()
225 {
226 self.node_finished(state, output_node_idx);
227 }
228 }
229 _ => {}
230 };
231 }
232
233 pub fn node_finished(&mut self, state: &mut State, node_idx: NodeIndex) {
234 // See if we we want any edges from this node.
235 for out_edge_idx in state
236 .node_state
237 .get_node(node_idx)
238 .out_edges()
239 .to_owned()
240 .into_iter()
241 {
242 let want_e = self.want.get(&out_edge_idx).cloned();
243 if want_e.is_none() {
244 continue;
245 }
246
247 {
248 let oe = state.edge_state.get_edge(out_edge_idx);
249 if !oe.all_inputs_ready(state) {
250 continue;
251 }
252 }
253
254 if want_e.unwrap() {
255 self.schedule_work(state, out_edge_idx);
256 } else {
257 // We do not need to build this edge, but we might need to build one of
258 // its dependents.
259 self.edge_finished(state, out_edge_idx, EdgeResult::EdgeSucceeded);
260 }
261 }
262 }
263
264 /// Clean the given node during the build.
265 /// Return false on error.
266 pub fn clean_node(
267 &mut self,
268 scan: &DependencyScan,
269 State: &State,
270 node_idx: NodeIndex,
271 ) -> Result<(), String> {
272 unimplemented!()
273 }
274}
275
276/*
277
278struct Plan {
279 Plan();
280
281 /// Dumps the current state of the plan.
282 void Dump();
283
284 enum EdgeResult {
285 kEdgeFailed,
286 kEdgeSucceeded
287 };
288
289
290 /// Clean the given node during the build.
291 /// Return false on error.
292 bool CleanNode(DependencyScan* scan, Node* node, string* err);
293
294
295 /// Reset state. Clears want and ready sets.
296 void Reset();
297
298private:
299 bool AddSubTarget(Node* node, Node* dependent, string* err);
300 void NodeFinished(Node* node);
301
302 set<Edge*> ready_;
303
304 /// Total number of edges that have commands (not phony).
305 int command_edges_;
306
307 /// Total remaining number of wanted edges.
308 int wanted_edges_;
309};
310*/
311
312/// CommandRunner is an interface that wraps running the build
313/// subcommands. This allows tests to abstract out running commands.
314/// RealCommandRunner is an implementation that actually runs commands.
315
316/// The result of waiting for a command.
317pub struct CommandRunnerResult {
318 pub edge: EdgeIndex,
319 pub status: ExitStatus,
320 pub output: Vec<u8>,
321}
322
323impl CommandRunnerResult {
324 fn is_success(&self) -> bool {
325 match self.status {
326 ExitStatus::ExitSuccess => true,
327 _ => false,
328 }
329 }
330}
331
332pub trait CommandRunner {
333 fn can_run_more(&self) -> bool;
334 fn start_command(&mut self, state: &State, edge: EdgeIndex) -> bool;
335 /// Wait for a command to complete, or return false if interrupted.
336 fn wait_for_command(&mut self) -> Option<CommandRunnerResult>;
337 fn get_active_edges(&self) -> Vec<EdgeIndex>;
338 fn abort(&mut self);
339}
340
341pub enum BuildConfigVerbosity {
342 NORMAL,
343 QUIET, // No output -- used when testing.
344 VERBOSE,
345}
346
347/// Options (e.g. verbosity, parallelism) passed to a build.
348pub struct BuildConfig {
349 pub verbosity: BuildConfigVerbosity,
350 pub dry_run: bool,
351 pub parallelism: usize,
352 pub failures_allowed: usize,
353 pub max_load_average: f64,
354}
355
356impl BuildConfig {
357 pub fn new() -> Self {
358 BuildConfig {
359 verbosity: BuildConfigVerbosity::NORMAL,
360 dry_run: false,
361 parallelism: 1,
362 failures_allowed: 1,
363 max_load_average: -0.0f64,
364 }
365 }
366}
367
368/*
369struct BuildConfig {
370 BuildConfig() : verbosity(NORMAL), dry_run(false), parallelism(1),
371 failures_allowed(1), max_load_average(-0.0f) {}
372
373 enum Verbosity {
374 NORMAL,
375 QUIET, // No output -- used when testing.
376 VERBOSE
377 };
378 Verbosity verbosity;
379 bool dry_run;
380 int parallelism;
381 int failures_allowed;
382 /// The maximum load average we must not exceed. A negative value
383 /// means that we do not have any limit.
384 double max_load_average;
385};
386*/
387
388/// Builder wraps the build process: starting commands, updating status.
389pub struct Builder<'s, 'p, 'a, 'b, 'c>
390where
391 's: 'a,
392{
393 state: &'s mut State,
394 config: &'p BuildConfig,
395 plan: Plan,
396 command_runner: Option<Box<CommandRunner + 'p>>,
397 disk_interface: &'c DiskInterface,
398 scan: DependencyScan<'s, 'a, 'b, 'c>,
399 status: BuildStatus<'p>,
400}
401
402impl<'s, 'p, 'a, 'b, 'c> Builder<'s, 'p, 'a, 'b, 'c>
403where
404 's: 'a,
405{
406 pub fn new(
407 state: &'s mut State,
408 config: &'p BuildConfig,
409 build_log: &'a BuildLog<'s>,
410 deps_log: &'b DepsLog,
411 disk_interface: &'c DiskInterface,
412 ) -> Self {
413 Builder {
414 state,
415 config,
416 plan: Plan::new(),
417 command_runner: None,
418 disk_interface,
419 scan: DependencyScan::new(build_log, deps_log, disk_interface),
420 status: BuildStatus::new(config),
421 }
422 }
423
424 /// Add a target to the build, scanning dependencies.
425 /// @return false on error.
426 pub fn add_target(&mut self, node_idx: NodeIndex) -> Result<(), String> {
427 self.scan.recompute_dirty(self.state, node_idx)?;
428
429 if let Some(in_edge) = self.state.node_state.get_node(node_idx).in_edge() {
430 if self.state.edge_state.get_edge(in_edge).outputs_ready() {
431 return Ok(()); // Nothing to do.
432 }
433 }
434
435 self.plan.add_target(self.state, node_idx)?;
436
437 Ok(())
438 }
439
440 /// Returns true if the build targets are already up to date.
441 pub fn is_already_up_to_date(&mut self) -> bool {
442 !self.plan.more_to_do()
443 }
444
445 /// Run the build. Returns false on error.
446 /// It is an error to call this function when AlreadyUpToDate() is true.
447 pub fn build(&mut self) -> Result<(), String> {
448 assert!(!self.is_already_up_to_date());
449
450 self.status.plan_has_total_edges(
451 self.plan.command_edge_count(),
452 );
453
454 let mut pending_commands = 0;
455 let mut failures_allowed = self.config.failures_allowed;
456
457 // Set up the command runner if we haven't done so already.
458 let config = self.config;
459 if self.command_runner.is_none() {
460 self.command_runner = Some(if config.dry_run {
461 Box::new(DryRunCommandRunner::new())
462 } else {
463 Box::new(RealCommandRunner::new(config))
464 });
465 }
466
467 // We are about to start the build process.
468 self.status.build_started();
469
470 // This main loop runs the entire build process.
471 // It is structured like this:
472 // First, we attempt to start as many commands as allowed by the
473 // command runner.
474 // Second, we attempt to wait for / reap the next finished command.
475
476 while self.plan.more_to_do() {
477 // See if we can start any more commands.
478 if failures_allowed > 0 && self.command_runner.as_ref().unwrap().can_run_more() {
479 if let Some(edge_idx) = self.plan.find_work() {
480 if let Err(e) = self.start_edge(edge_idx) {
481 self.cleanup();
482 self.status.build_finished();
483 return Err(e);
484 };
485
486 if self.state.edge_state.get_edge(edge_idx).is_phony() {
487 self.plan.edge_finished(
488 self.state,
489 edge_idx,
490 EdgeResult::EdgeSucceeded,
491 );
492 } else {
493 pending_commands += 1;
494 }
495
496 // We made some progress; go back to the main loop.
497 continue;
498 }
499 }
500
501 // See if we can reap any finished commands.
502 if pending_commands > 0 {
503 let result = self.command_runner.as_mut().unwrap().wait_for_command();
504
505 if result.is_none() ||
506 result.as_ref().unwrap().status == ExitStatus::ExitInterrupted
507 {
508 self.cleanup();
509 self.status.build_finished();
510 return Err("interrupted by user".to_owned());
511 }
512
513 pending_commands -= 1;
514 let result = self.finish_command(result.unwrap());
515 if let Err(e) = result {
516 self.cleanup();
517 self.status.build_finished();
518 return Err(e);
519 }
520
521 let result = result.unwrap();
522 if !result.is_success() {
523 if failures_allowed > 0 {
524 failures_allowed -= 1;
525 }
526 }
527
528 // We made some progress; start the main loop over.
529 continue;
530 }
531
532 // If we get here, we cannot make any more progress.
533 self.status.build_finished();
534 return match failures_allowed {
535 0 if config.failures_allowed > 1 => Err("subcommands failed".to_owned()),
536 0 => Err("subcommand failed".to_owned()),
537 _ if failures_allowed < self.config.failures_allowed => Err(
538 "cannot make progress due to previous errors"
539 .to_owned(),
540 ),
541 _ => Err("stuck [this is a bug]".to_owned()),
542 };
543 }
544
545 self.status.build_finished();
546 return Ok(());
547 }
548
549 fn start_edge(&mut self, edge_idx: EdgeIndex) -> Result<(), String> {
550 metric_record!("StartEdge");
551 let edge = self.state.edge_state.get_edge(edge_idx);
552 if edge.is_phony() {
553 return Ok(());
554 }
555
556 self.status.build_edge_started(self.state, edge_idx);
557
558 // Create directories necessary for outputs.
559 // XXX: this will block; do we care?
560 for out_idx in edge.outputs.iter() {
561 let path = pathbuf_from_bytes(
562 self.state.node_state.get_node(*out_idx).path().to_owned(),
563 ).map_err(|e| {
564 format!("invalid utf-8 filename: {}", String::from_utf8_lossy(&e))
565 })?;
566 if let Some(parent) = path.parent() {
567 self.disk_interface.make_dirs(parent).map_err(
568 |e| format!("{}", e),
569 )?;
570 }
571 }
572
573 // Create response file, if needed
574 // XXX: this may also block; do we care?
575 let rspfile = edge.get_unescaped_rspfile(&self.state.node_state);
576 if !rspfile.as_ref().is_empty() {
577 let content = edge.get_binding(&self.state.node_state, b"rspfile_content");
578 let rspfile_path = pathbuf_from_bytes(rspfile.into_owned()).map_err(|e| {
579 format!("invalid utf-8 filename: {}", String::from_utf8_lossy(&e))
580 })?;
581 self.disk_interface
582 .write_file(&rspfile_path, content.as_ref())
583 .map_err(|_| String::new())?;
584 }
585
586 // start command computing and run it
587 if !self.command_runner.as_mut().unwrap().start_command(
588 self.state,
589 edge_idx,
590 )
591 {
592 return Err(format!(
593 "command '{}' failed.",
594 String::from_utf8_lossy(
595 &edge.evaluate_command(&self.state.node_state),
596 )
597 ));
598 }
599
600 Ok(())
601 }
602
603 /// Update status ninja logs following a command termination.
604 /// @return false if the build can not proceed further due to a fatal error.
605 fn finish_command(
606 &mut self,
607 mut result: CommandRunnerResult,
608 ) -> Result<CommandRunnerResult, String> {
609 use errno;
610
611 metric_record!("FinishCommand");
612
613 let edge_idx = result.edge;
614
615 // First try to extract dependencies from the result, if any.
616 // This must happen first as it filters the command output (we want
617 // to filter /showIncludes output, even on compile failure) and
618 // extraction itself can fail, which makes the command fail from a
619 // build perspective.
620 let mut deps_nodes = Vec::new();
621
622 let (deps_type, deps_prefix) = {
623 let edge = self.state.edge_state.get_edge(edge_idx);
624 let deps_type = edge.get_binding(&self.state.node_state, b"deps");
625 let deps_prefix = edge.get_binding(&self.state.node_state, b"msvc_deps_prefix");
626 (deps_type.into_owned(), deps_prefix.into_owned())
627 };
628 if !deps_type.is_empty() {
629 match self.extract_deps(&mut result, deps_type.as_ref(), deps_prefix.as_ref()) {
630 Ok(n) => {
631 deps_nodes = n;
632 }
633 Err(e) => {
634 if result.is_success() {
635 if !result.output.is_empty() {
636 result.output.extend_from_slice(b"\n".as_ref());
637 }
638 result.output.extend_from_slice(e.as_bytes());
639 result.status = ExitStatus::ExitFailure;
640 }
641 }
642 }
643 }
644
645 let (start_time, end_time) = self.status.build_edge_finished(
646 self.state,
647 edge_idx,
648 result.is_success(),
649 &result.output,
650 );
651
652 if !result.is_success() {
653 self.plan.edge_finished(
654 self.state,
655 edge_idx,
656 EdgeResult::EdgeFailed,
657 );
658 return Ok(result);
659 }
660
661 // The rest of this function only applies to successful commands.
662
663 // Restat the edge outputs
664 let mut output_mtime = TimeStamp(0);
665 let restat = self.state.edge_state.get_edge(edge_idx).get_binding_bool(
666 &self.state
667 .node_state,
668 b"restat",
669 );
670 if !self.config.dry_run {
671 let edge = self.state.edge_state.get_edge(edge_idx);
672 let mut node_cleaned = false;
673 for o_node_idx in edge.outputs.iter() {
674 let o_node = self.state.node_state.get_node(*o_node_idx);
675 let path = pathbuf_from_bytes(o_node.path().to_owned()).map_err(|e| {
676 format!("Invalid utf-8 pathname {}", String::from_utf8_lossy(&e))
677 })?;
678 let new_mtime = self.disk_interface.stat(&path)?;
679 if new_mtime > output_mtime {
680 output_mtime = new_mtime;
681 }
682 if o_node.mtime() == new_mtime && restat {
683 // The rule command did not change the output. Propagate the clean
684 // state through the build graph.
685 // Note that this also applies to nonexistent outputs (mtime == 0).
686 self.plan.clean_node(&self.scan, self.state, *o_node_idx)?;
687 node_cleaned = true;
688 }
689 }
690
691 if node_cleaned {
692 let mut restat_mtime = TimeStamp(0);
693 // If any output was cleaned, find the most recent mtime of any
694 // (existing) non-order-only input or the depfile.
695 for i_idx in edge.inputs[edge.non_order_only_deps_range()].iter() {
696 let path = pathbuf_from_bytes(
697 self.state.node_state.get_node(*i_idx).path().to_owned(),
698 ).map_err(|e| {
699 format!("invalid utf-8 filename: {}", String::from_utf8_lossy(&e))
700 })?;
701 let input_mtime = self.disk_interface.stat(&path)?;
702 if input_mtime > restat_mtime {
703 restat_mtime = input_mtime;
704 }
705 }
706
707 let depfile = edge.get_unescaped_depfile(&self.state.node_state);
708 if restat_mtime.0 != 0 && deps_type.is_empty() && !depfile.is_empty() {
709 let path = pathbuf_from_bytes(depfile.into_owned()).map_err(|e| {
710 format!("invalid utf-8 filename: {}", String::from_utf8_lossy(&e))
711 })?;
712 let depfile_mtime = self.disk_interface.stat(&path)?;
713 if depfile_mtime > restat_mtime {
714 restat_mtime = depfile_mtime;
715 }
716 }
717
718 // The total number of edges in the plan may have changed as a result
719 // of a restat.
720 self.status.plan_has_total_edges(
721 self.plan.command_edge_count(),
722 );
723 output_mtime = restat_mtime;
724 }
725 }
726
727 self.plan.edge_finished(
728 self.state,
729 edge_idx,
730 EdgeResult::EdgeSucceeded,
731 );
732
733 let edge = self.state.edge_state.get_edge(edge_idx);
734 let rspfile = edge.get_unescaped_rspfile(&self.state.node_state);
735 if !rspfile.is_empty() && !KEEP_RSP {
736 if let Ok(path) = pathbuf_from_bytes(rspfile.into_owned()) {
737 let _ = self.disk_interface.remove_file(&path);
738 };
739 }
740
741 if let Some(build_log) = self.scan.build_log() {
742 build_log
743 .record_command(self.state, edge_idx, start_time, end_time, output_mtime)
744 .map_err(|e| {
745 format!("Error writing to build log: {}", errno::errno())
746 })?;
747 }
748
749 if !deps_type.is_empty() && !self.config.dry_run {
750 assert!(edge.outputs.len() == 1);
751 //or it should have been rejected by parser.
752 let out_idx = edge.outputs[0];
753 let out = self.state.node_state.get_node(out_idx);
754 let path = pathbuf_from_bytes(out.path().to_owned()).map_err(|e| {
755 format!("Invalid utf-8 pathname {}", String::from_utf8_lossy(&e))
756 })?;
757
758 let deps_mtime = self.disk_interface.stat(&path)?;
759
760 self.scan
761 .deps_log()
762 .record_deps(self.state, out_idx, deps_mtime, &deps_nodes)
763 .map_err(|e| format!("Error writing to deps log: {}", errno::errno()))?;
764 }
765
766 Ok(result)
767 }
768
769 /// Clean up after interrupted commands by deleting output files.
770 pub fn cleanup(&mut self) {
771 if self.command_runner.is_none() {
772 return;
773 }
774 let command_runner = self.command_runner.as_mut().unwrap();
775
776 let active_edges = command_runner.get_active_edges();
777 command_runner.abort();
778 for edge_idx in active_edges.into_iter() {
779 let edge = self.state.edge_state.get_edge(edge_idx);
780 let depfile = edge.get_unescaped_depfile(&self.state.node_state)
781 .into_owned();
782 for out_idx in edge.outputs.iter() {
783 // Only delete this output if it was actually modified. This is
784 // important for things like the generator where we don't want to
785 // delete the manifest file if we can avoid it. But if the rule
786 // uses a depfile, always delete. (Consider the case where we
787 // need to rebuild an output because of a modified header file
788 // mentioned in a depfile, and the command touches its depfile
789 // but is interrupted before it touches its output file.)
790 let out_node = self.state.node_state.get_node(*out_idx);
791 match pathbuf_from_bytes(out_node.path().to_owned()) {
792 Err(e) => {
793 error!("invalid utf-8 filename: {}", String::from_utf8_lossy(&e));
794 }
795 Ok(path) => {
796 match self.disk_interface.stat(&path) {
797 Err(e) => {
798 error!("{}", e);
799 }
800 Ok(new_mtime) => {
801 if !depfile.is_empty() || out_node.mtime() != new_mtime {
802 let _ = self.disk_interface.remove_file(&path);
803 }
804 }
805 }
806 }
807 }
808 }
809 if !depfile.is_empty() {
810 match pathbuf_from_bytes(depfile) {
811 Err(e) => {
812 error!("invalid utf-8 filename: {}", String::from_utf8_lossy(&e));
813 }
814 Ok(path) => {
815 let _ = self.disk_interface.remove_file(&path);
816 }
817 };
818 }
819 }
820 }
821
822 fn extract_deps(
823 &self,
824 result: &mut CommandRunnerResult,
825 deps_type: &[u8],
826 deps_prefix: &[u8],
827 ) -> Result<Vec<NodeIndex>, String> {
828 if deps_type == b"msvc" {
829 /*
830 CLParser parser;
831 string output;
832 if (!parser.Parse(result->output, deps_prefix, &output, err))
833 return false;
834 result->output = output;
835 for (set<string>::iterator i = parser.includes_.begin();
836 i != parser.includes_.end(); ++i) {
837 // ~0 is assuming that with MSVC-parsed headers, it's ok to always make
838 // all backslashes (as some of the slashes will certainly be backslashes
839 // anyway). This could be fixed if necessary with some additional
840 // complexity in IncludesNormalize::Relativize.
841 deps_nodes->push_back(state_->GetNode(*i, ~0u));
842 }
843*/
844 return Ok(Vec::new());
845 unimplemented!{}
846 } else if deps_type == b"gcc" {
847 /*
848 string depfile = result->edge->GetUnescapedDepfile();
849 if (depfile.empty()) {
850 *err = string("edge with deps=gcc but no depfile makes no sense");
851 return false;
852 }
853
854 // Read depfile content. Treat a missing depfile as empty.
855 string content;
856 switch (disk_interface_->ReadFile(depfile, &content, err)) {
857 case DiskInterface::Okay:
858 break;
859 case DiskInterface::NotFound:
860 err->clear();
861 break;
862 case DiskInterface::OtherError:
863 return false;
864 }
865 if (content.empty())
866 return true;
867
868 DepfileParser deps;
869 if (!deps.Parse(&content, err))
870 return false;
871
872 // XXX check depfile matches expected output.
873 deps_nodes->reserve(deps.ins_.size());
874 for (vector<StringPiece>::iterator i = deps.ins_.begin();
875 i != deps.ins_.end(); ++i) {
876 uint64_t slash_bits;
877 if (!CanonicalizePath(const_cast<char*>(i->str_), &i->len_, &slash_bits,
878 err))
879 return false;
880 deps_nodes->push_back(state_->GetNode(*i, slash_bits));
881 }
882
883 if (!g_keep_depfile) {
884 if (disk_interface_->RemoveFile(depfile) < 0) {
885 *err = string("deleting depfile: ") + strerror(errno) + string("\n");
886 return false;
887 }
888 }
889*/
890 return Ok(Vec::new());
891 unimplemented!{}
892 } else {
893 fatal!("unknown deps type '{}'", String::from_utf8_lossy(deps_type));
894 unreachable!();
895 }
896 }
897}
898
899impl<'s, 'p, 'a, 'b, 'c> Drop for Builder<'s, 'p, 'a, 'b, 'c> {
900 fn drop(&mut self) {
901 self.cleanup();
902 }
903}
904
905/*
906struct Builder {
907 Builder(State* state, const BuildConfig& config,
908 BuildLog* build_log, DepsLog* deps_log,
909 DiskInterface* disk_interface);
910 ~Builder();
911
912 /// Clean up after interrupted commands by deleting output files.
913 void Cleanup();
914
915 Node* AddTarget(const string& name, string* err);
916
917
918
919
920 /// Used for tests.
921 void SetBuildLog(BuildLog* log) {
922 scan_.set_build_log(log);
923 }
924
925 State* state_;
926 const BuildConfig& config_;
927 Plan plan_;
928 auto_ptr<CommandRunner> command_runner_;
929 BuildStatus* status_;
930
931 private:
932 bool ExtractDeps(CommandRunner::Result* result, const string& deps_type,
933 const string& deps_prefix, vector<Node*>* deps_nodes,
934 string* err);
935
936 DiskInterface* disk_interface_;
937 DependencyScan scan_;
938
939 // Unimplemented copy ctor and operator= ensure we don't copy the auto_ptr.
940 Builder(const Builder &other); // DO NOT IMPLEMENT
941 void operator=(const Builder &other); // DO NOT IMPLEMENT
942};
943*/
944
945enum BuildStatusEdgeStatus {
946 EdgeStarted,
947 EdgeFinished,
948}
949
950/// Tracks the status of a build: completion fraction, printing updates.
951struct BuildStatus<'a> {
952 config: &'a BuildConfig,
953
954 /// Time the build started.
955 start_time_millis: u64,
956
957 started_edges: usize,
958 running_edges: BTreeMap<EdgeIndex, u64>,
959 /// Map of running edge to time the edge started running.
960 finished_edges: usize,
961 total_edges: usize,
962
963 /// The custom progress status format to use.
964 progress_status_format: Vec<u8>,
965
966 /// Prints progress output.
967 printer: LinePrinter,
968
969 overall_rate: RefCell<RateInfo>,
970 current_rate: RefCell<SlidingRateInfo>,
971}
972
973impl<'a> BuildStatus<'a> {
974 pub fn new(config: &'a BuildConfig) -> Self {
975 let v = BuildStatus {
976 config,
977
978 start_time_millis: get_time_millis(),
979
980 started_edges: 0,
981 running_edges: BTreeMap::new(),
982 finished_edges: 0,
983 total_edges: 0,
984
985 progress_status_format: Vec::new(), // TODO
986 printer: LinePrinter::new(),
987
988 overall_rate: RefCell::new(RateInfo::new()),
989 current_rate: RefCell::new(SlidingRateInfo::new(config.parallelism)),
990 };
991 return v;
992 unimplemented!{}
993 }
994
995 pub fn plan_has_total_edges(&mut self, total: usize) {
996 self.total_edges = total;
997 }
998
999 pub fn build_started(&mut self) {
1000 self.overall_rate.borrow_mut().restart();
1001 self.current_rate.borrow_mut().restart();
1002 }
1003
1004 pub fn build_finished(&mut self) {
1005 self.printer.set_console_locked(false);
1006 self.printer.print_on_new_line(b"");
1007 }
1008
1009 pub fn build_edge_started(&mut self, state: &State, edge_idx: EdgeIndex) {
1010 let start_time = get_time_millis() - self.start_time_millis;
1011 self.running_edges.insert(edge_idx, start_time);
1012 self.started_edges += 1;
1013
1014 let edge_use_console = state.edge_state.get_edge(edge_idx).use_console();
1015 if edge_use_console || self.printer.is_smart_terminal() {
1016 self.print_status(state, edge_idx, BuildStatusEdgeStatus::EdgeStarted);
1017 }
1018
1019 if edge_use_console {
1020 self.printer.set_console_locked(true);
1021 }
1022 }
1023
1024 pub fn build_edge_finished(
1025 &mut self,
1026 state: &State,
1027 edge_idx: EdgeIndex,
1028 success: bool,
1029 output: &[u8],
1030 ) -> (u64, u64) {
1031 let now = get_time_millis();
1032 self.finished_edges += 1;
1033
1034 let start_time = self.running_edges.remove(&edge_idx).unwrap();
1035 let end_time = now - self.start_time_millis;
1036
1037 if state.edge_state.get_edge(edge_idx).use_console() {
1038 self.printer.set_console_locked(false);
1039 }
1040
1041 match self.config.verbosity {
1042 BuildConfigVerbosity::QUIET => {
1043 return (start_time, end_time);
1044 }
1045 _ => {}
1046 };
1047
1048 /*
1049 if (!edge->use_console())
1050 PrintStatus(edge, kEdgeFinished);
1051
1052 // Print the command that is spewing before printing its output.
1053 if (!success) {
1054 string outputs;
1055 for (vector<Node*>::const_iterator o = edge->outputs_.begin();
1056 o != edge->outputs_.end(); ++o)
1057 outputs += (*o)->path() + " ";
1058
1059 printer_.PrintOnNewLine("FAILED: " + outputs + "\n");
1060 printer_.PrintOnNewLine(edge->EvaluateCommand() + "\n");
1061 }
1062
1063 if (!output.empty()) {
1064 // ninja sets stdout and stderr of subprocesses to a pipe, to be able to
1065 // check if the output is empty. Some compilers, e.g. clang, check
1066 // isatty(stderr) to decide if they should print colored output.
1067 // To make it possible to use colored output with ninja, subprocesses should
1068 // be run with a flag that forces them to always print color escape codes.
1069 // To make sure these escape codes don't show up in a file if ninja's output
1070 // is piped to a file, ninja strips ansi escape codes again if it's not
1071 // writing to a |smart_terminal_|.
1072 // (Launching subprocesses in pseudo ttys doesn't work because there are
1073 // only a few hundred available on some systems, and ninja can launch
1074 // thousands of parallel compile commands.)
1075 // TODO: There should be a flag to disable escape code stripping.
1076 string final_output;
1077 if (!printer_.is_smart_terminal())
1078 final_output = StripAnsiEscapeCodes(output);
1079 else
1080 final_output = output;
1081
1082#ifdef _WIN32
1083 // Fix extra CR being added on Windows, writing out CR CR LF (#773)
1084 _setmode(_fileno(stdout), _O_BINARY); // Begin Windows extra CR fix
1085#endif
1086
1087 printer_.PrintOnNewLine(final_output);
1088
1089#ifdef _WIN32
1090 _setmode(_fileno(stdout), _O_TEXT); // End Windows extra CR fix
1091#endif
1092 }
1093*/
1094 return (start_time, end_time);
1095 unimplemented!();
1096 }
1097
1098 /// Format the progress status string by replacing the placeholders.
1099 /// See the user manual for more information about the available
1100 /// placeholders.
1101 /// @param progress_status_format The format of the progress status.
1102 /// @param status The status of the edge.
1103 pub fn format_progress_status(
1104 progress_status_format: &[u8],
1105 status: BuildStatusEdgeStatus,
1106 ) -> Vec<u8> {
1107 return Vec::new();
1108 unimplemented!()
1109 }
1110
1111 fn print_status(&self, state: &State, edge_idx: EdgeIndex, status: BuildStatusEdgeStatus) {
1112 let force_full_command = match self.config.verbosity {
1113 BuildConfigVerbosity::QUIET => {
1114 return;
1115 }
1116 BuildConfigVerbosity::VERBOSE => true,
1117 BuildConfigVerbosity::NORMAL => false,
1118 };
1119
1120 let edge = state.edge_state.get_edge(edge_idx);
1121 let mut desc_or_cmd = edge.get_binding(&state.node_state, b"description");
1122 if desc_or_cmd.is_empty() || force_full_command {
1123 desc_or_cmd = edge.get_binding(&state.node_state, b"command");
1124 }
1125
1126 let mut to_print = Self::format_progress_status(&self.progress_status_format, status);
1127 to_print.extend_from_slice(&desc_or_cmd);
1128 let ty = if force_full_command {
1129 LinePrinterLineType::Full
1130 } else {
1131 LinePrinterLineType::Elide
1132 };
1133 self.printer.print(&to_print, ty);
1134 }
1135}
1136/*
1137struct BuildStatus {
1138 explicit BuildStatus(const BuildConfig& config);
1139 void PlanHasTotalEdges(int total);
1140 void BuildEdgeStarted(Edge* edge);
1141 void BuildEdgeFinished(Edge* edge, bool success, const string& output,
1142 int* start_time, int* end_time);
1143 void BuildStarted();
1144 void BuildFinished();
1145
1146
1147
1148 private:
1149 void PrintStatus(Edge* edge, EdgeStatus status);
1150
1151
1152
1153 template<size_t S>
1154 void SnprintfRate(double rate, char(&buf)[S], const char* format) const {
1155 if (rate == -1)
1156 snprintf(buf, S, "?");
1157 else
1158 snprintf(buf, S, format, rate);
1159 }
1160*/
1161
1162struct RateInfo {
1163 rate: f64,
1164 stopwatch: Stopwatch,
1165}
1166
1167impl RateInfo {
1168 pub fn new() -> Self {
1169 RateInfo {
1170 rate: -1f64,
1171 stopwatch: Stopwatch::new(),
1172 }
1173 }
1174
1175 pub fn restart(&mut self) {
1176 self.stopwatch.restart()
1177 }
1178}
1179
1180/*
1181 struct RateInfo {
1182 RateInfo() : rate_(-1) {}
1183
1184 void Restart() { stopwatch_.Restart(); }
1185 double Elapsed() const { return stopwatch_.Elapsed(); }
1186 double rate() { return rate_; }
1187
1188 void UpdateRate(int edges) {
1189 if (edges && stopwatch_.Elapsed())
1190 rate_ = edges / stopwatch_.Elapsed();
1191 }
1192
1193 private:
1194 double rate_;
1195 Stopwatch stopwatch_;
1196 };
1197
1198 */
1199
1200struct SlidingRateInfo {
1201 rate: f64,
1202 stopwatch: Stopwatch,
1203 max_len: usize,
1204 times: VecDeque<f64>,
1205 last_update: isize,
1206}
1207
1208impl SlidingRateInfo {
1209 pub fn new(n: usize) -> Self {
1210 SlidingRateInfo {
1211 rate: -1.0f64,
1212 stopwatch: Stopwatch::new(),
1213 max_len: n,
1214 times: VecDeque::new(),
1215 last_update: -1,
1216 }
1217 }
1218
1219 pub fn restart(&mut self) {
1220 self.stopwatch.restart();
1221 }
1222}
1223
1224/*
1225 struct SlidingRateInfo {
1226 SlidingRateInfo(int n) : rate_(-1), N(n), last_update_(-1) {}
1227
1228 void Restart() { stopwatch_.Restart(); }
1229 double rate() { return rate_; }
1230
1231 void UpdateRate(int update_hint) {
1232 if (update_hint == last_update_)
1233 return;
1234 last_update_ = update_hint;
1235
1236 if (times_.size() == N)
1237 times_.pop();
1238 times_.push(stopwatch_.Elapsed());
1239 if (times_.back() != times_.front())
1240 rate_ = times_.size() / (times_.back() - times_.front());
1241 }
1242
1243 private:
1244 double rate_;
1245 Stopwatch stopwatch_;
1246 const size_t N;
1247 queue<double> times_;
1248 int last_update_;
1249 };
1250
1251 mutable RateInfo overall_rate_;
1252 mutable SlidingRateInfo current_rate_;
1253};
1254
1255#endif // NINJA_BUILD_H_
1256*/
1257
1258/*
1259
1260// Copyright 2011 Google Inc. All Rights Reserved.
1261//
1262// Licensed under the Apache License, Version 2.0 (the "License");
1263// you may not use this file except in compliance with the License.
1264// You may obtain a copy of the License at
1265//
1266// http://www.apache.org/licenses/LICENSE-2.0
1267//
1268// Unless required by applicable law or agreed to in writing, software
1269// distributed under the License is distributed on an "AS IS" BASIS,
1270// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1271// See the License for the specific language governing permissions and
1272// limitations under the License.
1273
1274#include "build.h"
1275
1276#include <assert.h>
1277#include <errno.h>
1278#include <stdio.h>
1279#include <stdlib.h>
1280#include <functional>
1281
1282#ifdef _WIN32
1283#include <fcntl.h>
1284#include <io.h>
1285#endif
1286
1287#if defined(__SVR4) && defined(__sun)
1288#include <sys/termios.h>
1289#endif
1290
1291#include "build_log.h"
1292#include "clparser.h"
1293#include "debug_flags.h"
1294#include "depfile_parser.h"
1295#include "deps_log.h"
1296#include "disk_interface.h"
1297#include "graph.h"
1298#include "state.h"
1299#include "subprocess.h"
1300#include "util.h"
1301*/
1302
1303use std::collections::VecDeque;
1304
1305struct DryRunCommandRunner {
1306 finished: VecDeque<EdgeIndex>,
1307}
1308
1309impl DryRunCommandRunner {
1310 pub fn new() -> Self {
1311 DryRunCommandRunner { finished: VecDeque::new() }
1312 }
1313}
1314
1315impl CommandRunner for DryRunCommandRunner {
1316 fn can_run_more(&self) -> bool {
1317 true
1318 }
1319
1320 fn start_command(&mut self, _: &State, edge: EdgeIndex) -> bool {
1321 self.finished.push_back(edge);
1322 true
1323 }
1324
1325 fn wait_for_command(&mut self) -> Option<CommandRunnerResult> {
1326 match self.finished.pop_front() {
1327 None => None,
1328 Some(e) => Some(CommandRunnerResult {
1329 edge: e,
1330 status: ExitStatus::ExitSuccess,
1331 output: Vec::new(),
1332 }),
1333 }
1334 }
1335
1336 fn get_active_edges(&self) -> Vec<EdgeIndex> {
1337 Vec::new()
1338 }
1339
1340 fn abort(&mut self) {
1341 //do nothing
1342 }
1343}
1344/*
1345
1346BuildStatus::BuildStatus(const BuildConfig& config)
1347 : config_(config),
1348 start_time_millis_(GetTimeMillis()),
1349 started_edges_(0), finished_edges_(0), total_edges_(0),
1350 progress_status_format_(NULL),
1351 overall_rate_(), current_rate_(config.parallelism) {
1352
1353 // Don't do anything fancy in verbose mode.
1354 if (config_.verbosity != BuildConfig::NORMAL)
1355 printer_.set_smart_terminal(false);
1356
1357 progress_status_format_ = getenv("NINJA_STATUS");
1358 if (!progress_status_format_)
1359 progress_status_format_ = "[%f/%t] ";
1360}
1361
1362void BuildStatus::PlanHasTotalEdges(int total) {
1363 total_edges_ = total;
1364}
1365
1366void BuildStatus::BuildEdgeStarted(Edge* edge) {
1367 int start_time = (int)(GetTimeMillis() - start_time_millis_);
1368 running_edges_.insert(make_pair(edge, start_time));
1369 ++started_edges_;
1370
1371 if (edge->use_console() || printer_.is_smart_terminal())
1372 PrintStatus(edge, kEdgeStarted);
1373
1374 if (edge->use_console())
1375 printer_.SetConsoleLocked(true);
1376}
1377
1378void BuildStatus::BuildEdgeFinished(Edge* edge,
1379 bool success,
1380 const string& output,
1381 int* start_time,
1382 int* end_time) {
1383 int64_t now = GetTimeMillis();
1384
1385 ++finished_edges_;
1386
1387 RunningEdgeMap::iterator i = running_edges_.find(edge);
1388 *start_time = i->second;
1389 *end_time = (int)(now - start_time_millis_);
1390 running_edges_.erase(i);
1391
1392 if (edge->use_console())
1393 printer_.SetConsoleLocked(false);
1394
1395 if (config_.verbosity == BuildConfig::QUIET)
1396 return;
1397
1398 if (!edge->use_console())
1399 PrintStatus(edge, kEdgeFinished);
1400
1401 // Print the command that is spewing before printing its output.
1402 if (!success) {
1403 string outputs;
1404 for (vector<Node*>::const_iterator o = edge->outputs_.begin();
1405 o != edge->outputs_.end(); ++o)
1406 outputs += (*o)->path() + " ";
1407
1408 printer_.PrintOnNewLine("FAILED: " + outputs + "\n");
1409 printer_.PrintOnNewLine(edge->EvaluateCommand() + "\n");
1410 }
1411
1412 if (!output.empty()) {
1413 // ninja sets stdout and stderr of subprocesses to a pipe, to be able to
1414 // check if the output is empty. Some compilers, e.g. clang, check
1415 // isatty(stderr) to decide if they should print colored output.
1416 // To make it possible to use colored output with ninja, subprocesses should
1417 // be run with a flag that forces them to always print color escape codes.
1418 // To make sure these escape codes don't show up in a file if ninja's output
1419 // is piped to a file, ninja strips ansi escape codes again if it's not
1420 // writing to a |smart_terminal_|.
1421 // (Launching subprocesses in pseudo ttys doesn't work because there are
1422 // only a few hundred available on some systems, and ninja can launch
1423 // thousands of parallel compile commands.)
1424 // TODO: There should be a flag to disable escape code stripping.
1425 string final_output;
1426 if (!printer_.is_smart_terminal())
1427 final_output = StripAnsiEscapeCodes(output);
1428 else
1429 final_output = output;
1430
1431#ifdef _WIN32
1432 // Fix extra CR being added on Windows, writing out CR CR LF (#773)
1433 _setmode(_fileno(stdout), _O_BINARY); // Begin Windows extra CR fix
1434#endif
1435
1436 printer_.PrintOnNewLine(final_output);
1437
1438#ifdef _WIN32
1439 _setmode(_fileno(stdout), _O_TEXT); // End Windows extra CR fix
1440#endif
1441 }
1442}
1443
1444void BuildStatus::BuildStarted() {
1445 overall_rate_.Restart();
1446 current_rate_.Restart();
1447}
1448
1449void BuildStatus::BuildFinished() {
1450 printer_.SetConsoleLocked(false);
1451 printer_.PrintOnNewLine("");
1452}
1453
1454string BuildStatus::FormatProgressStatus(
1455 const char* progress_status_format, EdgeStatus status) const {
1456 string out;
1457 char buf[32];
1458 int percent;
1459 for (const char* s = progress_status_format; *s != '\0'; ++s) {
1460 if (*s == '%') {
1461 ++s;
1462 switch (*s) {
1463 case '%':
1464 out.push_back('%');
1465 break;
1466
1467 // Started edges.
1468 case 's':
1469 snprintf(buf, sizeof(buf), "%d", started_edges_);
1470 out += buf;
1471 break;
1472
1473 // Total edges.
1474 case 't':
1475 snprintf(buf, sizeof(buf), "%d", total_edges_);
1476 out += buf;
1477 break;
1478
1479 // Running edges.
1480 case 'r': {
1481 int running_edges = started_edges_ - finished_edges_;
1482 // count the edge that just finished as a running edge
1483 if (status == kEdgeFinished)
1484 running_edges++;
1485 snprintf(buf, sizeof(buf), "%d", running_edges);
1486 out += buf;
1487 break;
1488 }
1489
1490 // Unstarted edges.
1491 case 'u':
1492 snprintf(buf, sizeof(buf), "%d", total_edges_ - started_edges_);
1493 out += buf;
1494 break;
1495
1496 // Finished edges.
1497 case 'f':
1498 snprintf(buf, sizeof(buf), "%d", finished_edges_);
1499 out += buf;
1500 break;
1501
1502 // Overall finished edges per second.
1503 case 'o':
1504 overall_rate_.UpdateRate(finished_edges_);
1505 SnprintfRate(overall_rate_.rate(), buf, "%.1f");
1506 out += buf;
1507 break;
1508
1509 // Current rate, average over the last '-j' jobs.
1510 case 'c':
1511 current_rate_.UpdateRate(finished_edges_);
1512 SnprintfRate(current_rate_.rate(), buf, "%.1f");
1513 out += buf;
1514 break;
1515
1516 // Percentage
1517 case 'p':
1518 percent = (100 * finished_edges_) / total_edges_;
1519 snprintf(buf, sizeof(buf), "%3i%%", percent);
1520 out += buf;
1521 break;
1522
1523 case 'e': {
1524 double elapsed = overall_rate_.Elapsed();
1525 snprintf(buf, sizeof(buf), "%.3f", elapsed);
1526 out += buf;
1527 break;
1528 }
1529
1530 default:
1531 Fatal("unknown placeholder '%%%c' in $NINJA_STATUS", *s);
1532 return "";
1533 }
1534 } else {
1535 out.push_back(*s);
1536 }
1537 }
1538
1539 return out;
1540}
1541
1542void BuildStatus::PrintStatus(Edge* edge, EdgeStatus status) {
1543 if (config_.verbosity == BuildConfig::QUIET)
1544 return;
1545
1546 bool force_full_command = config_.verbosity == BuildConfig::VERBOSE;
1547
1548 string to_print = edge->GetBinding("description");
1549 if (to_print.empty() || force_full_command)
1550 to_print = edge->GetBinding("command");
1551
1552 to_print = FormatProgressStatus(progress_status_format_, status) + to_print;
1553
1554 printer_.Print(to_print,
1555 force_full_command ? LinePrinter::FULL : LinePrinter::ELIDE);
1556}
1557
1558Plan::Plan() : command_edges_(0), wanted_edges_(0) {}
1559
1560bool Plan::CleanNode(DependencyScan* scan, Node* node, string* err) {
1561 node->set_dirty(false);
1562
1563 for (vector<Edge*>::const_iterator oe = node->out_edges().begin();
1564 oe != node->out_edges().end(); ++oe) {
1565 // Don't process edges that we don't actually want.
1566 map<Edge*, bool>::iterator want_e = want_.find(*oe);
1567 if (want_e == want_.end() || !want_e->second)
1568 continue;
1569
1570 // Don't attempt to clean an edge if it failed to load deps.
1571 if ((*oe)->deps_missing_)
1572 continue;
1573
1574 // If all non-order-only inputs for this edge are now clean,
1575 // we might have changed the dirty state of the outputs.
1576 vector<Node*>::iterator
1577 begin = (*oe)->inputs_.begin(),
1578 end = (*oe)->inputs_.end() - (*oe)->order_only_deps_;
1579 if (find_if(begin, end, mem_fun(&Node::dirty)) == end) {
1580 // Recompute most_recent_input.
1581 Node* most_recent_input = NULL;
1582 for (vector<Node*>::iterator i = begin; i != end; ++i) {
1583 if (!most_recent_input || (*i)->mtime() > most_recent_input->mtime())
1584 most_recent_input = *i;
1585 }
1586
1587 // Now, this edge is dirty if any of the outputs are dirty.
1588 // If the edge isn't dirty, clean the outputs and mark the edge as not
1589 // wanted.
1590 bool outputs_dirty = false;
1591 if (!scan->RecomputeOutputsDirty(*oe, most_recent_input,
1592 &outputs_dirty, err)) {
1593 return false;
1594 }
1595 if (!outputs_dirty) {
1596 for (vector<Node*>::iterator o = (*oe)->outputs_.begin();
1597 o != (*oe)->outputs_.end(); ++o) {
1598 if (!CleanNode(scan, *o, err))
1599 return false;
1600 }
1601
1602 want_e->second = false;
1603 --wanted_edges_;
1604 if (!(*oe)->is_phony())
1605 --command_edges_;
1606 }
1607 }
1608 }
1609 return true;
1610}
1611
1612void Plan::Dump() {
1613 printf("pending: %d\n", (int)want_.size());
1614 for (map<Edge*, bool>::iterator e = want_.begin(); e != want_.end(); ++e) {
1615 if (e->second)
1616 printf("want ");
1617 e->first->Dump();
1618 }
1619 printf("ready: %d\n", (int)ready_.size());
1620}
1621*/
1622
1623struct RealCommandRunner<'a> {
1624 config: &'a BuildConfig,
1625 subprocs: SubprocessSet<EdgeIndex>,
1626}
1627
1628impl<'a> RealCommandRunner<'a> {
1629 pub fn new(config: &'a BuildConfig) -> Self {
1630 RealCommandRunner {
1631 config,
1632 subprocs: SubprocessSet::new(),
1633 }
1634 }
1635}
1636
1637impl<'a> CommandRunner for RealCommandRunner<'a> {
1638 fn can_run_more(&self) -> bool {
1639 let subproc_number = self.subprocs.running().len() + self.subprocs.finished().len();
1640 if subproc_number >= self.config.parallelism {
1641 return false;
1642 }
1643 if self.subprocs.running().is_empty() {
1644 return true;
1645 }
1646 if self.config.max_load_average <= 0.0f64 {
1647 return true;
1648 }
1649 if get_load_average().unwrap_or(-0.0f64) < self.config.max_load_average {
1650 return true;
1651 }
1652 return false;
1653 }
1654
1655 fn start_command(&mut self, state: &State, edge_idx: EdgeIndex) -> bool {
1656 let edge = state.edge_state.get_edge(edge_idx);
1657 let command = edge.evaluate_command(&state.node_state);
1658
1659 return self.subprocs
1660 .add(&command, edge.use_console(), edge_idx)
1661 .is_some();
1662 }
1663
1664 fn wait_for_command(&mut self) -> Option<CommandRunnerResult> {
1665 let (mut subproc, edge_idx) = loop {
1666 if let Some(next_finished) = self.subprocs.next_finished() {
1667 break next_finished;
1668 }
1669 if self.subprocs.do_work().is_err() {
1670 //interrupted
1671 return None;
1672 }
1673 };
1674
1675 let status = subproc.finish();
1676 let output = subproc.output().to_owned();
1677 Some(CommandRunnerResult {
1678 status,
1679 output,
1680 edge: edge_idx,
1681 })
1682 }
1683
1684 fn get_active_edges(&self) -> Vec<EdgeIndex> {
1685 self.subprocs.iter().map(|x| x.1).collect()
1686 }
1687
1688 fn abort(&mut self) {
1689 self.subprocs.clear();
1690 }
1691}
1692
1693/*
1694struct RealCommandRunner : public CommandRunner {
1695 explicit RealCommandRunner(const BuildConfig& config) : config_(config) {}
1696 virtual ~RealCommandRunner() {}
1697 virtual bool CanRunMore();
1698 virtual bool StartCommand(Edge* edge);
1699 virtual bool WaitForCommand(Result* result);
1700 virtual vector<Edge*> GetActiveEdges();
1701 virtual void Abort();
1702
1703 const BuildConfig& config_;
1704 SubprocessSet subprocs_;
1705 map<Subprocess*, Edge*> subproc_to_edge_;
1706};
1707
1708bool RealCommandRunner::CanRunMore() {
1709 size_t subproc_number =
1710 subprocs_.running_.size() + subprocs_.finished_.size();
1711 return (int)subproc_number < config_.parallelism
1712 && ((subprocs_.running_.empty() || config_.max_load_average <= 0.0f)
1713 || GetLoadAverage() < config_.max_load_average);
1714}
1715
1716bool RealCommandRunner::StartCommand(Edge* edge) {
1717 string command = edge->EvaluateCommand();
1718 Subprocess* subproc = subprocs_.Add(command, edge->use_console());
1719 if (!subproc)
1720 return false;
1721 subproc_to_edge_.insert(make_pair(subproc, edge));
1722
1723 return true;
1724}
1725
1726bool RealCommandRunner::WaitForCommand(Result* result) {
1727 Subprocess* subproc;
1728 while ((subproc = subprocs_.NextFinished()) == NULL) {
1729 bool interrupted = subprocs_.DoWork();
1730 if (interrupted)
1731 return false;
1732 }
1733
1734 result->status = subproc->Finish();
1735 result->output = subproc->GetOutput();
1736
1737 map<Subprocess*, Edge*>::iterator e = subproc_to_edge_.find(subproc);
1738 result->edge = e->second;
1739 subproc_to_edge_.erase(e);
1740
1741 delete subproc;
1742 return true;
1743}
1744
1745Builder::Builder(State* state, const BuildConfig& config,
1746 BuildLog* build_log, DepsLog* deps_log,
1747 DiskInterface* disk_interface)
1748 : state_(state), config_(config), disk_interface_(disk_interface),
1749 scan_(state, build_log, deps_log, disk_interface) {
1750 status_ = new BuildStatus(config);
1751}
1752
1753Node* Builder::AddTarget(const string& name, string* err) {
1754 Node* node = state_->LookupNode(name);
1755 if (!node) {
1756 *err = "unknown target: '" + name + "'";
1757 return NULL;
1758 }
1759 if (!AddTarget(node, err))
1760 return NULL;
1761 return node;
1762}
1763
1764bool Builder::AddTarget(Node* node, string* err) {
1765 if (!scan_.RecomputeDirty(node, err))
1766 return false;
1767
1768 if (Edge* in_edge = node->in_edge()) {
1769 if (in_edge->outputs_ready())
1770 return true; // Nothing to do.
1771 }
1772
1773 if (!plan_.AddTarget(node, err))
1774 return false;
1775
1776 return true;
1777}
1778
1779
1780
1781bool Builder::ExtractDeps(CommandRunner::Result* result,
1782 const string& deps_type,
1783 const string& deps_prefix,
1784 vector<Node*>* deps_nodes,
1785 string* err) {
1786 if (deps_type == "msvc") {
1787 CLParser parser;
1788 string output;
1789 if (!parser.Parse(result->output, deps_prefix, &output, err))
1790 return false;
1791 result->output = output;
1792 for (set<string>::iterator i = parser.includes_.begin();
1793 i != parser.includes_.end(); ++i) {
1794 // ~0 is assuming that with MSVC-parsed headers, it's ok to always make
1795 // all backslashes (as some of the slashes will certainly be backslashes
1796 // anyway). This could be fixed if necessary with some additional
1797 // complexity in IncludesNormalize::Relativize.
1798 deps_nodes->push_back(state_->GetNode(*i, ~0u));
1799 }
1800 } else
1801 if (deps_type == "gcc") {
1802 string depfile = result->edge->GetUnescapedDepfile();
1803 if (depfile.empty()) {
1804 *err = string("edge with deps=gcc but no depfile makes no sense");
1805 return false;
1806 }
1807
1808 // Read depfile content. Treat a missing depfile as empty.
1809 string content;
1810 switch (disk_interface_->ReadFile(depfile, &content, err)) {
1811 case DiskInterface::Okay:
1812 break;
1813 case DiskInterface::NotFound:
1814 err->clear();
1815 break;
1816 case DiskInterface::OtherError:
1817 return false;
1818 }
1819 if (content.empty())
1820 return true;
1821
1822 DepfileParser deps;
1823 if (!deps.Parse(&content, err))
1824 return false;
1825
1826 // XXX check depfile matches expected output.
1827 deps_nodes->reserve(deps.ins_.size());
1828 for (vector<StringPiece>::iterator i = deps.ins_.begin();
1829 i != deps.ins_.end(); ++i) {
1830 uint64_t slash_bits;
1831 if (!CanonicalizePath(const_cast<char*>(i->str_), &i->len_, &slash_bits,
1832 err))
1833 return false;
1834 deps_nodes->push_back(state_->GetNode(*i, slash_bits));
1835 }
1836
1837 if (!g_keep_depfile) {
1838 if (disk_interface_->RemoveFile(depfile) < 0) {
1839 *err = string("deleting depfile: ") + strerror(errno) + string("\n");
1840 return false;
1841 }
1842 }
1843 } else {
1844 Fatal("unknown deps type '%s'", deps_type.c_str());
1845 }
1846
1847 return true;
1848}
1849
1850
1851*/
1852
1853#[cfg(test)]
1854mod tests {
1855 use super::*;
1856 use super::super::test::TestWithStateAndVFS;
1857 use super::super::graph::Node;
1858
1859 /// Fixture for tests involving Plan.
1860 // Though Plan doesn't use State, it's useful to have one around
1861 // to create Nodes and Edges.
1862 struct PlanTestData {
1863 plan: Plan,
1864 }
1865
1866 impl Default for PlanTestData {
1867 fn default() -> Self {
1868 PlanTestData { plan: Plan::new() }
1869 }
1870 }
1871
1872 type PlanTest = TestWithStateAndVFS<PlanTestData>;
1873
1874 impl PlanTest {
1875 pub fn new() -> Self {
1876 Self::new_with_builtin_rule()
1877 }
1878 }
1879
1880 /*
1881
1882/// Fixture for tests involving Plan.
1883// Though Plan doesn't use State, it's useful to have one around
1884// to create Nodes and Edges.
1885struct PlanTest : public StateTestWithBuiltinRules {
1886 Plan plan_;
1887
1888 /// Because FindWork does not return Edges in any sort of predictable order,
1889 // provide a means to get available Edges in order and in a format which is
1890 // easy to write tests around.
1891 void FindWorkSorted(deque<Edge*>* ret, int count) {
1892 struct CompareEdgesByOutput {
1893 static bool cmp(const Edge* a, const Edge* b) {
1894 return a->outputs_[0]->path() < b->outputs_[0]->path();
1895 }
1896 };
1897
1898 for (int i = 0; i < count; ++i) {
1899 ASSERT_TRUE(plan_.more_to_do());
1900 Edge* edge = plan_.FindWork();
1901 ASSERT_TRUE(edge);
1902 ret->push_back(edge);
1903 }
1904 ASSERT_FALSE(plan_.FindWork());
1905 sort(ret->begin(), ret->end(), CompareEdgesByOutput::cmp);
1906 }
1907
1908 void TestPoolWithDepthOne(const char *test_case);
1909};
1910*/
1911 #[test]
1912 fn plantest_basic() {
1913 let mut plantest = PlanTest::new();
1914 plantest.assert_parse(
1915 concat!("build out: cat mid\n", "build mid: cat in\n").as_bytes(),
1916 );
1917 plantest.assert_with_node_mut(b"mid", Node::mark_dirty);
1918 plantest.assert_with_node_mut(b"out", Node::mark_dirty);
1919 let out_node_idx = plantest.assert_node_idx(b"out");
1920
1921 let mut state = plantest.state.borrow_mut();
1922 let state = &mut *state;
1923 let plan = &mut plantest.other.plan;
1924 assert_eq!(Ok(true), plan.add_target(state, out_node_idx));
1925 assert_eq!(true, plan.more_to_do());
1926
1927 let edge_idx = plan.find_work().unwrap();
1928 {
1929 let edge = state.edge_state.get_edge(edge_idx);
1930 let input0 = edge.inputs[0];
1931 assert_eq!(b"in", state.node_state.get_node(input0).path());
1932 let output0 = edge.outputs[0];
1933 assert_eq!(b"mid", state.node_state.get_node(output0).path());
1934 }
1935 assert_eq!(None, plan.find_work());
1936 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
1937 let edge_idx = plan.find_work().unwrap();
1938 {
1939 let edge = state.edge_state.get_edge(edge_idx);
1940 let input0 = edge.inputs[0];
1941 assert_eq!(b"mid", state.node_state.get_node(input0).path());
1942 let output0 = edge.outputs[0];
1943 assert_eq!(b"out", state.node_state.get_node(output0).path());
1944 }
1945 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
1946
1947 assert_eq!(false, plan.more_to_do());
1948 assert_eq!(None, plan.find_work());
1949 }
1950
1951 // Test that two outputs from one rule can be handled as inputs to the next.
1952 #[test]
1953 fn plantest_double_output_direct() {
1954 let mut plantest = PlanTest::new();
1955 plantest.assert_parse(
1956 concat!("build out: cat mid1 mid2\n", "build mid1 mid2: cat in\n").as_bytes(),
1957 );
1958 plantest.assert_with_node_mut(b"mid1", Node::mark_dirty);
1959 plantest.assert_with_node_mut(b"mid2", Node::mark_dirty);
1960 plantest.assert_with_node_mut(b"out", Node::mark_dirty);
1961
1962 let out_node_idx = plantest.assert_node_idx(b"out");
1963 let mut state = plantest.state.borrow_mut();
1964 let state = &mut *state;
1965 let plan = &mut plantest.other.plan;
1966 assert_eq!(Ok(true), plan.add_target(state, out_node_idx));
1967 assert_eq!(true, plan.more_to_do());
1968
1969 let edge_idx = plan.find_work().unwrap(); // cat in
1970 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
1971
1972 let edge_idx = plan.find_work().unwrap(); // cat mid1 mid2
1973 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
1974
1975 assert_eq!(None, plan.find_work()); // done
1976 }
1977
1978 // Test that two outputs from one rule can eventually be routed to another.
1979 #[test]
1980 fn plantest_double_output_indirect() {
1981 let mut plantest = PlanTest::new();
1982 plantest.assert_parse(
1983 concat!(
1984 "build out: cat b1 b2\n",
1985 "build b1: cat a1\n",
1986 "build b2: cat a2\n",
1987 "build a1 a2: cat in\n"
1988 ).as_bytes(),
1989 );
1990 plantest.assert_with_node_mut(b"a1", Node::mark_dirty);
1991 plantest.assert_with_node_mut(b"a2", Node::mark_dirty);
1992 plantest.assert_with_node_mut(b"b1", Node::mark_dirty);
1993 plantest.assert_with_node_mut(b"b2", Node::mark_dirty);
1994 plantest.assert_with_node_mut(b"out", Node::mark_dirty);
1995
1996 let out_node_idx = plantest.assert_node_idx(b"out");
1997 let mut state = plantest.state.borrow_mut();
1998 let state = &mut *state;
1999 let plan = &mut plantest.other.plan;
2000 assert_eq!(Ok(true), plan.add_target(state, out_node_idx));
2001 assert_eq!(true, plan.more_to_do());
2002
2003 let edge_idx = plan.find_work().unwrap(); // cat in
2004 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
2005
2006 let edge_idx = plan.find_work().unwrap(); // cat a1
2007 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
2008
2009 let edge_idx = plan.find_work().unwrap(); // cat a2
2010 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
2011
2012 let edge_idx = plan.find_work().unwrap(); // cat b1 b2
2013 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
2014
2015 assert_eq!(None, plan.find_work()); // done
2016 }
2017
2018 // Test that two edges from one output can both execute.
2019 #[test]
2020 fn plantest_double_dependent() {
2021 let mut plantest = PlanTest::new();
2022 plantest.assert_parse(
2023 concat!(
2024 "build out: cat a1 a2\n",
2025 "build a1: cat mid\n",
2026 "build a2: cat mid\n",
2027 "build mid: cat in\n"
2028 ).as_bytes(),
2029 );
2030 plantest.assert_with_node_mut(b"mid", Node::mark_dirty);
2031 plantest.assert_with_node_mut(b"a1", Node::mark_dirty);
2032 plantest.assert_with_node_mut(b"a2", Node::mark_dirty);
2033 plantest.assert_with_node_mut(b"out", Node::mark_dirty);
2034
2035 let out_node_idx = plantest.assert_node_idx(b"out");
2036 let mut state = plantest.state.borrow_mut();
2037 let state = &mut *state;
2038 let plan = &mut plantest.other.plan;
2039 assert_eq!(Ok(true), plan.add_target(state, out_node_idx));
2040 assert_eq!(true, plan.more_to_do());
2041
2042 let edge_idx = plan.find_work().unwrap(); // cat in
2043 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
2044
2045 let edge_idx = plan.find_work().unwrap(); // cat mid
2046 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
2047
2048 let edge_idx = plan.find_work().unwrap(); // cat mid
2049 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
2050
2051 let edge_idx = plan.find_work().unwrap(); // cat a1 a2
2052 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
2053
2054 assert_eq!(None, plan.find_work()); // done
2055 }
2056
2057 fn test_pool_with_depth_one_helper(plantest: &mut PlanTest, test_case: &[u8]) {
2058 plantest.assert_parse(test_case);
2059 plantest.assert_with_node_mut(b"out1", Node::mark_dirty);
2060 plantest.assert_with_node_mut(b"out2", Node::mark_dirty);
2061
2062 let out1_node_idx = plantest.assert_node_idx(b"out1");
2063 let out2_node_idx = plantest.assert_node_idx(b"out2");
2064
2065 let mut state = plantest.state.borrow_mut();
2066 let state = &mut *state;
2067 let plan = &mut plantest.other.plan;
2068 assert_eq!(Ok(true), plan.add_target(state, out1_node_idx));
2069 assert_eq!(Ok(true), plan.add_target(state, out2_node_idx));
2070
2071 assert_eq!(true, plan.more_to_do());
2072
2073 let edge_idx = plan.find_work().unwrap();
2074 {
2075 let edge = state.edge_state.get_edge(edge_idx);
2076 let edge_in0_idx = edge.inputs.get(0).cloned().unwrap();
2077 let edge_in0_node = state.node_state.get_node(edge_in0_idx);
2078 assert_eq!(b"in".as_ref(), edge_in0_node.path());
2079 let edge_out0_idx = edge.outputs.get(0).cloned().unwrap();
2080 let edge_out0_node = state.node_state.get_node(edge_out0_idx);
2081 assert_eq!(b"out1".as_ref(), edge_out0_node.path());
2082 }
2083
2084 // This will be false since poolcat is serialized
2085 assert!(plan.find_work().is_none());
2086 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
2087
2088 let edge_idx = plan.find_work().unwrap();
2089 {
2090 let edge = state.edge_state.get_edge(edge_idx);
2091 let edge_in0_idx = edge.inputs.get(0).cloned().unwrap();
2092 let edge_in0_node = state.node_state.get_node(edge_in0_idx);
2093 assert_eq!(b"in".as_ref(), edge_in0_node.path());
2094 let edge_out0_idx = edge.outputs.get(0).cloned().unwrap();
2095 let edge_out0_node = state.node_state.get_node(edge_out0_idx);
2096 assert_eq!(b"out2".as_ref(), edge_out0_node.path());
2097 }
2098
2099 // This will be false since poolcat is serialized
2100 assert!(plan.find_work().is_none());
2101 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
2102
2103 assert_eq!(false, plan.more_to_do());
2104 assert_eq!(None, plan.find_work()); // done
2105 }
2106
2107 #[test]
2108 fn plantest_pool_with_depth_one() {
2109 let mut plantest = PlanTest::new();
2110 test_pool_with_depth_one_helper(
2111 &mut plantest,
2112 concat!(
2113 "pool foobar\n",
2114 " depth = 1\n",
2115 "rule poolcat\n",
2116 " command = cat $in > $out\n",
2117 " pool = foobar\n",
2118 "build out1: poolcat in\n",
2119 "build out2: poolcat in\n"
2120 ).as_bytes(),
2121 );
2122 }
2123
2124 #[test]
2125 fn plantest_console_pool() {
2126 let mut plantest = PlanTest::new();
2127 test_pool_with_depth_one_helper(
2128 &mut plantest,
2129 concat!(
2130 "rule poolcat\n",
2131 " command = cat $in > $out\n",
2132 " pool = console\n",
2133 "build out1: poolcat in\n",
2134 "build out2: poolcat in\n",
2135 ).as_bytes(),
2136 );
2137 }
2138
2139 /// Because FindWork does not return Edges in any sort of predictable order,
2140 // provide a means to get available Edges in order and in a format which is
2141 // easy to write tests around.
2142 fn find_work_sorted_helper(
2143 plan: &mut Plan,
2144 state: &State,
2145 count: usize,
2146 ) -> VecDeque<EdgeIndex> {
2147 let mut result = (0..count)
2148 .map(|i| {
2149 assert!(plan.more_to_do());
2150 plan.find_work().unwrap()
2151 })
2152 .collect::<Vec<_>>();
2153
2154 assert!(plan.find_work().is_none());
2155 result.sort_by_key(|e| {
2156 state
2157 .node_state
2158 .get_node(state.edge_state.get_edge(*e).outputs[0])
2159 .path()
2160 });
2161 result.into_iter().collect()
2162 }
2163
2164 #[test]
2165 fn plantest_pools_with_depth_two() {
2166 let mut plantest = PlanTest::new();
2167 plantest.assert_parse(
2168 concat!(
2169 "pool foobar\n",
2170 " depth = 2\n",
2171 "pool bazbin\n",
2172 " depth = 2\n",
2173 "rule foocat\n",
2174 " command = cat $in > $out\n",
2175 " pool = foobar\n",
2176 "rule bazcat\n",
2177 " command = cat $in > $out\n",
2178 " pool = bazbin\n",
2179 "build out1: foocat in\n",
2180 "build out2: foocat in\n",
2181 "build out3: foocat in\n",
2182 "build outb1: bazcat in\n",
2183 "build outb2: bazcat in\n",
2184 "build outb3: bazcat in\n",
2185 " pool =\n",
2186 "build allTheThings: cat out1 out2 out3 outb1 outb2 outb3\n"
2187 ).as_bytes(),
2188 );
2189 [
2190 b"out1".as_ref(),
2191 b"out2".as_ref(),
2192 b"out3".as_ref(),
2193 b"outb1".as_ref(),
2194 b"outb2".as_ref(),
2195 b"outb3".as_ref(),
2196 b"allTheThings".as_ref(),
2197 ].as_ref()
2198 .iter()
2199 .for_each(|path| {
2200 plantest.assert_with_node_mut(path, Node::mark_dirty);
2201 });
2202
2203 let mut state = plantest.state.borrow_mut();
2204 let state = &mut *state;
2205 let plan = &mut plantest.other.plan;
2206 let all_the_things_node = state.node_state.lookup_node(b"allTheThings").unwrap();
2207 assert_eq!(Ok(true), plan.add_target(state, all_the_things_node));
2208
2209 let mut edges = find_work_sorted_helper(plan, state, 5);
2210 {
2211 let edge_idx = edges[0];
2212 let edge = state.edge_state.get_edge(edge_idx);
2213 assert_eq!(
2214 b"in".as_ref(),
2215 state.node_state.get_node(edge.inputs[0]).path()
2216 );
2217 assert_eq!(
2218 b"out1".as_ref(),
2219 state.node_state.get_node(edge.outputs[0]).path()
2220 )
2221 }
2222 {
2223 let edge_idx = edges[1];
2224 let edge = state.edge_state.get_edge(edge_idx);
2225 assert_eq!(
2226 b"in".as_ref(),
2227 state.node_state.get_node(edge.inputs[0]).path()
2228 );
2229 assert_eq!(
2230 b"out2".as_ref(),
2231 state.node_state.get_node(edge.outputs[0]).path()
2232 )
2233 }
2234 {
2235 let edge_idx = edges[2];
2236 let edge = state.edge_state.get_edge(edge_idx);
2237 assert_eq!(
2238 b"in".as_ref(),
2239 state.node_state.get_node(edge.inputs[0]).path()
2240 );
2241 assert_eq!(
2242 b"outb1".as_ref(),
2243 state.node_state.get_node(edge.outputs[0]).path()
2244 )
2245 }
2246 {
2247 let edge_idx = edges[3];
2248 let edge = state.edge_state.get_edge(edge_idx);
2249 assert_eq!(
2250 b"in".as_ref(),
2251 state.node_state.get_node(edge.inputs[0]).path()
2252 );
2253 assert_eq!(
2254 b"outb2".as_ref(),
2255 state.node_state.get_node(edge.outputs[0]).path()
2256 )
2257 }
2258 {
2259 let edge_idx = edges[4];
2260 let edge = state.edge_state.get_edge(edge_idx);
2261 assert_eq!(
2262 b"in".as_ref(),
2263 state.node_state.get_node(edge.inputs[0]).path()
2264 );
2265 assert_eq!(
2266 b"outb3".as_ref(),
2267 state.node_state.get_node(edge.outputs[0]).path()
2268 )
2269 }
2270 // finish out1
2271 plan.edge_finished(state, edges.pop_front().unwrap(), EdgeResult::EdgeSucceeded);
2272
2273 let out3_idx = plan.find_work().unwrap();
2274 {
2275 let edge = state.edge_state.get_edge(out3_idx);
2276 assert_eq!(
2277 b"in".as_ref(),
2278 state.node_state.get_node(edge.inputs[0]).path()
2279 );
2280 assert_eq!(
2281 b"out3".as_ref(),
2282 state.node_state.get_node(edge.outputs[0]).path()
2283 )
2284 }
2285 assert!(plan.find_work().is_none());
2286 plan.edge_finished(state, out3_idx, EdgeResult::EdgeSucceeded);
2287 assert!(plan.find_work().is_none());
2288
2289 edges.into_iter().for_each(|edge_idx| {
2290 plan.edge_finished(state, edge_idx, EdgeResult::EdgeSucceeded);
2291 });
2292
2293 let last_idx = plan.find_work().unwrap();
2294 {
2295 let edge = state.edge_state.get_edge(last_idx);
2296 assert_eq!(
2297 b"allTheThings".as_ref(),
2298 state.node_state.get_node(edge.outputs[0]).path()
2299 )
2300 }
2301 plan.edge_finished(state, last_idx, EdgeResult::EdgeSucceeded);
2302
2303 assert_eq!(false, plan.more_to_do());
2304 assert_eq!(None, plan.find_work()); // done
2305 }
2306 /*
2307TEST_F(PlanTest, PoolWithRedundantEdges) {
2308 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2309 "pool compile\n"
2310 " depth = 1\n"
2311 "rule gen_foo\n"
2312 " command = touch foo.cpp\n"
2313 "rule gen_bar\n"
2314 " command = touch bar.cpp\n"
2315 "rule echo\n"
2316 " command = echo $out > $out\n"
2317 "build foo.cpp.obj: echo foo.cpp || foo.cpp\n"
2318 " pool = compile\n"
2319 "build bar.cpp.obj: echo bar.cpp || bar.cpp\n"
2320 " pool = compile\n"
2321 "build libfoo.a: echo foo.cpp.obj bar.cpp.obj\n"
2322 "build foo.cpp: gen_foo\n"
2323 "build bar.cpp: gen_bar\n"
2324 "build all: phony libfoo.a\n"));
2325 GetNode("foo.cpp")->MarkDirty();
2326 GetNode("foo.cpp.obj")->MarkDirty();
2327 GetNode("bar.cpp")->MarkDirty();
2328 GetNode("bar.cpp.obj")->MarkDirty();
2329 GetNode("libfoo.a")->MarkDirty();
2330 GetNode("all")->MarkDirty();
2331 string err;
2332 EXPECT_TRUE(plan_.AddTarget(GetNode("all"), &err));
2333 ASSERT_EQ("", err);
2334 ASSERT_TRUE(plan_.more_to_do());
2335
2336 Edge* edge = NULL;
2337
2338 deque<Edge*> initial_edges;
2339 FindWorkSorted(&initial_edges, 2);
2340
2341 edge = initial_edges[1]; // Foo first
2342 ASSERT_EQ("foo.cpp", edge->outputs_[0]->path());
2343 plan_.EdgeFinished(edge, Plan::kEdgeSucceeded);
2344
2345 edge = plan_.FindWork();
2346 ASSERT_TRUE(edge);
2347 ASSERT_FALSE(plan_.FindWork());
2348 ASSERT_EQ("foo.cpp", edge->inputs_[0]->path());
2349 ASSERT_EQ("foo.cpp", edge->inputs_[1]->path());
2350 ASSERT_EQ("foo.cpp.obj", edge->outputs_[0]->path());
2351 plan_.EdgeFinished(edge, Plan::kEdgeSucceeded);
2352
2353 edge = initial_edges[0]; // Now for bar
2354 ASSERT_EQ("bar.cpp", edge->outputs_[0]->path());
2355 plan_.EdgeFinished(edge, Plan::kEdgeSucceeded);
2356
2357 edge = plan_.FindWork();
2358 ASSERT_TRUE(edge);
2359 ASSERT_FALSE(plan_.FindWork());
2360 ASSERT_EQ("bar.cpp", edge->inputs_[0]->path());
2361 ASSERT_EQ("bar.cpp", edge->inputs_[1]->path());
2362 ASSERT_EQ("bar.cpp.obj", edge->outputs_[0]->path());
2363 plan_.EdgeFinished(edge, Plan::kEdgeSucceeded);
2364
2365 edge = plan_.FindWork();
2366 ASSERT_TRUE(edge);
2367 ASSERT_FALSE(plan_.FindWork());
2368 ASSERT_EQ("foo.cpp.obj", edge->inputs_[0]->path());
2369 ASSERT_EQ("bar.cpp.obj", edge->inputs_[1]->path());
2370 ASSERT_EQ("libfoo.a", edge->outputs_[0]->path());
2371 plan_.EdgeFinished(edge, Plan::kEdgeSucceeded);
2372
2373 edge = plan_.FindWork();
2374 ASSERT_TRUE(edge);
2375 ASSERT_FALSE(plan_.FindWork());
2376 ASSERT_EQ("libfoo.a", edge->inputs_[0]->path());
2377 ASSERT_EQ("all", edge->outputs_[0]->path());
2378 plan_.EdgeFinished(edge, Plan::kEdgeSucceeded);
2379
2380 edge = plan_.FindWork();
2381 ASSERT_FALSE(edge);
2382 ASSERT_FALSE(plan_.more_to_do());
2383}
2384
2385TEST_F(PlanTest, PoolWithFailingEdge) {
2386 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2387 "pool foobar\n"
2388 " depth = 1\n"
2389 "rule poolcat\n"
2390 " command = cat $in > $out\n"
2391 " pool = foobar\n"
2392 "build out1: poolcat in\n"
2393 "build out2: poolcat in\n"));
2394 GetNode("out1")->MarkDirty();
2395 GetNode("out2")->MarkDirty();
2396 string err;
2397 EXPECT_TRUE(plan_.AddTarget(GetNode("out1"), &err));
2398 ASSERT_EQ("", err);
2399 EXPECT_TRUE(plan_.AddTarget(GetNode("out2"), &err));
2400 ASSERT_EQ("", err);
2401 ASSERT_TRUE(plan_.more_to_do());
2402
2403 Edge* edge = plan_.FindWork();
2404 ASSERT_TRUE(edge);
2405 ASSERT_EQ("in", edge->inputs_[0]->path());
2406 ASSERT_EQ("out1", edge->outputs_[0]->path());
2407
2408 // This will be false since poolcat is serialized
2409 ASSERT_FALSE(plan_.FindWork());
2410
2411 plan_.EdgeFinished(edge, Plan::kEdgeFailed);
2412
2413 edge = plan_.FindWork();
2414 ASSERT_TRUE(edge);
2415 ASSERT_EQ("in", edge->inputs_[0]->path());
2416 ASSERT_EQ("out2", edge->outputs_[0]->path());
2417
2418 ASSERT_FALSE(plan_.FindWork());
2419
2420 plan_.EdgeFinished(edge, Plan::kEdgeFailed);
2421
2422 ASSERT_TRUE(plan_.more_to_do()); // Jobs have failed
2423 edge = plan_.FindWork();
2424 ASSERT_EQ(0, edge);
2425}
2426
2427/// Fake implementation of CommandRunner, useful for tests.
2428struct FakeCommandRunner : public CommandRunner {
2429 explicit FakeCommandRunner(VirtualFileSystem* fs) :
2430 last_command_(NULL), fs_(fs) {}
2431
2432 // CommandRunner impl
2433 virtual bool CanRunMore();
2434 virtual bool StartCommand(Edge* edge);
2435 virtual bool WaitForCommand(Result* result);
2436 virtual vector<Edge*> GetActiveEdges();
2437 virtual void Abort();
2438
2439 vector<string> commands_ran_;
2440 Edge* last_command_;
2441 VirtualFileSystem* fs_;
2442};
2443*/
2444
2445 /*
2446struct BuildTest : public StateTestWithBuiltinRules, public BuildLogUser {
2447 BuildTest() : config_(MakeConfig()), command_runner_(&fs_),
2448 builder_(&state_, config_, NULL, NULL, &fs_),
2449 status_(config_) {
2450 }
2451
2452 virtual void SetUp() {
2453 StateTestWithBuiltinRules::SetUp();
2454
2455 builder_.command_runner_.reset(&command_runner_);
2456 AssertParse(&state_,
2457"build cat1: cat in1\n"
2458"build cat2: cat in1 in2\n"
2459"build cat12: cat cat1 cat2\n");
2460
2461 fs_.Create("in1", "");
2462 fs_.Create("in2", "");
2463 }
2464
2465 ~BuildTest() {
2466 builder_.command_runner_.release();
2467 }
2468
2469 virtual bool IsPathDead(StringPiece s) const { return false; }
2470
2471 /// Rebuild target in the 'working tree' (fs_).
2472 /// State of command_runner_ and logs contents (if specified) ARE MODIFIED.
2473 /// Handy to check for NOOP builds, and higher-level rebuild tests.
2474 void RebuildTarget(const string& target, const char* manifest,
2475 const char* log_path = NULL, const char* deps_path = NULL,
2476 State* state = NULL);
2477
2478 // Mark a path dirty.
2479 void Dirty(const string& path);
2480
2481 BuildConfig MakeConfig() {
2482 BuildConfig config;
2483 config.verbosity = BuildConfig::QUIET;
2484 return config;
2485 }
2486
2487 BuildConfig config_;
2488 FakeCommandRunner command_runner_;
2489 VirtualFileSystem fs_;
2490 Builder builder_;
2491
2492 BuildStatus status_;
2493};
2494
2495void BuildTest::RebuildTarget(const string& target, const char* manifest,
2496 const char* log_path, const char* deps_path,
2497 State* state) {
2498 State local_state, *pstate = &local_state;
2499 if (state)
2500 pstate = state;
2501 ASSERT_NO_FATAL_FAILURE(AddCatRule(pstate));
2502 AssertParse(pstate, manifest);
2503
2504 string err;
2505 BuildLog build_log, *pbuild_log = NULL;
2506 if (log_path) {
2507 ASSERT_TRUE(build_log.Load(log_path, &err));
2508 ASSERT_TRUE(build_log.OpenForWrite(log_path, *this, &err));
2509 ASSERT_EQ("", err);
2510 pbuild_log = &build_log;
2511 }
2512
2513 DepsLog deps_log, *pdeps_log = NULL;
2514 if (deps_path) {
2515 ASSERT_TRUE(deps_log.Load(deps_path, pstate, &err));
2516 ASSERT_TRUE(deps_log.OpenForWrite(deps_path, &err));
2517 ASSERT_EQ("", err);
2518 pdeps_log = &deps_log;
2519 }
2520
2521 Builder builder(pstate, config_, pbuild_log, pdeps_log, &fs_);
2522 EXPECT_TRUE(builder.AddTarget(target, &err));
2523
2524 command_runner_.commands_ran_.clear();
2525 builder.command_runner_.reset(&command_runner_);
2526 if (!builder.AlreadyUpToDate()) {
2527 bool build_res = builder.Build(&err);
2528 EXPECT_TRUE(build_res);
2529 }
2530 builder.command_runner_.release();
2531}
2532
2533bool FakeCommandRunner::CanRunMore() {
2534 // Only run one at a time.
2535 return last_command_ == NULL;
2536}
2537
2538bool FakeCommandRunner::StartCommand(Edge* edge) {
2539 assert(!last_command_);
2540 commands_ran_.push_back(edge->EvaluateCommand());
2541 if (edge->rule().name() == "cat" ||
2542 edge->rule().name() == "cat_rsp" ||
2543 edge->rule().name() == "cat_rsp_out" ||
2544 edge->rule().name() == "cc" ||
2545 edge->rule().name() == "touch" ||
2546 edge->rule().name() == "touch-interrupt" ||
2547 edge->rule().name() == "touch-fail-tick2") {
2548 for (vector<Node*>::iterator out = edge->outputs_.begin();
2549 out != edge->outputs_.end(); ++out) {
2550 fs_->Create((*out)->path(), "");
2551 }
2552 } else if (edge->rule().name() == "true" ||
2553 edge->rule().name() == "fail" ||
2554 edge->rule().name() == "interrupt" ||
2555 edge->rule().name() == "console") {
2556 // Don't do anything.
2557 } else {
2558 printf("unknown command\n");
2559 return false;
2560 }
2561
2562 last_command_ = edge;
2563 return true;
2564}
2565
2566bool FakeCommandRunner::WaitForCommand(Result* result) {
2567 if (!last_command_)
2568 return false;
2569
2570 Edge* edge = last_command_;
2571 result->edge = edge;
2572
2573 if (edge->rule().name() == "interrupt" ||
2574 edge->rule().name() == "touch-interrupt") {
2575 result->status = ExitInterrupted;
2576 return true;
2577 }
2578
2579 if (edge->rule().name() == "console") {
2580 if (edge->use_console())
2581 result->status = ExitSuccess;
2582 else
2583 result->status = ExitFailure;
2584 last_command_ = NULL;
2585 return true;
2586 }
2587
2588 if (edge->rule().name() == "fail" ||
2589 (edge->rule().name() == "touch-fail-tick2" && fs_->now_ == 2))
2590 result->status = ExitFailure;
2591 else
2592 result->status = ExitSuccess;
2593 last_command_ = NULL;
2594 return true;
2595}
2596
2597vector<Edge*> FakeCommandRunner::GetActiveEdges() {
2598 vector<Edge*> edges;
2599 if (last_command_)
2600 edges.push_back(last_command_);
2601 return edges;
2602}
2603
2604void FakeCommandRunner::Abort() {
2605 last_command_ = NULL;
2606}
2607
2608void BuildTest::Dirty(const string& path) {
2609 Node* node = GetNode(path);
2610 node->MarkDirty();
2611
2612 // If it's an input file, mark that we've already stat()ed it and
2613 // it's missing.
2614 if (!node->in_edge())
2615 node->MarkMissing();
2616}
2617
2618TEST_F(BuildTest, NoWork) {
2619 string err;
2620 EXPECT_TRUE(builder_.AlreadyUpToDate());
2621}
2622
2623TEST_F(BuildTest, OneStep) {
2624 // Given a dirty target with one ready input,
2625 // we should rebuild the target.
2626 Dirty("cat1");
2627 string err;
2628 EXPECT_TRUE(builder_.AddTarget("cat1", &err));
2629 ASSERT_EQ("", err);
2630 EXPECT_TRUE(builder_.Build(&err));
2631 ASSERT_EQ("", err);
2632
2633 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
2634 EXPECT_EQ("cat in1 > cat1", command_runner_.commands_ran_[0]);
2635}
2636
2637TEST_F(BuildTest, OneStep2) {
2638 // Given a target with one dirty input,
2639 // we should rebuild the target.
2640 Dirty("cat1");
2641 string err;
2642 EXPECT_TRUE(builder_.AddTarget("cat1", &err));
2643 ASSERT_EQ("", err);
2644 EXPECT_TRUE(builder_.Build(&err));
2645 EXPECT_EQ("", err);
2646
2647 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
2648 EXPECT_EQ("cat in1 > cat1", command_runner_.commands_ran_[0]);
2649}
2650
2651TEST_F(BuildTest, TwoStep) {
2652 string err;
2653 EXPECT_TRUE(builder_.AddTarget("cat12", &err));
2654 ASSERT_EQ("", err);
2655 EXPECT_TRUE(builder_.Build(&err));
2656 EXPECT_EQ("", err);
2657 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
2658 // Depending on how the pointers work out, we could've ran
2659 // the first two commands in either order.
2660 EXPECT_TRUE((command_runner_.commands_ran_[0] == "cat in1 > cat1" &&
2661 command_runner_.commands_ran_[1] == "cat in1 in2 > cat2") ||
2662 (command_runner_.commands_ran_[1] == "cat in1 > cat1" &&
2663 command_runner_.commands_ran_[0] == "cat in1 in2 > cat2"));
2664
2665 EXPECT_EQ("cat cat1 cat2 > cat12", command_runner_.commands_ran_[2]);
2666
2667 fs_.Tick();
2668
2669 // Modifying in2 requires rebuilding one intermediate file
2670 // and the final file.
2671 fs_.Create("in2", "");
2672 state_.Reset();
2673 EXPECT_TRUE(builder_.AddTarget("cat12", &err));
2674 ASSERT_EQ("", err);
2675 EXPECT_TRUE(builder_.Build(&err));
2676 ASSERT_EQ("", err);
2677 ASSERT_EQ(5u, command_runner_.commands_ran_.size());
2678 EXPECT_EQ("cat in1 in2 > cat2", command_runner_.commands_ran_[3]);
2679 EXPECT_EQ("cat cat1 cat2 > cat12", command_runner_.commands_ran_[4]);
2680}
2681
2682TEST_F(BuildTest, TwoOutputs) {
2683 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2684"rule touch\n"
2685" command = touch $out\n"
2686"build out1 out2: touch in.txt\n"));
2687
2688 fs_.Create("in.txt", "");
2689
2690 string err;
2691 EXPECT_TRUE(builder_.AddTarget("out1", &err));
2692 ASSERT_EQ("", err);
2693 EXPECT_TRUE(builder_.Build(&err));
2694 EXPECT_EQ("", err);
2695 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
2696 EXPECT_EQ("touch out1 out2", command_runner_.commands_ran_[0]);
2697}
2698
2699TEST_F(BuildTest, ImplicitOutput) {
2700 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2701"rule touch\n"
2702" command = touch $out $out.imp\n"
2703"build out | out.imp: touch in.txt\n"));
2704 fs_.Create("in.txt", "");
2705
2706 string err;
2707 EXPECT_TRUE(builder_.AddTarget("out.imp", &err));
2708 ASSERT_EQ("", err);
2709 EXPECT_TRUE(builder_.Build(&err));
2710 EXPECT_EQ("", err);
2711 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
2712 EXPECT_EQ("touch out out.imp", command_runner_.commands_ran_[0]);
2713}
2714
2715// Test case from
2716// https://github.com/ninja-build/ninja/issues/148
2717TEST_F(BuildTest, MultiOutIn) {
2718 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2719"rule touch\n"
2720" command = touch $out\n"
2721"build in1 otherfile: touch in\n"
2722"build out: touch in | in1\n"));
2723
2724 fs_.Create("in", "");
2725 fs_.Tick();
2726 fs_.Create("in1", "");
2727
2728 string err;
2729 EXPECT_TRUE(builder_.AddTarget("out", &err));
2730 ASSERT_EQ("", err);
2731 EXPECT_TRUE(builder_.Build(&err));
2732 EXPECT_EQ("", err);
2733}
2734
2735TEST_F(BuildTest, Chain) {
2736 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2737"build c2: cat c1\n"
2738"build c3: cat c2\n"
2739"build c4: cat c3\n"
2740"build c5: cat c4\n"));
2741
2742 fs_.Create("c1", "");
2743
2744 string err;
2745 EXPECT_TRUE(builder_.AddTarget("c5", &err));
2746 ASSERT_EQ("", err);
2747 EXPECT_TRUE(builder_.Build(&err));
2748 EXPECT_EQ("", err);
2749 ASSERT_EQ(4u, command_runner_.commands_ran_.size());
2750
2751 err.clear();
2752 command_runner_.commands_ran_.clear();
2753 state_.Reset();
2754 EXPECT_TRUE(builder_.AddTarget("c5", &err));
2755 ASSERT_EQ("", err);
2756 EXPECT_TRUE(builder_.AlreadyUpToDate());
2757
2758 fs_.Tick();
2759
2760 fs_.Create("c3", "");
2761 err.clear();
2762 command_runner_.commands_ran_.clear();
2763 state_.Reset();
2764 EXPECT_TRUE(builder_.AddTarget("c5", &err));
2765 ASSERT_EQ("", err);
2766 EXPECT_FALSE(builder_.AlreadyUpToDate());
2767 EXPECT_TRUE(builder_.Build(&err));
2768 ASSERT_EQ(2u, command_runner_.commands_ran_.size()); // 3->4, 4->5
2769}
2770
2771TEST_F(BuildTest, MissingInput) {
2772 // Input is referenced by build file, but no rule for it.
2773 string err;
2774 Dirty("in1");
2775 EXPECT_FALSE(builder_.AddTarget("cat1", &err));
2776 EXPECT_EQ("'in1', needed by 'cat1', missing and no known rule to make it",
2777 err);
2778}
2779
2780TEST_F(BuildTest, MissingTarget) {
2781 // Target is not referenced by build file.
2782 string err;
2783 EXPECT_FALSE(builder_.AddTarget("meow", &err));
2784 EXPECT_EQ("unknown target: 'meow'", err);
2785}
2786
2787TEST_F(BuildTest, MakeDirs) {
2788 string err;
2789
2790#ifdef _WIN32
2791 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2792 "build subdir\\dir2\\file: cat in1\n"));
2793#else
2794 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2795 "build subdir/dir2/file: cat in1\n"));
2796#endif
2797 EXPECT_TRUE(builder_.AddTarget("subdir/dir2/file", &err));
2798
2799 EXPECT_EQ("", err);
2800 EXPECT_TRUE(builder_.Build(&err));
2801 ASSERT_EQ("", err);
2802 ASSERT_EQ(2u, fs_.directories_made_.size());
2803 EXPECT_EQ("subdir", fs_.directories_made_[0]);
2804 EXPECT_EQ("subdir/dir2", fs_.directories_made_[1]);
2805}
2806
2807TEST_F(BuildTest, DepFileMissing) {
2808 string err;
2809 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2810"rule cc\n command = cc $in\n depfile = $out.d\n"
2811"build fo$ o.o: cc foo.c\n"));
2812 fs_.Create("foo.c", "");
2813
2814 EXPECT_TRUE(builder_.AddTarget("fo o.o", &err));
2815 ASSERT_EQ("", err);
2816 ASSERT_EQ(1u, fs_.files_read_.size());
2817 EXPECT_EQ("fo o.o.d", fs_.files_read_[0]);
2818}
2819
2820TEST_F(BuildTest, DepFileOK) {
2821 string err;
2822 int orig_edges = state_.edges_.size();
2823 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2824"rule cc\n command = cc $in\n depfile = $out.d\n"
2825"build foo.o: cc foo.c\n"));
2826 Edge* edge = state_.edges_.back();
2827
2828 fs_.Create("foo.c", "");
2829 GetNode("bar.h")->MarkDirty(); // Mark bar.h as missing.
2830 fs_.Create("foo.o.d", "foo.o: blah.h bar.h\n");
2831 EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
2832 ASSERT_EQ("", err);
2833 ASSERT_EQ(1u, fs_.files_read_.size());
2834 EXPECT_EQ("foo.o.d", fs_.files_read_[0]);
2835
2836 // Expect three new edges: one generating foo.o, and two more from
2837 // loading the depfile.
2838 ASSERT_EQ(orig_edges + 3, (int)state_.edges_.size());
2839 // Expect our edge to now have three inputs: foo.c and two headers.
2840 ASSERT_EQ(3u, edge->inputs_.size());
2841
2842 // Expect the command line we generate to only use the original input.
2843 ASSERT_EQ("cc foo.c", edge->EvaluateCommand());
2844}
2845
2846TEST_F(BuildTest, DepFileParseError) {
2847 string err;
2848 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2849"rule cc\n command = cc $in\n depfile = $out.d\n"
2850"build foo.o: cc foo.c\n"));
2851 fs_.Create("foo.c", "");
2852 fs_.Create("foo.o.d", "randomtext\n");
2853 EXPECT_FALSE(builder_.AddTarget("foo.o", &err));
2854 EXPECT_EQ("foo.o.d: expected ':' in depfile", err);
2855}
2856
2857TEST_F(BuildTest, EncounterReadyTwice) {
2858 string err;
2859 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2860"rule touch\n"
2861" command = touch $out\n"
2862"build c: touch\n"
2863"build b: touch || c\n"
2864"build a: touch | b || c\n"));
2865
2866 vector<Edge*> c_out = GetNode("c")->out_edges();
2867 ASSERT_EQ(2u, c_out.size());
2868 EXPECT_EQ("b", c_out[0]->outputs_[0]->path());
2869 EXPECT_EQ("a", c_out[1]->outputs_[0]->path());
2870
2871 fs_.Create("b", "");
2872 EXPECT_TRUE(builder_.AddTarget("a", &err));
2873 ASSERT_EQ("", err);
2874
2875 EXPECT_TRUE(builder_.Build(&err));
2876 ASSERT_EQ("", err);
2877 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
2878}
2879
2880TEST_F(BuildTest, OrderOnlyDeps) {
2881 string err;
2882 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2883"rule cc\n command = cc $in\n depfile = $out.d\n"
2884"build foo.o: cc foo.c || otherfile\n"));
2885 Edge* edge = state_.edges_.back();
2886
2887 fs_.Create("foo.c", "");
2888 fs_.Create("otherfile", "");
2889 fs_.Create("foo.o.d", "foo.o: blah.h bar.h\n");
2890 EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
2891 ASSERT_EQ("", err);
2892
2893 // One explicit, two implicit, one order only.
2894 ASSERT_EQ(4u, edge->inputs_.size());
2895 EXPECT_EQ(2, edge->implicit_deps_);
2896 EXPECT_EQ(1, edge->order_only_deps_);
2897 // Verify the inputs are in the order we expect
2898 // (explicit then implicit then orderonly).
2899 EXPECT_EQ("foo.c", edge->inputs_[0]->path());
2900 EXPECT_EQ("blah.h", edge->inputs_[1]->path());
2901 EXPECT_EQ("bar.h", edge->inputs_[2]->path());
2902 EXPECT_EQ("otherfile", edge->inputs_[3]->path());
2903
2904 // Expect the command line we generate to only use the original input.
2905 ASSERT_EQ("cc foo.c", edge->EvaluateCommand());
2906
2907 // explicit dep dirty, expect a rebuild.
2908 EXPECT_TRUE(builder_.Build(&err));
2909 ASSERT_EQ("", err);
2910 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
2911
2912 fs_.Tick();
2913
2914 // Recreate the depfile, as it should have been deleted by the build.
2915 fs_.Create("foo.o.d", "foo.o: blah.h bar.h\n");
2916
2917 // implicit dep dirty, expect a rebuild.
2918 fs_.Create("blah.h", "");
2919 fs_.Create("bar.h", "");
2920 command_runner_.commands_ran_.clear();
2921 state_.Reset();
2922 EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
2923 EXPECT_TRUE(builder_.Build(&err));
2924 ASSERT_EQ("", err);
2925 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
2926
2927 fs_.Tick();
2928
2929 // Recreate the depfile, as it should have been deleted by the build.
2930 fs_.Create("foo.o.d", "foo.o: blah.h bar.h\n");
2931
2932 // order only dep dirty, no rebuild.
2933 fs_.Create("otherfile", "");
2934 command_runner_.commands_ran_.clear();
2935 state_.Reset();
2936 EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
2937 EXPECT_EQ("", err);
2938 EXPECT_TRUE(builder_.AlreadyUpToDate());
2939
2940 // implicit dep missing, expect rebuild.
2941 fs_.RemoveFile("bar.h");
2942 command_runner_.commands_ran_.clear();
2943 state_.Reset();
2944 EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
2945 EXPECT_TRUE(builder_.Build(&err));
2946 ASSERT_EQ("", err);
2947 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
2948}
2949
2950TEST_F(BuildTest, RebuildOrderOnlyDeps) {
2951 string err;
2952 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
2953"rule cc\n command = cc $in\n"
2954"rule true\n command = true\n"
2955"build oo.h: cc oo.h.in\n"
2956"build foo.o: cc foo.c || oo.h\n"));
2957
2958 fs_.Create("foo.c", "");
2959 fs_.Create("oo.h.in", "");
2960
2961 // foo.o and order-only dep dirty, build both.
2962 EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
2963 EXPECT_TRUE(builder_.Build(&err));
2964 ASSERT_EQ("", err);
2965 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
2966
2967 // all clean, no rebuild.
2968 command_runner_.commands_ran_.clear();
2969 state_.Reset();
2970 EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
2971 EXPECT_EQ("", err);
2972 EXPECT_TRUE(builder_.AlreadyUpToDate());
2973
2974 // order-only dep missing, build it only.
2975 fs_.RemoveFile("oo.h");
2976 command_runner_.commands_ran_.clear();
2977 state_.Reset();
2978 EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
2979 EXPECT_TRUE(builder_.Build(&err));
2980 ASSERT_EQ("", err);
2981 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
2982 ASSERT_EQ("cc oo.h.in", command_runner_.commands_ran_[0]);
2983
2984 fs_.Tick();
2985
2986 // order-only dep dirty, build it only.
2987 fs_.Create("oo.h.in", "");
2988 command_runner_.commands_ran_.clear();
2989 state_.Reset();
2990 EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
2991 EXPECT_TRUE(builder_.Build(&err));
2992 ASSERT_EQ("", err);
2993 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
2994 ASSERT_EQ("cc oo.h.in", command_runner_.commands_ran_[0]);
2995}
2996
2997#ifdef _WIN32
2998TEST_F(BuildTest, DepFileCanonicalize) {
2999 string err;
3000 int orig_edges = state_.edges_.size();
3001 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3002"rule cc\n command = cc $in\n depfile = $out.d\n"
3003"build gen/stuff\\things/foo.o: cc x\\y/z\\foo.c\n"));
3004 Edge* edge = state_.edges_.back();
3005
3006 fs_.Create("x/y/z/foo.c", "");
3007 GetNode("bar.h")->MarkDirty(); // Mark bar.h as missing.
3008 // Note, different slashes from manifest.
3009 fs_.Create("gen/stuff\\things/foo.o.d",
3010 "gen\\stuff\\things\\foo.o: blah.h bar.h\n");
3011 EXPECT_TRUE(builder_.AddTarget("gen/stuff/things/foo.o", &err));
3012 ASSERT_EQ("", err);
3013 ASSERT_EQ(1u, fs_.files_read_.size());
3014 // The depfile path does not get Canonicalize as it seems unnecessary.
3015 EXPECT_EQ("gen/stuff\\things/foo.o.d", fs_.files_read_[0]);
3016
3017 // Expect three new edges: one generating foo.o, and two more from
3018 // loading the depfile.
3019 ASSERT_EQ(orig_edges + 3, (int)state_.edges_.size());
3020 // Expect our edge to now have three inputs: foo.c and two headers.
3021 ASSERT_EQ(3u, edge->inputs_.size());
3022
3023 // Expect the command line we generate to only use the original input, and
3024 // using the slashes from the manifest.
3025 ASSERT_EQ("cc x\\y/z\\foo.c", edge->EvaluateCommand());
3026}
3027#endif
3028
3029TEST_F(BuildTest, Phony) {
3030 string err;
3031 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3032"build out: cat bar.cc\n"
3033"build all: phony out\n"));
3034 fs_.Create("bar.cc", "");
3035
3036 EXPECT_TRUE(builder_.AddTarget("all", &err));
3037 ASSERT_EQ("", err);
3038
3039 // Only one command to run, because phony runs no command.
3040 EXPECT_FALSE(builder_.AlreadyUpToDate());
3041 EXPECT_TRUE(builder_.Build(&err));
3042 ASSERT_EQ("", err);
3043 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
3044}
3045
3046TEST_F(BuildTest, PhonyNoWork) {
3047 string err;
3048 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3049"build out: cat bar.cc\n"
3050"build all: phony out\n"));
3051 fs_.Create("bar.cc", "");
3052 fs_.Create("out", "");
3053
3054 EXPECT_TRUE(builder_.AddTarget("all", &err));
3055 ASSERT_EQ("", err);
3056 EXPECT_TRUE(builder_.AlreadyUpToDate());
3057}
3058
3059// Test a self-referencing phony. Ideally this should not work, but
3060// ninja 1.7 and below tolerated and CMake 2.8.12.x and 3.0.x both
3061// incorrectly produce it. We tolerate it for compatibility.
3062TEST_F(BuildTest, PhonySelfReference) {
3063 string err;
3064 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3065"build a: phony a\n"));
3066
3067 EXPECT_TRUE(builder_.AddTarget("a", &err));
3068 ASSERT_EQ("", err);
3069 EXPECT_TRUE(builder_.AlreadyUpToDate());
3070}
3071
3072TEST_F(BuildTest, Fail) {
3073 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3074"rule fail\n"
3075" command = fail\n"
3076"build out1: fail\n"));
3077
3078 string err;
3079 EXPECT_TRUE(builder_.AddTarget("out1", &err));
3080 ASSERT_EQ("", err);
3081
3082 EXPECT_FALSE(builder_.Build(&err));
3083 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
3084 ASSERT_EQ("subcommand failed", err);
3085}
3086
3087TEST_F(BuildTest, SwallowFailures) {
3088 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3089"rule fail\n"
3090" command = fail\n"
3091"build out1: fail\n"
3092"build out2: fail\n"
3093"build out3: fail\n"
3094"build all: phony out1 out2 out3\n"));
3095
3096 // Swallow two failures, die on the third.
3097 config_.failures_allowed = 3;
3098
3099 string err;
3100 EXPECT_TRUE(builder_.AddTarget("all", &err));
3101 ASSERT_EQ("", err);
3102
3103 EXPECT_FALSE(builder_.Build(&err));
3104 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
3105 ASSERT_EQ("subcommands failed", err);
3106}
3107
3108TEST_F(BuildTest, SwallowFailuresLimit) {
3109 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3110"rule fail\n"
3111" command = fail\n"
3112"build out1: fail\n"
3113"build out2: fail\n"
3114"build out3: fail\n"
3115"build final: cat out1 out2 out3\n"));
3116
3117 // Swallow ten failures; we should stop before building final.
3118 config_.failures_allowed = 11;
3119
3120 string err;
3121 EXPECT_TRUE(builder_.AddTarget("final", &err));
3122 ASSERT_EQ("", err);
3123
3124 EXPECT_FALSE(builder_.Build(&err));
3125 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
3126 ASSERT_EQ("cannot make progress due to previous errors", err);
3127}
3128
3129TEST_F(BuildTest, SwallowFailuresPool) {
3130 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3131"pool failpool\n"
3132" depth = 1\n"
3133"rule fail\n"
3134" command = fail\n"
3135" pool = failpool\n"
3136"build out1: fail\n"
3137"build out2: fail\n"
3138"build out3: fail\n"
3139"build final: cat out1 out2 out3\n"));
3140
3141 // Swallow ten failures; we should stop before building final.
3142 config_.failures_allowed = 11;
3143
3144 string err;
3145 EXPECT_TRUE(builder_.AddTarget("final", &err));
3146 ASSERT_EQ("", err);
3147
3148 EXPECT_FALSE(builder_.Build(&err));
3149 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
3150 ASSERT_EQ("cannot make progress due to previous errors", err);
3151}
3152
3153TEST_F(BuildTest, PoolEdgesReadyButNotWanted) {
3154 fs_.Create("x", "");
3155
3156 const char* manifest =
3157 "pool some_pool\n"
3158 " depth = 4\n"
3159 "rule touch\n"
3160 " command = touch $out\n"
3161 " pool = some_pool\n"
3162 "rule cc\n"
3163 " command = touch grit\n"
3164 "\n"
3165 "build B.d.stamp: cc | x\n"
3166 "build C.stamp: touch B.d.stamp\n"
3167 "build final.stamp: touch || C.stamp\n";
3168
3169 RebuildTarget("final.stamp", manifest);
3170
3171 fs_.RemoveFile("B.d.stamp");
3172
3173 State save_state;
3174 RebuildTarget("final.stamp", manifest, NULL, NULL, &save_state);
3175 EXPECT_GE(save_state.LookupPool("some_pool")->current_use(), 0);
3176}
3177
3178struct BuildWithLogTest : public BuildTest {
3179 BuildWithLogTest() {
3180 builder_.SetBuildLog(&build_log_);
3181 }
3182
3183 BuildLog build_log_;
3184};
3185
3186TEST_F(BuildWithLogTest, NotInLogButOnDisk) {
3187 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3188"rule cc\n"
3189" command = cc\n"
3190"build out1: cc in\n"));
3191
3192 // Create input/output that would be considered up to date when
3193 // not considering the command line hash.
3194 fs_.Create("in", "");
3195 fs_.Create("out1", "");
3196 string err;
3197
3198 // Because it's not in the log, it should not be up-to-date until
3199 // we build again.
3200 EXPECT_TRUE(builder_.AddTarget("out1", &err));
3201 EXPECT_FALSE(builder_.AlreadyUpToDate());
3202
3203 command_runner_.commands_ran_.clear();
3204 state_.Reset();
3205
3206 EXPECT_TRUE(builder_.AddTarget("out1", &err));
3207 EXPECT_TRUE(builder_.Build(&err));
3208 EXPECT_TRUE(builder_.AlreadyUpToDate());
3209}
3210
3211TEST_F(BuildWithLogTest, RebuildAfterFailure) {
3212 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3213"rule touch-fail-tick2\n"
3214" command = touch-fail-tick2\n"
3215"build out1: touch-fail-tick2 in\n"));
3216
3217 string err;
3218
3219 fs_.Create("in", "");
3220
3221 // Run once successfully to get out1 in the log
3222 EXPECT_TRUE(builder_.AddTarget("out1", &err));
3223 EXPECT_TRUE(builder_.Build(&err));
3224 EXPECT_EQ("", err);
3225 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
3226
3227 command_runner_.commands_ran_.clear();
3228 state_.Reset();
3229 builder_.Cleanup();
3230 builder_.plan_.Reset();
3231
3232 fs_.Tick();
3233 fs_.Create("in", "");
3234
3235 // Run again with a failure that updates the output file timestamp
3236 EXPECT_TRUE(builder_.AddTarget("out1", &err));
3237 EXPECT_FALSE(builder_.Build(&err));
3238 EXPECT_EQ("subcommand failed", err);
3239 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
3240
3241 command_runner_.commands_ran_.clear();
3242 state_.Reset();
3243 builder_.Cleanup();
3244 builder_.plan_.Reset();
3245
3246 fs_.Tick();
3247
3248 // Run again, should rerun even though the output file is up to date on disk
3249 EXPECT_TRUE(builder_.AddTarget("out1", &err));
3250 EXPECT_FALSE(builder_.AlreadyUpToDate());
3251 EXPECT_TRUE(builder_.Build(&err));
3252 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
3253 EXPECT_EQ("", err);
3254}
3255
3256TEST_F(BuildWithLogTest, RebuildWithNoInputs) {
3257 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3258"rule touch\n"
3259" command = touch\n"
3260"build out1: touch\n"
3261"build out2: touch in\n"));
3262
3263 string err;
3264
3265 fs_.Create("in", "");
3266
3267 EXPECT_TRUE(builder_.AddTarget("out1", &err));
3268 EXPECT_TRUE(builder_.AddTarget("out2", &err));
3269 EXPECT_TRUE(builder_.Build(&err));
3270 EXPECT_EQ("", err);
3271 EXPECT_EQ(2u, command_runner_.commands_ran_.size());
3272
3273 command_runner_.commands_ran_.clear();
3274 state_.Reset();
3275
3276 fs_.Tick();
3277
3278 fs_.Create("in", "");
3279
3280 EXPECT_TRUE(builder_.AddTarget("out1", &err));
3281 EXPECT_TRUE(builder_.AddTarget("out2", &err));
3282 EXPECT_TRUE(builder_.Build(&err));
3283 EXPECT_EQ("", err);
3284 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
3285}
3286
3287TEST_F(BuildWithLogTest, RestatTest) {
3288 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3289"rule true\n"
3290" command = true\n"
3291" restat = 1\n"
3292"rule cc\n"
3293" command = cc\n"
3294" restat = 1\n"
3295"build out1: cc in\n"
3296"build out2: true out1\n"
3297"build out3: cat out2\n"));
3298
3299 fs_.Create("out1", "");
3300 fs_.Create("out2", "");
3301 fs_.Create("out3", "");
3302
3303 fs_.Tick();
3304
3305 fs_.Create("in", "");
3306
3307 // Do a pre-build so that there's commands in the log for the outputs,
3308 // otherwise, the lack of an entry in the build log will cause out3 to rebuild
3309 // regardless of restat.
3310 string err;
3311 EXPECT_TRUE(builder_.AddTarget("out3", &err));
3312 ASSERT_EQ("", err);
3313 EXPECT_TRUE(builder_.Build(&err));
3314 ASSERT_EQ("", err);
3315 EXPECT_EQ("[3/3]", builder_.status_->FormatProgressStatus("[%s/%t]",
3316 BuildStatus::kEdgeStarted));
3317 command_runner_.commands_ran_.clear();
3318 state_.Reset();
3319
3320 fs_.Tick();
3321
3322 fs_.Create("in", "");
3323 // "cc" touches out1, so we should build out2. But because "true" does not
3324 // touch out2, we should cancel the build of out3.
3325 EXPECT_TRUE(builder_.AddTarget("out3", &err));
3326 ASSERT_EQ("", err);
3327 EXPECT_TRUE(builder_.Build(&err));
3328 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
3329
3330 // If we run again, it should be a no-op, because the build log has recorded
3331 // that we've already built out2 with an input timestamp of 2 (from out1).
3332 command_runner_.commands_ran_.clear();
3333 state_.Reset();
3334 EXPECT_TRUE(builder_.AddTarget("out3", &err));
3335 ASSERT_EQ("", err);
3336 EXPECT_TRUE(builder_.AlreadyUpToDate());
3337
3338 fs_.Tick();
3339
3340 fs_.Create("in", "");
3341
3342 // The build log entry should not, however, prevent us from rebuilding out2
3343 // if out1 changes.
3344 command_runner_.commands_ran_.clear();
3345 state_.Reset();
3346 EXPECT_TRUE(builder_.AddTarget("out3", &err));
3347 ASSERT_EQ("", err);
3348 EXPECT_TRUE(builder_.Build(&err));
3349 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
3350}
3351
3352TEST_F(BuildWithLogTest, RestatMissingFile) {
3353 // If a restat rule doesn't create its output, and the output didn't
3354 // exist before the rule was run, consider that behavior equivalent
3355 // to a rule that doesn't modify its existent output file.
3356
3357 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3358"rule true\n"
3359" command = true\n"
3360" restat = 1\n"
3361"rule cc\n"
3362" command = cc\n"
3363"build out1: true in\n"
3364"build out2: cc out1\n"));
3365
3366 fs_.Create("in", "");
3367 fs_.Create("out2", "");
3368
3369 // Do a pre-build so that there's commands in the log for the outputs,
3370 // otherwise, the lack of an entry in the build log will cause out2 to rebuild
3371 // regardless of restat.
3372 string err;
3373 EXPECT_TRUE(builder_.AddTarget("out2", &err));
3374 ASSERT_EQ("", err);
3375 EXPECT_TRUE(builder_.Build(&err));
3376 ASSERT_EQ("", err);
3377 command_runner_.commands_ran_.clear();
3378 state_.Reset();
3379
3380 fs_.Tick();
3381 fs_.Create("in", "");
3382 fs_.Create("out2", "");
3383
3384 // Run a build, expect only the first command to run.
3385 // It doesn't touch its output (due to being the "true" command), so
3386 // we shouldn't run the dependent build.
3387 EXPECT_TRUE(builder_.AddTarget("out2", &err));
3388 ASSERT_EQ("", err);
3389 EXPECT_TRUE(builder_.Build(&err));
3390 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
3391}
3392
3393TEST_F(BuildWithLogTest, RestatSingleDependentOutputDirty) {
3394 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3395 "rule true\n"
3396 " command = true\n"
3397 " restat = 1\n"
3398 "rule touch\n"
3399 " command = touch\n"
3400 "build out1: true in\n"
3401 "build out2 out3: touch out1\n"
3402 "build out4: touch out2\n"
3403 ));
3404
3405 // Create the necessary files
3406 fs_.Create("in", "");
3407
3408 string err;
3409 EXPECT_TRUE(builder_.AddTarget("out4", &err));
3410 ASSERT_EQ("", err);
3411 EXPECT_TRUE(builder_.Build(&err));
3412 ASSERT_EQ("", err);
3413 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
3414
3415 fs_.Tick();
3416 fs_.Create("in", "");
3417 fs_.RemoveFile("out3");
3418
3419 // Since "in" is missing, out1 will be built. Since "out3" is missing,
3420 // out2 and out3 will be built even though "in" is not touched when built.
3421 // Then, since out2 is rebuilt, out4 should be rebuilt -- the restat on the
3422 // "true" rule should not lead to the "touch" edge writing out2 and out3 being
3423 // cleard.
3424 command_runner_.commands_ran_.clear();
3425 state_.Reset();
3426 EXPECT_TRUE(builder_.AddTarget("out4", &err));
3427 ASSERT_EQ("", err);
3428 EXPECT_TRUE(builder_.Build(&err));
3429 ASSERT_EQ("", err);
3430 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
3431}
3432
3433// Test scenario, in which an input file is removed, but output isn't changed
3434// https://github.com/ninja-build/ninja/issues/295
3435TEST_F(BuildWithLogTest, RestatMissingInput) {
3436 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3437 "rule true\n"
3438 " command = true\n"
3439 " depfile = $out.d\n"
3440 " restat = 1\n"
3441 "rule cc\n"
3442 " command = cc\n"
3443 "build out1: true in\n"
3444 "build out2: cc out1\n"));
3445
3446 // Create all necessary files
3447 fs_.Create("in", "");
3448
3449 // The implicit dependencies and the depfile itself
3450 // are newer than the output
3451 TimeStamp restat_mtime = fs_.Tick();
3452 fs_.Create("out1.d", "out1: will.be.deleted restat.file\n");
3453 fs_.Create("will.be.deleted", "");
3454 fs_.Create("restat.file", "");
3455
3456 // Run the build, out1 and out2 get built
3457 string err;
3458 EXPECT_TRUE(builder_.AddTarget("out2", &err));
3459 ASSERT_EQ("", err);
3460 EXPECT_TRUE(builder_.Build(&err));
3461 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
3462
3463 // See that an entry in the logfile is created, capturing
3464 // the right mtime
3465 BuildLog::LogEntry* log_entry = build_log_.LookupByOutput("out1");
3466 ASSERT_TRUE(NULL != log_entry);
3467 ASSERT_EQ(restat_mtime, log_entry->mtime);
3468
3469 // Now remove a file, referenced from depfile, so that target becomes
3470 // dirty, but the output does not change
3471 fs_.RemoveFile("will.be.deleted");
3472
3473 // Trigger the build again - only out1 gets built
3474 command_runner_.commands_ran_.clear();
3475 state_.Reset();
3476 EXPECT_TRUE(builder_.AddTarget("out2", &err));
3477 ASSERT_EQ("", err);
3478 EXPECT_TRUE(builder_.Build(&err));
3479 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
3480
3481 // Check that the logfile entry remains correctly set
3482 log_entry = build_log_.LookupByOutput("out1");
3483 ASSERT_TRUE(NULL != log_entry);
3484 ASSERT_EQ(restat_mtime, log_entry->mtime);
3485}
3486
3487struct BuildDryRun : public BuildWithLogTest {
3488 BuildDryRun() {
3489 config_.dry_run = true;
3490 }
3491};
3492
3493TEST_F(BuildDryRun, AllCommandsShown) {
3494 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3495"rule true\n"
3496" command = true\n"
3497" restat = 1\n"
3498"rule cc\n"
3499" command = cc\n"
3500" restat = 1\n"
3501"build out1: cc in\n"
3502"build out2: true out1\n"
3503"build out3: cat out2\n"));
3504
3505 fs_.Create("out1", "");
3506 fs_.Create("out2", "");
3507 fs_.Create("out3", "");
3508
3509 fs_.Tick();
3510
3511 fs_.Create("in", "");
3512
3513 // "cc" touches out1, so we should build out2. But because "true" does not
3514 // touch out2, we should cancel the build of out3.
3515 string err;
3516 EXPECT_TRUE(builder_.AddTarget("out3", &err));
3517 ASSERT_EQ("", err);
3518 EXPECT_TRUE(builder_.Build(&err));
3519 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
3520}
3521
3522// Test that RSP files are created when & where appropriate and deleted after
3523// successful execution.
3524TEST_F(BuildTest, RspFileSuccess)
3525{
3526 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3527 "rule cat_rsp\n"
3528 " command = cat $rspfile > $out\n"
3529 " rspfile = $rspfile\n"
3530 " rspfile_content = $long_command\n"
3531 "rule cat_rsp_out\n"
3532 " command = cat $rspfile > $out\n"
3533 " rspfile = $out.rsp\n"
3534 " rspfile_content = $long_command\n"
3535 "build out1: cat in\n"
3536 "build out2: cat_rsp in\n"
3537 " rspfile = out 2.rsp\n"
3538 " long_command = Some very long command\n"
3539 "build out$ 3: cat_rsp_out in\n"
3540 " long_command = Some very long command\n"));
3541
3542 fs_.Create("out1", "");
3543 fs_.Create("out2", "");
3544 fs_.Create("out 3", "");
3545
3546 fs_.Tick();
3547
3548 fs_.Create("in", "");
3549
3550 string err;
3551 EXPECT_TRUE(builder_.AddTarget("out1", &err));
3552 ASSERT_EQ("", err);
3553 EXPECT_TRUE(builder_.AddTarget("out2", &err));
3554 ASSERT_EQ("", err);
3555 EXPECT_TRUE(builder_.AddTarget("out 3", &err));
3556 ASSERT_EQ("", err);
3557
3558 size_t files_created = fs_.files_created_.size();
3559 size_t files_removed = fs_.files_removed_.size();
3560
3561 EXPECT_TRUE(builder_.Build(&err));
3562 ASSERT_EQ(3u, command_runner_.commands_ran_.size());
3563
3564 // The RSP files were created
3565 ASSERT_EQ(files_created + 2, fs_.files_created_.size());
3566 ASSERT_EQ(1u, fs_.files_created_.count("out 2.rsp"));
3567 ASSERT_EQ(1u, fs_.files_created_.count("out 3.rsp"));
3568
3569 // The RSP files were removed
3570 ASSERT_EQ(files_removed + 2, fs_.files_removed_.size());
3571 ASSERT_EQ(1u, fs_.files_removed_.count("out 2.rsp"));
3572 ASSERT_EQ(1u, fs_.files_removed_.count("out 3.rsp"));
3573}
3574
3575// Test that RSP file is created but not removed for commands, which fail
3576TEST_F(BuildTest, RspFileFailure) {
3577 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3578 "rule fail\n"
3579 " command = fail\n"
3580 " rspfile = $rspfile\n"
3581 " rspfile_content = $long_command\n"
3582 "build out: fail in\n"
3583 " rspfile = out.rsp\n"
3584 " long_command = Another very long command\n"));
3585
3586 fs_.Create("out", "");
3587 fs_.Tick();
3588 fs_.Create("in", "");
3589
3590 string err;
3591 EXPECT_TRUE(builder_.AddTarget("out", &err));
3592 ASSERT_EQ("", err);
3593
3594 size_t files_created = fs_.files_created_.size();
3595 size_t files_removed = fs_.files_removed_.size();
3596
3597 EXPECT_FALSE(builder_.Build(&err));
3598 ASSERT_EQ("subcommand failed", err);
3599 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
3600
3601 // The RSP file was created
3602 ASSERT_EQ(files_created + 1, fs_.files_created_.size());
3603 ASSERT_EQ(1u, fs_.files_created_.count("out.rsp"));
3604
3605 // The RSP file was NOT removed
3606 ASSERT_EQ(files_removed, fs_.files_removed_.size());
3607 ASSERT_EQ(0u, fs_.files_removed_.count("out.rsp"));
3608
3609 // The RSP file contains what it should
3610 ASSERT_EQ("Another very long command", fs_.files_["out.rsp"].contents);
3611}
3612
3613// Test that contents of the RSP file behaves like a regular part of
3614// command line, i.e. triggers a rebuild if changed
3615TEST_F(BuildWithLogTest, RspFileCmdLineChange) {
3616 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3617 "rule cat_rsp\n"
3618 " command = cat $rspfile > $out\n"
3619 " rspfile = $rspfile\n"
3620 " rspfile_content = $long_command\n"
3621 "build out: cat_rsp in\n"
3622 " rspfile = out.rsp\n"
3623 " long_command = Original very long command\n"));
3624
3625 fs_.Create("out", "");
3626 fs_.Tick();
3627 fs_.Create("in", "");
3628
3629 string err;
3630 EXPECT_TRUE(builder_.AddTarget("out", &err));
3631 ASSERT_EQ("", err);
3632
3633 // 1. Build for the 1st time (-> populate log)
3634 EXPECT_TRUE(builder_.Build(&err));
3635 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
3636
3637 // 2. Build again (no change)
3638 command_runner_.commands_ran_.clear();
3639 state_.Reset();
3640 EXPECT_TRUE(builder_.AddTarget("out", &err));
3641 EXPECT_EQ("", err);
3642 ASSERT_TRUE(builder_.AlreadyUpToDate());
3643
3644 // 3. Alter the entry in the logfile
3645 // (to simulate a change in the command line between 2 builds)
3646 BuildLog::LogEntry* log_entry = build_log_.LookupByOutput("out");
3647 ASSERT_TRUE(NULL != log_entry);
3648 ASSERT_NO_FATAL_FAILURE(AssertHash(
3649 "cat out.rsp > out;rspfile=Original very long command",
3650 log_entry->command_hash));
3651 log_entry->command_hash++; // Change the command hash to something else.
3652 // Now expect the target to be rebuilt
3653 command_runner_.commands_ran_.clear();
3654 state_.Reset();
3655 EXPECT_TRUE(builder_.AddTarget("out", &err));
3656 EXPECT_EQ("", err);
3657 EXPECT_TRUE(builder_.Build(&err));
3658 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
3659}
3660
3661TEST_F(BuildTest, InterruptCleanup) {
3662 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3663"rule interrupt\n"
3664" command = interrupt\n"
3665"rule touch-interrupt\n"
3666" command = touch-interrupt\n"
3667"build out1: interrupt in1\n"
3668"build out2: touch-interrupt in2\n"));
3669
3670 fs_.Create("out1", "");
3671 fs_.Create("out2", "");
3672 fs_.Tick();
3673 fs_.Create("in1", "");
3674 fs_.Create("in2", "");
3675
3676 // An untouched output of an interrupted command should be retained.
3677 string err;
3678 EXPECT_TRUE(builder_.AddTarget("out1", &err));
3679 EXPECT_EQ("", err);
3680 EXPECT_FALSE(builder_.Build(&err));
3681 EXPECT_EQ("interrupted by user", err);
3682 builder_.Cleanup();
3683 EXPECT_GT(fs_.Stat("out1", &err), 0);
3684 err = "";
3685
3686 // A touched output of an interrupted command should be deleted.
3687 EXPECT_TRUE(builder_.AddTarget("out2", &err));
3688 EXPECT_EQ("", err);
3689 EXPECT_FALSE(builder_.Build(&err));
3690 EXPECT_EQ("interrupted by user", err);
3691 builder_.Cleanup();
3692 EXPECT_EQ(0, fs_.Stat("out2", &err));
3693}
3694
3695TEST_F(BuildTest, StatFailureAbortsBuild) {
3696 const string kTooLongToStat(400, 'i');
3697 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3698("build " + kTooLongToStat + ": cat in\n").c_str()));
3699 fs_.Create("in", "");
3700
3701 // This simulates a stat failure:
3702 fs_.files_[kTooLongToStat].mtime = -1;
3703 fs_.files_[kTooLongToStat].stat_error = "stat failed";
3704
3705 string err;
3706 EXPECT_FALSE(builder_.AddTarget(kTooLongToStat, &err));
3707 EXPECT_EQ("stat failed", err);
3708}
3709
3710TEST_F(BuildTest, PhonyWithNoInputs) {
3711 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3712"build nonexistent: phony\n"
3713"build out1: cat || nonexistent\n"
3714"build out2: cat nonexistent\n"));
3715 fs_.Create("out1", "");
3716 fs_.Create("out2", "");
3717
3718 // out1 should be up to date even though its input is dirty, because its
3719 // order-only dependency has nothing to do.
3720 string err;
3721 EXPECT_TRUE(builder_.AddTarget("out1", &err));
3722 ASSERT_EQ("", err);
3723 EXPECT_TRUE(builder_.AlreadyUpToDate());
3724
3725 // out2 should still be out of date though, because its input is dirty.
3726 err.clear();
3727 command_runner_.commands_ran_.clear();
3728 state_.Reset();
3729 EXPECT_TRUE(builder_.AddTarget("out2", &err));
3730 ASSERT_EQ("", err);
3731 EXPECT_TRUE(builder_.Build(&err));
3732 EXPECT_EQ("", err);
3733 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
3734}
3735
3736TEST_F(BuildTest, DepsGccWithEmptyDepfileErrorsOut) {
3737 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3738"rule cc\n"
3739" command = cc\n"
3740" deps = gcc\n"
3741"build out: cc\n"));
3742 Dirty("out");
3743
3744 string err;
3745 EXPECT_TRUE(builder_.AddTarget("out", &err));
3746 ASSERT_EQ("", err);
3747 EXPECT_FALSE(builder_.AlreadyUpToDate());
3748
3749 EXPECT_FALSE(builder_.Build(&err));
3750 ASSERT_EQ("subcommand failed", err);
3751 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
3752}
3753
3754TEST_F(BuildTest, StatusFormatElapsed) {
3755 status_.BuildStarted();
3756 // Before any task is done, the elapsed time must be zero.
3757 EXPECT_EQ("[%/e0.000]",
3758 status_.FormatProgressStatus("[%%/e%e]",
3759 BuildStatus::kEdgeStarted));
3760}
3761
3762TEST_F(BuildTest, StatusFormatReplacePlaceholder) {
3763 EXPECT_EQ("[%/s0/t0/r0/u0/f0]",
3764 status_.FormatProgressStatus("[%%/s%s/t%t/r%r/u%u/f%f]",
3765 BuildStatus::kEdgeStarted));
3766}
3767
3768TEST_F(BuildTest, FailedDepsParse) {
3769 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3770"build bad_deps.o: cat in1\n"
3771" deps = gcc\n"
3772" depfile = in1.d\n"));
3773
3774 string err;
3775 EXPECT_TRUE(builder_.AddTarget("bad_deps.o", &err));
3776 ASSERT_EQ("", err);
3777
3778 // These deps will fail to parse, as they should only have one
3779 // path to the left of the colon.
3780 fs_.Create("in1.d", "AAA BBB");
3781
3782 EXPECT_FALSE(builder_.Build(&err));
3783 EXPECT_EQ("subcommand failed", err);
3784}
3785
3786/// Tests of builds involving deps logs necessarily must span
3787/// multiple builds. We reuse methods on BuildTest but not the
3788/// builder_ it sets up, because we want pristine objects for
3789/// each build.
3790struct BuildWithDepsLogTest : public BuildTest {
3791 BuildWithDepsLogTest() {}
3792
3793 virtual void SetUp() {
3794 BuildTest::SetUp();
3795
3796 temp_dir_.CreateAndEnter("BuildWithDepsLogTest");
3797 }
3798
3799 virtual void TearDown() {
3800 temp_dir_.Cleanup();
3801 }
3802
3803 ScopedTempDir temp_dir_;
3804
3805 /// Shadow parent class builder_ so we don't accidentally use it.
3806 void* builder_;
3807};
3808
3809/// Run a straightforwad build where the deps log is used.
3810TEST_F(BuildWithDepsLogTest, Straightforward) {
3811 string err;
3812 // Note: in1 was created by the superclass SetUp().
3813 const char* manifest =
3814 "build out: cat in1\n"
3815 " deps = gcc\n"
3816 " depfile = in1.d\n";
3817 {
3818 State state;
3819 ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
3820 ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
3821
3822 // Run the build once, everything should be ok.
3823 DepsLog deps_log;
3824 ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
3825 ASSERT_EQ("", err);
3826
3827 Builder builder(&state, config_, NULL, &deps_log, &fs_);
3828 builder.command_runner_.reset(&command_runner_);
3829 EXPECT_TRUE(builder.AddTarget("out", &err));
3830 ASSERT_EQ("", err);
3831 fs_.Create("in1.d", "out: in2");
3832 EXPECT_TRUE(builder.Build(&err));
3833 EXPECT_EQ("", err);
3834
3835 // The deps file should have been removed.
3836 EXPECT_EQ(0, fs_.Stat("in1.d", &err));
3837 // Recreate it for the next step.
3838 fs_.Create("in1.d", "out: in2");
3839 deps_log.Close();
3840 builder.command_runner_.release();
3841 }
3842
3843 {
3844 State state;
3845 ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
3846 ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
3847
3848 // Touch the file only mentioned in the deps.
3849 fs_.Tick();
3850 fs_.Create("in2", "");
3851
3852 // Run the build again.
3853 DepsLog deps_log;
3854 ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
3855 ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
3856
3857 Builder builder(&state, config_, NULL, &deps_log, &fs_);
3858 builder.command_runner_.reset(&command_runner_);
3859 command_runner_.commands_ran_.clear();
3860 EXPECT_TRUE(builder.AddTarget("out", &err));
3861 ASSERT_EQ("", err);
3862 EXPECT_TRUE(builder.Build(&err));
3863 EXPECT_EQ("", err);
3864
3865 // We should have rebuilt the output due to in2 being
3866 // out of date.
3867 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
3868
3869 builder.command_runner_.release();
3870 }
3871}
3872
3873/// Verify that obsolete dependency info causes a rebuild.
3874/// 1) Run a successful build where everything has time t, record deps.
3875/// 2) Move input/output to time t+1 -- despite files in alignment,
3876/// should still need to rebuild due to deps at older time.
3877TEST_F(BuildWithDepsLogTest, ObsoleteDeps) {
3878 string err;
3879 // Note: in1 was created by the superclass SetUp().
3880 const char* manifest =
3881 "build out: cat in1\n"
3882 " deps = gcc\n"
3883 " depfile = in1.d\n";
3884 {
3885 // Run an ordinary build that gathers dependencies.
3886 fs_.Create("in1", "");
3887 fs_.Create("in1.d", "out: ");
3888
3889 State state;
3890 ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
3891 ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
3892
3893 // Run the build once, everything should be ok.
3894 DepsLog deps_log;
3895 ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
3896 ASSERT_EQ("", err);
3897
3898 Builder builder(&state, config_, NULL, &deps_log, &fs_);
3899 builder.command_runner_.reset(&command_runner_);
3900 EXPECT_TRUE(builder.AddTarget("out", &err));
3901 ASSERT_EQ("", err);
3902 EXPECT_TRUE(builder.Build(&err));
3903 EXPECT_EQ("", err);
3904
3905 deps_log.Close();
3906 builder.command_runner_.release();
3907 }
3908
3909 // Push all files one tick forward so that only the deps are out
3910 // of date.
3911 fs_.Tick();
3912 fs_.Create("in1", "");
3913 fs_.Create("out", "");
3914
3915 // The deps file should have been removed, so no need to timestamp it.
3916 EXPECT_EQ(0, fs_.Stat("in1.d", &err));
3917
3918 {
3919 State state;
3920 ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
3921 ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
3922
3923 DepsLog deps_log;
3924 ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
3925 ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
3926
3927 Builder builder(&state, config_, NULL, &deps_log, &fs_);
3928 builder.command_runner_.reset(&command_runner_);
3929 command_runner_.commands_ran_.clear();
3930 EXPECT_TRUE(builder.AddTarget("out", &err));
3931 ASSERT_EQ("", err);
3932
3933 // Recreate the deps file here because the build expects them to exist.
3934 fs_.Create("in1.d", "out: ");
3935
3936 EXPECT_TRUE(builder.Build(&err));
3937 EXPECT_EQ("", err);
3938
3939 // We should have rebuilt the output due to the deps being
3940 // out of date.
3941 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
3942
3943 builder.command_runner_.release();
3944 }
3945}
3946
3947TEST_F(BuildWithDepsLogTest, DepsIgnoredInDryRun) {
3948 const char* manifest =
3949 "build out: cat in1\n"
3950 " deps = gcc\n"
3951 " depfile = in1.d\n";
3952
3953 fs_.Create("out", "");
3954 fs_.Tick();
3955 fs_.Create("in1", "");
3956
3957 State state;
3958 ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
3959 ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
3960
3961 // The deps log is NULL in dry runs.
3962 config_.dry_run = true;
3963 Builder builder(&state, config_, NULL, NULL, &fs_);
3964 builder.command_runner_.reset(&command_runner_);
3965 command_runner_.commands_ran_.clear();
3966
3967 string err;
3968 EXPECT_TRUE(builder.AddTarget("out", &err));
3969 ASSERT_EQ("", err);
3970 EXPECT_TRUE(builder.Build(&err));
3971 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
3972
3973 builder.command_runner_.release();
3974}
3975
3976/// Check that a restat rule generating a header cancels compilations correctly.
3977TEST_F(BuildTest, RestatDepfileDependency) {
3978 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
3979"rule true\n"
3980" command = true\n" // Would be "write if out-of-date" in reality.
3981" restat = 1\n"
3982"build header.h: true header.in\n"
3983"build out: cat in1\n"
3984" depfile = in1.d\n"));
3985
3986 fs_.Create("header.h", "");
3987 fs_.Create("in1.d", "out: header.h");
3988 fs_.Tick();
3989 fs_.Create("header.in", "");
3990
3991 string err;
3992 EXPECT_TRUE(builder_.AddTarget("out", &err));
3993 ASSERT_EQ("", err);
3994 EXPECT_TRUE(builder_.Build(&err));
3995 EXPECT_EQ("", err);
3996}
3997
3998/// Check that a restat rule generating a header cancels compilations correctly,
3999/// depslog case.
4000TEST_F(BuildWithDepsLogTest, RestatDepfileDependencyDepsLog) {
4001 string err;
4002 // Note: in1 was created by the superclass SetUp().
4003 const char* manifest =
4004 "rule true\n"
4005 " command = true\n" // Would be "write if out-of-date" in reality.
4006 " restat = 1\n"
4007 "build header.h: true header.in\n"
4008 "build out: cat in1\n"
4009 " deps = gcc\n"
4010 " depfile = in1.d\n";
4011 {
4012 State state;
4013 ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
4014 ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
4015
4016 // Run the build once, everything should be ok.
4017 DepsLog deps_log;
4018 ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
4019 ASSERT_EQ("", err);
4020
4021 Builder builder(&state, config_, NULL, &deps_log, &fs_);
4022 builder.command_runner_.reset(&command_runner_);
4023 EXPECT_TRUE(builder.AddTarget("out", &err));
4024 ASSERT_EQ("", err);
4025 fs_.Create("in1.d", "out: header.h");
4026 EXPECT_TRUE(builder.Build(&err));
4027 EXPECT_EQ("", err);
4028
4029 deps_log.Close();
4030 builder.command_runner_.release();
4031 }
4032
4033 {
4034 State state;
4035 ASSERT_NO_FATAL_FAILURE(AddCatRule(&state));
4036 ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
4037
4038 // Touch the input of the restat rule.
4039 fs_.Tick();
4040 fs_.Create("header.in", "");
4041
4042 // Run the build again.
4043 DepsLog deps_log;
4044 ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
4045 ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
4046
4047 Builder builder(&state, config_, NULL, &deps_log, &fs_);
4048 builder.command_runner_.reset(&command_runner_);
4049 command_runner_.commands_ran_.clear();
4050 EXPECT_TRUE(builder.AddTarget("out", &err));
4051 ASSERT_EQ("", err);
4052 EXPECT_TRUE(builder.Build(&err));
4053 EXPECT_EQ("", err);
4054
4055 // Rule "true" should have run again, but the build of "out" should have
4056 // been cancelled due to restat propagating through the depfile header.
4057 EXPECT_EQ(1u, command_runner_.commands_ran_.size());
4058
4059 builder.command_runner_.release();
4060 }
4061}
4062
4063TEST_F(BuildWithDepsLogTest, DepFileOKDepsLog) {
4064 string err;
4065 const char* manifest =
4066 "rule cc\n command = cc $in\n depfile = $out.d\n deps = gcc\n"
4067 "build fo$ o.o: cc foo.c\n";
4068
4069 fs_.Create("foo.c", "");
4070
4071 {
4072 State state;
4073 ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
4074
4075 // Run the build once, everything should be ok.
4076 DepsLog deps_log;
4077 ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
4078 ASSERT_EQ("", err);
4079
4080 Builder builder(&state, config_, NULL, &deps_log, &fs_);
4081 builder.command_runner_.reset(&command_runner_);
4082 EXPECT_TRUE(builder.AddTarget("fo o.o", &err));
4083 ASSERT_EQ("", err);
4084 fs_.Create("fo o.o.d", "fo\\ o.o: blah.h bar.h\n");
4085 EXPECT_TRUE(builder.Build(&err));
4086 EXPECT_EQ("", err);
4087
4088 deps_log.Close();
4089 builder.command_runner_.release();
4090 }
4091
4092 {
4093 State state;
4094 ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
4095
4096 DepsLog deps_log;
4097 ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
4098 ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
4099 ASSERT_EQ("", err);
4100
4101 Builder builder(&state, config_, NULL, &deps_log, &fs_);
4102 builder.command_runner_.reset(&command_runner_);
4103
4104 Edge* edge = state.edges_.back();
4105
4106 state.GetNode("bar.h", 0)->MarkDirty(); // Mark bar.h as missing.
4107 EXPECT_TRUE(builder.AddTarget("fo o.o", &err));
4108 ASSERT_EQ("", err);
4109
4110 // Expect three new edges: one generating fo o.o, and two more from
4111 // loading the depfile.
4112 ASSERT_EQ(3u, state.edges_.size());
4113 // Expect our edge to now have three inputs: foo.c and two headers.
4114 ASSERT_EQ(3u, edge->inputs_.size());
4115
4116 // Expect the command line we generate to only use the original input.
4117 ASSERT_EQ("cc foo.c", edge->EvaluateCommand());
4118
4119 deps_log.Close();
4120 builder.command_runner_.release();
4121 }
4122}
4123
4124#ifdef _WIN32
4125TEST_F(BuildWithDepsLogTest, DepFileDepsLogCanonicalize) {
4126 string err;
4127 const char* manifest =
4128 "rule cc\n command = cc $in\n depfile = $out.d\n deps = gcc\n"
4129 "build a/b\\c\\d/e/fo$ o.o: cc x\\y/z\\foo.c\n";
4130
4131 fs_.Create("x/y/z/foo.c", "");
4132
4133 {
4134 State state;
4135 ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
4136
4137 // Run the build once, everything should be ok.
4138 DepsLog deps_log;
4139 ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
4140 ASSERT_EQ("", err);
4141
4142 Builder builder(&state, config_, NULL, &deps_log, &fs_);
4143 builder.command_runner_.reset(&command_runner_);
4144 EXPECT_TRUE(builder.AddTarget("a/b/c/d/e/fo o.o", &err));
4145 ASSERT_EQ("", err);
4146 // Note, different slashes from manifest.
4147 fs_.Create("a/b\\c\\d/e/fo o.o.d",
4148 "a\\b\\c\\d\\e\\fo\\ o.o: blah.h bar.h\n");
4149 EXPECT_TRUE(builder.Build(&err));
4150 EXPECT_EQ("", err);
4151
4152 deps_log.Close();
4153 builder.command_runner_.release();
4154 }
4155
4156 {
4157 State state;
4158 ASSERT_NO_FATAL_FAILURE(AssertParse(&state, manifest));
4159
4160 DepsLog deps_log;
4161 ASSERT_TRUE(deps_log.Load("ninja_deps", &state, &err));
4162 ASSERT_TRUE(deps_log.OpenForWrite("ninja_deps", &err));
4163 ASSERT_EQ("", err);
4164
4165 Builder builder(&state, config_, NULL, &deps_log, &fs_);
4166 builder.command_runner_.reset(&command_runner_);
4167
4168 Edge* edge = state.edges_.back();
4169
4170 state.GetNode("bar.h", 0)->MarkDirty(); // Mark bar.h as missing.
4171 EXPECT_TRUE(builder.AddTarget("a/b/c/d/e/fo o.o", &err));
4172 ASSERT_EQ("", err);
4173
4174 // Expect three new edges: one generating fo o.o, and two more from
4175 // loading the depfile.
4176 ASSERT_EQ(3u, state.edges_.size());
4177 // Expect our edge to now have three inputs: foo.c and two headers.
4178 ASSERT_EQ(3u, edge->inputs_.size());
4179
4180 // Expect the command line we generate to only use the original input.
4181 // Note, slashes from manifest, not .d.
4182 ASSERT_EQ("cc x\\y/z\\foo.c", edge->EvaluateCommand());
4183
4184 deps_log.Close();
4185 builder.command_runner_.release();
4186 }
4187}
4188#endif
4189
4190/// Check that a restat rule doesn't clear an edge if the depfile is missing.
4191/// Follows from: https://github.com/ninja-build/ninja/issues/603
4192TEST_F(BuildTest, RestatMissingDepfile) {
4193const char* manifest =
4194"rule true\n"
4195" command = true\n" // Would be "write if out-of-date" in reality.
4196" restat = 1\n"
4197"build header.h: true header.in\n"
4198"build out: cat header.h\n"
4199" depfile = out.d\n";
4200
4201 fs_.Create("header.h", "");
4202 fs_.Tick();
4203 fs_.Create("out", "");
4204 fs_.Create("header.in", "");
4205
4206 // Normally, only 'header.h' would be rebuilt, as
4207 // its rule doesn't touch the output and has 'restat=1' set.
4208 // But we are also missing the depfile for 'out',
4209 // which should force its command to run anyway!
4210 RebuildTarget("out", manifest);
4211 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
4212}
4213
4214/// Check that a restat rule doesn't clear an edge if the deps are missing.
4215/// https://github.com/ninja-build/ninja/issues/603
4216TEST_F(BuildWithDepsLogTest, RestatMissingDepfileDepslog) {
4217 string err;
4218 const char* manifest =
4219"rule true\n"
4220" command = true\n" // Would be "write if out-of-date" in reality.
4221" restat = 1\n"
4222"build header.h: true header.in\n"
4223"build out: cat header.h\n"
4224" deps = gcc\n"
4225" depfile = out.d\n";
4226
4227 // Build once to populate ninja deps logs from out.d
4228 fs_.Create("header.in", "");
4229 fs_.Create("out.d", "out: header.h");
4230 fs_.Create("header.h", "");
4231
4232 RebuildTarget("out", manifest, "build_log", "ninja_deps");
4233 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
4234
4235 // Sanity: this rebuild should be NOOP
4236 RebuildTarget("out", manifest, "build_log", "ninja_deps");
4237 ASSERT_EQ(0u, command_runner_.commands_ran_.size());
4238
4239 // Touch 'header.in', blank dependencies log (create a different one).
4240 // Building header.h triggers 'restat' outputs cleanup.
4241 // Validate that out is rebuilt netherless, as deps are missing.
4242 fs_.Tick();
4243 fs_.Create("header.in", "");
4244
4245 // (switch to a new blank deps_log "ninja_deps2")
4246 RebuildTarget("out", manifest, "build_log", "ninja_deps2");
4247 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
4248
4249 // Sanity: this build should be NOOP
4250 RebuildTarget("out", manifest, "build_log", "ninja_deps2");
4251 ASSERT_EQ(0u, command_runner_.commands_ran_.size());
4252
4253 // Check that invalidating deps by target timestamp also works here
4254 // Repeat the test but touch target instead of blanking the log.
4255 fs_.Tick();
4256 fs_.Create("header.in", "");
4257 fs_.Create("out", "");
4258 RebuildTarget("out", manifest, "build_log", "ninja_deps2");
4259 ASSERT_EQ(2u, command_runner_.commands_ran_.size());
4260
4261 // And this build should be NOOP again
4262 RebuildTarget("out", manifest, "build_log", "ninja_deps2");
4263 ASSERT_EQ(0u, command_runner_.commands_ran_.size());
4264}
4265
4266TEST_F(BuildTest, WrongOutputInDepfileCausesRebuild) {
4267 string err;
4268 const char* manifest =
4269"rule cc\n"
4270" command = cc $in\n"
4271" depfile = $out.d\n"
4272"build foo.o: cc foo.c\n";
4273
4274 fs_.Create("foo.c", "");
4275 fs_.Create("foo.o", "");
4276 fs_.Create("header.h", "");
4277 fs_.Create("foo.o.d", "bar.o.d: header.h\n");
4278
4279 RebuildTarget("foo.o", manifest, "build_log", "ninja_deps");
4280 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
4281}
4282
4283TEST_F(BuildTest, Console) {
4284 ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
4285"rule console\n"
4286" command = console\n"
4287" pool = console\n"
4288"build cons: console in.txt\n"));
4289
4290 fs_.Create("in.txt", "");
4291
4292 string err;
4293 EXPECT_TRUE(builder_.AddTarget("cons", &err));
4294 ASSERT_EQ("", err);
4295 EXPECT_TRUE(builder_.Build(&err));
4296 EXPECT_EQ("", err);
4297 ASSERT_EQ(1u, command_runner_.commands_ran_.size());
4298}
4299
4300*/
4301
4302
4303}