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