Skip to content

Commit 23742cc

Browse files
author
Harlan Haskins
authored
Merge pull request #57 from DougGregor/linux-linx
[Linux] Add linux linking support
2 parents ef868d6 + 5b24d2b commit 23742cc

File tree

7 files changed

+792
-363
lines changed

7 files changed

+792
-363
lines changed
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
import TSCBasic
2+
import TSCUtility
3+
4+
extension DarwinToolchain {
5+
private func findARCLiteLibPath() throws -> AbsolutePath? {
6+
let path = try getToolPath(.swiftCompiler)
7+
.parentDirectory // 'swift'
8+
.parentDirectory // 'bin'
9+
.appending(components: "lib", "arc")
10+
11+
if localFileSystem.exists(path) { return path }
12+
13+
// If we don't have a 'lib/arc/' directory, find the "arclite" library
14+
// relative to the Clang in the active Xcode.
15+
if let clangPath = try? getToolPath(.clang) {
16+
return clangPath
17+
.parentDirectory // 'clang'
18+
.parentDirectory // 'bin'
19+
.appending(components: "lib", "arc")
20+
}
21+
return nil
22+
}
23+
24+
private func addProfileGenerationArgs(
25+
to commandLine: inout [Job.ArgTemplate],
26+
parsedOptions: inout ParsedOptions,
27+
targetTriple: Triple
28+
) throws {
29+
guard parsedOptions.hasArgument(.profile_generate) else { return }
30+
let clangPath = try clangLibraryPath(for: targetTriple,
31+
parsedOptions: &parsedOptions)
32+
33+
let runtime: String
34+
if targetTriple.os.isiOS {
35+
runtime = targetTriple.os.isTvOS ? "tvos" : "ios"
36+
} else if targetTriple.os.isWatchOS {
37+
runtime = "watchos"
38+
} else {
39+
assert(targetTriple.os.isMacOSX)
40+
runtime = "osx"
41+
}
42+
43+
var sim = ""
44+
if targetTriple.isSimulatorEnvironment {
45+
sim = "sim"
46+
}
47+
48+
var clangRTPath = clangPath
49+
.appending(component: "libclang_rt.profile_\(runtime)\(sim).a")
50+
51+
// FIXME: Continue accepting the old path for simulator libraries for now.
52+
if targetTriple.isSimulatorEnvironment &&
53+
!localFileSystem.exists(clangRTPath) {
54+
clangRTPath = clangRTPath.parentDirectory
55+
.appending(component: "libclang_rt.profile_\(runtime).a")
56+
}
57+
58+
commandLine.appendPath(clangRTPath)
59+
}
60+
61+
private func addDeploymentTargetArgs(
62+
to commandLine: inout [Job.ArgTemplate],
63+
targetTriple: Triple
64+
) {
65+
// FIXME: Properly handle deployment targets.
66+
assert(targetTriple.os.isiOS || targetTriple.os.isWatchOS || targetTriple.os.isMacOSX)
67+
68+
if (targetTriple.os.isiOS) {
69+
if (targetTriple.os.isTvOS) {
70+
if targetTriple.isSimulatorEnvironment {
71+
commandLine.appendFlag("-tvos_simulator_version_min")
72+
} else {
73+
commandLine.appendFlag("-tvos_version_min")
74+
}
75+
} else {
76+
if targetTriple.isSimulatorEnvironment {
77+
commandLine.appendFlag("-ios_simulator_version_min")
78+
} else {
79+
commandLine.appendFlag("-iphoneos_version_min")
80+
}
81+
}
82+
commandLine.appendFlag(targetTriple.iOSVersion().description)
83+
} else if targetTriple.os.isWatchOS {
84+
if targetTriple.isSimulatorEnvironment {
85+
commandLine.appendFlag("-watchos_simulator_version_min")
86+
} else {
87+
commandLine.appendFlag("-watchos_version_min")
88+
}
89+
commandLine.appendFlag(targetTriple.watchOSVersion().description)
90+
} else {
91+
commandLine.appendFlag("-macosx_version_min")
92+
commandLine.appendFlag(targetTriple.getMacOSXVersion().1.description)
93+
}
94+
}
95+
96+
/// Returns true if the compiler depends on features provided by the ObjC
97+
/// runtime that are not present on the deployment target indicated by
98+
/// `triple`.
99+
private func wantsObjCRuntime(triple: Triple) -> Bool {
100+
// When updating the versions listed here, please record the most recent
101+
// feature being depended on and when it was introduced:
102+
//
103+
// - Make assigning 'nil' to an NSMutableDictionary subscript delete the
104+
// entry, like it does for Swift.Dictionary, rather than trap.
105+
if triple.os.isiOS {
106+
return triple.iOSVersion() < Triple.Version(9, 0, 0)
107+
} else if triple.os.isMacOSX {
108+
return triple.getMacOSXVersion().1 < Triple.Version(10, 11, 0)
109+
} else if triple.os.isWatchOS {
110+
return false
111+
}
112+
fatalError("unknown Darwin OS")
113+
}
114+
115+
private func addArgsToLinkARCLite(
116+
to commandLine: inout [Job.ArgTemplate],
117+
parsedOptions: inout ParsedOptions,
118+
targetTriple: Triple
119+
) throws {
120+
if !parsedOptions.hasFlag(positive: .link_objc_runtime,
121+
negative: .no_link_objc_runtime,
122+
default: wantsObjCRuntime(triple: targetTriple)) {
123+
return
124+
}
125+
126+
guard let arcLiteLibPath = try findARCLiteLibPath(),
127+
let platformName = targetTriple.platformName else {
128+
return
129+
}
130+
let fullLibPath = arcLiteLibPath
131+
.appending(components: "libarclite_\(platformName).a")
132+
133+
commandLine.appendFlag("-force_load")
134+
commandLine.appendPath(fullLibPath)
135+
136+
// Arclite depends on CoreFoundation.
137+
commandLine.appendFlag(.framework)
138+
commandLine.appendFlag("CoreFoundation")
139+
}
140+
141+
/// Adds the arguments necessary to link the files from the given set of
142+
/// options for a Darwin platform.
143+
public func addPlatformSpecificLinkerArgs(
144+
to commandLine: inout [Job.ArgTemplate],
145+
parsedOptions: inout ParsedOptions,
146+
linkerOutputType: LinkOutputType,
147+
inputs: [TypedVirtualPath],
148+
outputFile: VirtualPath,
149+
sdkPath: String?,
150+
targetTriple: Triple
151+
) throws -> AbsolutePath {
152+
153+
// FIXME: If we used Clang as a linker instead of going straight to ld,
154+
// we wouldn't have to replicate a bunch of Clang's logic here.
155+
156+
// Always link the regular compiler_rt if it's present.
157+
//
158+
// Note: Normally we'd just add this unconditionally, but it's valid to build
159+
// Swift and use it as a linker without building compiler_rt.
160+
let darwinPlatformSuffix =
161+
targetTriple.darwinLibraryNameSuffix(distinguishSimulator: false)!
162+
let compilerRTPath =
163+
try clangLibraryPath(
164+
for: targetTriple, parsedOptions: &parsedOptions)
165+
.appending(component: "libclang_rt.\(darwinPlatformSuffix).a")
166+
if localFileSystem.exists(compilerRTPath) {
167+
commandLine.append(.path(.absolute(compilerRTPath)))
168+
}
169+
170+
// Set up for linking.
171+
let linkerTool: Tool
172+
switch linkerOutputType {
173+
case .dynamicLibrary:
174+
// Same as an executable, but with the -dylib flag
175+
commandLine.appendFlag("-dylib")
176+
fallthrough
177+
case .executable:
178+
linkerTool = .dynamicLinker
179+
let fSystemArgs = parsedOptions.filter {
180+
$0.option == .F || $0.option == .Fsystem
181+
}
182+
for opt in fSystemArgs {
183+
commandLine.appendFlag(.F)
184+
commandLine.appendPath(try VirtualPath(path: opt.argument.asSingle))
185+
}
186+
187+
// FIXME: Sanitizer args
188+
189+
commandLine.appendFlag("-arch")
190+
commandLine.appendFlag(targetTriple.archName)
191+
192+
try addArgsToLinkStdlib(
193+
to: &commandLine,
194+
parsedOptions: &parsedOptions,
195+
sdkPath: sdkPath,
196+
targetTriple: targetTriple
197+
)
198+
199+
// These custom arguments should be right before the object file at the
200+
// end.
201+
try commandLine.append(
202+
contentsOf: parsedOptions.filter { $0.option.group == .linker_option }
203+
)
204+
try commandLine.appendAllArguments(.Xlinker, from: &parsedOptions)
205+
206+
case .staticLibrary:
207+
linkerTool = .staticLinker
208+
commandLine.appendFlag(.static)
209+
break
210+
}
211+
212+
try addArgsToLinkARCLite(
213+
to: &commandLine,
214+
parsedOptions: &parsedOptions,
215+
targetTriple: targetTriple
216+
)
217+
addDeploymentTargetArgs(
218+
to: &commandLine,
219+
targetTriple: targetTriple
220+
)
221+
try addProfileGenerationArgs(
222+
to: &commandLine,
223+
parsedOptions: &parsedOptions,
224+
targetTriple: targetTriple
225+
)
226+
227+
commandLine.appendFlags(
228+
"-lobjc",
229+
"-lSystem",
230+
"-no_objc_category_merging"
231+
)
232+
233+
// Add the SDK path
234+
if let sdkPath = sdkPath {
235+
commandLine.appendFlag("-syslibroot")
236+
commandLine.appendPath(try VirtualPath(path: sdkPath))
237+
}
238+
239+
if parsedOptions.contains(.embed_bitcode) ||
240+
parsedOptions.contains(.embed_bitcode_marker) {
241+
commandLine.appendFlag("-bitcode_bundle")
242+
}
243+
244+
if parsedOptions.contains(.enable_app_extension) {
245+
commandLine.appendFlag("-application_extension")
246+
}
247+
248+
// Add inputs.
249+
commandLine.append(contentsOf: inputs.map { .path($0.file) })
250+
251+
// Add the output
252+
commandLine.appendFlag("-o")
253+
commandLine.appendPath(outputFile)
254+
255+
return try getToolPath(linkerTool)
256+
}
257+
}

0 commit comments

Comments
 (0)