@@ -47,6 +47,153 @@ extension DarwinToolchain {
47
47
return try findXcodeClangLibPath ( " arc " )
48
48
}
49
49
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
+
50
197
/// Adds the arguments necessary to link the files from the given set of
51
198
/// options for a Darwin platform.
52
199
public func addPlatformSpecificLinkerArgs(
@@ -66,7 +213,7 @@ extension DarwinToolchain {
66
213
case . dynamicLibrary:
67
214
// Same as an executable, but with the -dylib flag
68
215
linkerTool = . dynamicLinker
69
- commandLine. appendFlag ( " -dynamiclib " )
216
+ commandLine. appendFlag ( " -dylib " )
70
217
addLinkInputs ( shouldUseInputFileList: shouldUseInputFileList,
71
218
commandLine: & commandLine,
72
219
inputs: inputs,
@@ -133,7 +280,8 @@ extension DarwinToolchain {
133
280
commandLine. appendPath ( fileList)
134
281
if linkerOutputType != . staticLibrary {
135
282
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) )
137
285
}
138
286
}
139
287
@@ -143,7 +291,7 @@ extension DarwinToolchain {
143
291
commandLine. append ( contentsOf: inputs. flatMap {
144
292
( path: TypedVirtualPath ) -> [ Job . ArgTemplate ] in
145
293
if path. type == . swiftModule && linkerOutputType != . staticLibrary {
146
- return [ . joinedOptionAndPath ( " -Wl,- add_ast_path, " , path. file) ]
294
+ return [ . flag ( " -add_ast_path " ) , . path ( path. file) ]
147
295
} else if path. type == . object {
148
296
return [ . path( path. file) ]
149
297
} else if path. type == . tbd {
@@ -163,16 +311,39 @@ extension DarwinToolchain {
163
311
sanitizers: Set < Sanitizer > ,
164
312
linkerOutputType: LinkOutputType ,
165
313
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
+ }
173
334
335
+ try addArgsToLinkARCLite (
336
+ to: & commandLine,
337
+ parsedOptions: & parsedOptions,
338
+ targetTriple: targetTriple
339
+ )
340
+
341
+ if lto != nil {
174
342
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)
176
347
}
177
348
}
178
349
@@ -183,44 +354,43 @@ extension DarwinToolchain {
183
354
}
184
355
185
356
if parsedOptions. contains ( . enableAppExtension) {
186
- commandLine. appendFlag ( " -fapplication-extension " )
357
+ commandLine. appendFlag ( " -application_extension " )
187
358
}
188
359
189
360
// Linking sanitizers will add rpaths, which might negatively interact when
190
361
// other rpaths are involved, so we should make sure we add the rpaths after
191
362
// 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
+ )
198
374
}
199
375
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 " )
204
379
}
205
380
206
381
// Add the SDK path
207
382
if let sdkPath = targetInfo. sdkPath? . path {
208
- commandLine. appendFlag ( " --sysroot " )
383
+ commandLine. appendFlag ( " -syslibroot " )
209
384
commandLine. appendPath ( VirtualPath . lookup ( sdkPath) )
210
385
}
211
386
212
387
commandLine. appendFlags (
213
- " -fobjc-link-runtime " ,
214
388
" -lobjc " ,
215
389
" -lSystem "
216
390
)
217
391
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)
224
394
225
395
// On Darwin, we only support libc++.
226
396
if parsedOptions. contains ( . enableExperimentalCxxInterop) {
@@ -235,9 +405,19 @@ extension DarwinToolchain {
235
405
fileSystem: fileSystem
236
406
)
237
407
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
+ )
241
421
242
422
// These custom arguments should be right before the object file at the
243
423
// end.
@@ -247,13 +427,7 @@ extension DarwinToolchain {
247
427
from: & parsedOptions
248
428
)
249
429
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)
257
431
}
258
432
}
259
433
0 commit comments