Skip to content

Commit e4bff9d

Browse files
committed
Can build with toolchain other than swift-build’s
This is an essential part of the puzzle that is: * swift-build requires Swift 3 to build and consume Package.swift * Many packages exist that require Swift 2.2 The workaround here is to set `SWIFT_EXEC`, swift-build will use its toolchain for the parts that are intrinsically coupled to the toolchain, but composes a build-YAML that uses the toolchain with which `SWIFT_EXEC` is a part. Since SWIFT_EXEC is an expected feature, we are adapting it here, but it may make more sense long-term to have a dedicated `--toolchain` flag.
1 parent 2ce8a18 commit e4bff9d

22 files changed

+225
-174
lines changed

Sources/Build/Command.compile(ClangModule).swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import POSIX
1515
//FIXME: Incremental builds
1616

1717
extension Command {
18-
static func compile(clangModule module: ClangModule, externalModules: Set<Module>, configuration conf: Configuration, prefix: String) -> (Command, Command) {
18+
static func compile(clangModule module: ClangModule, externalModules: Set<Module>, configuration conf: Configuration, prefix: String, CC: String) -> (Command, Command) {
1919

2020
let wd = Path.join(prefix, "\(module.c99name).build")
2121
let mkdir = Command.createDirectory(wd)
@@ -61,7 +61,7 @@ extension Command {
6161
description: "Compiling \(module.name)",
6262
inputs: inputs,
6363
outputs: [productPath, module.targetName],
64-
args: [Toolchain.clang] + args)
64+
args: [CC] + args)
6565

6666
let command = Command(node: module.targetName, tool: clang)
6767

Sources/Build/Command.compile(SwiftModule).swift

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import PackageType
1212
import Utility
1313

1414
extension Command {
15-
static func compile(swiftModule module: SwiftModule, configuration conf: Configuration, prefix: String, otherArgs: [String]) throws -> (Command, [Command]) {
15+
static func compile(swiftModule module: SwiftModule, configuration conf: Configuration, prefix: String, otherArgs: [String], SWIFT_EXEC: String) throws -> (Command, [Command]) {
1616

1717
let otherArgs = otherArgs + module.Xcc
1818

@@ -24,15 +24,11 @@ extension Command {
2424
case .Debug:
2525
var args = ["-j8","-Onone","-g","-D","SWIFT_PACKAGE", "-enable-testing"]
2626

27-
#if os(OSX)
28-
if let platformPath = Toolchain.platformPath {
29-
let path = Path.join(platformPath, "Developer/Library/Frameworks")
30-
args += ["-F", path]
31-
} else {
32-
throw Error.InvalidPlatformPath
33-
}
34-
#endif
35-
let tool = SwiftcTool(module: module, prefix: prefix, otherArgs: args + otherArgs)
27+
#if os(OSX)
28+
args += ["-F", try platformFrameworksPath()]
29+
#endif
30+
31+
let tool = SwiftcTool(module: module, prefix: prefix, otherArgs: args + otherArgs, executable: SWIFT_EXEC)
3632
let mkdirs = Set(tool.objects.map{ $0.parentDirectory }).map(Command.createDirectory)
3733
return (cmd(tool), mkdirs)
3834

@@ -49,7 +45,7 @@ extension Command {
4945
description: "Compiling \(module.name)",
5046
inputs: inputs,
5147
outputs: [productPath, module.targetName],
52-
args: [Toolchain.swiftc, "-o", productPath] + args + module.sources.paths + otherArgs)
48+
args: [SWIFT_EXEC, "-o", productPath] + args + module.sources.paths + otherArgs)
5349

5450
return (cmd(tool), [])
5551
}

Sources/Build/Command.link().swift

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,22 @@ import Utility
1717

1818

1919
extension Command {
20-
static func link(product: Product, configuration conf: Configuration, prefix: String, otherArgs: [String]) throws -> Command {
20+
static func link(product: Product, configuration conf: Configuration, prefix: String, otherArgs: [String], SWIFT_EXEC: String) throws -> Command {
2121

2222
let objects: [String]
2323
switch conf {
2424
case .Release:
2525
objects = product.buildables.map{ Path.join(prefix, "\($0.c99name).o") }
2626
case .Debug:
27-
objects = product.buildables.flatMap{ return SwiftcTool(module: $0, prefix: prefix, otherArgs: []).objects }
27+
objects = product.buildables.flatMap{ return SwiftcTool(module: $0, prefix: prefix, otherArgs: [], executable: SWIFT_EXEC).objects }
2828
}
2929

3030
let outpath = Path.join(prefix, product.outname)
3131

3232
var args: [String]
3333
switch product.type {
3434
case .Library(.Dynamic), .Executable, .Test:
35-
args = [Toolchain.swiftc] + otherArgs
35+
args = [SWIFT_EXEC] + otherArgs
3636

3737
if conf == .Debug {
3838
args += ["-g"]
@@ -50,7 +50,7 @@ extension Command {
5050
let inputs = product.modules.flatMap { module -> [String] in
5151
switch conf {
5252
case .Debug:
53-
let tool = SwiftcTool(module: module, prefix: prefix, otherArgs: [])
53+
let tool = SwiftcTool(module: module, prefix: prefix, otherArgs: [], executable: SWIFT_EXEC)
5454
// must return tool’s outputs and inputs as shell nodes don't calculate more than that
5555
return tool.inputs + tool.outputs
5656
case .Release:
@@ -64,13 +64,7 @@ extension Command {
6464
case .Test:
6565
#if os(OSX)
6666
args += ["-Xlinker", "-bundle"]
67-
68-
if let platformPath = Toolchain.platformPath {
69-
let path = Path.join(platformPath, "Developer/Library/Frameworks")
70-
args += ["-F", path]
71-
} else {
72-
throw Error.InvalidPlatformPath
73-
}
67+
args += ["-F", try platformFrameworksPath()]
7468

7569
// TODO should be llbuild rules∫
7670
if conf == .Debug {

Sources/Build/ToolProtocol.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,13 @@ struct SwiftcTool: ToolProtocol {
5858
let module: SwiftModule
5959
let prefix: String
6060
let otherArgs: [String]
61+
let executable: String
6162

6263
var inputs: [String] {
6364
return module.recursiveDependencies.map{ $0.targetName }
6465
}
6566

6667
var outputs: [String] { return [module.targetName] + objects }
67-
var executable: String { return Toolchain.swiftc }
6868
var moduleName: String { return module.c99name }
6969
var moduleOutputPath: String { return Path.join(prefix, "\(module.c99name).swiftmodule") }
7070
var importPaths: String { return prefix }

Sources/Build/describe().swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import Utility
1818
/**
1919
- Returns: path to generated YAML for consumption by the llbuild based swift-build-tool
2020
*/
21-
public func describe(prefix: String, _ conf: Configuration, _ modules: [Module], _ externalModules: Set<Module> , _ products: [Product], Xcc: [String], Xld: [String], Xswiftc: [String]) throws -> String {
21+
public func describe(prefix: String, _ conf: Configuration, _ modules: [Module], _ externalModules: Set<Module>, _ products: [Product], Xcc: [String], Xld: [String], Xswiftc: [String], toolchain: Toolchain) throws -> String {
2222

2323
guard modules.count > 0 else {
2424
throw Error.NoModules
@@ -29,13 +29,16 @@ public func describe(prefix: String, _ conf: Configuration, _ modules: [Module],
2929
let prefix = try mkdir(prefix, conf.dirname) //TODO llbuild this
3030
let swiftcArgs = Xcc + Xswiftc + verbosity.ccArgs
3131

32+
let SWIFT_EXEC = toolchain.SWIFT_EXEC
33+
let CC = getenv("CC") ?? "clang"
34+
3235
var commands = [Command]()
3336
var targets = Targets()
3437

3538
for module in modules {
3639
switch module {
3740
case let module as SwiftModule:
38-
let (compile, mkdirs) = try Command.compile(swiftModule: module, configuration: conf, prefix: prefix, otherArgs: swiftcArgs + platformArgs())
41+
let (compile, mkdirs) = try Command.compile(swiftModule: module, configuration: conf, prefix: prefix, otherArgs: swiftcArgs + toolchain.platformArgs, SWIFT_EXEC: SWIFT_EXEC)
3942
commands.append(contentsOf: mkdirs + [compile])
4043
targets.append(compile, for: module)
4144

@@ -50,7 +53,7 @@ public func describe(prefix: String, _ conf: Configuration, _ modules: [Module],
5053
}
5154
}
5255

53-
let (compile, mkdir) = Command.compile(clangModule: module, externalModules: externalModules, configuration: conf, prefix: prefix)
56+
let (compile, mkdir) = Command.compile(clangModule: module, externalModules: externalModules, configuration: conf, prefix: prefix, CC: CC)
5457
commands.append(compile)
5558
commands.append(mkdir)
5659
targets.main.cmds.append(compile)
@@ -64,7 +67,7 @@ public func describe(prefix: String, _ conf: Configuration, _ modules: [Module],
6467
}
6568

6669
for product in products {
67-
let command = try Command.link(product, configuration: conf, prefix: prefix, otherArgs: Xld + swiftcArgs + platformArgs())
70+
let command = try Command.link(product, configuration: conf, prefix: prefix, otherArgs: Xld + swiftcArgs + toolchain.platformArgs, SWIFT_EXEC: SWIFT_EXEC)
6871
commands.append(command)
6972
targets.append(command, for: product)
7073
}

Sources/Build/misc.swift

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,23 @@
99
*/
1010

1111
import func POSIX.getenv
12+
import func POSIX.popen
1213
import PackageType
1314
import Utility
1415

15-
func platformArgs() -> [String] {
16-
var args = [String]()
17-
18-
#if os(OSX)
19-
args += ["-target", "x86_64-apple-macosx10.10"]
16+
public protocol Toolchain {
17+
var platformArgs: [String] { get }
18+
var sysroot: String? { get }
19+
var SWIFT_EXEC: String { get }
20+
var clang: String { get }
21+
}
2022

21-
if let sysroot = Toolchain.sysroot {
22-
args += ["-sdk", sysroot]
23+
func platformFrameworksPath() throws -> String {
24+
guard let popened = try? POSIX.popen(["xcrun", "--sdk", "macosx", "--show-sdk-platform-path"]),
25+
let chuzzled = popened.chuzzle() else {
26+
throw Error.InvalidPlatformPath
2327
}
24-
#endif
25-
26-
return args
28+
return Path.join(chuzzled, "Developer/Library/Frameworks")
2729
}
2830

2931
extension CModule {

Sources/Multitool/Error.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,22 @@ public enum CommandLineError: ErrorProtocol {
2222

2323
public enum Error: ErrorProtocol {
2424
case NoManifestFound
25+
case InvalidToolchain
26+
case InvalidInstallation(String)
27+
case InvalidSwiftExec(String)
2528
}
2629

2730
extension Error: CustomStringConvertible {
2831
public var description: String {
2932
switch self {
3033
case .NoManifestFound:
3134
return "no \(Manifest.filename) file found"
35+
case .InvalidToolchain:
36+
return "invalid inferred toolchain"
37+
case .InvalidInstallation(let prefix):
38+
return "invalid or incomplete Swift toolchain:\n \(prefix)"
39+
case .InvalidSwiftExec(let value):
40+
return "invalid SWIFT_EXEC value: \(value)"
3241
}
3342
}
3443
}

Sources/Multitool/Toolchain.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright 2015 - 2016 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See http://swift.org/LICENSE.txt for license information
8+
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import PackageType
12+
import Utility
13+
import POSIX
14+
15+
#if Xcode
16+
17+
// when in Xcode we are built with same toolchain as we will run
18+
// this is not a production ready mode
19+
20+
public let SWIFT_EXEC = getenv("SWIFT_EXEC")!.abspath()
21+
public let llbuild = Path.join(getenv("SWIFT_EXEC")!, "../swift-build-tool").abspath()
22+
public let libdir = Process.arguments.first!.parentDirectory
23+
#else
24+
public let SWIFT_EXEC = Path.join(Process.arguments.first!, "../swiftc").abspath()
25+
public let llbuild = Path.join(Process.arguments.first!, "../swift-build-tool").abspath()
26+
public let libdir = Path.join(Process.arguments.first!, "../../lib/swift/pm").abspath()
27+
#endif

Sources/Multitool/build().swift

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,11 @@
99
*/
1010

1111
import func POSIX.getenv
12+
import PackageType
1213
import Utility
1314

1415
public func build(YAMLPath YAMLPath: String, target: String) throws {
15-
var args = [swift_build_tool(), "-f", YAMLPath, target]
16+
var args = [llbuild, "-f", YAMLPath, target]
1617
if verbosity != .Concise { args.append("-v") }
1718
try system(args)
1819
}
19-
20-
private func swift_build_tool() -> String {
21-
if let tool = getenv("SWIFT_BUILD_TOOL") { //FIXME remove and if people complain, make it a flag
22-
return tool
23-
} else if let path = try? Path.join(exepath, "..", "swift-build-tool").abspath() where path.isFile {
24-
return path
25-
} else {
26-
return Toolchain.which("swift-build-tool")
27-
}
28-
}
29-
30-
private let exepath: String = try! Process.arguments.first!.abspath()

Sources/POSIX/system.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ func posix_spawnp(path: String, args: [String], environment: [String: String] =
4949
defer { for arg in argv { free(arg) } }
5050

5151
var environment = environment
52-
for key in ["PATH", "SDKROOT", "TOOLCHAINS", "HOME", "SWIFT_EXEC"] {
52+
#if Xcode
53+
let keys = ["SWIFT_EXEC", "HOME", "PATH"]
54+
#else
55+
let keys = ["SWIFT_EXEC", "HOME", "PATH", "SDKROOT", "TOOLCHAINS"]
56+
#endif
57+
for key in keys {
5358
if environment[key] == nil {
5459
environment[key] = POSIX.getenv(key)
5560
}

Sources/Utility/Path.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ extension String {
222222

223223
/**
224224
- Returns: true if the string is a file on the filesystem
225-
- Note: if the entry is a symlink, but the symlink points to Array
225+
- Note: if the entry is a symlink, but the symlink points to a
226226
file, then this function returns true. Use `isSymlink` if the
227227
distinction is important.
228228
*/

Sources/Utility/Toolchain.swift

Lines changed: 0 additions & 56 deletions
This file was deleted.

0 commit comments

Comments
 (0)