From 6a43f047772ab30e89eb7cb5346a08db889a2e7b Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Thu, 12 Oct 2017 23:05:00 +0900 Subject: [PATCH] Squash vendor sources before linkageMutator runs linkageMutator removes srcs property of the shared variant of a lib in order to reuse *.o files compiled for the static variant also to the shared variant. However, this causes problem when vendor-specific srcs are specified in target: {vendor: {srcs: ["..."]}}. For example, let's assume cc_library { name: "libfoo", srcs: ["foo.c"], target: { vendor: { srcs: ["bar.c"], }, }, } Then, static_vendor: inputs = foo.o, bar.o shared_vendor: inputs = foo.o (from static_vendor), bar.o (from static_vendor), bar.o So, bar.o is included twice and this causes multiple symbol definition error. In order to handle the problem, vendor mutator is applied before the linkage mutator and the vendor-specific srcs are squashed in the vendor mutator. Bug: 67731122 Test: build Test: cc_test.go Change-Id: I2a5390295dddfc41260e9b6f02746908cdf47228 --- android/config.go | 4 +- cc/cc.go | 20 ++++++-- cc/cc_test.go | 126 ++++++++++++++++++++++++++++++++++++++++++++++ cc/compiler.go | 8 --- 4 files changed, 145 insertions(+), 13 deletions(-) diff --git a/android/config.go b/android/config.go index 90616528f..5abda26fc 100644 --- a/android/config.go +++ b/android/config.go @@ -193,8 +193,8 @@ func TestArchConfig(buildDir string, env map[string]string) Config { config.Targets = map[OsClass][]Target{ Device: []Target{ - {Android, Arch{ArchType: Arm64, Native: true}}, - {Android, Arch{ArchType: Arm, Native: true}}, + {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true}}, + {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true}}, }, Host: []Target{ {BuildOs, Arch{ArchType: X86_64}}, diff --git a/cc/cc.go b/cc/cc.go index 0404cfb50..4c02e9e29 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -34,9 +34,9 @@ func init() { android.RegisterModuleType("cc_defaults", defaultsFactory) android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("image", vendorMutator).Parallel() ctx.BottomUp("link", linkageMutator).Parallel() ctx.BottomUp("vndk", vndkMutator).Parallel() - ctx.BottomUp("image", vendorMutator).Parallel() ctx.BottomUp("ndk_api", ndkApiMutator).Parallel() ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel() ctx.BottomUp("begin", beginMutator).Parallel() @@ -1297,6 +1297,16 @@ const ( vendorMode = "vendor" ) +func squashVendorSrcs(m *Module) { + if lib, ok := m.compiler.(*libraryDecorator); ok { + lib.baseCompiler.Properties.Srcs = append(lib.baseCompiler.Properties.Srcs, + lib.baseCompiler.Properties.Target.Vendor.Srcs...) + + lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs, + lib.baseCompiler.Properties.Target.Vendor.Exclude_srcs...) + } +} + func vendorMutator(mctx android.BottomUpMutatorContext) { if mctx.Os() != android.Android { return @@ -1352,11 +1362,15 @@ func vendorMutator(mctx android.BottomUpMutatorContext) { // This will be available in both /system and /vendor // or a /system directory that is available to vendor. mod := mctx.CreateVariations(coreMode, vendorMode) - mod[1].(*Module).Properties.UseVndk = true + vendor := mod[1].(*Module) + vendor.Properties.UseVndk = true + squashVendorSrcs(vendor) } else if mctx.Vendor() && m.Properties.Sdk_version == "" { // This will be available in /vendor only mod := mctx.CreateVariations(vendorMode) - mod[0].(*Module).Properties.UseVndk = true + vendor := mod[0].(*Module) + vendor.Properties.UseVndk = true + squashVendorSrcs(vendor) } else { // This is either in /system (or similar: /data), or is a // modules built with the NDK. Modules built with the NDK diff --git a/cc/cc_test.go b/cc/cc_test.go index 92120a54e..94e3e66bc 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -2,10 +2,136 @@ package cc import ( "android/soong/android" + "io/ioutil" + "os" "reflect" "testing" + + "github.com/google/blueprint/proptools" ) +var buildDir string + +func setUp() { + var err error + buildDir, err = ioutil.TempDir("", "soong_cc_test") + if err != nil { + panic(err) + } +} + +func tearDown() { + os.RemoveAll(buildDir) +} + +func TestMain(m *testing.M) { + run := func() int { + setUp() + defer tearDown() + + return m.Run() + } + + os.Exit(run()) +} + +func testCc(t *testing.T, bp string) *android.TestContext { + config := android.TestArchConfig(buildDir, nil) + config.ProductVariables.DeviceVndkVersion = proptools.StringPtr("current") + + ctx := android.NewTestArchContext() + ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(libraryFactory)) + ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(toolchainLibraryFactory)) + ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(llndkLibraryFactory)) + ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("image", vendorMutator).Parallel() + ctx.BottomUp("link", linkageMutator).Parallel() + ctx.BottomUp("vndk", vndkMutator).Parallel() + }) + ctx.Register() + + ctx.MockFileSystem(map[string][]byte{ + "Android.bp": []byte(bp), + "foo.c": nil, + "bar.c": nil, + }) + + _, errs := ctx.ParseBlueprintsFiles("Android.bp") + fail(t, errs) + _, errs = ctx.PrepareBuildActions(config) + fail(t, errs) + + return ctx +} + +func TestVendorSrc(t *testing.T) { + ctx := testCc(t, ` + cc_library { + name: "libTest", + srcs: ["foo.c"], + no_libgcc : true, + nocrt : true, + system_shared_libs : [], + vendor_available: true, + target: { + vendor: { + srcs: ["bar.c"], + }, + }, + } + toolchain_library { + name: "libatomic", + vendor_available: true, + } + toolchain_library { + name: "libcompiler_rt-extras", + vendor_available: true, + } + cc_library { + name: "libc", + no_libgcc : true, + nocrt : true, + system_shared_libs: [], + } + llndk_library { + name: "libc", + symbol_file: "", + } + cc_library { + name: "libm", + no_libgcc : true, + nocrt : true, + system_shared_libs: [], + } + llndk_library { + name: "libm", + symbol_file: "", + } + cc_library { + name: "libdl", + no_libgcc : true, + nocrt : true, + system_shared_libs: [], + } + llndk_library { + name: "libdl", + symbol_file: "", + } + `) + + ld := ctx.ModuleForTests("libTest", "android_arm_armv7-a-neon_vendor_shared").Rule("ld") + var objs []string + for _, o := range ld.Inputs { + objs = append(objs, o.Base()) + } + if len(objs) != 2 { + t.Errorf("inputs of libTest is expected to 2, but was %d.", len(objs)) + } + if objs[0] != "foo.o" || objs[1] != "bar.o" { + t.Errorf("inputs of libTest must be []string{\"foo.o\", \"bar.o\"}, but was %#v.", objs) + } +} + var firstUniqueElementsTestCases = []struct { in []string out []string diff --git a/cc/compiler.go b/cc/compiler.go index a65ddf873..3b3bbbb1a 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -490,14 +490,6 @@ func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathD pathDeps := deps.GeneratedHeaders pathDeps = append(pathDeps, ndkPathDeps(ctx)...) - if ctx.vndk() { - compiler.Properties.Srcs = append(compiler.Properties.Srcs, - compiler.Properties.Target.Vendor.Srcs...) - - compiler.Properties.Exclude_srcs = append(compiler.Properties.Exclude_srcs, - compiler.Properties.Target.Vendor.Exclude_srcs...) - } - srcs := ctx.ExpandSources(compiler.Properties.Srcs, compiler.Properties.Exclude_srcs) srcs = append(srcs, deps.GeneratedSources...)