Skip to content

Commit ca9b5fc

Browse files
committed
Merge pull request #230 from mxcl/multi-toolchain
Multi toolchain
2 parents 7661b27 + e4bff9d commit ca9b5fc

27 files changed

+297
-237
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/Multitool/directories.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public func directories() throws -> (root: String, build: String) {
2020
}
2121

2222
private func packageRoot() throws -> String {
23-
var rootd = try getcwd()
23+
var rootd = getcwd()
2424
while !Path.join(rootd, Manifest.filename).isFile {
2525
rootd = rootd.parentDirectory
2626
guard rootd != "/" else {

Sources/POSIX/getcwd.swift

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,33 @@
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
99
*/
1010

11-
12-
import var libc.errno
13-
import func libc.free
1411
import func libc.getcwd
12+
import func libc.free
13+
import func libc.exit
1514
import var libc.PATH_MAX
15+
import var libc.stderr
16+
import var libc.errno
1617

1718
/**
1819
- Returns: The absolute pathname of the current working directory.
20+
- Note: If the current directory does not exist, aborts program,
21+
to deal with this you should `opendir(getcwd())` as soon as your
22+
program starts and then not `chdir()`, `chdir` is an anti-pattern
23+
in tooling anyway.
24+
- Warning: As a result of the above note use of POSIX demands that
25+
the working directory not change during execution. This requires
26+
you to have control over the purity of your dependencies.
1927
*/
20-
public func getcwd() throws -> String {
28+
public func getcwd() -> String {
29+
30+
@noreturn func error() {
31+
try! fputs("error: no current directory\n", libc.stderr)
32+
exit(2)
33+
}
34+
2135
let cwd = libc.getcwd(nil, Int(PATH_MAX))
22-
if cwd == nil { throw SystemError.getcwd(errno) }
36+
if cwd == nil { error() }
2337
defer { free(cwd) }
24-
guard let path = String(validatingUTF8: cwd) else { throw SystemError.getcwd(-1) }
38+
guard let path = String(validatingUTF8: cwd) else { error() }
2539
return path
2640
}

Sources/POSIX/mkdir.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public func mkdir(path: [String]) throws -> String {
2828
let parts = path.flatMap{ $0.characters.split(separator: "/") }
2929
var prefix = path.first!.hasPrefix("/")
3030
? ""
31-
: try getcwd()
31+
: getcwd()
3232

3333
for dir in parts {
3434
prefix = "\(prefix)/\(String(dir))"

Sources/POSIX/system.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +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",
53-
// FIXME these
54-
"SPM_INSTALL_PATH", "SWIFT_BUILD_TOOL"] {
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 {
5558
if environment[key] == nil {
5659
environment[key] = POSIX.getenv(key)
5760
}

0 commit comments

Comments
 (0)