diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index 7768279e4..87645100b 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -259,6 +259,9 @@ public struct Driver { /// The information about the module to produce. @_spi(Testing) public let moduleOutputInfo: ModuleOutputInfo + /// Information about the target variant module to produce if applicable + @_spi(Testing) public let variantModuleOutputInfo: ModuleOutputInfo? + /// Name of the package containing a target module or file. @_spi(Testing) public let packageName: String? @@ -376,17 +379,213 @@ public struct Driver { /// Path to the TBD file (text-based dylib). let tbdPath: VirtualPath.Handle? - /// Path to the module documentation file. - let moduleDocOutputPath: VirtualPath.Handle? + /// Target-specific supplemental output file paths + struct SupplementalModuleTargetOutputPaths { + /// Path to the module documentation file. + let moduleDocOutputPath: VirtualPath.Handle? + + /// Path to the Swift interface file. + let swiftInterfacePath: VirtualPath.Handle? + + /// Path to the Swift private interface file. + let swiftPrivateInterfacePath: VirtualPath.Handle? + + /// Path to the Swift package interface file. + let swiftPackageInterfacePath: VirtualPath.Handle? + + /// Path to the Swift module source information file. + let moduleSourceInfoPath: VirtualPath.Handle? + + /// Path to the emitted API descriptor file. + let apiDescriptorFilePath: VirtualPath.Handle? + + /// Path to the emitted ABI descriptor file. + let abiDescriptorFilePath: TypedVirtualPath? + } + + private static func computeModuleOutputPaths( + _ parsedOptions: inout ParsedOptions, + moduleName: String, + packageName: String?, + moduleOutputInfo: ModuleOutputInfo, + compilerOutputType: FileType?, + compilerMode: CompilerMode, + emitModuleSeparately: Bool, + outputFileMap: OutputFileMap?, + projectDirectory: VirtualPath.Handle?, + apiDescriptorDirectory: VirtualPath?, + supportedFrontendFeatures: Set, + target: FrontendTargetInfo.Target, + isVariant: Bool) throws -> SupplementalModuleTargetOutputPaths { + struct SupplementalPathOptions { + let moduleDocPath: Option + let sourceInfoPath: Option + let apiDescriptorPath: Option + let abiDescriptorPath: Option + let moduleInterfacePath: Option + let privateInterfacePath: Option + let packageInterfacePath: Option + + static let targetPathOptions = SupplementalPathOptions( + moduleDocPath: .emitModuleDocPath, + sourceInfoPath: .emitModuleSourceInfoPath, + apiDescriptorPath: .emitApiDescriptorPath, + abiDescriptorPath: .emitAbiDescriptorPath, + moduleInterfacePath: .emitModuleInterfacePath, + privateInterfacePath: .emitPrivateModuleInterfacePath, + packageInterfacePath: .emitPackageModuleInterfacePath) + + static let variantTargetPathOptions = SupplementalPathOptions( + moduleDocPath: .emitVariantModuleDocPath, + sourceInfoPath: .emitVariantModuleSourceInfoPath, + apiDescriptorPath: .emitVariantApiDescriptorPath, + abiDescriptorPath: .emitVariantAbiDescriptorPath, + moduleInterfacePath: .emitVariantModuleInterfacePath, + privateInterfacePath: .emitVariantPrivateModuleInterfacePath, + packageInterfacePath: .emitVariantPackageModuleInterfacePath) + } + + let pathOptions: SupplementalPathOptions = isVariant ? .variantTargetPathOptions : .targetPathOptions + + let moduleDocOutputPath = try Self.computeModuleDocOutputPath( + &parsedOptions, + moduleOutputPath: moduleOutputInfo.output?.outputPath, + outputOption: pathOptions.moduleDocPath, + compilerOutputType: compilerOutputType, + compilerMode: compilerMode, + outputFileMap: outputFileMap, + moduleName: moduleOutputInfo.name) + + let moduleSourceInfoPath = try Self.computeModuleSourceInfoOutputPath( + &parsedOptions, + moduleOutputPath: moduleOutputInfo.output?.outputPath, + outputOption: pathOptions.sourceInfoPath, + compilerOutputType: compilerOutputType, + compilerMode: compilerMode, + outputFileMap: outputFileMap, + moduleName: moduleOutputInfo.name, + projectDirectory: projectDirectory) + + // --------------------- + // ABI Descriptor Path + func computeABIDescriptorFilePath(target: FrontendTargetInfo.Target, + features: Set) -> TypedVirtualPath? { + guard features.contains(KnownCompilerFeature.emit_abi_descriptor.rawValue) else { + return nil + } + // Emit the descriptor only on platforms where Library Evolution is + // supported + guard target.triple.isDarwin || parsedOptions.hasArgument(.enableLibraryEvolution) else { + return nil + } + guard let moduleOutput = moduleOutputInfo.output else { + return nil + } + + guard let path = try? VirtualPath.lookup(moduleOutput.outputPath) + .replacingExtension(with: .jsonABIBaseline) else { + return nil + } + return TypedVirtualPath(file: path.intern(), type: .jsonABIBaseline) + } + let abiDescriptorFilePath = computeABIDescriptorFilePath(target: target, + features: supportedFrontendFeatures) + + // --------------------- + // API Descriptor Path + let apiDescriptorFilePath: VirtualPath.Handle? + if let apiDescriptorDirectory = apiDescriptorDirectory { + apiDescriptorFilePath = apiDescriptorDirectory + .appending(component: "\(moduleOutputInfo.name).\(target.moduleTriple.triple).swift.sdkdb") + .intern() + } else { + apiDescriptorFilePath = try Self.computeSupplementaryOutputPath( + &parsedOptions, type: .jsonAPIDescriptor, isOutputOptions: [], + outputPath: pathOptions.apiDescriptorPath, + compilerOutputType: compilerOutputType, + compilerMode: compilerMode, + emitModuleSeparately: emitModuleSeparately, + outputFileMap: outputFileMap, + moduleName: moduleOutputInfo.name) + } + + // --------------------- + // Swift interface paths + let swiftInterfacePath = try Self.computeSupplementaryOutputPath( + &parsedOptions, type: .swiftInterface, isOutputOptions: [.emitModuleInterface], + outputPath: pathOptions.moduleInterfacePath, + compilerOutputType: compilerOutputType, + compilerMode: compilerMode, + emitModuleSeparately: emitModuleSeparately, + outputFileMap: outputFileMap, + moduleName: moduleOutputInfo.name) - /// Path to the Swift interface file. - let swiftInterfacePath: VirtualPath.Handle? + let givenPrivateInterfacePath = try Self.computeSupplementaryOutputPath( + &parsedOptions, type: .privateSwiftInterface, isOutputOptions: [], + outputPath: pathOptions.privateInterfacePath, + compilerOutputType: compilerOutputType, + compilerMode: compilerMode, + emitModuleSeparately: emitModuleSeparately, + outputFileMap: outputFileMap, + moduleName: moduleOutputInfo.name) + let givenPackageInterfacePath = try Self.computeSupplementaryOutputPath( + &parsedOptions, type: .packageSwiftInterface, isOutputOptions: [], + outputPath: pathOptions.packageInterfacePath, + compilerOutputType: compilerOutputType, + compilerMode: compilerMode, + emitModuleSeparately: emitModuleSeparately, + outputFileMap: outputFileMap, + moduleName: moduleOutputInfo.name) + + // Always emit the private swift interface if a public interface is emitted. + // With the introduction of features like @_spi_available, we may print + // public and private interfaces differently even from the same codebase. + // For this reason, we should always print private interfaces so that we + // don’t mix the public interfaces with private Clang modules. + let swiftPrivateInterfacePath: VirtualPath.Handle? + if let privateInterfacePath = givenPrivateInterfacePath { + swiftPrivateInterfacePath = privateInterfacePath + } else if let swiftInterfacePath = swiftInterfacePath { + swiftPrivateInterfacePath = try VirtualPath.lookup(swiftInterfacePath) + .replacingExtension(with: .privateSwiftInterface).intern() + } else { + swiftPrivateInterfacePath = nil + } + + let swiftPackageInterfacePath: VirtualPath.Handle? + if let packageName = packageName, + !packageName.isEmpty { + // Generate a package interface if built with -package-name required for + // decls with the `package` access level. The `.package.swiftinterface` + // contains package decls as well as SPI and public decls (superset of a + // private interface). + if let givenPackageInterfacePath = givenPackageInterfacePath { + swiftPackageInterfacePath = givenPackageInterfacePath + } else if let swiftInterfacePath = swiftInterfacePath { + swiftPackageInterfacePath = try VirtualPath.lookup(swiftInterfacePath) + .replacingExtension(with: .packageSwiftInterface).intern() + } else { + swiftPackageInterfacePath = nil + } + } else { + swiftPackageInterfacePath = nil + } + + return SupplementalModuleTargetOutputPaths( + moduleDocOutputPath: moduleDocOutputPath, + swiftInterfacePath: swiftInterfacePath, + swiftPrivateInterfacePath: swiftPrivateInterfacePath, + swiftPackageInterfacePath: swiftPackageInterfacePath, + moduleSourceInfoPath: moduleSourceInfoPath, + apiDescriptorFilePath: apiDescriptorFilePath, + abiDescriptorFilePath: abiDescriptorFilePath) + } - /// Path to the Swift private interface file. - let swiftPrivateInterfacePath: VirtualPath.Handle? + /// Structure storing paths to supplemental outputs for the target module + let moduleOutputPaths: SupplementalModuleTargetOutputPaths - /// Path to the Swift package interface file. - let swiftPackageInterfacePath: VirtualPath.Handle? + /// Structure storing paths to supplemental outputs for the target variant + let variantModuleOutputPaths: SupplementalModuleTargetOutputPaths? /// File type for the optimization record. let optimizationRecordFileType: FileType? @@ -394,14 +593,9 @@ public struct Driver { /// Path to the optimization record. let optimizationRecordPath: VirtualPath.Handle? - /// Path to the Swift module source information file. - let moduleSourceInfoPath: VirtualPath.Handle? - /// Path to the module's digester baseline file. let digesterBaselinePath: VirtualPath.Handle? - /// Path to the emitted API descriptor file. - let apiDescriptorFilePath: VirtualPath.Handle? /// The mode the API digester should run in. let digesterMode: DigesterMode @@ -461,24 +655,6 @@ public struct Driver { .appending(component: "Frameworks") } () - lazy var abiDescriptorPath: TypedVirtualPath? = { - guard isFeatureSupported(.emit_abi_descriptor) else { - return nil - } - // Emit the descriptor only on platforms where Library Evolution is supported, - // or opted-into explicitly. - guard targetTriple.isDarwin || parsedOptions.hasArgument(.enableLibraryEvolution) else { - return nil - } - guard let moduleOutput = moduleOutputInfo.output else { - return nil - } - guard let path = try? VirtualPath.lookup(moduleOutput.outputPath).replacingExtension(with: .jsonABIBaseline) else { - return nil - } - return TypedVirtualPath(file: path.intern(), type: .jsonABIBaseline) - }() - public static func isOptionFound(_ opt: String, allOpts: Set) -> Bool { var current = opt while(true) { @@ -843,10 +1019,24 @@ public struct Driver { // Determine the module we're building and whether/how the module file itself will be emitted. self.moduleOutputInfo = try Self.computeModuleInfo( - &parsedOptions, compilerOutputType: compilerOutputType, compilerMode: compilerMode, linkerOutputType: linkerOutputType, - debugInfoLevel: debugInfo.level, diagnosticsEngine: diagnosticEngine, + &parsedOptions, + modulePath: parsedOptions.getLastArgument(.emitModulePath)?.asSingle, + compilerOutputType: compilerOutputType, + compilerMode: compilerMode, + linkerOutputType: linkerOutputType, + debugInfoLevel: debugInfo.level, + diagnosticsEngine: diagnosticEngine, workingDirectory: self.workingDirectory) + self.variantModuleOutputInfo = try Self.computeVariantModuleInfo( + &parsedOptions, + compilerOutputType: compilerOutputType, + compilerMode: compilerMode, + linkerOutputType: linkerOutputType, + debugInfoLevel: debugInfo.level, + diagnosticsEngine: diagnosticsEngine, + workingDirectory: workingDirectory) + // Should we schedule a separate emit-module job? self.emitModuleSeparately = Self.computeEmitModuleSeparately(parsedOptions: &parsedOptions, compilerMode: compilerMode, @@ -1023,24 +1213,53 @@ public struct Driver { emitModuleSeparately: emitModuleSeparately, outputFileMap: self.outputFileMap, moduleName: moduleOutputInfo.name) - self.moduleDocOutputPath = try Self.computeModuleDocOutputPath( - &parsedOptions, moduleOutputPath: self.moduleOutputInfo.output?.outputPath, - compilerOutputType: compilerOutputType, - compilerMode: compilerMode, - outputFileMap: self.outputFileMap, - moduleName: moduleOutputInfo.name) let projectDirectory = Self.computeProjectDirectoryPath( - moduleOutputPath: self.moduleOutputInfo.output?.outputPath, + moduleOutputPath: moduleOutputInfo.output?.outputPath, fileSystem: self.fileSystem) - self.moduleSourceInfoPath = try Self.computeModuleSourceInfoOutputPath( + + var apiDescriptorDirectory: VirtualPath? = nil + if let apiDescriptorDirectoryEnvVar = env["TAPI_SDKDB_OUTPUT_PATH"] { + apiDescriptorDirectory = try VirtualPath(path: apiDescriptorDirectoryEnvVar) + } else if let ldTraceFileEnvVar = env["LD_TRACE_FILE"] { + apiDescriptorDirectory = try VirtualPath(path: ldTraceFileEnvVar).parentDirectory.appending(component: "SDKDB") + } + + self.moduleOutputPaths = try Self.computeModuleOutputPaths( + &parsedOptions, + moduleName: moduleOutputInfo.name, + packageName: self.packageName, + moduleOutputInfo: self.moduleOutputInfo, + compilerOutputType: compilerOutputType, + compilerMode: compilerMode, + emitModuleSeparately: emitModuleSeparately, + outputFileMap: self.outputFileMap, + projectDirectory: projectDirectory, + apiDescriptorDirectory: apiDescriptorDirectory, + supportedFrontendFeatures: self.supportedFrontendFeatures, + target: frontendTargetInfo.target, + isVariant: false) + + if let variantModuleOutputInfo = self.variantModuleOutputInfo, + let targetVariant = self.frontendTargetInfo.targetVariant { + self.variantModuleOutputPaths = try Self.computeModuleOutputPaths( &parsedOptions, - moduleOutputPath: self.moduleOutputInfo.output?.outputPath, + moduleName: variantModuleOutputInfo.name, + packageName: self.packageName, + moduleOutputInfo: variantModuleOutputInfo, compilerOutputType: compilerOutputType, compilerMode: compilerMode, + emitModuleSeparately: true, // variant module is always independent outputFileMap: self.outputFileMap, - moduleName: moduleOutputInfo.name, - projectDirectory: projectDirectory) + projectDirectory: projectDirectory, + apiDescriptorDirectory: apiDescriptorDirectory, + supportedFrontendFeatures: self.supportedFrontendFeatures, + target: targetVariant, + isVariant: true) + } else { + self.variantModuleOutputPaths = nil + } + self.digesterBaselinePath = try Self.computeDigesterBaselineOutputPath( &parsedOptions, moduleOutputPath: self.moduleOutputInfo.output?.outputPath, @@ -1050,59 +1269,6 @@ public struct Driver { outputFileMap: self.outputFileMap, moduleName: moduleOutputInfo.name, projectDirectory: projectDirectory) - self.swiftInterfacePath = try Self.computeSupplementaryOutputPath( - &parsedOptions, type: .swiftInterface, isOutputOptions: [.emitModuleInterface], - outputPath: .emitModuleInterfacePath, - compilerOutputType: compilerOutputType, - compilerMode: compilerMode, - emitModuleSeparately: emitModuleSeparately, - outputFileMap: self.outputFileMap, - moduleName: moduleOutputInfo.name) - let givenPrivateInterfacePath = try Self.computeSupplementaryOutputPath( - &parsedOptions, type: .privateSwiftInterface, isOutputOptions: [], - outputPath: .emitPrivateModuleInterfacePath, - compilerOutputType: compilerOutputType, - compilerMode: compilerMode, - emitModuleSeparately: emitModuleSeparately, - outputFileMap: self.outputFileMap, - moduleName: moduleOutputInfo.name) - let givenPackageInterfacePath = try Self.computeSupplementaryOutputPath( - &parsedOptions, type: .packageSwiftInterface, isOutputOptions: [], - outputPath: .emitPackageModuleInterfacePath, - compilerOutputType: compilerOutputType, - compilerMode: compilerMode, - emitModuleSeparately: emitModuleSeparately, - outputFileMap: self.outputFileMap, - moduleName: moduleOutputInfo.name) - - // Always emitting private swift interfaces if public interfaces are emitted.' - // With the introduction of features like @_spi_available, we may print public - // and private interfaces differently even from the same codebase. For this reason, - // we should always print private interfaces so that we don’t mix the public interfaces - // with private Clang modules. - if let swiftInterfacePath = self.swiftInterfacePath, - givenPrivateInterfacePath == nil { - self.swiftPrivateInterfacePath = try VirtualPath.lookup(swiftInterfacePath) - .replacingExtension(with: .privateSwiftInterface).intern() - } else { - self.swiftPrivateInterfacePath = givenPrivateInterfacePath - } - - if let packageNameInput = parsedOptions.getLastArgument(Option.packageName), - !packageNameInput.asSingle.isEmpty { - // Generate a package interface if built with `-package-name` required for decls - // with the `package` access level. The .package.swiftinterface contains package - // decls as well as SPI and public decls (superset of a private interface). - if let publicInterfacePath = self.swiftInterfacePath, - givenPackageInterfacePath == nil { - self.swiftPackageInterfacePath = try VirtualPath.lookup(publicInterfacePath) - .replacingExtension(with: .packageSwiftInterface).intern() - } else { - self.swiftPackageInterfacePath = givenPackageInterfacePath - } - } else { - self.swiftPackageInterfacePath = nil - } var optimizationRecordFileType = FileType.yamlOptimizationRecord if let argument = parsedOptions.getLastArgument(.saveOptimizationRecordEQ)?.asSingle { @@ -1127,31 +1293,10 @@ public struct Driver { outputFileMap: self.outputFileMap, moduleName: moduleOutputInfo.name) - var apiDescriptorDirectory: VirtualPath? = nil - if let apiDescriptorDirectoryEnvVar = env["TAPI_SDKDB_OUTPUT_PATH"] { - apiDescriptorDirectory = try VirtualPath(path: apiDescriptorDirectoryEnvVar) - } else if let ldTraceFileEnvVar = env["LD_TRACE_FILE"] { - apiDescriptorDirectory = try VirtualPath(path: ldTraceFileEnvVar).parentDirectory.appending(component: "SDKDB") - } - if let apiDescriptorDirectory = apiDescriptorDirectory { - self.apiDescriptorFilePath = apiDescriptorDirectory - .appending(component: "\(moduleOutputInfo.name).\(frontendTargetInfo.target.moduleTriple.triple).swift.sdkdb") - .intern() - } else { - self.apiDescriptorFilePath = try Self.computeSupplementaryOutputPath( - &parsedOptions, type: .jsonAPIDescriptor, isOutputOptions: [], - outputPath: .emitApiDescriptorPath, - compilerOutputType: compilerOutputType, - compilerMode: compilerMode, - emitModuleSeparately: emitModuleSeparately, - outputFileMap: self.outputFileMap, - moduleName: moduleOutputInfo.name) - } - Self.validateDigesterArgs(&parsedOptions, moduleOutputInfo: moduleOutputInfo, digesterMode: self.digesterMode, - swiftInterfacePath: self.swiftInterfacePath, + swiftInterfacePath: self.moduleOutputPaths.swiftInterfacePath, diagnosticEngine: diagnosticsEngine) try verifyOutputOptions() @@ -2625,9 +2770,37 @@ extension Driver { return "" } + private static func computeVariantModuleInfo( + _ parsedOptions: inout ParsedOptions, + compilerOutputType: FileType?, + compilerMode: CompilerMode, + linkerOutputType: LinkOutputType?, + debugInfoLevel: DebugInfo.Level?, + diagnosticsEngine: DiagnosticsEngine, + workingDirectory: AbsolutePath? + ) throws -> ModuleOutputInfo? { + // If there is no target variant, then there is no target variant module. + // If there is no emit-variant-module, then there is not target variant + // module. + guard let variantModulePath = parsedOptions.getLastArgument(.emitVariantModulePath), + parsedOptions.hasArgument(.targetVariant) else { + return nil + } + return try computeModuleInfo(&parsedOptions, + modulePath: variantModulePath.asSingle, + compilerOutputType: compilerOutputType, + compilerMode: compilerMode, + linkerOutputType: linkerOutputType, + debugInfoLevel: debugInfoLevel, + diagnosticsEngine: diagnosticsEngine, + workingDirectory: workingDirectory) + return nil + } + /// Determine how the module will be emitted and the name of the module. private static func computeModuleInfo( _ parsedOptions: inout ParsedOptions, + modulePath: String?, compilerOutputType: FileType?, compilerMode: CompilerMode, linkerOutputType: LinkOutputType?, @@ -2642,7 +2815,7 @@ extension Driver { } var moduleOutputKind: ModuleOutputKind? - if parsedOptions.hasArgument(.emitModule, .emitModulePath) { + if parsedOptions.hasArgument(.emitModule) || modulePath != nil { // The user has requested a module, so generate one and treat it as // top-level output. moduleOutputKind = .topLevel @@ -2724,9 +2897,9 @@ extension Driver { // FIXME: Look in the output file map. It looks like it is weirdly // anchored to the first input? - if let modulePathArg = parsedOptions.getLastArgument(.emitModulePath) { + if let modulePathArg = modulePath { // The module path was specified. - moduleOutputPath = try VirtualPath(path: modulePathArg.asSingle) + moduleOutputPath = try VirtualPath(path: modulePathArg) } else if moduleOutputKind == .topLevel { // FIXME: Logic to infer from primary outputs, etc. let moduleFilename = moduleName.appendingFileTypeExtension(.swiftModule) @@ -3622,6 +3795,7 @@ extension Driver { static func computeModuleDocOutputPath( _ parsedOptions: inout ParsedOptions, moduleOutputPath: VirtualPath.Handle?, + outputOption: Option, compilerOutputType: FileType?, compilerMode: CompilerMode, outputFileMap: OutputFileMap?, @@ -3631,7 +3805,7 @@ extension Driver { moduleOutputPath: moduleOutputPath, type: .swiftDocumentation, isOutput: .emitModuleDoc, - outputPath: .emitModuleDocPath, + outputPath: outputOption, compilerOutputType: compilerOutputType, compilerMode: compilerMode, outputFileMap: outputFileMap, @@ -3642,6 +3816,7 @@ extension Driver { static func computeModuleSourceInfoOutputPath( _ parsedOptions: inout ParsedOptions, moduleOutputPath: VirtualPath.Handle?, + outputOption: Option, compilerOutputType: FileType?, compilerMode: CompilerMode, outputFileMap: OutputFileMap?, @@ -3653,7 +3828,7 @@ extension Driver { moduleOutputPath: moduleOutputPath, type: .swiftSourceInfoFile, isOutput: .emitModuleSourceInfo, - outputPath: .emitModuleSourceInfoPath, + outputPath: outputOption, compilerOutputType: compilerOutputType, compilerMode: compilerMode, outputFileMap: outputFileMap, diff --git a/Sources/SwiftDriver/Jobs/APIDigesterJobs.swift b/Sources/SwiftDriver/Jobs/APIDigesterJobs.swift index 3d8a60f1c..84dd11846 100644 --- a/Sources/SwiftDriver/Jobs/APIDigesterJobs.swift +++ b/Sources/SwiftDriver/Jobs/APIDigesterJobs.swift @@ -46,7 +46,10 @@ extension Driver { var commandLine = [Job.ArgTemplate]() commandLine.appendFlag("-dump-sdk") - try addCommonDigesterOptions(&commandLine, modulePath: modulePath, mode: mode) + try addCommonDigesterOptions(&commandLine, + modulePath: modulePath, + swiftModuleInterfacePath: self.moduleOutputPaths.swiftInterfacePath, + mode: mode) commandLine.appendFlag(.o) commandLine.appendPath(VirtualPath.lookup(outputPath)) @@ -69,12 +72,16 @@ extension Driver { case .api: return nil case .abi: - return abiDescriptorPath + return moduleOutputPaths.abiDescriptorFilePath } } guard let currentABI = getDescriptorPath(for: mode) else { // we don't have existing descriptor to use so we have to load the module from interface/swiftmodule - return try digesterCompareToBaselineJob(modulePath: modulePath, baselinePath: baselinePath, mode: digesterMode) + return try digesterCompareToBaselineJob( + modulePath: modulePath, + swiftModuleInterfacePath: self.moduleOutputPaths.swiftInterfacePath, + baselinePath: baselinePath, + mode: digesterMode) } var commandLine = [Job.ArgTemplate]() commandLine.appendFlag("-diagnose-sdk") @@ -105,14 +112,20 @@ extension Driver { ) } - mutating func digesterCompareToBaselineJob(modulePath: VirtualPath.Handle, baselinePath: VirtualPath.Handle, mode: DigesterMode) throws -> Job { + mutating func digesterCompareToBaselineJob(modulePath: VirtualPath.Handle, + swiftModuleInterfacePath: VirtualPath.Handle?, + baselinePath: VirtualPath.Handle, + mode: DigesterMode) throws -> Job { var commandLine = [Job.ArgTemplate]() commandLine.appendFlag("-diagnose-sdk") commandLine.appendFlag("-disable-fail-on-error") commandLine.appendFlag("-baseline-path") commandLine.appendPath(VirtualPath.lookup(baselinePath)) - try addCommonDigesterOptions(&commandLine, modulePath: modulePath, mode: mode) + try addCommonDigesterOptions(&commandLine, + modulePath: modulePath, + swiftModuleInterfacePath: swiftModuleInterfacePath, + mode: mode) var serializedDiagnosticsPath: VirtualPath.Handle? if let arg = parsedOptions.getLastArgument(.serializeBreakingChangesPath)?.asSingle { @@ -130,7 +143,7 @@ extension Driver { var inputs: [TypedVirtualPath] = [.init(file: modulePath, type: .swiftModule), .init(file: baselinePath, type: mode.baselineFileType)] // If a module interface was emitted, treat it as an input in ABI mode. - if let interfacePath = self.swiftInterfacePath, mode == .abi { + if let interfacePath = swiftModuleInterfacePath, mode == .abi { inputs.append(.init(file: interfacePath, type: .swiftInterface)) } @@ -147,6 +160,7 @@ extension Driver { private mutating func addCommonDigesterOptions(_ commandLine: inout [Job.ArgTemplate], modulePath: VirtualPath.Handle, + swiftModuleInterfacePath: VirtualPath.Handle?, mode: DigesterMode) throws { commandLine.appendFlag("-module") commandLine.appendFlag(moduleOutputInfo.name) @@ -160,7 +174,7 @@ extension Driver { let searchPath = VirtualPath.lookup(modulePath).parentDirectory commandLine.appendFlag(.I) commandLine.appendPath(searchPath) - if let interfacePath = self.swiftInterfacePath { + if let interfacePath = swiftModuleInterfacePath { let interfaceSearchPath = VirtualPath.lookup(interfacePath).parentDirectory if interfaceSearchPath != searchPath { commandLine.appendFlag(.I) diff --git a/Sources/SwiftDriver/Jobs/CompileJob.swift b/Sources/SwiftDriver/Jobs/CompileJob.swift index f307f9846..6f2aa1051 100644 --- a/Sources/SwiftDriver/Jobs/CompileJob.swift +++ b/Sources/SwiftDriver/Jobs/CompileJob.swift @@ -277,6 +277,8 @@ extension Driver { primaryInputs: primaryInputs, inputsGeneratingCodeCount: inputsGeneratingCodeCount, inputOutputMap: &inputOutputMap, + moduleOutputInfo: self.moduleOutputInfo, + moduleOutputPaths: self.moduleOutputPaths, includeModuleTracePath: emitModuleTrace, indexFilePath: indexFilePath) diff --git a/Sources/SwiftDriver/Jobs/EmitModuleJob.swift b/Sources/SwiftDriver/Jobs/EmitModuleJob.swift index 489e70d07..0a8fde6db 100644 --- a/Sources/SwiftDriver/Jobs/EmitModuleJob.swift +++ b/Sources/SwiftDriver/Jobs/EmitModuleJob.swift @@ -17,6 +17,7 @@ extension Driver { mutating func addCommonModuleOptions( commandLine: inout [Job.ArgTemplate], outputs: inout [TypedVirtualPath], + moduleOutputPaths: SupplementalModuleTargetOutputPaths, isMergeModule: Bool ) throws { // Add supplemental outputs. @@ -28,16 +29,16 @@ extension Driver { outputs.append(.init(file: path, type: type)) } - addSupplementalOutput(path: moduleDocOutputPath, flag: "-emit-module-doc-path", type: .swiftDocumentation) - addSupplementalOutput(path: moduleSourceInfoPath, flag: "-emit-module-source-info-path", type: .swiftSourceInfoFile) - addSupplementalOutput(path: swiftInterfacePath, flag: "-emit-module-interface-path", type: .swiftInterface) - addSupplementalOutput(path: swiftPrivateInterfacePath, flag: "-emit-private-module-interface-path", type: .privateSwiftInterface) + addSupplementalOutput(path: moduleOutputPaths.moduleDocOutputPath, flag: "-emit-module-doc-path", type: .swiftDocumentation) + addSupplementalOutput(path: moduleOutputPaths.moduleSourceInfoPath, flag: "-emit-module-source-info-path", type: .swiftSourceInfoFile) + addSupplementalOutput(path: moduleOutputPaths.swiftInterfacePath, flag: "-emit-module-interface-path", type: .swiftInterface) + addSupplementalOutput(path: moduleOutputPaths.swiftPrivateInterfacePath, flag: "-emit-private-module-interface-path", type: .privateSwiftInterface) if let pkgName = packageName, !pkgName.isEmpty { - addSupplementalOutput(path: swiftPackageInterfacePath, flag: "-emit-package-module-interface-path", type: .packageSwiftInterface) + addSupplementalOutput(path: moduleOutputPaths.swiftPackageInterfacePath, flag: "-emit-package-module-interface-path", type: .packageSwiftInterface) } addSupplementalOutput(path: objcGeneratedHeaderPath, flag: "-emit-objc-header-path", type: .objcHeader) addSupplementalOutput(path: tbdPath, flag: "-emit-tbd-path", type: .tbd) - addSupplementalOutput(path: apiDescriptorFilePath, flag: "-emit-api-descriptor-path", type: .jsonAPIDescriptor) + addSupplementalOutput(path: moduleOutputPaths.apiDescriptorFilePath, flag: "-emit-api-descriptor-path", type: .jsonAPIDescriptor) if isMergeModule { return @@ -78,8 +79,13 @@ extension Driver { } /// Form a job that emits a single module - @_spi(Testing) public mutating func emitModuleJob(pchCompileJob: Job?) throws -> Job { - let moduleOutputPath = moduleOutputInfo.output!.outputPath + @_spi(Testing) public mutating func emitModuleJob(pchCompileJob: Job?, isVariantJob: Bool = false) throws -> Job { + precondition(!isVariantJob || (isVariantJob && + variantModuleOutputInfo != nil && variantModuleOutputPaths != nil), + "target variant module requested without a target variant") + + let moduleOutputPath = isVariantJob ? variantModuleOutputInfo!.output!.outputPath : moduleOutputInfo.output!.outputPath + let moduleOutputPaths = isVariantJob ? variantModuleOutputPaths! : moduleOutputPaths var commandLine: [Job.ArgTemplate] = swiftCompilerPrefixArgs.map { Job.ArgTemplate.flag($0) } var inputs: [TypedVirtualPath] = [] var outputs: [TypedVirtualPath] = [ @@ -102,7 +108,12 @@ extension Driver { try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .emitModule) // FIXME: Add MSVC runtime library flags - try addCommonModuleOptions(commandLine: &commandLine, outputs: &outputs, isMergeModule: false) + try addCommonModuleOptions( + commandLine: &commandLine, + outputs: &outputs, + moduleOutputPaths: moduleOutputPaths, + isMergeModule: false) + try addCommonSymbolGraphOptions(commandLine: &commandLine) try commandLine.appendLast(.checkApiAvailabilityOnly, from: &parsedOptions) @@ -114,7 +125,7 @@ extension Driver { let outputPath = VirtualPath.lookup(moduleOutputPath) commandLine.appendFlag(.o) commandLine.appendPath(outputPath) - if let abiPath = abiDescriptorPath { + if let abiPath = moduleOutputPaths.abiDescriptorFilePath { commandLine.appendFlag(.emitAbiDescriptorPath) commandLine.appendPath(abiPath.file) outputs.append(abiPath) diff --git a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift index b253ae797..9e845fc99 100644 --- a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift +++ b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift @@ -551,6 +551,8 @@ extension Driver { primaryInputs: [TypedVirtualPath], inputsGeneratingCodeCount: Int, inputOutputMap: inout [TypedVirtualPath: [TypedVirtualPath]], + moduleOutputInfo: ModuleOutputInfo, + moduleOutputPaths: SupplementalModuleTargetOutputPaths, includeModuleTracePath: Bool, indexFilePath: TypedVirtualPath?) throws -> [TypedVirtualPath] { var flaggedInputOutputPairs: [(flag: String, input: TypedVirtualPath?, output: TypedVirtualPath)] = [] @@ -597,7 +599,9 @@ extension Driver { } /// Add all of the outputs needed for a given input. - func addAllOutputsFor(input: TypedVirtualPath?) throws { + func addAllOutputsFor(input: TypedVirtualPath?, + moduleOutputInfo: ModuleOutputInfo, + moduleOutputPaths: SupplementalModuleTargetOutputPaths) throws { if !emitModuleSeparately { // Generate the module files with the main job. try addOutputOfType( @@ -607,12 +611,12 @@ extension Driver { flag: "-emit-module-path") try addOutputOfType( outputType: .swiftDocumentation, - finalOutputPath: moduleDocOutputPath, + finalOutputPath: moduleOutputPaths.moduleDocOutputPath, input: input, flag: "-emit-module-doc-path") try addOutputOfType( outputType: .swiftSourceInfoFile, - finalOutputPath: moduleSourceInfoPath, + finalOutputPath: moduleOutputPaths.moduleSourceInfoPath, input: input, flag: "-emit-module-source-info-path") } @@ -650,10 +654,14 @@ extension Driver { if compilerMode.usesPrimaryFileInputs { for input in primaryInputs { - try addAllOutputsFor(input: input) + try addAllOutputsFor(input: input, + moduleOutputInfo: moduleOutputInfo, + moduleOutputPaths: moduleOutputPaths) } } else { - try addAllOutputsFor(input: nil) + try addAllOutputsFor(input: nil, + moduleOutputInfo: moduleOutputInfo, + moduleOutputPaths: moduleOutputPaths) if !emitModuleSeparately { // Outputs that only make sense when the whole module is processed @@ -666,20 +674,20 @@ extension Driver { try addOutputOfType( outputType: .swiftInterface, - finalOutputPath: swiftInterfacePath, + finalOutputPath: moduleOutputPaths.swiftInterfacePath, input: nil, flag: "-emit-module-interface-path") try addOutputOfType( outputType: .privateSwiftInterface, - finalOutputPath: swiftPrivateInterfacePath, + finalOutputPath: moduleOutputPaths.swiftPrivateInterfacePath, input: nil, flag: "-emit-private-module-interface-path") if let pkgName = packageName, !pkgName.isEmpty { try addOutputOfType( outputType: .packageSwiftInterface, - finalOutputPath: swiftPackageInterfacePath, + finalOutputPath: moduleOutputPaths.swiftPackageInterfacePath, input: nil, flag: "-emit-package-module-interface-path") } @@ -689,7 +697,7 @@ extension Driver { input: nil, flag: "-emit-tbd-path") - if let abiDescriptorPath = abiDescriptorPath { + if let abiDescriptorPath = moduleOutputPaths.abiDescriptorFilePath { try addOutputOfType(outputType: .jsonABIBaseline, finalOutputPath: abiDescriptorPath.fileHandle, input: nil, @@ -698,7 +706,7 @@ extension Driver { try addOutputOfType( outputType: .jsonAPIDescriptor, - finalOutputPath: apiDescriptorFilePath, + finalOutputPath: moduleOutputPaths.apiDescriptorFilePath, input: nil, flag: "-emit-api-descriptor-path") } diff --git a/Sources/SwiftDriver/Jobs/MergeModuleJob.swift b/Sources/SwiftDriver/Jobs/MergeModuleJob.swift index 3b976636a..b5e8147fd 100644 --- a/Sources/SwiftDriver/Jobs/MergeModuleJob.swift +++ b/Sources/SwiftDriver/Jobs/MergeModuleJob.swift @@ -57,7 +57,7 @@ extension Driver { try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .mergeModule, bridgingHeaderHandling: .parsed) // FIXME: Add MSVC runtime library flags - try addCommonModuleOptions(commandLine: &commandLine, outputs: &outputs, isMergeModule: true) + try addCommonModuleOptions(commandLine: &commandLine, outputs: &outputs, moduleOutputPaths: moduleOutputPaths, isMergeModule: true) try addCommonSymbolGraphOptions(commandLine: &commandLine) @@ -65,7 +65,7 @@ extension Driver { commandLine.appendFlag(.o) commandLine.appendPath(outputPath) - if let abiPath = abiDescriptorPath { + if let abiPath = moduleOutputPaths.abiDescriptorFilePath { commandLine.appendFlag(.emitAbiDescriptorPath) commandLine.appendPath(abiPath.file) outputs.append(abiPath) diff --git a/Sources/SwiftDriver/Jobs/Planning.swift b/Sources/SwiftDriver/Jobs/Planning.swift index 555d2dca0..651a99b4f 100644 --- a/Sources/SwiftDriver/Jobs/Planning.swift +++ b/Sources/SwiftDriver/Jobs/Planning.swift @@ -256,13 +256,21 @@ extension Driver { ) } - private mutating func addEmitModuleJob(addJobBeforeCompiles: (Job) -> Void, pchCompileJob: Job?) throws -> Job? { - if emitModuleSeparately { - let emitJob = try emitModuleJob(pchCompileJob: pchCompileJob) - addJobBeforeCompiles(emitJob) - return emitJob - } - return nil + private mutating func addEmitModuleJob( + addJobBeforeCompiles: (Job) -> Void, + pchCompileJob: Job?, + isVariantModule: Bool = false) throws -> Job? { + // The target variant module is always emitted separately, so we need to + // add an explicit job regardless of whether the primary target was + // emitted separately + if emitModuleSeparately || isVariantModule { + let emitJob = try emitModuleJob( + pchCompileJob: pchCompileJob, + isVariantJob: isVariantModule) + addJobBeforeCompiles(emitJob) + return emitJob + } + return nil } private mutating func addJobsFeedingLinker( @@ -337,6 +345,13 @@ extension Driver { addLinkerInput: addLinkerInput) } + if variantModuleOutputInfo != nil { + _ = try addEmitModuleJob( + addJobBeforeCompiles: addJobBeforeCompiles, + pchCompileJob: jobCreatingPch, + isVariantModule: true) + } + try addJobsForPrimaryInputs( addCompileJobGroup: addCompileJobGroup, addModuleInput: addModuleInput, diff --git a/Sources/SwiftOptions/Options.swift b/Sources/SwiftOptions/Options.swift index bb0745d94..1bd084765 100644 --- a/Sources/SwiftOptions/Options.swift +++ b/Sources/SwiftOptions/Options.swift @@ -384,6 +384,14 @@ extension Option { public static let emitTbdPathEQ: Option = Option("-emit-tbd-path=", .joined, alias: Option.emitTbdPath, attributes: [.frontend, .noInteractive, .argumentIsPath, .supplementaryOutput, .cacheInvariant]) public static let emitTbdPath: Option = Option("-emit-tbd-path", .separate, attributes: [.frontend, .noInteractive, .argumentIsPath, .supplementaryOutput, .cacheInvariant], metaVar: "", helpText: "Emit the TBD file to ") public static let emitTbd: Option = Option("-emit-tbd", .flag, attributes: [.frontend, .noInteractive, .supplementaryOutput], helpText: "Emit a TBD file") + public static let emitVariantAbiDescriptorPath: Option = Option("-emit-variant-abi-descriptor-path", .separate, attributes: [.frontend, .noDriver, .cacheInvariant], metaVar: "", helpText: "Output the ABI descriptor of current target variant module to ") + public static let emitVariantApiDescriptorPath: Option = Option("-emit-variant-api-descriptor-path", .separate, attributes: [.frontend, .noInteractive, .argumentIsPath, .supplementaryOutput, .cacheInvariant], metaVar: "", helpText: "Output a JSON file describing the target variant module's API to ") + public static let emitVariantModuleDocPath: Option = Option("-emit-variant-module-doc-path", .separate, attributes: [.frontend, .noDriver, .cacheInvariant], metaVar: "", helpText: "Output module documentation file for the target variant to ") + public static let emitVariantModuleInterfacePath: Option = Option("-emit-variant-module-interface-path", .separate, attributes: [.frontend, .noInteractive, .argumentIsPath, .supplementaryOutput, .cacheInvariant], metaVar: "", helpText: "Output module interface file for the target variant to ") + public static let emitVariantModulePath: Option = Option("-emit-variant-module-path", .separate, attributes: [.noInteractive, .argumentIsPath, .supplementaryOutput, .cacheInvariant], metaVar: "", helpText: "Emit an importable module for the target variant at the specified path") + public static let emitVariantModuleSourceInfoPath: Option = Option("-emit-variant-module-source-info-path", .separate, attributes: [.frontend, .noInteractive, .argumentIsPath, .supplementaryOutput], metaVar: "", helpText: "Output module source info file for the target variant to ") + public static let emitVariantPackageModuleInterfacePath: Option = Option("-emit-variant-package-module-interface-path", .separate, attributes: [.frontend, .noInteractive, .argumentIsPath, .supplementaryOutput, .cacheInvariant], metaVar: "", helpText: "Output package module interface file for the target variant to ") + public static let emitVariantPrivateModuleInterfacePath: Option = Option("-emit-variant-private-module-interface-path", .separate, attributes: [.frontend, .noInteractive, .argumentIsPath, .supplementaryOutput, .cacheInvariant], metaVar: "", helpText: "Output private module interface file for the target variant to ") public static let emitVerboseSil: Option = Option("-emit-verbose-sil", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Emit locations during SIL emission") public static let emptyAbiDescriptor: Option = Option("-empty-abi-descriptor", .flag, attributes: [.frontend, .noDriver], helpText: "Avoid printing actual module content into ABI descriptor file") public static let emptyBaseline: Option = Option("-empty-baseline", .flag, attributes: [.noDriver], helpText: "Use empty baseline for diagnostics") @@ -1297,6 +1305,14 @@ extension Option { Option.emitTbdPathEQ, Option.emitTbdPath, Option.emitTbd, + Option.emitVariantAbiDescriptorPath, + Option.emitVariantApiDescriptorPath, + Option.emitVariantModuleDocPath, + Option.emitVariantModuleInterfacePath, + Option.emitVariantModulePath, + Option.emitVariantModuleSourceInfoPath, + Option.emitVariantPackageModuleInterfacePath, + Option.emitVariantPrivateModuleInterfacePath, Option.emitVerboseSil, Option.emptyAbiDescriptor, Option.emptyBaseline, diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index 713a1ac4d..04c4edcfa 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -4090,6 +4090,162 @@ final class SwiftDriverTests: XCTestCase { } } + func testTargetVariantEmitModule() throws { + do { + var driver = try Driver(args: ["swiftc", + "-target", "x86_64-apple-macosx10.14", + "-target-variant", "x86_64-apple-ios13.1-macabi", + "-enable-library-evolution", + "-emit-module", + "-emit-module-path", "foo.swiftmodule/target.swiftmodule", + "-emit-variant-module-path", "foo.swiftmodule/variant.swiftmodule", + "foo.swift"]) + + let plannedJobs = try driver.planBuild().removingAutolinkExtractJobs() + XCTAssertEqual(plannedJobs.count, 3) + + let targetModuleJob = plannedJobs[0] + let variantModuleJob = plannedJobs[1] + + XCTAssert(targetModuleJob.commandLine.contains(.flag("-emit-module"))) + XCTAssert(variantModuleJob.commandLine.contains(.flag("-emit-module"))) + + XCTAssert(targetModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/target.swiftdoc"))))) + XCTAssert(targetModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/target.swiftsourceinfo"))))) + XCTAssert(targetModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/target.abi.json"))))) + XCTAssertTrue(targetModuleJob.commandLine.contains(subsequence: [.flag("-o"), .path(.relative(try .init(validating: "foo.swiftmodule/target.swiftmodule")))])) + + XCTAssert(variantModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/variant.swiftdoc"))))) + XCTAssert(variantModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/variant.swiftsourceinfo"))))) + XCTAssert(variantModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/variant.abi.json"))))) + XCTAssertTrue(variantModuleJob.commandLine.contains(subsequence: [.flag("-o"), .path(.relative(try .init(validating: "foo.swiftmodule/variant.swiftmodule")))])) + } + + do { + // explicitly emit variant supplemental outputs + var driver = try Driver(args: ["swiftc", + "-target", "x86_64-apple-macosx10.14", + "-target-variant", "x86_64-apple-ios13.1-macabi", + "-enable-library-evolution", + "-package-name", "Susan", + "-emit-module", + "-emit-module-path", "target.swiftmodule", + "-emit-variant-module-path", "variant.swiftmodule", + "-Xfrontend", "-emit-module-doc-path", "-Xfrontend", "target.swiftdoc", + "-Xfrontend", "-emit-variant-module-doc-path", "variant.swiftdoc", + "-emit-module-source-info-path", "target.sourceinfo", + "-emit-variant-module-source-info-path", "variant.sourceinfo", + "-emit-package-module-interface-path", "target.package.swiftinterface", + "-emit-variant-package-module-interface-path", "variant.package.swiftinterface", + "-emit-private-module-interface-path", "target.private.swiftinterface", + "-emit-variant-private-module-interface-path", "variant.private.swiftinterface", + "-emit-module-interface-path", "target.swiftinterface", + "-emit-variant-module-interface-path", "variant.swiftinterface", + "foo.swift"]) + + let plannedJobs = try driver.planBuild().removingAutolinkExtractJobs() + // emit module, emit module, compile foo.swift, + // verify target.swiftinterface, + // verify target.private.swiftinterface, + // verify target.package.swiftinterface, + XCTAssertEqual(plannedJobs.count, 6) + + let targetModuleJob: Job = plannedJobs[0] + let variantModuleJob = plannedJobs[1] + + XCTAssertEqual(targetModuleJob.outputs.filter { $0.type == .swiftModule }.last!.file, + try toPath("target.swiftmodule")) + XCTAssertEqual(variantModuleJob.outputs.filter { $0.type == .swiftModule }.last!.file, + try toPath("variant.swiftmodule")) + + XCTAssertEqual(targetModuleJob.outputs.filter { $0.type == .swiftDocumentation }.last!.file, + try toPath("target.swiftdoc")) + XCTAssertEqual(variantModuleJob.outputs.filter { $0.type == .swiftDocumentation }.last!.file, + try toPath("variant.swiftdoc")) + + XCTAssertEqual(targetModuleJob.outputs.filter { $0.type == .swiftSourceInfoFile }.last!.file, + try toPath("target.sourceinfo")) + XCTAssertEqual(variantModuleJob.outputs.filter { $0.type == .swiftSourceInfoFile }.last!.file, + try toPath("variant.sourceinfo")) + + XCTAssertEqual(targetModuleJob.outputs.filter { $0.type == .swiftInterface}.last!.file, + try toPath("target.swiftinterface")) + XCTAssertEqual(variantModuleJob.outputs.filter { $0.type == .swiftInterface}.last!.file, + try toPath("variant.swiftinterface")) + + XCTAssertEqual(targetModuleJob.outputs.filter { $0.type == .privateSwiftInterface}.last!.file, + try toPath("target.private.swiftinterface")) + XCTAssertEqual(variantModuleJob.outputs.filter { $0.type == .privateSwiftInterface}.last!.file, + try toPath("variant.private.swiftinterface")) + + XCTAssertEqual(targetModuleJob.outputs.filter { $0.type == .packageSwiftInterface}.last!.file, + try toPath("target.package.swiftinterface")) + XCTAssertEqual(variantModuleJob.outputs.filter { $0.type == .packageSwiftInterface}.last!.file, + try toPath("variant.package.swiftinterface")) + + XCTAssertEqual(targetModuleJob.outputs.filter { $0.type == .jsonABIBaseline }.last!.file, + try toPath("target.abi.json")) + XCTAssertEqual(variantModuleJob.outputs.filter { $0.type == .jsonABIBaseline}.last!.file, + try toPath("variant.abi.json")) + } + +#if os(macOS) + do { + try withTemporaryDirectory { path in + var env = ProcessEnv.vars + env["LD_TRACE_FILE"] = path.appending(component: ".LD_TRACE").nativePathString(escaped: false) + var driver = try Driver(args: ["swiftc", + "-target", "x86_64-apple-macosx10.14", + "-target-variant", "x86_64-apple-ios13.1-macabi", + "-emit-variant-module-path", "foo.swiftmodule/x86_64-apple-ios13.1-macabi.swiftmodule", + "-enable-library-evolution", + "-emit-module", + "foo.swift"], env: env) + + let plannedJobs = try driver.planBuild().removingAutolinkExtractJobs() + let targetModuleJob = plannedJobs[0] + let variantModuleJob = plannedJobs[1] + + XCTAssert(targetModuleJob.commandLine.contains(subsequence: [ + .flag("-emit-api-descriptor-path"), + .path(.absolute(path.appending(components: "SDKDB", "foo.\(driver.frontendTargetInfo.target.moduleTriple.triple).swift.sdkdb"))), + ])) + + XCTAssert(variantModuleJob.commandLine.contains(subsequence: [ + .flag("-emit-api-descriptor-path"), + .path(.absolute(path.appending(components: "SDKDB", "foo.\(driver.frontendTargetInfo.targetVariant!.moduleTriple.triple).swift.sdkdb"))), + ])) + } + } + + do { + var driver = try Driver(args: ["swiftc", + "-target", "x86_64-apple-macosx10.14", + "-target-variant", "x86_64-apple-ios13.1-macabi", + "-emit-variant-module-path", "foo.swiftmodule/x86_64-apple-ios13.1-macabi.swiftmodule", + "-enable-library-evolution", + "-emit-module", + "-emit-api-descriptor-path", "foo.swiftmodule/target.api.json", + "-emit-variant-api-descriptor-path", "foo.swiftmodule/variant.api.json", + "foo.swift"]) + + let plannedJobs = try driver.planBuild().removingAutolinkExtractJobs() + let targetModuleJob = plannedJobs[0] + let variantModuleJob = plannedJobs[1] + + XCTAssert(targetModuleJob.commandLine.contains(subsequence: [ + .flag("-emit-api-descriptor-path"), + .path(.relative(try .init(validating: "foo.swiftmodule/target.api.json"))) + ])) + + XCTAssert(variantModuleJob.commandLine.contains(subsequence: [ + .flag("-emit-api-descriptor-path"), + .path(.relative(try .init(validating: "foo.swiftmodule/variant.api.json"))) + ])) + } +#endif + } + func testValidDeprecatedTargetiOS() throws { var driver = try Driver(args: ["swiftc", "-emit-module", "-target", "armv7-apple-ios13.0", "foo.swift"]) let plannedJobs = try driver.planBuild()