Unfortunately, OutputFileMap does not normalize input names when it is constructing keys. Instead, keys to the map are formed by appending the entry's value directly onto the working directory with the test host's path separator convention.
On Windows, the tests here were using UNIX-style path separators when passing inputs to the Driver, so the key was
"C:\Path\To\File\A.swift"
But the input path to the driver was
"C:\Path\To\File/A.swift"
To work around this - and to ultimately make the test slightly more portable - just use relative paths to the input files since we've already changed directories to the working directory before we run these driver commands.
We cannot know a-priori how a change to an external dependency will
affect the resulting structure of every file in the module that depends
upon it. Therefore, we must be conservative and ensure that these
dependent files always rebuild. Commit a test to this effect.
Plumb the logic necessary to schedule merge-modules incrementally. This means that if any inputs jobs to merge-modules run, merge-modules is run. But, if they are all skipped, merge-modules will be skipped as well.
This requires some light special-casing of the legacy driver's incremental job handling because it assumes in a few places it can always extract a swiftdeps file. This invariant will be further broken when the precompile step for bridging headers is skipped as well.
rdar://65893400
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