14
14
@testable import PackageModel
15
15
16
16
import Basics
17
+ import LLBuildManifest
18
+ @_spi ( DontAdoptOutsideOfSwiftPMExposedForBenchmarksAndTestsOnly)
19
+ import PackageGraph
17
20
import SPMTestSupport
18
21
import XCTest
19
22
20
23
import class TSCBasic. BufferedOutputByteStream
21
24
import class TSCBasic. InMemoryFileSystem
22
25
26
+ private func mockBuildOperation(
27
+ buildParameters: BuildParameters ,
28
+ cacheBuildManifest: Bool = false ,
29
+ packageGraphLoader: @escaping ( ) -> ModulesGraph = { fatalError ( ) } ,
30
+ scratchDirectory: AbsolutePath ,
31
+ fs: any Basics . FileSystem ,
32
+ observabilityScope: ObservabilityScope
33
+ ) -> BuildOperation {
34
+ return BuildOperation (
35
+ productsBuildParameters: buildParameters,
36
+ toolsBuildParameters: buildParameters,
37
+ cacheBuildManifest: cacheBuildManifest,
38
+ packageGraphLoader: packageGraphLoader,
39
+ scratchDirectory: scratchDirectory,
40
+ additionalFileRules: [ ] ,
41
+ pkgConfigDirectories: [ ] ,
42
+ dependenciesByRootPackageIdentity: [ : ] ,
43
+ targetsByRootPackageIdentity: [ : ] ,
44
+ outputStream: BufferedOutputByteStream ( ) ,
45
+ logLevel: . info,
46
+ fileSystem: fs,
47
+ observabilityScope: observabilityScope
48
+ )
49
+ }
50
+
23
51
final class BuildOperationTests : XCTestCase {
24
52
func testDetectUnexpressedDependencies( ) throws {
25
- let buildParameters = mockBuildParameters ( shouldDisableLocalRpath: false )
53
+ let scratchDirectory = AbsolutePath ( " /path/to/build " )
54
+ let triple = hostTriple
55
+ let buildParameters = mockBuildParameters (
56
+ buildPath: scratchDirectory. appending ( triple. tripleString) ,
57
+ shouldDisableLocalRpath: false ,
58
+ triple: triple
59
+ )
26
60
27
61
let fs = InMemoryFileSystem ( files: [
28
62
" \( buildParameters. dataPath) /debug/Lunch.build/Lunch.d " : " /Best.framework "
29
63
] )
30
64
31
65
let observability = ObservabilitySystem . makeForTesting ( )
32
- let buildOp = BuildOperation (
33
- productsBuildParameters: buildParameters,
34
- toolsBuildParameters: buildParameters,
35
- cacheBuildManifest: false ,
36
- packageGraphLoader: { fatalError ( ) } ,
37
- additionalFileRules: [ ] ,
38
- pkgConfigDirectories: [ ] ,
39
- dependenciesByRootPackageIdentity: [ : ] ,
40
- targetsByRootPackageIdentity: [ : ] ,
41
- outputStream: BufferedOutputByteStream ( ) ,
42
- logLevel: . info,
43
- fileSystem: fs,
44
- observabilityScope: observability. topScope
66
+ let buildOp = mockBuildOperation (
67
+ buildParameters: buildParameters,
68
+ scratchDirectory: scratchDirectory,
69
+ fs: fs, observabilityScope: observability. topScope
45
70
)
46
71
buildOp. detectUnexpressedDependencies (
47
72
availableLibraries: [
@@ -65,4 +90,85 @@ final class BuildOperationTests: XCTestCase {
65
90
[ " target 'Lunch' has an unexpressed depedency on 'foo' " ]
66
91
)
67
92
}
93
+
94
+ func testDetectProductTripleChange( ) throws {
95
+ let observability = ObservabilitySystem . makeForTesting ( )
96
+ let fs = InMemoryFileSystem (
97
+ emptyFiles: " /Pkg/Sources/ATarget/foo.swift "
98
+ )
99
+ let packageGraph = try loadModulesGraph (
100
+ fileSystem: fs,
101
+ manifests: [
102
+ . createRootManifest(
103
+ displayName: " SwitchTriple " ,
104
+ path: " /Pkg " ,
105
+ targets: [
106
+ TargetDescription ( name: " ATarget " ) ,
107
+ ]
108
+ ) ,
109
+ ] ,
110
+ observabilityScope: observability. topScope
111
+ )
112
+ try withTemporaryDirectory { tmpDir in
113
+ let scratchDirectory = tmpDir. appending ( " .build " )
114
+ let fs = localFileSystem
115
+ let triples = try [ Triple ( " x86_64-unknown-linux-gnu " ) , Triple ( " wasm32-unknown-wasi " ) ]
116
+ var llbuildManifestByTriple : [ String : String ] = [ : ]
117
+
118
+ // Perform initial builds for each triple
119
+ for triple in triples {
120
+ let buildParameters = mockBuildParameters (
121
+ buildPath: scratchDirectory. appending ( triple. tripleString) ,
122
+ config: . debug,
123
+ triple: triple
124
+ )
125
+ let buildOp = mockBuildOperation (
126
+ buildParameters: buildParameters,
127
+ cacheBuildManifest: false ,
128
+ packageGraphLoader: { packageGraph } ,
129
+ scratchDirectory: scratchDirectory,
130
+ fs: fs, observabilityScope: observability. topScope
131
+ )
132
+ // Generate initial llbuild manifest
133
+ let _ = try buildOp. getBuildDescription ( )
134
+ // Record the initial llbuild manifest as expected one
135
+ llbuildManifestByTriple [ triple. tripleString] = try fs. readFileContents ( buildParameters. llbuildManifest)
136
+ }
137
+
138
+ XCTAssertTrue ( fs. exists ( scratchDirectory. appending ( " debug.yaml " ) ) )
139
+ // FIXME: There should be a build database with manifest cache after the initial build.
140
+ // The initial build usually triggered with `cacheBuildManifest=false` because llbuild
141
+ // manifest file and description.json are not found. However, with `cacheBuildManifest=false`,
142
+ // `BuildOperation` does not trigger "PackageStructure" build, thus the initial build does
143
+ // not record the manifest cache. So "getBuildDescription" doesn't create build.db for the
144
+ // initial planning and the second build always need full-planning.
145
+ //
146
+ // XCTAssertTrue(fs.exists(scratchDirectory.appending("build.db")))
147
+
148
+ // Perform incremental build several times and switch triple for each time
149
+ for _ in 0 ..< 4 {
150
+ for triple in triples {
151
+ let buildParameters = mockBuildParameters (
152
+ buildPath: scratchDirectory. appending ( triple. tripleString) ,
153
+ config: . debug,
154
+ triple: triple
155
+ )
156
+ let buildOp = mockBuildOperation (
157
+ buildParameters: buildParameters,
158
+ cacheBuildManifest: true ,
159
+ packageGraphLoader: { packageGraph } ,
160
+ scratchDirectory: scratchDirectory,
161
+ fs: fs, observabilityScope: observability. topScope
162
+ )
163
+ // Generate llbuild manifest
164
+ let _ = try buildOp. getBuildDescription ( )
165
+
166
+ // Ensure that llbuild manifest is updated to the expected one
167
+ let actualManifest : String = try fs. readFileContents ( buildParameters. llbuildManifest)
168
+ let expectedManifest = try XCTUnwrap ( llbuildManifestByTriple [ triple. tripleString] )
169
+ XCTAssertEqual ( actualManifest, expectedManifest)
170
+ }
171
+ }
172
+ }
173
+ }
68
174
}
0 commit comments