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