Skip to content

Commit 563d196

Browse files
authored
Merge pull request #1487 from apple/es-pkg-interface
Support package interface gen and verification in driver
2 parents 0194450 + 949530c commit 563d196

11 files changed

+227
-20
lines changed

Sources/SwiftDriver/Driver/Driver.swift

+28-1
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,9 @@ public struct Driver {
374374
/// Path to the Swift private interface file.
375375
let swiftPrivateInterfacePath: VirtualPath.Handle?
376376

377+
/// Path to the Swift package interface file.
378+
let swiftPackageInterfacePath: VirtualPath.Handle?
379+
377380
/// File type for the optimization record.
378381
let optimizationRecordFileType: FileType?
379382

@@ -964,6 +967,14 @@ public struct Driver {
964967
emitModuleSeparately: emitModuleSeparately,
965968
outputFileMap: self.outputFileMap,
966969
moduleName: moduleOutputInfo.name)
970+
let givenPackageInterfacePath = try Self.computeSupplementaryOutputPath(
971+
&parsedOptions, type: .packageSwiftInterface, isOutputOptions: [],
972+
outputPath: .emitPackageModuleInterfacePath,
973+
compilerOutputType: compilerOutputType,
974+
compilerMode: compilerMode,
975+
emitModuleSeparately: emitModuleSeparately,
976+
outputFileMap: self.outputFileMap,
977+
moduleName: moduleOutputInfo.name)
967978

968979
// Always emitting private swift interfaces if public interfaces are emitted.'
969980
// With the introduction of features like @_spi_available, we may print public
@@ -978,6 +989,22 @@ public struct Driver {
978989
self.swiftPrivateInterfacePath = givenPrivateInterfacePath
979990
}
980991

992+
if let packageNameInput = parsedOptions.getLastArgument(Option.packageName),
993+
!packageNameInput.asSingle.isEmpty {
994+
// Generate a package interface if built with `-package-name` required for decls
995+
// with the `package` access level. The .package.swiftinterface contains package
996+
// decls as well as SPI and public decls (superset of a private interface).
997+
if let publicInterfacePath = self.swiftInterfacePath,
998+
givenPackageInterfacePath == nil {
999+
self.swiftPackageInterfacePath = try VirtualPath.lookup(publicInterfacePath)
1000+
.replacingExtension(with: .packageSwiftInterface).intern()
1001+
} else {
1002+
self.swiftPackageInterfacePath = givenPackageInterfacePath
1003+
}
1004+
} else {
1005+
self.swiftPackageInterfacePath = nil
1006+
}
1007+
9811008
var optimizationRecordFileType = FileType.yamlOptimizationRecord
9821009
if let argument = parsedOptions.getLastArgument(.saveOptimizationRecordEQ)?.asSingle {
9831010
switch argument {
@@ -2546,7 +2573,7 @@ extension Driver {
25462573
moduleOutputKind = .auxiliary
25472574
} else if parsedOptions.hasArgument(.emitObjcHeader, .emitObjcHeaderPath,
25482575
.emitModuleInterface, .emitModuleInterfacePath,
2549-
.emitPrivateModuleInterfacePath) {
2576+
.emitPrivateModuleInterfacePath, .emitPackageModuleInterfacePath) {
25502577
// An option has been passed which requires whole-module knowledge, but we
25512578
// don't have that. Generate a module, but treat it as an intermediate
25522579
// output.

Sources/SwiftDriver/Jobs/CompileJob.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ extension Driver {
9292
case .swiftModule:
9393
return compilerMode.isSingleCompilation && moduleOutputInfo.output?.isTopLevel ?? false
9494
case .swift, .image, .dSYM, .dependencies, .emitModuleDependencies, .autolink,
95-
.swiftDocumentation, .swiftInterface, .privateSwiftInterface, .swiftSourceInfoFile,
95+
.swiftDocumentation, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface, .swiftSourceInfoFile,
9696
.diagnostics, .emitModuleDiagnostics, .objcHeader, .swiftDeps, .remap, .tbd,
9797
.moduleTrace, .yamlOptimizationRecord, .bitstreamOptimizationRecord, .pcm, .pch,
9898
.clangModuleMap, .jsonCompilerFeatures, .jsonTargetInfo, .jsonSwiftArtifacts,
@@ -470,7 +470,7 @@ extension FileType {
470470
case .swift, .dSYM, .autolink, .dependencies, .emitModuleDependencies,
471471
.swiftDocumentation, .pcm, .diagnostics, .emitModuleDiagnostics,
472472
.objcHeader, .image, .swiftDeps, .moduleTrace, .tbd, .yamlOptimizationRecord,
473-
.bitstreamOptimizationRecord, .swiftInterface, .privateSwiftInterface,
473+
.bitstreamOptimizationRecord, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface,
474474
.swiftSourceInfoFile, .clangModuleMap, .jsonSwiftArtifacts,
475475
.indexUnitOutputPath, .modDepCache, .jsonAPIBaseline, .jsonABIBaseline,
476476
.swiftConstValues, .jsonAPIDescriptor, .moduleSummary, .moduleSemanticInfo,

Sources/SwiftDriver/Jobs/EmitModuleJob.swift

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ extension Driver {
3232
addSupplementalOutput(path: moduleSourceInfoPath, flag: "-emit-module-source-info-path", type: .swiftSourceInfoFile)
3333
addSupplementalOutput(path: swiftInterfacePath, flag: "-emit-module-interface-path", type: .swiftInterface)
3434
addSupplementalOutput(path: swiftPrivateInterfacePath, flag: "-emit-private-module-interface-path", type: .privateSwiftInterface)
35+
if let pkgName = packageName, !pkgName.isEmpty {
36+
addSupplementalOutput(path: swiftPackageInterfacePath, flag: "-emit-package-module-interface-path", type: .packageSwiftInterface)
37+
}
3538
addSupplementalOutput(path: objcGeneratedHeaderPath, flag: "-emit-objc-header-path", type: .objcHeader)
3639
addSupplementalOutput(path: tbdPath, flag: "-emit-tbd-path", type: .tbd)
3740
addSupplementalOutput(path: apiDescriptorFilePath, flag: "-emit-api-descriptor-path", type: .jsonAPIDescriptor)

Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift

+8
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ extension Driver {
233233
try commandLine.appendLast(.debugDiagnosticNames, from: &parsedOptions)
234234
try commandLine.appendLast(.scanDependencies, from: &parsedOptions)
235235
try commandLine.appendLast(.enableExperimentalConcisePoundFile, from: &parsedOptions)
236+
try commandLine.appendLast(.experimentalPackageInterfaceLoad, from: &parsedOptions)
236237
try commandLine.appendLast(.printEducationalNotes, from: &parsedOptions)
237238
try commandLine.appendLast(.diagnosticStyle, from: &parsedOptions)
238239
try commandLine.appendLast(.locale, from: &parsedOptions)
@@ -587,6 +588,13 @@ extension Driver {
587588
input: nil,
588589
flag: "-emit-private-module-interface-path")
589590

591+
if let pkgName = packageName, !pkgName.isEmpty {
592+
try addOutputOfType(
593+
outputType: .packageSwiftInterface,
594+
finalOutputPath: swiftPackageInterfacePath,
595+
input: nil,
596+
flag: "-emit-package-module-interface-path")
597+
}
590598
try addOutputOfType(
591599
outputType: .tbd,
592600
finalOutputPath: tbdPath,

Sources/SwiftDriver/Jobs/Planning.swift

+24-9
Original file line numberDiff line numberDiff line change
@@ -571,15 +571,29 @@ extension Driver {
571571

572572
let optIn = env["ENABLE_DEFAULT_INTERFACE_VERIFIER"] != nil ||
573573
parsedOptions.hasArgument(.verifyEmittedModuleInterface)
574-
func addVerifyJob(forPrivate: Bool) throws {
575-
let isNeeded =
576-
forPrivate
577-
? parsedOptions.hasArgument(.emitPrivateModuleInterfacePath)
578-
: parsedOptions.hasArgument(.emitModuleInterface, .emitModuleInterfacePath)
574+
575+
enum InterfaceMode {
576+
case Public, Private, Package
577+
}
578+
579+
func addVerifyJob(for mode: InterfaceMode) throws {
580+
var isNeeded = false
581+
var outputType: FileType
582+
583+
switch mode {
584+
case .Public:
585+
isNeeded = parsedOptions.hasArgument(.emitModuleInterface, .emitModuleInterfacePath)
586+
outputType = FileType.swiftInterface
587+
case .Private:
588+
isNeeded = parsedOptions.hasArgument(.emitPrivateModuleInterfacePath)
589+
outputType = .privateSwiftInterface
590+
case .Package:
591+
isNeeded = parsedOptions.hasArgument(.emitPackageModuleInterfacePath)
592+
outputType = .packageSwiftInterface
593+
}
594+
579595
guard isNeeded else { return }
580596

581-
let outputType: FileType =
582-
forPrivate ? .privateSwiftInterface : .swiftInterface
583597
let mergeInterfaceOutputs = emitModuleJob.outputs.filter { $0.type == outputType }
584598
assert(mergeInterfaceOutputs.count == 1,
585599
"Merge module job should only have one swiftinterface output")
@@ -588,8 +602,9 @@ extension Driver {
588602
optIn: optIn)
589603
addJob(job)
590604
}
591-
try addVerifyJob(forPrivate: false)
592-
try addVerifyJob(forPrivate: true)
605+
try addVerifyJob(for: .Public)
606+
try addVerifyJob(for: .Private)
607+
try addVerifyJob(for: .Package)
593608
}
594609

595610
private mutating func addAutolinkExtractJob(

Sources/SwiftDriver/Jobs/PrebuiltModulesJob.swift

+2
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ public class SwiftAdopter: Codable {
353353
public let moduleDir: String
354354
public let hasInterface: Bool
355355
public let hasPrivateInterface: Bool
356+
public let hasPackageInterface: Bool
356357
public let hasModule: Bool
357358
public let isFramework: Bool
358359
public let isPrivate: Bool
@@ -364,6 +365,7 @@ public class SwiftAdopter: Codable {
364365
self.moduleDir = SwiftAdopter.relativeToSDK(moduleDir)
365366
self.hasInterface = !hasInterface.isEmpty
366367
self.hasPrivateInterface = hasInterface.contains { $0.basename.hasSuffix(".private.swiftinterface") }
368+
self.hasPackageInterface = hasInterface.contains { $0.basename.hasSuffix(".package.swiftinterface") }
367369
self.hasModule = !hasModule.isEmpty
368370
self.isFramework = self.moduleDir.contains("\(name).framework")
369371
self.isPrivate = self.moduleDir.contains("PrivateFrameworks")

Sources/SwiftDriver/Jobs/VerifyModuleInterfaceJob.swift

+6-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
extension Driver {
1414
mutating func computeCacheKeyForInterface(emitModuleJob: Job,
1515
interfaceKind: FileType) throws -> String? {
16-
assert(interfaceKind == .swiftInterface || interfaceKind == .privateSwiftInterface,
16+
assert(interfaceKind == .swiftInterface || interfaceKind == .privateSwiftInterface || interfaceKind == .packageSwiftInterface,
1717
"only expect interface output kind")
1818
let isNeeded = emitModuleJob.outputs.contains { $0.type == interfaceKind }
1919
guard isCachingEnabled && isNeeded else { return nil }
@@ -54,11 +54,14 @@ extension Driver {
5454
}
5555

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

61-
let cacheKeys = try computeOutputCacheKeyForJob(commandLine: commandLine, inputs: [interfaceInput])
64+
let cacheKeys = try computeOutputCacheKeyForJob(commandLine: commandLine, inputs: [interfaceInput])
6265
return Job(
6366
moduleName: moduleOutputInfo.name,
6467
kind: .verifyModuleInterface,

Sources/SwiftDriver/Utilities/FileType.swift

+12-4
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ public enum FileType: String, Hashable, CaseIterable, Codable {
5454
/// An SPI Swift Interface file.
5555
case privateSwiftInterface = "private.swiftinterface"
5656

57+
/// An interface file containng package decls as well as SPI and public decls.
58+
case packageSwiftInterface = "package.swiftinterface"
59+
5760
/// Serialized source information.
5861
case swiftSourceInfoFile = "swiftsourceinfo"
5962

@@ -194,6 +197,9 @@ extension FileType: CustomStringConvertible {
194197
case .privateSwiftInterface:
195198
return "private-swiftinterface"
196199

200+
case .packageSwiftInterface:
201+
return "package-swiftinterface"
202+
197203
case .objcHeader:
198204
return "objc-header"
199205

@@ -275,7 +281,7 @@ extension FileType {
275281
.emitModuleDependencies, .swiftDocumentation, .pcm, .diagnostics,
276282
.emitModuleDiagnostics, .objcHeader, .image, .swiftDeps, .moduleTrace,
277283
.tbd, .yamlOptimizationRecord, .bitstreamOptimizationRecord,
278-
.swiftInterface, .privateSwiftInterface, .swiftSourceInfoFile,
284+
.swiftInterface, .privateSwiftInterface, .packageSwiftInterface, .swiftSourceInfoFile,
279285
.jsonDependencies, .clangModuleMap, .jsonTargetInfo, .jsonCompilerFeatures,
280286
.jsonSwiftArtifacts, .indexUnitOutputPath, .modDepCache, .jsonAPIBaseline,
281287
.jsonABIBaseline, .swiftConstValues, .jsonAPIDescriptor,
@@ -324,6 +330,8 @@ extension FileType {
324330
return "swiftinterface"
325331
case .privateSwiftInterface:
326332
return "private-swiftinterface"
333+
case .packageSwiftInterface:
334+
return "package-swiftinterface"
327335
case .swiftSourceInfoFile:
328336
return "swiftsourceinfo"
329337
case .clangModuleMap:
@@ -401,7 +409,7 @@ extension FileType {
401409
switch self {
402410
case .swift, .sil, .dependencies, .emitModuleDependencies, .assembly, .ast,
403411
.raw_sil, .llvmIR,.objcHeader, .autolink, .importedModules, .tbd,
404-
.moduleTrace, .yamlOptimizationRecord, .swiftInterface, .privateSwiftInterface,
412+
.moduleTrace, .yamlOptimizationRecord, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface,
405413
.jsonDependencies, .clangModuleMap, .jsonCompilerFeatures, .jsonTargetInfo,
406414
.jsonSwiftArtifacts, .jsonAPIBaseline, .jsonABIBaseline, .swiftConstValues,
407415
.jsonAPIDescriptor, .moduleSummary, .moduleSemanticInfo, .cachedDiagnostics:
@@ -422,7 +430,7 @@ extension FileType {
422430
return true
423431
case .swift, .sil, .sib, .ast, .image, .dSYM, .dependencies, .emitModuleDependencies,
424432
.autolink, .swiftModule, .swiftDocumentation, .swiftInterface,
425-
.privateSwiftInterface, .swiftSourceInfoFile, .raw_sil, .raw_sib,
433+
.privateSwiftInterface, .packageSwiftInterface, .swiftSourceInfoFile, .raw_sil, .raw_sib,
426434
.diagnostics, .emitModuleDiagnostics, .objcHeader, .swiftDeps, .remap,
427435
.importedModules, .tbd, .moduleTrace, .indexData, .yamlOptimizationRecord,
428436
.modDepCache, .bitstreamOptimizationRecord, .pcm, .pch, .jsonDependencies,
@@ -445,7 +453,7 @@ extension FileType {
445453
return false
446454
case .assembly, .llvmIR, .llvmBitcode, .object, .sil, .sib, .ast,
447455
.dependencies, .emitModuleDependencies, .swiftModule,
448-
.swiftDocumentation, .swiftInterface, .privateSwiftInterface,
456+
.swiftDocumentation, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface,
449457
.swiftSourceInfoFile, .raw_sil, .raw_sib, .objcHeader, .swiftDeps, .tbd,
450458
.moduleTrace, .indexData, .yamlOptimizationRecord,
451459
.bitstreamOptimizationRecord, .pcm, .pch, .jsonDependencies,

Sources/SwiftOptions/Options.swift

+4
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ extension Option {
327327
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>")
328328
public static let emitObjcHeader: Option = Option("-emit-objc-header", .flag, attributes: [.frontend, .noInteractive, .supplementaryOutput], helpText: "Emit an Objective-C header file")
329329
public static let emitObject: Option = Option("-emit-object", .flag, attributes: [.frontend, .noInteractive, .doesNotAffectIncrementalBuild], helpText: "Emit object file(s) (-c)", group: .modes)
330+
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>")
330331
public static let emitParseableModuleInterfacePath: Option = Option("-emit-parseable-module-interface-path", .separate, alias: Option.emitModuleInterfacePath, attributes: [.helpHidden, .frontend, .noInteractive, .argumentIsPath, .supplementaryOutput, .cacheInvariant])
331332
public static let emitParseableModuleInterface: Option = Option("-emit-parseable-module-interface", .flag, alias: Option.emitModuleInterface, attributes: [.helpHidden, .noInteractive, .supplementaryOutput])
332333
public static let emitParse: Option = Option("-emit-parse", .flag, alias: Option.dumpParse, attributes: [.frontend, .noInteractive, .doesNotAffectIncrementalBuild])
@@ -455,6 +456,7 @@ extension Option {
455456
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")
456457
public static let experimentalLazyTypecheck: Option = Option("-experimental-lazy-typecheck", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Type-check lazily as needed to produce requested outputs")
457458
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")
459+
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")
458460
public static let ExperimentalPerformanceAnnotations: Option = Option("-experimental-performance-annotations", .flag, attributes: [.helpHidden, .frontend], helpText: "Deprecated, has no effect")
459461
public static let platformCCallingConventionEQ: Option = Option("-experimental-platform-c-calling-convention=", .joined, alias: Option.platformCCallingConvention, attributes: [.helpHidden, .frontend, .noDriver])
460462
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.")
@@ -1149,6 +1151,7 @@ extension Option {
11491151
Option.emitObjcHeaderPath,
11501152
Option.emitObjcHeader,
11511153
Option.emitObject,
1154+
Option.emitPackageModuleInterfacePath,
11521155
Option.emitParseableModuleInterfacePath,
11531156
Option.emitParseableModuleInterface,
11541157
Option.emitParse,
@@ -1277,6 +1280,7 @@ extension Option {
12771280
Option.experimentalHermeticSealAtLink,
12781281
Option.experimentalLazyTypecheck,
12791282
Option.experimentalOneWayClosureParams,
1283+
Option.experimentalPackageInterfaceLoad,
12801284
Option.ExperimentalPerformanceAnnotations,
12811285
Option.platformCCallingConventionEQ,
12821286
Option.platformCCallingConvention,

Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift

+2
Original file line numberDiff line numberDiff line change
@@ -2086,13 +2086,15 @@ final class ExplicitModuleBuildTests: XCTestCase {
20862086
XCTAssertFalse(A.isPrivate)
20872087
XCTAssertFalse(A.hasModule)
20882088
XCTAssertFalse(A.hasPrivateInterface)
2089+
XCTAssertFalse(A.hasPackageInterface)
20892090
XCTAssertTrue(A.hasInterface)
20902091

20912092
let B = adopters.first {$0.name == "B"}!
20922093
XCTAssertTrue(B.isFramework)
20932094
XCTAssertFalse(B.isPrivate)
20942095
XCTAssertFalse(B.hasModule)
20952096
XCTAssertTrue(B.hasPrivateInterface)
2097+
XCTAssertFalse(B.hasPackageInterface)
20962098
}
20972099

20982100
func testCollectSwiftAdoptersWhetherMixed() throws {

0 commit comments

Comments
 (0)