lto_test.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // Copyright 2021 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package cc
  15. import (
  16. "strings"
  17. "testing"
  18. "android/soong/android"
  19. "github.com/google/blueprint"
  20. )
  21. var NoGlobalThinLTOPreparer = android.GroupFixturePreparers(
  22. prepareForCcTest,
  23. android.FixtureModifyEnv(func(env map[string]string) {
  24. env["GLOBAL_THINLTO"] = "false"
  25. }))
  26. func TestThinLtoDeps(t *testing.T) {
  27. t.Parallel()
  28. bp := `
  29. cc_library_shared {
  30. name: "lto_enabled",
  31. srcs: ["src.c"],
  32. static_libs: ["foo", "lib_never_lto"],
  33. shared_libs: ["bar"],
  34. lto: {
  35. thin: true,
  36. }
  37. }
  38. cc_library_static {
  39. name: "foo",
  40. static_libs: ["baz"],
  41. }
  42. cc_library_shared {
  43. name: "bar",
  44. static_libs: ["qux"],
  45. }
  46. cc_library_static {
  47. name: "baz",
  48. }
  49. cc_library_static {
  50. name: "qux",
  51. }
  52. cc_library_static {
  53. name: "lib_never_lto",
  54. lto: {
  55. never: true,
  56. },
  57. }
  58. `
  59. result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
  60. libLto := result.ModuleForTests("lto_enabled", "android_arm64_armv8-a_shared").Module()
  61. hasDep := func(m android.Module, wantDep android.Module) bool {
  62. var found bool
  63. result.VisitDirectDeps(m, func(dep blueprint.Module) {
  64. if dep == wantDep {
  65. found = true
  66. }
  67. })
  68. return found
  69. }
  70. libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static_lto-thin").Module()
  71. if !hasDep(libLto, libFoo) {
  72. t.Errorf("'lto_enabled' missing dependency on thin lto variant of 'foo'")
  73. }
  74. libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin").Module()
  75. if !hasDep(libFoo, libBaz) {
  76. t.Errorf("'foo' missing dependency on thin lto variant of transitive dep 'baz'")
  77. }
  78. libNeverLto := result.ModuleForTests("lib_never_lto", "android_arm64_armv8-a_static_lto-thin").Module()
  79. if !hasDep(libLto, libNeverLto) {
  80. t.Errorf("'lto_enabled' missing dependency on NO-thin lto variant of 'lib_never_lto'")
  81. }
  82. libBar := result.ModuleForTests("bar", "android_arm64_armv8-a_shared").Module()
  83. if !hasDep(libLto, libBar) {
  84. t.Errorf("'lto_enabled' missing dependency on non-thin lto variant of 'bar'")
  85. }
  86. barVariants := result.ModuleVariantsForTests("bar")
  87. for _, v := range barVariants {
  88. if strings.Contains(v, "lto-thin") {
  89. t.Errorf("Expected variants for 'bar' to not contain 'lto-thin', but found %q", v)
  90. }
  91. }
  92. quxVariants := result.ModuleVariantsForTests("qux")
  93. for _, v := range quxVariants {
  94. if strings.Contains(v, "lto-thin") {
  95. t.Errorf("Expected variants for 'qux' to not contain 'lto-thin', but found %q", v)
  96. }
  97. }
  98. }
  99. func TestThinLtoOnlyOnStaticDep(t *testing.T) {
  100. t.Parallel()
  101. bp := `
  102. cc_library_shared {
  103. name: "root",
  104. srcs: ["src.c"],
  105. static_libs: ["foo"],
  106. }
  107. cc_library_shared {
  108. name: "root_no_lto",
  109. srcs: ["src.c"],
  110. static_libs: ["foo"],
  111. lto: {
  112. never: true,
  113. }
  114. }
  115. cc_library_static {
  116. name: "foo",
  117. srcs: ["foo.c"],
  118. static_libs: ["baz"],
  119. lto: {
  120. thin: true,
  121. }
  122. }
  123. cc_library_static {
  124. name: "baz",
  125. srcs: ["baz.c"],
  126. }
  127. `
  128. result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
  129. libRoot := result.ModuleForTests("root", "android_arm64_armv8-a_shared").Module()
  130. libRootLtoNever := result.ModuleForTests("root_no_lto", "android_arm64_armv8-a_shared").Module()
  131. hasDep := func(m android.Module, wantDep android.Module) bool {
  132. var found bool
  133. result.VisitDirectDeps(m, func(dep blueprint.Module) {
  134. if dep == wantDep {
  135. found = true
  136. }
  137. })
  138. return found
  139. }
  140. libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static")
  141. if !hasDep(libRoot, libFoo.Module()) {
  142. t.Errorf("'root' missing dependency on thin lto variant of 'foo'")
  143. }
  144. if !hasDep(libRootLtoNever, libFoo.Module()) {
  145. t.Errorf("'root_no_lto' missing dependency on thin lto variant of 'foo'")
  146. }
  147. libFooCFlags := libFoo.Rule("cc").Args["cFlags"]
  148. if w := "-flto=thin -fsplit-lto-unit"; !strings.Contains(libFooCFlags, w) {
  149. t.Errorf("'foo' expected to have flags %q, but got %q", w, libFooCFlags)
  150. }
  151. libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin")
  152. if !hasDep(libFoo.Module(), libBaz.Module()) {
  153. t.Errorf("'foo' missing dependency on thin lto variant of transitive dep 'baz'")
  154. }
  155. libBazCFlags := libFoo.Rule("cc").Args["cFlags"]
  156. if w := "-flto=thin -fsplit-lto-unit"; !strings.Contains(libBazCFlags, w) {
  157. t.Errorf("'baz' expected to have flags %q, but got %q", w, libFooCFlags)
  158. }
  159. }
  160. func TestLtoDisabledButEnabledForArch(t *testing.T) {
  161. t.Parallel()
  162. bp := `
  163. cc_library {
  164. name: "libfoo",
  165. srcs: ["foo.c"],
  166. lto: {
  167. never: true,
  168. },
  169. target: {
  170. android_arm: {
  171. lto: {
  172. never: false,
  173. thin: true,
  174. },
  175. },
  176. },
  177. }`
  178. result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
  179. libFooWithLto := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
  180. libFooWithoutLto := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld")
  181. android.AssertStringDoesContain(t, "missing flag for LTO in variant that expects it",
  182. libFooWithLto.Args["ldFlags"], "-flto=thin")
  183. android.AssertStringDoesNotContain(t, "got flag for LTO in variant that doesn't expect it",
  184. libFooWithoutLto.Args["ldFlags"], "-flto=thin")
  185. }
  186. func TestLtoDoesNotPropagateToRuntimeLibs(t *testing.T) {
  187. t.Parallel()
  188. bp := `
  189. cc_library {
  190. name: "runtime_libbar",
  191. srcs: ["bar.c"],
  192. }
  193. cc_library {
  194. name: "libfoo",
  195. srcs: ["foo.c"],
  196. runtime_libs: ["runtime_libbar"],
  197. lto: {
  198. thin: true,
  199. },
  200. }`
  201. result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
  202. libFoo := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
  203. libBar := result.ModuleForTests("runtime_libbar", "android_arm_armv7-a-neon_shared").Rule("ld")
  204. android.AssertStringDoesContain(t, "missing flag for LTO in LTO enabled library",
  205. libFoo.Args["ldFlags"], "-flto=thin")
  206. android.AssertStringDoesNotContain(t, "got flag for LTO in runtime_lib",
  207. libBar.Args["ldFlags"], "-flto=thin")
  208. }