From 9fcd3f2b5e7f38d37a0ddf433a3dc70484527a53 Mon Sep 17 00:00:00 2001 From: stevapple Date: Mon, 14 Sep 2020 00:30:45 +0800 Subject: [PATCH 01/10] Implement WindowsToolchain --- README.md | 2 +- Sources/SwiftDriver/CMakeLists.txt | 4 +- Sources/SwiftDriver/Driver/Driver.swift | 4 +- .../Jobs/CommandLineArguments.swift | 8 +- .../Jobs/Toolchain+InterpreterSupport.swift | 11 + .../Jobs/Toolchain+LinkerSupport.swift | 23 ++ .../Jobs/WindowsToolchain+LinkerSupport.swift | 220 ++++++++++++++++++ .../SwiftDriver/Toolchains/Toolchain.swift | 8 +- .../Toolchains/WindowsToolchain.swift | 94 ++++++++ 9 files changed, 363 insertions(+), 11 deletions(-) create mode 100644 Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift create mode 100644 Sources/SwiftDriver/Toolchains/WindowsToolchain.swift diff --git a/README.md b/README.md index d0d58d7d6..fa49d4e59 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ The goal of the new Swift driver is to provide a drop-in replacement for the exi * Platform support * [x] Teach the `DarwinToolchain` to also handle iOS, tvOS, watchOS * [x] Fill out the `GenericUnixToolchain` toolchain to get it working - * [ ] Implement a `WindowsToolchain` + * [x] Implement a `WindowsToolchain` * [x] Implement proper tokenization for response files * Compilation modes * [x] Batch mode diff --git a/Sources/SwiftDriver/CMakeLists.txt b/Sources/SwiftDriver/CMakeLists.txt index 73a31a8f0..be7edfd67 100644 --- a/Sources/SwiftDriver/CMakeLists.txt +++ b/Sources/SwiftDriver/CMakeLists.txt @@ -1,6 +1,6 @@ # This source file is part of the Swift.org open source project # -# Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +# Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors # Licensed under Apache License v2.0 with Runtime Library Exception # # See http://swift.org/LICENSE.txt for license information @@ -57,10 +57,12 @@ add_library(SwiftDriver Jobs/Toolchain+InterpreterSupport.swift Jobs/Toolchain+LinkerSupport.swift Jobs/VerifyDebugInfoJob.swift + Jobs/WindowsToolchain+LinkerSupport.swift Toolchains/DarwinToolchain.swift Toolchains/GenericUnixToolchain.swift Toolchains/Toolchain.swift + Toolchains/WindowsToolchain.swift Utilities/Bits.swift Utilities/Bitstream.swift diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index 001648fe3..b2ed3695f 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -1702,7 +1702,7 @@ extension Triple { case .freeBSD, .haiku: return GenericUnixToolchain.self case .win32: - fatalError("Windows target not supported yet") + return WindowsToolchain.self default: diagnosticsEngine.emit(.error_unknown_target(triple)) throw Diagnostics.fatalError @@ -1715,7 +1715,7 @@ extension Driver { #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) static let defaultToolchainType: Toolchain.Type = DarwinToolchain.self #elseif os(Windows) - static let defaultToolchainType: Toolchain.Type = { fatalError("Windows target not supported yet") }() + static let defaultToolchainType: Toolchain.Type = WindowsToolchain.self #else static let defaultToolchainType: Toolchain.Type = GenericUnixToolchain.self #endif diff --git a/Sources/SwiftDriver/Jobs/CommandLineArguments.swift b/Sources/SwiftDriver/Jobs/CommandLineArguments.swift index 06e76a188..b560d4f8b 100644 --- a/Sources/SwiftDriver/Jobs/CommandLineArguments.swift +++ b/Sources/SwiftDriver/Jobs/CommandLineArguments.swift @@ -165,10 +165,10 @@ extension Array where Element == Job.ArgTemplate { var joinedArguments: String { return self.map { switch $0 { - case .flag(let string): - return string.spm_shellEscaped() - case .path(let path): - return path.name.spm_shellEscaped() + case .flag(let string): + return string.spm_shellEscaped() + case .path(let path): + return path.name.spm_shellEscaped() case .responseFilePath(let path): return "@\(path.name.spm_shellEscaped())" case let .joinedOptionAndPath(option, path): diff --git a/Sources/SwiftDriver/Jobs/Toolchain+InterpreterSupport.swift b/Sources/SwiftDriver/Jobs/Toolchain+InterpreterSupport.swift index fc9e9628c..ab860276e 100644 --- a/Sources/SwiftDriver/Jobs/Toolchain+InterpreterSupport.swift +++ b/Sources/SwiftDriver/Jobs/Toolchain+InterpreterSupport.swift @@ -81,3 +81,14 @@ extension GenericUnixToolchain { return envVars } } + +extension WindowsToolchain { + public func platformSpecificInterpreterEnvironmentVariables( + env: [String : String], + parsedOptions: inout ParsedOptions, + sdkPath: String?, + targetTriple: Triple) throws -> [String: String] { + // TODO: See whether Windows needs `platformSpecificInterpreterEnvironmentVariables` + return [:] + } +} diff --git a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift index a9ad52e12..6bdc469ba 100644 --- a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift @@ -30,6 +30,12 @@ extension Toolchain { resourceDirBase = sdkPath .appending(components: "usr", "lib", isShared ? "swift" : "swift_static") + } else if triple.isWindows, + let SDKROOT = env["SDKROOT"], + let sdkPath = try? AbsolutePath(validating: SDKROOT) { + resourceDirBase = sdkPath + .appending(components: "usr", "lib", + isShared ? "swift" : "swift_static") } else { resourceDirBase = try getToolPath(.swiftCompiler) .parentDirectory // remove /swift @@ -48,6 +54,21 @@ extension Toolchain { for triple: Triple, parsedOptions: inout ParsedOptions ) throws -> AbsolutePath { + /// Use the one in `VCTools` if exists on Windows. + if triple.isWindows, + let vctools = env["VCToolsInstallDir"], + let root = try? AbsolutePath(validating: vctools) { + let archName: String = { + switch triple.arch { + case .aarch64, .aarch64_32: return "arm64" + case .arm: return "arm" + case .x86: return "x86" + case nil, .x86_64: return "x64" + default: fatalError("unknown arch \(triple.archName) on Windows") + } + }() + return root.appending(components: "lib", archName) + } return try computeResourceDirPath(for: triple, parsedOptions: &parsedOptions, isShared: true) @@ -258,3 +279,5 @@ extension DarwinToolchain { } } + +// TODO: See whether Windows needs `addArgsToLinkStdlib`. diff --git a/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift new file mode 100644 index 000000000..0f1d9ab12 --- /dev/null +++ b/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift @@ -0,0 +1,220 @@ +//===---------------- WindowsToolchain+LinkerSupport.swift ----------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 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 TSCBasic +import SwiftOptions + +extension WindowsToolchain { + public func addPlatformSpecificLinkerArgs( + to commandLine: inout [Job.ArgTemplate], + parsedOptions: inout ParsedOptions, + linkerOutputType: LinkOutputType, + inputs: [TypedVirtualPath], + outputFile: VirtualPath, + shouldUseInputFileList: Bool, + sdkPath: String?, + sanitizers: Set, + targetInfo: FrontendTargetInfo + ) throws -> AbsolutePath { + let targetTriple = targetInfo.target.triple + switch linkerOutputType { + case .dynamicLibrary: + // Same options as an executable, just with '-shared' + commandLine.appendFlags("-parse-as-library", "-emit-library") + fallthrough + case .executable: + if !targetTriple.triple.isEmpty { + commandLine.appendFlag("-target") + commandLine.appendFlag(targetTriple.triple) + } + commandLine.appendFlag("-emit-executable") + default: + break + } + + switch linkerOutputType { + case .staticLibrary: + commandLine.append(.joinedOptionAndPath("-out:", outputFile)) + commandLine.append(contentsOf: inputs.map { .path($0.file) }) + return try getToolPath(.staticLinker) + default: + // 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.exe", searchPaths: [toolsDir]) { + clangPath = tool + } + + // Look for binutils in the toolchain folder. + commandLine.appendFlag("-B") + commandLine.appendPath(toolsDir) + } + + let staticStdlib = parsedOptions.hasFlag(positive: .staticStdlib, + negative: .noStaticStdlib, + default: false) + let staticExecutable = parsedOptions.hasFlag(positive: .staticExecutable, + negative: .noStaticExecutable, + default: false) + let hasRuntimeArgs = !(staticStdlib || staticExecutable) + + let runtimePaths = try runtimeLibraryPaths( + for: targetTriple, + parsedOptions: &parsedOptions, + sdkPath: sdkPath, + isShared: hasRuntimeArgs + ) + + if hasRuntimeArgs && targetTriple.environment != .android { + // FIXME: We probably shouldn't be adding an rpath here unless we know + // ahead of time the standard library won't be copied. + for path in runtimePaths { + commandLine.appendFlag(.Xlinker) + commandLine.appendFlag("-rpath") + commandLine.appendFlag(.Xlinker) + commandLine.appendPath(path) + } + } + + let sharedResourceDirPath = try computeResourceDirPath( + for: targetTriple, + parsedOptions: &parsedOptions, + isShared: true + ) + + let swiftrtPath = sharedResourceDirPath + .appending( + components: "x86_64", "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) + + let fSystemArgs = parsedOptions.arguments(for: .F, .Fsystem) + for opt in fSystemArgs { + if opt.option == .Fsystem { + commandLine.appendFlag("-iframework") + } else { + commandLine.appendFlag(.F) + } + commandLine.appendPath(try VirtualPath(path: opt.argument.asSingle)) + } + + // Add the runtime library link paths. + for path in runtimePaths { + commandLine.appendFlag(.L) + commandLine.appendPath(path) + } + + // Link the standard library. In two paths, we do this using a .lnk file + // if we're going that route, we'll set `linkFilePath` to the path to that + // file. + var linkFilePath: AbsolutePath? = try computeResourceDirPath( + for: targetTriple, + parsedOptions: &parsedOptions, + isShared: false + ) + + if staticExecutable { + linkFilePath = linkFilePath?.appending(component: "static-executable-args.lnk") + } else if staticStdlib { + linkFilePath = linkFilePath?.appending(component: "static-stdlib-args.lnk") + } else { + linkFilePath = nil + commandLine.appendFlag("-lswiftCore") + } + + if let linkFile = linkFilePath { + guard fileSystem.isFile(linkFile) else { + fatalError("\(linkFile.pathString) not found") + } + commandLine.append(.responseFilePath(.absolute(linkFile))) + } + + // 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. + if linkerOutputType == .executable && !sanitizers.isEmpty { + let sanitizerNames = sanitizers + .map { $0.rawValue } + .sorted() // Sort so we get a stable, testable order + .joined(separator: ",") + commandLine.appendFlag("-fsanitize=\(sanitizerNames)") + + // The TSan runtime depends on the blocks runtime and libdispatch. + if sanitizers.contains(.thread) { + commandLine.appendFlag("-lBlocksRuntime") + commandLine.appendFlag("-ldispatch") + } + } + + if parsedOptions.hasArgument(.profileGenerate) { + let libProfile = sharedResourceDirPath + .parentDirectory // remove platform name + .appending(components: "clang", "lib", targetTriple.osName, + "libclangrt_profile-\(targetTriple.archName).a") + commandLine.appendPath(libProfile) + + // HACK: Hard-coded from llvm::getInstrProfRuntimeHookVarName() + commandLine.appendFlag("-u__llvm_profile_runtime") + } + + // 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.append( + contentsOf: parsedOptions.arguments(in: .linkerOption) + ) + 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 clangPath + } + + } +} diff --git a/Sources/SwiftDriver/Toolchains/Toolchain.swift b/Sources/SwiftDriver/Toolchains/Toolchain.swift index 11ec15ab4..076d14f9f 100644 --- a/Sources/SwiftDriver/Toolchains/Toolchain.swift +++ b/Sources/SwiftDriver/Toolchains/Toolchain.swift @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 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 @@ -135,7 +135,7 @@ extension Toolchain { return path } else if let path = try? xcrunFind(executable: executable) { return path - } else if !["swift-frontend", "swift"].contains(executable), + } else if !["swift-frontend", "swift", "swift-frontend.exe", "swift.exe"].contains(executable), let parentDirectory = try? getToolPath(.swiftCompiler).parentDirectory, parentDirectory != executableDir, let path = lookupExecutablePath(filename: executable, searchPaths: [parentDirectory]) { @@ -144,9 +144,11 @@ extension Toolchain { return path } else if let path = lookupExecutablePath(filename: executable, searchPaths: searchPaths) { return path + // Temporary shim: fall back to looking for "swift" before failing. } else if executable == "swift-frontend" { - // Temporary shim: fall back to looking for "swift" before failing. return try lookup(executable: "swift") + } else if executable == "swift-frontend.exe" { + return try lookup(executable: "swift.exe") } else if fallbackToExecutableDefaultPath { return AbsolutePath("/usr/bin/" + executable) } else { diff --git a/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift b/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift new file mode 100644 index 000000000..d34309496 --- /dev/null +++ b/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift @@ -0,0 +1,94 @@ +//===--------- WindowsToolchain.swift - Swift Windows Toolchain -----------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 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 TSCBasic + +/// Toolchain for Windows. +public final class WindowsToolchain: Toolchain { + public let env: [String: String] + + /// The executor used to run processes used to find tools and retrieve target info. + public let executor: DriverExecutor + + /// The file system to use for queries. + public let fileSystem: FileSystem + + /// Doubles as path cache and point for overriding normal lookup + private var toolPaths = [Tool: AbsolutePath]() + + public init(env: [String: String], executor: DriverExecutor, fileSystem: FileSystem = localFileSystem) { + self.env = env + self.executor = executor + self.fileSystem = fileSystem + } + + public func makeLinkerOutputFilename(moduleName: String, type: LinkOutputType) -> String { + switch type { + case .executable: return "\(moduleName).exe" + case .dynamicLibrary: return "\(moduleName).dll" + case .staticLibrary: return "\(moduleName).lib" + } + } + + /// Retrieve the absolute path for a given tool. + public func getToolPath(_ tool: Tool) throws -> AbsolutePath { + // Check the cache + if let toolPath = toolPaths[tool] { + return toolPath + } + let path = try lookupToolPath(tool) + // Cache the path + toolPaths[tool] = path + return path + } + + private func lookupToolPath(_ tool: Tool) throws -> AbsolutePath { + switch tool { + case .swiftCompiler: + return try lookup(executable: "swift-frontend.exe") + case .staticLinker: + return try lookup(executable: "llvm-lib.exe") + case .dynamicLinker: + // FIXME: This needs to look in the tools_directory first. + return try lookup(executable: "lld-link.exe") + case .clang: + return try lookup(executable: "clang.exe") + case .swiftAutolinkExtract: + return try lookup(executable: "swift-autolink-extract.exe") + case .dsymutil: + return try lookup(executable: "dsymutil.exe") + case .lldb: + return try lookup(executable: "lldb.exe") + case .dwarfdump: + return try lookup(executable: "llvm-dwarfdump.exe") + case .swiftHelp: + return try lookup(executable: "swift-help.exe") + } + } + + public func overrideToolPath(_ tool: Tool, path: AbsolutePath) { + toolPaths[tool] = path + } + + public func defaultSDKPath(_ target: Triple?) throws -> AbsolutePath? { + return nil + } + + public var shouldStoreInvocationInDebugInfo: Bool { false } + + public func runtimeLibraryName( + for sanitizer: Sanitizer, + targetTriple: Triple, + isShared: Bool + ) throws -> String { + return "clang_rt.\(sanitizer.libraryName)-\(targetTriple.archName).dll" + } +} From 9076ab2d5b55ba9f7f9fbb3a2fa3d27d0b91a066 Mon Sep 17 00:00:00 2001 From: stevapple Date: Mon, 14 Sep 2020 00:59:58 +0800 Subject: [PATCH 02/10] Fix swiftrtPath --- .../Jobs/WindowsToolchain+LinkerSupport.swift | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift index 0f1d9ab12..03714d22e 100644 --- a/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift @@ -93,7 +93,7 @@ extension WindowsToolchain { isShared: hasRuntimeArgs ) - if hasRuntimeArgs && targetTriple.environment != .android { + if hasRuntimeArgs { // FIXME: We probably shouldn't be adding an rpath here unless we know // ahead of time the standard library won't be copied. for path in runtimePaths { @@ -110,10 +110,9 @@ extension WindowsToolchain { isShared: true ) - let swiftrtPath = sharedResourceDirPath - .appending( - components: "x86_64", "swiftrt.o" - ) + let swiftrtPath = sharedResourceDirPath.appending( + components: "windows", targetTriple.archName, "swiftrt.obj" + ) commandLine.appendPath(swiftrtPath) let inputFiles: [Job.ArgTemplate] = inputs.compactMap { input in From 2c9716b749f3925cb3047741a97097105fbc9743 Mon Sep 17 00:00:00 2001 From: stevapple Date: Mon, 14 Sep 2020 13:40:18 +0800 Subject: [PATCH 03/10] Fix various problems --- .../Jobs/Toolchain+LinkerSupport.swift | 4 +-- .../Jobs/WindowsToolchain+LinkerSupport.swift | 26 ++++++------------- .../Toolchains/WindowsToolchain.swift | 19 ++++++++++---- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift index 6bdc469ba..4dd95e0b9 100644 --- a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift @@ -60,7 +60,7 @@ extension Toolchain { let root = try? AbsolutePath(validating: vctools) { let archName: String = { switch triple.arch { - case .aarch64, .aarch64_32: return "arm64" + case .aarch64: return "arm64" case .arm: return "arm" case .x86: return "x86" case nil, .x86_64: return "x64" @@ -280,4 +280,4 @@ extension DarwinToolchain { } -// TODO: See whether Windows needs `addArgsToLinkStdlib`. +// TODO: Implement `addArgsToLinkStdlib` for `WindowsToolchain`. diff --git a/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift index 03714d22e..d771479e5 100644 --- a/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift @@ -27,24 +27,26 @@ extension WindowsToolchain { let targetTriple = targetInfo.target.triple switch linkerOutputType { case .dynamicLibrary: - // Same options as an executable, just with '-shared' commandLine.appendFlags("-parse-as-library", "-emit-library") - fallthrough case .executable: if !targetTriple.triple.isEmpty { commandLine.appendFlag("-target") commandLine.appendFlag(targetTriple.triple) } - commandLine.appendFlag("-emit-executable") + commandLine.appendFlag("-emit-executable") default: break } - + switch linkerOutputType { case .staticLibrary: - commandLine.append(.joinedOptionAndPath("-out:", outputFile)) - commandLine.append(contentsOf: inputs.map { .path($0.file) }) + commandLine.append(.joinedOptionAndPath("-out:", outputFile)) + commandLine.append(contentsOf: inputs.map { .path($0.file) }) + if commandLine.contains(.flag("-use-ld=lld")) { + return try lookup(executable: "llvm-lib.exe") + } return try getToolPath(.staticLinker) + // TODO: Check for `-use-ld=lld`. default: // Configure the toolchain. // @@ -93,17 +95,6 @@ extension WindowsToolchain { isShared: hasRuntimeArgs ) - if hasRuntimeArgs { - // FIXME: We probably shouldn't be adding an rpath here unless we know - // ahead of time the standard library won't be copied. - for path in runtimePaths { - commandLine.appendFlag(.Xlinker) - commandLine.appendFlag("-rpath") - commandLine.appendFlag(.Xlinker) - commandLine.appendPath(path) - } - } - let sharedResourceDirPath = try computeResourceDirPath( for: targetTriple, parsedOptions: &parsedOptions, @@ -214,6 +205,5 @@ extension WindowsToolchain { commandLine.appendPath(outputFile) return clangPath } - } } diff --git a/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift b/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift index d34309496..d7f29c4b1 100644 --- a/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift +++ b/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift @@ -55,16 +55,16 @@ public final class WindowsToolchain: Toolchain { case .swiftCompiler: return try lookup(executable: "swift-frontend.exe") case .staticLinker: - return try lookup(executable: "llvm-lib.exe") + return try lookup(executable: "lib.exe") case .dynamicLinker: // FIXME: This needs to look in the tools_directory first. - return try lookup(executable: "lld-link.exe") + return try lookup(executable: "link.exe") case .clang: return try lookup(executable: "clang.exe") case .swiftAutolinkExtract: - return try lookup(executable: "swift-autolink-extract.exe") + fatalError("Trying to look up \"swift-autolink-extract\" on Windows") case .dsymutil: - return try lookup(executable: "dsymutil.exe") + fatalError("Trying to look up \"dsymutil\" on Windows") case .lldb: return try lookup(executable: "lldb.exe") case .dwarfdump: @@ -89,6 +89,15 @@ public final class WindowsToolchain: Toolchain { targetTriple: Triple, isShared: Bool ) throws -> String { - return "clang_rt.\(sanitizer.libraryName)-\(targetTriple.archName).dll" + let archName: String = { + switch targetTriple.arch { + case .aarch64: return "aarch64" + case .arm: return "armv7" + case .x86: return "i386" + case nil, .x86_64: return "x86_64" + default: fatalError("unknown arch \(targetTriple.archName) on Windows") + } + }() + return "clang_rt.\(sanitizer.libraryName)-\(archName).lib" } } From 8b7b0df2f859fd57fa9472e685a7714a702d9097 Mon Sep 17 00:00:00 2001 From: stevapple Date: Mon, 14 Sep 2020 15:10:07 +0800 Subject: [PATCH 04/10] Derive executable file name from Toolchain --- .../Toolchains/DarwinToolchain.swift | 9 ++++++--- .../Toolchains/GenericUnixToolchain.swift | 3 +++ Sources/SwiftDriver/Toolchains/Toolchain.swift | 15 ++++++++------- .../Toolchains/WindowsToolchain.swift | 17 ++++++++++------- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift b/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift index e63ed010b..c6627b37e 100644 --- a/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift +++ b/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift @@ -20,15 +20,18 @@ import SwiftOptions public final class DarwinToolchain: Toolchain { public let env: [String: String] - /// Doubles as path cache and point for overriding normal lookup - private var toolPaths = [Tool: AbsolutePath]() - /// The executor used to run processes used to find tools and retrieve target info. public let executor: DriverExecutor /// The file system to use for any file operations. public let fileSystem: FileSystem + /// The suffix of executable files. + public let executableSuffix = "" + + /// Doubles as path cache and point for overriding normal lookup + private var toolPaths = [Tool: AbsolutePath]() + public init(env: [String: String], executor: DriverExecutor, fileSystem: FileSystem = localFileSystem) { self.env = env self.executor = executor diff --git a/Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift b/Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift index 09ca4d00a..5a9bf124f 100644 --- a/Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift +++ b/Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift @@ -21,6 +21,9 @@ public final class GenericUnixToolchain: Toolchain { /// The file system to use for queries. public let fileSystem: FileSystem + /// The suffix of executable files. + public let executableSuffix = "" + /// Doubles as path cache and point for overriding normal lookup private var toolPaths = [Tool: AbsolutePath]() diff --git a/Sources/SwiftDriver/Toolchains/Toolchain.swift b/Sources/SwiftDriver/Toolchains/Toolchain.swift index 076d14f9f..d1b434ae2 100644 --- a/Sources/SwiftDriver/Toolchains/Toolchain.swift +++ b/Sources/SwiftDriver/Toolchains/Toolchain.swift @@ -38,6 +38,8 @@ public protocol Toolchain { var executor: DriverExecutor { get } + var executableSuffix: String { get } + /// Retrieve the absolute path to a particular tool. func getToolPath(_ tool: Tool) throws -> AbsolutePath @@ -129,26 +131,25 @@ extension Toolchain { /// looks in the `executableDir`, `xcrunFind` or in the `searchPaths`. /// - Parameter executable: executable to look for [i.e. `swift`]. func lookup(executable: String) throws -> AbsolutePath { + let filename = executable + executableSuffix if let overrideString = envVar(forExecutable: executable) { return try AbsolutePath(validating: overrideString) - } else if let path = lookupExecutablePath(filename: executable, searchPaths: [executableDir]) { + } else if let path = lookupExecutablePath(filename: filename, searchPaths: [executableDir]) { return path } else if let path = try? xcrunFind(executable: executable) { return path - } else if !["swift-frontend", "swift", "swift-frontend.exe", "swift.exe"].contains(executable), + } else if !["swift-frontend", "swift"].contains(executable), let parentDirectory = try? getToolPath(.swiftCompiler).parentDirectory, parentDirectory != executableDir, - let path = lookupExecutablePath(filename: executable, searchPaths: [parentDirectory]) { + let path = lookupExecutablePath(filename: filename, searchPaths: [parentDirectory]) { // If the driver library's client and the frontend are in different directories, // try looking for tools next to the frontend. return path - } else if let path = lookupExecutablePath(filename: executable, searchPaths: searchPaths) { + } else if let path = lookupExecutablePath(filename: filename, searchPaths: searchPaths) { return path - // Temporary shim: fall back to looking for "swift" before failing. } else if executable == "swift-frontend" { + // Temporary shim: fall back to looking for "swift" before failing. return try lookup(executable: "swift") - } else if executable == "swift-frontend.exe" { - return try lookup(executable: "swift.exe") } else if fallbackToExecutableDefaultPath { return AbsolutePath("/usr/bin/" + executable) } else { diff --git a/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift b/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift index d7f29c4b1..7ae4db01b 100644 --- a/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift +++ b/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift @@ -21,6 +21,9 @@ public final class WindowsToolchain: Toolchain { /// The file system to use for queries. public let fileSystem: FileSystem + /// The suffix of executable files. + public let executableSuffix = ".exe" + /// Doubles as path cache and point for overriding normal lookup private var toolPaths = [Tool: AbsolutePath]() @@ -53,24 +56,24 @@ public final class WindowsToolchain: Toolchain { private func lookupToolPath(_ tool: Tool) throws -> AbsolutePath { switch tool { case .swiftCompiler: - return try lookup(executable: "swift-frontend.exe") + return try lookup(executable: "swift-frontend") case .staticLinker: - return try lookup(executable: "lib.exe") + return try lookup(executable: "lib") case .dynamicLinker: // FIXME: This needs to look in the tools_directory first. - return try lookup(executable: "link.exe") + return try lookup(executable: "link") case .clang: - return try lookup(executable: "clang.exe") + return try lookup(executable: "clang") case .swiftAutolinkExtract: fatalError("Trying to look up \"swift-autolink-extract\" on Windows") case .dsymutil: fatalError("Trying to look up \"dsymutil\" on Windows") case .lldb: - return try lookup(executable: "lldb.exe") + return try lookup(executable: "lldb") case .dwarfdump: - return try lookup(executable: "llvm-dwarfdump.exe") + return try lookup(executable: "llvm-dwarfdump") case .swiftHelp: - return try lookup(executable: "swift-help.exe") + return try lookup(executable: "swift-help") } } From 3c0feb330778fcf501bdb07519959ed91371e174 Mon Sep 17 00:00:00 2001 From: stevapple Date: Tue, 15 Sep 2020 00:22:40 +0800 Subject: [PATCH 05/10] Fix addPlatformSpecificLinkerArgs for WindowsToolchain --- .../Jobs/Toolchain+LinkerSupport.swift | 15 - .../Jobs/WindowsToolchain+LinkerSupport.swift | 293 ++++++++---------- .../Toolchains/WindowsToolchain.swift | 23 +- 3 files changed, 145 insertions(+), 186 deletions(-) diff --git a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift index 4dd95e0b9..44702d3ff 100644 --- a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift @@ -54,21 +54,6 @@ extension Toolchain { for triple: Triple, parsedOptions: inout ParsedOptions ) throws -> AbsolutePath { - /// Use the one in `VCTools` if exists on Windows. - if triple.isWindows, - let vctools = env["VCToolsInstallDir"], - let root = try? AbsolutePath(validating: vctools) { - let archName: String = { - switch triple.arch { - case .aarch64: return "arm64" - case .arm: return "arm" - case .x86: return "x86" - case nil, .x86_64: return "x64" - default: fatalError("unknown arch \(triple.archName) on Windows") - } - }() - return root.appending(components: "lib", archName) - } return try computeResourceDirPath(for: triple, parsedOptions: &parsedOptions, isShared: true) diff --git a/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift index d771479e5..ad520fd10 100644 --- a/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift @@ -25,185 +25,158 @@ extension WindowsToolchain { targetInfo: FrontendTargetInfo ) throws -> AbsolutePath { let targetTriple = targetInfo.target.triple + switch linkerOutputType { case .dynamicLibrary: - commandLine.appendFlags("-parse-as-library", "-emit-library") + commandLine.appendFlags("-Xlinker", "-dll") + fallthrough case .executable: if !targetTriple.triple.isEmpty { commandLine.appendFlag("-target") commandLine.appendFlag(targetTriple.triple) } - commandLine.appendFlag("-emit-executable") - default: - break - } - - switch linkerOutputType { - case .staticLibrary: - commandLine.append(.joinedOptionAndPath("-out:", outputFile)) - commandLine.append(contentsOf: inputs.map { .path($0.file) }) - if commandLine.contains(.flag("-use-ld=lld")) { - return try lookup(executable: "llvm-lib.exe") - } - return try getToolPath(.staticLinker) - // TODO: Check for `-use-ld=lld`. - default: - // 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.exe", searchPaths: [toolsDir]) { - clangPath = tool - } - - // Look for binutils in the toolchain folder. - commandLine.appendFlag("-B") - commandLine.appendPath(toolsDir) + // 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.exe", searchPaths: [toolsDir]) { + clangPath = tool } - let staticStdlib = parsedOptions.hasFlag(positive: .staticStdlib, - negative: .noStaticStdlib, - default: false) - let staticExecutable = parsedOptions.hasFlag(positive: .staticExecutable, - negative: .noStaticExecutable, - default: false) - let hasRuntimeArgs = !(staticStdlib || staticExecutable) - - let runtimePaths = try runtimeLibraryPaths( - for: targetTriple, - parsedOptions: &parsedOptions, - sdkPath: sdkPath, - isShared: hasRuntimeArgs - ) - - let sharedResourceDirPath = try computeResourceDirPath( - for: targetTriple, - parsedOptions: &parsedOptions, - isShared: true - ) - - let swiftrtPath = sharedResourceDirPath.appending( - components: "windows", targetTriple.archName, "swiftrt.obj" - ) - 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) - - let fSystemArgs = parsedOptions.arguments(for: .F, .Fsystem) - for opt in fSystemArgs { - if opt.option == .Fsystem { - commandLine.appendFlag("-iframework") - } else { - commandLine.appendFlag(.F) - } - commandLine.appendPath(try VirtualPath(path: opt.argument.asSingle)) - } - - // Add the runtime library link paths. - for path in runtimePaths { - commandLine.appendFlag(.L) - commandLine.appendPath(path) - } + // Look for binutils in the toolchain folder. + commandLine.appendFlag("-B") + commandLine.appendPath(toolsDir) + } - // Link the standard library. In two paths, we do this using a .lnk file - // if we're going that route, we'll set `linkFilePath` to the path to that - // file. - var linkFilePath: AbsolutePath? = try computeResourceDirPath( - for: targetTriple, - parsedOptions: &parsedOptions, - isShared: false - ) - - if staticExecutable { - linkFilePath = linkFilePath?.appending(component: "static-executable-args.lnk") - } else if staticStdlib { - linkFilePath = linkFilePath?.appending(component: "static-stdlib-args.lnk") + let linker: String + if let arg = parsedOptions.getLastArgument(.useLd) { + linker = arg.asSingle + } else { + linker = "link" + } + commandLine.appendFlag("-fuse-ld=\(linker)") + + let staticStdlib = parsedOptions.hasFlag(positive: .staticStdlib, + negative: .noStaticStdlib, + default: false) + let staticExecutable = parsedOptions.hasFlag(positive: .staticExecutable, + negative: .noStaticExecutable, + default: false) + let hasRuntimeArgs = !(staticStdlib || staticExecutable) + + let runtimePaths = try runtimeLibraryPaths( + for: targetTriple, + parsedOptions: &parsedOptions, + sdkPath: sdkPath, + isShared: hasRuntimeArgs + ) + + let sharedResourceDirPath = try computeResourceDirPath( + for: targetTriple, + parsedOptions: &parsedOptions, + isShared: true + ) + + let swiftrtPath = sharedResourceDirPath.appending( + components: targetTriple.archName, "swiftrt.obj" + ) + 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 { - linkFilePath = nil - commandLine.appendFlag("-lswiftCore") + return nil } + } + commandLine.append(contentsOf: inputFiles) - if let linkFile = linkFilePath { - guard fileSystem.isFile(linkFile) else { - fatalError("\(linkFile.pathString) not found") - } - commandLine.append(.responseFilePath(.absolute(linkFile))) + let fSystemArgs = parsedOptions.arguments(for: .F, .Fsystem) + for opt in fSystemArgs { + if opt.option == .Fsystem { + commandLine.appendFlag("-iframework") + } else { + commandLine.appendFlag(.F) } + commandLine.appendPath(try VirtualPath(path: opt.argument.asSingle)) + } - // 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. - if linkerOutputType == .executable && !sanitizers.isEmpty { - let sanitizerNames = sanitizers - .map { $0.rawValue } - .sorted() // Sort so we get a stable, testable order - .joined(separator: ",") - commandLine.appendFlag("-fsanitize=\(sanitizerNames)") - - // The TSan runtime depends on the blocks runtime and libdispatch. - if sanitizers.contains(.thread) { - commandLine.appendFlag("-lBlocksRuntime") - commandLine.appendFlag("-ldispatch") - } - } + // Add the runtime library link paths. + for path in runtimePaths { + commandLine.appendFlag(.L) + commandLine.appendPath(path) + } - if parsedOptions.hasArgument(.profileGenerate) { - let libProfile = sharedResourceDirPath - .parentDirectory // remove platform name - .appending(components: "clang", "lib", targetTriple.osName, - "libclangrt_profile-\(targetTriple.archName).a") - commandLine.appendPath(libProfile) + if hasRuntimeArgs { + commandLine.appendFlag("-lswiftCore") + } - // HACK: Hard-coded from llvm::getInstrProfRuntimeHookVarName() - commandLine.appendFlag("-u__llvm_profile_runtime") + // Explicitly pass the target to the linker + commandLine.appendFlags("-target", targetTriple.triple) + + // Delegate to Clang for sanitizers. It will figure out the correct linker + // options. + if linkerOutputType == .executable && !sanitizers.isEmpty { + let sanitizerNames = sanitizers + .map { $0.rawValue } + .sorted() // Sort so we get a stable, testable order + .joined(separator: ",") + commandLine.appendFlag("-fsanitize=\(sanitizerNames)") + + // The TSan runtime depends on the blocks runtime and libdispatch. + if sanitizers.contains(.thread) { + commandLine.appendFlag("-lBlocksRuntime") + commandLine.appendFlag("-ldispatch") } + } + + if parsedOptions.hasArgument(.profileGenerate) { + let libProfile = try clangLibraryPath(for: targetTriple, parsedOptions: &parsedOptions) + .appending(components: "clang_rt.profile-\(archName(for: targetTriple)).lib") + commandLine.appendPath(libProfile) + } - // 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.append( - contentsOf: parsedOptions.arguments(in: .linkerOption) - ) - 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 clangPath + // 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.append( + contentsOf: parsedOptions.arguments(in: .linkerOption) + ) + 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 clangPath + case .staticLibrary: + commandLine.append(.joinedOptionAndPath("-out:", outputFile)) + commandLine.append(contentsOf: inputs.map { .path($0.file) }) + return try getToolPath(.staticLinker) } } } diff --git a/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift b/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift index 7ae4db01b..88904b853 100644 --- a/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift +++ b/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift @@ -27,6 +27,16 @@ public final class WindowsToolchain: Toolchain { /// Doubles as path cache and point for overriding normal lookup private var toolPaths = [Tool: AbsolutePath]() + public func archName(for triple: Triple) -> String { + switch triple.arch { + case .aarch64: return "aarch64" + case .arm: return "armv7" + case .x86: return "i386" + case nil, .x86_64: return "x86_64" + default: fatalError("unknown arch \(triple.archName) on Windows") + } + } + public init(env: [String: String], executor: DriverExecutor, fileSystem: FileSystem = localFileSystem) { self.env = env self.executor = executor @@ -37,7 +47,7 @@ public final class WindowsToolchain: Toolchain { switch type { case .executable: return "\(moduleName).exe" case .dynamicLibrary: return "\(moduleName).dll" - case .staticLibrary: return "\(moduleName).lib" + case .staticLibrary: return "lib\(moduleName).lib" } } @@ -92,15 +102,6 @@ public final class WindowsToolchain: Toolchain { targetTriple: Triple, isShared: Bool ) throws -> String { - let archName: String = { - switch targetTriple.arch { - case .aarch64: return "aarch64" - case .arm: return "armv7" - case .x86: return "i386" - case nil, .x86_64: return "x86_64" - default: fatalError("unknown arch \(targetTriple.archName) on Windows") - } - }() - return "clang_rt.\(sanitizer.libraryName)-\(archName).lib" + return "clang_rt.\(sanitizer.libraryName)-\(archName(for: targetTriple)).lib" } } From 633801de73bead02059c1e4853c3c889284f26a4 Mon Sep 17 00:00:00 2001 From: stevapple Date: Tue, 15 Sep 2020 07:54:08 +0800 Subject: [PATCH 06/10] Fix clangLibraryPath for Windows --- .../Jobs/Toolchain+LinkerSupport.swift | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift index 44702d3ff..f495f09d5 100644 --- a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift @@ -54,12 +54,20 @@ extension Toolchain { for triple: Triple, parsedOptions: inout ParsedOptions ) throws -> AbsolutePath { - return try computeResourceDirPath(for: triple, - parsedOptions: &parsedOptions, - isShared: true) - .parentDirectory // Remove platform name. - .appending(components: "clang", "lib", - triple.platformName(conflatingDarwin: true)!) + #if os(Windows) + return try getToolPath(.swiftCompiler) + .parentDirectory // remove /swift + .parentDirectory // remove /bin + .appending(components: "lib", "swift", "clang", "lib", + triple.platformName(conflatingDarwin: true)!) + #else + return try computeResourceDirPath(for: triple, + parsedOptions: &parsedOptions, + isShared: true) + .parentDirectory // Remove platform name. + .appending(components: "clang", "lib", + triple.platformName(conflatingDarwin: true)!) + #endif } func runtimeLibraryPaths( From 59877f13445b6c1b81b6e296975dd5402035ab67 Mon Sep 17 00:00:00 2001 From: stevapple Date: Thu, 17 Sep 2020 00:38:16 +0800 Subject: [PATCH 07/10] Disable profiling support on Windows --- Sources/SwiftDriver/Driver/Driver.swift | 25 +++++++++++++++++-- .../Jobs/WindowsToolchain+LinkerSupport.swift | 5 ++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index b2ed3695f..66f7a5250 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -361,7 +361,8 @@ public struct Driver { Self.validateProfilingArgs(&parsedOptions, fileSystem: fileSystem, workingDirectory: workingDirectory, - diagnosticEngine: diagnosticEngine) + diagnosticEngine: diagnosticEngine, + targetTriple: self.frontendTargetInfo.target.triple) Self.validateCompilationConditionArgs(&parsedOptions, diagnosticEngine: diagnosticEngine) Self.validateFrameworkSearchPathArgs(&parsedOptions, diagnosticEngine: diagnosticEngine) Self.validateCoverageArgs(&parsedOptions, diagnosticsEngine: diagnosticEngine) @@ -1642,12 +1643,32 @@ extension Driver { static func validateProfilingArgs(_ parsedOptions: inout ParsedOptions, fileSystem: FileSystem, workingDirectory: AbsolutePath?, - diagnosticEngine: DiagnosticsEngine) { + diagnosticEngine: DiagnosticsEngine, + targetTriple: Triple) { if parsedOptions.hasArgument(.profileGenerate) && parsedOptions.hasArgument(.profileUse) { diagnosticEngine.emit(Error.conflictingOptions(.profileGenerate, .profileUse)) } + // Windows executables should be profiled with ETW, whose support needs to be + // implemented before we can enable the option. + if targetTriple.isWindows { + if parsedOptions.hasArgument(.profileGenerate) { + diagnosticEngine.emit( + .error_unsupported_opt_for_target( + arg: "-profile-generate", + target: targetTriple) + ) + } + if parsedOptions.hasArgument(.profileUse) { + diagnosticEngine.emit( + .error_unsupported_opt_for_target( + arg: "-profile-use=", + target: targetTriple) + ) + } + } + if let profileArgs = parsedOptions.getLastArgument(.profileUse)?.asMultiple, let workingDirectory = workingDirectory ?? fileSystem.currentWorkingDirectory { for profilingData in profileArgs { diff --git a/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift index ad520fd10..72cb3d01a 100644 --- a/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift @@ -153,9 +153,8 @@ extension WindowsToolchain { } if parsedOptions.hasArgument(.profileGenerate) { - let libProfile = try clangLibraryPath(for: targetTriple, parsedOptions: &parsedOptions) - .appending(components: "clang_rt.profile-\(archName(for: targetTriple)).lib") - commandLine.appendPath(libProfile) + // Profiling support for Windows isn't ready yet. It should have been disabled. + fatalError("Profiling support should have been disabled on Windows.") } // Run clang++ in verbose mode if "-v" is set From 4b69ec6d628231ff2c83c7546feb73089ff50a6a Mon Sep 17 00:00:00 2001 From: stevapple Date: Thu, 17 Sep 2020 00:38:32 +0800 Subject: [PATCH 08/10] Disable unsupported sanitizers on Windows --- Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift index f495f09d5..75d350bad 100644 --- a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift @@ -119,6 +119,13 @@ extension Toolchain { parsedOptions: inout ParsedOptions, isShared: Bool ) throws -> Bool { + // Currently only ASAN is supported on Windows, but clang builds may + // include runtime libraries for unsupported sanitizers. Manually + // disable unsupported sanitizers. + if targetTriple.isWindows && sanitizer != .address { + return false + } + let runtimeName = try runtimeLibraryName( for: sanitizer, targetTriple: targetTriple, From d8c4f60fe2d577bf8c37291fba16cafaeba6ba75 Mon Sep 17 00:00:00 2001 From: stevapple Date: Thu, 17 Sep 2020 14:33:09 +0800 Subject: [PATCH 09/10] Fix cross-compilation problems --- Sources/SwiftDriver/Driver/Driver.swift | 30 ++++----------- .../Jobs/Toolchain+LinkerSupport.swift | 7 ---- .../Toolchains/DarwinToolchain.swift | 3 -- .../Toolchains/GenericUnixToolchain.swift | 3 -- .../SwiftDriver/Toolchains/Toolchain.swift | 9 +++-- .../Toolchains/WindowsToolchain.swift | 37 ++++++++++++++++--- 6 files changed, 44 insertions(+), 45 deletions(-) diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index ebdeddcf4..712e6d302 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -373,8 +373,7 @@ public struct Driver { Self.validateProfilingArgs(&parsedOptions, fileSystem: fileSystem, workingDirectory: workingDirectory, - diagnosticEngine: diagnosticEngine, - targetTriple: self.frontendTargetInfo.target.triple) + diagnosticEngine: diagnosticEngine) Self.validateCompilationConditionArgs(&parsedOptions, diagnosticEngine: diagnosticEngine) Self.validateFrameworkSearchPathArgs(&parsedOptions, diagnosticEngine: diagnosticEngine) Self.validateCoverageArgs(&parsedOptions, diagnosticsEngine: diagnosticEngine) @@ -1300,6 +1299,11 @@ extension Driver { sanitizerSupported = false } + // Currently only ASAN is supported on Windows. + if sanitizer != .address && targetTriple.isWindows { + sanitizerSupported = false + } + if !sanitizerSupported { diagnosticEngine.emit( .error_unsupported_opt_for_target( @@ -1659,32 +1663,12 @@ extension Driver { static func validateProfilingArgs(_ parsedOptions: inout ParsedOptions, fileSystem: FileSystem, workingDirectory: AbsolutePath?, - diagnosticEngine: DiagnosticsEngine, - targetTriple: Triple) { + diagnosticEngine: DiagnosticsEngine) { if parsedOptions.hasArgument(.profileGenerate) && parsedOptions.hasArgument(.profileUse) { diagnosticEngine.emit(Error.conflictingOptions(.profileGenerate, .profileUse)) } - // Windows executables should be profiled with ETW, whose support needs to be - // implemented before we can enable the option. - if targetTriple.isWindows { - if parsedOptions.hasArgument(.profileGenerate) { - diagnosticEngine.emit( - .error_unsupported_opt_for_target( - arg: "-profile-generate", - target: targetTriple) - ) - } - if parsedOptions.hasArgument(.profileUse) { - diagnosticEngine.emit( - .error_unsupported_opt_for_target( - arg: "-profile-use=", - target: targetTriple) - ) - } - } - if let profileArgs = parsedOptions.getLastArgument(.profileUse)?.asMultiple, let workingDirectory = workingDirectory ?? fileSystem.currentWorkingDirectory { for profilingData in profileArgs { diff --git a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift index 75d350bad..f495f09d5 100644 --- a/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/Toolchain+LinkerSupport.swift @@ -119,13 +119,6 @@ extension Toolchain { parsedOptions: inout ParsedOptions, isShared: Bool ) throws -> Bool { - // Currently only ASAN is supported on Windows, but clang builds may - // include runtime libraries for unsupported sanitizers. Manually - // disable unsupported sanitizers. - if targetTriple.isWindows && sanitizer != .address { - return false - } - let runtimeName = try runtimeLibraryName( for: sanitizer, targetTriple: targetTriple, diff --git a/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift b/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift index c6627b37e..9469bc3f1 100644 --- a/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift +++ b/Sources/SwiftDriver/Toolchains/DarwinToolchain.swift @@ -26,9 +26,6 @@ public final class DarwinToolchain: Toolchain { /// The file system to use for any file operations. public let fileSystem: FileSystem - /// The suffix of executable files. - public let executableSuffix = "" - /// Doubles as path cache and point for overriding normal lookup private var toolPaths = [Tool: AbsolutePath]() diff --git a/Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift b/Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift index 5a9bf124f..09ca4d00a 100644 --- a/Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift +++ b/Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift @@ -21,9 +21,6 @@ public final class GenericUnixToolchain: Toolchain { /// The file system to use for queries. public let fileSystem: FileSystem - /// The suffix of executable files. - public let executableSuffix = "" - /// Doubles as path cache and point for overriding normal lookup private var toolPaths = [Tool: AbsolutePath]() diff --git a/Sources/SwiftDriver/Toolchains/Toolchain.swift b/Sources/SwiftDriver/Toolchains/Toolchain.swift index d1b434ae2..ebfe27107 100644 --- a/Sources/SwiftDriver/Toolchains/Toolchain.swift +++ b/Sources/SwiftDriver/Toolchains/Toolchain.swift @@ -38,8 +38,6 @@ public protocol Toolchain { var executor: DriverExecutor { get } - var executableSuffix: String { get } - /// Retrieve the absolute path to a particular tool. func getToolPath(_ tool: Tool) throws -> AbsolutePath @@ -131,7 +129,12 @@ extension Toolchain { /// looks in the `executableDir`, `xcrunFind` or in the `searchPaths`. /// - Parameter executable: executable to look for [i.e. `swift`]. func lookup(executable: String) throws -> AbsolutePath { - let filename = executable + executableSuffix + let filename: String + #if os(Windows) + filename = "\(executable).exe" + #else + filename = executable + #endif if let overrideString = envVar(forExecutable: executable) { return try AbsolutePath(validating: overrideString) } else if let path = lookupExecutablePath(filename: filename, searchPaths: [executableDir]) { diff --git a/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift b/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift index 88904b853..432e6a460 100644 --- a/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift +++ b/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// import TSCBasic +import SwiftOptions /// Toolchain for Windows. public final class WindowsToolchain: Toolchain { @@ -21,9 +22,6 @@ public final class WindowsToolchain: Toolchain { /// The file system to use for queries. public let fileSystem: FileSystem - /// The suffix of executable files. - public let executableSuffix = ".exe" - /// Doubles as path cache and point for overriding normal lookup private var toolPaths = [Tool: AbsolutePath]() @@ -33,7 +31,7 @@ public final class WindowsToolchain: Toolchain { case .arm: return "armv7" case .x86: return "i386" case nil, .x86_64: return "x86_64" - default: fatalError("unknown arch \(triple.archName) on Windows") + default: fatalError("unknown arch \(triple.archName) for Windows") } } @@ -75,9 +73,9 @@ public final class WindowsToolchain: Toolchain { case .clang: return try lookup(executable: "clang") case .swiftAutolinkExtract: - fatalError("Trying to look up \"swift-autolink-extract\" on Windows") + return try lookup(executable: "swift-autolink-extract") case .dsymutil: - fatalError("Trying to look up \"dsymutil\" on Windows") + return try lookup(executable: "llvm-dsymutil") case .lldb: return try lookup(executable: "lldb") case .dwarfdump: @@ -105,3 +103,30 @@ public final class WindowsToolchain: Toolchain { return "clang_rt.\(sanitizer.libraryName)-\(archName(for: targetTriple)).lib" } } + +extension WindowsToolchain { + public func validateArgs(_ parsedOptions: inout ParsedOptions, + targetTriple: Triple, + targetVariantTriple: Triple?, + diagnosticsEngine: DiagnosticsEngine) throws { + // Windows executables should be profiled with ETW, whose support needs to be + // implemented before we can enable the option. + if parsedOptions.hasArgument(.profileGenerate) { + throw ToolchainValidationError.argumentNotSupported("-profile-generate") + } + if parsedOptions.hasArgument(.profileUse) { + throw ToolchainValidationError.argumentNotSupported("-profile-use=") + } + } +} + +public enum ToolchainValidationError: Error, DiagnosticData { + case argumentNotSupported(String) + + public var description: String { + switch self { + case .argumentNotSupported(let argument): + return "\(argument) is not supported for Windows" + } + } +} From ed1b8c2552d791befa681e03be2797eab52096a0 Mon Sep 17 00:00:00 2001 From: stevapple Date: Thu, 17 Sep 2020 15:33:32 +0800 Subject: [PATCH 10/10] Fix CRT support for Windows --- Sources/SwiftDriver/Driver/Driver.swift | 11 ++++++++ .../Jobs/WindowsToolchain+LinkerSupport.swift | 19 ++++++++++---- .../Toolchains/WindowsToolchain.swift | 25 +++++++++++++------ 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index 712e6d302..ba2aa52e0 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -370,6 +370,9 @@ public struct Driver { self.numParallelJobs = Self.determineNumParallelJobs(&parsedOptions, diagnosticsEngine: diagnosticEngine, env: env) Self.validateWarningControlArgs(&parsedOptions, diagnosticEngine: diagnosticEngine) + Self.validateCRuntimeArgs(&parsedOptions, + diagnosticEngine: diagnosticsEngine, + targetTriple: self.frontendTargetInfo.target.triple) Self.validateProfilingArgs(&parsedOptions, fileSystem: fileSystem, workingDirectory: workingDirectory, @@ -1660,6 +1663,14 @@ extension Driver { } } + static func validateCRuntimeArgs(_ parsedOptions: inout ParsedOptions, + diagnosticEngine: DiagnosticsEngine, + targetTriple: Triple) { + if parsedOptions.hasArgument(.libc) && !targetTriple.isWindows { + diagnosticEngine.emit(.error_unsupported_opt_for_target(arg: "-libc", target: targetTriple)) + } + } + static func validateProfilingArgs(_ parsedOptions: inout ParsedOptions, fileSystem: FileSystem, workingDirectory: AbsolutePath?, diff --git a/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift index 72cb3d01a..02a75498d 100644 --- a/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/WindowsToolchain+LinkerSupport.swift @@ -75,6 +75,20 @@ extension WindowsToolchain { } commandLine.appendFlag("-fuse-ld=\(linker)") + // FIXME: Do we really need `oldnames`? + commandLine.appendFlags("-autolink-library", "oldnames") + if let crt = parsedOptions.getLastArgument(.libc) { + switch crt.asSingle { + case "MT": commandLine.appendFlags("-autolink-library", "libcmt") + case "MTd": commandLine.appendFlags("-autolink-library", "libcmtd") + case "MD": commandLine.appendFlags("-autolink-library", "msvcrt") + case "MDd": commandLine.appendFlags("-autolink-library", "msvcrtd") + default: fatalError("Invalid C runtime value should be filtered") + } + } else { + commandLine.appendFlags("-autolink-library", "msvcrt") + } + let staticStdlib = parsedOptions.hasFlag(positive: .staticStdlib, negative: .noStaticStdlib, default: false) @@ -152,11 +166,6 @@ extension WindowsToolchain { } } - if parsedOptions.hasArgument(.profileGenerate) { - // Profiling support for Windows isn't ready yet. It should have been disabled. - fatalError("Profiling support should have been disabled on Windows.") - } - // Run clang++ in verbose mode if "-v" is set try commandLine.appendLast(.v, from: &parsedOptions) diff --git a/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift b/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift index 432e6a460..1659e9ca4 100644 --- a/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift +++ b/Sources/SwiftDriver/Toolchains/WindowsToolchain.swift @@ -117,16 +117,25 @@ extension WindowsToolchain { if parsedOptions.hasArgument(.profileUse) { throw ToolchainValidationError.argumentNotSupported("-profile-use=") } + + if let crt = parsedOptions.getLastArgument(.libc) { + if !["MT", "MTd", "MD", "MDd"].contains(crt.asSingle) { + throw ToolchainValidationError.illegalCrtName(crt.asSingle) + } + } } -} - -public enum ToolchainValidationError: Error, DiagnosticData { - case argumentNotSupported(String) - public var description: String { - switch self { - case .argumentNotSupported(let argument): - return "\(argument) is not supported for Windows" + public enum ToolchainValidationError: Error, DiagnosticData { + case argumentNotSupported(String) + case illegalCrtName(String) + + public var description: String { + switch self { + case .argumentNotSupported(let argument): + return "\(argument) is not supported for Windows" + case .illegalCrtName(let argument): + return "\(argument) is not a valid C Runtime for Windows" + } } } }