@@ -75,6 +75,7 @@ extension Driver {
7575 break
7676 }
7777
78+ let jobNeedPathRemap: Bool
7879 // If in ExplicitModuleBuild mode and the dependency graph has been computed, add module
7980 // dependencies.
8081 // May also be used for generation of the dependency graph itself in ExplicitModuleBuild mode.
@@ -83,17 +84,21 @@ extension Driver {
8384 switch kind {
8485 case .generatePCH:
8586 try addExplicitPCHBuildArguments(inputs: &inputs, commandLine: &commandLine)
87+ jobNeedPathRemap = true
8688 case .compile, .emitModule, .interpret, .verifyModuleInterface:
8789 try addExplicitModuleBuildArguments(inputs: &inputs, commandLine: &commandLine)
90+ jobNeedPathRemap = true
8891 case .backend, .mergeModule, .compileModuleFromInterface,
8992 .generatePCM, .dumpPCM, .repl, .printTargetInfo,
9093 .versionRequest, .autolinkExtract, .generateDSYM,
9194 .help, .link, .verifyDebugInfo, .scanDependencies,
9295 .emitSupportedFeatures, .moduleWrap,
9396 .generateAPIBaseline, .generateABIBaseline, .compareAPIBaseline,
9497 .compareABIBaseline:
95- break // Do not support creating from dependency scanner output.
98+ jobNeedPathRemap = false
9699 }
100+ } else {
101+ jobNeedPathRemap = false
97102 }
98103
99104 if let variant = parsedOptions.getLastArgument(.targetVariant)?.asSingle {
@@ -126,24 +131,22 @@ extension Driver {
126131 try commandLine.appendLast(.targetCpu, from: &parsedOptions)
127132
128133 if let sdkPath = frontendTargetInfo.sdkPath?.path {
129- commandLine.appendFlag(.sdk)
130- commandLine.append(.path(VirtualPath.lookup(sdkPath)))
134+ try addPathOption(option: .sdk, path: VirtualPath.lookup(sdkPath), to: &commandLine, remap: jobNeedPathRemap)
131135 }
132136
133137 for args: (Option, Option) in [
134138 (.visualcToolsRoot, .visualcToolsVersion),
135139 (.windowsSdkRoot, .windowsSdkVersion)
136140 ] {
137- let (rootArg, versionArg) = args
138- if let value = parsedOptions.getLastArgument(rootArg)?.asSingle,
139- isFrontendArgSupported(rootArg) {
140- commandLine.appendFlag(rootArg.spelling)
141- commandLine.appendPath(try .init(validating: value))
141+ let (rootOpt, versionOpt) = args
142+ if let rootArg = parsedOptions.last(for: rootOpt),
143+ isFrontendArgSupported(rootOpt) {
144+ try addPathOption(rootArg, to: &commandLine, remap: jobNeedPathRemap)
142145 }
143146
144- if let value = parsedOptions.getLastArgument(versionArg )?.asSingle,
145- isFrontendArgSupported(versionArg ) {
146- commandLine.appendFlags(versionArg .spelling, value)
147+ if let value = parsedOptions.getLastArgument(versionOpt )?.asSingle,
148+ isFrontendArgSupported(versionOpt ) {
149+ commandLine.appendFlags(versionOpt .spelling, value)
147150 }
148151 }
149152
@@ -302,12 +305,14 @@ extension Driver {
302305 commandLine.appendFlag(.Xcc)
303306 commandLine.appendFlag(.workingDirectory)
304307 commandLine.appendFlag(.Xcc)
305- commandLine.appendPath (.absolute(workingDirectory))
308+ try addPathArgument (.absolute(workingDirectory), to: &commandLine, remap: jobNeedPathRemap )
306309 }
307310
308311 // Resource directory.
309- commandLine.appendFlag(.resourceDir)
310- commandLine.appendPath(VirtualPath.lookup(frontendTargetInfo.runtimeResourcePath.path))
312+ try addPathOption(option: .resourceDir,
313+ path: VirtualPath.lookup(frontendTargetInfo.runtimeResourcePath.path),
314+ to: &commandLine,
315+ remap: jobNeedPathRemap)
311316
312317 if self.useStaticResourceDir {
313318 commandLine.appendFlag("-use-static-resource-dir")
@@ -347,6 +352,7 @@ extension Driver {
347352 try commandLine.appendAll(.casPluginOption, from: &parsedOptions)
348353 try commandLine.appendLast(.cacheRemarks, from: &parsedOptions)
349354 }
355+ addCacheReplayMapping(to: &commandLine)
350356 if useClangIncludeTree {
351357 commandLine.appendFlag(.clangIncludeTree)
352358 }
@@ -369,16 +375,16 @@ extension Driver {
369375 // of a lookup failure.
370376 if parsedOptions.contains(.pchOutputDir) &&
371377 !parsedOptions.contains(.driverExplicitModuleBuild) {
372- commandLine.appendPath (VirtualPath.lookup(importedObjCHeader))
378+ try addPathArgument (VirtualPath.lookup(importedObjCHeader), to:&commandLine, remap: jobNeedPathRemap )
373379 try commandLine.appendLast(.pchOutputDir, from: &parsedOptions)
374380 if !compilerMode.isSingleCompilation {
375381 commandLine.appendFlag(.pchDisableValidation)
376382 }
377383 } else {
378- commandLine.appendPath (VirtualPath.lookup(pch))
384+ try addPathArgument (VirtualPath.lookup(pch), to:&commandLine, remap: jobNeedPathRemap )
379385 }
380386 } else {
381- commandLine.appendPath (VirtualPath.lookup(importedObjCHeader))
387+ try addPathArgument (VirtualPath.lookup(importedObjCHeader), to:&commandLine, remap: jobNeedPathRemap )
382388 }
383389 }
384390
@@ -418,16 +424,17 @@ extension Driver {
418424 }
419425 }
420426
421- func addBridgingHeaderPCHCacheKeyArguments(commandLine: inout [Job.ArgTemplate],
422- pchCompileJob: Job?) throws {
427+ mutating func addBridgingHeaderPCHCacheKeyArguments(commandLine: inout [Job.ArgTemplate],
428+ pchCompileJob: Job?) throws {
423429 guard let pchJob = pchCompileJob, enableCaching else { return }
424430
425431 // The pch input file (the bridging header) is added as last inputs to the job.
426432 guard let inputFile = pchJob.inputs.last else { assertionFailure("no input files from pch job"); return }
427433 assert(inputFile.type == .objcHeader, "Expect objc header input type")
434+ let mappedInput = remapPath(inputFile.file).intern()
428435 let bridgingHeaderCacheKey = try interModuleDependencyOracle.computeCacheKeyForOutput(kind: .pch,
429436 commandLine: pchJob.commandLine,
430- input: inputFile.fileHandle )
437+ input: mappedInput )
431438 commandLine.appendFlag("-bridging-header-pch-key")
432439 commandLine.appendFlag(bridgingHeaderCacheKey)
433440 }
@@ -609,7 +616,7 @@ extension Driver {
609616 var entries = [VirtualPath.Handle: [FileType: VirtualPath.Handle]]()
610617 for input in primaryInputs {
611618 if let output = inputOutputMap[input]?.first {
612- addEntry(&entries, input: input, output: output)
619+ try addEntry(&entries, input: input, output: output)
613620 } else {
614621 // Primary inputs are expected to appear in the output file map even
615622 // if they have no corresponding outputs.
@@ -628,7 +635,7 @@ extension Driver {
628635 }
629636
630637 for flaggedPair in flaggedInputOutputPairs {
631- addEntry(&entries, input: flaggedPair.input, output: flaggedPair.output)
638+ try addEntry(&entries, input: flaggedPair.input, output: flaggedPair.output)
632639 }
633640 // To match the legacy driver behavior, make sure we add an entry for the
634641 // file under indexing and the primary output file path.
@@ -662,14 +669,15 @@ extension Driver {
662669 try commandLine.appendLast(.symbolGraphMinimumAccessLevel, from: &parsedOptions)
663670 }
664671
665- func addEntry(_ entries: inout [VirtualPath.Handle: [FileType: VirtualPath.Handle]], input: TypedVirtualPath?, output: TypedVirtualPath) {
672+ mutating func addEntry(_ entries: inout [VirtualPath.Handle: [FileType: VirtualPath.Handle]], input: TypedVirtualPath?, output: TypedVirtualPath) throws {
666673 let entryInput: VirtualPath.Handle
667674 if let input = input?.fileHandle, input != OutputFileMap.singleInputKey {
668675 entryInput = input
669676 } else {
670677 entryInput = inputFiles[0].fileHandle
671678 }
672- entries[entryInput, default: [:]][output.type] = output.fileHandle
679+ let inputEntry = enableCaching ? remapPath(VirtualPath.lookup(entryInput)).intern() : entryInput
680+ entries[inputEntry, default: [:]][output.type] = output.fileHandle
673681 }
674682
675683 /// Adds all dependencies required for an explicit module build
@@ -706,3 +714,84 @@ extension Driver {
706714 return job.moduleName == moduleOutputInfo.name
707715 }
708716}
717+
718+ extension Driver {
719+ private func getAbsolutePathFromVirtualPath(_ path: VirtualPath) -> AbsolutePath? {
720+ guard let cwd = workingDirectory ?? fileSystem.currentWorkingDirectory else {
721+ return nil
722+ }
723+ return path.resolvedRelativePath(base: cwd).absolutePath
724+ }
725+
726+ private mutating func remapPath(absolute path: AbsolutePath) -> AbsolutePath {
727+ guard !prefixMapping.isEmpty else {
728+ return path
729+ }
730+ for (prefix, value) in prefixMapping {
731+ if path.isDescendantOfOrEqual(to: prefix) {
732+ return value.appending(path.relative(to: prefix))
733+ }
734+ }
735+ return path
736+ }
737+
738+ public mutating func remapPath(_ path: VirtualPath) -> VirtualPath {
739+ guard !prefixMapping.isEmpty,
740+ let absPath = getAbsolutePathFromVirtualPath(path) else {
741+ return path
742+ }
743+ let mappedPath = remapPath(absolute: absPath)
744+ return try! VirtualPath(path: mappedPath.pathString)
745+ }
746+
747+ /// Helper function to add path to commandLine. Function will validate the path, and remap the path if needed.
748+ public mutating func addPathArgument(_ path: VirtualPath, to commandLine: inout [Job.ArgTemplate], remap: Bool = false) throws {
749+ guard remap && enableCaching else {
750+ commandLine.appendPath(path)
751+ return
752+ }
753+ let mappedPath = remapPath(path)
754+ commandLine.appendPath(mappedPath)
755+ }
756+
757+ public mutating func addPathOption(_ option: ParsedOption, to commandLine: inout [Job.ArgTemplate], remap: Bool = false) throws {
758+ let path = try VirtualPath(path: option.argument.asSingle)
759+ try addPathOption(option: option.option, path: path, to: &commandLine, remap: remap)
760+ }
761+
762+ public mutating func addPathOption(option: Option, path: VirtualPath, to commandLine: inout [Job.ArgTemplate], remap: Bool = false) throws {
763+ commandLine.appendFlag(option)
764+ let needRemap = remap && option.attributes.contains(.argumentIsPath) &&
765+ !option.attributes.contains(.cacheInvariant)
766+ try addPathArgument(path, to: &commandLine, remap: needRemap)
767+
768+ }
769+
770+ /// Helper function to add last argument with path to command-line.
771+ public mutating func addLastArgumentWithPath(_ options: Option...,
772+ from parsedOptions: inout ParsedOptions,
773+ to commandLine: inout [Job.ArgTemplate]) throws {
774+ guard let parsedOption = parsedOptions.last(for: options) else {
775+ return
776+ }
777+ try addPathOption(parsedOption, to: &commandLine)
778+ }
779+
780+ /// Helper function to add all arguments with path to command-line.
781+ public mutating func addAllArgumentsWithPath(_ options: Option...,
782+ from parsedOptions: inout ParsedOptions,
783+ to commandLine: inout [Job.ArgTemplate]) throws {
784+ for matching in parsedOptions.arguments(for: options) {
785+ try addPathOption(matching, to: &commandLine)
786+ }
787+ }
788+
789+ public mutating func addCacheReplayMapping(to commandLine: inout [Job.ArgTemplate]) {
790+ if enableCaching && isFrontendArgSupported(.scannerPrefixMap) {
791+ for (key, value) in prefixMapping {
792+ commandLine.appendFlag("-cache-replay-prefix-map")
793+ commandLine.appendFlag(value.pathString + "=" + key.pathString)
794+ }
795+ }
796+ }
797+ }
0 commit comments