Skip to content

Commit 4a77d91

Browse files
committed
Refactor Build
This makes it more maintainable by splitting out the code into separate files and independent functions based on purpose. The code is more encapsulated and its boundaries more defined. Ready for static library implementation.
1 parent 1ca731b commit 4a77d91

12 files changed

+511
-477
lines changed

Sources/Build/Buildable.swift

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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+
13+
protocol Buildable {
14+
var targetName: String { get }
15+
var isTest: Bool { get }
16+
}
17+
18+
extension Module: Buildable {
19+
var isTest: Bool {
20+
return self is TestModule
21+
}
22+
23+
var Xcc: [String] {
24+
return recursiveDependencies.flatMap { module -> [String] in
25+
if let module = module as? CModule {
26+
return ["-Xcc", "-fmodule-map-file=\(module.moduleMapPath)"]
27+
} else {
28+
return []
29+
}
30+
}
31+
}
32+
33+
var targetName: String {
34+
return "<\(name).module>"
35+
}
36+
}
37+
38+
extension Product: Buildable {
39+
var isTest: Bool {
40+
if case .Test = type {
41+
return true
42+
}
43+
return false
44+
}
45+
46+
var targetName: String {
47+
switch type {
48+
case .Library(.Dynamic):
49+
return "<\(name).dylib>"
50+
case .Test:
51+
return "<\(name).test>"
52+
case .Library(.Static):
53+
return "<\(name).a>"
54+
case .Executable:
55+
return "<\(name).exe>"
56+
}
57+
}
58+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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+
//FIXME: Incremental builds
16+
17+
extension Command {
18+
static func compile(clangModule module: ClangModule, configuration conf: Configuration, prefix: String) -> (Command, Command) {
19+
20+
let wd = Path.join(prefix, "\(module.c99name).build")
21+
let mkdir = Command.createDirectory(wd)
22+
23+
let inputs = module.dependencies.map{ $0.targetName } + module.sources.paths + [mkdir.node]
24+
let productPath = Path.join(prefix, "lib\(module.c99name).so")
25+
26+
var args: [String] = []
27+
#if os(Linux)
28+
args += ["-fPIC"]
29+
#endif
30+
args += ["-fmodules", "-fmodule-name=\(module.name)"]
31+
args += ["-L\(prefix)"]
32+
33+
for case let dep as ClangModule in module.dependencies {
34+
let includeFlag: String
35+
//add `-iquote` argument to the include directory of every target in the package in the
36+
//transitive closure of the target being built allowing the use of `#include "..."`
37+
//add `-I` argument to the include directory of every target outside the package in the
38+
//transitive closure of the target being built allowing the use of `#include <...>`
39+
//FIXME: To detect external deps we're checking if their path's parent.parent directory
40+
//is `Packages` as external deps will get copied to `Packages` dir. There should be a
41+
//better way to do this.
42+
if dep.path.parentDirectory.parentDirectory.basename == "Packages" {
43+
includeFlag = "-I"
44+
} else {
45+
includeFlag = "-iquote"
46+
}
47+
args += [includeFlag, dep.path]
48+
args += ["-l\(dep.c99name)"] //FIXME: giving path to other module's -fmodule-map-file is not linking that module
49+
}
50+
51+
switch conf {
52+
case .Debug:
53+
args += ["-g", "-O0"]
54+
case .Release:
55+
args += ["-O2"]
56+
}
57+
58+
args += module.sources.paths
59+
args += ["-shared", "-o", productPath]
60+
61+
let clang = ShellTool(
62+
description: "Compiling \(module.name)",
63+
inputs: inputs,
64+
outputs: [productPath, module.targetName],
65+
args: [Toolchain.clang] + args)
66+
67+
let command = Command(node: module.targetName, tool: clang)
68+
69+
return (command, mkdir)
70+
}
71+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
14+
extension Command {
15+
static func compile(swiftModule module: SwiftModule, configuration conf: Configuration, prefix: String, otherArgs: [String]) throws -> (Command, [Command]) {
16+
17+
let otherArgs = otherArgs + module.Xcc
18+
19+
func cmd(tool: ToolProtocol) -> Command {
20+
return Command(node: module.targetName, tool: tool)
21+
}
22+
23+
switch conf {
24+
case .Debug:
25+
var args = ["-j8","-Onone","-g","-D","SWIFT_PACKAGE", "-enable-testing"]
26+
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)
36+
let mkdirs = Set(tool.objects.map{ $0.parentDirectory }).map(Command.createDirectory)
37+
return (cmd(tool), mkdirs)
38+
39+
case .Release:
40+
let inputs = module.dependencies.map{ $0.targetName } + module.sources.paths
41+
var args = ["-c", "-emit-module", "-D", "SWIFT_PACKAGE", "-O", "-whole-module-optimization", "-I", prefix] + otherArgs
42+
let productPath = Path.join(prefix, "\(module.c99name).o")
43+
44+
if module.type == .Library {
45+
args += ["-parse-as-library"]
46+
}
47+
48+
let tool = ShellTool(
49+
description: "Compiling \(module.name)",
50+
inputs: inputs,
51+
outputs: [productPath, module.targetName],
52+
args: [Toolchain.swiftc, "-o", productPath] + args + module.sources.paths + otherArgs)
53+
54+
return (cmd(tool), [])
55+
}
56+
}
57+
}

Sources/Build/Command.link().swift

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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 func POSIX.mkdir
12+
import PackageType
13+
import Utility
14+
15+
extension Command {
16+
static func link(product: Product, configuration conf: Configuration, prefix: String, otherArgs: [String]) throws -> Command {
17+
18+
let objects: [String]
19+
switch conf {
20+
case .Release:
21+
objects = product.buildables.map{ Path.join(prefix, "\($0.c99name).o") }
22+
case .Debug:
23+
objects = product.buildables.flatMap{ return SwiftcTool(module: $0, prefix: prefix, otherArgs: []).objects }
24+
}
25+
26+
let outpath = Path.join(prefix, product.outname)
27+
28+
var args = [Toolchain.swiftc] + otherArgs
29+
30+
switch product.type {
31+
case .Library(.Static):
32+
fatalError("Unimplemented")
33+
case .Test:
34+
#if os(OSX)
35+
args += ["-Xlinker", "-bundle"]
36+
37+
if let platformPath = Toolchain.platformPath {
38+
let path = Path.join(platformPath, "Developer/Library/Frameworks")
39+
args += ["-F", path]
40+
} else {
41+
throw Error.InvalidPlatformPath
42+
}
43+
44+
// TODO should be llbuild rules∫
45+
if conf == .Debug {
46+
try mkdir(outpath.parentDirectory)
47+
try fopen(outpath.parentDirectory.parentDirectory, "Info.plist", mode: .Write) { fp in
48+
try fputs(product.Info.plist, fp)
49+
}
50+
}
51+
#else
52+
// HACK: To get a path to LinuxMain.swift, we just grab the
53+
// parent directory of the first test module we can find.
54+
let firstTestModule = product.modules.flatMap{ $0 as? TestModule }.first!
55+
let testDirectory = firstTestModule.sources.root.parentDirectory
56+
let main = Path.join(testDirectory, "LinuxMain.swift")
57+
args.append(main)
58+
for module in product.modules {
59+
args += module.Xcc
60+
}
61+
args.append("-emit-executable")
62+
args += ["-I", prefix]
63+
#endif
64+
case .Library(.Dynamic):
65+
args.append("-emit-library")
66+
case .Executable:
67+
args.append("-emit-executable")
68+
if conf == .Release {
69+
args += ["-Xlinker", "-dead_strip"]
70+
}
71+
}
72+
73+
if conf == .Debug {
74+
args += ["-g"]
75+
}
76+
77+
args += ["-L\(prefix)"]
78+
args += ["-o", outpath]
79+
args += objects
80+
81+
let inputs = product.modules.flatMap{ [$0.targetName] + SwiftcTool(module: $0, prefix: prefix, otherArgs: []).inputs }
82+
83+
let shell = ShellTool(
84+
description: "Linking \(outpath.prettyPath)",
85+
inputs: inputs,
86+
outputs: [product.targetName, outpath],
87+
args: args)
88+
89+
return Command(node: product.targetName, tool: shell)
90+
}
91+
}
92+
93+
extension Product {
94+
private var buildables: [SwiftModule] {
95+
return recursiveDependencies(modules.map{$0}).flatMap{ $0 as? SwiftModule }
96+
}
97+
}

Sources/Build/Command.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
struct Command {
12+
let node: String
13+
let tool: ToolProtocol
14+
15+
static func createDirectory(path: String) -> Command {
16+
return Command(node: path, tool: MkdirTool(path: path))
17+
}
18+
}

Sources/Build/IncrementalNode.swift

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

0 commit comments

Comments
 (0)