Skip to content

Commit 99eb72f

Browse files
committed
Emit variant module
This patch wires up emitting the interface information for the target variant in the same swiftc invocation that emits the zippered object file.
1 parent 0055bc6 commit 99eb72f

File tree

5 files changed

+139
-15
lines changed

5 files changed

+139
-15
lines changed

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,9 @@ public struct Driver {
259259
/// The information about the module to produce.
260260
@_spi(Testing) public let moduleOutputInfo: ModuleOutputInfo
261261

262+
/// Information about the target variant module to produce if applicable
263+
@_spi(Testing) public let variantModuleOutputInfo: ModuleOutputInfo?
264+
262265
/// Name of the package containing a target module or file.
263266
@_spi(Testing) public let packageName: String?
264267

@@ -494,6 +497,9 @@ public struct Driver {
494497
/// Structure storing paths to supplemental outputs for the target module
495498
let moduleOutputPaths: SupplementalModuleTargetOutputPaths
496499

500+
/// Structure storing paths to supplemental outputs for the target variant
501+
let variantModuleOutputPaths: SupplementalModuleTargetOutputPaths?
502+
497503
/// File type for the optimization record.
498504
let optimizationRecordFileType: FileType?
499505

@@ -946,10 +952,24 @@ public struct Driver {
946952

947953
// Determine the module we're building and whether/how the module file itself will be emitted.
948954
self.moduleOutputInfo = try Self.computeModuleInfo(
949-
&parsedOptions, compilerOutputType: compilerOutputType, compilerMode: compilerMode, linkerOutputType: linkerOutputType,
950-
debugInfoLevel: debugInfo.level, diagnosticsEngine: diagnosticEngine,
955+
&parsedOptions,
956+
modulePath: parsedOptions.getLastArgument(.emitModulePath)?.asSingle,
957+
compilerOutputType: compilerOutputType,
958+
compilerMode: compilerMode,
959+
linkerOutputType: linkerOutputType,
960+
debugInfoLevel: debugInfo.level,
961+
diagnosticsEngine: diagnosticEngine,
951962
workingDirectory: self.workingDirectory)
952963

964+
self.variantModuleOutputInfo = try Self.computeVariantModuleInfo(
965+
&parsedOptions,
966+
compilerOutputType: compilerOutputType,
967+
compilerMode: compilerMode,
968+
linkerOutputType: linkerOutputType,
969+
debugInfoLevel: debugInfo.level,
970+
diagnosticsEngine: diagnosticsEngine,
971+
workingDirectory: workingDirectory)
972+
953973
// Should we schedule a separate emit-module job?
954974
self.emitModuleSeparately = Self.computeEmitModuleSeparately(parsedOptions: &parsedOptions,
955975
compilerMode: compilerMode,
@@ -1142,6 +1162,21 @@ public struct Driver {
11421162
outputFileMap: self.outputFileMap,
11431163
projectDirectory: projectDirectory)
11441164

1165+
if let variantModuleOutputInfo = self.variantModuleOutputInfo {
1166+
self.variantModuleOutputPaths = try Self.computeModuleOutputPaths(
1167+
&parsedOptions,
1168+
moduleName: variantModuleOutputInfo.name,
1169+
packageName: self.packageName,
1170+
moduleOutputInfo: variantModuleOutputInfo,
1171+
compilerOutputType: compilerOutputType,
1172+
compilerMode: compilerMode,
1173+
emitModuleSeparately: true, // variant module is always independent
1174+
outputFileMap: self.outputFileMap,
1175+
projectDirectory: projectDirectory)
1176+
} else {
1177+
self.variantModuleOutputPaths = nil
1178+
}
1179+
11451180
self.digesterBaselinePath = try Self.computeDigesterBaselineOutputPath(
11461181
&parsedOptions,
11471182
moduleOutputPath: self.moduleOutputInfo.output?.outputPath,
@@ -2673,9 +2708,37 @@ extension Driver {
26732708
return ""
26742709
}
26752710

2711+
private static func computeVariantModuleInfo(
2712+
_ parsedOptions: inout ParsedOptions,
2713+
compilerOutputType: FileType?,
2714+
compilerMode: CompilerMode,
2715+
linkerOutputType: LinkOutputType?,
2716+
debugInfoLevel: DebugInfo.Level?,
2717+
diagnosticsEngine: DiagnosticsEngine,
2718+
workingDirectory: AbsolutePath?
2719+
) throws -> ModuleOutputInfo? {
2720+
// If there is no target variant, then there is no target variant module.
2721+
// If there is no emit-variant-module, then there is not target variant
2722+
// module.
2723+
guard let variantModulePath = parsedOptions.getLastArgument(.emitVariantModulePath),
2724+
parsedOptions.hasArgument(.targetVariant) else {
2725+
return nil
2726+
}
2727+
return try computeModuleInfo(&parsedOptions,
2728+
modulePath: variantModulePath.asSingle,
2729+
compilerOutputType: compilerOutputType,
2730+
compilerMode: compilerMode,
2731+
linkerOutputType: linkerOutputType,
2732+
debugInfoLevel: debugInfoLevel,
2733+
diagnosticsEngine: diagnosticsEngine,
2734+
workingDirectory: workingDirectory)
2735+
return nil
2736+
}
2737+
26762738
/// Determine how the module will be emitted and the name of the module.
26772739
private static func computeModuleInfo(
26782740
_ parsedOptions: inout ParsedOptions,
2741+
modulePath: String?,
26792742
compilerOutputType: FileType?,
26802743
compilerMode: CompilerMode,
26812744
linkerOutputType: LinkOutputType?,
@@ -2690,7 +2753,7 @@ extension Driver {
26902753
}
26912754

26922755
var moduleOutputKind: ModuleOutputKind?
2693-
if parsedOptions.hasArgument(.emitModule, .emitModulePath) {
2756+
if parsedOptions.hasArgument(.emitModule) || modulePath != nil {
26942757
// The user has requested a module, so generate one and treat it as
26952758
// top-level output.
26962759
moduleOutputKind = .topLevel
@@ -2772,9 +2835,9 @@ extension Driver {
27722835

27732836
// FIXME: Look in the output file map. It looks like it is weirdly
27742837
// anchored to the first input?
2775-
if let modulePathArg = parsedOptions.getLastArgument(.emitModulePath) {
2838+
if let modulePathArg = modulePath {
27762839
// The module path was specified.
2777-
moduleOutputPath = try VirtualPath(path: modulePathArg.asSingle)
2840+
moduleOutputPath = try VirtualPath(path: modulePathArg)
27782841
} else if moduleOutputKind == .topLevel {
27792842
// FIXME: Logic to infer from primary outputs, etc.
27802843
let moduleFilename = moduleName.appendingFileTypeExtension(.swiftModule)

Sources/SwiftDriver/Jobs/EmitModuleJob.swift

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,13 @@ extension Driver {
7979
}
8080

8181
/// Form a job that emits a single module
82-
@_spi(Testing) public mutating func emitModuleJob(pchCompileJob: Job?) throws -> Job {
83-
let moduleOutputPath = moduleOutputInfo.output!.outputPath
82+
@_spi(Testing) public mutating func emitModuleJob(pchCompileJob: Job?, isVariantJob: Bool = false) throws -> Job {
83+
precondition(!isVariantJob || (isVariantJob &&
84+
variantModuleOutputInfo != nil && variantModuleOutputPaths != nil),
85+
"target variant module requested without a target variant")
86+
87+
let moduleOutputPath = isVariantJob ? variantModuleOutputInfo!.output!.outputPath : moduleOutputInfo.output!.outputPath
88+
let moduleOutputPaths = isVariantJob ? variantModuleOutputPaths! : moduleOutputPaths
8489
var commandLine: [Job.ArgTemplate] = swiftCompilerPrefixArgs.map { Job.ArgTemplate.flag($0) }
8590
var inputs: [TypedVirtualPath] = []
8691
var outputs: [TypedVirtualPath] = [
@@ -103,7 +108,12 @@ extension Driver {
103108
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .emitModule)
104109
// FIXME: Add MSVC runtime library flags
105110

106-
try addCommonModuleOptions(commandLine: &commandLine, outputs: &outputs, moduleOutputPaths: moduleOutputPaths,isMergeModule: false)
111+
try addCommonModuleOptions(
112+
commandLine: &commandLine,
113+
outputs: &outputs,
114+
moduleOutputPaths: moduleOutputPaths,
115+
isMergeModule: false)
116+
107117
try addCommonSymbolGraphOptions(commandLine: &commandLine)
108118

109119
try commandLine.appendLast(.checkApiAvailabilityOnly, from: &parsedOptions)

Sources/SwiftDriver/Jobs/Planning.swift

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,21 @@ extension Driver {
256256
)
257257
}
258258

259-
private mutating func addEmitModuleJob(addJobBeforeCompiles: (Job) -> Void, pchCompileJob: Job?) throws -> Job? {
260-
if emitModuleSeparately {
261-
let emitJob = try emitModuleJob(pchCompileJob: pchCompileJob)
262-
addJobBeforeCompiles(emitJob)
263-
return emitJob
264-
}
265-
return nil
259+
private mutating func addEmitModuleJob(
260+
addJobBeforeCompiles: (Job) -> Void,
261+
pchCompileJob: Job?,
262+
isVariantModule: Bool = false) throws -> Job? {
263+
// The target variant module is always emitted separately, so we need to
264+
// add an explicit job regardless of whether the primary target was
265+
// emitted separately
266+
if emitModuleSeparately || isVariantModule {
267+
let emitJob = try emitModuleJob(
268+
pchCompileJob: pchCompileJob,
269+
isVariantJob: isVariantModule)
270+
addJobBeforeCompiles(emitJob)
271+
return emitJob
272+
}
273+
return nil
266274
}
267275

268276
private mutating func addJobsFeedingLinker(
@@ -337,6 +345,13 @@ extension Driver {
337345
addLinkerInput: addLinkerInput)
338346
}
339347

348+
if variantModuleOutputInfo != nil {
349+
_ = try addEmitModuleJob(
350+
addJobBeforeCompiles: addJobBeforeCompiles,
351+
pchCompileJob: jobCreatingPch,
352+
isVariantModule: true)
353+
}
354+
340355
try addJobsForPrimaryInputs(
341356
addCompileJobGroup: addCompileJobGroup,
342357
addModuleInput: addModuleInput,

Sources/SwiftOptions/Options.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,10 @@ extension Option {
926926
public static let Xlinker: Option = Option("-Xlinker", .separate, attributes: [.doesNotAffectIncrementalBuild], helpText: "Specifies an option which should be passed to the linker")
927927
public static let Xllvm: Option = Option("-Xllvm", .separate, attributes: [.helpHidden, .frontend], metaVar: "<arg>", helpText: "Pass <arg> to LLVM.")
928928
public static let DASHDASH: Option = Option("--", .remaining, attributes: [.frontend, .doesNotAffectIncrementalBuild])
929+
930+
public static let emitVariantModulePath: Option = Option("-emit-variant-module-path", .separate, attributes: [.noInteractive, .supplementaryOutput, .argumentIsPath], helpText: "Emit an importable module for the target variant at the specified path")
931+
public static let emitVariantModuleInterface: Option = Option("-emit-variant-module-interface", .flag, attributes: [.noInteractive, .supplementaryOutput], helpText: "Emit an importable module for the target variant")
932+
929933
}
930934

931935
extension Option {
@@ -1839,6 +1843,8 @@ extension Option {
18391843
Option.Xlinker,
18401844
Option.Xllvm,
18411845
Option.DASHDASH,
1846+
Option.emitVariantModulePath,
1847+
Option.emitVariantModuleInterface,
18421848
]
18431849
}
18441850
}

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4090,6 +4090,36 @@ final class SwiftDriverTests: XCTestCase {
40904090
}
40914091
}
40924092

4093+
func testTargetVariantEmitModule() throws {
4094+
do {
4095+
var driver = try Driver(args: ["swiftc",
4096+
"-target", "x86_64-apple-macosx10.14",
4097+
"-target-variant", "x86_64-apple-ios13.1-macabi",
4098+
"-enable-library-evolution",
4099+
"-emit-module",
4100+
"-emit-module-path", "foo.swiftmodule/target.swiftmodule",
4101+
"-emit-variant-module-path", "foo.swiftmodule/variant.swiftmodule",
4102+
"foo.swift"])
4103+
4104+
let plannedJobs = try driver.planBuild().removingAutolinkExtractJobs()
4105+
XCTAssertEqual(plannedJobs.count, 3)
4106+
4107+
let targetModuleJob = plannedJobs[0]
4108+
let variantModuleJob = plannedJobs[1]
4109+
4110+
XCTAssert(targetModuleJob.commandLine.contains(.flag("-emit-module")))
4111+
XCTAssert(variantModuleJob.commandLine.contains(.flag("-emit-module")))
4112+
4113+
XCTAssert(targetModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/target.swiftdoc")))))
4114+
XCTAssert(targetModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/target.swiftsourceinfo")))))
4115+
XCTAssertTrue(targetModuleJob.commandLine.contains(subsequence: [.flag("-o"), .path(.relative(try .init(validating: "foo.swiftmodule/target.swiftmodule")))]))
4116+
4117+
XCTAssert(variantModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/variant.swiftdoc")))))
4118+
XCTAssert(variantModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/variant.swiftsourceinfo")))))
4119+
XCTAssertTrue(variantModuleJob.commandLine.contains(subsequence: [.flag("-o"), .path(.relative(try .init(validating: "foo.swiftmodule/variant.swiftmodule")))]))
4120+
}
4121+
}
4122+
40934123
func testValidDeprecatedTargetiOS() throws {
40944124
var driver = try Driver(args: ["swiftc", "-emit-module", "-target", "armv7-apple-ios13.0", "foo.swift"])
40954125
let plannedJobs = try driver.planBuild()

0 commit comments

Comments
 (0)