Skip to content

Commit 422d495

Browse files
committed
Incremental build for C targets
1 parent 2c588fd commit 422d495

File tree

3 files changed

+108
-32
lines changed

3 files changed

+108
-32
lines changed

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

Lines changed: 83 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,19 @@ import PackageType
1212
import Utility
1313
import POSIX
1414

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, module.type == .Library ? "lib\(module.c99name).so" : module.c99name)
25-
15+
private extension ClangModule {
16+
var basicArgs: [String] {
2617
var args: [String] = []
27-
#if os(Linux)
28-
args += ["-fPIC"]
29-
#endif
30-
args += ["-fmodules", "-fmodule-name=\(module.name)"]
31-
args += ["-L\(prefix)"]
18+
#if os(Linux)
19+
args += ["-fPIC"]
20+
#endif
21+
args += ["-fmodules", "-fmodule-name=\(name)"]
22+
return args
23+
}
3224

33-
for case let dep as ClangModule in module.dependencies {
25+
var includeFlags: [String] {
26+
var args: [String] = []
27+
for case let dep as ClangModule in dependencies {
3428
let includeFlag: String
3529
//add `-iquote` argument to the include directory of every target in the package in the
3630
//transitive closure of the target being built allowing the use of `#include "..."`
@@ -45,32 +39,91 @@ extension Command {
4539
includeFlag = "-iquote"
4640
}
4741
args += [includeFlag, dep.path]
48-
args += ["-l\(dep.c99name)"] //FIXME: giving path to other module's -fmodule-map-file is not linking that module
4942
}
43+
return args
44+
}
45+
46+
var linkFlags: [String] {
47+
var args: [String] = []
48+
for case let dep as ClangModule in dependencies {
49+
args += ["-l\(dep.c99name)"]
50+
}
51+
return args
52+
}
5053

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

58-
args += module.sources.paths
59-
60113
if module.type == .Library {
61114
args += ["-shared"]
62115
}
63-
64-
args += ["-o", productPath]
65116

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

120+
let clang = ClangTool(desc: "Linking \(module.name)",
121+
inputs: dependencies + compileCommands.map{$0.node} + [mkdir.node],
122+
outputs: [productPath, module.targetName],
123+
args: args,
124+
deps: nil)
72125
let command = Command(node: module.targetName, tool: clang)
73126

74-
return (command, mkdir)
127+
return (compileCommands + [command], mkdir)
75128
}
76129
}

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)