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 15package cc 16 17import ( 18 "strings" 19 "testing" 20 21 "android/soong/android" 22 23 "github.com/google/blueprint" 24) 25 26func 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 60 result := android.GroupFixturePreparers( 61 prepareForCcTest, 62 ).RunTestWithBp(t, bp) 63 64 libLto := result.ModuleForTests("lto_enabled", "android_arm64_armv8-a_shared").Module() 65 66 hasDep := func(m android.Module, wantDep android.Module) bool { 67 var found bool 68 result.VisitDirectDeps(m, func(dep blueprint.Module) { 69 if dep == wantDep { 70 found = true 71 } 72 }) 73 return found 74 } 75 76 libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static_lto-thin").Module() 77 if !hasDep(libLto, libFoo) { 78 t.Errorf("'lto_enabled' missing dependency on thin lto variant of 'foo'") 79 } 80 81 libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin").Module() 82 if !hasDep(libFoo, libBaz) { 83 t.Errorf("'foo' missing dependency on thin lto variant of transitive dep 'baz'") 84 } 85 86 libNeverLto := result.ModuleForTests("lib_never_lto", "android_arm64_armv8-a_static_lto-thin").Module() 87 if !hasDep(libLto, libNeverLto) { 88 t.Errorf("'lto_enabled' missing dependency on NO-thin lto variant of 'lib_never_lto'") 89 } 90 91 libBar := result.ModuleForTests("bar", "android_arm64_armv8-a_shared").Module() 92 if !hasDep(libLto, libBar) { 93 t.Errorf("'lto_enabled' missing dependency on non-thin lto variant of 'bar'") 94 } 95 96 barVariants := result.ModuleVariantsForTests("bar") 97 for _, v := range barVariants { 98 if strings.Contains(v, "lto-thin") { 99 t.Errorf("Expected variants for 'bar' to not contain 'lto-thin', but found %q", v) 100 } 101 } 102 quxVariants := result.ModuleVariantsForTests("qux") 103 for _, v := range quxVariants { 104 if strings.Contains(v, "lto-thin") { 105 t.Errorf("Expected variants for 'qux' to not contain 'lto-thin', but found %q", v) 106 } 107 } 108} 109 110func TestThinLtoOnlyOnStaticDep(t *testing.T) { 111 t.Parallel() 112 bp := ` 113 cc_library_shared { 114 name: "root", 115 srcs: ["src.c"], 116 static_libs: ["foo"], 117 } 118 cc_library_shared { 119 name: "root_no_lto", 120 srcs: ["src.c"], 121 static_libs: ["foo"], 122 lto: { 123 never: true, 124 } 125 } 126 cc_library_static { 127 name: "foo", 128 srcs: ["foo.c"], 129 static_libs: ["baz"], 130 lto: { 131 thin: true, 132 } 133 } 134 cc_library_static { 135 name: "baz", 136 srcs: ["baz.c"], 137 } 138` 139 140 result := android.GroupFixturePreparers( 141 prepareForCcTest, 142 ).RunTestWithBp(t, bp) 143 144 libRoot := result.ModuleForTests("root", "android_arm64_armv8-a_shared").Module() 145 libRootLtoNever := result.ModuleForTests("root_no_lto", "android_arm64_armv8-a_shared").Module() 146 147 hasDep := func(m android.Module, wantDep android.Module) bool { 148 var found bool 149 result.VisitDirectDeps(m, func(dep blueprint.Module) { 150 if dep == wantDep { 151 found = true 152 } 153 }) 154 return found 155 } 156 157 libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static") 158 if !hasDep(libRoot, libFoo.Module()) { 159 t.Errorf("'root' missing dependency on thin lto variant of 'foo'") 160 } 161 162 if !hasDep(libRootLtoNever, libFoo.Module()) { 163 t.Errorf("'root_no_lto' missing dependency on thin lto variant of 'foo'") 164 } 165 166 libFooCFlags := libFoo.Rule("cc").Args["cFlags"] 167 if w := "-flto=thin -fsplit-lto-unit"; !strings.Contains(libFooCFlags, w) { 168 t.Errorf("'foo' expected to have flags %q, but got %q", w, libFooCFlags) 169 } 170 171 libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin") 172 if !hasDep(libFoo.Module(), libBaz.Module()) { 173 t.Errorf("'foo' missing dependency on thin lto variant of transitive dep 'baz'") 174 } 175 176 libBazCFlags := libFoo.Rule("cc").Args["cFlags"] 177 if w := "-flto=thin -fsplit-lto-unit"; !strings.Contains(libBazCFlags, w) { 178 t.Errorf("'baz' expected to have flags %q, but got %q", w, libFooCFlags) 179 } 180} 181 182func TestLtoDisabledButEnabledForArch(t *testing.T) { 183 t.Parallel() 184 bp := ` 185 cc_library { 186 name: "libfoo", 187 srcs: ["foo.c"], 188 lto: { 189 never: true, 190 }, 191 target: { 192 android_arm: { 193 lto: { 194 never: false, 195 thin: true, 196 }, 197 }, 198 }, 199 }` 200 result := android.GroupFixturePreparers( 201 prepareForCcTest, 202 ).RunTestWithBp(t, bp) 203 204 libFooWithLto := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") 205 libFooWithoutLto := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld") 206 207 android.AssertStringDoesContain(t, "missing flag for LTO in variant that expects it", 208 libFooWithLto.Args["ldFlags"], "-flto=thin") 209 android.AssertStringDoesNotContain(t, "got flag for LTO in variant that doesn't expect it", 210 libFooWithoutLto.Args["ldFlags"], "-flto=thin") 211} 212 213func TestLtoDoesNotPropagateToRuntimeLibs(t *testing.T) { 214 t.Parallel() 215 bp := ` 216 cc_library { 217 name: "runtime_libbar", 218 srcs: ["bar.c"], 219 } 220 221 cc_library { 222 name: "libfoo", 223 srcs: ["foo.c"], 224 runtime_libs: ["runtime_libbar"], 225 lto: { 226 thin: true, 227 }, 228 }` 229 230 result := android.GroupFixturePreparers( 231 prepareForCcTest, 232 ).RunTestWithBp(t, bp) 233 234 libFoo := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") 235 libBar := result.ModuleForTests("runtime_libbar", "android_arm_armv7-a-neon_shared").Rule("ld") 236 237 android.AssertStringDoesContain(t, "missing flag for LTO in LTO enabled library", 238 libFoo.Args["ldFlags"], "-flto=thin") 239 android.AssertStringDoesNotContain(t, "got flag for LTO in runtime_lib", 240 libBar.Args["ldFlags"], "-flto=thin") 241} 242