Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion Sources/SwiftDriver/Driver/Driver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,9 @@ public struct Driver {
/// Path to the Swift private interface file.
let swiftPrivateInterfacePath: VirtualPath.Handle?

/// Path to the Swift package interface file.
let swiftPackageInterfacePath: VirtualPath.Handle?

/// File type for the optimization record.
let optimizationRecordFileType: FileType?

Expand Down Expand Up @@ -964,6 +967,14 @@ public struct Driver {
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
Expand All @@ -978,6 +989,22 @@ public struct Driver {
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 {
switch argument {
Expand Down Expand Up @@ -2546,7 +2573,7 @@ extension Driver {
moduleOutputKind = .auxiliary
} else if parsedOptions.hasArgument(.emitObjcHeader, .emitObjcHeaderPath,
.emitModuleInterface, .emitModuleInterfacePath,
.emitPrivateModuleInterfacePath) {
.emitPrivateModuleInterfacePath, .emitPackageModuleInterfacePath) {
// An option has been passed which requires whole-module knowledge, but we
// don't have that. Generate a module, but treat it as an intermediate
// output.
Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftDriver/Jobs/CompileJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ extension Driver {
case .swiftModule:
return compilerMode.isSingleCompilation && moduleOutputInfo.output?.isTopLevel ?? false
case .swift, .image, .dSYM, .dependencies, .emitModuleDependencies, .autolink,
.swiftDocumentation, .swiftInterface, .privateSwiftInterface, .swiftSourceInfoFile,
.swiftDocumentation, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface, .swiftSourceInfoFile,
.diagnostics, .emitModuleDiagnostics, .objcHeader, .swiftDeps, .remap, .tbd,
.moduleTrace, .yamlOptimizationRecord, .bitstreamOptimizationRecord, .pcm, .pch,
.clangModuleMap, .jsonCompilerFeatures, .jsonTargetInfo, .jsonSwiftArtifacts,
Expand Down Expand Up @@ -470,7 +470,7 @@ extension FileType {
case .swift, .dSYM, .autolink, .dependencies, .emitModuleDependencies,
.swiftDocumentation, .pcm, .diagnostics, .emitModuleDiagnostics,
.objcHeader, .image, .swiftDeps, .moduleTrace, .tbd, .yamlOptimizationRecord,
.bitstreamOptimizationRecord, .swiftInterface, .privateSwiftInterface,
.bitstreamOptimizationRecord, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface,
.swiftSourceInfoFile, .clangModuleMap, .jsonSwiftArtifacts,
.indexUnitOutputPath, .modDepCache, .jsonAPIBaseline, .jsonABIBaseline,
.swiftConstValues, .jsonAPIDescriptor, .moduleSummary, .moduleSemanticInfo,
Expand Down
3 changes: 3 additions & 0 deletions Sources/SwiftDriver/Jobs/EmitModuleJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ extension Driver {
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)
if let pkgName = packageName, !pkgName.isEmpty {
addSupplementalOutput(path: 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)
Expand Down
8 changes: 8 additions & 0 deletions Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ extension Driver {
try commandLine.appendLast(.debugDiagnosticNames, from: &parsedOptions)
try commandLine.appendLast(.scanDependencies, from: &parsedOptions)
try commandLine.appendLast(.enableExperimentalConcisePoundFile, from: &parsedOptions)
try commandLine.appendLast(.experimentalPackageInterfaceLoad, from: &parsedOptions)
try commandLine.appendLast(.printEducationalNotes, from: &parsedOptions)
try commandLine.appendLast(.diagnosticStyle, from: &parsedOptions)
try commandLine.appendLast(.locale, from: &parsedOptions)
Expand Down Expand Up @@ -587,6 +588,13 @@ extension Driver {
input: nil,
flag: "-emit-private-module-interface-path")

if let pkgName = packageName, !pkgName.isEmpty {
try addOutputOfType(
outputType: .packageSwiftInterface,
finalOutputPath: swiftPackageInterfacePath,
input: nil,
flag: "-emit-package-module-interface-path")
}
try addOutputOfType(
outputType: .tbd,
finalOutputPath: tbdPath,
Expand Down
33 changes: 24 additions & 9 deletions Sources/SwiftDriver/Jobs/Planning.swift
Original file line number Diff line number Diff line change
Expand Up @@ -571,15 +571,29 @@ extension Driver {

let optIn = env["ENABLE_DEFAULT_INTERFACE_VERIFIER"] != nil ||
parsedOptions.hasArgument(.verifyEmittedModuleInterface)
func addVerifyJob(forPrivate: Bool) throws {
let isNeeded =
forPrivate
? parsedOptions.hasArgument(.emitPrivateModuleInterfacePath)
: parsedOptions.hasArgument(.emitModuleInterface, .emitModuleInterfacePath)

enum InterfaceMode {
case Public, Private, Package
}

func addVerifyJob(for mode: InterfaceMode) throws {
var isNeeded = false
var outputType: FileType

switch mode {
case .Public:
isNeeded = parsedOptions.hasArgument(.emitModuleInterface, .emitModuleInterfacePath)
outputType = FileType.swiftInterface
case .Private:
isNeeded = parsedOptions.hasArgument(.emitPrivateModuleInterfacePath)
outputType = .privateSwiftInterface
case .Package:
isNeeded = parsedOptions.hasArgument(.emitPackageModuleInterfacePath)
outputType = .packageSwiftInterface
}

guard isNeeded else { return }

let outputType: FileType =
forPrivate ? .privateSwiftInterface : .swiftInterface
let mergeInterfaceOutputs = emitModuleJob.outputs.filter { $0.type == outputType }
assert(mergeInterfaceOutputs.count == 1,
"Merge module job should only have one swiftinterface output")
Expand All @@ -588,8 +602,9 @@ extension Driver {
optIn: optIn)
addJob(job)
}
try addVerifyJob(forPrivate: false)
try addVerifyJob(forPrivate: true)
try addVerifyJob(for: .Public)
try addVerifyJob(for: .Private)
try addVerifyJob(for: .Package)
}

private mutating func addAutolinkExtractJob(
Expand Down
2 changes: 2 additions & 0 deletions Sources/SwiftDriver/Jobs/PrebuiltModulesJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ public class SwiftAdopter: Codable {
public let moduleDir: String
public let hasInterface: Bool
public let hasPrivateInterface: Bool
public let hasPackageInterface: Bool
public let hasModule: Bool
public let isFramework: Bool
public let isPrivate: Bool
Expand All @@ -364,6 +365,7 @@ public class SwiftAdopter: Codable {
self.moduleDir = SwiftAdopter.relativeToSDK(moduleDir)
self.hasInterface = !hasInterface.isEmpty
self.hasPrivateInterface = hasInterface.contains { $0.basename.hasSuffix(".private.swiftinterface") }
self.hasPackageInterface = hasInterface.contains { $0.basename.hasSuffix(".package.swiftinterface") }
self.hasModule = !hasModule.isEmpty
self.isFramework = self.moduleDir.contains("\(name).framework")
self.isPrivate = self.moduleDir.contains("PrivateFrameworks")
Expand Down
9 changes: 6 additions & 3 deletions Sources/SwiftDriver/Jobs/VerifyModuleInterfaceJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
extension Driver {
mutating func computeCacheKeyForInterface(emitModuleJob: Job,
interfaceKind: FileType) throws -> String? {
assert(interfaceKind == .swiftInterface || interfaceKind == .privateSwiftInterface,
assert(interfaceKind == .swiftInterface || interfaceKind == .privateSwiftInterface || interfaceKind == .packageSwiftInterface,
"only expect interface output kind")
let isNeeded = emitModuleJob.outputs.contains { $0.type == interfaceKind }
guard isCachingEnabled && isNeeded else { return nil }
Expand Down Expand Up @@ -54,11 +54,14 @@ extension Driver {
}

// TODO: remove this because we'd like module interface errors to fail the build.
if !optIn && isFrontendArgSupported(.downgradeTypecheckInterfaceError) {
if isFrontendArgSupported(.downgradeTypecheckInterfaceError) &&
(!optIn ||
// package interface is new and should not be a blocker for now
interfaceInput.type == .packageSwiftInterface) {
commandLine.appendFlag(.downgradeTypecheckInterfaceError)
}

let cacheKeys = try computeOutputCacheKeyForJob(commandLine: commandLine, inputs: [interfaceInput])
let cacheKeys = try computeOutputCacheKeyForJob(commandLine: commandLine, inputs: [interfaceInput])
return Job(
moduleName: moduleOutputInfo.name,
kind: .verifyModuleInterface,
Expand Down
16 changes: 12 additions & 4 deletions Sources/SwiftDriver/Utilities/FileType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ public enum FileType: String, Hashable, CaseIterable, Codable {
/// An SPI Swift Interface file.
case privateSwiftInterface = "private.swiftinterface"

/// An interface file containng package decls as well as SPI and public decls.
case packageSwiftInterface = "package.swiftinterface"

/// Serialized source information.
case swiftSourceInfoFile = "swiftsourceinfo"

Expand Down Expand Up @@ -194,6 +197,9 @@ extension FileType: CustomStringConvertible {
case .privateSwiftInterface:
return "private-swiftinterface"

case .packageSwiftInterface:
return "package-swiftinterface"

case .objcHeader:
return "objc-header"

Expand Down Expand Up @@ -275,7 +281,7 @@ extension FileType {
.emitModuleDependencies, .swiftDocumentation, .pcm, .diagnostics,
.emitModuleDiagnostics, .objcHeader, .image, .swiftDeps, .moduleTrace,
.tbd, .yamlOptimizationRecord, .bitstreamOptimizationRecord,
.swiftInterface, .privateSwiftInterface, .swiftSourceInfoFile,
.swiftInterface, .privateSwiftInterface, .packageSwiftInterface, .swiftSourceInfoFile,
.jsonDependencies, .clangModuleMap, .jsonTargetInfo, .jsonCompilerFeatures,
.jsonSwiftArtifacts, .indexUnitOutputPath, .modDepCache, .jsonAPIBaseline,
.jsonABIBaseline, .swiftConstValues, .jsonAPIDescriptor,
Expand Down Expand Up @@ -324,6 +330,8 @@ extension FileType {
return "swiftinterface"
case .privateSwiftInterface:
return "private-swiftinterface"
case .packageSwiftInterface:
return "package-swiftinterface"
case .swiftSourceInfoFile:
return "swiftsourceinfo"
case .clangModuleMap:
Expand Down Expand Up @@ -401,7 +409,7 @@ extension FileType {
switch self {
case .swift, .sil, .dependencies, .emitModuleDependencies, .assembly, .ast,
.raw_sil, .llvmIR,.objcHeader, .autolink, .importedModules, .tbd,
.moduleTrace, .yamlOptimizationRecord, .swiftInterface, .privateSwiftInterface,
.moduleTrace, .yamlOptimizationRecord, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface,
.jsonDependencies, .clangModuleMap, .jsonCompilerFeatures, .jsonTargetInfo,
.jsonSwiftArtifacts, .jsonAPIBaseline, .jsonABIBaseline, .swiftConstValues,
.jsonAPIDescriptor, .moduleSummary, .moduleSemanticInfo, .cachedDiagnostics:
Expand All @@ -422,7 +430,7 @@ extension FileType {
return true
case .swift, .sil, .sib, .ast, .image, .dSYM, .dependencies, .emitModuleDependencies,
.autolink, .swiftModule, .swiftDocumentation, .swiftInterface,
.privateSwiftInterface, .swiftSourceInfoFile, .raw_sil, .raw_sib,
.privateSwiftInterface, .packageSwiftInterface, .swiftSourceInfoFile, .raw_sil, .raw_sib,
.diagnostics, .emitModuleDiagnostics, .objcHeader, .swiftDeps, .remap,
.importedModules, .tbd, .moduleTrace, .indexData, .yamlOptimizationRecord,
.modDepCache, .bitstreamOptimizationRecord, .pcm, .pch, .jsonDependencies,
Expand All @@ -445,7 +453,7 @@ extension FileType {
return false
case .assembly, .llvmIR, .llvmBitcode, .object, .sil, .sib, .ast,
.dependencies, .emitModuleDependencies, .swiftModule,
.swiftDocumentation, .swiftInterface, .privateSwiftInterface,
.swiftDocumentation, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface,
.swiftSourceInfoFile, .raw_sil, .raw_sib, .objcHeader, .swiftDeps, .tbd,
.moduleTrace, .indexData, .yamlOptimizationRecord,
.bitstreamOptimizationRecord, .pcm, .pch, .jsonDependencies,
Expand Down
4 changes: 4 additions & 0 deletions Sources/SwiftOptions/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ extension Option {
public static let emitObjcHeaderPath: Option = Option("-emit-objc-header-path", .separate, attributes: [.frontend, .noInteractive, .argumentIsPath, .supplementaryOutput, .cacheInvariant], metaVar: "<path>", helpText: "Emit an Objective-C header file to <path>")
public static let emitObjcHeader: Option = Option("-emit-objc-header", .flag, attributes: [.frontend, .noInteractive, .supplementaryOutput], helpText: "Emit an Objective-C header file")
public static let emitObject: Option = Option("-emit-object", .flag, attributes: [.frontend, .noInteractive, .doesNotAffectIncrementalBuild], helpText: "Emit object file(s) (-c)", group: .modes)
public static let emitPackageModuleInterfacePath: Option = Option("-emit-package-module-interface-path", .separate, attributes: [.helpHidden, .frontend, .noInteractive, .argumentIsPath, .supplementaryOutput, .cacheInvariant], metaVar: "<path>", helpText: "Output package module interface file to <path>")
public static let emitParseableModuleInterfacePath: Option = Option("-emit-parseable-module-interface-path", .separate, alias: Option.emitModuleInterfacePath, attributes: [.helpHidden, .frontend, .noInteractive, .argumentIsPath, .supplementaryOutput, .cacheInvariant])
public static let emitParseableModuleInterface: Option = Option("-emit-parseable-module-interface", .flag, alias: Option.emitModuleInterface, attributes: [.helpHidden, .noInteractive, .supplementaryOutput])
public static let emitParse: Option = Option("-emit-parse", .flag, alias: Option.dumpParse, attributes: [.frontend, .noInteractive, .doesNotAffectIncrementalBuild])
Expand Down Expand Up @@ -455,6 +456,7 @@ extension Option {
public static let experimentalHermeticSealAtLink: Option = Option("-experimental-hermetic-seal-at-link", .flag, attributes: [.helpHidden, .frontend], helpText: "Library code can assume that all clients are visible at linktime, and aggressively strip unused code")
public static let experimentalLazyTypecheck: Option = Option("-experimental-lazy-typecheck", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Type-check lazily as needed to produce requested outputs")
public static let experimentalOneWayClosureParams: Option = Option("-experimental-one-way-closure-params", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Enable experimental support for one-way closure parameters")
public static let experimentalPackageInterfaceLoad: Option = Option("-experimental-package-interface-load", .flag, attributes: [.helpHidden, .frontend, .moduleInterface], helpText: "Supports loading a module via .package.swiftinterface in the same package")
public static let ExperimentalPerformanceAnnotations: Option = Option("-experimental-performance-annotations", .flag, attributes: [.helpHidden, .frontend], helpText: "Deprecated, has no effect")
public static let platformCCallingConventionEQ: Option = Option("-experimental-platform-c-calling-convention=", .joined, alias: Option.platformCCallingConvention, attributes: [.helpHidden, .frontend, .noDriver])
public static let platformCCallingConvention: Option = Option("-experimental-platform-c-calling-convention", .separate, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Which calling convention is used to perform non-swift calls. Defaults to llvm's standard C calling convention.")
Expand Down Expand Up @@ -1149,6 +1151,7 @@ extension Option {
Option.emitObjcHeaderPath,
Option.emitObjcHeader,
Option.emitObject,
Option.emitPackageModuleInterfacePath,
Option.emitParseableModuleInterfacePath,
Option.emitParseableModuleInterface,
Option.emitParse,
Expand Down Expand Up @@ -1277,6 +1280,7 @@ extension Option {
Option.experimentalHermeticSealAtLink,
Option.experimentalLazyTypecheck,
Option.experimentalOneWayClosureParams,
Option.experimentalPackageInterfaceLoad,
Option.ExperimentalPerformanceAnnotations,
Option.platformCCallingConventionEQ,
Option.platformCCallingConvention,
Expand Down
2 changes: 2 additions & 0 deletions Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2086,13 +2086,15 @@ final class ExplicitModuleBuildTests: XCTestCase {
XCTAssertFalse(A.isPrivate)
XCTAssertFalse(A.hasModule)
XCTAssertFalse(A.hasPrivateInterface)
XCTAssertFalse(A.hasPackageInterface)
XCTAssertTrue(A.hasInterface)

let B = adopters.first {$0.name == "B"}!
XCTAssertTrue(B.isFramework)
XCTAssertFalse(B.isPrivate)
XCTAssertFalse(B.hasModule)
XCTAssertTrue(B.hasPrivateInterface)
XCTAssertFalse(B.hasPackageInterface)
}

func testCollectSwiftAdoptersWhetherMixed() throws {
Expand Down
Loading