bootstrap_test.sh 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. #!/bin/bash -eu
  2. # This test exercises the bootstrapping process of the build system
  3. # in a source tree that only contains enough files for Bazel and Soong to work.
  4. HARDWIRED_MOCK_TOP=
  5. # Uncomment this to be able to view the source tree after a test is run
  6. # HARDWIRED_MOCK_TOP=/tmp/td
  7. REAL_TOP="$(readlink -f "$(dirname "$0")"/../..)"
  8. function fail {
  9. echo ERROR: $1
  10. exit 1
  11. }
  12. function copy_directory() {
  13. local dir="$1"
  14. local parent="$(dirname "$dir")"
  15. mkdir -p "$MOCK_TOP/$parent"
  16. cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
  17. }
  18. function symlink_file() {
  19. local file="$1"
  20. mkdir -p "$MOCK_TOP/$(dirname "$file")"
  21. ln -s "$REAL_TOP/$file" "$MOCK_TOP/$file"
  22. }
  23. function symlink_directory() {
  24. local dir="$1"
  25. mkdir -p "$MOCK_TOP/$dir"
  26. # We need to symlink the contents of the directory individually instead of
  27. # using one symlink for the whole directory because finder.go doesn't follow
  28. # symlinks when looking for Android.bp files
  29. for i in $(ls "$REAL_TOP/$dir"); do
  30. local target="$MOCK_TOP/$dir/$i"
  31. local source="$REAL_TOP/$dir/$i"
  32. if [[ -e "$target" ]]; then
  33. if [[ ! -d "$source" || ! -d "$target" ]]; then
  34. fail "Trying to symlink $dir twice"
  35. fi
  36. else
  37. ln -s "$REAL_TOP/$dir/$i" "$MOCK_TOP/$dir/$i";
  38. fi
  39. done
  40. }
  41. function setup_bazel() {
  42. copy_directory build/bazel
  43. symlink_directory prebuilts/bazel
  44. symlink_directory prebuilts/jdk
  45. symlink_file WORKSPACE
  46. symlink_file tools/bazel
  47. }
  48. function setup() {
  49. if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
  50. MOCK_TOP="$HARDWIRED_MOCK_TOP"
  51. rm -fr "$MOCK_TOP"
  52. mkdir -p "$MOCK_TOP"
  53. else
  54. MOCK_TOP=$(mktemp -t -d st.XXXXX)
  55. trap 'echo cd / && echo rm -fr "$MOCK_TOP"' EXIT
  56. fi
  57. echo "Test case: ${FUNCNAME[1]}, mock top path: $MOCK_TOP"
  58. cd "$MOCK_TOP"
  59. copy_directory build/blueprint
  60. copy_directory build/soong
  61. symlink_directory prebuilts/go
  62. symlink_directory prebuilts/build-tools
  63. symlink_directory external/golang-protobuf
  64. touch "$MOCK_TOP/Android.bp"
  65. export ALLOW_MISSING_DEPENDENCIES=true
  66. mkdir -p out/soong
  67. }
  68. function run_soong() {
  69. build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests
  70. }
  71. function test_smoke {
  72. setup
  73. run_soong
  74. }
  75. function test_bazel_smoke {
  76. setup
  77. setup_bazel
  78. tools/bazel info
  79. }
  80. function test_null_build() {
  81. setup
  82. run_soong
  83. local bootstrap_mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
  84. local output_mtime1=$(stat -c "%y" out/soong/build.ninja)
  85. run_soong
  86. local bootstrap_mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
  87. local output_mtime2=$(stat -c "%y" out/soong/build.ninja)
  88. if [[ "$bootstrap_mtime1" == "$bootstrap_mtime2" ]]; then
  89. # Bootstrapping is always done. It doesn't take a measurable amount of time.
  90. fail "Bootstrap Ninja file did not change on null build"
  91. fi
  92. if [[ "$output_mtime1" != "$output_mtime2" ]]; then
  93. fail "Output Ninja file changed on null build"
  94. fi
  95. }
  96. function test_soong_build_rebuilt_if_blueprint_changes() {
  97. setup
  98. run_soong
  99. local mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
  100. sed -i 's/pluginGenSrcCmd/pluginGenSrcCmd2/g' build/blueprint/bootstrap/bootstrap.go
  101. run_soong
  102. local mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
  103. if [[ "$mtime1" == "$mtime2" ]]; then
  104. fail "Bootstrap Ninja file did not change"
  105. fi
  106. }
  107. function test_change_android_bp() {
  108. setup
  109. mkdir -p a
  110. cat > a/Android.bp <<'EOF'
  111. python_binary_host {
  112. name: "my_little_binary_host",
  113. srcs: ["my_little_binary_host.py"]
  114. }
  115. EOF
  116. touch a/my_little_binary_host.py
  117. run_soong
  118. grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja || fail "module not found"
  119. cat > a/Android.bp <<'EOF'
  120. python_binary_host {
  121. name: "my_great_binary_host",
  122. srcs: ["my_great_binary_host.py"]
  123. }
  124. EOF
  125. touch a/my_great_binary_host.py
  126. run_soong
  127. grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja && fail "old module found"
  128. grep -q "^# Module:.*my_great_binary_host" out/soong/build.ninja || fail "new module not found"
  129. }
  130. function test_add_android_bp() {
  131. setup
  132. run_soong
  133. local mtime1=$(stat -c "%y" out/soong/build.ninja)
  134. mkdir -p a
  135. cat > a/Android.bp <<'EOF'
  136. python_binary_host {
  137. name: "my_little_binary_host",
  138. srcs: ["my_little_binary_host.py"]
  139. }
  140. EOF
  141. touch a/my_little_binary_host.py
  142. run_soong
  143. local mtime2=$(stat -c "%y" out/soong/build.ninja)
  144. if [[ "$mtime1" == "$mtime2" ]]; then
  145. fail "Output Ninja file did not change"
  146. fi
  147. grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "New module not in output"
  148. run_soong
  149. }
  150. function test_delete_android_bp() {
  151. setup
  152. mkdir -p a
  153. cat > a/Android.bp <<'EOF'
  154. python_binary_host {
  155. name: "my_little_binary_host",
  156. srcs: ["my_little_binary_host.py"]
  157. }
  158. EOF
  159. touch a/my_little_binary_host.py
  160. run_soong
  161. grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "Module not in output"
  162. rm a/Android.bp
  163. run_soong
  164. grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja && fail "Old module in output"
  165. }
  166. function test_add_file_to_glob() {
  167. setup
  168. mkdir -p a
  169. cat > a/Android.bp <<'EOF'
  170. python_binary_host {
  171. name: "my_little_binary_host",
  172. srcs: ["*.py"],
  173. }
  174. EOF
  175. touch a/my_little_binary_host.py
  176. run_soong
  177. local mtime1=$(stat -c "%y" out/soong/build.ninja)
  178. touch a/my_little_library.py
  179. run_soong
  180. local mtime2=$(stat -c "%y" out/soong/build.ninja)
  181. if [[ "$mtime1" == "$mtime2" ]]; then
  182. fail "Output Ninja file did not change"
  183. fi
  184. grep -q my_little_library.py out/soong/build.ninja || fail "new file is not in output"
  185. }
  186. function test_add_file_to_soong_build() {
  187. setup
  188. run_soong
  189. local mtime1=$(stat -c "%y" out/soong/build.ninja)
  190. mkdir -p a
  191. cat > a/Android.bp <<'EOF'
  192. bootstrap_go_package {
  193. name: "picard-soong-rules",
  194. pkgPath: "android/soong/picard",
  195. deps: [
  196. "blueprint",
  197. "soong",
  198. "soong-android",
  199. ],
  200. srcs: [
  201. "picard.go",
  202. ],
  203. pluginFor: ["soong_build"],
  204. }
  205. EOF
  206. cat > a/picard.go <<'EOF'
  207. package picard
  208. import (
  209. "android/soong/android"
  210. "github.com/google/blueprint"
  211. )
  212. var (
  213. pctx = android.NewPackageContext("picard")
  214. )
  215. func init() {
  216. android.RegisterSingletonType("picard", PicardSingleton)
  217. }
  218. func PicardSingleton() android.Singleton {
  219. return &picardSingleton{}
  220. }
  221. type picardSingleton struct{}
  222. func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
  223. picardRule := ctx.Rule(pctx, "picard",
  224. blueprint.RuleParams{
  225. Command: "echo Make it so. > ${out}",
  226. CommandDeps: []string{},
  227. Description: "Something quotable",
  228. })
  229. outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
  230. var deps android.Paths
  231. ctx.Build(pctx, android.BuildParams{
  232. Rule: picardRule,
  233. Output: outputFile,
  234. Inputs: deps,
  235. })
  236. }
  237. EOF
  238. run_soong
  239. local mtime2=$(stat -c "%y" out/soong/build.ninja)
  240. if [[ "$mtime1" == "$mtime2" ]]; then
  241. fail "Output Ninja file did not change"
  242. fi
  243. grep -q "Make it so" out/soong/build.ninja || fail "New action not present"
  244. }
  245. test_bazel_smoke
  246. test_smoke
  247. test_null_build
  248. test_soong_build_rebuilt_if_blueprint_changes
  249. test_add_file_to_glob
  250. test_add_android_bp
  251. test_change_android_bp
  252. test_delete_android_bp
  253. test_add_file_to_soong_build