Skip to content

Commit e36943b

Browse files
authored
Split LLBuildManifestBuilder.swift into extension files (#6966)
`LLBuildManifestBuilder.swift` is getting too big, especially when there's a need to add new commands for additional build steps. Fortunately, it's already separated out into multiple extensions, with different commands implemented in each extension. Let's move those extensions into separate files for better readability and easier discovery/navigation.
1 parent 9799a78 commit e36943b

8 files changed

+644
-590
lines changed

Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ public final class SwiftTargetBuildDescription {
553553
// // User arguments (from -Xcxx) should follow generated arguments to allow user overrides
554554
// args += self.buildParameters.flags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
555555

556-
// Enable the correct lto mode if requested.
556+
// Enable the correct LTO mode if requested.
557557
switch self.buildParameters.linkTimeOptimizationMode {
558558
case nil:
559559
break
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2015-2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import struct LLBuildManifest.Node
14+
import struct Basics.AbsolutePath
15+
import struct Basics.InternalError
16+
import class PackageGraph.ResolvedTarget
17+
import PackageModel
18+
19+
extension LLBuildManifestBuilder {
20+
/// Create a llbuild target for a Clang target description.
21+
func createClangCompileCommand(
22+
_ target: ClangTargetBuildDescription
23+
) throws {
24+
let standards = [
25+
(target.clangTarget.cxxLanguageStandard, SupportedLanguageExtension.cppExtensions),
26+
(target.clangTarget.cLanguageStandard, SupportedLanguageExtension.cExtensions),
27+
]
28+
29+
var inputs: [Node] = []
30+
31+
// Add resources node as the input to the target. This isn't great because we
32+
// don't need to block building of a module until its resources are assembled but
33+
// we don't currently have a good way to express that resources should be built
34+
// whenever a module is being built.
35+
if let resourcesNode = try self.createResourcesBundle(for: .clang(target)) {
36+
inputs.append(resourcesNode)
37+
}
38+
39+
func addStaticTargetInputs(_ target: ResolvedTarget) {
40+
if case .swift(let desc)? = self.plan.targetMap[target], target.type == .library {
41+
inputs.append(file: desc.moduleOutputPath)
42+
}
43+
}
44+
45+
for dependency in target.target.dependencies(satisfying: self.buildEnvironment) {
46+
switch dependency {
47+
case .target(let target, _):
48+
addStaticTargetInputs(target)
49+
50+
case .product(let product, _):
51+
switch product.type {
52+
case .executable, .snippet, .library(.dynamic), .macro:
53+
guard let planProduct = plan.productMap[product] else {
54+
throw InternalError("unknown product \(product)")
55+
}
56+
// Establish a dependency on binary of the product.
57+
let binary = try planProduct.binaryPath
58+
inputs.append(file: binary)
59+
60+
case .library(.automatic), .library(.static), .plugin:
61+
for target in product.targets {
62+
addStaticTargetInputs(target)
63+
}
64+
case .test:
65+
break
66+
}
67+
}
68+
}
69+
70+
for binaryPath in target.libraryBinaryPaths {
71+
let path = destinationPath(forBinaryAt: binaryPath)
72+
if self.fileSystem.isDirectory(binaryPath) {
73+
inputs.append(directory: path)
74+
} else {
75+
inputs.append(file: path)
76+
}
77+
}
78+
79+
var objectFileNodes: [Node] = []
80+
81+
for path in try target.compilePaths() {
82+
let isCXX = path.source.extension.map { SupportedLanguageExtension.cppExtensions.contains($0) } ?? false
83+
let isC = path.source.extension.map { $0 == SupportedLanguageExtension.c.rawValue } ?? false
84+
85+
var args = try target.basicArguments(isCXX: isCXX, isC: isC)
86+
87+
args += ["-MD", "-MT", "dependencies", "-MF", path.deps.pathString]
88+
89+
// Add language standard flag if needed.
90+
if let ext = path.source.extension {
91+
for (standard, validExtensions) in standards {
92+
if let standard, validExtensions.contains(ext) {
93+
args += ["-std=\(standard)"]
94+
}
95+
}
96+
}
97+
98+
args += ["-c", path.source.pathString, "-o", path.object.pathString]
99+
100+
let clangCompiler = try buildParameters.toolchain.getClangCompiler().pathString
101+
args.insert(clangCompiler, at: 0)
102+
103+
let objectFileNode: Node = .file(path.object)
104+
objectFileNodes.append(objectFileNode)
105+
106+
self.manifest.addClangCmd(
107+
name: path.object.pathString,
108+
description: "Compiling \(target.target.name) \(path.filename)",
109+
inputs: inputs + [.file(path.source)],
110+
outputs: [objectFileNode],
111+
arguments: args,
112+
dependencies: path.deps.pathString
113+
)
114+
}
115+
116+
try addBuildToolPlugins(.clang(target))
117+
118+
// Create a phony node to represent the entire target.
119+
let targetName = target.target.getLLBuildTargetName(config: self.buildConfig)
120+
let output: Node = .virtual(targetName)
121+
122+
self.manifest.addNode(output, toTarget: targetName)
123+
self.manifest.addPhonyCmd(
124+
name: output.name,
125+
inputs: objectFileNodes,
126+
outputs: [output]
127+
)
128+
129+
if self.plan.graph.isInRootPackages(target.target, satisfying: self.buildEnvironment) {
130+
if !target.isTestTarget {
131+
self.addNode(output, toTarget: .main)
132+
}
133+
self.addNode(output, toTarget: .test)
134+
}
135+
}
136+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2015-2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import struct LLBuildManifest.Node
14+
import struct Basics.RelativePath
15+
16+
extension LLBuildManifestBuilder {
17+
/// Adds command for creating the resources bundle of the given target.
18+
///
19+
/// Returns the virtual node that will build the entire bundle.
20+
func createResourcesBundle(
21+
for target: TargetBuildDescription
22+
) throws -> Node? {
23+
guard let bundlePath = target.bundlePath else { return nil }
24+
25+
var outputs: [Node] = []
26+
27+
let infoPlistDestination = try RelativePath(validating: "Info.plist")
28+
29+
// Create a copy command for each resource file.
30+
for resource in target.resources {
31+
switch resource.rule {
32+
case .copy, .process:
33+
let destination = try bundlePath.appending(resource.destination)
34+
let (_, output) = addCopyCommand(from: resource.path, to: destination)
35+
outputs.append(output)
36+
case .embedInCode:
37+
break
38+
}
39+
}
40+
41+
// Create a copy command for the Info.plist if a resource with the same name doesn't exist yet.
42+
if let infoPlistPath = target.resourceBundleInfoPlistPath {
43+
let destination = bundlePath.appending(infoPlistDestination)
44+
let (_, output) = addCopyCommand(from: infoPlistPath, to: destination)
45+
outputs.append(output)
46+
}
47+
48+
let cmdName = target.target.getLLBuildResourcesCmdName(config: self.buildConfig)
49+
self.manifest.addPhonyCmd(name: cmdName, inputs: outputs, outputs: [.virtual(cmdName)])
50+
51+
return .virtual(cmdName)
52+
}
53+
}

0 commit comments

Comments
 (0)