Skip to content

Commit a77f059

Browse files
committed
Turn on Cross-Module Incremental Dependencies!
Cross-Module incremental dependencies are a new experimental mode of the Swift driver and frontend. Through a tight partnership between the two, we enable the driver to have far greater visibility into the dependency structure of a Swift module. Rather than invent a new model, we have chosen to extend the existing incremental compilation model that works for a single module to multiple modules. To do this, we need the frontend to emit Swift dependencies in a form the driver can consume. We could emit these metadata in the form of an extra supplementary output that summarizes the contents of a generated module. However, this approach comes with a number of downsides: - It requires additional integration with the build system - It assumes swiftmodule files will be consumed directly from the build directory; they are not - It incorrectly assumes a swiftmodule has but one interface. Taken in aggregate, a swiftmodule directory has one interface *per triple* Given this, the approach we take here is to encode these dependencies directly into the swiftmodule file itself. When frontends load these souped-up incremental swiftmodule files, they record in their own swiftdeps files that they depend on an incremental swiftmodule. Upon the next build, the driver is then able to read that module file, extract the swiftdeps information from it, and use it to influence the way it schedules jobs. The sum total is that we neatly extend the intra-module case of incremental builds to the inter-module case by treating swiftmodule inputs not as opaque entities, but as "big ol' flat Swift files" that just export an interface like any other Swift file within the module. As a further optimization, and because clients literally cannot observe this aspect of the incremental build, we only serialize the provides (the "defs" side of a "use-def" edge) when emitting swiftdeps metadata into swiftmodule files. rdar://69595010
1 parent d7cd605 commit a77f059

File tree

16 files changed

+192
-7
lines changed

16 files changed

+192
-7
lines changed

include/swift/Option/Options.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,7 @@ def experimental_cxx_stdlib :
573573

574574
def enable_experimental_cross_module_incremental_build :
575575
Flag<["-"], "enable-experimental-cross-module-incremental-build">,
576+
Flags<[FrontendOption]>,
576577
HelpText<"(experimental) Enable cross-module incremental build metadata and "
577578
"driver scheduling">;
578579

lib/Serialization/SerializedModuleLoader.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -973,13 +973,6 @@ SerializedModuleLoaderBase::loadModule(SourceLoc importLoc,
973973
isFramework, isSystemModule)) {
974974
return nullptr;
975975
}
976-
if (dependencyTracker) {
977-
// Don't record cached artifacts as dependencies.
978-
StringRef DepPath = moduleInputBuffer->getBufferIdentifier();
979-
if (!isCached(DepPath)) {
980-
dependencyTracker->addDependency(DepPath, /*isSystem=*/false);
981-
}
982-
}
983976

984977
assert(moduleInputBuffer);
985978

@@ -997,6 +990,18 @@ SerializedModuleLoaderBase::loadModule(SourceLoc importLoc,
997990
} else {
998991
M->setFailedToLoad();
999992
}
993+
994+
if (dependencyTracker && file) {
995+
auto DepPath = file->getFilename();
996+
// Don't record cached artifacts as dependencies.
997+
if (!isCached(DepPath)) {
998+
if (M->hasIncrementalInfo()) {
999+
dependencyTracker->addIncrementalDependency(DepPath);
1000+
} else {
1001+
dependencyTracker->addDependency(DepPath, /*isSystem=*/false);
1002+
}
1003+
}
1004+
}
10001005
return M;
10011006
}
10021007

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"A.swift": {
3+
"object": "./A.o",
4+
"swift-dependencies": "./A.swiftdeps",
5+
"swiftmodule": "./A~partial.swiftmodule",
6+
"swiftdoc": "./A.swiftdoc",
7+
},
8+
"": {
9+
"swift-dependencies": "./A~buildrecord.swiftdeps"
10+
}
11+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import B
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"B.swift": {
3+
"object": "./B.o",
4+
"swift-dependencies": "./B.swiftdeps",
5+
"swiftmodule": "./B~partial.swiftmodule",
6+
"swiftdoc": "./B.swiftdoc",
7+
},
8+
"": {
9+
"swift-dependencies": "./B~buildrecord.swiftdeps"
10+
}
11+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import C
2+
3+
public func fromB() {
4+
return fromC()
5+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"C.swift": {
3+
"object": "./C.o",
4+
"swift-dependencies": "./C.swiftdeps",
5+
"swiftmodule": "./C~partial.swiftmodule",
6+
"swiftdoc": "./C.swiftdoc",
7+
},
8+
"": {
9+
"swift-dependencies": "./C~buildrecord.swiftdeps"
10+
}
11+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#if OLD
2+
public func fromC() {}
3+
#elseif NEW
4+
public func fromC(parameter: Int = 0) {}
5+
#else
6+
#error("test must define one of NEW or OLD macros")
7+
#endif
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"A.swift": {
3+
"object": "./A.o",
4+
"swift-dependencies": "./A.swiftdeps",
5+
"swiftmodule": "./A~partial.swiftmodule",
6+
"swiftdoc": "./A.swiftdoc",
7+
},
8+
"": {
9+
"swift-dependencies": "./A~buildrecord.swiftdeps"
10+
}
11+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import B
2+
import C
3+
4+
public func use() {
5+
fromB()
6+
#if USEC
7+
fromC()
8+
#endif
9+
}

0 commit comments

Comments
 (0)