Skip to content

Commit fd7fa72

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 1f86e98 commit fd7fa72

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,
@@ -2708,9 +2743,37 @@ extension Driver {
27082743
return ""
27092744
}
27102745

2746+
private static func computeVariantModuleInfo(
2747+
_ parsedOptions: inout ParsedOptions,
2748+
compilerOutputType: FileType?,
2749+
compilerMode: CompilerMode,
2750+
linkerOutputType: LinkOutputType?,
2751+
debugInfoLevel: DebugInfo.Level?,
2752+
diagnosticsEngine: DiagnosticsEngine,
2753+
workingDirectory: AbsolutePath?
2754+
) throws -> ModuleOutputInfo? {
2755+
// If there is no target variant, then there is no target variant module.
2756+
// If there is no emit-variant-module, then there is not target variant
2757+
// module.
2758+
guard let variantModulePath = parsedOptions.getLastArgument(.emitVariantModulePath),
2759+
parsedOptions.hasArgument(.targetVariant) else {
2760+
return nil
2761+
}
2762+
return try computeModuleInfo(&parsedOptions,
2763+
modulePath: variantModulePath.asSingle,
2764+
compilerOutputType: compilerOutputType,
2765+
compilerMode: compilerMode,
2766+
linkerOutputType: linkerOutputType,
2767+
debugInfoLevel: debugInfoLevel,
2768+
diagnosticsEngine: diagnosticsEngine,
2769+
workingDirectory: workingDirectory)
2770+
return nil
2771+
}
2772+
27112773
/// Determine how the module will be emitted and the name of the module.
27122774
private static func computeModuleInfo(
27132775
_ parsedOptions: inout ParsedOptions,
2776+
modulePath: String?,
27142777
compilerOutputType: FileType?,
27152778
compilerMode: CompilerMode,
27162779
linkerOutputType: LinkOutputType?,
@@ -2725,7 +2788,7 @@ extension Driver {
27252788
}
27262789

27272790
var moduleOutputKind: ModuleOutputKind?
2728-
if parsedOptions.hasArgument(.emitModule, .emitModulePath) {
2791+
if parsedOptions.hasArgument(.emitModule) || modulePath != nil {
27292792
// The user has requested a module, so generate one and treat it as
27302793
// top-level output.
27312794
moduleOutputKind = .topLevel
@@ -2807,9 +2870,9 @@ extension Driver {
28072870

28082871
// FIXME: Look in the output file map. It looks like it is weirdly
28092872
// anchored to the first input?
2810-
if let modulePathArg = parsedOptions.getLastArgument(.emitModulePath) {
2873+
if let modulePathArg = modulePath {
28112874
// The module path was specified.
2812-
moduleOutputPath = try VirtualPath(path: modulePathArg.asSingle)
2875+
moduleOutputPath = try VirtualPath(path: modulePathArg)
28132876
} else if moduleOutputKind == .topLevel {
28142877
// FIXME: Logic to infer from primary outputs, etc.
28152878
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
@@ -923,6 +923,10 @@ extension Option {
923923
public static let Xlinker: Option = Option("-Xlinker", .separate, attributes: [.doesNotAffectIncrementalBuild], helpText: "Specifies an option which should be passed to the linker")
924924
public static let Xllvm: Option = Option("-Xllvm", .separate, attributes: [.helpHidden, .frontend], metaVar: "<arg>", helpText: "Pass <arg> to LLVM.")
925925
public static let DASHDASH: Option = Option("--", .remaining, attributes: [.frontend, .doesNotAffectIncrementalBuild])
926+
927+
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")
928+
public static let emitVariantModuleInterface: Option = Option("-emit-variant-module-interface", .flag, attributes: [.noInteractive, .supplementaryOutput], helpText: "Emit an importable module for the target variant")
929+
926930
}
927931

928932
extension Option {
@@ -1832,6 +1836,8 @@ extension Option {
18321836
Option.Xlinker,
18331837
Option.Xllvm,
18341838
Option.DASHDASH,
1839+
Option.emitVariantModulePath,
1840+
Option.emitVariantModuleInterface,
18351841
]
18361842
}
18371843
}

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4068,6 +4068,36 @@ final class SwiftDriverTests: XCTestCase {
40684068
}
40694069
}
40704070

4071+
func testTargetVariantEmitModule() throws {
4072+
do {
4073+
var driver = try Driver(args: ["swiftc",
4074+
"-target", "x86_64-apple-macosx10.14",
4075+
"-target-variant", "x86_64-apple-ios13.1-macabi",
4076+
"-enable-library-evolution",
4077+
"-emit-module",
4078+
"-emit-module-path", "foo.swiftmodule/target.swiftmodule",
4079+
"-emit-variant-module-path", "foo.swiftmodule/variant.swiftmodule",
4080+
"foo.swift"])
4081+
4082+
let plannedJobs = try driver.planBuild().removingAutolinkExtractJobs()
4083+
XCTAssertEqual(plannedJobs.count, 3)
4084+
4085+
let targetModuleJob = plannedJobs[0]
4086+
let variantModuleJob = plannedJobs[1]
4087+
4088+
XCTAssert(targetModuleJob.commandLine.contains(.flag("-emit-module")))
4089+
XCTAssert(variantModuleJob.commandLine.contains(.flag("-emit-module")))
4090+
4091+
XCTAssert(targetModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/target.swiftdoc")))))
4092+
XCTAssert(targetModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/target.swiftsourceinfo")))))
4093+
XCTAssertTrue(targetModuleJob.commandLine.contains(subsequence: [.flag("-o"), .path(.relative(try .init(validating: "foo.swiftmodule/target.swiftmodule")))]))
4094+
4095+
XCTAssert(variantModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/variant.swiftdoc")))))
4096+
XCTAssert(variantModuleJob.commandLine.contains(.path(.relative(try .init(validating: "foo.swiftmodule/variant.swiftsourceinfo")))))
4097+
XCTAssertTrue(variantModuleJob.commandLine.contains(subsequence: [.flag("-o"), .path(.relative(try .init(validating: "foo.swiftmodule/variant.swiftmodule")))]))
4098+
}
4099+
}
4100+
40714101
func testValidDeprecatedTargetiOS() throws {
40724102
var driver = try Driver(args: ["swiftc", "-emit-module", "-target", "armv7-apple-ios13.0", "foo.swift"])
40734103
let plannedJobs = try driver.planBuild()

0 commit comments

Comments
 (0)