Skip to content

Commit 8b96d1b

Browse files
committed
SwiftDriver: handle -libc on Windows
Windows has a special flag `-libc` that is responsible for determining the libc variant (ABI flavour) to link against. This flag defaults to `MD` if unspecified. We did not replicate the behaviour from the C++ implementation of the Swift driver to the Swift implementation of the driver which prevented the use of the early swift-driver.
1 parent 3668c9f commit 8b96d1b

9 files changed

+105
-8
lines changed

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public extension Driver {
115115
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .scanDependencies,
116116
bridgingHeaderHandling: .parsed,
117117
moduleDependencyGraphUse: .dependencyScan)
118-
// FIXME: MSVC runtime flags
118+
try addRuntimeLibraryFlags(commandLine: &commandLine)
119119

120120
// Pass in external target dependencies to be treated as placeholder dependencies by the scanner
121121
if let externalTargetDetailsMap = externalTargetModuleDetailsMap,
@@ -355,7 +355,7 @@ public extension Driver {
355355
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .scanDependencies,
356356
bridgingHeaderHandling: .parsed,
357357
moduleDependencyGraphUse: .dependencyScan)
358-
// FIXME: MSVC runtime flags
358+
try addRuntimeLibraryFlags(commandLine: &commandLine)
359359

360360
// Pass on the input files
361361
commandLine.append(contentsOf: inputFiles.map { .path($0.file) })

Sources/SwiftDriver/Jobs/CompileJob.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,7 @@ extension Driver {
293293
}
294294

295295
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .compile)
296-
297-
// FIXME: MSVC runtime flags
296+
try addRuntimeLibraryFlags(commandLine: &commandLine)
298297

299298
if Driver.canDoCrossModuleOptimization(parsedOptions: &parsedOptions) &&
300299
// For historical reasons, -cross-module-optimization turns on "aggressive" CMO

Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,61 @@ extension Driver {
583583
}
584584
}
585585

586+
mutating func addRuntimeLibraryFlags(commandLine: inout [Job.ArgTemplate]) throws {
587+
guard targetTriple.isWindows else { return }
588+
589+
enum RuntimeFlavour {
590+
case MT
591+
case MTd
592+
case MD
593+
case MDd
594+
}
595+
596+
let option = parsedOptions.getLastArgument(.libc)
597+
598+
// NOTE: default to `/MD`. This is different from `cl`'s default behaviour
599+
// of `/MT` on the command line, however, Visual Studio 2015 and newer will
600+
// default `/MD` as well. Furthermore, this is far more useful of a mode
601+
// since the `/MT` mode requires that everything is statically linked.
602+
let runtime: RuntimeFlavour? = switch (option?.asSingle ?? "MD") {
603+
case "MD", "MultiThreadedDLL", "shared-ucrt":
604+
.MD
605+
case "MDd", "MultiThreadedDebugDLL", "shared-debug-ucrt":
606+
.MDd
607+
case "MT", "MultiThreaded", "static-ucrt":
608+
.MT
609+
case "MTd", "MultiThreadedDebug", "static-debug-ucrt":
610+
.MTd
611+
default:
612+
nil
613+
}
614+
615+
guard let runtime else {
616+
diagnosticEngine.emit(.error_invalid_arg_value(arg: .libc, value: option!.asSingle))
617+
return
618+
}
619+
620+
commandLine.appendFlag(.autolinkLibrary)
621+
commandLine.appendFlag("oldnames")
622+
623+
commandLine.appendFlag(.autolinkLibrary)
624+
let name = switch (runtime) {
625+
case .MD: "msvcrt"
626+
case .MDd: "msvcrtd"
627+
case .MT: "libcmt"
628+
case .MTd: "libcmtd"
629+
}
630+
commandLine.appendFlag(name)
631+
632+
commandLine.appendFlag(.Xcc)
633+
commandLine.appendFlag("-D_MT")
634+
635+
if [.MD, .MDd].contains(runtime) {
636+
commandLine.appendFlag(.Xcc)
637+
commandLine.appendFlag("-D_DLL")
638+
}
639+
}
640+
586641
mutating func addBridgingHeaderPCHCacheKeyArguments(commandLine: inout [Job.ArgTemplate],
587642
pchCompileJob: Job?) throws {
588643
guard let pchJob = pchCompileJob, isCachingEnabled else { return }

Sources/SwiftDriver/Jobs/GeneratePCHJob.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ extension Driver {
3636
} else {
3737
try addGeneratePCHFlags(commandLine: &commandLine, inputs: &inputs)
3838
}
39+
try addRuntimeLibraryFlags(commandLine: &commandLine)
3940

4041
// TODO: Should this just be pch output with extension changed?
4142
if parsedOptions.hasArgument(.serializeDiagnostics), let outputDirectory = parsedOptions.getLastArgument(.pchOutputDir)?.asSingle {

Sources/SwiftDriver/Jobs/InterpretJob.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ extension Driver {
2828
}
2929

3030
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .interpret)
31-
// FIXME: MSVC runtime flags
31+
try addRuntimeLibraryFlags(commandLine: &commandLine)
3232

3333
try commandLine.appendLast(.parseSil, from: &parsedOptions)
3434
toolchain.addLinkedLibArgs(to: &commandLine, parsedOptions: &parsedOptions)

Sources/SwiftDriver/Jobs/MergeModuleJob.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ extension Driver {
5555
commandLine.appendFlag(.disableSilPerfOptzns)
5656

5757
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .mergeModule, bridgingHeaderHandling: .parsed)
58-
// FIXME: Add MSVC runtime library flags
58+
try addRuntimeLibraryFlags(commandLine: &commandLine)
5959

6060
try addCommonModuleOptions(commandLine: &commandLine, outputs: &outputs, moduleOutputPaths: moduleOutputPaths, isMergeModule: true)
6161

Sources/SwiftDriver/Jobs/ReplJob.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ extension Driver {
1616
var inputs: [TypedVirtualPath] = []
1717

1818
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .repl)
19-
// FIXME: MSVC runtime flags
19+
try addRuntimeLibraryFlags(commandLine: &commandLine)
2020

2121
try commandLine.appendLast(.importObjcHeader, from: &parsedOptions)
2222
toolchain.addLinkedLibArgs(

Sources/SwiftDriver/Jobs/VerifyModuleInterfaceJob.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ extension Driver {
3636
commandLine.appendFlags("-frontend", "-typecheck-module-from-interface")
3737
try addPathArgument(interfaceInput.file, to: &commandLine)
3838
try addCommonFrontendOptions(commandLine: &commandLine, inputs: &inputs, kind: .verifyModuleInterface, bridgingHeaderHandling: .ignored)
39-
// FIXME: MSVC runtime flags
39+
try addRuntimeLibraryFlags(commandLine: &commandLine)
4040

4141
// Output serialized diagnostics for this job, if specifically requested
4242
var outputs: [TypedVirtualPath] = []

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8268,6 +8268,48 @@ final class SwiftDriverTests: XCTestCase {
82688268
XCTAssertFalse(driver.diagnosticEngine.hasErrors)
82698269
}
82708270
}
8271+
8272+
func testWindowsRuntimeLibraryFlags() throws {
8273+
do {
8274+
var driver = try Driver(args: ["swiftc", "-target", "x86_64-unknown-windows-msvc", "-libc", "MD", "-use-ld=lld", "-c", "input.swift"])
8275+
let jobs = try driver.planBuild()
8276+
8277+
XCTAssertEqual(jobs.count, 1)
8278+
XCTAssertEqual(jobs[0].kind, .compile)
8279+
8280+
XCTAssertJobInvocationMatches(jobs[0], .flag("-autolink-library"), .flag("oldnames"), .flag("-autolink-library"), .flag("msvcrt"), .flag("-Xcc"), .flag("-D_MT"), .flag("-Xcc"), .flag("-D_DLL"))
8281+
}
8282+
8283+
do {
8284+
var driver = try Driver(args: ["swiftc", "-target", "x86_64-unknown-windows-msvc", "-use-ld=lld", "-c", "input.swift"])
8285+
let jobs = try driver.planBuild()
8286+
8287+
XCTAssertEqual(jobs.count, 1)
8288+
XCTAssertEqual(jobs[0].kind, .compile)
8289+
8290+
XCTAssertJobInvocationMatches(jobs[0], .flag("-autolink-library"), .flag("oldnames"), .flag("-autolink-library"), .flag("msvcrt"), .flag("-Xcc"), .flag("-D_MT"), .flag("-Xcc"), .flag("-D_DLL"))
8291+
}
8292+
8293+
do {
8294+
var driver = try Driver(args: ["swiftc", "-target", "x86_64-unknown-windows-msvc", "-libc", "MultiThreadedDLL", "-use-ld=lld", "-c", "input.swift"])
8295+
let jobs = try driver.planBuild()
8296+
8297+
XCTAssertEqual(jobs.count, 1)
8298+
XCTAssertEqual(jobs[0].kind, .compile)
8299+
8300+
XCTAssertJobInvocationMatches(jobs[0], .flag("-autolink-library"), .flag("oldnames"), .flag("-autolink-library"), .flag("msvcrt"), .flag("-Xcc"), .flag("-D_MT"), .flag("-Xcc"), .flag("-D_DLL"))
8301+
}
8302+
8303+
do {
8304+
var driver = try Driver(args: ["swiftc", "-target", "x86_64-unknown-windows-msvc", "-libc", "MTd", "-use-ld=lld", "-c", "input.swift"])
8305+
let jobs = try driver.planBuild()
8306+
8307+
XCTAssertEqual(jobs.count, 1)
8308+
XCTAssertEqual(jobs[0].kind, .compile)
8309+
8310+
XCTAssertJobInvocationMatches(jobs[0], .flag("-autolink-library"), .flag("oldnames"), .flag("-autolink-library"), .flag("libcmtd"), .flag("-Xcc"), .flag("-D_MT"))
8311+
}
8312+
}
82718313
}
82728314

82738315
func assertString(

0 commit comments

Comments
 (0)