2022-09-16 18:39:27 +02:00
|
|
|
// Copyright 2021 Google Inc. All rights reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package cc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
2023-02-07 20:46:51 +01:00
|
|
|
"android/soong/android"
|
|
|
|
|
2022-09-16 18:39:27 +02:00
|
|
|
"github.com/google/blueprint"
|
|
|
|
)
|
|
|
|
|
2023-10-05 07:03:42 +02:00
|
|
|
var LTOPreparer = android.GroupFixturePreparers(
|
2023-06-12 08:50:26 +02:00
|
|
|
prepareForCcTest,
|
2023-10-05 07:03:42 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func hasDep(result *android.TestResult, m android.Module, wantDep android.Module) bool {
|
|
|
|
var found bool
|
|
|
|
result.VisitDirectDeps(m, func(dep blueprint.Module) {
|
|
|
|
if dep == wantDep {
|
|
|
|
found = true
|
|
|
|
}
|
|
|
|
})
|
|
|
|
return found
|
|
|
|
}
|
2023-06-12 08:50:26 +02:00
|
|
|
|
2022-09-16 18:39:27 +02:00
|
|
|
func TestThinLtoDeps(t *testing.T) {
|
2022-10-31 21:27:38 +01:00
|
|
|
t.Parallel()
|
2022-09-16 18:39:27 +02:00
|
|
|
bp := `
|
2022-10-31 19:44:46 +01:00
|
|
|
cc_library_shared {
|
2022-09-16 18:39:27 +02:00
|
|
|
name: "lto_enabled",
|
|
|
|
srcs: ["src.c"],
|
2022-10-31 19:44:46 +01:00
|
|
|
static_libs: ["foo", "lib_never_lto"],
|
2022-09-16 18:39:27 +02:00
|
|
|
shared_libs: ["bar"],
|
|
|
|
}
|
2022-10-31 19:44:46 +01:00
|
|
|
cc_library_static {
|
2022-09-16 18:39:27 +02:00
|
|
|
name: "foo",
|
|
|
|
static_libs: ["baz"],
|
|
|
|
}
|
2022-10-31 19:44:46 +01:00
|
|
|
cc_library_shared {
|
2022-09-16 18:39:27 +02:00
|
|
|
name: "bar",
|
|
|
|
static_libs: ["qux"],
|
|
|
|
}
|
2022-10-31 19:44:46 +01:00
|
|
|
cc_library_static {
|
2022-09-16 18:39:27 +02:00
|
|
|
name: "baz",
|
|
|
|
}
|
2022-10-31 19:44:46 +01:00
|
|
|
cc_library_static {
|
2022-09-16 18:39:27 +02:00
|
|
|
name: "qux",
|
|
|
|
}
|
2022-10-31 19:44:46 +01:00
|
|
|
cc_library_static {
|
|
|
|
name: "lib_never_lto",
|
|
|
|
lto: {
|
|
|
|
never: true,
|
|
|
|
},
|
|
|
|
}
|
2022-09-16 18:39:27 +02:00
|
|
|
`
|
|
|
|
|
2023-10-05 07:03:42 +02:00
|
|
|
result := LTOPreparer.RunTestWithBp(t, bp)
|
2022-09-16 18:39:27 +02:00
|
|
|
|
|
|
|
libLto := result.ModuleForTests("lto_enabled", "android_arm64_armv8-a_shared").Module()
|
|
|
|
|
2023-10-05 07:03:42 +02:00
|
|
|
libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static").Module()
|
|
|
|
if !hasDep(result, libLto, libFoo) {
|
|
|
|
t.Errorf("'lto_enabled' missing dependency on the default variant of 'foo'")
|
2022-09-16 18:39:27 +02:00
|
|
|
}
|
|
|
|
|
2023-10-05 07:03:42 +02:00
|
|
|
libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static").Module()
|
|
|
|
if !hasDep(result, libFoo, libBaz) {
|
|
|
|
t.Errorf("'foo' missing dependency on the default variant of transitive dep 'baz'")
|
2022-10-31 19:44:46 +01:00
|
|
|
}
|
|
|
|
|
2023-10-05 07:03:42 +02:00
|
|
|
libNeverLto := result.ModuleForTests("lib_never_lto", "android_arm64_armv8-a_static").Module()
|
|
|
|
if !hasDep(result, libLto, libNeverLto) {
|
|
|
|
t.Errorf("'lto_enabled' missing dependency on the default variant of 'lib_never_lto'")
|
2022-10-31 19:44:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
libBar := result.ModuleForTests("bar", "android_arm64_armv8-a_shared").Module()
|
2023-10-05 07:03:42 +02:00
|
|
|
if !hasDep(result, libLto, libBar) {
|
|
|
|
t.Errorf("'lto_enabled' missing dependency on the default variant of 'bar'")
|
2022-09-16 18:39:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
barVariants := result.ModuleVariantsForTests("bar")
|
|
|
|
for _, v := range barVariants {
|
2023-10-05 07:03:42 +02:00
|
|
|
if strings.Contains(v, "lto-none") {
|
|
|
|
t.Errorf("Expected variants for 'bar' to not contain 'lto-none', but found %q", v)
|
2022-09-16 18:39:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
quxVariants := result.ModuleVariantsForTests("qux")
|
|
|
|
for _, v := range quxVariants {
|
2023-10-05 07:03:42 +02:00
|
|
|
if strings.Contains(v, "lto-none") {
|
|
|
|
t.Errorf("Expected variants for 'qux' to not contain 'lto-none', but found %q", v)
|
2022-09-16 18:39:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-10-31 19:44:46 +01:00
|
|
|
|
|
|
|
func TestThinLtoOnlyOnStaticDep(t *testing.T) {
|
2022-10-31 21:27:38 +01:00
|
|
|
t.Parallel()
|
2022-10-31 19:44:46 +01:00
|
|
|
bp := `
|
|
|
|
cc_library_shared {
|
|
|
|
name: "root",
|
|
|
|
srcs: ["src.c"],
|
|
|
|
static_libs: ["foo"],
|
|
|
|
}
|
|
|
|
cc_library_shared {
|
|
|
|
name: "root_no_lto",
|
|
|
|
srcs: ["src.c"],
|
|
|
|
static_libs: ["foo"],
|
|
|
|
lto: {
|
|
|
|
never: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cc_library_static {
|
|
|
|
name: "foo",
|
|
|
|
srcs: ["foo.c"],
|
|
|
|
static_libs: ["baz"],
|
|
|
|
lto: {
|
|
|
|
thin: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cc_library_static {
|
|
|
|
name: "baz",
|
|
|
|
srcs: ["baz.c"],
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
2023-10-05 07:03:42 +02:00
|
|
|
result := LTOPreparer.RunTestWithBp(t, bp)
|
2022-10-31 19:44:46 +01:00
|
|
|
|
|
|
|
libRoot := result.ModuleForTests("root", "android_arm64_armv8-a_shared").Module()
|
|
|
|
libRootLtoNever := result.ModuleForTests("root_no_lto", "android_arm64_armv8-a_shared").Module()
|
|
|
|
|
|
|
|
libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static")
|
2023-10-05 07:03:42 +02:00
|
|
|
if !hasDep(result, libRoot, libFoo.Module()) {
|
|
|
|
t.Errorf("'root' missing dependency on the default variant of 'foo'")
|
2022-10-31 19:44:46 +01:00
|
|
|
}
|
|
|
|
|
2023-10-05 07:03:42 +02:00
|
|
|
if !hasDep(result, libRootLtoNever, libFoo.Module()) {
|
|
|
|
t.Errorf("'root_no_lto' missing dependency on the default variant of 'foo'")
|
2022-10-31 19:44:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
libFooCFlags := libFoo.Rule("cc").Args["cFlags"]
|
|
|
|
if w := "-flto=thin -fsplit-lto-unit"; !strings.Contains(libFooCFlags, w) {
|
|
|
|
t.Errorf("'foo' expected to have flags %q, but got %q", w, libFooCFlags)
|
|
|
|
}
|
|
|
|
|
2023-10-05 07:03:42 +02:00
|
|
|
libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static")
|
|
|
|
if !hasDep(result, libFoo.Module(), libBaz.Module()) {
|
|
|
|
t.Errorf("'foo' missing dependency on the default variant of transitive dep 'baz'")
|
2022-10-31 19:44:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
libBazCFlags := libFoo.Rule("cc").Args["cFlags"]
|
|
|
|
if w := "-flto=thin -fsplit-lto-unit"; !strings.Contains(libBazCFlags, w) {
|
|
|
|
t.Errorf("'baz' expected to have flags %q, but got %q", w, libFooCFlags)
|
|
|
|
}
|
|
|
|
}
|
2023-02-07 20:46:51 +01:00
|
|
|
|
|
|
|
func TestLtoDisabledButEnabledForArch(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
bp := `
|
|
|
|
cc_library {
|
|
|
|
name: "libfoo",
|
|
|
|
srcs: ["foo.c"],
|
|
|
|
lto: {
|
|
|
|
never: true,
|
|
|
|
},
|
|
|
|
target: {
|
2023-02-09 20:01:31 +01:00
|
|
|
android_arm: {
|
2023-02-07 20:46:51 +01:00
|
|
|
lto: {
|
|
|
|
never: false,
|
|
|
|
thin: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}`
|
2023-10-05 07:03:42 +02:00
|
|
|
result := LTOPreparer.RunTestWithBp(t, bp)
|
2023-02-07 20:46:51 +01:00
|
|
|
|
2023-02-09 20:01:31 +01:00
|
|
|
libFooWithLto := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
|
|
|
|
libFooWithoutLto := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld")
|
2023-02-07 20:46:51 +01:00
|
|
|
|
|
|
|
android.AssertStringDoesContain(t, "missing flag for LTO in variant that expects it",
|
|
|
|
libFooWithLto.Args["ldFlags"], "-flto=thin")
|
|
|
|
android.AssertStringDoesNotContain(t, "got flag for LTO in variant that doesn't expect it",
|
|
|
|
libFooWithoutLto.Args["ldFlags"], "-flto=thin")
|
|
|
|
}
|
2023-02-10 21:29:20 +01:00
|
|
|
|
|
|
|
func TestLtoDoesNotPropagateToRuntimeLibs(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
bp := `
|
|
|
|
cc_library {
|
|
|
|
name: "runtime_libbar",
|
|
|
|
srcs: ["bar.c"],
|
|
|
|
}
|
|
|
|
|
|
|
|
cc_library {
|
|
|
|
name: "libfoo",
|
|
|
|
srcs: ["foo.c"],
|
|
|
|
runtime_libs: ["runtime_libbar"],
|
|
|
|
lto: {
|
|
|
|
thin: true,
|
|
|
|
},
|
|
|
|
}`
|
|
|
|
|
2023-10-05 07:03:42 +02:00
|
|
|
result := LTOPreparer.RunTestWithBp(t, bp)
|
2023-02-10 21:29:20 +01:00
|
|
|
|
|
|
|
libFoo := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
|
|
|
|
libBar := result.ModuleForTests("runtime_libbar", "android_arm_armv7-a-neon_shared").Rule("ld")
|
|
|
|
|
|
|
|
android.AssertStringDoesContain(t, "missing flag for LTO in LTO enabled library",
|
|
|
|
libFoo.Args["ldFlags"], "-flto=thin")
|
|
|
|
android.AssertStringDoesNotContain(t, "got flag for LTO in runtime_lib",
|
|
|
|
libBar.Args["ldFlags"], "-flto=thin")
|
|
|
|
}
|