Skip to content

Commit 633bd1f

Browse files
committed
SwiftDriver: initial (incomplete) windows port
This is sufficient to build on Windows, and the resulting driver is able to somewhat function. The tests are still not usable due to assumptions about path which do not hold and the insufficiency of the path representation in tools-support-core. This is likely best approached by replacing the use of `Path` from t-s-c with the representation in system. However, this allows some attempt to validate the swift-driver which is increasingly becoming required for s-p-m, and thus unblocks further work.
1 parent dc27691 commit 633bd1f

File tree

9 files changed

+370
-18
lines changed

9 files changed

+370
-18
lines changed

Sources/SwiftDriver/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,14 @@ add_library(SwiftDriver
8686
Jobs/VerifyDebugInfoJob.swift
8787
Jobs/VerifyModuleInterfaceJob.swift
8888
Jobs/WebAssemblyToolchain+LinkerSupport.swift
89+
Jobs/WindowsToolchain+LinkerSupport.swift
8990
Jobs/PrebuiltModulesJob.swift
9091

9192
Toolchains/DarwinToolchain.swift
9293
Toolchains/GenericUnixToolchain.swift
9394
Toolchains/Toolchain.swift
9495
Toolchains/WebAssemblyToolchain.swift
96+
Toolchains/WindowsToolchain.swift
9597

9698
Utilities/DOTJobGraphSerializer.swift
9799
Utilities/DateAdditions.swift

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,7 @@ extension Driver {
787787
let execName = try VirtualPath(path: args[0]).basenameWithoutExt
788788

789789
// If we are not run as 'swift' or 'swiftc' or there are no program arguments, always invoke as normal.
790-
guard execName == "swift" || execName == "swiftc", args.count > 1 else {
790+
guard [executableName("swift"), executableName("swiftc")].contains(execName), args.count > 1 else {
791791
return (.normal(isRepl: false), args)
792792
}
793793

@@ -797,13 +797,13 @@ extension Driver {
797797

798798
// Check for flags associated with frontend tools.
799799
if firstArg == "-frontend" {
800-
updatedArgs.replaceSubrange(0...1, with: ["swift-frontend"])
801-
return (.subcommand("swift-frontend"), updatedArgs)
800+
updatedArgs.replaceSubrange(0...1, with: [executableName("swift-frontend")])
801+
return (.subcommand(executableName("swift-frontend")), updatedArgs)
802802
}
803803

804804
if firstArg == "-modulewrap" {
805-
updatedArgs[0] = "swift-frontend"
806-
return (.subcommand("swift-frontend"), updatedArgs)
805+
updatedArgs[0] = executableName("swift-frontend")
806+
return (.subcommand(executableName("swift-frontend")), updatedArgs)
807807
}
808808

809809
// Only 'swift' supports subcommands.
@@ -824,7 +824,7 @@ extension Driver {
824824
return (.normal(isRepl: true), updatedArgs)
825825
}
826826

827-
let subcommand = "swift-\(firstArg)"
827+
let subcommand = executableName("swift-\(firstArg)")
828828

829829
updatedArgs.replaceSubrange(0...1, with: [subcommand])
830830

@@ -2222,10 +2222,12 @@ extension Driver {
22222222

22232223
if !fileSystem.exists(path) {
22242224
diagnosticsEngine.emit(.warning_no_such_sdk(sdkPath))
2225-
} else if isSDKTooOld(sdkPath: path, fileSystem: fileSystem,
2226-
diagnosticsEngine: diagnosticsEngine) {
2227-
diagnosticsEngine.emit(.error_sdk_too_old(sdkPath))
2228-
return nil
2225+
} else if !(targetTriple?.isWindows ?? (defaultToolchainType == WindowsToolchain.self)) {
2226+
if isSDKTooOld(sdkPath: path, fileSystem: fileSystem,
2227+
diagnosticsEngine: diagnosticsEngine) {
2228+
diagnosticsEngine.emit(.error_sdk_too_old(sdkPath))
2229+
return nil
2230+
}
22292231
}
22302232

22312233
return .absolute(path)
@@ -2510,7 +2512,7 @@ extension Triple {
25102512
case .wasi:
25112513
return WebAssemblyToolchain.self
25122514
case .win32:
2513-
fatalError("Windows target not supported yet")
2515+
return WindowsToolchain.self
25142516
default:
25152517
diagnosticsEngine.emit(.error_unknown_target(triple))
25162518
throw Diagnostics.fatalError
@@ -2523,7 +2525,7 @@ extension Driver {
25232525
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
25242526
static let defaultToolchainType: Toolchain.Type = DarwinToolchain.self
25252527
#elseif os(Windows)
2526-
static let defaultToolchainType: Toolchain.Type = { fatalError("Windows target not supported yet") }()
2528+
static let defaultToolchainType: Toolchain.Type = WindowsToolchain.self
25272529
#else
25282530
static let defaultToolchainType: Toolchain.Type = GenericUnixToolchain.self
25292531
#endif
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===------------- WindowsExtensions.swift - Windows Extensions -----------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Foundation
14+
15+
internal func executableName(_ name: String) -> String {
16+
#if os(Windows)
17+
if name.suffix(from: name.index(name.endIndex, offsetBy: -4)) == ".exe" {
18+
return name
19+
}
20+
return "\(name).exe"
21+
#else
22+
return name
23+
#endif
24+
}

Sources/SwiftDriver/ExplicitModuleBuilds/ModuleDependencyScanning.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,14 @@ public extension Driver {
314314
@_spi(Testing) public extension Driver {
315315
static func getScanLibPath(of toolchain: Toolchain, hostTriple: Triple,
316316
env: [String: String]) throws -> AbsolutePath {
317+
if hostTriple.isWindows {
318+
// no matter if we are in a build tree or an installed tree, the layout is
319+
// always: `bin/_InternalSwiftScan.dll`
320+
return try getRootPath(of: toolchain, env: env)
321+
.appending(component: "bin")
322+
.appending(component: "_InternalSwiftScan.dll")
323+
}
324+
317325
let sharedLibExt: String
318326
if hostTriple.isMacOSX {
319327
sharedLibExt = ".dylib"

Sources/SwiftDriver/Jobs/Toolchain+InterpreterSupport.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,16 @@ extension GenericUnixToolchain {
7373
return envVars
7474
}
7575
}
76+
77+
extension WindowsToolchain {
78+
public func platformSpecificInterpreterEnvironmentVariables(
79+
env: [String : String],
80+
parsedOptions: inout ParsedOptions,
81+
sdkPath: VirtualPath.Handle?,
82+
targetInfo: FrontendTargetInfo) throws -> [String: String] {
83+
84+
// TODO(compnerd): setting up `Path` is meaningless currently as the lldb
85+
// support required for the interpreter mode fails to load the dependencies.
86+
return [:]
87+
}
88+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
//===--------------- WindowsToolchain+LinkerSupport.swift -----------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import TSCBasic
14+
import SwiftOptions
15+
16+
extension WindowsToolchain {
17+
public func addPlatformSpecificLinkerArgs(to commandLine: inout [Job.ArgTemplate],
18+
parsedOptions: inout ParsedOptions,
19+
linkerOutputType: LinkOutputType,
20+
inputs: [TypedVirtualPath],
21+
outputFile: VirtualPath,
22+
shouldUseInputFileList: Bool,
23+
lto: LTOKind?,
24+
sanitizers: Set<Sanitizer>,
25+
targetInfo: FrontendTargetInfo)
26+
throws -> AbsolutePath {
27+
let targetTriple = targetInfo.target.triple
28+
29+
if !targetTriple.triple.isEmpty {
30+
commandLine.appendFlag("-target")
31+
commandLine.appendFlag(targetTriple.triple)
32+
}
33+
34+
switch linkerOutputType {
35+
case .staticLibrary:
36+
break
37+
case .dynamicLibrary:
38+
commandLine.appendFlag("-shared")
39+
case .executable:
40+
break
41+
}
42+
43+
// Select the linker to use.
44+
if let arg = parsedOptions.getLastArgument(.useLd) {
45+
commandLine.appendFlag("-fuse-ld=\(arg.asSingle)")
46+
} else if lto != nil {
47+
commandLine.appendFlag("-fuse-ld=lld")
48+
}
49+
50+
switch lto {
51+
case .some(.llvmThin):
52+
commandLine.appendFlag("-flto=thin")
53+
case .some(.llvmFull):
54+
commandLine.appendFlag("-flto=full")
55+
case .none:
56+
break
57+
}
58+
59+
// FIXME(compnerd): render `-Xlinker /DEBUG` or `-Xlinker /DEBUG:DWARF` with
60+
// DWARF + lld
61+
62+
// Rely on `-libc` to correctly identify the MSVC Runtime Library. We use
63+
// `-nostartfiles` as that limits the difference to just the
64+
// `-defaultlib:libcmt` which is passed unconditionally with the `clang`
65+
// driver rather than the `clang-cl` driver.
66+
commandLine.appendFlag("-nostartfiles")
67+
68+
// TODO(compnerd) investigate the proper way to port this logic over from
69+
// the C++ driver.
70+
71+
// Since Windows has separate libraries per architecture, link against the
72+
// architecture specific version of the static library.
73+
commandLine.appendFlag(.L)
74+
commandLine.appendPath(VirtualPath.lookup(targetInfo.runtimeLibraryImportPaths.last!.path))
75+
76+
// FIXME(compnerd) figure out how to ensure that the SDK relative path is
77+
// the last one
78+
commandLine.appendPath(VirtualPath.lookup(targetInfo.runtimeLibraryImportPaths.last!.path)
79+
.appending(component: "swiftrt.obj"))
80+
81+
commandLine.append(contentsOf: inputs.compactMap { (input: TypedVirtualPath) -> Job.ArgTemplate? in
82+
switch input.type {
83+
case .object, .llvmBitcode:
84+
return .path(input.file)
85+
default:
86+
return nil
87+
}
88+
})
89+
90+
for framework in parsedOptions.arguments(for: .F, .Fsystem) {
91+
commandLine.appendFlag(framework.option == .Fsystem ? "-iframework" : "-F")
92+
try commandLine.appendPath(VirtualPath(path: framework.argument.asSingle))
93+
}
94+
95+
if let sdkPath = targetInfo.sdkPath?.path {
96+
commandLine.appendFlag("-I")
97+
commandLine.appendPath(VirtualPath.lookup(sdkPath))
98+
}
99+
100+
if let stdlib = parsedOptions.getLastArgument(.experimentalCxxStdlib) {
101+
commandLine.appendFlag("-stdlib=\(stdlib.asSingle)")
102+
}
103+
104+
// FIXME(compnerd) render asan/ubsan runtime link for executables
105+
106+
if parsedOptions.contains(.profileGenerate) {
107+
commandLine.appendFlag("-Xlinker")
108+
// FIXME(compnerd) wrap llvm::getInstrProfRuntimeHookVarName()
109+
commandLine.appendFlag("-include:__llvm_profile_runtime")
110+
commandLine.appendFlag("-lclang_rt.profile")
111+
}
112+
113+
for option in parsedOptions.arguments(for: .Xlinker) {
114+
commandLine.appendFlag(.Xlinker)
115+
commandLine.appendFlag(option.argument.asSingle)
116+
}
117+
// TODO(compnerd) is there a separate equivalent to OPT_linker_option_group?
118+
try commandLine.appendAllArguments(.XclangLinker, from: &parsedOptions)
119+
120+
if parsedOptions.contains(.v) {
121+
commandLine.appendFlag("-v")
122+
}
123+
124+
commandLine.appendFlag("-o")
125+
commandLine.appendPath(outputFile)
126+
127+
// TODO(compnerd) handle static libraries
128+
return try getToolPath(.clang)
129+
}
130+
}

Sources/SwiftDriver/Toolchains/Toolchain.swift

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,14 @@ public protocol Toolchain {
104104

105105
extension Toolchain {
106106
public var searchPaths: [AbsolutePath] {
107-
getEnvSearchPaths(pathString: env["PATH"], currentWorkingDirectory: fileSystem.currentWorkingDirectory)
107+
// Conditionalize this on the build time host because cross-compiling from
108+
// a non-Windows host, we would use a Windows toolchain, but would want to
109+
// use the platform variable for the path.
110+
#if os(Windows)
111+
return getEnvSearchPaths(pathString: env["Path"], currentWorkingDirectory: fileSystem.currentWorkingDirectory)
112+
#else
113+
return getEnvSearchPaths(pathString: env["PATH"], currentWorkingDirectory: fileSystem.currentWorkingDirectory)
114+
#endif
108115
}
109116

110117
/// Returns the `executablePath`'s directory.
@@ -131,6 +138,9 @@ extension Toolchain {
131138
private func envVarName(for toolName: String) -> String {
132139
let lookupName = toolName
133140
.replacingOccurrences(of: "-", with: "_")
141+
// FIXME(compnerd) we should extract the extension for generating the
142+
// toolname rather than assuming that we can convert the tool name blindly
143+
.replacingOccurrences(of: ".", with: "_")
134144
.uppercased()
135145
return "SWIFT_DRIVER_\(lookupName)_EXEC"
136146
}
@@ -157,7 +167,7 @@ extension Toolchain {
157167
return path
158168
} else if let path = try? xcrunFind(executable: executable) {
159169
return path
160-
} else if !["swift-frontend", "swift"].contains(executable),
170+
} else if ![executableName("swift-frontend"), executableName("swift")].contains(executable),
161171
let parentDirectory = try? getToolPath(.swiftCompiler).parentDirectory,
162172
parentDirectory != executableDir,
163173
let path = lookupExecutablePath(filename: executable, searchPaths: [parentDirectory]) {
@@ -166,11 +176,25 @@ extension Toolchain {
166176
return path
167177
} else if let path = lookupExecutablePath(filename: executable, searchPaths: searchPaths) {
168178
return path
169-
} else if executable == "swift-frontend" {
179+
} else if executable == executableName("swift-frontend") {
170180
// Temporary shim: fall back to looking for "swift" before failing.
171-
return try lookup(executable: "swift")
181+
return try lookup(executable: executableName("swift"))
172182
} else if fallbackToExecutableDefaultPath {
173-
return AbsolutePath("/usr/bin/" + executable)
183+
if self is WindowsToolchain {
184+
if let DEVELOPER_DIR = env["DEVELOPER_DIR"] {
185+
return AbsolutePath(DEVELOPER_DIR)
186+
.appending(component: "Toolchains")
187+
.appending(component: "unknown-Asserts-development.xctoolchain")
188+
.appending(component: "usr")
189+
.appending(component: "bin")
190+
.appending(component: executable)
191+
}
192+
return try getToolPath(.swiftCompiler)
193+
.parentDirectory
194+
.appending(component: executable)
195+
} else {
196+
return AbsolutePath("/usr/bin/" + executable)
197+
}
174198
} else {
175199
throw ToolchainError.unableToFind(tool: executable)
176200
}

0 commit comments

Comments
 (0)