blob: 68ebe7cc056ca563e095978efad64f52894dd442 [file] [log] [blame]
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +01001#!/bin/bash -eu
2
3# This test exercises the bootstrapping process of the build system
4# in a source tree that only contains enough files for Bazel and Soong to work.
5
Lukacs T. Berki3b730c42021-04-08 13:21:13 +02006source "$(dirname "$0")/lib.sh"
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +01007
8function test_smoke {
9 setup
10 run_soong
11}
12
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +010013function test_null_build() {
14 setup
15 run_soong
16 local bootstrap_mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
17 local output_mtime1=$(stat -c "%y" out/soong/build.ninja)
18 run_soong
19 local bootstrap_mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
20 local output_mtime2=$(stat -c "%y" out/soong/build.ninja)
21
22 if [[ "$bootstrap_mtime1" == "$bootstrap_mtime2" ]]; then
23 # Bootstrapping is always done. It doesn't take a measurable amount of time.
24 fail "Bootstrap Ninja file did not change on null build"
25 fi
26
27 if [[ "$output_mtime1" != "$output_mtime2" ]]; then
28 fail "Output Ninja file changed on null build"
29 fi
30}
31
32function test_soong_build_rebuilt_if_blueprint_changes() {
33 setup
34 run_soong
35 local mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
36
37 sed -i 's/pluginGenSrcCmd/pluginGenSrcCmd2/g' build/blueprint/bootstrap/bootstrap.go
38
39 run_soong
40 local mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
41
42 if [[ "$mtime1" == "$mtime2" ]]; then
43 fail "Bootstrap Ninja file did not change"
44 fi
45}
46
47function test_change_android_bp() {
48 setup
49 mkdir -p a
50 cat > a/Android.bp <<'EOF'
51python_binary_host {
52 name: "my_little_binary_host",
53 srcs: ["my_little_binary_host.py"]
54}
55EOF
56 touch a/my_little_binary_host.py
57 run_soong
58
59 grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja || fail "module not found"
60
61 cat > a/Android.bp <<'EOF'
62python_binary_host {
63 name: "my_great_binary_host",
64 srcs: ["my_great_binary_host.py"]
65}
66EOF
67 touch a/my_great_binary_host.py
68 run_soong
69
70 grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja && fail "old module found"
71 grep -q "^# Module:.*my_great_binary_host" out/soong/build.ninja || fail "new module not found"
72}
73
74
75function test_add_android_bp() {
76 setup
77 run_soong
78 local mtime1=$(stat -c "%y" out/soong/build.ninja)
79
80 mkdir -p a
81 cat > a/Android.bp <<'EOF'
82python_binary_host {
83 name: "my_little_binary_host",
84 srcs: ["my_little_binary_host.py"]
85}
86EOF
87 touch a/my_little_binary_host.py
88 run_soong
89
90 local mtime2=$(stat -c "%y" out/soong/build.ninja)
91 if [[ "$mtime1" == "$mtime2" ]]; then
92 fail "Output Ninja file did not change"
93 fi
94
95 grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "New module not in output"
96
97 run_soong
98}
99
100function test_delete_android_bp() {
101 setup
102 mkdir -p a
103 cat > a/Android.bp <<'EOF'
104python_binary_host {
105 name: "my_little_binary_host",
106 srcs: ["my_little_binary_host.py"]
107}
108EOF
109 touch a/my_little_binary_host.py
110 run_soong
111
112 grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "Module not in output"
113
114 rm a/Android.bp
115 run_soong
116
117 grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja && fail "Old module in output"
118}
119
Colin Cross10425952021-04-12 18:59:18 -0700120# Test that an incremental build with a glob doesn't rerun soong_build, and
121# only regenerates the globs on the first but not the second incremental build.
122function test_glob_noop_incremental() {
123 setup
124
125 mkdir -p a
126 cat > a/Android.bp <<'EOF'
127python_binary_host {
128 name: "my_little_binary_host",
129 srcs: ["*.py"],
130}
131EOF
132 touch a/my_little_binary_host.py
133 run_soong
134 local ninja_mtime1=$(stat -c "%y" out/soong/build.ninja)
135
136 local glob_deps_file=out/soong/.glob/a/__py.glob.d
137
138 if [ -e "$glob_deps_file" ]; then
139 fail "Glob deps file unexpectedly written on first build"
140 fi
141
142 run_soong
143 local ninja_mtime2=$(stat -c "%y" out/soong/build.ninja)
144
145 # There is an ineffiencency in glob that requires bpglob to rerun once for each glob to update
146 # the entry in the .ninja_log. It doesn't update the output file, but we can detect the rerun
147 # by checking if the deps file was created.
148 if [ ! -e "$glob_deps_file" ]; then
149 fail "Glob deps file missing after second build"
150 fi
151
152 local glob_deps_mtime2=$(stat -c "%y" "$glob_deps_file")
153
154 if [[ "$ninja_mtime1" != "$ninja_mtime2" ]]; then
155 fail "Ninja file rewritten on null incremental build"
156 fi
157
158 run_soong
159 local ninja_mtime3=$(stat -c "%y" out/soong/build.ninja)
160 local glob_deps_mtime3=$(stat -c "%y" "$glob_deps_file")
161
162 if [[ "$ninja_mtime2" != "$ninja_mtime3" ]]; then
163 fail "Ninja file rewritten on null incremental build"
164 fi
165
166 # The bpglob commands should not rerun after the first incremental build.
167 if [[ "$glob_deps_mtime2" != "$glob_deps_mtime3" ]]; then
168 fail "Glob deps file rewritten on second null incremental build"
169 fi
170}
171
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100172function test_add_file_to_glob() {
173 setup
174
175 mkdir -p a
176 cat > a/Android.bp <<'EOF'
177python_binary_host {
178 name: "my_little_binary_host",
179 srcs: ["*.py"],
180}
181EOF
182 touch a/my_little_binary_host.py
183 run_soong
184 local mtime1=$(stat -c "%y" out/soong/build.ninja)
185
186 touch a/my_little_library.py
187 run_soong
188
189 local mtime2=$(stat -c "%y" out/soong/build.ninja)
190 if [[ "$mtime1" == "$mtime2" ]]; then
191 fail "Output Ninja file did not change"
192 fi
193
194 grep -q my_little_library.py out/soong/build.ninja || fail "new file is not in output"
195}
196
Lukacs T. Berkif0b3b942021-03-23 11:46:47 +0100197function test_soong_build_rerun_iff_environment_changes() {
198 setup
199
200 mkdir -p cherry
201 cat > cherry/Android.bp <<'EOF'
202bootstrap_go_package {
203 name: "cherry",
204 pkgPath: "android/soong/cherry",
205 deps: [
206 "blueprint",
207 "soong",
208 "soong-android",
209 ],
210 srcs: [
211 "cherry.go",
212 ],
213 pluginFor: ["soong_build"],
214}
215EOF
216
217 cat > cherry/cherry.go <<'EOF'
218package cherry
219
220import (
221 "android/soong/android"
222 "github.com/google/blueprint"
223)
224
225var (
226 pctx = android.NewPackageContext("cherry")
227)
228
229func init() {
230 android.RegisterSingletonType("cherry", CherrySingleton)
231}
232
233func CherrySingleton() android.Singleton {
234 return &cherrySingleton{}
235}
236
237type cherrySingleton struct{}
238
239func (p *cherrySingleton) GenerateBuildActions(ctx android.SingletonContext) {
240 cherryRule := ctx.Rule(pctx, "cherry",
241 blueprint.RuleParams{
242 Command: "echo CHERRY IS " + ctx.Config().Getenv("CHERRY") + " > ${out}",
243 CommandDeps: []string{},
244 Description: "Cherry",
245 })
246
247 outputFile := android.PathForOutput(ctx, "cherry", "cherry.txt")
248 var deps android.Paths
249
250 ctx.Build(pctx, android.BuildParams{
251 Rule: cherryRule,
252 Output: outputFile,
253 Inputs: deps,
254 })
255}
256EOF
257
258 export CHERRY=TASTY
259 run_soong
260 grep -q "CHERRY IS TASTY" out/soong/build.ninja \
261 || fail "first value of environment variable is not used"
262
263 export CHERRY=RED
264 run_soong
265 grep -q "CHERRY IS RED" out/soong/build.ninja \
266 || fail "second value of environment variable not used"
267 local mtime1=$(stat -c "%y" out/soong/build.ninja)
268
269 run_soong
270 local mtime2=$(stat -c "%y" out/soong/build.ninja)
271 if [[ "$mtime1" != "$mtime2" ]]; then
272 fail "Output Ninja file changed when environment variable did not"
273 fi
274
275}
276
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100277function test_add_file_to_soong_build() {
278 setup
279 run_soong
280 local mtime1=$(stat -c "%y" out/soong/build.ninja)
281
282 mkdir -p a
283 cat > a/Android.bp <<'EOF'
284bootstrap_go_package {
285 name: "picard-soong-rules",
286 pkgPath: "android/soong/picard",
287 deps: [
288 "blueprint",
289 "soong",
290 "soong-android",
291 ],
292 srcs: [
293 "picard.go",
294 ],
295 pluginFor: ["soong_build"],
296}
297EOF
298
299 cat > a/picard.go <<'EOF'
300package picard
301
302import (
303 "android/soong/android"
304 "github.com/google/blueprint"
305)
306
307var (
308 pctx = android.NewPackageContext("picard")
309)
310
311func init() {
312 android.RegisterSingletonType("picard", PicardSingleton)
313}
314
315func PicardSingleton() android.Singleton {
316 return &picardSingleton{}
317}
318
319type picardSingleton struct{}
320
321func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
322 picardRule := ctx.Rule(pctx, "picard",
323 blueprint.RuleParams{
324 Command: "echo Make it so. > ${out}",
325 CommandDeps: []string{},
326 Description: "Something quotable",
327 })
328
329 outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
330 var deps android.Paths
331
332 ctx.Build(pctx, android.BuildParams{
333 Rule: picardRule,
334 Output: outputFile,
335 Inputs: deps,
336 })
337}
338
339EOF
340
341 run_soong
342 local mtime2=$(stat -c "%y" out/soong/build.ninja)
343 if [[ "$mtime1" == "$mtime2" ]]; then
344 fail "Output Ninja file did not change"
345 fi
346
347 grep -q "Make it so" out/soong/build.ninja || fail "New action not present"
348}
349
Colin Crossc02504e2021-04-08 10:34:16 -0700350# Tests a glob in a build= statement in an Android.bp file, which is interpreted
351# during bootstrapping.
352function test_glob_during_bootstrapping() {
353 setup
354
355 mkdir -p a
356 cat > a/Android.bp <<'EOF'
357build=["foo*.bp"]
358EOF
359 cat > a/fooa.bp <<'EOF'
360bootstrap_go_package {
361 name: "picard-soong-rules",
362 pkgPath: "android/soong/picard",
363 deps: [
364 "blueprint",
365 "soong",
366 "soong-android",
367 ],
368 srcs: [
369 "picard.go",
370 ],
371 pluginFor: ["soong_build"],
372}
373EOF
374
375 cat > a/picard.go <<'EOF'
376package picard
377
378import (
379 "android/soong/android"
380 "github.com/google/blueprint"
381)
382
383var (
384 pctx = android.NewPackageContext("picard")
385)
386
387func init() {
388 android.RegisterSingletonType("picard", PicardSingleton)
389}
390
391func PicardSingleton() android.Singleton {
392 return &picardSingleton{}
393}
394
395type picardSingleton struct{}
396
397var Message = "Make it so."
398
399func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
400 picardRule := ctx.Rule(pctx, "picard",
401 blueprint.RuleParams{
402 Command: "echo " + Message + " > ${out}",
403 CommandDeps: []string{},
404 Description: "Something quotable",
405 })
406
407 outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
408 var deps android.Paths
409
410 ctx.Build(pctx, android.BuildParams{
411 Rule: picardRule,
412 Output: outputFile,
413 Inputs: deps,
414 })
415}
416
417EOF
418
419 run_soong
420 local mtime1=$(stat -c "%y" out/soong/build.ninja)
421
422 grep -q "Make it so" out/soong/build.ninja || fail "Original action not present"
423
424 cat > a/foob.bp <<'EOF'
425bootstrap_go_package {
426 name: "worf-soong-rules",
427 pkgPath: "android/soong/worf",
428 deps: [
429 "blueprint",
430 "soong",
431 "soong-android",
432 "picard-soong-rules",
433 ],
434 srcs: [
435 "worf.go",
436 ],
437 pluginFor: ["soong_build"],
438}
439EOF
440
441 cat > a/worf.go <<'EOF'
442package worf
443
444import "android/soong/picard"
445
446func init() {
447 picard.Message = "Engage."
448}
449EOF
450
451 run_soong
452 local mtime2=$(stat -c "%y" out/soong/build.ninja)
453 if [[ "$mtime1" == "$mtime2" ]]; then
454 fail "Output Ninja file did not change"
455 fi
456
457 grep -q "Engage" out/soong/build.ninja || fail "New action not present"
458
459 grep -q "Make it so" out/soong/build.ninja && fail "Original action still present"
460}
461
Lukacs T. Berkif0b3b942021-03-23 11:46:47 +0100462function test_null_build_after_docs {
463 setup
464 run_soong
465 local mtime1=$(stat -c "%y" out/soong/build.ninja)
466
467 prebuilts/build-tools/linux-x86/bin/ninja -f out/soong/build.ninja soong_docs
468 run_soong
469 local mtime2=$(stat -c "%y" out/soong/build.ninja)
470
471 if [[ "$mtime1" != "$mtime2" ]]; then
472 fail "Output Ninja file changed on null build"
473 fi
474}
475
Lukacs T. Berki97bb9f12021-04-01 18:28:45 +0200476function test_dump_json_module_graph() {
477 setup
478 SOONG_DUMP_JSON_MODULE_GRAPH="$MOCK_TOP/modules.json" run_soong
479 if [[ ! -r "$MOCK_TOP/modules.json" ]]; then
480 fail "JSON file was not created"
481 fi
482}
483
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100484test_smoke
485test_null_build
Lukacs T. Berkif0b3b942021-03-23 11:46:47 +0100486test_null_build_after_docs
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100487test_soong_build_rebuilt_if_blueprint_changes
Colin Cross10425952021-04-12 18:59:18 -0700488test_glob_noop_incremental
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100489test_add_file_to_glob
490test_add_android_bp
491test_change_android_bp
492test_delete_android_bp
493test_add_file_to_soong_build
Colin Crossc02504e2021-04-08 10:34:16 -0700494test_glob_during_bootstrapping
Lukacs T. Berkif0b3b942021-03-23 11:46:47 +0100495test_soong_build_rerun_iff_environment_changes
Lukacs T. Berki97bb9f12021-04-01 18:28:45 +0200496test_dump_json_module_graph