Skip to content

Commit 6401fbb

Browse files
authored
Merge pull request #878 from compnerd/windows
SwiftDriver: initial (incomplete) windows port
2 parents 9597a9e + 633bd1f commit 6401fbb

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
@@ -788,7 +788,7 @@ extension Driver {
788788
let execName = try VirtualPath(path: args[0]).basenameWithoutExt
789789

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

@@ -798,13 +798,13 @@ extension Driver {
798798

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

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

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

828-
let subcommand = "swift-\(firstArg)"
828+
let subcommand = executableName("swift-\(firstArg)")
829829

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

@@ -2223,10 +2223,12 @@ extension Driver {
22232223

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

22322234
return .absolute(path)
@@ -2524,7 +2526,7 @@ extension Triple {
25242526
case .wasi:
25252527
return WebAssemblyToolchain.self
25262528
case .win32:
2527-
fatalError("Windows target not supported yet")
2529+
return WindowsToolchain.self
25282530
default:
25292531
diagnosticsEngine.emit(.error_unknown_target(triple))
25302532
throw Diagnostics.fatalError
@@ -2537,7 +2539,7 @@ extension Driver {
25372539
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
25382540
static let defaultToolchainType: Toolchain.Type = DarwinToolchain.self
25392541
#elseif os(Windows)
2540-
static let defaultToolchainType: Toolchain.Type = { fatalError("Windows target not supported yet") }()
2542+
static let defaultToolchainType: Toolchain.Type = WindowsToolchain.self
25412543
#else
25422544
static let defaultToolchainType: Toolchain.Type = GenericUnixToolchain.self
25432545
#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)