forked from apple/swift-driver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
WebAssemblyToolchain+LinkerSupport.swift
175 lines (153 loc) · 6.79 KB
/
WebAssemblyToolchain+LinkerSupport.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//===--------------- WebAssemblyToolchain+LinkerSupport.swift -------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import SwiftOptions
import func TSCBasic.lookupExecutablePath
import protocol TSCBasic.FileSystem
import struct TSCBasic.AbsolutePath
extension WebAssemblyToolchain {
public func addPlatformSpecificLinkerArgs(
to commandLine: inout [Job.ArgTemplate],
parsedOptions: inout ParsedOptions,
linkerOutputType: LinkOutputType,
inputs: [TypedVirtualPath],
outputFile: VirtualPath,
shouldUseInputFileList: Bool,
lto: LTOKind?,
sanitizers: Set<Sanitizer>,
targetInfo: FrontendTargetInfo
) throws -> ResolvedTool {
let targetTriple = targetInfo.target.triple
switch linkerOutputType {
case .dynamicLibrary:
throw Error.dynamicLibrariesUnsupportedForTarget(targetTriple.triple)
case .executable:
if !targetTriple.triple.isEmpty {
commandLine.appendFlag("-target")
commandLine.appendFlag(targetTriple.triple)
}
// Select the linker to use.
if let linkerArg = parsedOptions.getLastArgument(.useLd)?.asSingle {
commandLine.appendFlag("-fuse-ld=\(linkerArg)")
}
try commandLine.appendLast(.ldPath, from: &parsedOptions)
// Configure the toolchain.
//
// By default use the system `clang` to perform the link. We use `clang` for
// the driver here because we do not wish to select a particular C++ runtime.
// Furthermore, until C++ interop is enabled, we cannot have a dependency on
// C++ code from pure Swift code. If linked libraries are C++ based, they
// should properly link C++. In the case of static linking, the user can
// explicitly specify the C++ runtime to link against. This is particularly
// important for platforms like android where as it is a Linux platform, the
// default C++ runtime is `libstdc++` which is unsupported on the target but
// as the builds are usually cross-compiled from Linux, libstdc++ is going to
// be present. This results in linking the wrong version of libstdc++
// generating invalid binaries. It is also possible to use different C++
// runtimes than the default C++ runtime for the platform (e.g. libc++ on
// Windows rather than msvcprt). When C++ interop is enabled, we will need to
// surface this via a driver flag. For now, opt for the simpler approach of
// just using `clang` and avoid a dependency on the C++ runtime.
var clangPath = try getToolPath(.clang)
if let toolsDirPath = parsedOptions.getLastArgument(.toolsDirectory) {
// FIXME: What if this isn't an absolute path?
let toolsDir = try AbsolutePath(validating: toolsDirPath.asSingle)
// If there is a clang in the toolchain folder, use that instead.
if let tool = lookupExecutablePath(filename: "clang", searchPaths: [toolsDir]) {
clangPath = tool
}
}
guard !parsedOptions.hasArgument(.noStaticStdlib, .noStaticExecutable) else {
throw Error.dynamicLibrariesUnsupportedForTarget(targetTriple.triple)
}
let runtimePaths = try runtimeLibraryPaths(
for: targetInfo,
parsedOptions: &parsedOptions,
sdkPath: targetInfo.sdkPath?.path,
isShared: false
)
if !parsedOptions.hasArgument(.nostartfiles) {
let swiftrtPath = VirtualPath.lookup(targetInfo.runtimeResourcePath.path)
.appending(
components: targetTriple.platformName() ?? "",
targetTriple.archName,
"swiftrt.o"
)
commandLine.appendPath(swiftrtPath)
}
let inputFiles: [Job.ArgTemplate] = inputs.compactMap { input in
// Autolink inputs are handled specially
if input.type == .autolink {
return .responseFilePath(input.file)
} else if input.type == .object {
return .path(input.file)
} else {
return nil
}
}
commandLine.append(contentsOf: inputFiles)
if let path = targetInfo.sdkPath?.path {
commandLine.appendFlag("--sysroot")
commandLine.appendPath(VirtualPath.lookup(path))
}
// Add the runtime library link paths.
for path in runtimePaths {
commandLine.appendFlag(.L)
commandLine.appendPath(path)
}
// Link the standard library and dependencies.
let linkFilePath: VirtualPath =
VirtualPath.lookup(targetInfo.runtimeResourcePath.path)
.appending(components: targetTriple.platformName() ?? "",
"static-executable-args.lnk")
guard try fileSystem.exists(linkFilePath) else {
throw Error.missingExternalDependency(linkFilePath.name)
}
commandLine.append(.responseFilePath(linkFilePath))
// Pass down an optimization level
if let optArg = mapOptimizationLevelToClangArg(from: &parsedOptions) {
commandLine.appendFlag(optArg)
}
// Explicitly pass the target to the linker
commandLine.appendFlag("--target=\(targetTriple.triple)")
// Delegate to Clang for sanitizers. It will figure out the correct linker
// options.
guard sanitizers.isEmpty else {
throw Error.sanitizersUnsupportedForTarget(targetTriple.triple)
}
guard !parsedOptions.hasArgument(.profileGenerate) else {
throw Error.profilingUnsupportedForTarget(targetTriple.triple)
}
// Run clang++ in verbose mode if "-v" is set
try commandLine.appendLast(.v, from: &parsedOptions)
// These custom arguments should be right before the object file at the
// end.
try commandLine.appendAllExcept(
includeList: [.linkerOption],
excludeList: [.l],
from: &parsedOptions
)
addLinkedLibArgs(to: &commandLine, parsedOptions: &parsedOptions)
try commandLine.appendAllArguments(.Xlinker, from: &parsedOptions)
try commandLine.appendAllArguments(.XclangLinker, from: &parsedOptions)
// This should be the last option, for convenience in checking output.
commandLine.appendFlag(.o)
commandLine.appendPath(outputFile)
return try resolvedTool(.clang, pathOverride: clangPath)
case .staticLibrary:
// We're using 'ar' as a linker
commandLine.appendFlag("crs")
commandLine.appendPath(outputFile)
commandLine.append(contentsOf: inputs.map { .path($0.file) })
return try resolvedTool(.staticLinker(lto))
}
}
}