15
15
#include " swift/AST/DiagnosticEngine.h"
16
16
#include " swift/AST/DiagnosticsDriver.h"
17
17
#include " swift/AST/FineGrainedDependencies.h"
18
+ #include " swift/AST/FineGrainedDependencyFormat.h"
18
19
#include " swift/Basic/OutputFileMap.h"
19
20
#include " swift/Basic/Program.h"
20
21
#include " swift/Basic/STLExtras.h"
@@ -1185,6 +1186,30 @@ namespace driver {
1185
1186
return ExternallyDependentJobs;
1186
1187
}
1187
1188
1189
+ using ChangeSet = fine_grained_dependencies::ModuleDepGraph::Changes::value_type;
1190
+ static void
1191
+ pruneChangeSetFromExternalDependency (ChangeSet &changes) {
1192
+ // The changeset includes detritus from the graph that gets consed up
1193
+ // in \c writePriorDependencyGraph. We need to ignore the fake
1194
+ // source file provides nodes and the fake incremental external
1195
+ // dependencies linked to them.
1196
+ swift::erase_if (
1197
+ changes, [&](fine_grained_dependencies::ModuleDepGraphNode *node) {
1198
+ if (node->getKey ().getKind () ==
1199
+ fine_grained_dependencies::NodeKind::sourceFileProvide ||
1200
+ node->getKey ().getKind () ==
1201
+ fine_grained_dependencies::NodeKind::
1202
+ incrementalExternalDepend) {
1203
+ return true ;
1204
+ }
1205
+ if (node->getKey ().getAspect () ==
1206
+ fine_grained_dependencies::DeclAspect::implementation) {
1207
+ return true ;
1208
+ }
1209
+ return !node->getIsProvides ();
1210
+ });
1211
+ }
1212
+
1188
1213
SmallVector<const Job *, 16 >
1189
1214
collectIncrementalExternallyDependentJobsFromDependencyGraph (
1190
1215
const bool forRanges) {
@@ -1196,6 +1221,17 @@ namespace driver {
1196
1221
}
1197
1222
};
1198
1223
1224
+ // Load our priors, which are always adjacent to the build record. We
1225
+ // don't care if this load succeeds or not. If it fails, and we succeed at
1226
+ // integrating one of the external files below, the changeset will be the
1227
+ // entire module!
1228
+ const auto *externalPriorJob = Comp.addExternalJob (
1229
+ std::make_unique<Job>(Comp.getDerivedOutputFileMap (),
1230
+ Comp.getExternalSwiftDepsFilePath ()));
1231
+ getFineGrainedDepGraph (forRanges).loadFromPath (
1232
+ externalPriorJob, Comp.getExternalSwiftDepsFilePath (),
1233
+ Comp.getDiags ());
1234
+
1199
1235
for (auto external : getFineGrainedDepGraph (forRanges)
1200
1236
.getIncrementalExternalDependencies ()) {
1201
1237
llvm::sys::fs::file_status depStatus;
@@ -1231,20 +1267,23 @@ namespace driver {
1231
1267
// code's internal invariants.
1232
1268
const auto *externalJob = Comp.addExternalJob (
1233
1269
std::make_unique<Job>(Comp.getDerivedOutputFileMap (), external));
1234
- auto subChanges =
1270
+ auto maybeChanges =
1235
1271
getFineGrainedDepGraph (forRanges).loadFromSwiftModuleBuffer (
1236
1272
externalJob, *buffer.get (), Comp.getDiags ());
1237
1273
1238
1274
// If the incremental dependency graph failed to load, fall back to
1239
1275
// treating this as plain external job.
1240
- if (!subChanges .hasValue ()) {
1276
+ if (!maybeChanges .hasValue ()) {
1241
1277
fallbackToExternalBehavior (external);
1242
1278
continue ;
1243
1279
}
1244
1280
1245
- for (auto *CMD :
1246
- getFineGrainedDepGraph (forRanges)
1247
- .findJobsToRecompileWhenNodesChange (subChanges.getValue ())) {
1281
+ // Prune away the detritus from the build record.
1282
+ auto &changes = maybeChanges.getValue ();
1283
+ pruneChangeSetFromExternalDependency (changes);
1284
+
1285
+ for (auto *CMD : getFineGrainedDepGraph (forRanges)
1286
+ .findJobsToRecompileWhenNodesChange (changes)) {
1248
1287
if (CMD == externalJob) {
1249
1288
continue ;
1250
1289
}
@@ -1861,6 +1900,76 @@ static void writeCompilationRecord(StringRef path, StringRef argsHash,
1861
1900
}
1862
1901
}
1863
1902
1903
+ using SourceFileDepGraph = swift::fine_grained_dependencies::SourceFileDepGraph;
1904
+
1905
+ // / Render out the unified module dependency graph to the given \p path, which
1906
+ // / is expected to be a path relative to the build record.
1907
+ static void withPriorDependencyGraph (StringRef path,
1908
+ const Compilation::Result &result,
1909
+ llvm::function_ref<void (SourceFileDepGraph &&)> cont) {
1910
+ // Building a source file dependency graph from the module dependency graph
1911
+ // is a strange task on its face because a source file dependency graph is
1912
+ // usually built for exactly one file. However, the driver is going to use
1913
+ // some encoding tricks to get the dependencies for each incremental external
1914
+ // dependency into one big file. Note that these tricks
1915
+ // are undone in \c pruneChangeSetFromExternalDependency, so if you modify
1916
+ // this you need to go fix that algorithm up as well. This is a diagrammatic
1917
+ // view of the structure of the dependencies this function builds:
1918
+ //
1919
+ // SourceFile => interface <BUILD_RECORD>.external
1920
+ // | - Incremetal External Dependency => interface <MODULE_1>.swiftmodule
1921
+ // | | - <dependency> ...
1922
+ // | | - <dependency> ...
1923
+ // | | - <dependency> ...
1924
+ // | - Incremetal External Dependency => interface <MODULE_2>.swiftmodule
1925
+ // | | - <dependency> ...
1926
+ // | | - <dependency> ...
1927
+ // | - Incremetal External Dependency => interface <MODULE_3>.swiftmodule
1928
+ // | - ...
1929
+ //
1930
+ // Where each <dependency> node has an arc back to its parent swiftmodule.
1931
+ // That swiftmodule, in turn, takes the form of as an incremental external
1932
+ // dependency. This formulation allows us to easily discern the original
1933
+ // swiftmodule that a <dependency> came from just by examining that arc. This
1934
+ // is used in integrate to "move" the <dependency> from the build record to
1935
+ // the swiftmodule by swapping the key it uses.
1936
+ using namespace swift ::fine_grained_dependencies;
1937
+ SourceFileDepGraph g;
1938
+ const auto &resultModuleGraph = result.depGraph ;
1939
+ // Create the key for the entire external build record.
1940
+ auto fileKey =
1941
+ DependencyKey::createKeyForWholeSourceFile (DeclAspect::interface, path);
1942
+ auto fileNodePair = g.findExistingNodePairOrCreateAndAddIfNew (fileKey, None);
1943
+ for (StringRef incrExternalDep :
1944
+ resultModuleGraph.getIncrementalExternalDependencies ()) {
1945
+ // Now make a node for each incremental external dependency.
1946
+ auto interfaceKey =
1947
+ DependencyKey (NodeKind::incrementalExternalDepend,
1948
+ DeclAspect::interface, " " , incrExternalDep.str ());
1949
+ auto ifaceNode = g.findExistingNodeOrCreateIfNew (interfaceKey, None,
1950
+ false /* = !isProvides */ );
1951
+ resultModuleGraph.forEachNodeInJob (incrExternalDep, [&](const auto *node) {
1952
+ // Reject
1953
+ // 1) Implementation nodes: We don't care about the interface nodes
1954
+ // for cross-module dependencies because the client cannot observe it
1955
+ // by definition.
1956
+ // 2) Source file nodes: we're about to define our own.
1957
+ if (!node->getKey ().isInterface () ||
1958
+ node->getKey ().getKind () == NodeKind::sourceFileProvide) {
1959
+ return ;
1960
+ }
1961
+ assert (node->getIsProvides () &&
1962
+ " Found a node in module depdendencies that is not a provides!" );
1963
+ auto *newNode = new SourceFileDepGraphNode (
1964
+ node->getKey (), node->getFingerprint (), /* isProvides*/ true );
1965
+ g.addNode (newNode);
1966
+ g.addArc (ifaceNode, newNode);
1967
+ });
1968
+ g.addArc (fileNodePair.getInterface (), ifaceNode);
1969
+ }
1970
+ return cont (std::move (g));
1971
+ }
1972
+
1864
1973
static void writeInputJobsToFilelist (llvm::raw_fd_ostream &out, const Job *job,
1865
1974
const file_types::ID infoType) {
1866
1975
// FIXME: Duplicated from ToolChains.cpp.
@@ -1960,6 +2069,15 @@ Compilation::performJobsImpl(std::unique_ptr<TaskQueue> &&TQ) {
1960
2069
auto result = std::move (State).takeResult ();
1961
2070
writeCompilationRecord (CompilationRecordPath, ArgsHash, BuildStartTime,
1962
2071
InputInfo);
2072
+ if (EnableCrossModuleIncrementalBuild) {
2073
+ // Write out our priors adjacent to the build record so we can pick
2074
+ // the up in a subsequent build.
2075
+ withPriorDependencyGraph (getExternalSwiftDepsFilePath (), result,
2076
+ [&](SourceFileDepGraph &&g) {
2077
+ writeFineGrainedDependencyGraphToPath (
2078
+ Diags, getExternalSwiftDepsFilePath (), g);
2079
+ });
2080
+ }
1963
2081
return result;
1964
2082
} else {
1965
2083
return std::move (State).takeResult ();
0 commit comments