blob: 68067ee87519bfbaa571b5749fa693b892f7ca50 [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
6HARDWIRED_MOCK_TOP=
7# Uncomment this for to be able to view the source tree after a test is run
8# HARDWIRED_MOCK_TOP=/tmp/td
9
10REAL_TOP="$(readlink -f "$(dirname "$0")"/../..)"
11
12function fail {
13 echo ERROR: $1
14 exit 1
15}
16
17function copy_directory() {
18 local dir="$1"
19 local parent="$(dirname "$dir")"
20
21 mkdir -p "$MOCK_TOP/$parent"
22 cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
23}
24
25function symlink_file() {
26 local file="$1"
27
28 mkdir -p "$MOCK_TOP/$(dirname "$file")"
29 ln -s "$REAL_TOP/$file" "$MOCK_TOP/$file"
30}
31
32function symlink_directory() {
33 local dir="$1"
34
35 mkdir -p "$MOCK_TOP/$dir"
36 # We need to symlink the contents of the directory individually instead of
37 # using one symlink for the whole directory because finder.go doesn't follow
38 # symlinks when looking for Android.bp files
39 for i in $(ls "$REAL_TOP/$dir"); do
40 local target="$MOCK_TOP/$dir/$i"
41 local source="$REAL_TOP/$dir/$i"
42
43 if [[ -e "$target" ]]; then
44 if [[ ! -d "$source" || ! -d "$target" ]]; then
45 fail "Trying to symlink $dir twice"
46 fi
47 else
48 ln -s "$REAL_TOP/$dir/$i" "$MOCK_TOP/$dir/$i";
49 fi
50 done
51}
52
53function setup_bazel() {
54 copy_directory build/bazel
55
56 symlink_directory prebuilts/bazel
57 symlink_directory prebuilts/jdk
58
59 symlink_file WORKSPACE
60 symlink_file tools/bazel
61}
62
63function setup() {
64 if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
65 MOCK_TOP="$HARDWIRED_MOCK_TOP"
66 rm -fr "$MOCK_TOP"
67 mkdir -p "$MOCK_TOP"
68 else
69 MOCK_TOP=$(mktemp -t -d st.XXXXX)
70 trap 'echo cd / && echo rm -fr "$MOCK_TOP"' EXIT
71 fi
72
73 echo "Test case: ${FUNCNAME[1]}, mock top path: $MOCK_TOP"
74 cd "$MOCK_TOP"
75
76 copy_directory build/blueprint
77 copy_directory build/soong
78
79 symlink_directory prebuilts/go
80 symlink_directory prebuilts/build-tools
81 symlink_directory external/golang-protobuf
82
83 touch "$MOCK_TOP/Android.bp"
84
85 export ALLOW_MISSING_DEPENDENCIES=true
86
87 mkdir -p out/soong
88 # This is necessary because the empty soong.variables file written to satisfy
89 # Ninja would contain "BootJars: {}" instead of "BootJars: []" which cannot
90 # be parsed back
91 # TODO(b/182965747): Fix this.
92 cat > out/soong/soong.variables <<'EOF'
93{
94 "BuildNumberFile": "build_number.txt",
95 "Platform_version_name": "S",
96 "Platform_sdk_version": 30,
97 "Platform_sdk_codename": "S",
98 "Platform_sdk_final": false,
99 "Platform_version_active_codenames": [
100 "S"
101 ],
102 "Platform_vndk_version": "S",
103 "DeviceName": "generic_arm64",
104 "DeviceArch": "arm64",
105 "DeviceArchVariant": "armv8-a",
106 "DeviceCpuVariant": "generic",
107 "DeviceAbi": [
108 "arm64-v8a"
109 ],
110 "DeviceSecondaryArch": "arm",
111 "DeviceSecondaryArchVariant": "armv8-a",
112 "DeviceSecondaryCpuVariant": "generic",
113 "DeviceSecondaryAbi": [
114 "armeabi-v7a",
115 "armeabi"
116 ],
117 "HostArch": "x86_64",
118 "HostSecondaryArch": "x86",
119 "CrossHost": "windows",
120 "CrossHostArch": "x86",
121 "CrossHostSecondaryArch": "x86_64",
122 "AAPTCharacteristics": "nosdcard",
123 "AAPTConfig": [
124 "normal",
125 "large",
126 "xlarge",
127 "hdpi",
128 "xhdpi",
129 "xxhdpi"
130 ],
131 "AAPTPreferredConfig": "xhdpi",
132 "AAPTPrebuiltDPI": [
133 "xhdpi",
134 "xxhdpi"
135 ],
136 "Malloc_not_svelte": true,
137 "Malloc_zero_contents": true,
138 "Malloc_pattern_fill_contents": false,
139 "Safestack": false,
140 "BootJars": [],
141 "UpdatableBootJars": [],
142 "Native_coverage": null
143}
144EOF
145}
146
147function run_soong() {
148 build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests
149}
150
151function test_smoke {
152 setup
153 run_soong
154}
155
156function test_bazel_smoke {
157 setup
158 setup_bazel
159
160 tools/bazel info
161
162}
163function test_null_build() {
164 setup
165 run_soong
166 local bootstrap_mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
167 local output_mtime1=$(stat -c "%y" out/soong/build.ninja)
168 run_soong
169 local bootstrap_mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
170 local output_mtime2=$(stat -c "%y" out/soong/build.ninja)
171
172 if [[ "$bootstrap_mtime1" == "$bootstrap_mtime2" ]]; then
173 # Bootstrapping is always done. It doesn't take a measurable amount of time.
174 fail "Bootstrap Ninja file did not change on null build"
175 fi
176
177 if [[ "$output_mtime1" != "$output_mtime2" ]]; then
178 fail "Output Ninja file changed on null build"
179 fi
180}
181
182function test_soong_build_rebuilt_if_blueprint_changes() {
183 setup
184 run_soong
185 local mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
186
187 sed -i 's/pluginGenSrcCmd/pluginGenSrcCmd2/g' build/blueprint/bootstrap/bootstrap.go
188
189 run_soong
190 local mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
191
192 if [[ "$mtime1" == "$mtime2" ]]; then
193 fail "Bootstrap Ninja file did not change"
194 fi
195}
196
197function test_change_android_bp() {
198 setup
199 mkdir -p a
200 cat > a/Android.bp <<'EOF'
201python_binary_host {
202 name: "my_little_binary_host",
203 srcs: ["my_little_binary_host.py"]
204}
205EOF
206 touch a/my_little_binary_host.py
207 run_soong
208
209 grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja || fail "module not found"
210
211 cat > a/Android.bp <<'EOF'
212python_binary_host {
213 name: "my_great_binary_host",
214 srcs: ["my_great_binary_host.py"]
215}
216EOF
217 touch a/my_great_binary_host.py
218 run_soong
219
220 grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja && fail "old module found"
221 grep -q "^# Module:.*my_great_binary_host" out/soong/build.ninja || fail "new module not found"
222}
223
224
225function test_add_android_bp() {
226 setup
227 run_soong
228 local mtime1=$(stat -c "%y" out/soong/build.ninja)
229
230 mkdir -p a
231 cat > a/Android.bp <<'EOF'
232python_binary_host {
233 name: "my_little_binary_host",
234 srcs: ["my_little_binary_host.py"]
235}
236EOF
237 touch a/my_little_binary_host.py
238 run_soong
239
240 local mtime2=$(stat -c "%y" out/soong/build.ninja)
241 if [[ "$mtime1" == "$mtime2" ]]; then
242 fail "Output Ninja file did not change"
243 fi
244
245 grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "New module not in output"
246
247 run_soong
248}
249
250function test_delete_android_bp() {
251 setup
252 mkdir -p a
253 cat > a/Android.bp <<'EOF'
254python_binary_host {
255 name: "my_little_binary_host",
256 srcs: ["my_little_binary_host.py"]
257}
258EOF
259 touch a/my_little_binary_host.py
260 run_soong
261
262 grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "Module not in output"
263
264 rm a/Android.bp
265 run_soong
266
267 grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja && fail "Old module in output"
268}
269
270function test_add_file_to_glob() {
271 setup
272
273 mkdir -p a
274 cat > a/Android.bp <<'EOF'
275python_binary_host {
276 name: "my_little_binary_host",
277 srcs: ["*.py"],
278}
279EOF
280 touch a/my_little_binary_host.py
281 run_soong
282 local mtime1=$(stat -c "%y" out/soong/build.ninja)
283
284 touch a/my_little_library.py
285 run_soong
286
287 local mtime2=$(stat -c "%y" out/soong/build.ninja)
288 if [[ "$mtime1" == "$mtime2" ]]; then
289 fail "Output Ninja file did not change"
290 fi
291
292 grep -q my_little_library.py out/soong/build.ninja || fail "new file is not in output"
293}
294
295function test_add_file_to_soong_build() {
296 setup
297 run_soong
298 local mtime1=$(stat -c "%y" out/soong/build.ninja)
299
300 mkdir -p a
301 cat > a/Android.bp <<'EOF'
302bootstrap_go_package {
303 name: "picard-soong-rules",
304 pkgPath: "android/soong/picard",
305 deps: [
306 "blueprint",
307 "soong",
308 "soong-android",
309 ],
310 srcs: [
311 "picard.go",
312 ],
313 pluginFor: ["soong_build"],
314}
315EOF
316
317 cat > a/picard.go <<'EOF'
318package picard
319
320import (
321 "android/soong/android"
322 "github.com/google/blueprint"
323)
324
325var (
326 pctx = android.NewPackageContext("picard")
327)
328
329func init() {
330 android.RegisterSingletonType("picard", PicardSingleton)
331}
332
333func PicardSingleton() android.Singleton {
334 return &picardSingleton{}
335}
336
337type picardSingleton struct{}
338
339func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
340 picardRule := ctx.Rule(pctx, "picard",
341 blueprint.RuleParams{
342 Command: "echo Make it so. > ${out}",
343 CommandDeps: []string{},
344 Description: "Something quotable",
345 })
346
347 outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
348 var deps android.Paths
349
350 ctx.Build(pctx, android.BuildParams{
351 Rule: picardRule,
352 Output: outputFile,
353 Inputs: deps,
354 })
355}
356
357EOF
358
359 run_soong
360 local mtime2=$(stat -c "%y" out/soong/build.ninja)
361 if [[ "$mtime1" == "$mtime2" ]]; then
362 fail "Output Ninja file did not change"
363 fi
364
365 grep -q "Make it so" out/soong/build.ninja || fail "New action not present"
366}
367
368test_bazel_smoke
369test_smoke
370test_null_build
371test_soong_build_rebuilt_if_blueprint_changes
372test_add_file_to_glob
373test_add_android_bp
374test_change_android_bp
375test_delete_android_bp
376test_add_file_to_soong_build