Skip to content

Commit 70554a4

Browse files
authored
Merge pull request #1655 from hamishknight/windows-coverage
Pass `-lld-allow-duplicate-weak` for coverage on Windows
2 parents cac5980 + e206bfd commit 70554a4

File tree

2 files changed

+99
-9
lines changed

2 files changed

+99
-9
lines changed

Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,41 @@ extension WindowsToolchain {
3939
sanitizers: Set<Sanitizer>,
4040
targetInfo: FrontendTargetInfo)
4141
throws -> ResolvedTool {
42+
// Check to see whether we need to use lld as the linker.
43+
let requiresLLD = {
44+
if let ld = parsedOptions.getLastArgument(.useLd)?.asSingle {
45+
switch ld {
46+
case "lld", "lld.exe", "lld-link", "lld-link.exe":
47+
return true
48+
default:
49+
return false
50+
}
51+
}
52+
if lto != nil {
53+
return true
54+
}
55+
// Profiling currently relies on the ability to emit duplicate weak
56+
// symbols across translation units and having the linker coalesce them.
57+
// Unfortunately link.exe does not support this, so require lld-link
58+
// for now, which supports the behavior via a flag.
59+
// TODO: Once we've changed coverage to no longer rely on emitting
60+
// duplicate weak symbols (rdar://131295678), we can remove this.
61+
if parsedOptions.hasArgument(.profileGenerate) {
62+
return true
63+
}
64+
return false
65+
}()
66+
4267
// Special case static linking as clang cannot drive the operation.
4368
if linkerOutputType == .staticLibrary {
4469
let librarian: String
45-
switch parsedOptions.getLastArgument(.useLd)?.asSingle {
46-
case .none:
47-
librarian = lto == nil ? "link" : "lld-link"
48-
case .some("lld"), .some("lld.exe"), .some("lld-link"), .some("lld-link.exe"):
70+
if requiresLLD {
4971
librarian = "lld-link"
50-
case let .some(linker):
51-
librarian = linker
72+
} else if let ld = parsedOptions.getLastArgument(.useLd)?.asSingle {
73+
librarian = ld
74+
} else {
75+
librarian = "link"
5276
}
53-
5477
commandLine.appendFlag("/LIB")
5578
commandLine.appendFlag("/NOLOGO")
5679
commandLine.appendFlag("/OUT:\(outputFile.name.spm_shellEscaped())")
@@ -101,7 +124,7 @@ extension WindowsToolchain {
101124
// Select the linker to use.
102125
if let arg = parsedOptions.getLastArgument(.useLd)?.asSingle {
103126
commandLine.appendFlag("-fuse-ld=\(arg)")
104-
} else if lto != nil {
127+
} else if requiresLLD {
105128
commandLine.appendFlag("-fuse-ld=lld")
106129
}
107130

@@ -195,6 +218,13 @@ extension WindowsToolchain {
195218
// FIXME(compnerd) wrap llvm::getInstrProfRuntimeHookVarName()
196219
commandLine.appendFlag("-include:__llvm_profile_runtime")
197220
commandLine.appendFlag("-lclang_rt.profile")
221+
222+
// FIXME(rdar://131295678): Currently profiling requires the ability to
223+
// emit duplicate weak symbols. Assuming we're using lld, pass
224+
// -lld-allow-duplicate-weak to enable this behavior.
225+
if requiresLLD {
226+
commandLine.appendFlags("-Xlinker", "-lld-allow-duplicate-weak")
227+
}
198228
}
199229

200230
try addExtraClangLinkerArgs(to: &commandLine, parsedOptions: &parsedOptions)

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4401,7 +4401,67 @@ final class SwiftDriverTests: XCTestCase {
44014401
}
44024402
#endif
44034403

4404-
// TODO: Windows
4404+
for explicitUseLd in [true, false] {
4405+
var args = ["swiftc", "-profile-generate", "-target", "x86_64-unknown-windows-msvc", "test.swift"]
4406+
if explicitUseLd {
4407+
// Explicitly passing '-use-ld=lld' should still result in '-lld-allow-duplicate-weak'.
4408+
args.append("-use-ld=lld")
4409+
}
4410+
var driver = try Driver(args: args)
4411+
let plannedJobs = try driver.planBuild()
4412+
print(plannedJobs[1].commandLine)
4413+
4414+
XCTAssertEqual(plannedJobs.count, 2)
4415+
XCTAssertEqual(plannedJobs[0].kind, .compile)
4416+
4417+
XCTAssertEqual(plannedJobs[1].kind, .link)
4418+
4419+
let linkCmds = plannedJobs[1].commandLine
4420+
XCTAssert(linkCmds.contains(.flag("-include:__llvm_profile_runtime")))
4421+
XCTAssert(linkCmds.contains(.flag("-lclang_rt.profile")))
4422+
4423+
// rdar://131295678 - Make sure we force the use of lld and pass
4424+
// '-lld-allow-duplicate-weak'.
4425+
XCTAssert(linkCmds.contains(.flag("-fuse-ld=lld")))
4426+
XCTAssert(linkCmds.contains([.flag("-Xlinker"), .flag("-lld-allow-duplicate-weak")]))
4427+
}
4428+
4429+
do {
4430+
// If the user passes -use-ld for a non-lld linker, respect that and
4431+
// don't use '-lld-allow-duplicate-weak'
4432+
var driver = try Driver(args: ["swiftc", "-profile-generate", "-use-ld=link", "-target", "x86_64-unknown-windows-msvc", "test.swift"])
4433+
let plannedJobs = try driver.planBuild()
4434+
print(plannedJobs[1].commandLine)
4435+
4436+
XCTAssertEqual(plannedJobs.count, 2)
4437+
XCTAssertEqual(plannedJobs[0].kind, .compile)
4438+
4439+
XCTAssertEqual(plannedJobs[1].kind, .link)
4440+
4441+
let linkCmds = plannedJobs[1].commandLine
4442+
XCTAssert(linkCmds.contains(.flag("-include:__llvm_profile_runtime")))
4443+
XCTAssert(linkCmds.contains(.flag("-lclang_rt.profile")))
4444+
4445+
XCTAssertTrue(linkCmds.contains(.flag("-fuse-ld=link")))
4446+
XCTAssertFalse(linkCmds.contains(.flag("-fuse-ld=lld")))
4447+
XCTAssertFalse(linkCmds.contains(.flag("-lld-allow-duplicate-weak")))
4448+
}
4449+
4450+
do {
4451+
// If we're not building for profiling, don't add '-lld-allow-duplicate-weak'.
4452+
var driver = try Driver(args: ["swiftc", "-use-ld=lld", "-target", "x86_64-unknown-windows-msvc", "test.swift"])
4453+
let plannedJobs = try driver.planBuild()
4454+
print(plannedJobs[1].commandLine)
4455+
4456+
XCTAssertEqual(plannedJobs.count, 2)
4457+
XCTAssertEqual(plannedJobs[0].kind, .compile)
4458+
4459+
XCTAssertEqual(plannedJobs[1].kind, .link)
4460+
4461+
let linkCmds = plannedJobs[1].commandLine
4462+
XCTAssertTrue(linkCmds.contains(.flag("-fuse-ld=lld")))
4463+
XCTAssertFalse(linkCmds.contains(.flag("-lld-allow-duplicate-weak")))
4464+
}
44054465
}
44064466

44074467
func testConditionalCompilationArgValidation() throws {

0 commit comments

Comments
 (0)