Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply runtime library workaround for snapshot toolchains on macOS #484

Merged
merged 14 commits into from
Jun 10, 2024
6 changes: 6 additions & 0 deletions Sources/CartonCore/Environment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ public enum Environment: String, CaseIterable {
// for future dynamic linking support.
parameters.otherSwiftcFlags += ["-static-stdlib"]

#if compiler(>=6.0) && compiler(<6.1)
// A workaround for the linker issue.
// https://github.com/swiftwasm/swift/issues/5580
parameters.otherLinkerFlags += ["-lswift_RegexParser"]
#endif

switch self {
case .command: break
case .node, .browser:
Expand Down
4 changes: 4 additions & 0 deletions Sources/CartonCore/FoundationProcessEx.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,16 @@ extension Foundation.Process {
public static func checkRun(
_ executableURL: URL,
arguments: [String],
environment: [String: String]? = nil,
printsLoadingMessage: Bool = true,
forwardExit: Bool = false
) throws {
let process = Foundation.Process()
process.executableURL = executableURL
process.arguments = arguments
if let environment {
process.environment = environment
Copy link
Contributor Author

@omochi omochi Jun 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

環境変数を設定する口を開けました。
nil をセットすると、
継承するデフォルト挙動が消えるようなので、
nilの時はifで避けます。

参考:
https://developer.apple.com/documentation/foundation/process/1409412-environment

If this method isn’t used, the environment is inherited from the process that created the receiver

}
try process.checkRun(
printsLoadingMessage: printsLoadingMessage,
forwardExit: forwardExit
Expand Down
22 changes: 17 additions & 5 deletions Sources/CartonDriver/CartonDriverCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,19 +135,30 @@ func pluginSubcommand(subcommand: String, argv0: String, arguments: [String]) as

let terminal = InteractiveWriter.stdout
let toolchainSystem = try ToolchainSystem(fileSystem: localFileSystem)
let (swiftPath, _) = try await toolchainSystem.inferSwiftPath(terminal)
let swiftPath = try await toolchainSystem.inferSwiftPath(terminal)
let extraArguments = arguments

let swiftExec = URL(fileURLWithPath: swiftPath.pathString)
let swiftExec = URL(fileURLWithPath: swiftPath.swift.pathString)
let pluginArguments = try derivePackageCommandArguments(
swiftExec: swiftExec,
subcommand: subcommand,
scratchPath: scratchPath.path,
extraArguments: extraArguments
)

var env: [String: String] = ProcessInfo.processInfo.environment
if ToolchainSystem.isSnapshotVersion(swiftPath.verison),
swiftPath.toolchain.extension == "xctoolchain"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mac環境かつsnapshotなら、DYLD... を設定します。

{
env["DYLD_LIBRARY_PATH"] = swiftPath.toolchain.appending(
components: ["usr", "lib", "swift", "macosx"]
).pathString
}

try Foundation.Process.checkRun(
swiftExec, arguments: pluginArguments,
swiftExec,
arguments: pluginArguments,
environment: env,
forwardExit: true
)
}
Expand Down Expand Up @@ -175,9 +186,10 @@ public func main(arguments: [String]) async throws {
case "package":
let terminal = InteractiveWriter.stdout
let toolchainSystem = try ToolchainSystem(fileSystem: localFileSystem)
let (swiftPath, _) = try await toolchainSystem.inferSwiftPath(terminal)
let swiftPath = try await toolchainSystem.inferSwiftPath(terminal)

try Foundation.Process.checkRun(
URL(fileURLWithPath: swiftPath.pathString),
URL(fileURLWithPath: swiftPath.swift.pathString),
arguments: ["package"] + arguments.dropFirst(),
forwardExit: true
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,16 @@ struct CommandTestRunner: TestRunner {
var arguments = [program, testFilePath.pathString]
if listTestCases {
arguments.append(contentsOf: ["--", "-l"])
} else if !testCases.isEmpty {
arguments.append("--")
arguments.append(contentsOf: testCases)
} else {
let programName = (program as NSString).lastPathComponent
if programName == "wasmtime" {
arguments += ["--dir", "."]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wasmtimeのpreopenの問題の対応

}

if !testCases.isEmpty {
arguments.append("--")
arguments.append(contentsOf: testCases)
}
}
try await Process.run(arguments, parser: TestsParser(), terminal)
}
Expand Down
4 changes: 3 additions & 1 deletion Sources/CartonHelpers/DefaultToolchain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#if compiler(>=5.10)
#if compiler(>=6.0)
public let defaultToolchainVersion = "wasm-6.0-SNAPSHOT-2024-06-08-a"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6.0のsnapshotを追加します。
CIのSwift6.0が swift-6.0-DEVELOPMENT-SNAPSHOT-2024-06-07-a になっていて、
それと対応する wasm swift にしています。
だから1日ズレています。

#elseif compiler(>=5.10)
public let defaultToolchainVersion = "wasm-5.10.0-RELEASE"
#else
public let defaultToolchainVersion = "wasm-5.9.2-RELEASE"
Expand Down
3 changes: 1 addition & 2 deletions Sources/CartonHelpers/Process+run.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ extension Process {

switch result.map(\.exitStatus) {
case .success(.terminated(code: EXIT_SUCCESS)):
terminal.write("\n")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この改行が不要そうでした。

if let parser = parser {
if parser.parsingConditions.contains(.success) {
parser.parse(stdoutBuffer, terminal)
Expand All @@ -103,7 +102,7 @@ extension Process {
terminal.write(stdoutBuffer)
}
terminal.write(
"\n`\(processName)` process finished successfully\n",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この冒頭の改行も不要だと思いました。

"`\(processName)` process finished successfully\n",
inColor: .green,
bold: false
)
Expand Down
8 changes: 4 additions & 4 deletions Sources/CartonKit/Server/StaticArchive.swift

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions Sources/SwiftToolchain/ToolchainInstallation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import CartonCore
import CartonHelpers
import Foundation

Expand Down Expand Up @@ -65,6 +66,8 @@ extension ToolchainSystem {
stream: stdoutStream,
header: "Downloading the archive"
)
defer { terminal.write("\n") }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ダウンロードが完了した時
Download completed successfully
のメッセージが saving to ... の右に表示されていておかしかったので、改行を入れます。

ここはターミナルがアニメーションするループがあるので、
エラーの場合もうまくいくように
defer でここに書きます。


var previouslyReceived = 0
for try await progress in fileDownload.progressStream {
guard progress.receivedBytes - previouslyReceived >= (progress.totalOrEstimatedBytes / 100)
Expand Down Expand Up @@ -109,6 +112,32 @@ extension ToolchainSystem {
terminal.logLookup("Unpacking the archive: ", arguments.joined(separator: " "))
try await Process.run(arguments, terminal)

if ext == "pkg", Self.isSnapshotVersion(version) {
try await patchSnapshotForMac(path: installationPath, terminal: terminal)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

インストール後にmacでsnapshotならパッチ(再署名)します。

}

return installationPath
}

func patchSnapshotForMac(path: AbsolutePath, terminal: InteractiveWriter) async throws {
let binDir = path.appending(components: ["usr", "bin"])

terminal.write(
"To avoid issues with the snapshot, the toolchain will be re-signed.\n",
inColor: .yellow
)

for file in try fileSystem.traverseRecursively(binDir) {
guard fileSystem.isFile(file) else { continue }

try Foundation.Process.checkRun(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

出力がスッキリするので Foundation.Process.checkRun を使いました。

URL(fileURLWithPath: "/usr/bin/codesign"),
arguments: [
"--force",
"--preserve-metadata=identifier,entitlements",
"--sign", "-", file.pathString
]
)
}
}
}
22 changes: 15 additions & 7 deletions Sources/SwiftToolchain/ToolchainManagement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -235,13 +235,19 @@ public class ToolchainSystem {
}
}

public struct SwiftPath {
public var verison: String
public var swift: AbsolutePath
public var toolchain: AbsolutePath
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

従来、swiftとバージョンのタプルでしたが、
ツールチェーンディレクトリも使いたくなったので追加します。

ついでにタプルをやめて型にすることで利用側のコードを読みやすくします。


/** Infer `swift` binary path matching a given version if any is present, or infer the
version from the `.swift-version` file. If neither version is installed, download it.
*/
public func inferSwiftPath(
from versionSpec: String? = nil,
_ terminal: InteractiveWriter
) async throws -> (AbsolutePath, String) {
) async throws -> SwiftPath {
let specURL = versionSpec.flatMap { (string: String) -> Foundation.URL? in
guard
let url = Foundation.URL(string: string),
Expand All @@ -254,11 +260,9 @@ public class ToolchainSystem {
let swiftVersion = try inferSwiftVersion(from: versionSpec, terminal)

for resolver in resolvers {
if let path = try checkAndLog(
installationPath: resolver.toolchain(for: swiftVersion),
terminal
) {
return (path, swiftVersion)
let toolchain = resolver.toolchain(for: swiftVersion)
if let path = try checkAndLog(installationPath: toolchain, terminal) {
return SwiftPath(verison: swiftVersion, swift: path, toolchain: toolchain)
}
}

Expand Down Expand Up @@ -291,7 +295,7 @@ public class ToolchainSystem {
throw ToolchainError.invalidInstallationArchive(installationPath)
}

return (path, swiftVersion)
return SwiftPath(verison: swiftVersion, swift: path, toolchain: installationPath)
}

public func fetchAllSwiftVersions() throws -> [String] {
Expand All @@ -311,4 +315,8 @@ public class ToolchainSystem {

return version
}

public static func isSnapshotVersion(_ version: String) -> Bool {
version.contains("SNAPSHOT")
}
}
4 changes: 2 additions & 2 deletions Tests/CartonCommandTests/FrontendDevServerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ final class FrontendDevServerTests: XCTestCase {

if !fs.exists(wasmFile) {
let tools = try ToolchainSystem(fileSystem: fs)
let (builderSwift, _) = try await tools.inferSwiftPath(terminal)
let builderSwift = try await tools.inferSwiftPath(terminal)

var args: [String] = [
builderSwift.pathString, "build", "--triple", "wasm32-unknown-wasi"
builderSwift.swift.pathString, "build", "--triple", "wasm32-unknown-wasi"
]
args += Environment.browser.buildParameters().asBuildArguments()

Expand Down
2 changes: 1 addition & 1 deletion entrypoint/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export const WasmRunner = (rawOptions: Options, SwiftRuntime: SwiftRuntimeConstr
};

const defaultRunnerOptions = (options: Options): Options => {
if (options.args != null) {
if (options.args == null) {
options.args = ["main.wasm"];
}
return options;
Expand Down