Created an Orderfile go file for the build system.
In addition, I added a test file to check if flags are added and propagated correctly.
Test: mma build/soong
Output: #### build completed successfully (07:24 (mm:ss)) ####
For testing with an actual binary or shared library, steps are in this
README:
https://android.googlesource.com/toolchain/pgo-profiles/+/refs/heads/main/orderfiles/README.md
Change-Id: Idcf169156ef691bcacb8adc92828ef09450085f8
diff --git a/cc/Android.bp b/cc/Android.bp
index e88ea03..c32d854 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -37,6 +37,7 @@
"linkable.go",
"lto.go",
"makevars.go",
+ "orderfile.go",
"pgo.go",
"prebuilt.go",
"proto.go",
@@ -104,6 +105,7 @@
"lto_test.go",
"ndk_test.go",
"object_test.go",
+ "orderfile_test.go",
"prebuilt_test.go",
"proto_test.go",
"sanitize_test.go",
diff --git a/cc/cc.go b/cc/cc.go
index be67286..3b92696 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -74,6 +74,9 @@
ctx.TopDown("afdo_deps", afdoDepsMutator)
ctx.BottomUp("afdo", afdoMutator).Parallel()
+ ctx.TopDown("orderfile_deps", orderfileDepsMutator)
+ ctx.BottomUp("orderfile", orderfileMutator).Parallel()
+
ctx.TopDown("lto_deps", ltoDepsMutator)
ctx.BottomUp("lto", ltoMutator).Parallel()
@@ -526,6 +529,7 @@
getVndkExtendsModuleName() string
isAfdoCompile() bool
isPgoCompile() bool
+ isOrderfileCompile() bool
isCfi() bool
isFuzzer() bool
isNDKStubLibrary() bool
@@ -885,6 +889,7 @@
lto *lto
afdo *afdo
pgo *pgo
+ orderfile *orderfile
library libraryInterface
@@ -1259,6 +1264,9 @@
if c.pgo != nil {
c.AddProperties(c.pgo.props()...)
}
+ if c.orderfile != nil {
+ c.AddProperties(c.orderfile.props()...)
+ }
for _, feature := range c.features {
c.AddProperties(feature.props()...)
}
@@ -1392,6 +1400,13 @@
return false
}
+func (c *Module) isOrderfileCompile() bool {
+ if orderfile := c.orderfile; orderfile != nil {
+ return orderfile.Properties.OrderfileLoad
+ }
+ return false
+}
+
func (c *Module) isCfi() bool {
if sanitize := c.sanitize; sanitize != nil {
return Bool(sanitize.Properties.SanitizeMutated.Cfi)
@@ -1697,6 +1712,10 @@
return ctx.mod.isPgoCompile()
}
+func (ctx *moduleContextImpl) isOrderfileCompile() bool {
+ return ctx.mod.isOrderfileCompile()
+}
+
func (ctx *moduleContextImpl) isCfi() bool {
return ctx.mod.isCfi()
}
@@ -1806,6 +1825,7 @@
module.lto = <o{}
module.afdo = &afdo{}
module.pgo = &pgo{}
+ module.orderfile = &orderfile{}
return module
}
@@ -2234,6 +2254,9 @@
if c.pgo != nil {
flags = c.pgo.flags(ctx, flags)
}
+ if c.orderfile != nil {
+ flags = c.orderfile.flags(ctx, flags)
+ }
for _, feature := range c.features {
flags = feature.flags(ctx, flags)
}
@@ -2376,6 +2399,9 @@
if c.lto != nil {
c.lto.begin(ctx)
}
+ if c.orderfile != nil {
+ c.orderfile.begin(ctx)
+ }
if c.pgo != nil {
c.pgo.begin(ctx)
}
@@ -4284,6 +4310,7 @@
<OProperties{},
&AfdoProperties{},
&PgoProperties{},
+ &OrderfileProperties{},
&android.ProtoProperties{},
// RustBindgenProperties is included here so that cc_defaults can be used for rust_bindgen modules.
&RustBindgenClangProperties{},
diff --git a/cc/orderfile.go b/cc/orderfile.go
new file mode 100644
index 0000000..cc1ab29
--- /dev/null
+++ b/cc/orderfile.go
@@ -0,0 +1,257 @@
+// 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.
+//
+// Note: If you want to know how to use orderfile for your binary or shared
+// library, you can go look at the README in toolchains/pgo-profiles/orderfiles
+
+package cc
+
+import (
+ "fmt"
+
+ "android/soong/android"
+)
+
+// Order files are text files containing symbols representing functions names.
+// Linkers (lld) uses order files to layout functions in a specific order.
+// These binaries with ordered symbols will reduce page faults and improve a program's launch time
+// due to the efficient loading of symbols during a program’s cold-start.
+var (
+ // Add flags to ignore warnings about symbols not be found
+ // or not allowed to be ordered
+ orderfileOtherFlags = []string{
+ "-Wl,--no-warn-symbol-ordering",
+ }
+
+ // Add folder projects for orderfiles
+ globalOrderfileProjects = []string{
+ "toolchain/pgo-profiles/orderfiles",
+ "vendor/google_data/pgo_profile/orderfiles",
+ }
+)
+
+var orderfileProjectsConfigKey = android.NewOnceKey("OrderfileProjects")
+
+const orderfileProfileFlag = "-forder-file-instrumentation"
+const orderfileUseFormat = "-Wl,--symbol-ordering-file=%s"
+
+func getOrderfileProjects(config android.DeviceConfig) []string {
+ return config.OnceStringSlice(orderfileProjectsConfigKey, func() []string {
+ return globalOrderfileProjects
+ })
+}
+
+func recordMissingOrderfile(ctx BaseModuleContext, missing string) {
+ getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
+}
+
+type OrderfileProperties struct {
+ Orderfile struct {
+ Instrumentation *bool
+ Order_file_path *string `android:"arch_variant"`
+ Load_order_file *bool `android:"arch_variant"`
+ // Additional compiler flags to use when building this module
+ // for orderfile profiling.
+ Cflags []string `android:"arch_variant"`
+ } `android:"arch_variant"`
+
+ ShouldProfileModule bool `blueprint:"mutated"`
+ OrderfileLoad bool `blueprint:"mutated"`
+ OrderfileInstrLink bool `blueprint:"mutated"`
+}
+
+type orderfile struct {
+ Properties OrderfileProperties
+}
+
+func (props *OrderfileProperties) shouldInstrument() bool {
+ return Bool(props.Orderfile.Instrumentation)
+}
+
+// ShouldLoadOrderfile returns true if we need to load the order file rather than
+// profile the binary or shared library
+func (props *OrderfileProperties) shouldLoadOrderfile() bool {
+ return Bool(props.Orderfile.Load_order_file) && props.Orderfile.Order_file_path != nil
+}
+
+// orderfileEnabled returns true for binaries and shared libraries
+// if instrument flag is set to true
+func (orderfile *orderfile) orderfileEnabled() bool {
+ return orderfile != nil && orderfile.Properties.shouldInstrument()
+}
+
+// orderfileLinkEnabled returns true for binaries and shared libraries
+// if you should instrument dependencies
+func (orderfile *orderfile) orderfileLinkEnabled() bool {
+ return orderfile != nil && orderfile.Properties.OrderfileInstrLink
+}
+
+func (orderfile *orderfile) props() []interface{} {
+ return []interface{}{&orderfile.Properties}
+}
+
+// Get the path to the order file by checking it is valid and not empty
+func (props *OrderfileProperties) getOrderfile(ctx BaseModuleContext) android.OptionalPath {
+ orderFile := *props.Orderfile.Order_file_path
+
+ // Test if the order file is present in any of the Orderfile projects
+ for _, profileProject := range getOrderfileProjects(ctx.DeviceConfig()) {
+ path := android.ExistentPathForSource(ctx, profileProject, orderFile)
+ if path.Valid() {
+ return path
+ }
+ }
+
+ // Record that this module's order file is absent
+ missing := *props.Orderfile.Order_file_path + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
+ recordMissingOrderfile(ctx, missing)
+
+ return android.OptionalPath{}
+}
+
+func (props *OrderfileProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
+ flags.Local.CFlags = append(flags.Local.CFlags, props.Orderfile.Cflags...)
+ flags.Local.CFlags = append(flags.Local.CFlags, orderfileProfileFlag)
+ flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm -enable-order-file-instrumentation")
+ flags.Local.LdFlags = append(flags.Local.LdFlags, orderfileProfileFlag)
+ return flags
+}
+
+
+func (props *OrderfileProperties) loadOrderfileFlags(ctx ModuleContext, file string) []string {
+ flags := []string{fmt.Sprintf(orderfileUseFormat, file)}
+ flags = append(flags, orderfileOtherFlags...)
+ return flags
+}
+
+func (props *OrderfileProperties) addLoadFlags(ctx ModuleContext, flags Flags) Flags {
+ orderFile := props.getOrderfile(ctx)
+ orderFilePath := orderFile.Path()
+ loadFlags := props.loadOrderfileFlags(ctx, orderFilePath.String())
+
+ flags.Local.CFlags = append(flags.Local.CFlags, loadFlags...)
+ flags.Local.LdFlags = append(flags.Local.LdFlags, loadFlags...)
+
+ // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
+ // if orderfile gets updated
+ flags.CFlagsDeps = append(flags.CFlagsDeps, orderFilePath)
+ flags.LdFlagsDeps = append(flags.LdFlagsDeps, orderFilePath)
+ return flags
+}
+
+func (orderfile *orderfile) begin(ctx BaseModuleContext) {
+ // Currently, we are not enabling orderfiles for host
+ if ctx.Host() {
+ return
+ }
+
+ // Currently, we are not enabling orderfiles to begin from static libraries
+ if ctx.static() && !ctx.staticBinary() {
+ return
+ }
+
+ if ctx.DeviceConfig().ClangCoverageEnabled() {
+ return
+ }
+
+ // Checking if orderfile is enabled for this module
+ if !orderfile.orderfileEnabled() {
+ return
+ }
+
+ orderfile.Properties.OrderfileLoad = orderfile.Properties.shouldLoadOrderfile()
+ orderfile.Properties.ShouldProfileModule = !orderfile.Properties.shouldLoadOrderfile()
+ orderfile.Properties.OrderfileInstrLink = orderfile.orderfileEnabled() && !orderfile.Properties.shouldLoadOrderfile()
+}
+
+func (orderfile *orderfile) flags(ctx ModuleContext, flags Flags) Flags {
+ props := orderfile.Properties
+ // Add flags to load the orderfile using the path in its Android.bp
+ if orderfile.Properties.OrderfileLoad {
+ flags = props.addLoadFlags(ctx, flags)
+ return flags
+ }
+
+ // Add flags to profile this module
+ if props.ShouldProfileModule {
+ flags = props.addInstrumentationProfileGatherFlags(ctx, flags)
+ return flags
+ }
+
+ return flags
+}
+
+// Propagate profile orderfile flags down from binaries and shared libraries
+// We do not allow propagation for load flags because the orderfile is specific
+// to the module (binary / shared library)
+func orderfileDepsMutator(mctx android.TopDownMutatorContext) {
+ if m, ok := mctx.Module().(*Module); ok {
+ if !m.orderfile.orderfileLinkEnabled() {
+ return
+ }
+ mctx.WalkDeps(func(dep android.
+ Module, parent android.Module) bool {
+ tag := mctx.OtherModuleDependencyTag(dep)
+ libTag, isLibTag := tag.(libraryDependencyTag)
+
+ // Do not recurse down non-static dependencies
+ if isLibTag {
+ if !libTag.static() {
+ return false
+ }
+ } else {
+ if tag != objDepTag && tag != reuseObjTag {
+ return false
+ }
+ }
+
+ if dep, ok := dep.(*Module); ok {
+ if m.orderfile.Properties.OrderfileInstrLink {
+ dep.orderfile.Properties.OrderfileInstrLink = true;
+ }
+ }
+
+ return true
+ })
+ }
+}
+
+// Create orderfile variants for modules that need them
+func orderfileMutator(mctx android.BottomUpMutatorContext) {
+ if m, ok := mctx.Module().(*Module); ok && m.orderfile != nil {
+ if !m.static() && m.orderfile.orderfileEnabled() {
+ mctx.SetDependencyVariation("orderfile")
+ return
+ }
+
+ variationNames := []string{""}
+ if m.orderfile.Properties.OrderfileInstrLink {
+ variationNames = append(variationNames, "orderfile")
+ }
+
+ if len(variationNames) > 1 {
+ modules := mctx.CreateVariations(variationNames...)
+ for i, name := range variationNames {
+ if name == "" {
+ continue
+ }
+ variation := modules[i].(*Module)
+ variation.Properties.PreventInstall = true
+ variation.Properties.HideFromMake = true
+ variation.orderfile.Properties.ShouldProfileModule = true
+ variation.orderfile.Properties.OrderfileLoad = false
+ }
+ }
+ }
+}
diff --git a/cc/orderfile_test.go b/cc/orderfile_test.go
new file mode 100644
index 0000000..9e30bd2
--- /dev/null
+++ b/cc/orderfile_test.go
@@ -0,0 +1,493 @@
+// 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 (
+ "testing"
+ "strings"
+
+ "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 cFlags of orderfile-enabled module
+ cFlags := libTest.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libTest' to load 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 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 cFlags of orderfile-enabled module
+ cFlags := test.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'test' to load 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 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 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 load orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // 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' not load 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' not load 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 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)
+ }
+ }
+}
\ No newline at end of file