34
34
#include " depfile_parser.h"
35
35
#include " deps_log.h"
36
36
#include " disk_interface.h"
37
+ #include " dynout_parser.h"
37
38
#include " explanations.h"
38
39
#include " graph.h"
39
40
#include " metrics.h"
@@ -698,6 +699,7 @@ void Builder::Cleanup() {
698
699
for (vector<Edge*>::iterator e = active_edges.begin ();
699
700
e != active_edges.end (); ++e) {
700
701
string depfile = (*e)->GetUnescapedDepfile ();
702
+ string dynout = (*e)->GetUnescapedDynout ();
701
703
for (vector<Node*>::iterator o = (*e)->outputs_ .begin ();
702
704
o != (*e)->outputs_ .end (); ++o) {
703
705
// Only delete this output if it was actually modified. This is
@@ -716,6 +718,8 @@ void Builder::Cleanup() {
716
718
}
717
719
if (!depfile.empty ())
718
720
disk_interface_->RemoveFile (depfile);
721
+ if (!dynout.empty ())
722
+ disk_interface_->RemoveFile (dynout);
719
723
}
720
724
}
721
725
@@ -949,6 +953,18 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {
949
953
}
950
954
}
951
955
956
+ int outputs_count = 0 ;
957
+ string extract_err;
958
+ std::string dynout_file = edge->GetUnescapedDynout ();
959
+ if (!ExtractDynouts (edge, dynout_file, &deps_nodes, &outputs_count,
960
+ &extract_err) &&
961
+ result->success ()) {
962
+ if (!result->output .empty ())
963
+ result->output .append (" \n " );
964
+ result->output .append (extract_err);
965
+ result->status = ExitFailure;
966
+ }
967
+
952
968
int64_t start_time_millis, end_time_millis;
953
969
RunningEdgeMap::iterator it = running_edges_.find (edge);
954
970
start_time_millis = it->second ;
@@ -1008,21 +1024,23 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) {
1008
1024
disk_interface_->RemoveFile (rspfile);
1009
1025
1010
1026
if (scan_.build_log ()) {
1011
- if (!scan_.build_log ()->RecordCommand (edge, start_time_millis,
1012
- end_time_millis, record_mtime)) {
1027
+ std::vector<Node*> dynouts (deps_nodes.end () - outputs_count,
1028
+ deps_nodes.end ());
1029
+ if (!scan_.build_log ()->RecordCommand (
1030
+ edge, start_time_millis, end_time_millis, record_mtime, dynouts)) {
1013
1031
*err = string (" Error writing to build log: " ) + strerror (errno);
1014
1032
return false ;
1015
1033
}
1016
1034
}
1017
1035
1018
- if (!deps_type.empty () && !config_.dry_run ) {
1036
+ if (( !deps_type.empty () || !dynout_file. empty () ) && !config_.dry_run ) {
1019
1037
assert (!edge->outputs_ .empty () && " should have been rejected by parser" );
1020
1038
for (std::vector<Node*>::const_iterator o = edge->outputs_ .begin ();
1021
1039
o != edge->outputs_ .end (); ++o) {
1022
1040
TimeStamp deps_mtime = disk_interface_->Stat ((*o)->path (), err);
1023
1041
if (deps_mtime == -1 )
1024
1042
return false ;
1025
- if (!scan_.deps_log ()->RecordDeps (*o, deps_mtime, deps_nodes, 0 )) {
1043
+ if (!scan_.deps_log ()->RecordDeps (*o, deps_mtime, deps_nodes, outputs_count )) {
1026
1044
*err = std::string (" Error writing to deps log: " ) + strerror (errno);
1027
1045
return false ;
1028
1046
}
@@ -1109,3 +1127,58 @@ bool Builder::LoadDyndeps(Node* node, string* err) {
1109
1127
1110
1128
return true ;
1111
1129
}
1130
+
1131
+ bool Builder::ExtractDynouts (Edge* edge, const std::string& dynout_file,
1132
+ std::vector<Node*>* nodes, int * outputs_count,
1133
+ std::string* err) {
1134
+ if (dynout_file.empty ()) {
1135
+ return true ;
1136
+ }
1137
+
1138
+ // Read depfile content. Treat a missing depfile as empty.
1139
+ std::string content;
1140
+ switch (disk_interface_->ReadFile (dynout_file, &content, err)) {
1141
+ case DiskInterface::Okay:
1142
+ break ;
1143
+ case DiskInterface::NotFound:
1144
+ if (err != NULL ) {
1145
+ err->clear ();
1146
+ }
1147
+ break ;
1148
+ case DiskInterface::OtherError:
1149
+ if (err != NULL ) {
1150
+ *err = " loading '" + dynout_file + " ': " + *err;
1151
+ }
1152
+ return false ;
1153
+ }
1154
+
1155
+ std::vector<StringPiece> output_paths;
1156
+ std::string parse_err;
1157
+ if (!DynoutParser::Parse (content, output_paths, &parse_err)) {
1158
+ if (err != NULL ) {
1159
+ *err = parse_err;
1160
+ }
1161
+ return false ;
1162
+ }
1163
+
1164
+ int start_size = nodes->size ();
1165
+
1166
+ for (const StringPiece &p : output_paths) {
1167
+ uint64_t slash_bits;
1168
+ std::string canonical = p.AsString ();
1169
+ CanonicalizePath (&canonical, &slash_bits);
1170
+ Node* new_node = state_->GetNode (canonical, slash_bits);
1171
+ nodes->push_back (new_node);
1172
+ }
1173
+ *outputs_count = (int ) nodes->size () - start_size;
1174
+
1175
+ if (!g_keep_dynout) {
1176
+ if (disk_interface_->RemoveFile (dynout_file) < 0 ) {
1177
+ if (err != NULL ) {
1178
+ *err = std::string (" deleting dynout: " ) + strerror (errno) + std::string (" \n " );
1179
+ }
1180
+ return false ;
1181
+ }
1182
+ }
1183
+ return true ;
1184
+ }
0 commit comments