forked from swiftlang/swift-sdk-generator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWebAssemblyRecipe.swift
168 lines (151 loc) · 7.55 KB
/
WebAssemblyRecipe.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
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2022-2024 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 Helpers
import struct SystemPackage.FilePath
public struct WebAssemblyRecipe: SwiftSDKRecipe {
let hostSwiftPackage: HostToolchainPackage?
let targetSwiftPackagePath: FilePath
let wasiSysroot: FilePath
let swiftVersion: String
public struct HostToolchainPackage: Sendable {
let path: FilePath
let triple: Triple
public init(path: FilePath, triple: Triple) {
self.path = path
self.triple = triple
}
}
public init(
hostSwiftPackage: HostToolchainPackage?,
targetSwiftPackagePath: FilePath,
wasiSysroot: FilePath,
swiftVersion: String
) {
self.hostSwiftPackage = hostSwiftPackage
self.targetSwiftPackagePath = targetSwiftPackagePath
self.wasiSysroot = wasiSysroot
self.swiftVersion = swiftVersion
}
public var defaultArtifactID: String {
"\(self.swiftVersion)_wasm"
}
public func applyPlatformOptions(toolset: inout Toolset, targetTriple: Triple) {
// We only support static linking for WebAssembly for now, so make it the default.
toolset.swiftCompiler = Toolset.ToolProperties(extraCLIOptions: ["-static-stdlib"])
if targetTriple.environmentName == "threads" {
// Enable features required for threading support
let ccOptions = [
"-matomics", "-mbulk-memory", "-mthread-model", "posix",
"-pthread", "-ftls-model=local-exec",
]
// Tell LLVM codegen in swiftc to enable those features via clang options
toolset.swiftCompiler?.extraCLIOptions?.append(contentsOf: ccOptions.flatMap {
["-Xcc", $0]
})
// Tell the C and C++ compilers to enable those features
toolset.cCompiler = Toolset.ToolProperties(extraCLIOptions: ccOptions)
toolset.cxxCompiler = Toolset.ToolProperties(extraCLIOptions: ccOptions)
let linkerOptions = [
// Shared memory is required for WASI threads ABI
// See https://github.com/WebAssembly/wasi-threads for more information.
"--import-memory", "--export-memory", "--shared-memory",
// Set the maximum memory size to 1GB because shared memory must specify
// a maximum size. 1GB is chosen as a conservative default, but it can be
// overridden by the user-provided --max-memory linker option.
"--max-memory=1073741824",
]
toolset.linker = Toolset.ToolProperties(extraCLIOptions: linkerOptions)
}
}
public func applyPlatformOptions(
metadata: inout SwiftSDKMetadataV4.TripleProperties,
paths: PathsConfiguration,
targetTriple: Triple
) {
var relativeToolchainDir = paths.toolchainDirPath
guard relativeToolchainDir.removePrefix(paths.swiftSDKRootPath) else {
fatalError("The toolchain bin directory path must be a subdirectory of the Swift SDK root path.")
}
metadata.swiftStaticResourcesPath = relativeToolchainDir.appending("usr/lib/swift_static").string
metadata.swiftResourcesPath = metadata.swiftStaticResourcesPath
}
public func makeSwiftSDK(
generator: SwiftSDKGenerator,
engine: QueryEngine,
httpClient: some HTTPClientProtocol
) async throws -> SwiftSDKProduct {
let pathsConfiguration = generator.pathsConfiguration
let targetSwiftLibPath = self.targetSwiftPackagePath.appending("usr/lib")
logGenerationStep("Copying Swift binaries for the host triple...")
var hostTriples: [Triple]? = nil
if let hostSwiftPackage {
hostTriples = [hostSwiftPackage.triple]
try await generator.rsync(from: hostSwiftPackage.path.appending("usr"), to: pathsConfiguration.toolchainDirPath)
logGenerationStep("Removing unused toolchain components...")
let liblldbNames: [String] = try await {
let libDirPath = pathsConfiguration.toolchainDirPath.appending("usr/lib")
guard await generator.doesFileExist(at: libDirPath) else {
return []
}
return try await generator.contentsOfDirectory(at: libDirPath).filter { dirEntry in
// liblldb is version suffixed: liblldb.so.17.0.0
dirEntry.hasPrefix("liblldb")
}
}()
try await generator.removeToolchainComponents(
pathsConfiguration.toolchainDirPath,
platforms: unusedTargetPlatforms,
libraries: unusedHostLibraries + liblldbNames,
binaries: unusedHostBinaries + ["lldb", "lldb-argdumper", "lldb-server"]
)
// Merge target Swift package with the host package.
try await self.mergeTargetSwift(from: targetSwiftLibPath, generator: generator)
} else {
// Simply copy the target Swift package into the SDK bundle when building host-agnostic SDK.
try await generator.createDirectoryIfNeeded(at: pathsConfiguration.toolchainDirPath.appending("usr"))
try await generator.copy(from: targetSwiftLibPath, to: pathsConfiguration.toolchainDirPath.appending("usr/lib"))
}
let autolinkExtractPath = generator.pathsConfiguration.toolchainBinDirPath.appending("swift-autolink-extract")
// WebAssembly object file requires `swift-autolink-extract`
if await !generator.doesFileExist(at: autolinkExtractPath),
await generator.doesFileExist(at: generator.pathsConfiguration.toolchainBinDirPath.appending("swift"))
{
logGenerationStep("Fixing `swift-autolink-extract` symlink...")
try await generator.createSymlink(at: autolinkExtractPath, pointingTo: "swift")
}
// Copy the WASI sysroot into the SDK bundle.
let sdkDirPath = pathsConfiguration.swiftSDKRootPath.appending("WASI.sdk")
try await generator.rsyncContents(from: self.wasiSysroot, to: sdkDirPath)
return SwiftSDKProduct(sdkDirPath: sdkDirPath, hostTriples: hostTriples)
}
/// Merge the target Swift package into the Swift SDK bundle derived from the host Swift package.
func mergeTargetSwift(from distributionPath: FilePath, generator: SwiftSDKGenerator) async throws {
let pathsConfiguration = generator.pathsConfiguration
logGenerationStep("Copying Swift core libraries for the target triple into Swift SDK bundle...")
for (pathWithinPackage, pathWithinSwiftSDK, isOptional) in [
("clang", pathsConfiguration.toolchainDirPath.appending("usr/lib"), false),
("swift/clang", pathsConfiguration.toolchainDirPath.appending("usr/lib/swift"), false),
("swift/wasi", pathsConfiguration.toolchainDirPath.appending("usr/lib/swift"), false),
("swift_static/clang", pathsConfiguration.toolchainDirPath.appending("usr/lib/swift_static"), false),
("swift_static/wasi", pathsConfiguration.toolchainDirPath.appending("usr/lib/swift_static"), false),
("swift_static/shims", pathsConfiguration.toolchainDirPath.appending("usr/lib/swift_static"), false),
// Mark CoreFoundation as optional until we set up build system to build it for WebAssembly
("swift_static/CoreFoundation", pathsConfiguration.toolchainDirPath.appending("usr/lib/swift_static"), true),
] {
if isOptional, await !(generator.doesFileExist(at: distributionPath.appending(pathWithinPackage))) {
logGenerationStep("Skipping optional path \(pathWithinPackage)")
continue
}
try await generator.rsync(from: distributionPath.appending(pathWithinPackage), to: pathWithinSwiftSDK)
}
}
}