diff options
author | 2023-07-18 21:01:11 +0000 | |
---|---|---|
committer | 2023-08-01 16:58:58 +0000 | |
commit | c6a93d853b37ec90786e745b8d282145e6d3b589 (patch) | |
tree | 2111734c9647d83d263f00fcd3b601350c929fe8 | |
parent | 09195f4ffd24c7bb67262045cb1b2a1a7ef1d2f6 (diff) |
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
-rw-r--r-- | cc/Android.bp | 2 | ||||
-rw-r--r-- | cc/cc.go | 27 | ||||
-rw-r--r-- | cc/orderfile.go | 257 | ||||
-rw-r--r-- | cc/orderfile_test.go | 493 |
4 files changed, 779 insertions, 0 deletions
diff --git a/cc/Android.bp b/cc/Android.bp index e88ea03b3..c32d85490 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -37,6 +37,7 @@ bootstrap_go_package { "linkable.go", "lto.go", "makevars.go", + "orderfile.go", "pgo.go", "prebuilt.go", "proto.go", @@ -104,6 +105,7 @@ bootstrap_go_package { "lto_test.go", "ndk_test.go", "object_test.go", + "orderfile_test.go", "prebuilt_test.go", "proto_test.go", "sanitize_test.go", @@ -74,6 +74,9 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { 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 @@ type ModuleContextIntf interface { getVndkExtendsModuleName() string isAfdoCompile() bool isPgoCompile() bool + isOrderfileCompile() bool isCfi() bool isFuzzer() bool isNDKStubLibrary() bool @@ -885,6 +889,7 @@ type Module struct { lto *lto afdo *afdo pgo *pgo + orderfile *orderfile library libraryInterface @@ -1259,6 +1264,9 @@ func (c *Module) Init() android.Module { 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 @@ func (c *Module) isPgoCompile() bool { 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 @@ func (ctx *moduleContextImpl) isPgoCompile() bool { 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 @@ func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Mo module.lto = <o{} module.afdo = &afdo{} module.pgo = &pgo{} + module.orderfile = &orderfile{} return module } @@ -2234,6 +2254,9 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { 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 @@ func (c *Module) begin(ctx BaseModuleContext) { 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 @@ func DefaultsFactory(props ...interface{}) android.Module { <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 000000000..cc1ab29d0 --- /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 000000000..9e30bd2d5 --- /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 |