File: WebAssemblyToolchain%2BLinkerSupport.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (191 lines) | stat: -rw-r--r-- 7,764 bytes parent folder | download
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
//===--------------- 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)")
      }

      if let arg = parsedOptions.getLastArgument(.ldPath)?.asSingle {
        commandLine.append(.joinedOptionAndPath("--ld-path=", try VirtualPath(path: arg)))
      }

      // 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
        }

        // Look for binutils in the toolchain folder.
        commandLine.appendFlag("-B")
        commandLine.appendPath(toolsDir)
      }

      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)")

      // WebAssembly doesn't reserve low addresses as its ABI. But without
      // "extra inhabitants" of the pointer representation, runtime performance
      // and memory footprint are significantly degraded. So we reserve the
      // low addresses to use them as extra inhabitants by telling the lowest
      // valid address to the linker.
      // The value of lowest valid address, called "global base", must be always
      // synchronized with `SWIFT_ABI_WASM32_LEAST_VALID_POINTER` defined in
      // apple/swift's runtime library.
      commandLine.appendFlag(.Xlinker)
      commandLine.appendFlag("--global-base=4096")

      // 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 addExtraClangLinkerArgs(to: &commandLine, parsedOptions: &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))
    }
  }
}