|  | // Copyright 2023 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" | 
|  |  | 
|  | "android/soong/android" | 
|  | ) | 
|  |  | 
|  | func TestOrderfileProfileSharedLibrary(t *testing.T) { | 
|  | t.Parallel() | 
|  | bp := ` | 
|  | cc_library_shared { | 
|  | name: "libTest", | 
|  | srcs: ["test.c"], | 
|  | orderfile : { | 
|  | instrumentation: true, | 
|  | load_order_file: false, | 
|  | order_file_path: "", | 
|  | }, | 
|  | } | 
|  | ` | 
|  |  | 
|  | result := android.GroupFixturePreparers( | 
|  | prepareForCcTest, | 
|  | ).RunTestWithBp(t, bp) | 
|  |  | 
|  | expectedCFlag := "-forder-file-instrumentation" | 
|  |  | 
|  | libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") | 
|  |  | 
|  | // Check cFlags of orderfile-enabled module | 
|  | cFlags := libTest.Rule("cc").Args["cFlags"] | 
|  | if !strings.Contains(cFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags) | 
|  | } | 
|  |  | 
|  | // Check ldFlags of orderfile-enabled module | 
|  | ldFlags := libTest.Rule("ld").Args["ldFlags"] | 
|  | if !strings.Contains(ldFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestOrderfileLoadSharedLibrary(t *testing.T) { | 
|  | t.Parallel() | 
|  | bp := ` | 
|  | cc_library_shared { | 
|  | name: "libTest", | 
|  | srcs: ["test.c"], | 
|  | orderfile : { | 
|  | instrumentation: true, | 
|  | load_order_file: true, | 
|  | order_file_path: "libTest.orderfile", | 
|  | }, | 
|  | } | 
|  | ` | 
|  |  | 
|  | result := android.GroupFixturePreparers( | 
|  | prepareForCcTest, | 
|  | android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/libTest.orderfile", "TEST"), | 
|  | ).RunTestWithBp(t, bp) | 
|  |  | 
|  | expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/libTest.orderfile" | 
|  |  | 
|  | libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") | 
|  |  | 
|  | // Check ldFlags of orderfile-enabled module | 
|  | ldFlags := libTest.Rule("ld").Args["ldFlags"] | 
|  | if !strings.Contains(ldFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestOrderfileProfileBinary(t *testing.T) { | 
|  | t.Parallel() | 
|  | bp := ` | 
|  | cc_binary { | 
|  | name: "test", | 
|  | srcs: ["test.c"], | 
|  | orderfile : { | 
|  | instrumentation: true, | 
|  | load_order_file: false, | 
|  | order_file_path: "", | 
|  | }, | 
|  | } | 
|  | ` | 
|  |  | 
|  | result := android.GroupFixturePreparers( | 
|  | prepareForCcTest, | 
|  | ).RunTestWithBp(t, bp) | 
|  |  | 
|  | expectedCFlag := "-forder-file-instrumentation" | 
|  |  | 
|  | test := result.ModuleForTests("test", "android_arm64_armv8-a") | 
|  |  | 
|  | // Check cFlags of orderfile-enabled module | 
|  | cFlags := test.Rule("cc").Args["cFlags"] | 
|  | if !strings.Contains(cFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'test' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags) | 
|  | } | 
|  |  | 
|  | // Check ldFlags of orderfile-enabled module | 
|  | ldFlags := test.Rule("ld").Args["ldFlags"] | 
|  | if !strings.Contains(ldFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'test' to enable orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestOrderfileLoadBinary(t *testing.T) { | 
|  | t.Parallel() | 
|  | bp := ` | 
|  | cc_binary { | 
|  | name: "test", | 
|  | srcs: ["test.c"], | 
|  | orderfile : { | 
|  | instrumentation: true, | 
|  | load_order_file: true, | 
|  | order_file_path: "test.orderfile", | 
|  | }, | 
|  | } | 
|  | ` | 
|  |  | 
|  | result := android.GroupFixturePreparers( | 
|  | prepareForCcTest, | 
|  | android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/test.orderfile", "TEST"), | 
|  | ).RunTestWithBp(t, bp) | 
|  |  | 
|  | expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/test.orderfile" | 
|  |  | 
|  | test := result.ModuleForTests("test", "android_arm64_armv8-a") | 
|  |  | 
|  | // Check ldFlags of orderfile-enabled module | 
|  | ldFlags := test.Rule("ld").Args["ldFlags"] | 
|  | if !strings.Contains(ldFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'test' to load orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Profile flags should propagate through static libraries | 
|  | func TestOrderfileProfilePropagateStaticDeps(t *testing.T) { | 
|  | t.Parallel() | 
|  | bp := ` | 
|  | cc_library_shared { | 
|  | name: "libTest", | 
|  | srcs: ["test.c"], | 
|  | static_libs: ["libFoo"], | 
|  | orderfile : { | 
|  | instrumentation: true, | 
|  | load_order_file: false, | 
|  | order_file_path: "", | 
|  | }, | 
|  | } | 
|  |  | 
|  | cc_library_static { | 
|  | name: "libFoo", | 
|  | srcs: ["foo.c"], | 
|  | static_libs: ["libBar"], | 
|  | } | 
|  |  | 
|  | cc_library_static { | 
|  | name: "libBar", | 
|  | srcs: ["bar.c"], | 
|  | } | 
|  | ` | 
|  |  | 
|  | result := android.GroupFixturePreparers( | 
|  | prepareForCcTest, | 
|  | ).RunTestWithBp(t, bp) | 
|  |  | 
|  | expectedCFlag := "-forder-file-instrumentation" | 
|  |  | 
|  | // Check cFlags of orderfile-enabled module | 
|  | libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") | 
|  |  | 
|  | cFlags := libTest.Rule("cc").Args["cFlags"] | 
|  | if !strings.Contains(cFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags) | 
|  | } | 
|  |  | 
|  | // Check cFlags of orderfile variant static libraries | 
|  | libFooOfVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_orderfile") | 
|  | libBarOfVariant := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_orderfile") | 
|  |  | 
|  | cFlags = libFooOfVariant.Rule("cc").Args["cFlags"] | 
|  | if !strings.Contains(cFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libFooOfVariant' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags) | 
|  | } | 
|  |  | 
|  | cFlags = libBarOfVariant.Rule("cc").Args["cFlags"] | 
|  | if !strings.Contains(cFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libBarOfVariant' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags) | 
|  | } | 
|  |  | 
|  | // Check dependency edge from orderfile-enabled module to orderfile variant static libraries | 
|  | if !hasDirectDep(result, libTest.Module(), libFooOfVariant.Module()) { | 
|  | t.Errorf("libTest missing dependency on orderfile variant of libFoo") | 
|  | } | 
|  |  | 
|  | if !hasDirectDep(result, libFooOfVariant.Module(), libBarOfVariant.Module()) { | 
|  | t.Errorf("libTest missing dependency on orderfile variant of libBar") | 
|  | } | 
|  |  | 
|  | // Check cFlags of the non-orderfile variant static libraries | 
|  | libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static") | 
|  | libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static") | 
|  |  | 
|  | cFlags = libFoo.Rule("cc").Args["cFlags"] | 
|  | if strings.Contains(cFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libFoo' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) | 
|  | } | 
|  |  | 
|  | cFlags = libBar.Rule("cc").Args["cFlags"] | 
|  | if strings.Contains(cFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libBar' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) | 
|  | } | 
|  |  | 
|  | // Check no dependency edge from orderfile-enabled module to non-orderfile variant static libraries | 
|  | if hasDirectDep(result, libTest.Module(), libFoo.Module()) { | 
|  | t.Errorf("libTest has dependency on non-orderfile variant of libFoo") | 
|  | } | 
|  |  | 
|  | if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { | 
|  | t.Errorf("libTest has dependency on non-orderfile variant of libBar") | 
|  | } | 
|  | } | 
|  |  | 
|  | // Load flags should never propagate | 
|  | func TestOrderfileLoadPropagateStaticDeps(t *testing.T) { | 
|  | t.Parallel() | 
|  | bp := ` | 
|  | cc_library_shared { | 
|  | name: "libTest", | 
|  | srcs: ["test.c"], | 
|  | static_libs: ["libFoo"], | 
|  | orderfile : { | 
|  | instrumentation: true, | 
|  | load_order_file: true, | 
|  | order_file_path: "test.orderfile", | 
|  | }, | 
|  | } | 
|  |  | 
|  | cc_library_static { | 
|  | name: "libFoo", | 
|  | srcs: ["foo.c"], | 
|  | static_libs: ["libBar"], | 
|  | } | 
|  |  | 
|  | cc_library_static { | 
|  | name: "libBar", | 
|  | srcs: ["bar.c"], | 
|  | } | 
|  | ` | 
|  |  | 
|  | result := android.GroupFixturePreparers( | 
|  | prepareForCcTest, | 
|  | android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/test.orderfile", "TEST"), | 
|  | ).RunTestWithBp(t, bp) | 
|  |  | 
|  | expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/test.orderfile" | 
|  |  | 
|  | // Check ldFlags of orderfile-enabled module | 
|  | libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") | 
|  |  | 
|  | ldFlags := libTest.Rule("ld").Args["ldFlags"] | 
|  | if !strings.Contains(ldFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in ldFlags %q", expectedCFlag, ldFlags) | 
|  | } | 
|  |  | 
|  | libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static") | 
|  | libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static") | 
|  |  | 
|  | // Check dependency edge from orderfile-enabled module to non-orderfile variant static libraries | 
|  | if !hasDirectDep(result, libTest.Module(), libFoo.Module()) { | 
|  | t.Errorf("libTest missing dependency on non-orderfile variant of libFoo") | 
|  | } | 
|  |  | 
|  | if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { | 
|  | t.Errorf("libTest missing dependency on non-orderfile variant of libBar") | 
|  | } | 
|  |  | 
|  | // Make sure no orderfile variants are created for static libraries because the flags were not propagated | 
|  | libFooVariants := result.ModuleVariantsForTests("libFoo") | 
|  | for _, v := range libFooVariants { | 
|  | if strings.Contains(v, "orderfile") { | 
|  | t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v) | 
|  | } | 
|  | } | 
|  |  | 
|  | libBarVariants := result.ModuleVariantsForTests("libBar") | 
|  | for _, v := range libBarVariants { | 
|  | if strings.Contains(v, "orderfile") { | 
|  | t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Profile flags should not propagate through shared libraries | 
|  | func TestOrderfileProfilePropagateSharedDeps(t *testing.T) { | 
|  | t.Parallel() | 
|  | bp := ` | 
|  | cc_library_shared { | 
|  | name: "libTest", | 
|  | srcs: ["test.c"], | 
|  | shared_libs: ["libFoo"], | 
|  | orderfile : { | 
|  | instrumentation: true, | 
|  | load_order_file: false, | 
|  | order_file_path: "", | 
|  | }, | 
|  | } | 
|  |  | 
|  | cc_library_shared { | 
|  | name: "libFoo", | 
|  | srcs: ["foo.c"], | 
|  | static_libs: ["libBar"], | 
|  | } | 
|  |  | 
|  | cc_library_static { | 
|  | name: "libBar", | 
|  | srcs: ["bar.c"], | 
|  | } | 
|  | ` | 
|  |  | 
|  | result := android.GroupFixturePreparers( | 
|  | prepareForCcTest, | 
|  | ).RunTestWithBp(t, bp) | 
|  |  | 
|  | expectedCFlag := "-forder-file-instrumentation" | 
|  |  | 
|  | // Check cFlags of orderfile-enabled module | 
|  | libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") | 
|  |  | 
|  | cFlags := libTest.Rule("cc").Args["cFlags"] | 
|  | if !strings.Contains(cFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags) | 
|  | } | 
|  |  | 
|  | // Check cFlags of the static and shared libraries | 
|  | libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_shared") | 
|  | libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static") | 
|  |  | 
|  | cFlags = libFoo.Rule("cc").Args["cFlags"] | 
|  | if strings.Contains(cFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libFoo' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) | 
|  | } | 
|  |  | 
|  | cFlags = libBar.Rule("cc").Args["cFlags"] | 
|  | if strings.Contains(cFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libBar' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) | 
|  | } | 
|  |  | 
|  | // Check dependency edge from orderfile-enabled module to non-orderfile variant static libraries | 
|  | if !hasDirectDep(result, libTest.Module(), libFoo.Module()) { | 
|  | t.Errorf("libTest missing dependency on non-orderfile variant of libFoo") | 
|  | } | 
|  |  | 
|  | if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { | 
|  | t.Errorf("libTest missing dependency on non-orderfile variant of libBar") | 
|  | } | 
|  |  | 
|  | // Make sure no orderfile variants are created for libraries because the flags were not propagated | 
|  | libFooVariants := result.ModuleVariantsForTests("libFoo") | 
|  | for _, v := range libFooVariants { | 
|  | if strings.Contains(v, "orderfile") { | 
|  | t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v) | 
|  | } | 
|  | } | 
|  |  | 
|  | libBarVariants := result.ModuleVariantsForTests("libBar") | 
|  | for _, v := range libBarVariants { | 
|  | if strings.Contains(v, "orderfile") { | 
|  | t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Profile flags should not work or be propagated if orderfile flags start at a static library | 
|  | func TestOrderfileProfileStaticLibrary(t *testing.T) { | 
|  | t.Parallel() | 
|  | bp := ` | 
|  | cc_library_static { | 
|  | name: "libTest", | 
|  | srcs: ["test.c"], | 
|  | static_libs: ["libFoo"], | 
|  | orderfile : { | 
|  | instrumentation: true, | 
|  | load_order_file: false, | 
|  | order_file_path: "", | 
|  | }, | 
|  | } | 
|  |  | 
|  | cc_library_static { | 
|  | name: "libFoo", | 
|  | srcs: ["foo.c"], | 
|  | static_libs: ["libBar"], | 
|  | } | 
|  |  | 
|  | cc_library_static { | 
|  | name: "libBar", | 
|  | srcs: ["bar.c"], | 
|  | } | 
|  | ` | 
|  |  | 
|  | result := android.GroupFixturePreparers( | 
|  | prepareForCcTest, | 
|  | ).RunTestWithBp(t, bp) | 
|  |  | 
|  | expectedCFlag := "-forder-file-instrumentation" | 
|  |  | 
|  | // Check cFlags of module | 
|  | libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_static") | 
|  |  | 
|  | cFlags := libTest.Rule("cc").Args["cFlags"] | 
|  | if strings.Contains(cFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libTest' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) | 
|  | } | 
|  |  | 
|  | // Check cFlags of the static libraries | 
|  | libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static") | 
|  | libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static") | 
|  |  | 
|  | cFlags = libFoo.Rule("cc").Args["cFlags"] | 
|  | if strings.Contains(cFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libFoo' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) | 
|  | } | 
|  |  | 
|  | cFlags = libBar.Rule("cc").Args["cFlags"] | 
|  | if strings.Contains(cFlags, expectedCFlag) { | 
|  | t.Errorf("Expected 'libBar' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags) | 
|  | } | 
|  |  | 
|  | // Check dependency edge from orderfile-enabled module to non-orderfile variant libraries | 
|  | if !hasDirectDep(result, libTest.Module(), libFoo.Module()) { | 
|  | t.Errorf("libTest missing dependency on non-orderfile variant of libFoo") | 
|  | } | 
|  |  | 
|  | if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { | 
|  | t.Errorf("libTest missing dependency on non-orderfile variant of libBar") | 
|  | } | 
|  |  | 
|  | // Make sure no orderfile variants are created for static libraries because the flags were not propagated | 
|  | libFooVariants := result.ModuleVariantsForTests("libFoo") | 
|  | for _, v := range libFooVariants { | 
|  | if strings.Contains(v, "orderfile") { | 
|  | t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v) | 
|  | } | 
|  | } | 
|  |  | 
|  | libBarVariants := result.ModuleVariantsForTests("libBar") | 
|  | for _, v := range libBarVariants { | 
|  | if strings.Contains(v, "orderfile") { | 
|  | t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v) | 
|  | } | 
|  | } | 
|  | } |