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