Skip to content

Commit 44507b2

Browse files
authored
Revert "Switch to using clang as linker on darwin"
1 parent e590576 commit 44507b2

File tree

5 files changed

+411
-120
lines changed

5 files changed

+411
-120
lines changed

Sources/SwiftDriver/Jobs/DarwinToolchain+LinkerSupport.swift

Lines changed: 214 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,153 @@ extension DarwinToolchain {
4747
return try findXcodeClangLibPath("arc")
4848
}
4949

50+
internal func addLTOLibArgs(to commandLine: inout [Job.ArgTemplate]) throws {
51+
if let path = try findXcodeClangLibPath("libLTO.dylib") {
52+
commandLine.appendFlag("-lto_library")
53+
commandLine.appendPath(path)
54+
}
55+
}
56+
57+
func addLinkRuntimeLibraryRPath(
58+
to commandLine: inout [Job.ArgTemplate],
59+
parsedOptions: inout ParsedOptions,
60+
targetInfo: FrontendTargetInfo,
61+
darwinLibName: String
62+
) throws {
63+
// Adding the rpaths might negatively interact when other rpaths are involved,
64+
// so we should make sure we add the rpaths last, after all user-specified
65+
// rpaths. This is currently true from this place, but we need to be
66+
// careful if this function is ever called before user's rpaths are emitted.
67+
assert(darwinLibName.hasSuffix(".dylib"), "must be a dynamic library")
68+
69+
// Add @executable_path to rpath to support having the dylib copied with
70+
// the executable.
71+
commandLine.appendFlag("-rpath")
72+
commandLine.appendFlag("@executable_path")
73+
74+
// Add the path to the resource dir to rpath to support using the dylib
75+
// from the default location without copying.
76+
77+
78+
let clangPath = try clangLibraryPath(
79+
for: targetInfo,
80+
parsedOptions: &parsedOptions)
81+
commandLine.appendFlag("-rpath")
82+
commandLine.appendPath(clangPath)
83+
}
84+
85+
func addLinkSanitizerLibArgsForDarwin(
86+
to commandLine: inout [Job.ArgTemplate],
87+
parsedOptions: inout ParsedOptions,
88+
targetInfo: FrontendTargetInfo,
89+
sanitizer: Sanitizer,
90+
isShared: Bool
91+
) throws {
92+
// Sanitizer runtime libraries requires C++.
93+
commandLine.appendFlag("-lc++")
94+
// Add explicit dependency on -lc++abi, as -lc++ doesn't re-export
95+
// all RTTI-related symbols that are used.
96+
commandLine.appendFlag("-lc++abi")
97+
98+
let sanitizerName = try runtimeLibraryName(
99+
for: sanitizer,
100+
targetTriple: targetInfo.target.triple,
101+
isShared: isShared
102+
)
103+
try addLinkRuntimeLibrary(
104+
named: sanitizerName,
105+
to: &commandLine,
106+
for: targetInfo,
107+
parsedOptions: &parsedOptions
108+
)
109+
110+
if isShared {
111+
try addLinkRuntimeLibraryRPath(
112+
to: &commandLine,
113+
parsedOptions: &parsedOptions,
114+
targetInfo: targetInfo,
115+
darwinLibName: sanitizerName
116+
)
117+
}
118+
}
119+
120+
private func addProfileGenerationArgs(
121+
to commandLine: inout [Job.ArgTemplate],
122+
parsedOptions: inout ParsedOptions,
123+
targetInfo: FrontendTargetInfo
124+
) throws {
125+
guard parsedOptions.hasArgument(.profileGenerate) else { return }
126+
let clangPath = try clangLibraryPath(for: targetInfo,
127+
parsedOptions: &parsedOptions)
128+
129+
for runtime in targetInfo.target.triple.darwinPlatform!.profileLibraryNameSuffixes {
130+
let clangRTPath = clangPath
131+
.appending(component: "libclang_rt.profile_\(runtime).a")
132+
commandLine.appendPath(clangRTPath)
133+
}
134+
}
135+
136+
private func addPlatformVersionArg(to commandLine: inout [Job.ArgTemplate],
137+
for triple: Triple, sdkPath: VirtualPath.Handle?) {
138+
assert(triple.isDarwin)
139+
let platformName = triple.darwinPlatform!.linkerPlatformName
140+
let platformVersion = triple.darwinLinkerPlatformVersion
141+
let sdkVersion: Version
142+
if let sdkPath = sdkPath,
143+
let sdkInfo = getTargetSDKInfo(sdkPath: sdkPath) {
144+
sdkVersion = sdkInfo.sdkVersion(for: triple)
145+
} else {
146+
sdkVersion = Version(0, 0, 0)
147+
}
148+
149+
commandLine.append(.flag("-platform_version"))
150+
commandLine.append(.flag(platformName))
151+
commandLine.append(.flag(platformVersion.description))
152+
commandLine.append(.flag(sdkVersion.description))
153+
}
154+
155+
private func addDeploymentTargetArgs(
156+
to commandLine: inout [Job.ArgTemplate],
157+
targetTriple: Triple,
158+
targetVariantTriple: Triple?,
159+
sdkPath: VirtualPath.Handle?
160+
) {
161+
addPlatformVersionArg(to: &commandLine, for: targetTriple, sdkPath: sdkPath)
162+
if let variantTriple = targetVariantTriple {
163+
assert(targetTriple.isValidForZipperingWithTriple(variantTriple))
164+
addPlatformVersionArg(to: &commandLine, for: variantTriple,
165+
sdkPath: sdkPath)
166+
}
167+
}
168+
169+
private func addArgsToLinkARCLite(
170+
to commandLine: inout [Job.ArgTemplate],
171+
parsedOptions: inout ParsedOptions,
172+
targetTriple: Triple
173+
) throws {
174+
guard parsedOptions.hasFlag(
175+
positive: .linkObjcRuntime,
176+
negative: .noLinkObjcRuntime,
177+
default: !targetTriple.supports(.nativeARC)
178+
) else {
179+
return
180+
}
181+
182+
guard let arcLiteLibPath = try findARCLiteLibPath(),
183+
let platformName = targetTriple.platformName() else {
184+
return
185+
}
186+
let fullLibPath = arcLiteLibPath
187+
.appending(components: "libarclite_\(platformName).a")
188+
189+
commandLine.appendFlag("-force_load")
190+
commandLine.appendPath(fullLibPath)
191+
192+
// Arclite depends on CoreFoundation.
193+
commandLine.appendFlag(.framework)
194+
commandLine.appendFlag("CoreFoundation")
195+
}
196+
50197
/// Adds the arguments necessary to link the files from the given set of
51198
/// options for a Darwin platform.
52199
public func addPlatformSpecificLinkerArgs(
@@ -66,7 +213,7 @@ extension DarwinToolchain {
66213
case .dynamicLibrary:
67214
// Same as an executable, but with the -dylib flag
68215
linkerTool = .dynamicLinker
69-
commandLine.appendFlag("-dynamiclib")
216+
commandLine.appendFlag("-dylib")
70217
addLinkInputs(shouldUseInputFileList: shouldUseInputFileList,
71218
commandLine: &commandLine,
72219
inputs: inputs,
@@ -133,7 +280,8 @@ extension DarwinToolchain {
133280
commandLine.appendPath(fileList)
134281
if linkerOutputType != .staticLibrary {
135282
for module in inputModules {
136-
commandLine.append(.joinedOptionAndPath("-Wl,-add_ast_path,", module))
283+
commandLine.append(.flag("-add_ast_path"))
284+
commandLine.append(.path(module))
137285
}
138286
}
139287

@@ -143,7 +291,7 @@ extension DarwinToolchain {
143291
commandLine.append(contentsOf: inputs.flatMap {
144292
(path: TypedVirtualPath) -> [Job.ArgTemplate] in
145293
if path.type == .swiftModule && linkerOutputType != .staticLibrary {
146-
return [.joinedOptionAndPath("-Wl,-add_ast_path,", path.file)]
294+
return [.flag("-add_ast_path"), .path(path.file)]
147295
} else if path.type == .object {
148296
return [.path(path.file)]
149297
} else if path.type == .tbd {
@@ -163,16 +311,39 @@ extension DarwinToolchain {
163311
sanitizers: Set<Sanitizer>,
164312
linkerOutputType: LinkOutputType,
165313
lto: LTOKind?) throws {
166-
if let lto = lto {
167-
switch lto {
168-
case .llvmFull:
169-
commandLine.appendFlag("-flto=full")
170-
case .llvmThin:
171-
commandLine.appendFlag("-flto=thin")
172-
}
314+
// FIXME: If we used Clang as a linker instead of going straight to ld,
315+
// we wouldn't have to replicate a bunch of Clang's logic here.
316+
317+
// Always link the regular compiler_rt if it's present. Note that the
318+
// regular libclang_rt.a uses a fat binary for device and simulator; this is
319+
// not true for all compiler_rt build products.
320+
//
321+
// Note: Normally we'd just add this unconditionally, but it's valid to build
322+
// Swift and use it as a linker without building compiler_rt.
323+
let targetTriple = targetInfo.target.triple
324+
let darwinPlatformSuffix =
325+
targetTriple.darwinPlatform!.with(.device)!.libraryNameSuffix
326+
let compilerRTPath =
327+
try clangLibraryPath(
328+
for: targetInfo,
329+
parsedOptions: &parsedOptions)
330+
.appending(component: "libclang_rt.\(darwinPlatformSuffix).a")
331+
if try fileSystem.exists(compilerRTPath) {
332+
commandLine.append(.path(compilerRTPath))
333+
}
173334

335+
try addArgsToLinkARCLite(
336+
to: &commandLine,
337+
parsedOptions: &parsedOptions,
338+
targetTriple: targetTriple
339+
)
340+
341+
if lto != nil {
174342
if let arg = parsedOptions.getLastArgument(.ltoLibrary)?.asSingle {
175-
commandLine.append(.joinedOptionAndPath("-Wl,-lto_library,", try VirtualPath(path: arg)))
343+
commandLine.appendFlag("-lto_library")
344+
commandLine.appendPath(try VirtualPath(path: arg))
345+
} else {
346+
try addLTOLibArgs(to: &commandLine)
176347
}
177348
}
178349

@@ -183,44 +354,43 @@ extension DarwinToolchain {
183354
}
184355

185356
if parsedOptions.contains(.enableAppExtension) {
186-
commandLine.appendFlag("-fapplication-extension")
357+
commandLine.appendFlag("-application_extension")
187358
}
188359

189360
// Linking sanitizers will add rpaths, which might negatively interact when
190361
// other rpaths are involved, so we should make sure we add the rpaths after
191362
// all user-specified rpaths.
192-
if linkerOutputType == .executable && !sanitizers.isEmpty {
193-
let sanitizerNames = sanitizers
194-
.map { $0.rawValue }
195-
.sorted() // Sort so we get a stable, testable order
196-
.joined(separator: ",")
197-
commandLine.appendFlag("-fsanitize=\(sanitizerNames)")
363+
for sanitizer in sanitizers {
364+
if sanitizer == .fuzzer {
365+
guard linkerOutputType == .executable else { continue }
366+
}
367+
try addLinkSanitizerLibArgsForDarwin(
368+
to: &commandLine,
369+
parsedOptions: &parsedOptions,
370+
targetInfo: targetInfo,
371+
sanitizer: sanitizer,
372+
isShared: sanitizer != .fuzzer
373+
)
198374
}
199375

200-
if parsedOptions.contains(.embedBitcode) {
201-
commandLine.appendFlag("-fembed-bitcode")
202-
} else if parsedOptions.contains(.embedBitcodeMarker) {
203-
commandLine.appendFlag("-fembed-bitcode=marker")
376+
if parsedOptions.contains(.embedBitcode) ||
377+
parsedOptions.contains(.embedBitcodeMarker) {
378+
commandLine.appendFlag("-bitcode_bundle")
204379
}
205380

206381
// Add the SDK path
207382
if let sdkPath = targetInfo.sdkPath?.path {
208-
commandLine.appendFlag("--sysroot")
383+
commandLine.appendFlag("-syslibroot")
209384
commandLine.appendPath(VirtualPath.lookup(sdkPath))
210385
}
211386

212387
commandLine.appendFlags(
213-
"-fobjc-link-runtime",
214388
"-lobjc",
215389
"-lSystem"
216390
)
217391

218-
let targetTriple = targetInfo.target.triple
219-
commandLine.appendFlag("--target=\(targetTriple.triple)")
220-
if let variantTriple = targetInfo.targetVariant?.triple {
221-
assert(targetTriple.isValidForZipperingWithTriple(variantTriple))
222-
commandLine.appendFlag("-darwin-target-variant=\(variantTriple.triple)")
223-
}
392+
commandLine.appendFlag("-arch")
393+
commandLine.appendFlag(targetTriple.archName)
224394

225395
// On Darwin, we only support libc++.
226396
if parsedOptions.contains(.enableExperimentalCxxInterop) {
@@ -235,9 +405,19 @@ extension DarwinToolchain {
235405
fileSystem: fileSystem
236406
)
237407

238-
if parsedOptions.hasArgument(.profileGenerate) {
239-
commandLine.appendFlag("-fprofile-generate")
240-
}
408+
try addProfileGenerationArgs(
409+
to: &commandLine,
410+
parsedOptions: &parsedOptions,
411+
targetInfo: targetInfo
412+
)
413+
414+
let targetVariantTriple = targetInfo.targetVariant?.triple
415+
addDeploymentTargetArgs(
416+
to: &commandLine,
417+
targetTriple: targetTriple,
418+
targetVariantTriple: targetVariantTriple,
419+
sdkPath: targetInfo.sdkPath?.path
420+
)
241421

242422
// These custom arguments should be right before the object file at the
243423
// end.
@@ -247,13 +427,7 @@ extension DarwinToolchain {
247427
from: &parsedOptions
248428
)
249429
addLinkedLibArgs(to: &commandLine, parsedOptions: &parsedOptions)
250-
// Because we invoke `clang` as the linker executable, we must still
251-
// use `-Xlinker` for linker-specific arguments.
252-
for linkerOpt in parsedOptions.arguments(for: .Xlinker) {
253-
commandLine.appendFlag(.Xlinker)
254-
commandLine.appendFlag(linkerOpt.argument.asSingle)
255-
}
256-
try commandLine.appendAllArguments(.XclangLinker, from: &parsedOptions)
430+
try commandLine.appendAllArguments(.Xlinker, from: &parsedOptions)
257431
}
258432
}
259433

Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,19 @@ extension Toolchain {
5656
return result
5757
}
5858

59+
func addLinkRuntimeLibrary(
60+
named name: String,
61+
to commandLine: inout [Job.ArgTemplate],
62+
for targetInfo: FrontendTargetInfo,
63+
parsedOptions: inout ParsedOptions
64+
) throws {
65+
let path = try clangLibraryPath(
66+
for: targetInfo,
67+
parsedOptions: &parsedOptions)
68+
.appending(component: name)
69+
commandLine.appendPath(path)
70+
}
71+
5972
func runtimeLibraryExists(
6073
for sanitizer: Sanitizer,
6174
targetInfo: FrontendTargetInfo,

Sources/SwiftDriver/Toolchains/DarwinToolchain.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public final class DarwinToolchain: Toolchain {
6464
case .swiftCompiler:
6565
return try lookup(executable: "swift-frontend")
6666
case .dynamicLinker:
67-
return try lookup(executable: "clang")
67+
return try lookup(executable: "ld")
6868
case .staticLinker:
6969
return try lookup(executable: "libtool")
7070
case .dsymutil:

Tests/SwiftDriverTests/JobExecutorTests.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,11 @@ final class JobExecutorTests: XCTestCase {
179179
.path(.temporary(RelativePath("foo.o"))),
180180
.path(.temporary(RelativePath("main.o"))),
181181
.path(.absolute(try toolchain.clangRT.get())),
182-
"--sysroot", .path(.absolute(try toolchain.sdk.get())),
183-
"-lobjc", "-lSystem", .flag("--target=\(hostTriple.triple)"),
182+
"-syslibroot", .path(.absolute(try toolchain.sdk.get())),
183+
"-lobjc", "-lSystem", "-arch", .flag(hostTriple.archName),
184184
"-L", .path(.absolute(try toolchain.resourcesDirectory.get())),
185185
"-L", .path(.absolute(try toolchain.sdkStdlib(sdk: toolchain.sdk.get()))),
186-
"-rpath", "/usr/lib/swift", "-o",
186+
"-rpath", "/usr/lib/swift", "-macosx_version_min", "10.14.0", "-o",
187187
.path(.relative(RelativePath("main"))),
188188
],
189189
inputs: [
@@ -249,10 +249,12 @@ final class JobExecutorTests: XCTestCase {
249249
tool: try toolchain.resolvedTool(.dynamicLinker),
250250
commandLine: [
251251
.path(.temporary(RelativePath("main.o"))),
252-
"--sysroot", .path(.absolute(try toolchain.sdk.get())),
253-
"-lobjc", "-lSystem", .flag("--target=\(hostTriple.triple)"),
252+
.path(.absolute(try toolchain.clangRT.get())),
253+
"-syslibroot", .path(.absolute(try toolchain.sdk.get())),
254+
"-lobjc", "-lSystem", "-arch", .flag(hostTriple.archName),
254255
"-L", .path(.absolute(try toolchain.resourcesDirectory.get())),
255256
"-L", .path(.absolute(try toolchain.sdkStdlib(sdk: toolchain.sdk.get()))),
257+
"-rpath", "/usr/lib/swift", "-macosx_version_min", "10.14.0",
256258
"-o", .path(.absolute(exec)),
257259
],
258260
inputs: [

0 commit comments

Comments
 (0)