@@ -518,6 +518,10 @@ Builder::Builder(State* state, const BuildConfig& config,
518518 start_time_millis_(start_time_millis), disk_interface_(disk_interface),
519519 scan_(state, build_log, deps_log, disk_interface,
520520 &config_.depfile_parser_options) {
521+ lock_file_path_ = " .ninja_lock" ;
522+ string build_dir = state_->bindings_ .LookupVariable (" builddir" );
523+ if (!build_dir.empty ())
524+ lock_file_path_ = build_dir + " /" + lock_file_path_;
521525}
522526
523527Builder::~Builder () {
@@ -552,6 +556,10 @@ void Builder::Cleanup() {
552556 disk_interface_->RemoveFile (depfile);
553557 }
554558 }
559+
560+ string err;
561+ if (disk_interface_->Stat (lock_file_path_, &err) > 0 )
562+ disk_interface_->RemoveFile (lock_file_path_);
555563}
556564
557565Node* Builder::AddTarget (const string& name, string* err) {
@@ -704,14 +712,25 @@ bool Builder::StartEdge(Edge* edge, string* err) {
704712
705713 status_->BuildEdgeStarted (edge, start_time_millis);
706714
707- // Create directories necessary for outputs.
715+ TimeStamp build_start = -1 ;
716+
717+ // Create directories necessary for outputs and remember the current
718+ // filesystem mtime to record later
708719 // XXX: this will block; do we care?
709720 for (vector<Node*>::iterator o = edge->outputs_ .begin ();
710721 o != edge->outputs_ .end (); ++o) {
711722 if (!disk_interface_->MakeDirs ((*o)->path ()))
712723 return false ;
724+ if (build_start == -1 ) {
725+ disk_interface_->WriteFile (lock_file_path_, " " );
726+ build_start = disk_interface_->Stat (lock_file_path_, err);
727+ if (build_start == -1 )
728+ build_start = 0 ;
729+ }
713730 }
714731
732+ edge->command_start_time_ = build_start;
733+
715734 // Create response file, if needed
716735 // XXX: this may also block; do we care?
717736 string rspfile = edge->GetUnescapedRspfile ();
@@ -770,55 +789,42 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {
770789 }
771790
772791 // Restat the edge outputs
773- TimeStamp output_mtime = 0 ;
774- bool restat = edge->GetBindingBool (" restat" );
792+ TimeStamp record_mtime = 0 ;
775793 if (!config_.dry_run ) {
794+ const bool restat = edge->GetBindingBool (" restat" );
795+ const bool generator = edge->GetBindingBool (" generator" );
776796 bool node_cleaned = false ;
777-
778- for (vector<Node*>::iterator o = edge->outputs_ .begin ();
779- o != edge->outputs_ .end (); ++o) {
780- TimeStamp new_mtime = disk_interface_->Stat ((*o)->path (), err);
781- if (new_mtime == -1 )
782- return false ;
783- if (new_mtime > output_mtime)
784- output_mtime = new_mtime;
785- if ((*o)->mtime () == new_mtime && restat) {
786- // The rule command did not change the output. Propagate the clean
787- // state through the build graph.
788- // Note that this also applies to nonexistent outputs (mtime == 0).
789- if (!plan_.CleanNode (&scan_, *o, err))
797+ record_mtime = edge->command_start_time_ ;
798+
799+ // restat and generator rules must restat the outputs after the build
800+ // has finished. if record_mtime == 0, then there was an error while
801+ // attempting to touch/stat the temp file when the edge started and
802+ // we should fall back to recording the outputs' current mtime in the
803+ // log.
804+ if (record_mtime == 0 || restat || generator) {
805+ for (vector<Node*>::iterator o = edge->outputs_ .begin ();
806+ o != edge->outputs_ .end (); ++o) {
807+ TimeStamp new_mtime = disk_interface_->Stat ((*o)->path (), err);
808+ if (new_mtime == -1 )
790809 return false ;
791- node_cleaned = true ;
810+ if (new_mtime > record_mtime)
811+ record_mtime = new_mtime;
812+ if ((*o)->mtime () == new_mtime && restat) {
813+ // The rule command did not change the output. Propagate the clean
814+ // state through the build graph.
815+ // Note that this also applies to nonexistent outputs (mtime == 0).
816+ if (!plan_.CleanNode (&scan_, *o, err))
817+ return false ;
818+ node_cleaned = true ;
819+ }
792820 }
793821 }
794-
795822 if (node_cleaned) {
796- TimeStamp restat_mtime = 0 ;
797- // If any output was cleaned, find the most recent mtime of any
798- // (existing) non-order-only input or the depfile.
799- for (vector<Node*>::iterator i = edge->inputs_ .begin ();
800- i != edge->inputs_ .end () - edge->order_only_deps_ ; ++i) {
801- TimeStamp input_mtime = disk_interface_->Stat ((*i)->path (), err);
802- if (input_mtime == -1 )
803- return false ;
804- if (input_mtime > restat_mtime)
805- restat_mtime = input_mtime;
806- }
807-
808- string depfile = edge->GetUnescapedDepfile ();
809- if (restat_mtime != 0 && deps_type.empty () && !depfile.empty ()) {
810- TimeStamp depfile_mtime = disk_interface_->Stat (depfile, err);
811- if (depfile_mtime == -1 )
812- return false ;
813- if (depfile_mtime > restat_mtime)
814- restat_mtime = depfile_mtime;
815- }
823+ record_mtime = edge->command_start_time_ ;
816824
817825 // The total number of edges in the plan may have changed as a result
818826 // of a restat.
819827 status_->PlanHasTotalEdges (plan_.command_edge_count ());
820-
821- output_mtime = restat_mtime;
822828 }
823829 }
824830
@@ -832,7 +838,7 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {
832838
833839 if (scan_.build_log ()) {
834840 if (!scan_.build_log ()->RecordCommand (edge, start_time_millis,
835- end_time_millis, output_mtime )) {
841+ end_time_millis, record_mtime )) {
836842 *err = string (" Error writing to build log: " ) + strerror (errno);
837843 return false ;
838844 }
0 commit comments