Skip to content

Commit 401ed4a

Browse files
committed
Incremental build for C targets
1 parent 2c588fd commit 401ed4a

File tree

3 files changed

+110
-29
lines changed

3 files changed

+110
-29
lines changed

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

Lines changed: 85 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,20 @@ import POSIX
1414

1515
//FIXME: Incremental builds
1616

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, module.type == .Library ? "lib\(module.c99name).so" : module.c99name)
17+
private extension ClangModule {
2518

19+
var basicArgs: [String] {
2620
var args: [String] = []
27-
#if os(Linux)
28-
args += ["-fPIC"]
29-
#endif
30-
args += ["-fmodules", "-fmodule-name=\(module.name)"]
31-
args += ["-L\(prefix)"]
21+
#if os(Linux)
22+
args += ["-fPIC"]
23+
#endif
24+
args += ["-fmodules", "-fmodule-name=\(name)"]
25+
return args
26+
}
3227

33-
for case let dep as ClangModule in module.dependencies {
28+
var includeFlags: [String] {
29+
var args: [String] = []
30+
for case let dep as ClangModule in dependencies {
3431
let includeFlag: String
3532
//add `-iquote` argument to the include directory of every target in the package in the
3633
//transitive closure of the target being built allowing the use of `#include "..."`
@@ -45,32 +42,93 @@ extension Command {
4542
includeFlag = "-iquote"
4643
}
4744
args += [includeFlag, dep.path]
48-
args += ["-l\(dep.c99name)"] //FIXME: giving path to other module's -fmodule-map-file is not linking that module
4945
}
46+
return args
47+
}
48+
49+
var linkFlags: [String] {
50+
var args: [String] = []
51+
for case let dep as ClangModule in dependencies {
52+
args += ["-l\(dep.c99name)"]
53+
}
54+
return args
55+
}
5056

57+
func optimizationFlags(conf: Configuration) -> [String] {
5158
switch conf {
5259
case .Debug:
53-
args += ["-g", "-O0"]
60+
return ["-g", "-O0"]
5461
case .Release:
55-
args += ["-O2"]
62+
return ["-O2"]
63+
}
64+
}
65+
}
66+
67+
private extension Sources {
68+
69+
func compilePathsForBuildDir(wd: String) -> [(filename: String, source: String, object: String, deps: String)] {
70+
return relativePaths.map { source in
71+
let path = Path.join(root, source)
72+
let object = Path.join(wd, "\(source).o")
73+
let deps = Path.join(wd, "\(source).d")
74+
return (source, path, object, deps)
75+
}
76+
}
77+
78+
}
79+
80+
extension Command {
81+
static func compile(clangModule module: ClangModule, configuration conf: Configuration, prefix: String) -> ([Command], Command) {
82+
83+
let wd = Path.join(prefix, "\(module.c99name).build")
84+
let mkdir = Command.createDirectory(wd)
85+
86+
///------------------------------ Compile -----------------------------------------
87+
var compileCommands = [Command]()
88+
let dependencies = module.dependencies.map{ $0.targetName }
89+
let basicArgs = module.basicArgs + module.includeFlags + module.optimizationFlags(conf)
90+
for path in module.sources.compilePathsForBuildDir(wd) {
91+
var args = basicArgs
92+
args += ["-MMD", "-MT", "dependencies", "-MF", path.deps]
93+
args += ["-c", path.source, "-o", path.object]
94+
95+
let node = "<\(module.name).\(path.filename)>"
96+
97+
let clang = ClangTool(desc: "Compiling \(module.name) \(path.filename)",
98+
inputs: dependencies + [path.source, mkdir.node],
99+
outputs: [path.object, node],
100+
args: args,
101+
deps: path.deps)
102+
103+
let command = Command(node: node, tool: clang)
104+
105+
compileCommands.append(command)
56106
}
57107

58-
args += module.sources.paths
59-
108+
109+
///FIXME: This probably doesn't belong here
110+
///------------------------------ Product -----------------------------------------
111+
112+
var args = module.basicArgs
113+
args += module.optimizationFlags(conf)
114+
args += ["-L\(prefix)"]
115+
args += module.linkFlags
116+
args += module.sources.compilePathsForBuildDir(wd).map{$0.object}
117+
60118
if module.type == .Library {
61119
args += ["-shared"]
62120
}
63-
64-
args += ["-o", productPath]
65121

66-
let clang = ShellTool(
67-
description: "Compiling \(module.name)",
68-
inputs: inputs,
69-
outputs: [productPath, module.targetName],
70-
args: [Toolchain.clang] + args)
122+
let productPath = Path.join(prefix, module.type == .Library ? "lib\(module.c99name).so" : module.c99name)
123+
args += ["-o", productPath]
71124

125+
let clang = ClangTool(desc: "Linking \(module.name)",
126+
inputs: dependencies + compileCommands.map{$0.node} + [mkdir.node],
127+
outputs: [productPath, module.targetName],
128+
args: args,
129+
deps: nil)
72130
let command = Command(node: module.targetName, tool: clang)
73131

74-
return (command, mkdir)
132+
return (compileCommands + [command], mkdir)
75133
}
76134
}

Sources/Build/ToolProtocol.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,26 @@ struct MkdirTool: ToolProtocol {
110110
return yaml
111111
}
112112
}
113+
114+
struct ClangTool: ToolProtocol {
115+
let desc: String
116+
let inputs: [String]
117+
let outputs: [String]
118+
let args: [String]
119+
let deps: String?
120+
121+
var name: String { return "clang" }
122+
123+
var YAMLDescription: String {
124+
var yaml = ""
125+
yaml += " tool: " + name.YAML + "\n"
126+
yaml += " description: " + desc.YAML + "\n"
127+
yaml += " inputs: " + inputs.YAML + "\n"
128+
yaml += " outputs: " + outputs.YAML + "\n"
129+
yaml += " args: " + ([Toolchain.clang] + args).joined(separator: " ").YAML + "\n"
130+
if let deps = deps {
131+
yaml += " deps: " + deps.YAML + "\n"
132+
}
133+
return yaml
134+
}
135+
}

Sources/Build/describe().swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ public func describe(prefix: String, _ conf: Configuration, _ modules: [Module],
5151
}
5252

5353
let (compile, mkdir) = Command.compile(clangModule: module, configuration: conf, prefix: prefix)
54-
commands.append(compile)
54+
commands += compile
5555
commands.append(mkdir)
56-
targets.main.cmds.append(compile)
56+
targets.main.cmds += compile
5757

5858
case is CModule:
5959
continue

0 commit comments

Comments
 (0)