diff options
Diffstat (limited to 'cc')
103 files changed, 6713 insertions, 14663 deletions
diff --git a/cc/Android.bp b/cc/Android.bp index be2cc5a34..3bbcaa92e 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -9,34 +9,34 @@ bootstrap_go_package { "blueprint", "blueprint-pathtools", "soong", + "soong-aconfig", + "soong-aidl-library", "soong-android", - "soong-bazel", "soong-cc-config", "soong-etc", "soong-fuzz", "soong-genrule", "soong-multitree", - "soong-snapshot", + "soong-testing", "soong-tradefed", ], srcs: [ "afdo.go", "fdo_profile.go", - "androidmk.go", "api_level.go", - "bp2build.go", "builder.go", "cc.go", "ccdeps.go", "check.go", "coverage.go", "gen.go", + "generated_cc_library.go", "image.go", "linkable.go", "lto.go", "makevars.go", - "pgo.go", + "orderfile.go", "prebuilt.go", "proto.go", "rs.go", @@ -44,16 +44,14 @@ bootstrap_go_package { "sabi.go", "sdk.go", "snapshot_prebuilt.go", - "snapshot_utils.go", "stl.go", "strip.go", - "sysprop.go", "tidy.go", "util.go", - "vendor_snapshot.go", "vndk.go", "vndk_prebuilt.go", + "cmake_snapshot.go", "cmakelists.go", "compdb.go", "compiler.go", @@ -94,15 +92,17 @@ bootstrap_go_package { "afdo_test.go", "binary_test.go", "cc_test.go", + "cc_test_only_property_test.go", + "cmake_snapshot_test.go", "compiler_test.go", "gen_test.go", "genrule_test.go", "library_headers_test.go", - "library_stub_test.go", "library_test.go", "lto_test.go", "ndk_test.go", "object_test.go", + "orderfile_test.go", "prebuilt_test.go", "proto_test.go", "sanitize_test.go", @@ -110,7 +110,13 @@ bootstrap_go_package { "test_data_test.go", "tidy_test.go", "vendor_public_library_test.go", - "vendor_snapshot_test.go", + ], + embedSrcs: [ + "cmake_ext_add_aidl_library.txt", + "cmake_ext_append_flags.txt", + "cmake_main.txt", + "cmake_module_aidl.txt", + "cmake_module_cc.txt", ], pluginFor: ["soong_build"], } diff --git a/cc/afdo.go b/cc/afdo.go index 137ea97fe..6921edfba 100644 --- a/cc/afdo.go +++ b/cc/afdo.go @@ -21,38 +21,17 @@ import ( "android/soong/android" "github.com/google/blueprint" - "github.com/google/blueprint/proptools" ) -// TODO(b/267229066): Remove globalAfdoProfileProjects after implementing bp2build converter for fdo_profile -var ( - globalAfdoProfileProjects = []string{ - "vendor/google_data/pgo_profile/sampling/", - "toolchain/pgo-profiles/sampling/", - } -) - -var afdoProfileProjectsConfigKey = android.NewOnceKey("AfdoProfileProjects") - -const afdoCFlagsFormat = "-fprofile-sample-use=%s" - -func recordMissingAfdoProfileFile(ctx android.BaseModuleContext, missing string) { - getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true) -} - -type afdoRdep struct { - VariationName *string - ProfilePath *string -} +// This flag needs to be in both CFlags and LdFlags to ensure correct symbol ordering +const afdoFlagsFormat = "-fprofile-sample-use=%s -fprofile-sample-accurate" type AfdoProperties struct { // Afdo allows developers self-service enroll for // automatic feedback-directed optimization using profile data. Afdo bool - FdoProfilePath *string `blueprint:"mutated"` - - AfdoRDeps []afdoRdep `blueprint:"mutated"` + AfdoDep bool `blueprint:"mutated"` } type afdo struct { @@ -63,14 +42,40 @@ func (afdo *afdo) props() []interface{} { return []interface{}{&afdo.Properties} } +func (afdo *afdo) begin(ctx BaseModuleContext) { + // Disable on eng builds for faster build. + if ctx.Config().Eng() { + afdo.Properties.Afdo = false + } +} + // afdoEnabled returns true for binaries and shared libraries -// that set afdo prop to True and there is a profile available +// that set afdo prop to True. func (afdo *afdo) afdoEnabled() bool { return afdo != nil && afdo.Properties.Afdo } +func (afdo *afdo) isAfdoCompile(ctx ModuleContext) bool { + fdoProfilePath := getFdoProfilePathFromDep(ctx) + return !ctx.Host() && (afdo.Properties.Afdo || afdo.Properties.AfdoDep) && (fdoProfilePath != "") +} + +func getFdoProfilePathFromDep(ctx ModuleContext) string { + fdoProfileDeps := ctx.GetDirectDepsWithTag(FdoProfileTag) + if len(fdoProfileDeps) > 0 && fdoProfileDeps[0] != nil { + if info, ok := android.OtherModuleProvider(ctx, fdoProfileDeps[0], FdoProfileProvider); ok { + return info.Path.String() + } + } + return "" +} + func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags { - if afdo.Properties.Afdo { + if ctx.Host() { + return flags + } + + if afdo.Properties.Afdo || afdo.Properties.AfdoDep { // We use `-funique-internal-linkage-names` to associate profiles to the right internal // functions. This option should be used before generating a profile. Because a profile // generated for a binary without unique names doesn't work well building a binary with @@ -83,16 +88,20 @@ func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags { // 3. Make the profile searchable by the build system. So it's used the next time the binary // is built. flags.Local.CFlags = append([]string{"-funique-internal-linkage-names"}, flags.Local.CFlags...) + // Flags for Flow Sensitive AutoFDO + flags.Local.CFlags = append([]string{"-mllvm", "-enable-fs-discriminator=true"}, flags.Local.CFlags...) + // TODO(b/266595187): Remove the following feature once it is enabled in LLVM by default. + flags.Local.CFlags = append([]string{"-mllvm", "-improved-fs-discriminator=true"}, flags.Local.CFlags...) } - if path := afdo.Properties.FdoProfilePath; path != nil { + if fdoProfilePath := getFdoProfilePathFromDep(ctx); fdoProfilePath != "" { // The flags are prepended to allow overriding. - profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, *path) + profileUseFlag := fmt.Sprintf(afdoFlagsFormat, fdoProfilePath) flags.Local.CFlags = append([]string{profileUseFlag}, flags.Local.CFlags...) flags.Local.LdFlags = append([]string{profileUseFlag, "-Wl,-mllvm,-no-warn-sample-unused=true"}, flags.Local.LdFlags...) // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt // if profileFile gets updated - pathForSrc := android.PathForSource(ctx, *path) + pathForSrc := android.PathForSource(ctx, fdoProfilePath) flags.CFlagsDeps = append(flags.CFlagsDeps, pathForSrc) flags.LdFlagsDeps = append(flags.LdFlagsDeps, pathForSrc) } @@ -100,119 +109,89 @@ func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags { return flags } -func (afdo *afdo) addDep(ctx BaseModuleContext, actx android.BottomUpMutatorContext) { - if ctx.Host() { - return +func (a *afdo) addDep(ctx android.BottomUpMutatorContext, fdoProfileTarget string) { + if fdoProfileName, err := ctx.DeviceConfig().AfdoProfile(fdoProfileTarget); fdoProfileName != "" && err == nil { + ctx.AddFarVariationDependencies( + []blueprint.Variation{ + {Mutator: "arch", Variation: ctx.Target().ArchVariation()}, + {Mutator: "os", Variation: "android"}, + }, + FdoProfileTag, + fdoProfileName) } +} - if ctx.static() && !ctx.staticBinary() { - return +func afdoPropagateViaDepTag(tag blueprint.DependencyTag) bool { + libTag, isLibTag := tag.(libraryDependencyTag) + // Do not recurse down non-static dependencies + if isLibTag { + return libTag.static() + } else { + return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag } +} - if c, ok := ctx.Module().(*Module); ok && c.Enabled() { - if fdoProfileName, err := actx.DeviceConfig().AfdoProfile(actx.ModuleName()); fdoProfileName != nil && err == nil { - actx.AddFarVariationDependencies( - []blueprint.Variation{ - {Mutator: "arch", Variation: actx.Target().ArchVariation()}, - {Mutator: "os", Variation: "android"}, - }, - FdoProfileTag, - []string{*fdoProfileName}..., - ) - } - } +// afdoTransitionMutator creates afdo variants of cc modules. +type afdoTransitionMutator struct{} + +func (a *afdoTransitionMutator) Split(ctx android.BaseModuleContext) []string { + return []string{""} } -// FdoProfileMutator reads the FdoProfileProvider from a direct dep with FdoProfileTag -// assigns FdoProfileInfo.Path to the FdoProfilePath mutated property -func (c *Module) fdoProfileMutator(ctx android.BottomUpMutatorContext) { - if !c.Enabled() { - return +func (a *afdoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + if ctx.Host() { + return "" } - ctx.VisitDirectDepsWithTag(FdoProfileTag, func(m android.Module) { - if ctx.OtherModuleHasProvider(m, FdoProfileProvider) { - info := ctx.OtherModuleProvider(m, FdoProfileProvider).(FdoProfileInfo) - c.afdo.Properties.FdoProfilePath = proptools.StringPtr(info.Path.String()) + if m, ok := ctx.Module().(*Module); ok && m.afdo != nil { + if !afdoPropagateViaDepTag(ctx.DepTag()) { + return "" } - }) -} - -var _ FdoProfileMutatorInterface = (*Module)(nil) - -// Propagate afdo requirements down from binaries and shared libraries -func afdoDepsMutator(mctx android.TopDownMutatorContext) { - if m, ok := mctx.Module().(*Module); ok && m.afdo.afdoEnabled() { - path := m.afdo.Properties.FdoProfilePath - 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 { - dep.afdo.Properties.AfdoRDeps = append( - dep.afdo.Properties.AfdoRDeps, - afdoRdep{ - VariationName: proptools.StringPtr(encodeTarget(m.Name())), - ProfilePath: path, - }, - ) - } + if sourceVariation != "" { + return sourceVariation + } - return true - }) + if !m.afdo.afdoEnabled() { + return "" + } + + // TODO(b/324141705): this is designed to prevent propagating AFDO from static libraries that have afdo: true set, but + // it should be m.static() && !m.staticBinary() so that static binaries use AFDO variants of dependencies. + if m.static() { + return "" + } + + return encodeTarget(ctx.Module().Name()) } + return "" } -// Create afdo variants for modules that need them -func afdoMutator(mctx android.BottomUpMutatorContext) { - if m, ok := mctx.Module().(*Module); ok && m.afdo != nil { - if !m.static() && m.afdo.Properties.Afdo { - mctx.SetDependencyVariation(encodeTarget(m.Name())) - return - } +func (a *afdoTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { + if m, ok := ctx.Module().(*Module); ok && m.afdo != nil { + return incomingVariation + } + return "" +} - variationNames := []string{""} - - variantNameToProfilePath := make(map[string]*string) - - for _, afdoRDep := range m.afdo.Properties.AfdoRDeps { - variantName := *afdoRDep.VariationName - // An rdep can be set twice in AfdoRDeps because there can be - // more than one path from an afdo-enabled module to - // a static dep such as - // afdo_enabled_foo -> static_bar ----> static_baz - // \ ^ - // ----------------------| - // We only need to create one variant per unique rdep - if _, exists := variantNameToProfilePath[variantName]; !exists { - variationNames = append(variationNames, variantName) - variantNameToProfilePath[variantName] = afdoRDep.ProfilePath - } +func (a *afdoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { + if m, ok := ctx.Module().(*Module); ok && m.afdo != nil { + if !m.Enabled(ctx) { + return } - - 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.afdo.Properties.Afdo = true - variation.afdo.Properties.FdoProfilePath = variantNameToProfilePath[name] + if variation == "" { + // The empty variation is either a module that has enabled AFDO for itself, or the non-AFDO + // variant of a dependency. + if m.afdo.afdoEnabled() && !(m.static() && !m.staticBinary()) && !m.Host() { + m.afdo.addDep(ctx, ctx.ModuleName()) } + } else { + // The non-empty variation is the AFDO variant of a dependency of a module that enabled AFDO + // for itself. + m.Properties.PreventInstall = true + m.Properties.HideFromMake = true + m.afdo.Properties.AfdoDep = true + m.afdo.addDep(ctx, decodeTarget(variation)) } } } diff --git a/cc/afdo_test.go b/cc/afdo_test.go index b250ad1a1..0679d1386 100644 --- a/cc/afdo_test.go +++ b/cc/afdo_test.go @@ -15,6 +15,7 @@ package cc import ( + "runtime" "strings" "testing" @@ -42,19 +43,25 @@ func TestAfdoDeps(t *testing.T) { bp := ` cc_library_shared { name: "libTest", + host_supported: true, srcs: ["test.c"], static_libs: ["libFoo"], afdo: true, + lto: { + thin: true, + }, } cc_library_static { name: "libFoo", + host_supported: true, srcs: ["foo.c"], static_libs: ["libBar"], } cc_library_static { name: "libBar", + host_supported: true, srcs: ["bar.c"], } ` @@ -72,13 +79,20 @@ func TestAfdoDeps(t *testing.T) { "afdo_profiles_package/Android.bp": []byte(` fdo_profile { name: "libTest_afdo", - profile: "libTest.afdo", + arch: { + arm64: { + profile: "libTest.afdo", + }, + }, } `), }.AddToFixture(), ).RunTestWithBp(t, bp) - expectedCFlag := "-fprofile-sample-use=afdo_profiles_package/libTest.afdo" + profileSampleCFlag := "-fprofile-sample-use=afdo_profiles_package/libTest.afdo" + uniqueInternalLinkageNamesCFlag := "-funique-internal-linkage-names" + afdoLtoLdFlag := "-Wl,-plugin-opt,-import-instr-limit=40" + noAfdoLtoLdFlag := "-Wl,-plugin-opt,-import-instr-limit=5" libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") libFooAfdoVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest") @@ -86,18 +100,32 @@ func TestAfdoDeps(t *testing.T) { // Check cFlags of afdo-enabled module and the afdo-variant of its static deps cFlags := libTest.Rule("cc").Args["cFlags"] - if !strings.Contains(cFlags, expectedCFlag) { - t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags) + if !strings.Contains(cFlags, profileSampleCFlag) { + t.Errorf("Expected 'libTest' to enable afdo profile, but did not find %q in cflags %q", profileSampleCFlag, cFlags) + } + if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) { + t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", profileSampleCFlag, cFlags) + } + + ldFlags := libTest.Rule("ld").Args["ldFlags"] + if !strings.Contains(ldFlags, afdoLtoLdFlag) { + t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in ldflags %q", afdoLtoLdFlag, ldFlags) } cFlags = libFooAfdoVariant.Rule("cc").Args["cFlags"] - if !strings.Contains(cFlags, expectedCFlag) { - t.Errorf("Expected 'libFooAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags) + if !strings.Contains(cFlags, profileSampleCFlag) { + t.Errorf("Expected 'libFooAfdoVariant' to enable afdo profile, but did not find %q in cflags %q", profileSampleCFlag, cFlags) + } + if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) { + t.Errorf("Expected 'libFooAfdoVariant' to enable afdo, but did not find %q in cflags %q", profileSampleCFlag, cFlags) } cFlags = libBarAfdoVariant.Rule("cc").Args["cFlags"] - if !strings.Contains(cFlags, expectedCFlag) { - t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags) + if !strings.Contains(cFlags, profileSampleCFlag) { + t.Errorf("Expected 'libBarAfdoVariant' to enable afdo profile, but did not find %q in cflags %q", profileSampleCFlag, cFlags) + } + if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) { + t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", profileSampleCFlag, cFlags) } // Check dependency edge from afdo-enabled module to static deps @@ -114,12 +142,18 @@ func TestAfdoDeps(t *testing.T) { 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 afdo, but found %q in cflags %q", expectedCFlag, cFlags) + if strings.Contains(cFlags, profileSampleCFlag) { + t.Errorf("Expected 'libFoo' to not enable afdo profile, but found %q in cflags %q", profileSampleCFlag, cFlags) + } + if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) { + t.Errorf("Expected 'libFoo' to not enable afdo, but found %q in cflags %q", profileSampleCFlag, cFlags) } cFlags = libBar.Rule("cc").Args["cFlags"] - if strings.Contains(cFlags, expectedCFlag) { - t.Errorf("Expected 'libBar' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags) + if strings.Contains(cFlags, profileSampleCFlag) { + t.Errorf("Expected 'libBar' to not enable afdo profile, but found %q in cflags %q", profileSampleCFlag, cFlags) + } + if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) { + t.Errorf("Expected 'libBar' to not enable afdo, but found %q in cflags %q", profileSampleCFlag, cFlags) } // Check dependency edges of static deps @@ -130,6 +164,104 @@ func TestAfdoDeps(t *testing.T) { if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { t.Errorf("libFoo missing dependency on non-afdo variant of libBar") } + + // Verify that the arm variant does not have FDO since the fdo_profile module only has a profile for arm64 + libTest32 := result.ModuleForTests("libTest", "android_arm_armv7-a-neon_shared") + libFooAfdoVariant32 := result.ModuleForTests("libFoo", "android_arm_armv7-a-neon_static_afdo-libTest_lto-thin") + libBarAfdoVariant32 := result.ModuleForTests("libBar", "android_arm_armv7-a-neon_static_afdo-libTest_lto-thin") + + cFlags = libTest32.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags, profileSampleCFlag) { + t.Errorf("Expected arm32 'libTest' not to enable afdo, but found %q in cflags %q", profileSampleCFlag, cFlags) + } + + // TODO(b/324141705): when the fdo_profile module doesn't provide a source file the dependencies don't get + // -funique-internal-linkage-names but the module does. + if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) { + t.Errorf("Expected arm32 'libTest' to enable -funique-internal-linkage-names but did not find %q in cflags %q", + uniqueInternalLinkageNamesCFlag, cFlags) + } + + ldFlags = libTest32.Rule("ld").Args["ldFlags"] + if !strings.Contains(ldFlags, noAfdoLtoLdFlag) { + t.Errorf("Expected arm32 'libTest' to not enable afdo, but did not find %q in ldflags %q", noAfdoLtoLdFlag, ldFlags) + } + if strings.Contains(ldFlags, afdoLtoLdFlag) { + t.Errorf("Expected arm32 'libTest' to not enable afdo, but found %q in ldflags %q", afdoLtoLdFlag, ldFlags) + } + + // Check dependency edge from afdo-enabled module to static deps + if !hasDirectDep(result, libTest32.Module(), libFooAfdoVariant32.Module()) { + t.Errorf("arm32 libTest missing dependency on afdo variant of libFoo") + } + + if !hasDirectDep(result, libFooAfdoVariant32.Module(), libBarAfdoVariant32.Module()) { + t.Errorf("arm32 libTest missing dependency on afdo variant of libBar") + } + + cFlags = libFooAfdoVariant32.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags, profileSampleCFlag) { + t.Errorf("Expected arm32 'libFoo' to not enable afdo profile, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags) + } + if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) { + t.Errorf("Expected arm32 'libFoo' to enable afdo, but did not find %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags) + } + cFlags = libBarAfdoVariant32.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags, profileSampleCFlag) { + t.Errorf("Expected arm32 'libBar' to not enable afdo profile, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags) + } + if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) { + t.Errorf("Expected arm32 'libBar' to enable afdo, but did not find %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags) + } + + // Verify that the host variants don't enable afdo + libTestHost := result.ModuleForTests("libTest", result.Config.BuildOSTarget.String()+"_shared") + libFooHost := result.ModuleForTests("libFoo", result.Config.BuildOSTarget.String()+"_static_lto-thin") + libBarHost := result.ModuleForTests("libBar", result.Config.BuildOSTarget.String()+"_static_lto-thin") + + cFlags = libTestHost.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags, profileSampleCFlag) { + t.Errorf("Expected host 'libTest' to not enable afdo profile, but found %q in cflags %q", profileSampleCFlag, cFlags) + } + + if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) { + t.Errorf("Expected host 'libTest' to not enable afdo but found %q in cflags %q", + uniqueInternalLinkageNamesCFlag, cFlags) + } + + if runtime.GOOS != "darwin" { + ldFlags := libTestHost.Rule("ld").Args["ldFlags"] + if !strings.Contains(ldFlags, noAfdoLtoLdFlag) { + t.Errorf("Expected host 'libTest' to not enable afdo, but did not find %q in ldflags %q", noAfdoLtoLdFlag, ldFlags) + } + if strings.Contains(ldFlags, afdoLtoLdFlag) { + t.Errorf("Expected host 'libTest' to not enable afdo, but found %q in ldflags %q", afdoLtoLdFlag, ldFlags) + } + } + + // Check dependency edge from afdo-enabled module to static deps + if !hasDirectDep(result, libTestHost.Module(), libFooHost.Module()) { + t.Errorf("host libTest missing dependency on non-afdo variant of libFoo") + } + + if !hasDirectDep(result, libFooHost.Module(), libBarHost.Module()) { + t.Errorf("host libTest missing dependency on non-afdo variant of libBar") + } + + cFlags = libFooHost.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags, profileSampleCFlag) { + t.Errorf("Expected host 'libFoo' to not enable afdo profile, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags) + } + if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) { + t.Errorf("Expected host 'libFoo' to not enable afdo, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags) + } + cFlags = libBarHost.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags, profileSampleCFlag) { + t.Errorf("Expected host 'libBar' to not enable afdo profile, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags) + } + if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) { + t.Errorf("Expected host 'libBar' to not enable afdo, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags) + } } func TestAfdoEnabledOnStaticDepNoAfdo(t *testing.T) { @@ -174,11 +306,11 @@ func TestAfdoEnabledOnStaticDepNoAfdo(t *testing.T) { libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static").Module() if !hasDirectDep(result, libTest, libFoo.Module()) { - t.Errorf("libTest missing dependency on afdo variant of libFoo") + t.Errorf("libTest missing dependency on non-afdo variant of libFoo") } if !hasDirectDep(result, libFoo.Module(), libBar) { - t.Errorf("libFoo missing dependency on afdo variant of libBar") + t.Errorf("libFoo missing dependency on non-afdo variant of libBar") } fooVariants := result.ModuleVariantsForTests("foo") diff --git a/cc/androidmk.go b/cc/androidmk.go index 980dd0762..41346538f 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -15,8 +15,6 @@ package cc import ( - "github.com/google/blueprint/proptools" - "fmt" "io" "path/filepath" @@ -50,6 +48,7 @@ type AndroidMkContext interface { InVendorRamdisk() bool InRecovery() bool NotInPlatform() bool + InVendorOrProduct() bool } type subAndroidMkProvider interface { @@ -82,13 +81,14 @@ func (c *Module) AndroidMkEntries() []android.AndroidMkEntries { // causing multiple ART APEXes (com.android.art and com.android.art.debug) // to be installed. And this is breaking some older devices (like marlin) // where system.img is small. - Required: c.Properties.AndroidMkRuntimeLibs, - Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk", + Required: c.Properties.AndroidMkRuntimeLibs, + OverrideName: c.BaseModuleName(), + Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { if len(c.Properties.Logtags) > 0 { - entries.AddStrings("LOCAL_LOGTAGS_FILES", c.Properties.Logtags...) + entries.AddStrings("LOCAL_SOONG_LOGTAGS_FILES", c.logtagsPaths.Strings()...) } // Note: Pass the exact value of AndroidMkSystemSharedLibs to the Make // world, even if it is an empty list. In the Make world, @@ -100,42 +100,22 @@ func (c *Module) AndroidMkEntries() []android.AndroidMkEntries { if len(c.Properties.AndroidMkSharedLibs) > 0 { entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...) } - if len(c.Properties.AndroidMkStaticLibs) > 0 { - entries.AddStrings("LOCAL_STATIC_LIBRARIES", c.Properties.AndroidMkStaticLibs...) - } - if len(c.Properties.AndroidMkWholeStaticLibs) > 0 { - entries.AddStrings("LOCAL_WHOLE_STATIC_LIBRARIES", c.Properties.AndroidMkWholeStaticLibs...) - } - if len(c.Properties.AndroidMkHeaderLibs) > 0 { - entries.AddStrings("LOCAL_HEADER_LIBRARIES", c.Properties.AndroidMkHeaderLibs...) - } if len(c.Properties.AndroidMkRuntimeLibs) > 0 { entries.AddStrings("LOCAL_RUNTIME_LIBRARIES", c.Properties.AndroidMkRuntimeLibs...) } entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType) - if c.UseVndk() { - entries.SetBool("LOCAL_USE_VNDK", true) - if c.IsVndk() && !c.static() { - entries.SetString("LOCAL_SOONG_VNDK_VERSION", c.VndkVersion()) - // VNDK libraries available to vendor are not installed because - // they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go) - if !c.IsVndkExt() { - entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) - } - } + if c.InVendor() { + entries.SetBool("LOCAL_IN_VENDOR", true) + } else if c.InProduct() { + entries.SetBool("LOCAL_IN_PRODUCT", true) } - if c.Properties.IsSdkVariant { - // Make the SDK variant uninstallable so that there are not two rules to install - // to the same location. - entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) - - if c.Properties.SdkAndPlatformVariantVisibleToMake { - // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite - // dependencies to the .sdk suffix when building a module that uses the SDK. - entries.SetString("SOONG_SDK_VARIANT_MODULES", - "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))") - } + if c.Properties.SdkAndPlatformVariantVisibleToMake { + // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite + // dependencies to the .sdk suffix when building a module that uses the SDK. + entries.SetString("SOONG_SDK_VARIANT_MODULES", + "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))") } + entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", c.IsSkipInstall()) }, }, ExtraFooters: []android.AndroidMkExtraFootersFunc{ @@ -178,15 +158,6 @@ func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *and } } -func AndroidMkWriteTestData(data []android.DataPath, entries *android.AndroidMkEntries) { - testFiles := android.AndroidMkDataPaths(data) - if len(testFiles) > 0 { - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - entries.AddStrings("LOCAL_TEST_DATA", testFiles...) - }) - } -} - func makeOverrideModuleNames(ctx AndroidMkContext, overrides []string) []string { if ctx.Target().NativeBridge == android.NativeBridgeEnabled { var result []string @@ -280,15 +251,6 @@ func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries if library.coverageOutputFile.Valid() { entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String()) } - - if library.useCoreVariant { - entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) - entries.SetBool("LOCAL_NO_NOTICE_FILE", true) - entries.SetBool("LOCAL_VNDK_DEPEND_ON_CORE_VARIANT", true) - } - if library.checkSameCoreVariant { - entries.SetBool("LOCAL_CHECK_SAME_VNDK_VARIANTS", true) - } }) if library.shared() && !library.buildStubs() { @@ -313,7 +275,7 @@ func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries // they can be exceptionally used directly when APEXes are not available (e.g. during the // very early stage in the boot process). if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.NotInPlatform() && - !ctx.InRamdisk() && !ctx.InVendorRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() && !ctx.static() { + !ctx.InRamdisk() && !ctx.InVendorRamdisk() && !ctx.InRecovery() && !ctx.InVendorOrProduct() && !ctx.static() { if library.buildStubs() && library.isLatestStubVersion() { entries.SubName = "" } @@ -382,11 +344,6 @@ func (benchmark *benchmarkDecorator) AndroidMkEntries(ctx AndroidMkContext, entr entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true) } }) - dataPaths := []android.DataPath{} - for _, srcPath := range benchmark.data { - dataPaths = append(dataPaths, android.DataPath{SrcPath: srcPath}) - } - AndroidMkWriteTestData(dataPaths, entries) } func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { @@ -394,9 +351,6 @@ func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android. ctx.subAndroidMk(entries, test.testDecorator) entries.Class = "NATIVE_TESTS" - if Bool(test.Properties.Test_per_src) { - entries.SubName = "_" + String(test.binaryDecorator.Properties.Stem) - } entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { if test.testConfig != nil { entries.SetString("LOCAL_FULL_TEST_CONFIG", test.testConfig.String()) @@ -414,40 +368,16 @@ func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android. test.Properties.Test_options.CommonTestOptions.SetAndroidMkEntries(entries) }) - AndroidMkWriteTestData(test.data, entries) androidMkWriteExtraTestConfigs(test.extraTestConfigs, entries) } func (fuzz *fuzzBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { ctx.subAndroidMk(entries, fuzz.binaryDecorator) - var fuzzFiles []string - for _, d := range fuzz.fuzzPackagedModule.Corpus { - fuzzFiles = append(fuzzFiles, - filepath.Dir(fuzz.fuzzPackagedModule.CorpusIntermediateDir.String())+":corpus/"+d.Base()) - } - - for _, d := range fuzz.fuzzPackagedModule.Data { - fuzzFiles = append(fuzzFiles, - filepath.Dir(fuzz.fuzzPackagedModule.DataIntermediateDir.String())+":data/"+d.Rel()) - } - - if fuzz.fuzzPackagedModule.Dictionary != nil { - fuzzFiles = append(fuzzFiles, - filepath.Dir(fuzz.fuzzPackagedModule.Dictionary.String())+":"+fuzz.fuzzPackagedModule.Dictionary.Base()) - } - - if fuzz.fuzzPackagedModule.Config != nil { - fuzzFiles = append(fuzzFiles, - filepath.Dir(fuzz.fuzzPackagedModule.Config.String())+":config.json") - } - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { entries.SetBool("LOCAL_IS_FUZZ_TARGET", true) - if len(fuzzFiles) > 0 { - entries.AddStrings("LOCAL_TEST_DATA", fuzzFiles...) - } if fuzz.installedSharedDeps != nil { + // TOOD: move to install dep entries.AddStrings("LOCAL_FUZZ_INSTALLED_SHARED_DEPS", fuzz.installedSharedDeps...) } }) @@ -491,6 +421,7 @@ func (c *stubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android. if c.parsedCoverageXmlPath.String() != "" { entries.SetString("SOONG_NDK_API_XML", "$(SOONG_NDK_API_XML) "+c.parsedCoverageXmlPath.String()) } + entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) // Stubs should not be installed }) } @@ -520,79 +451,6 @@ func (c *vndkPrebuiltLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, en }) } -func (c *snapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - // Each vendor snapshot is exported to androidMk only when BOARD_VNDK_VERSION != current - // and the version of the prebuilt is same as BOARD_VNDK_VERSION. - if c.shared() { - entries.Class = "SHARED_LIBRARIES" - } else if c.static() { - entries.Class = "STATIC_LIBRARIES" - } else if c.header() { - entries.Class = "HEADER_LIBRARIES" - } - - entries.SubName = "" - - if c.isSanitizerEnabled(cfi) { - entries.SubName += ".cfi" - } else if c.isSanitizerEnabled(Hwasan) { - entries.SubName += ".hwasan" - } - - entries.SubName += c.baseProperties.Androidmk_suffix - - entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - c.libraryDecorator.androidMkWriteExportedFlags(entries) - - if c.shared() || c.static() { - src := c.path.String() - // For static libraries which aren't installed, directly use Src to extract filename. - // This is safe: generated snapshot modules have a real path as Src, not a module - if c.static() { - src = proptools.String(c.properties.Src) - } - path, file := filepath.Split(src) - stem, suffix, ext := android.SplitFileExt(file) - entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext) - entries.SetString("LOCAL_MODULE_SUFFIX", suffix) - entries.SetString("LOCAL_MODULE_STEM", stem) - if c.shared() { - entries.SetString("LOCAL_MODULE_PATH", path) - } - if c.tocFile.Valid() { - entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String()) - } - - if c.shared() && len(c.Properties.Overrides) > 0 { - entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, c.Properties.Overrides), " ")) - } - } - - if !c.shared() { // static or header - entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) - } - }) -} - -func (c *snapshotBinaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - entries.Class = "EXECUTABLES" - entries.SubName = c.baseProperties.Androidmk_suffix -} - -func (c *snapshotObjectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - entries.Class = "STATIC_LIBRARIES" - entries.SubName = c.baseProperties.Androidmk_suffix - - entries.ExtraFooters = append(entries.ExtraFooters, - func(w io.Writer, name, prefix, moduleDir string) { - out := entries.OutputFile.Path() - varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName) - - fmt.Fprintf(w, "\n%s := %s\n", varname, out.String()) - fmt.Fprintln(w, ".KATI_READONLY: "+varname) - }) -} - func (c *ndkPrebuiltStlLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { entries.Class = "SHARED_LIBRARIES" } @@ -615,14 +473,14 @@ func (p *prebuiltLibraryLinker) AndroidMkEntries(ctx AndroidMkContext, entries * ctx.subAndroidMk(entries, p.libraryDecorator) if p.shared() { ctx.subAndroidMk(entries, &p.prebuiltLinker) - androidMkWriteAllowUndefinedSymbols(p.baseLinker, entries) + androidMkWritePrebuiltOptions(p.baseLinker, entries) } } func (p *prebuiltBinaryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { ctx.subAndroidMk(entries, p.binaryDecorator) ctx.subAndroidMk(entries, &p.prebuiltLinker) - androidMkWriteAllowUndefinedSymbols(p.baseLinker, entries) + androidMkWritePrebuiltOptions(p.baseLinker, entries) } func (a *apiLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { @@ -653,11 +511,17 @@ func (a *apiHeadersDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *an }) } -func androidMkWriteAllowUndefinedSymbols(linker *baseLinker, entries *android.AndroidMkEntries) { +func androidMkWritePrebuiltOptions(linker *baseLinker, entries *android.AndroidMkEntries) { allow := linker.Properties.Allow_undefined_symbols if allow != nil { entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { entries.SetBool("LOCAL_ALLOW_UNDEFINED_SYMBOLS", *allow) }) } + ignore := linker.Properties.Ignore_max_page_size + if ignore != nil { + entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { + entries.SetBool("LOCAL_IGNORE_MAX_PAGE_SIZE", *ignore) + }) + } } diff --git a/cc/api_level.go b/cc/api_level.go index a5571f31f..69a0d3ae4 100644 --- a/cc/api_level.go +++ b/cc/api_level.go @@ -31,7 +31,11 @@ func MinApiForArch(ctx android.EarlyModuleContext, case android.Arm64, android.X86_64: return android.FirstLp64Version case android.Riscv64: - return android.FutureApiLevel + apiLevel, err := android.ApiLevelFromUser(ctx, "VanillaIceCream") + if err != nil { + panic(err) + } + return apiLevel default: panic(fmt.Errorf("Unknown arch %q", arch)) } diff --git a/cc/binary.go b/cc/binary.go index 097f82252..2ac9a45bc 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -17,13 +17,9 @@ package cc import ( "path/filepath" - "android/soong/bazel/cquery" + "android/soong/android" "github.com/google/blueprint" - "github.com/google/blueprint/proptools" - - "android/soong/android" - "android/soong/bazel" ) type BinaryLinkerProperties struct { @@ -71,14 +67,13 @@ func RegisterBinaryBuildComponents(ctx android.RegistrationContext) { // cc_binary produces a binary that is runnable on a device. func BinaryFactory() android.Module { - module, _ := newBinary(android.HostAndDeviceSupported, true) - module.bazelHandler = &ccBinaryBazelHandler{module: module} + module, _ := newBinary(android.HostAndDeviceSupported) return module.Init() } // cc_binary_host produces a binary that is runnable on a host. func BinaryHostFactory() android.Module { - module, _ := newBinary(android.HostSupported, true) + module, _ := newBinary(android.HostSupported) return module.Init() } @@ -196,10 +191,10 @@ func (binary *binaryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { // Individual module implementations which comprise a C++ binary should call this function, // set some fields on the result, and then call the Init function. func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { - return newBinary(hod, true) + return newBinary(hod) } -func newBinary(hod android.HostOrDeviceSupported, bazelable bool) (*Module, *binaryDecorator) { +func newBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { module := newModule(hod, android.MultilibFirst) binary := &binaryDecorator{ baseLinker: NewBaseLinker(module.sanitize), @@ -208,7 +203,6 @@ func newBinary(hod android.HostOrDeviceSupported, bazelable bool) (*Module, *bin module.compiler = NewBaseCompiler() module.linker = binary module.installer = binary - module.bazelable = bazelable // Allow module to be added as member of an sdk/module_exports. module.sdkMemberTypes = []android.SdkMemberType{ @@ -432,6 +426,10 @@ func (binary *binaryDecorator) link(ctx ModuleContext, validations = append(validations, objs.tidyDepFiles...) linkerDeps = append(linkerDeps, flags.LdFlagsDeps...) + if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil { + deps.StaticLibs = append(deps.StaticLibs, generatedLib) + } + // Register link action. transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true, @@ -452,6 +450,10 @@ func (binary *binaryDecorator) unstrippedOutputFilePath() android.Path { return binary.unstrippedOutputFile } +func (binary *binaryDecorator) strippedAllOutputFilePath() android.Path { + return nil +} + func (binary *binaryDecorator) setSymlinkList(ctx ModuleContext) { for _, symlink := range binary.Properties.Symlinks { binary.symlinks = append(binary.symlinks, @@ -512,7 +514,7 @@ func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) { } binary.baseInstaller.subDir = "bootstrap" } - binary.baseInstaller.installExecutable(ctx, file) + binary.baseInstaller.install(ctx, file) var preferredArchSymlinkPath android.OptionalPath for _, symlink := range binary.symlinks { @@ -544,6 +546,11 @@ func (binary *binaryDecorator) overriddenModules() []string { return binary.Properties.Overrides } +func (binary *binaryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + moduleInfoJSON.Class = []string{"EXECUTABLES"} + binary.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON) +} + var _ overridable = (*binaryDecorator)(nil) func init() { @@ -568,144 +575,3 @@ func (binary *binaryDecorator) verifyHostBionicLinker(ctx ModuleContext, in, lin }, }) } - -type ccBinaryBazelHandler struct { - module *Module -} - -var _ BazelHandler = (*ccBinaryBazelHandler)(nil) - -func (handler *ccBinaryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) { - bazelCtx := ctx.Config().BazelContext - bazelCtx.QueueBazelRequest(label, cquery.GetCcUnstrippedInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx))) -} - -func (handler *ccBinaryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) { - bazelCtx := ctx.Config().BazelContext - info, err := bazelCtx.GetCcUnstrippedInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx))) - if err != nil { - ctx.ModuleErrorf(err.Error()) - return - } - - var outputFilePath android.Path = android.PathForBazelOut(ctx, info.OutputFile) - if len(info.TidyFiles) > 0 { - handler.module.tidyFiles = android.PathsForBazelOut(ctx, info.TidyFiles) - outputFilePath = android.AttachValidationActions(ctx, outputFilePath, handler.module.tidyFiles) - } - handler.module.outputFile = android.OptionalPathForPath(outputFilePath) - handler.module.linker.(*binaryDecorator).unstrippedOutputFile = android.PathForBazelOut(ctx, info.UnstrippedOutput) - - handler.module.setAndroidMkVariablesFromCquery(info.CcAndroidMkInfo) -} - -func binaryBp2buildAttrs(ctx android.TopDownMutatorContext, m *Module) binaryAttributes { - baseAttrs := bp2BuildParseBaseProps(ctx, m) - binaryLinkerAttrs := bp2buildBinaryLinkerProps(ctx, m) - - if proptools.BoolDefault(binaryLinkerAttrs.Linkshared, true) { - baseAttrs.implementationDynamicDeps.Add(baseAttrs.protoDependency) - } else { - baseAttrs.implementationDeps.Add(baseAttrs.protoDependency) - } - - attrs := binaryAttributes{ - binaryLinkerAttrs: binaryLinkerAttrs, - - Srcs: baseAttrs.srcs, - Srcs_c: baseAttrs.cSrcs, - Srcs_as: baseAttrs.asSrcs, - - Copts: baseAttrs.copts, - Cppflags: baseAttrs.cppFlags, - Conlyflags: baseAttrs.conlyFlags, - Asflags: baseAttrs.asFlags, - - Deps: baseAttrs.implementationDeps, - Dynamic_deps: baseAttrs.implementationDynamicDeps, - Whole_archive_deps: baseAttrs.wholeArchiveDeps, - System_deps: baseAttrs.systemDynamicDeps, - Runtime_deps: baseAttrs.runtimeDeps, - - Local_includes: baseAttrs.localIncludes, - Absolute_includes: baseAttrs.absoluteIncludes, - Linkopts: baseAttrs.linkopts, - Use_version_lib: baseAttrs.useVersionLib, - Rtti: baseAttrs.rtti, - Stl: baseAttrs.stl, - Cpp_std: baseAttrs.cppStd, - - Additional_linker_inputs: baseAttrs.additionalLinkerInputs, - - Strip: stripAttributes{ - Keep_symbols: baseAttrs.stripKeepSymbols, - Keep_symbols_and_debug_frame: baseAttrs.stripKeepSymbolsAndDebugFrame, - Keep_symbols_list: baseAttrs.stripKeepSymbolsList, - All: baseAttrs.stripAll, - None: baseAttrs.stripNone, - }, - - Features: baseAttrs.features, - - sdkAttributes: bp2BuildParseSdkAttributes(m), - - Native_coverage: baseAttrs.Native_coverage, - } - - m.convertTidyAttributes(ctx, &attrs.tidyAttributes) - - return attrs -} - -func binaryBp2build(ctx android.TopDownMutatorContext, m *Module) { - // shared with cc_test - binaryAttrs := binaryBp2buildAttrs(ctx, m) - - tags := android.ApexAvailableTags(m) - ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{ - Rule_class: "cc_binary", - Bzl_load_location: "//build/bazel/rules/cc:cc_binary.bzl", - }, - android.CommonAttributes{Name: m.Name(), Tags: tags}, - &binaryAttrs) -} - -// binaryAttributes contains Bazel attributes corresponding to a cc binary -type binaryAttributes struct { - binaryLinkerAttrs - Srcs bazel.LabelListAttribute - Srcs_c bazel.LabelListAttribute - Srcs_as bazel.LabelListAttribute - - Copts bazel.StringListAttribute - Cppflags bazel.StringListAttribute - Conlyflags bazel.StringListAttribute - Asflags bazel.StringListAttribute - - Deps bazel.LabelListAttribute - Dynamic_deps bazel.LabelListAttribute - Whole_archive_deps bazel.LabelListAttribute - System_deps bazel.LabelListAttribute - Runtime_deps bazel.LabelListAttribute - - Local_includes bazel.StringListAttribute - Absolute_includes bazel.StringListAttribute - - Linkopts bazel.StringListAttribute - Additional_linker_inputs bazel.LabelListAttribute - Use_version_lib bazel.BoolAttribute - - Rtti bazel.BoolAttribute - Stl *string - Cpp_std *string - - Strip stripAttributes - - Features bazel.StringListAttribute - - sdkAttributes - - tidyAttributes - - Native_coverage *bool -} diff --git a/cc/binary_test.go b/cc/binary_test.go index 2fac0023b..3e18940fe 100644 --- a/cc/binary_test.go +++ b/cc/binary_test.go @@ -17,89 +17,9 @@ package cc import ( "testing" - "android/soong/bazel/cquery" - "android/soong/android" ) -func TestCcBinaryWithBazel(t *testing.T) { - t.Parallel() - bp := ` -cc_binary { - name: "foo", - srcs: ["foo.cc"], - bazel_module: { label: "//foo/bar:bar" }, -}` - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: "outputbase", - LabelToCcBinary: map[string]cquery.CcUnstrippedInfo{ - "//foo/bar:bar": cquery.CcUnstrippedInfo{ - OutputFile: "foo", - UnstrippedOutput: "foo.unstripped", - }, - }, - } - ctx := testCcWithConfig(t, config) - - binMod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module() - producer := binMod.(android.OutputFileProducer) - outputFiles, err := producer.OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_binary outputfiles %s", err) - } - expectedOutputFiles := []string{"outputbase/execroot/__main__/foo"} - android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings()) - - unStrippedFilePath := binMod.(*Module).UnstrippedOutputFile() - expectedUnStrippedFile := "outputbase/execroot/__main__/foo.unstripped" - android.AssertStringEquals(t, "Unstripped output file", expectedUnStrippedFile, unStrippedFilePath.String()) - - entries := android.AndroidMkEntriesForTest(t, ctx, binMod)[0] - android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_binary", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0]) -} - -func TestCcBinaryWithBazelValidations(t *testing.T) { - t.Parallel() - bp := ` -cc_binary { - name: "foo", - srcs: ["foo.cc"], - bazel_module: { label: "//foo/bar:bar" }, - tidy: true, -}` - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: "outputbase", - LabelToCcBinary: map[string]cquery.CcUnstrippedInfo{ - "//foo/bar:bar": cquery.CcUnstrippedInfo{ - OutputFile: "foo", - UnstrippedOutput: "foo.unstripped", - TidyFiles: []string{"foo.c.tidy"}, - }, - }, - } - ctx := android.GroupFixturePreparers( - prepareForCcTest, - android.FixtureMergeEnv(map[string]string{ - "ALLOW_LOCAL_TIDY_TRUE": "1", - }), - ).RunTestWithConfig(t, config).TestContext - - binMod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module() - producer := binMod.(android.OutputFileProducer) - outputFiles, err := producer.OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_binary outputfiles %s", err) - } - expectedOutputFiles := []string{"out/soong/.intermediates/foo/android_arm64_armv8-a/validated/foo"} - android.AssertPathsRelativeToTopEquals(t, "output files", expectedOutputFiles, outputFiles) - - unStrippedFilePath := binMod.(*Module).UnstrippedOutputFile() - expectedUnStrippedFile := "outputbase/execroot/__main__/foo.unstripped" - android.AssertStringEquals(t, "Unstripped output file", expectedUnStrippedFile, unStrippedFilePath.String()) -} - func TestBinaryLinkerScripts(t *testing.T) { t.Parallel() result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, ` diff --git a/cc/bp2build.go b/cc/bp2build.go deleted file mode 100644 index adf5a08ec..000000000 --- a/cc/bp2build.go +++ /dev/null @@ -1,1554 +0,0 @@ -// 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 ( - "fmt" - "path/filepath" - "strings" - - "android/soong/android" - "android/soong/bazel" - "android/soong/cc/config" - - "github.com/google/blueprint" - - "github.com/google/blueprint/proptools" -) - -const ( - cSrcPartition = "c" - asSrcPartition = "as" - asmSrcPartition = "asm" - lSrcPartition = "l" - llSrcPartition = "ll" - cppSrcPartition = "cpp" - protoSrcPartition = "proto" - aidlSrcPartition = "aidl" - syspropSrcPartition = "sysprop" - - stubsSuffix = "_stub_libs_current" -) - -// staticOrSharedAttributes are the Bazel-ified versions of StaticOrSharedProperties -- -// properties which apply to either the shared or static version of a cc_library module. -type staticOrSharedAttributes struct { - Srcs bazel.LabelListAttribute - Srcs_c bazel.LabelListAttribute - Srcs_as bazel.LabelListAttribute - Srcs_aidl bazel.LabelListAttribute - Hdrs bazel.LabelListAttribute - Copts bazel.StringListAttribute - - Deps bazel.LabelListAttribute - Implementation_deps bazel.LabelListAttribute - Dynamic_deps bazel.LabelListAttribute - Implementation_dynamic_deps bazel.LabelListAttribute - Whole_archive_deps bazel.LabelListAttribute - Implementation_whole_archive_deps bazel.LabelListAttribute - Runtime_deps bazel.LabelListAttribute - - System_dynamic_deps bazel.LabelListAttribute - - Enabled bazel.BoolAttribute - - Native_coverage *bool - - Apex_available []string - - sdkAttributes - - tidyAttributes -} - -type tidyAttributes struct { - Tidy *string - Tidy_flags []string - Tidy_checks []string - Tidy_checks_as_errors []string - Tidy_disabled_srcs bazel.LabelListAttribute - Tidy_timeout_srcs bazel.LabelListAttribute -} - -func (m *Module) convertTidyAttributes(ctx android.BaseMutatorContext, moduleAttrs *tidyAttributes) { - for _, f := range m.features { - if tidy, ok := f.(*tidyFeature); ok { - var tidyAttr *string - if tidy.Properties.Tidy != nil { - if *tidy.Properties.Tidy { - tidyAttr = proptools.StringPtr("local") - } else { - tidyAttr = proptools.StringPtr("never") - } - } - moduleAttrs.Tidy = tidyAttr - moduleAttrs.Tidy_flags = tidy.Properties.Tidy_flags - moduleAttrs.Tidy_checks = tidy.Properties.Tidy_checks - moduleAttrs.Tidy_checks_as_errors = tidy.Properties.Tidy_checks_as_errors - } - - } - archVariantProps := m.GetArchVariantProperties(ctx, &BaseCompilerProperties{}) - for axis, configToProps := range archVariantProps { - for cfg, _props := range configToProps { - if archProps, ok := _props.(*BaseCompilerProperties); ok { - archDisabledSrcs := android.BazelLabelForModuleSrc(ctx, archProps.Tidy_disabled_srcs) - moduleAttrs.Tidy_disabled_srcs.SetSelectValue(axis, cfg, archDisabledSrcs) - archTimeoutSrcs := android.BazelLabelForModuleSrc(ctx, archProps.Tidy_timeout_srcs) - moduleAttrs.Tidy_timeout_srcs.SetSelectValue(axis, cfg, archTimeoutSrcs) - } - } - } -} - -// groupSrcsByExtension partitions `srcs` into groups based on file extension. -func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute { - // Convert filegroup dependencies into extension-specific filegroups filtered in the filegroup.bzl - // macro. - addSuffixForFilegroup := func(suffix string) bazel.LabelMapper { - return func(otherModuleCtx bazel.OtherModuleContext, label bazel.Label) (string, bool) { - - m, exists := otherModuleCtx.ModuleFromName(label.OriginalModuleName) - labelStr := label.Label - if !exists || !android.IsFilegroup(otherModuleCtx, m) { - return labelStr, false - } - // If the filegroup is already converted to aidl_library or proto_library, - // skip creating _c_srcs, _as_srcs, _cpp_srcs filegroups - fg, _ := m.(android.FileGroupAsLibrary) - if fg.ShouldConvertToAidlLibrary(ctx) || fg.ShouldConvertToProtoLibrary(ctx) { - return labelStr, false - } - return labelStr + suffix, true - } - } - - // TODO(b/190006308): Handle language detection of sources in a Bazel rule. - labels := bazel.LabelPartitions{ - protoSrcPartition: android.ProtoSrcLabelPartition, - cSrcPartition: bazel.LabelPartition{Extensions: []string{".c"}, LabelMapper: addSuffixForFilegroup("_c_srcs")}, - asSrcPartition: bazel.LabelPartition{Extensions: []string{".s", ".S"}, LabelMapper: addSuffixForFilegroup("_as_srcs")}, - asmSrcPartition: bazel.LabelPartition{Extensions: []string{".asm"}}, - aidlSrcPartition: android.AidlSrcLabelPartition, - // TODO(http://b/231968910): If there is ever a filegroup target that - // contains .l or .ll files we will need to find a way to add a - // LabelMapper for these that identifies these filegroups and - // converts them appropriately - lSrcPartition: bazel.LabelPartition{Extensions: []string{".l"}}, - llSrcPartition: bazel.LabelPartition{Extensions: []string{".ll"}}, - // C++ is the "catch-all" group, and comprises generated sources because we don't - // know the language of these sources until the genrule is executed. - cppSrcPartition: bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true}, - syspropSrcPartition: bazel.LabelPartition{Extensions: []string{".sysprop"}}, - } - - return bazel.PartitionLabelListAttribute(ctx, &srcs, labels) -} - -// bp2BuildParseLibProps returns the attributes for a variant of a cc_library. -func bp2BuildParseLibProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) staticOrSharedAttributes { - lib, ok := module.compiler.(*libraryDecorator) - if !ok { - return staticOrSharedAttributes{} - } - return bp2buildParseStaticOrSharedProps(ctx, module, lib, isStatic) -} - -// bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library. -func bp2BuildParseSharedProps(ctx android.BazelConversionPathContext, module *Module) staticOrSharedAttributes { - return bp2BuildParseLibProps(ctx, module, false) -} - -// bp2buildParseStaticProps returns the attributes for the static variant of a cc_library. -func bp2BuildParseStaticProps(ctx android.BazelConversionPathContext, module *Module) staticOrSharedAttributes { - return bp2BuildParseLibProps(ctx, module, true) -} - -type depsPartition struct { - export bazel.LabelList - implementation bazel.LabelList -} - -type bazelLabelForDepsFn func(android.BazelConversionPathContext, []string) bazel.LabelList - -func maybePartitionExportedAndImplementationsDeps(ctx android.BazelConversionPathContext, exportsDeps bool, allDeps, exportedDeps []string, fn bazelLabelForDepsFn) depsPartition { - if !exportsDeps { - return depsPartition{ - implementation: fn(ctx, allDeps), - } - } - - implementation, export := android.FilterList(allDeps, exportedDeps) - - return depsPartition{ - export: fn(ctx, export), - implementation: fn(ctx, implementation), - } -} - -type bazelLabelForDepsExcludesFn func(android.BazelConversionPathContext, []string, []string) bazel.LabelList - -func maybePartitionExportedAndImplementationsDepsExcludes(ctx android.BazelConversionPathContext, exportsDeps bool, allDeps, excludes, exportedDeps []string, fn bazelLabelForDepsExcludesFn) depsPartition { - if !exportsDeps { - return depsPartition{ - implementation: fn(ctx, allDeps, excludes), - } - } - implementation, export := android.FilterList(allDeps, exportedDeps) - - return depsPartition{ - export: fn(ctx, export, excludes), - implementation: fn(ctx, implementation, excludes), - } -} - -func bp2BuildPropParseHelper(ctx android.ArchVariantContext, module *Module, propsType interface{}, parseFunc func(axis bazel.ConfigurationAxis, config string, props interface{})) { - for axis, configToProps := range module.GetArchVariantProperties(ctx, propsType) { - for cfg, props := range configToProps { - parseFunc(axis, cfg, props) - } - } -} - -// Parses properties common to static and shared libraries. Also used for prebuilt libraries. -func bp2buildParseStaticOrSharedProps(ctx android.BazelConversionPathContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes { - attrs := staticOrSharedAttributes{} - - setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) { - attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag)) - attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs)) - attrs.System_dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.System_shared_libs)) - - staticDeps := maybePartitionExportedAndImplementationsDeps(ctx, true, props.Static_libs, props.Export_static_lib_headers, bazelLabelForStaticDeps) - attrs.Deps.SetSelectValue(axis, config, staticDeps.export) - attrs.Implementation_deps.SetSelectValue(axis, config, staticDeps.implementation) - - sharedDeps := maybePartitionExportedAndImplementationsDeps(ctx, true, props.Shared_libs, props.Export_shared_lib_headers, bazelLabelForSharedDeps) - attrs.Dynamic_deps.SetSelectValue(axis, config, sharedDeps.export) - attrs.Implementation_dynamic_deps.SetSelectValue(axis, config, sharedDeps.implementation) - - attrs.Whole_archive_deps.SetSelectValue(axis, config, bazelLabelForWholeDeps(ctx, props.Whole_static_libs)) - attrs.Enabled.SetSelectValue(axis, config, props.Enabled) - } - // system_dynamic_deps distinguishes between nil/empty list behavior: - // nil -> use default values - // empty list -> no values specified - attrs.System_dynamic_deps.ForceSpecifyEmptyList = true - - var apexAvailable []string - if isStatic { - apexAvailable = lib.StaticProperties.Static.Apex_available - bp2BuildPropParseHelper(ctx, module, &StaticProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - if staticOrSharedProps, ok := props.(*StaticProperties); ok { - setAttrs(axis, config, staticOrSharedProps.Static) - } - }) - } else { - apexAvailable = lib.SharedProperties.Shared.Apex_available - bp2BuildPropParseHelper(ctx, module, &SharedProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - if staticOrSharedProps, ok := props.(*SharedProperties); ok { - setAttrs(axis, config, staticOrSharedProps.Shared) - } - }) - } - - partitionedSrcs := groupSrcsByExtension(ctx, attrs.Srcs) - attrs.Srcs = partitionedSrcs[cppSrcPartition] - attrs.Srcs_c = partitionedSrcs[cSrcPartition] - attrs.Srcs_as = partitionedSrcs[asSrcPartition] - - attrs.Apex_available = android.ConvertApexAvailableToTags(apexAvailable) - - if !partitionedSrcs[protoSrcPartition].IsEmpty() { - // TODO(b/208815215): determine whether this is used and add support if necessary - ctx.ModuleErrorf("Migrating static/shared only proto srcs is not currently supported") - } - - return attrs -} - -// Convenience struct to hold all attributes parsed from prebuilt properties. -type prebuiltAttributes struct { - Src bazel.LabelAttribute - Enabled bazel.BoolAttribute -} - -func parseSrc(ctx android.BazelConversionPathContext, srcLabelAttribute *bazel.LabelAttribute, axis bazel.ConfigurationAxis, config string, srcs []string) { - srcFileError := func() { - ctx.ModuleErrorf("parseSrc: Expected at most one source file for %s %s\n", axis, config) - } - if len(srcs) > 1 { - srcFileError() - return - } else if len(srcs) == 0 { - return - } - if srcLabelAttribute.SelectValue(axis, config) != nil { - srcFileError() - return - } - srcLabelAttribute.SetSelectValue(axis, config, android.BazelLabelForModuleSrcSingle(ctx, srcs[0])) -} - -// NOTE: Used outside of Soong repo project, in the clangprebuilts.go bootstrap_go_package -func Bp2BuildParsePrebuiltLibraryProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) prebuiltAttributes { - - var srcLabelAttribute bazel.LabelAttribute - bp2BuildPropParseHelper(ctx, module, &prebuiltLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - if prebuiltLinkerProperties, ok := props.(*prebuiltLinkerProperties); ok { - parseSrc(ctx, &srcLabelAttribute, axis, config, prebuiltLinkerProperties.Srcs) - } - }) - - var enabledLabelAttribute bazel.BoolAttribute - parseAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) { - if props.Enabled != nil { - enabledLabelAttribute.SetSelectValue(axis, config, props.Enabled) - } - parseSrc(ctx, &srcLabelAttribute, axis, config, props.Srcs) - } - - if isStatic { - bp2BuildPropParseHelper(ctx, module, &StaticProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - if staticProperties, ok := props.(*StaticProperties); ok { - parseAttrs(axis, config, staticProperties.Static) - } - }) - } else { - bp2BuildPropParseHelper(ctx, module, &SharedProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - if sharedProperties, ok := props.(*SharedProperties); ok { - parseAttrs(axis, config, sharedProperties.Shared) - } - }) - } - - return prebuiltAttributes{ - Src: srcLabelAttribute, - Enabled: enabledLabelAttribute, - } -} - -func bp2BuildParsePrebuiltBinaryProps(ctx android.BazelConversionPathContext, module *Module) prebuiltAttributes { - var srcLabelAttribute bazel.LabelAttribute - bp2BuildPropParseHelper(ctx, module, &prebuiltLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - if props, ok := props.(*prebuiltLinkerProperties); ok { - parseSrc(ctx, &srcLabelAttribute, axis, config, props.Srcs) - } - }) - - return prebuiltAttributes{ - Src: srcLabelAttribute, - } -} - -func bp2BuildParsePrebuiltObjectProps(ctx android.BazelConversionPathContext, module *Module) prebuiltAttributes { - var srcLabelAttribute bazel.LabelAttribute - bp2BuildPropParseHelper(ctx, module, &prebuiltObjectProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - if props, ok := props.(*prebuiltObjectProperties); ok { - parseSrc(ctx, &srcLabelAttribute, axis, config, props.Srcs) - } - }) - - return prebuiltAttributes{ - Src: srcLabelAttribute, - } -} - -type baseAttributes struct { - compilerAttributes - linkerAttributes - - // A combination of compilerAttributes.features and linkerAttributes.features, as well as sanitizer features - features bazel.StringListAttribute - protoDependency *bazel.LabelAttribute - aidlDependency *bazel.LabelAttribute - Native_coverage *bool -} - -// Convenience struct to hold all attributes parsed from compiler properties. -type compilerAttributes struct { - // Options for all languages - copts bazel.StringListAttribute - // Assembly options and sources - asFlags bazel.StringListAttribute - asSrcs bazel.LabelListAttribute - asmSrcs bazel.LabelListAttribute - // C options and sources - conlyFlags bazel.StringListAttribute - cSrcs bazel.LabelListAttribute - // C++ options and sources - cppFlags bazel.StringListAttribute - srcs bazel.LabelListAttribute - - // Lex sources and options - lSrcs bazel.LabelListAttribute - llSrcs bazel.LabelListAttribute - lexopts bazel.StringListAttribute - - // Sysprop sources - syspropSrcs bazel.LabelListAttribute - - hdrs bazel.LabelListAttribute - - rtti bazel.BoolAttribute - - // Not affected by arch variants - stl *string - cStd *string - cppStd *string - - localIncludes bazel.StringListAttribute - absoluteIncludes bazel.StringListAttribute - - includes BazelIncludes - - protoSrcs bazel.LabelListAttribute - aidlSrcs bazel.LabelListAttribute - - stubsSymbolFile *string - stubsVersions bazel.StringListAttribute - - features bazel.StringListAttribute - - suffix bazel.StringAttribute - - fdoProfile bazel.LabelAttribute -} - -type filterOutFn func(string) bool - -func filterOutStdFlag(flag string) bool { - return strings.HasPrefix(flag, "-std=") -} - -func filterOutClangUnknownCflags(flag string) bool { - for _, f := range config.ClangUnknownCflags { - if f == flag { - return true - } - } - return false -} - -func parseCommandLineFlags(soongFlags []string, filterOut ...filterOutFn) []string { - var result []string - for _, flag := range soongFlags { - skipFlag := false - for _, filter := range filterOut { - if filter != nil && filter(flag) { - skipFlag = true - } - } - if skipFlag { - continue - } - // Soong's cflags can contain spaces, like `-include header.h`. For - // Bazel's copts, split them up to be compatible with the - // no_copts_tokenization feature. - result = append(result, strings.Split(flag, " ")...) - } - return result -} - -func (ca *compilerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, config string, props *BaseCompilerProperties) { - // If there's arch specific srcs or exclude_srcs, generate a select entry for it. - // TODO(b/186153868): do this for OS specific srcs and exclude_srcs too. - if srcsList, ok := parseSrcs(ctx, props); ok { - ca.srcs.SetSelectValue(axis, config, srcsList) - } - - localIncludeDirs := props.Local_include_dirs - if axis == bazel.NoConfigAxis { - ca.cStd, ca.cppStd = bp2buildResolveCppStdValue(props.C_std, props.Cpp_std, props.Gnu_extensions) - if includeBuildDirectory(props.Include_build_directory) { - localIncludeDirs = append(localIncludeDirs, ".") - } - } - - ca.absoluteIncludes.SetSelectValue(axis, config, props.Include_dirs) - ca.localIncludes.SetSelectValue(axis, config, localIncludeDirs) - - instructionSet := proptools.StringDefault(props.Instruction_set, "") - if instructionSet == "arm" { - ca.features.SetSelectValue(axis, config, []string{"arm_isa_arm", "-arm_isa_thumb"}) - } else if instructionSet != "" && instructionSet != "thumb" { - ctx.ModuleErrorf("Unknown value for instruction_set: %s", instructionSet) - } - - // In Soong, cflags occur on the command line before -std=<val> flag, resulting in the value being - // overridden. In Bazel we always allow overriding, via flags; however, this can cause - // incompatibilities, so we remove "-std=" flags from Cflag properties while leaving it in other - // cases. - ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag, filterOutClangUnknownCflags)) - ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags, nil)) - ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags, filterOutClangUnknownCflags)) - ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags, filterOutClangUnknownCflags)) - ca.rtti.SetSelectValue(axis, config, props.Rtti) -} - -func (ca *compilerAttributes) convertStlProps(ctx android.ArchVariantContext, module *Module) { - bp2BuildPropParseHelper(ctx, module, &StlProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - if stlProps, ok := props.(*StlProperties); ok { - if stlProps.Stl == nil { - return - } - if ca.stl == nil { - stl := deduplicateStlInput(*stlProps.Stl) - ca.stl = &stl - } else if ca.stl != stlProps.Stl { - ctx.ModuleErrorf("Unsupported conversion: module with different stl for different variants: %s and %s", *ca.stl, stlProps.Stl) - } - } - }) -} - -func (ca *compilerAttributes) convertProductVariables(ctx android.BazelConversionPathContext, productVariableProps android.ProductConfigProperties) { - productVarPropNameToAttribute := map[string]*bazel.StringListAttribute{ - "Cflags": &ca.copts, - "Asflags": &ca.asFlags, - "Cppflags": &ca.cppFlags, - } - for propName, attr := range productVarPropNameToAttribute { - if productConfigProps, exists := productVariableProps[propName]; exists { - for productConfigProp, prop := range productConfigProps { - flags, ok := prop.([]string) - if !ok { - ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName)) - } - newFlags, _ := bazel.TryVariableSubstitutions(flags, productConfigProp.Name) - attr.SetSelectValue(productConfigProp.ConfigurationAxis(), productConfigProp.SelectKey(), newFlags) - } - } - } -} - -func (ca *compilerAttributes) finalize(ctx android.BazelConversionPathContext, implementationHdrs bazel.LabelListAttribute) { - ca.srcs.ResolveExcludes() - partitionedSrcs := groupSrcsByExtension(ctx, ca.srcs) - - ca.protoSrcs = partitionedSrcs[protoSrcPartition] - ca.aidlSrcs = partitionedSrcs[aidlSrcPartition] - - for p, lla := range partitionedSrcs { - // if there are no sources, there is no need for headers - if lla.IsEmpty() { - continue - } - lla.Append(implementationHdrs) - partitionedSrcs[p] = lla - } - - ca.srcs = partitionedSrcs[cppSrcPartition] - ca.cSrcs = partitionedSrcs[cSrcPartition] - ca.asSrcs = partitionedSrcs[asSrcPartition] - ca.asmSrcs = partitionedSrcs[asmSrcPartition] - ca.lSrcs = partitionedSrcs[lSrcPartition] - ca.llSrcs = partitionedSrcs[llSrcPartition] - ca.syspropSrcs = partitionedSrcs[syspropSrcPartition] - - ca.absoluteIncludes.DeduplicateAxesFromBase() - ca.localIncludes.DeduplicateAxesFromBase() -} - -// Parse srcs from an arch or OS's props value. -func parseSrcs(ctx android.BazelConversionPathContext, props *BaseCompilerProperties) (bazel.LabelList, bool) { - anySrcs := false - // Add srcs-like dependencies such as generated files. - // First create a LabelList containing these dependencies, then merge the values with srcs. - generatedSrcsLabelList := android.BazelLabelForModuleDepsExcludes(ctx, props.Generated_sources, props.Exclude_generated_sources) - if len(props.Generated_sources) > 0 || len(props.Exclude_generated_sources) > 0 { - anySrcs = true - } - - allSrcsLabelList := android.BazelLabelForModuleSrcExcludes(ctx, props.Srcs, props.Exclude_srcs) - - if len(props.Srcs) > 0 || len(props.Exclude_srcs) > 0 { - anySrcs = true - } - - return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedSrcsLabelList), anySrcs -} - -func bp2buildStdVal(std *string, prefix string, useGnu bool) *string { - defaultVal := prefix + "_std_default" - // If c{,pp}std properties are not specified, don't generate them in the BUILD file. - // Defaults are handled by the toolchain definition. - // However, if gnu_extensions is false, then the default gnu-to-c version must be specified. - stdVal := proptools.StringDefault(std, defaultVal) - if stdVal == "experimental" || stdVal == defaultVal { - if stdVal == "experimental" { - stdVal = prefix + "_std_experimental" - } - if !useGnu { - stdVal += "_no_gnu" - } - } else if !useGnu { - stdVal = gnuToCReplacer.Replace(stdVal) - } - - if stdVal == defaultVal { - return nil - } - return &stdVal -} - -func bp2buildResolveCppStdValue(c_std *string, cpp_std *string, gnu_extensions *bool) (*string, *string) { - useGnu := useGnuExtensions(gnu_extensions) - - return bp2buildStdVal(c_std, "c", useGnu), bp2buildStdVal(cpp_std, "cpp", useGnu) -} - -// packageFromLabel extracts package from a fully-qualified or relative Label and whether the label -// is fully-qualified. -// e.g. fully-qualified "//a/b:foo" -> "a/b", true, relative: ":bar" -> ".", false -func packageFromLabel(label string) (string, bool) { - split := strings.Split(label, ":") - if len(split) != 2 { - return "", false - } - if split[0] == "" { - return ".", false - } - // remove leading "//" - return split[0][2:], true -} - -// includesFromLabelList extracts relative/absolute includes from a bazel.LabelList> -func includesFromLabelList(labelList bazel.LabelList) (relative, absolute []string) { - for _, hdr := range labelList.Includes { - if pkg, hasPkg := packageFromLabel(hdr.Label); hasPkg { - absolute = append(absolute, pkg) - } else if pkg != "" { - relative = append(relative, pkg) - } - } - return relative, absolute -} - -type YasmAttributes struct { - Srcs bazel.LabelListAttribute - Flags bazel.StringListAttribute - Include_dirs bazel.StringListAttribute -} - -func bp2BuildYasm(ctx android.Bp2buildMutatorContext, m *Module, ca compilerAttributes) *bazel.LabelAttribute { - if ca.asmSrcs.IsEmpty() { - return nil - } - - // Yasm needs the include directories from both local_includes and - // export_include_dirs. We don't care about actually exporting them from the - // yasm rule though, because they will also be present on the cc_ rule that - // wraps this yasm rule. - includes := ca.localIncludes.Clone() - bp2BuildPropParseHelper(ctx, m, &FlagExporterProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - if flagExporterProperties, ok := props.(*FlagExporterProperties); ok { - if len(flagExporterProperties.Export_include_dirs) > 0 { - x := bazel.StringListAttribute{} - x.SetSelectValue(axis, config, flagExporterProperties.Export_include_dirs) - includes.Append(x) - } - } - }) - - ctx.CreateBazelTargetModule( - bazel.BazelTargetModuleProperties{ - Rule_class: "yasm", - Bzl_load_location: "//build/bazel/rules/cc:yasm.bzl", - }, - android.CommonAttributes{Name: m.Name() + "_yasm"}, - &YasmAttributes{ - Srcs: ca.asmSrcs, - Flags: ca.asFlags, - Include_dirs: *includes, - }) - - // We only want to add a dependency on the _yasm target if there are asm - // sources in the current configuration. If there are unconfigured asm - // sources, always add the dependency. Otherwise, add the dependency only - // on the configuration axes and values that had asm sources. - if len(ca.asmSrcs.Value.Includes) > 0 { - return bazel.MakeLabelAttribute(":" + m.Name() + "_yasm") - } - - ret := &bazel.LabelAttribute{} - for _, axis := range ca.asmSrcs.SortedConfigurationAxes() { - for cfg := range ca.asmSrcs.ConfigurableValues[axis] { - ret.SetSelectValue(axis, cfg, bazel.Label{Label: ":" + m.Name() + "_yasm"}) - } - } - return ret -} - -// bp2BuildParseBaseProps returns all compiler, linker, library attributes of a cc module.. -func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) baseAttributes { - archVariantCompilerProps := module.GetArchVariantProperties(ctx, &BaseCompilerProperties{}) - archVariantLinkerProps := module.GetArchVariantProperties(ctx, &BaseLinkerProperties{}) - archVariantLibraryProperties := module.GetArchVariantProperties(ctx, &LibraryProperties{}) - - var implementationHdrs bazel.LabelListAttribute - - axisToConfigs := map[bazel.ConfigurationAxis]map[string]bool{} - allAxesAndConfigs := func(cp android.ConfigurationAxisToArchVariantProperties) { - for axis, configMap := range cp { - if _, ok := axisToConfigs[axis]; !ok { - axisToConfigs[axis] = map[string]bool{} - } - for cfg := range configMap { - axisToConfigs[axis][cfg] = true - } - } - } - allAxesAndConfigs(archVariantCompilerProps) - allAxesAndConfigs(archVariantLinkerProps) - allAxesAndConfigs(archVariantLibraryProperties) - - compilerAttrs := compilerAttributes{} - linkerAttrs := linkerAttributes{} - - // Iterate through these axes in a deterministic order. This is required - // because processing certain dependencies may result in concatenating - // elements along other axes. (For example, processing NoConfig may result - // in elements being added to InApex). This is thus the only way to ensure - // that the order of entries in each list is in a predictable order. - for _, axis := range bazel.SortedConfigurationAxes(axisToConfigs) { - configs := axisToConfigs[axis] - for cfg := range configs { - var allHdrs []string - if baseCompilerProps, ok := archVariantCompilerProps[axis][cfg].(*BaseCompilerProperties); ok { - allHdrs = baseCompilerProps.Generated_headers - if baseCompilerProps.Lex != nil { - compilerAttrs.lexopts.SetSelectValue(axis, cfg, baseCompilerProps.Lex.Flags) - } - (&compilerAttrs).bp2buildForAxisAndConfig(ctx, axis, cfg, baseCompilerProps) - } - - var exportHdrs []string - - if baseLinkerProps, ok := archVariantLinkerProps[axis][cfg].(*BaseLinkerProperties); ok { - exportHdrs = baseLinkerProps.Export_generated_headers - - (&linkerAttrs).bp2buildForAxisAndConfig(ctx, module, axis, cfg, baseLinkerProps) - } - headers := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrs, exportHdrs, android.BazelLabelForModuleDeps) - implementationHdrs.SetSelectValue(axis, cfg, headers.implementation) - compilerAttrs.hdrs.SetSelectValue(axis, cfg, headers.export) - - exportIncludes, exportAbsoluteIncludes := includesFromLabelList(headers.export) - compilerAttrs.includes.Includes.SetSelectValue(axis, cfg, exportIncludes) - compilerAttrs.includes.AbsoluteIncludes.SetSelectValue(axis, cfg, exportAbsoluteIncludes) - - includes, absoluteIncludes := includesFromLabelList(headers.implementation) - currAbsoluteIncludes := compilerAttrs.absoluteIncludes.SelectValue(axis, cfg) - currAbsoluteIncludes = android.FirstUniqueStrings(append(currAbsoluteIncludes, absoluteIncludes...)) - - compilerAttrs.absoluteIncludes.SetSelectValue(axis, cfg, currAbsoluteIncludes) - - currIncludes := compilerAttrs.localIncludes.SelectValue(axis, cfg) - currIncludes = android.FirstUniqueStrings(append(currIncludes, includes...)) - - compilerAttrs.localIncludes.SetSelectValue(axis, cfg, currIncludes) - - if libraryProps, ok := archVariantLibraryProperties[axis][cfg].(*LibraryProperties); ok { - if axis == bazel.NoConfigAxis { - if libraryProps.Stubs.Symbol_file != nil { - compilerAttrs.stubsSymbolFile = libraryProps.Stubs.Symbol_file - versions := android.CopyOf(libraryProps.Stubs.Versions) - normalizeVersions(ctx, versions) - versions = addCurrentVersionIfNotPresent(versions) - compilerAttrs.stubsVersions.SetSelectValue(axis, cfg, versions) - } - } - if suffix := libraryProps.Suffix; suffix != nil { - compilerAttrs.suffix.SetSelectValue(axis, cfg, suffix) - } - } - } - } - - compilerAttrs.convertStlProps(ctx, module) - (&linkerAttrs).convertStripProps(ctx, module) - - var nativeCoverage *bool - if module.coverage != nil && module.coverage.Properties.Native_coverage != nil && - !Bool(module.coverage.Properties.Native_coverage) { - nativeCoverage = BoolPtr(false) - } - - productVariableProps := android.ProductVariableProperties(ctx, ctx.Module()) - - (&compilerAttrs).convertProductVariables(ctx, productVariableProps) - (&linkerAttrs).convertProductVariables(ctx, productVariableProps) - - (&compilerAttrs).finalize(ctx, implementationHdrs) - (&linkerAttrs).finalize(ctx) - - (&compilerAttrs.srcs).Add(bp2BuildYasm(ctx, module, compilerAttrs)) - - protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs) - - // bp2buildProto will only set wholeStaticLib or implementationWholeStaticLib, but we don't know - // which. This will add the newly generated proto library to the appropriate attribute and nothing - // to the other - (&linkerAttrs).wholeArchiveDeps.Add(protoDep.wholeStaticLib) - (&linkerAttrs).implementationWholeArchiveDeps.Add(protoDep.implementationWholeStaticLib) - - aidlDep := bp2buildCcAidlLibrary(ctx, module, compilerAttrs.aidlSrcs, linkerAttrs) - if aidlDep != nil { - if lib, ok := module.linker.(*libraryDecorator); ok { - if proptools.Bool(lib.Properties.Aidl.Export_aidl_headers) { - (&linkerAttrs).wholeArchiveDeps.Add(aidlDep) - } else { - (&linkerAttrs).implementationWholeArchiveDeps.Add(aidlDep) - } - } - } - - convertedLSrcs := bp2BuildLex(ctx, module.Name(), compilerAttrs) - (&compilerAttrs).srcs.Add(&convertedLSrcs.srcName) - (&compilerAttrs).cSrcs.Add(&convertedLSrcs.cSrcName) - - if module.afdo != nil && module.afdo.Properties.Afdo { - fdoProfileDep := bp2buildFdoProfile(ctx, module) - if fdoProfileDep != nil { - (&compilerAttrs).fdoProfile.SetValue(*fdoProfileDep) - } - } - - if !compilerAttrs.syspropSrcs.IsEmpty() { - (&linkerAttrs).wholeArchiveDeps.Add(bp2buildCcSysprop(ctx, module.Name(), module.Properties.Min_sdk_version, compilerAttrs.syspropSrcs)) - } - - linkerAttrs.wholeArchiveDeps.Prepend = true - linkerAttrs.deps.Prepend = true - compilerAttrs.localIncludes.Prepend = true - compilerAttrs.absoluteIncludes.Prepend = true - compilerAttrs.hdrs.Prepend = true - - features := compilerAttrs.features.Clone().Append(linkerAttrs.features).Append(bp2buildSanitizerFeatures(ctx, module)) - features = features.Append(bp2buildLtoFeatures(ctx, module)) - features.DeduplicateAxesFromBase() - - addMuslSystemDynamicDeps(ctx, linkerAttrs) - - return baseAttributes{ - compilerAttrs, - linkerAttrs, - *features, - protoDep.protoDep, - aidlDep, - nativeCoverage, - } -} - -// As a workaround for b/261657184, we are manually adding the default value -// of system_dynamic_deps for the linux_musl os. -// TODO: Solve this properly -func addMuslSystemDynamicDeps(ctx android.Bp2buildMutatorContext, attrs linkerAttributes) { - systemDynamicDeps := attrs.systemDynamicDeps.SelectValue(bazel.OsConfigurationAxis, "linux_musl") - if attrs.systemDynamicDeps.HasAxisSpecificValues(bazel.OsConfigurationAxis) && systemDynamicDeps.IsNil() { - attrs.systemDynamicDeps.SetSelectValue(bazel.OsConfigurationAxis, "linux_musl", android.BazelLabelForModuleDeps(ctx, config.MuslDefaultSharedLibraries)) - } -} - -type fdoProfileAttributes struct { - Absolute_path_profile string -} - -func bp2buildFdoProfile( - ctx android.Bp2buildMutatorContext, - m *Module, -) *bazel.Label { - for _, project := range globalAfdoProfileProjects { - // Ensure handcrafted BUILD file exists in the project - BUILDPath := android.ExistentPathForSource(ctx, project, "BUILD") - if BUILDPath.Valid() { - // We handcraft a BUILD file with fdo_profile targets that use the existing profiles in the project - // This implementation is assuming that every afdo profile in globalAfdoProfileProjects already has - // an associated fdo_profile target declared in the same package. - // TODO(b/260714900): Handle arch-specific afdo profiles (e.g. `<module-name>-arm<64>.afdo`) - path := android.ExistentPathForSource(ctx, project, m.Name()+".afdo") - if path.Valid() { - // FIXME: Some profiles only exist internally and are not released to AOSP. - // When generated BUILD files are checked in, we'll run into merge conflict. - // The cc_library_shared target in AOSP won't have reference to an fdo_profile target because - // the profile doesn't exist. Internally, the same cc_library_shared target will - // have reference to the fdo_profile. - // For more context, see b/258682955#comment2 - fdoProfileLabel := "//" + strings.TrimSuffix(project, "/") + ":" + m.Name() - return &bazel.Label{ - Label: fdoProfileLabel, - } - } - } - } - - return nil -} - -func bp2buildCcAidlLibrary( - ctx android.Bp2buildMutatorContext, - m *Module, - aidlLabelList bazel.LabelListAttribute, - linkerAttrs linkerAttributes, -) *bazel.LabelAttribute { - if !aidlLabelList.IsEmpty() { - aidlLibs, aidlSrcs := aidlLabelList.Partition(func(src bazel.Label) bool { - if fg, ok := android.ToFileGroupAsLibrary(ctx, src.OriginalModuleName); ok && - fg.ShouldConvertToAidlLibrary(ctx) { - return true - } - return false - }) - - apexAvailableTags := android.ApexAvailableTags(ctx.Module()) - sdkAttrs := bp2BuildParseSdkAttributes(m) - - if !aidlSrcs.IsEmpty() { - aidlLibName := m.Name() + "_aidl_library" - ctx.CreateBazelTargetModule( - bazel.BazelTargetModuleProperties{ - Rule_class: "aidl_library", - Bzl_load_location: "//build/bazel/rules/aidl:aidl_library.bzl", - }, - android.CommonAttributes{Name: aidlLibName}, - &aidlLibraryAttributes{ - Srcs: aidlSrcs, - Tags: apexAvailableTags, - }, - ) - aidlLibs.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + aidlLibName}}) - } - - if !aidlLibs.IsEmpty() { - ccAidlLibrarylabel := m.Name() + "_cc_aidl_library" - // Since parent cc_library already has these dependencies, we can add them as implementation - // deps so that they don't re-export - implementationDeps := linkerAttrs.deps.Clone() - implementationDeps.Append(linkerAttrs.implementationDeps) - implementationDynamicDeps := linkerAttrs.dynamicDeps.Clone() - implementationDynamicDeps.Append(linkerAttrs.implementationDynamicDeps) - - ctx.CreateBazelTargetModule( - bazel.BazelTargetModuleProperties{ - Rule_class: "cc_aidl_library", - Bzl_load_location: "//build/bazel/rules/cc:cc_aidl_library.bzl", - }, - android.CommonAttributes{Name: ccAidlLibrarylabel}, - &ccAidlLibraryAttributes{ - Deps: aidlLibs, - Implementation_deps: *implementationDeps, - Implementation_dynamic_deps: *implementationDynamicDeps, - Tags: apexAvailableTags, - sdkAttributes: sdkAttrs, - }, - ) - label := &bazel.LabelAttribute{ - Value: &bazel.Label{ - Label: ":" + ccAidlLibrarylabel, - }, - } - return label - } - } - - return nil -} - -func bp2BuildParseSdkAttributes(module *Module) sdkAttributes { - return sdkAttributes{ - Sdk_version: module.Properties.Sdk_version, - Min_sdk_version: module.Properties.Min_sdk_version, - } -} - -type sdkAttributes struct { - Sdk_version *string - Min_sdk_version *string -} - -// Convenience struct to hold all attributes parsed from linker properties. -type linkerAttributes struct { - deps bazel.LabelListAttribute - implementationDeps bazel.LabelListAttribute - dynamicDeps bazel.LabelListAttribute - implementationDynamicDeps bazel.LabelListAttribute - runtimeDeps bazel.LabelListAttribute - wholeArchiveDeps bazel.LabelListAttribute - implementationWholeArchiveDeps bazel.LabelListAttribute - systemDynamicDeps bazel.LabelListAttribute - usedSystemDynamicDepAsDynamicDep map[string]bool - - useVersionLib bazel.BoolAttribute - linkopts bazel.StringListAttribute - additionalLinkerInputs bazel.LabelListAttribute - stripKeepSymbols bazel.BoolAttribute - stripKeepSymbolsAndDebugFrame bazel.BoolAttribute - stripKeepSymbolsList bazel.StringListAttribute - stripAll bazel.BoolAttribute - stripNone bazel.BoolAttribute - features bazel.StringListAttribute -} - -var ( - soongSystemSharedLibs = []string{"libc", "libm", "libdl"} - versionLib = "libbuildversion" -) - -// resolveTargetApex re-adds the shared and static libs in target.apex.exclude_shared|static_libs props to non-apex variant -// since all libs are already excluded by default -func (la *linkerAttributes) resolveTargetApexProp(ctx android.BazelConversionPathContext, props *BaseLinkerProperties) { - excludeSharedLibs := bazelLabelForSharedDeps(ctx, props.Target.Apex.Exclude_shared_libs) - sharedExcludes := bazel.LabelList{Excludes: excludeSharedLibs.Includes} - sharedExcludesLabelList := bazel.LabelListAttribute{} - sharedExcludesLabelList.SetSelectValue(bazel.InApexAxis, bazel.InApex, sharedExcludes) - - la.dynamicDeps.Append(sharedExcludesLabelList) - la.implementationDynamicDeps.Append(sharedExcludesLabelList) - - excludeStaticLibs := bazelLabelForStaticDeps(ctx, props.Target.Apex.Exclude_static_libs) - staticExcludes := bazel.LabelList{Excludes: excludeStaticLibs.Includes} - staticExcludesLabelList := bazel.LabelListAttribute{} - staticExcludesLabelList.SetSelectValue(bazel.InApexAxis, bazel.InApex, staticExcludes) - - la.deps.Append(staticExcludesLabelList) - la.implementationDeps.Append(staticExcludesLabelList) -} - -func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, module *Module, axis bazel.ConfigurationAxis, config string, props *BaseLinkerProperties) { - isBinary := module.Binary() - // Use a single variable to capture usage of nocrt in arch variants, so there's only 1 error message for this module - var axisFeatures []string - - wholeStaticLibs := android.FirstUniqueStrings(props.Whole_static_libs) - staticLibs := android.FirstUniqueStrings(android.RemoveListFromList(props.Static_libs, wholeStaticLibs)) - if axis == bazel.NoConfigAxis { - la.useVersionLib.SetSelectValue(axis, config, props.Use_version_lib) - if proptools.Bool(props.Use_version_lib) { - versionLibAlreadyInDeps := android.InList(versionLib, wholeStaticLibs) - // remove from static libs so there is no duplicate dependency - _, staticLibs = android.RemoveFromList(versionLib, staticLibs) - // only add the dep if it is not in progress - if !versionLibAlreadyInDeps { - if isBinary { - wholeStaticLibs = append(wholeStaticLibs, versionLib) - } else { - la.implementationWholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, []string{versionLib}, props.Exclude_static_libs)) - } - } - } - } - - // Excludes to parallel Soong: - // https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=247-249;drc=088b53577dde6e40085ffd737a1ae96ad82fc4b0 - la.wholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, wholeStaticLibs, props.Exclude_static_libs)) - - staticDeps := maybePartitionExportedAndImplementationsDepsExcludes( - ctx, - !isBinary, - staticLibs, - props.Exclude_static_libs, - props.Export_static_lib_headers, - bazelLabelForStaticDepsExcludes, - ) - - headerLibs := android.FirstUniqueStrings(props.Header_libs) - hDeps := maybePartitionExportedAndImplementationsDeps(ctx, !isBinary, headerLibs, props.Export_header_lib_headers, bazelLabelForHeaderDeps) - - (&hDeps.export).Append(staticDeps.export) - la.deps.SetSelectValue(axis, config, hDeps.export) - - (&hDeps.implementation).Append(staticDeps.implementation) - la.implementationDeps.SetSelectValue(axis, config, hDeps.implementation) - - systemSharedLibs := props.System_shared_libs - // systemSharedLibs distinguishes between nil/empty list behavior: - // nil -> use default values - // empty list -> no values specified - if len(systemSharedLibs) > 0 { - systemSharedLibs = android.FirstUniqueStrings(systemSharedLibs) - } - la.systemDynamicDeps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, systemSharedLibs)) - - sharedLibs := android.FirstUniqueStrings(props.Shared_libs) - excludeSharedLibs := props.Exclude_shared_libs - usedSystem := android.FilterListPred(sharedLibs, func(s string) bool { - return android.InList(s, soongSystemSharedLibs) && !android.InList(s, excludeSharedLibs) - }) - for _, el := range usedSystem { - if la.usedSystemDynamicDepAsDynamicDep == nil { - la.usedSystemDynamicDepAsDynamicDep = map[string]bool{} - } - la.usedSystemDynamicDepAsDynamicDep[el] = true - } - - sharedDeps := maybePartitionExportedAndImplementationsDepsExcludes( - ctx, - !isBinary, - sharedLibs, - props.Exclude_shared_libs, - props.Export_shared_lib_headers, - bazelLabelForSharedDepsExcludes, - ) - la.dynamicDeps.SetSelectValue(axis, config, sharedDeps.export) - la.implementationDynamicDeps.SetSelectValue(axis, config, sharedDeps.implementation) - la.resolveTargetApexProp(ctx, props) - - if axis == bazel.NoConfigAxis || (axis == bazel.OsConfigurationAxis && config == bazel.OsAndroid) { - // If a dependency in la.implementationDynamicDeps or la.dynamicDeps has stubs, its - // stub variant should be used when the dependency is linked in a APEX. The - // dependencies in NoConfigAxis and OsConfigurationAxis/OsAndroid are grouped by - // having stubs or not, so Bazel select() statement can be used to choose - // source/stub variants of them. - apexAvailable := module.ApexAvailable() - setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0) - setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1) - } - - if !BoolDefault(props.Pack_relocations, packRelocationsDefault) { - axisFeatures = append(axisFeatures, "disable_pack_relocations") - } - - if Bool(props.Allow_undefined_symbols) { - axisFeatures = append(axisFeatures, "-no_undefined_symbols") - } - - var linkerFlags []string - if len(props.Ldflags) > 0 { - linkerFlags = append(linkerFlags, proptools.NinjaEscapeList(props.Ldflags)...) - // binaries remove static flag if -shared is in the linker flags - if isBinary && android.InList("-shared", linkerFlags) { - axisFeatures = append(axisFeatures, "-static_flag") - } - } - - if !props.libCrt() { - axisFeatures = append(axisFeatures, "-use_libcrt") - } - if !props.crt() { - axisFeatures = append(axisFeatures, "-link_crt") - } - - // This must happen before the addition of flags for Version Script and - // Dynamic List, as these flags must be split on spaces and those must not - linkerFlags = parseCommandLineFlags(linkerFlags, filterOutClangUnknownCflags) - - additionalLinkerInputs := bazel.LabelList{} - if props.Version_script != nil { - label := android.BazelLabelForModuleSrcSingle(ctx, *props.Version_script) - additionalLinkerInputs.Add(&label) - linkerFlags = append(linkerFlags, fmt.Sprintf("-Wl,--version-script,$(location %s)", label.Label)) - } - - if props.Dynamic_list != nil { - label := android.BazelLabelForModuleSrcSingle(ctx, *props.Dynamic_list) - additionalLinkerInputs.Add(&label) - linkerFlags = append(linkerFlags, fmt.Sprintf("-Wl,--dynamic-list,$(location %s)", label.Label)) - } - - la.additionalLinkerInputs.SetSelectValue(axis, config, additionalLinkerInputs) - la.linkopts.SetSelectValue(axis, config, linkerFlags) - - if axisFeatures != nil { - la.features.SetSelectValue(axis, config, axisFeatures) - } - - runtimeDeps := android.BazelLabelForModuleDepsExcludes(ctx, props.Runtime_libs, props.Exclude_runtime_libs) - if !runtimeDeps.IsEmpty() { - la.runtimeDeps.SetSelectValue(axis, config, runtimeDeps) - } -} - -var ( - apiSurfaceModuleLibCurrentPackage = "@api_surfaces//" + android.ModuleLibApi.String() + "/current:" -) - -func availableToSameApexes(a, b []string) bool { - if len(a) == 0 && len(b) == 0 { - return true - } - differ, _, _ := android.ListSetDifference(a, b) - return !differ -} - -func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, - config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int) { - - depsWithStubs := []bazel.Label{} - for _, l := range dynamicLibs.Includes { - dep, _ := ctx.ModuleFromName(l.OriginalModuleName) - if d, ok := dep.(*Module); ok && d.HasStubsVariants() { - depApexAvailable := d.ApexAvailable() - if !availableToSameApexes(apexAvailable, depApexAvailable) { - depsWithStubs = append(depsWithStubs, l) - } - } - } - if len(depsWithStubs) > 0 { - implDynamicDeps := bazel.SubtractBazelLabelList(dynamicLibs, bazel.MakeLabelList(depsWithStubs)) - dynamicDeps.SetSelectValue(axis, config, implDynamicDeps) - - stubLibLabels := []bazel.Label{} - for _, l := range depsWithStubs { - stubLabelInApiSurfaces := bazel.Label{ - Label: apiSurfaceModuleLibCurrentPackage + strings.TrimPrefix(l.OriginalModuleName, ":"), - } - stubLibLabels = append(stubLibLabels, stubLabelInApiSurfaces) - } - inApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex) - nonApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex) - defaultSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey) - if axis == bazel.NoConfigAxis { - (&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels)) - (&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs)) - (&defaultSelectValue).Append(bazel.MakeLabelList(depsWithStubs)) - dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue)) - dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue)) - dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue)) - } else if config == bazel.OsAndroid { - (&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels)) - (&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs)) - dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue)) - dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue)) - } - } -} - -func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) { - bp2BuildPropParseHelper(ctx, module, &StripProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - if stripProperties, ok := props.(*StripProperties); ok { - la.stripKeepSymbols.SetSelectValue(axis, config, stripProperties.Strip.Keep_symbols) - la.stripKeepSymbolsList.SetSelectValue(axis, config, stripProperties.Strip.Keep_symbols_list) - la.stripKeepSymbolsAndDebugFrame.SetSelectValue(axis, config, stripProperties.Strip.Keep_symbols_and_debug_frame) - la.stripAll.SetSelectValue(axis, config, stripProperties.Strip.All) - la.stripNone.SetSelectValue(axis, config, stripProperties.Strip.None) - } - }) -} - -func (la *linkerAttributes) convertProductVariables(ctx android.BazelConversionPathContext, productVariableProps android.ProductConfigProperties) { - - type productVarDep struct { - // the name of the corresponding excludes field, if one exists - excludesField string - // reference to the bazel attribute that should be set for the given product variable config - attribute *bazel.LabelListAttribute - - depResolutionFunc func(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList - } - - // an intermediate attribute that holds Header_libs info, and will be appended to - // implementationDeps at the end, to solve the confliction that both header_libs - // and static_libs use implementationDeps. - var headerDeps bazel.LabelListAttribute - - productVarToDepFields := map[string]productVarDep{ - // product variables do not support exclude_shared_libs - "Shared_libs": {attribute: &la.implementationDynamicDeps, depResolutionFunc: bazelLabelForSharedDepsExcludes}, - "Static_libs": {"Exclude_static_libs", &la.implementationDeps, bazelLabelForStaticDepsExcludes}, - "Whole_static_libs": {"Exclude_static_libs", &la.wholeArchiveDeps, bazelLabelForWholeDepsExcludes}, - "Header_libs": {attribute: &headerDeps, depResolutionFunc: bazelLabelForHeaderDepsExcludes}, - } - - for name, dep := range productVarToDepFields { - props, exists := productVariableProps[name] - excludeProps, excludesExists := productVariableProps[dep.excludesField] - // if neither an include nor excludes property exists, then skip it - if !exists && !excludesExists { - continue - } - // Collect all the configurations that an include or exclude property exists for. - // We want to iterate all configurations rather than either the include or exclude because, for a - // particular configuration, we may have either only an include or an exclude to handle. - productConfigProps := make(map[android.ProductConfigProperty]bool, len(props)+len(excludeProps)) - for p := range props { - productConfigProps[p] = true - } - for p := range excludeProps { - productConfigProps[p] = true - } - - for productConfigProp := range productConfigProps { - prop, includesExists := props[productConfigProp] - excludesProp, excludesExists := excludeProps[productConfigProp] - var includes, excludes []string - var ok bool - // if there was no includes/excludes property, casting fails and that's expected - if includes, ok = prop.([]string); includesExists && !ok { - ctx.ModuleErrorf("Could not convert product variable %s property", name) - } - if excludes, ok = excludesProp.([]string); excludesExists && !ok { - ctx.ModuleErrorf("Could not convert product variable %s property", dep.excludesField) - } - - dep.attribute.EmitEmptyList = productConfigProp.AlwaysEmit() - dep.attribute.SetSelectValue( - productConfigProp.ConfigurationAxis(), - productConfigProp.SelectKey(), - dep.depResolutionFunc(ctx, android.FirstUniqueStrings(includes), excludes), - ) - } - } - la.implementationDeps.Append(headerDeps) -} - -func (la *linkerAttributes) finalize(ctx android.BazelConversionPathContext) { - // if system dynamic deps have the default value, any use of a system dynamic library used will - // result in duplicate library errors for bionic OSes. Here, we explicitly exclude those libraries - // from bionic OSes and the no config case as these libraries only build for bionic OSes. - if la.systemDynamicDeps.IsNil() && len(la.usedSystemDynamicDepAsDynamicDep) > 0 { - toRemove := bazelLabelForSharedDeps(ctx, android.SortedKeys(la.usedSystemDynamicDepAsDynamicDep)) - la.dynamicDeps.Exclude(bazel.NoConfigAxis, "", toRemove) - la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove) - la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove) - la.implementationDynamicDeps.Exclude(bazel.NoConfigAxis, "", toRemove) - la.implementationDynamicDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove) - la.implementationDynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove) - - la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, toRemove) - la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, toRemove) - stubsToRemove := make([]bazel.Label, 0, len(la.usedSystemDynamicDepAsDynamicDep)) - for _, lib := range toRemove.Includes { - stubLabelInApiSurfaces := bazel.Label{ - Label: apiSurfaceModuleLibCurrentPackage + lib.OriginalModuleName, - } - stubsToRemove = append(stubsToRemove, stubLabelInApiSurfaces) - } - la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.MakeLabelList(stubsToRemove)) - } - - la.deps.ResolveExcludes() - la.implementationDeps.ResolveExcludes() - la.dynamicDeps.ResolveExcludes() - la.implementationDynamicDeps.ResolveExcludes() - la.wholeArchiveDeps.ResolveExcludes() - la.systemDynamicDeps.ForceSpecifyEmptyList = true - -} - -// Relativize a list of root-relative paths with respect to the module's -// directory. -// -// include_dirs Soong prop are root-relative (b/183742505), but -// local_include_dirs, export_include_dirs and export_system_include_dirs are -// module dir relative. This function makes a list of paths entirely module dir -// relative. -// -// For the `include` attribute, Bazel wants the paths to be relative to the -// module. -func bp2BuildMakePathsRelativeToModule(ctx android.BazelConversionPathContext, paths []string) []string { - var relativePaths []string - for _, path := range paths { - // Semantics of filepath.Rel: join(ModuleDir, rel(ModuleDir, path)) == path - relativePath, err := filepath.Rel(ctx.ModuleDir(), path) - if err != nil { - panic(err) - } - relativePaths = append(relativePaths, relativePath) - } - return relativePaths -} - -// BazelIncludes contains information about -I and -isystem paths from a module converted to Bazel -// attributes. -type BazelIncludes struct { - AbsoluteIncludes bazel.StringListAttribute - Includes bazel.StringListAttribute - SystemIncludes bazel.StringListAttribute -} - -func bp2BuildParseExportedIncludes(ctx android.BazelConversionPathContext, module *Module, includes *BazelIncludes) BazelIncludes { - var exported BazelIncludes - if includes != nil { - exported = *includes - } else { - exported = BazelIncludes{} - } - - // cc library Export_include_dirs and Export_system_include_dirs are marked - // "variant_prepend" in struct tag, set their prepend property to true to make - // sure bp2build generates correct result. - exported.Includes.Prepend = true - exported.SystemIncludes.Prepend = true - - bp2BuildPropParseHelper(ctx, module, &FlagExporterProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - if flagExporterProperties, ok := props.(*FlagExporterProperties); ok { - if len(flagExporterProperties.Export_include_dirs) > 0 { - exported.Includes.SetSelectValue(axis, config, android.FirstUniqueStrings(append(exported.Includes.SelectValue(axis, config), flagExporterProperties.Export_include_dirs...))) - } - if len(flagExporterProperties.Export_system_include_dirs) > 0 { - exported.SystemIncludes.SetSelectValue(axis, config, android.FirstUniqueStrings(append(exported.SystemIncludes.SelectValue(axis, config), flagExporterProperties.Export_system_include_dirs...))) - } - } - }) - exported.AbsoluteIncludes.DeduplicateAxesFromBase() - exported.Includes.DeduplicateAxesFromBase() - exported.SystemIncludes.DeduplicateAxesFromBase() - - return exported -} - -func BazelLabelNameForStaticModule(baseLabel string) string { - return baseLabel + "_bp2build_cc_library_static" -} - -func bazelLabelForStaticModule(ctx android.BazelConversionPathContext, m blueprint.Module) string { - label := android.BazelModuleLabel(ctx, m) - if ccModule, ok := m.(*Module); ok && ccModule.typ() == fullLibrary { - return BazelLabelNameForStaticModule(label) - } - return label -} - -func bazelLabelForSharedModule(ctx android.BazelConversionPathContext, m blueprint.Module) string { - // cc_library, at it's root name, propagates the shared library, which depends on the static - // library. - return android.BazelModuleLabel(ctx, m) -} - -func bazelLabelForStaticWholeModuleDeps(ctx android.BazelConversionPathContext, m blueprint.Module) string { - label := bazelLabelForStaticModule(ctx, m) - if aModule, ok := m.(android.Module); ok { - if android.IsModulePrebuilt(aModule) { - label += "_alwayslink" - } - } - return label -} - -func bazelLabelForWholeDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList { - return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticWholeModuleDeps) -} - -func bazelLabelForWholeDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList { - return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForStaticWholeModuleDeps) -} - -func bazelLabelForStaticDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList { - return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForStaticModule) -} - -func bazelLabelForStaticDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList { - return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticModule) -} - -func bazelLabelForSharedDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList { - return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForSharedModule) -} - -func bazelLabelForHeaderDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList { - // This is not elegant, but bp2build's shared library targets only propagate - // their header information as part of the normal C++ provider. - return bazelLabelForSharedDeps(ctx, modules) -} - -func bazelLabelForHeaderDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList { - // This is only used when product_variable header_libs is processed, to follow - // the pattern of depResolutionFunc - return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForSharedModule) -} - -func bazelLabelForSharedDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList { - return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForSharedModule) -} - -type binaryLinkerAttrs struct { - Linkshared *bool - Suffix bazel.StringAttribute -} - -func bp2buildBinaryLinkerProps(ctx android.BazelConversionPathContext, m *Module) binaryLinkerAttrs { - attrs := binaryLinkerAttrs{} - bp2BuildPropParseHelper(ctx, m, &BinaryLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - linkerProps := props.(*BinaryLinkerProperties) - staticExecutable := linkerProps.Static_executable - if axis == bazel.NoConfigAxis { - if linkBinaryShared := !proptools.Bool(staticExecutable); !linkBinaryShared { - attrs.Linkshared = &linkBinaryShared - } - } else if staticExecutable != nil { - // TODO(b/202876379): Static_executable is arch-variant; however, linkshared is a - // nonconfigurable attribute. Only 4 AOSP modules use this feature, defer handling - ctx.ModuleErrorf("bp2build cannot migrate a module with arch/target-specific static_executable values") - } - if suffix := linkerProps.Suffix; suffix != nil { - attrs.Suffix.SetSelectValue(axis, config, suffix) - } - }) - - return attrs -} - -func bp2buildSanitizerFeatures(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute { - sanitizerFeatures := bazel.StringListAttribute{} - bp2BuildPropParseHelper(ctx, m, &SanitizeProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - var features []string - if sanitizerProps, ok := props.(*SanitizeProperties); ok { - if sanitizerProps.Sanitize.Integer_overflow != nil && *sanitizerProps.Sanitize.Integer_overflow { - features = append(features, "ubsan_integer_overflow") - } - for _, sanitizer := range sanitizerProps.Sanitize.Misc_undefined { - features = append(features, "ubsan_"+sanitizer) - } - sanitizerFeatures.SetSelectValue(axis, config, features) - } - }) - return sanitizerFeatures -} - -func bp2buildLtoFeatures(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute { - lto_feature_name := "android_thin_lto" - ltoBoolFeatures := bazel.BoolAttribute{} - bp2BuildPropParseHelper(ctx, m, <OProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) { - if ltoProps, ok := props.(*LTOProperties); ok { - thinProp := ltoProps.Lto.Thin != nil && *ltoProps.Lto.Thin - thinPropSetToFalse := ltoProps.Lto.Thin != nil && !*ltoProps.Lto.Thin - neverProp := ltoProps.Lto.Never != nil && *ltoProps.Lto.Never - if thinProp { - ltoBoolFeatures.SetSelectValue(axis, config, BoolPtr(true)) - return - } - if neverProp || thinPropSetToFalse { - if thinProp { - ctx.ModuleErrorf("lto.thin and lto.never are mutually exclusive but were specified together") - } else { - ltoBoolFeatures.SetSelectValue(axis, config, BoolPtr(false)) - } - return - } - } - ltoBoolFeatures.SetSelectValue(axis, config, nil) - }) - - props := m.GetArchVariantProperties(ctx, <OProperties{}) - ltoStringFeatures, err := ltoBoolFeatures.ToStringListAttribute(func(boolPtr *bool, axis bazel.ConfigurationAxis, config string) []string { - if boolPtr == nil { - return []string{} - } - if !*boolPtr { - return []string{"-" + lto_feature_name} - } - features := []string{lto_feature_name} - if ltoProps, ok := props[axis][config].(*LTOProperties); ok { - if ltoProps.Whole_program_vtables != nil && *ltoProps.Whole_program_vtables { - features = append(features, "android_thin_lto_whole_program_vtables") - } - } - return features - }) - if err != nil { - ctx.ModuleErrorf("Error processing LTO attributes: %s", err) - } - return ltoStringFeatures -} diff --git a/cc/builder.go b/cc/builder.go index fef00d4d5..367bda380 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -19,6 +19,7 @@ package cc // functions. import ( + "fmt" "path/filepath" "runtime" "strconv" @@ -45,18 +46,18 @@ var ( blueprint.RuleParams{ Depfile: "${out}.d", Deps: blueprint.DepsGCC, - Command: "$relPwd ${config.CcWrapper}$ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in", + Command: "$relPwd ${config.CcWrapper}$ccCmd -c $cFlags -MD -MF ${out}.d -o $out $in$postCmd", CommandDeps: []string{"$ccCmd"}, }, - "ccCmd", "cFlags") + "ccCmd", "cFlags", "postCmd") // Rule to invoke gcc with given command and flags, but no dependencies. ccNoDeps = pctx.AndroidStaticRule("ccNoDeps", blueprint.RuleParams{ - Command: "$relPwd $ccCmd -c $cFlags -o $out $in", + Command: "$relPwd $ccCmd -c $cFlags -o $out $in$postCmd", CommandDeps: []string{"$ccCmd"}, }, - "ccCmd", "cFlags") + "ccCmd", "cFlags", "postCmd") // Rules to invoke ld to link binaries. Uses a .rsp file to list dependencies, as there may // be many. @@ -125,6 +126,14 @@ var ( }, "objcopyCmd", "prefix") + // Rule to run objcopy --remove-section=.llvm_addrsig on a partially linked object + noAddrSig = pctx.AndroidStaticRule("noAddrSig", + blueprint.RuleParams{ + Command: "rm -f ${out} && $objcopyCmd --remove-section=.llvm_addrsig ${in} ${out}", + CommandDeps: []string{"$objcopyCmd"}, + }, + "objcopyCmd") + _ = pctx.SourcePathVariable("stripPath", "build/soong/scripts/strip.sh") _ = pctx.SourcePathVariable("xzCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/xz") _ = pctx.SourcePathVariable("createMiniDebugInfo", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/create_minidebuginfo") @@ -322,6 +331,15 @@ var ( CommandDeps: []string{"$cxxExtractor", "$kytheVnames"}, }, "cFlags") + + // Function pointer for producting staticlibs from rlibs. Corresponds to + // rust.TransformRlibstoStaticlib(), initialized in soong-rust (rust/builder.go init()) + // + // This is required since soong-rust depends on soong-cc, so soong-cc cannot depend on soong-rust + // without resulting in a circular dependency. Setting this function pointer in soong-rust allows + // soong-cc to call into this particular function. + TransformRlibstoStaticlib (func(ctx android.ModuleContext, mainSrc android.Path, deps []RustRlibDep, + outputFile android.WritablePath) android.Path) = nil ) func PwdPrefix() string { @@ -367,13 +385,14 @@ type builderFlags struct { localCppFlags string localLdFlags string - libFlags string // Flags to add to the linker directly after specifying libraries to link. - extraLibFlags string // Flags to add to the linker last. - tidyFlags string // Flags that apply to clang-tidy - sAbiFlags string // Flags that apply to header-abi-dumps - aidlFlags string // Flags that apply to aidl source files - rsFlags string // Flags that apply to renderscript source files - toolchain config.Toolchain + noOverrideFlags string // Flags appended at the end so they are not overridden. + libFlags string // Flags to add to the linker directly after specifying libraries to link. + extraLibFlags string // Flags to add to the linker last. + tidyFlags string // Flags that apply to clang-tidy + sAbiFlags string // Flags that apply to header-abi-dumps + aidlFlags string // Flags that apply to aidl source files + rsFlags string // Flags that apply to renderscript source files + toolchain config.Toolchain // True if these extra features are enabled. tidy bool @@ -381,6 +400,7 @@ type builderFlags struct { gcovCoverage bool sAbiDump bool emitXrefs bool + clangVerify bool assemblerWithCpp bool // True if .s files should be processed with the c preprocessor. @@ -465,7 +485,7 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs coverageFiles = make(android.Paths, 0, len(srcFiles)) } var kytheFiles android.Paths - if flags.emitXrefs { + if flags.emitXrefs && ctx.Module() == ctx.PrimaryModule() { kytheFiles = make(android.Paths, 0, len(srcFiles)) } @@ -477,7 +497,8 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs flags.localCommonFlags + " " + flags.localToolingCFlags + " " + flags.localConlyFlags + " " + - flags.systemIncludeFlags + flags.systemIncludeFlags + " " + + flags.noOverrideFlags cflags := flags.globalCommonFlags + " " + flags.globalCFlags + " " + @@ -485,7 +506,8 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs flags.localCommonFlags + " " + flags.localCFlags + " " + flags.localConlyFlags + " " + - flags.systemIncludeFlags + flags.systemIncludeFlags + " " + + flags.noOverrideFlags toolingCppflags := flags.globalCommonFlags + " " + flags.globalToolingCFlags + " " + @@ -493,7 +515,8 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs flags.localCommonFlags + " " + flags.localToolingCFlags + " " + flags.localToolingCppFlags + " " + - flags.systemIncludeFlags + flags.systemIncludeFlags + " " + + flags.noOverrideFlags cppflags := flags.globalCommonFlags + " " + flags.globalCFlags + " " + @@ -501,7 +524,8 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs flags.localCommonFlags + " " + flags.localCFlags + " " + flags.localCppFlags + " " + - flags.systemIncludeFlags + flags.systemIncludeFlags + " " + + flags.noOverrideFlags asflags := flags.globalCommonFlags + " " + flags.globalAsFlags + " " + @@ -514,26 +538,6 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs sAbiDumpFiles = make(android.Paths, 0, len(srcFiles)) } - cflags += " ${config.NoOverrideGlobalCflags}" - toolingCflags += " ${config.NoOverrideGlobalCflags}" - cppflags += " ${config.NoOverrideGlobalCflags}" - toolingCppflags += " ${config.NoOverrideGlobalCflags}" - - if flags.toolchain.Is64Bit() { - cflags += " ${config.NoOverride64GlobalCflags}" - toolingCflags += " ${config.NoOverride64GlobalCflags}" - cppflags += " ${config.NoOverride64GlobalCflags}" - toolingCppflags += " ${config.NoOverride64GlobalCflags}" - } - - modulePath := android.PathForModuleSrc(ctx).String() - if android.IsThirdPartyPath(modulePath) { - cflags += " ${config.NoOverrideExternalGlobalCflags}" - toolingCflags += " ${config.NoOverrideExternalGlobalCflags}" - cppflags += " ${config.NoOverrideExternalGlobalCflags}" - toolingCppflags += " ${config.NoOverrideExternalGlobalCflags}" - } - // Multiple source files have build rules usually share the same cFlags or tidyFlags. // Define only one version in this module and share it in multiple build rules. // To simplify the code, the shared variables are all named as $flags<nnn>. @@ -588,6 +592,7 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs var moduleToolingFlags string var ccCmd string + var postCmd string tidy := flags.tidy coverage := flags.gcovCoverage dump := flags.sAbiDump @@ -615,6 +620,10 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs ccCmd = "clang++" moduleFlags = cppflags moduleToolingFlags = toolingCppflags + case ".rs": + // A source provider (e.g. rust_bindgen) may provide both rs and c files. + // Ignore the rs files. + continue case ".h", ".hpp": ctx.PropertyErrorf("srcs", "Header file %s is not supported, instead use export_include_dirs or local_include_dirs.", srcFile) continue @@ -628,6 +637,10 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs ccCmd = "${config.ClangBin}/" + ccCmd + if flags.clangVerify { + postCmd = " && touch " + objFile.String() + } + var implicitOutputs android.WritablePaths if coverage { gcnoFile := android.ObjPathWithExt(ctx, subdir, srcFile, "gcno") @@ -644,13 +657,14 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs Implicits: cFlagsDeps, OrderOnly: pathDeps, Args: map[string]string{ - "cFlags": shareFlags("cFlags", moduleFlags), - "ccCmd": ccCmd, // short and not shared + "cFlags": shareFlags("cFlags", moduleFlags), + "ccCmd": ccCmd, // short and not shared + "postCmd": postCmd, }, }) // Register post-process build statements (such as for tidy or kythe). - if emitXref { + if emitXref && ctx.Module() == ctx.PrimaryModule() { kytheFile := android.ObjPathWithExt(ctx, subdir, srcFile, "kzip") ctx.Build(pctx, android.BuildParams{ Rule: kytheExtract, @@ -673,16 +687,11 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs tidyCmd := "${config.ClangBin}/clang-tidy" rule := clangTidy - reducedCFlags := moduleFlags if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CLANG_TIDY") { rule = clangTidyRE - // b/248371171, work around RBE input processor problem - // some cflags rejected by input processor, but usually - // do not affect included files or clang-tidy - reducedCFlags = config.TidyReduceCFlags(reducedCFlags) } - sharedCFlags := shareFlags("cFlags", reducedCFlags) + sharedCFlags := shareFlags("cFlags", moduleFlags) srcRelPath := srcFile.Rel() // Add the .tidy rule @@ -786,6 +795,51 @@ func transformObjToStaticLib(ctx android.ModuleContext, } } +// Generate a Rust staticlib from a list of rlibDeps. Returns nil if TransformRlibstoStaticlib is nil or rlibDeps is empty. +func generateRustStaticlib(ctx android.ModuleContext, rlibDeps []RustRlibDep) android.Path { + if TransformRlibstoStaticlib == nil && len(rlibDeps) > 0 { + // This should only be reachable if a module defines Rust deps in static_libs and + // soong-rust hasn't been loaded alongside soong-cc (e.g. in soong-cc tests). + panic(fmt.Errorf( + "TransformRlibstoStaticlib is not set and rust deps are defined in static_libs for %s", + ctx.ModuleName())) + + } else if len(rlibDeps) == 0 { + return nil + } + + output := android.PathForModuleOut(ctx, "generated_rust_staticlib", "lib"+ctx.ModuleName()+"_rust_staticlib.a") + stemFile := output.ReplaceExtension(ctx, "rs") + crateNames := []string{} + + // Collect crate names + for _, lib := range rlibDeps { + // Exclude libstd so this can support no_std builds. + if lib.CrateName != "libstd" { + crateNames = append(crateNames, lib.CrateName) + } + } + + // Deduplicate any crateNames just to be safe + crateNames = android.FirstUniqueStrings(crateNames) + + // Write the source file + android.WriteFileRule(ctx, stemFile, genRustStaticlibSrcFile(crateNames)) + + return TransformRlibstoStaticlib(ctx, stemFile, rlibDeps, output) +} + +func genRustStaticlibSrcFile(crateNames []string) string { + lines := []string{ + "// @Soong generated Source", + "#![no_std]", // pre-emptively set no_std to support both std and no_std. + } + for _, crate := range crateNames { + lines = append(lines, fmt.Sprintf("extern crate %s;", crate)) + } + return strings.Join(lines, "\n") +} + // Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries, // and shared libraries, to a shared library (.so) or dynamic executable func transformObjToDynamicBinary(ctx android.ModuleContext, @@ -866,13 +920,15 @@ func transformObjToDynamicBinary(ctx android.ModuleContext, // Generate a rule to combine .dump sAbi dump files from multiple source files // into a single .ldump sAbi dump file func transformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths, soFile android.Path, - baseName, exportedHeaderFlags string, symbolFile android.OptionalPath, - excludedSymbolVersions, excludedSymbolTags []string) android.OptionalPath { + baseName string, exportedIncludeDirs []string, symbolFile android.OptionalPath, + excludedSymbolVersions, excludedSymbolTags, includedSymbolTags []string, + api string, isLlndk bool) android.Path { outputFile := android.PathForModuleOut(ctx, baseName+".lsdump") implicits := android.Paths{soFile} symbolFilterStr := "-so " + soFile.String() + exportedHeaderFlags := android.JoinWithPrefix(exportedIncludeDirs, "-I") if symbolFile.Valid() { implicits = append(implicits, symbolFile.Path()) @@ -884,6 +940,17 @@ func transformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Path for _, tag := range excludedSymbolTags { symbolFilterStr += " --exclude-symbol-tag " + tag } + for _, tag := range includedSymbolTags { + symbolFilterStr += " --include-symbol-tag " + tag + } + if isLlndk { + symbolFilterStr += " --symbol-tag-policy MatchTagOnly" + } + apiLevelsJson := android.GetApiLevelsJson(ctx) + implicits = append(implicits, apiLevelsJson) + symbolFilterStr += " --api-map " + apiLevelsJson.String() + symbolFilterStr += " --api " + api + rule := sAbiLink args := map[string]string{ "symbolFilter": symbolFilterStr, @@ -892,13 +959,7 @@ func transformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Path } if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ABI_LINKER") { rule = sAbiLinkRE - rbeImplicits := implicits.Strings() - for _, p := range strings.Split(exportedHeaderFlags, " ") { - if len(p) > 2 { - // Exclude the -I prefix. - rbeImplicits = append(rbeImplicits, p[2:]) - } - } + rbeImplicits := append(implicits.Strings(), exportedIncludeDirs...) args["implicitInputs"] = strings.Join(rbeImplicits, ",") } ctx.Build(pctx, android.BuildParams{ @@ -909,7 +970,7 @@ func transformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Path Implicits: implicits, Args: args, }) - return android.OptionalPathForPath(outputFile) + return outputFile } func transformAbiDumpToAbiDiff(ctx android.ModuleContext, inputDump, referenceDump android.Path, @@ -1008,6 +1069,21 @@ func transformBinaryPrefixSymbols(ctx android.ModuleContext, prefix string, inpu }) } +// Generate a rule for running objcopy --remove-section=.llvm_addrsig on a partially linked object +func transformObjectNoAddrSig(ctx android.ModuleContext, inputFile android.Path, outputFile android.WritablePath) { + objcopyCmd := "${config.ClangBin}/llvm-objcopy" + + ctx.Build(pctx, android.BuildParams{ + Rule: noAddrSig, + Description: "remove addrsig " + outputFile.Base(), + Output: outputFile, + Input: inputFile, + Args: map[string]string{ + "objcopyCmd": objcopyCmd, + }, + }) +} + // Registers a build statement to invoke `strip` (to discard symbols and data from object files). func transformStrip(ctx android.ModuleContext, inputFile android.Path, outputFile android.WritablePath, flags StripFlags) { @@ -1028,6 +1104,9 @@ func transformStrip(ctx android.ModuleContext, inputFile android.Path, if flags.StripKeepSymbolsAndDebugFrame { args += " --keep-symbols-and-debug-frame" } + if ctx.Windows() { + args += " --windows" + } ctx.Build(pctx, android.BuildParams{ Rule: strip, @@ -24,21 +24,23 @@ import ( "strconv" "strings" + "android/soong/testing" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" + "android/soong/aidl_library" "android/soong/android" - "android/soong/bazel/cquery" "android/soong/cc/config" "android/soong/fuzz" "android/soong/genrule" "android/soong/multitree" - "android/soong/snapshot" ) func init() { RegisterCCBuildComponents(android.InitRegistrationContext) + pctx.Import("android/soong/android") pctx.Import("android/soong/cc/config") } @@ -47,12 +49,10 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("sdk", sdkMutator).Parallel() - ctx.BottomUp("vndk", VndkMutator).Parallel() + ctx.BottomUp("llndk", llndkMutator).Parallel() ctx.BottomUp("link", LinkageMutator).Parallel() - ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel() ctx.BottomUp("version", versionMutator).Parallel() ctx.BottomUp("begin", BeginMutator).Parallel() - ctx.BottomUp("fdo_profile", fdoProfileMutator) }) ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { @@ -65,13 +65,13 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.TopDown("fuzz_deps", fuzzMutatorDeps) - ctx.BottomUp("coverage", coverageMutator).Parallel() + ctx.Transition("coverage", &coverageTransitionMutator{}) + + ctx.Transition("afdo", &afdoTransitionMutator{}) - ctx.TopDown("afdo_deps", afdoDepsMutator) - ctx.BottomUp("afdo", afdoMutator).Parallel() + ctx.Transition("orderfile", &orderfileTransitionMutator{}) - ctx.TopDown("lto_deps", ltoDepsMutator) - ctx.BottomUp("lto", ltoMutator).Parallel() + ctx.Transition("lto", <oTransitionMutator{}) ctx.BottomUp("check_linktype", checkLinkTypeMutator).Parallel() ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel() @@ -82,7 +82,7 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.TopDown("sabi_deps", sabiDepsMutator) }) - ctx.RegisterSingletonType("kythe_extract_all", kytheExtractAllFactory) + ctx.RegisterParallelSingletonType("kythe_extract_all", kytheExtractAllFactory) } // Deps is a struct containing module names of dependencies, separated by the kind of dependency. @@ -110,6 +110,9 @@ type Deps struct { // Used by DepsMutator to pass system_shared_libs information to check_elf_file.py. SystemSharedLibs []string + // Used by DepMutator to pass aidl_library modules to aidl compiler + AidlLibs []string + // If true, statically link the unwinder into native libraries/binaries. StaticUnwinderIfLegacy bool @@ -130,6 +133,25 @@ type Deps struct { // List of libs that need to be excluded for APEX variant ExcludeLibsForApex []string + // List of libs that need to be excluded for non-APEX variant + ExcludeLibsForNonApex []string + + // LLNDK headers for the ABI checker to check LLNDK implementation library. + // An LLNDK implementation is the core variant. LLNDK header libs are reexported by the vendor variant. + // The core variant cannot depend on the vendor variant because of the order of CreateVariations. + // Instead, the LLNDK implementation depends on the LLNDK header libs. + LlndkHeaderLibs []string +} + +// A struct which to collect flags for rlib dependencies +type RustRlibDep struct { + LibPath android.Path // path to the rlib + LinkDirs []string // flags required for dependency (e.g. -L flags) + CrateName string // crateNames associated with rlibDeps +} + +func EqRustRlibDeps(a RustRlibDep, b RustRlibDep) bool { + return a.LibPath == b.LibPath } // PathDeps is a struct containing file paths to dependencies of a module. @@ -144,9 +166,11 @@ type PathDeps struct { SharedLibsDeps, EarlySharedLibsDeps, LateSharedLibsDeps android.Paths // Paths to .a files StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths + // Paths and crateNames for RustStaticLib dependencies + RustRlibDeps []RustRlibDep // Transitive static library dependencies of static libraries for use in ordering. - TranstiveStaticLibrariesForOrdering *android.DepSet + TranstiveStaticLibrariesForOrdering *android.DepSet[android.Path] // Paths to .o files Objs Objects @@ -172,6 +196,7 @@ type PathDeps struct { ReexportedFlags []string ReexportedGeneratedHeaders android.Paths ReexportedDeps android.Paths + ReexportedRustRlibDeps []RustRlibDep // Paths to crt*.o files CrtBegin, CrtEnd android.Paths @@ -182,6 +207,13 @@ type PathDeps struct { // For Darwin builds, the path to the second architecture's output that should // be combined with this architectures's output into a FAT MachO file. DarwinSecondArchOutput android.OptionalPath + + // Paths to direct srcs and transitive include dirs from direct aidl_library deps + AidlLibraryInfos []aidl_library.AidlLibraryInfo + + // LLNDK headers for the ABI checker to check LLNDK implementation library. + LlndkIncludeDirs android.Paths + LlndkSystemIncludeDirs android.Paths } // LocalOrGlobalFlags contains flags that need to have values set globally by the build system or locally by the module @@ -205,7 +237,8 @@ type Flags struct { // Local flags (which individual modules are responsible for). These may override global flags. Local LocalOrGlobalFlags // Global flags (which build system or toolchain is responsible for). - Global LocalOrGlobalFlags + Global LocalOrGlobalFlags + NoOverrideFlags []string // Flags applied to the end of list of flags so they are not overridden aidlFlags []string // Flags that apply to aidl source files rsFlags []string // Flags that apply to renderscript source files @@ -224,6 +257,7 @@ type Flags struct { GcovCoverage bool // True if coverage files should be generated. SAbiDump bool // True if header abi dumps should be generated. EmitXrefs bool // If true, generate Ninja rules to generate emitXrefs input files for Kythe + ClangVerify bool // If true, append cflags "-Xclang -verify" and append "&& touch $out" to the clang command line. // The instruction set required for clang ("arm" or "thumb"). RequiredInstructionSet string @@ -249,6 +283,11 @@ type BaseProperties struct { // Deprecated. true is the default, false is invalid. Clang *bool `android:"arch_variant"` + // Aggresively trade performance for smaller binary size. + // This should only be used for on-device binaries that are rarely executed and not + // performance critical. + Optimize_for_size *bool `android:"arch_variant"` + // The API level that this module is built against. The APIs of this API level will be // visible at build time, but use of any APIs newer than min_sdk_version will render the // module unloadable on older devices. In the future it will be possible to weakly-link new @@ -277,6 +316,7 @@ type BaseProperties struct { AndroidMkSharedLibs []string `blueprint:"mutated"` AndroidMkStaticLibs []string `blueprint:"mutated"` + AndroidMkRlibs []string `blueprint:"mutated"` AndroidMkRuntimeLibs []string `blueprint:"mutated"` AndroidMkWholeStaticLibs []string `blueprint:"mutated"` AndroidMkHeaderLibs []string `blueprint:"mutated"` @@ -287,8 +327,8 @@ type BaseProperties struct { // Set by DepsMutator. AndroidMkSystemSharedLibs []string `blueprint:"mutated"` - // The name of the image this module is built for, suffixed with a '.' - ImageVariationPrefix string `blueprint:"mutated"` + // The name of the image this module is built for + ImageVariation string `blueprint:"mutated"` // The VNDK version this module is built against. If empty, the module is not // build against the VNDK. @@ -299,7 +339,7 @@ type BaseProperties struct { // *.logtags files, to combine together in order to generate the /system/etc/event-log-tags // file - Logtags []string + Logtags []string `android:"path"` // Make this module available when building for ramdisk. // On device without a dedicated recovery partition, the module is only @@ -319,6 +359,8 @@ type BaseProperties struct { Recovery_available *bool // Used by imageMutator, set by ImageMutatorBegin() + VendorVariantNeeded bool `blueprint:"mutated"` + ProductVariantNeeded bool `blueprint:"mutated"` CoreVariantNeeded bool `blueprint:"mutated"` RamdiskVariantNeeded bool `blueprint:"mutated"` VendorRamdiskVariantNeeded bool `blueprint:"mutated"` @@ -332,14 +374,9 @@ type BaseProperties struct { // for building binaries that are started before APEXes are activated. Bootstrap *bool - // Even if DeviceConfig().VndkUseCoreVariant() is set, this module must use vendor variant. - // see soong/cc/config/vndk.go - MustUseVendorVariant bool `blueprint:"mutated"` - - // Used by vendor snapshot to record dependencies from snapshot modules. - SnapshotSharedLibs []string `blueprint:"mutated"` - SnapshotStaticLibs []string `blueprint:"mutated"` - SnapshotRuntimeLibs []string `blueprint:"mutated"` + // Allows this module to be included in CMake release snapshots to be built outside of Android + // build system and source tree. + Cmake_snapshot_supported *bool Installable *bool `android:"arch_variant"` @@ -353,20 +390,6 @@ type BaseProperties struct { // variant to have a ".sdk" suffix. SdkAndPlatformVariantVisibleToMake bool `blueprint:"mutated"` - // Normally Soong uses the directory structure to decide which modules - // should be included (framework) or excluded (non-framework) from the - // different snapshots (vendor, recovery, etc.), but this property - // allows a partner to exclude a module normally thought of as a - // framework module from the vendor snapshot. - Exclude_from_vendor_snapshot *bool - - // Normally Soong uses the directory structure to decide which modules - // should be included (framework) or excluded (non-framework) from the - // different snapshots (vendor, recovery, etc.), but this property - // allows a partner to exclude a module normally thought of as a - // framework module from the recovery snapshot. - Exclude_from_recovery_snapshot *bool - // List of APEXes that this module has private access to for testing purpose. The module // can depend on libraries that are not exported by the APEXes and use private symbols // from the exported libraries. @@ -456,23 +479,6 @@ type VendorProperties struct { // IsLLNDK is set to true for the vendor variant of a cc_library module that has LLNDK stubs. IsLLNDK bool `blueprint:"mutated"` - // IsVNDKUsingCoreVariant is true for VNDK modules if the global VndkUseCoreVariant option is - // set and the module is not listed in VndkMustUseVendorVariantList. - IsVNDKUsingCoreVariant bool `blueprint:"mutated"` - - // IsVNDKCore is set if a VNDK module does not set the vndk.support_system_process property. - IsVNDKCore bool `blueprint:"mutated"` - - // IsVNDKSP is set if a VNDK module sets the vndk.support_system_process property. - IsVNDKSP bool `blueprint:"mutated"` - - // IsVNDKPrivate is set if a VNDK module sets the vndk.private property or an LLNDK - // module sets the llndk.private property. - IsVNDKPrivate bool `blueprint:"mutated"` - - // IsVNDKProduct is set if a VNDK module sets the product_available property. - IsVNDKProduct bool `blueprint:"mutated"` - // IsVendorPublicLibrary is set for the core and product variants of a library that has // vendor_public_library stubs. IsVendorPublicLibrary bool `blueprint:"mutated"` @@ -499,36 +505,33 @@ type ModuleContextIntf interface { useVndk() bool isNdk(config android.Config) bool IsLlndk() bool - IsLlndkPublic() bool isImplementationForLLNDKPublic() bool - IsVndkPrivate() bool - isVndk() bool - isVndkSp() bool - IsVndkExt() bool IsVendorPublicLibrary() bool inProduct() bool inVendor() bool inRamdisk() bool inVendorRamdisk() bool inRecovery() bool + InVendorOrProduct() bool selectedStl() string baseModuleName() string - getVndkExtendsModuleName() string - isAfdoCompile() bool - isPgoCompile() bool + isAfdoCompile(ctx ModuleContext) bool + isOrderfileCompile() bool isCfi() bool + isFuzzer() bool isNDKStubLibrary() bool useClangLld(actx ModuleContext) bool isForPlatform() bool apexVariationName() string apexSdkVersion() android.ApiLevel bootstrap() bool - mustUseVendorVariant() bool nativeCoverage() bool directlyInAnyApex() bool isPreventInstall() bool isCfiAssemblySupportEnabled() bool getSharedFlags() *SharedFlags + notInPlatform() bool + optimizeForSize() bool } type SharedFlags struct { @@ -558,6 +561,24 @@ type feature interface { props() []interface{} } +// Information returned from Generator about the source code it's generating +type GeneratedSource struct { + IncludeDirs android.Paths + Sources android.Paths + Headers android.Paths + ReexportedDirs android.Paths +} + +// generator allows injection of generated code +type Generator interface { + GeneratorProps() []interface{} + GeneratorInit(ctx BaseModuleContext) + GeneratorDeps(ctx DepsContext, deps Deps) Deps + GeneratorFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags + GeneratorSources(ctx ModuleContext) GeneratedSource + GeneratorBuildActions(ctx ModuleContext, flags Flags, deps PathDeps) +} + // compiler is the interface for a compiler helper object. Different module decorators may implement // this helper differently. type compiler interface { @@ -565,6 +586,7 @@ type compiler interface { compilerDeps(ctx DepsContext, deps Deps) Deps compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags compilerProps() []interface{} + baseCompilerProps() BaseCompilerProperties appendCflags([]string) appendAsflags([]string) @@ -579,17 +601,21 @@ type linker interface { linkerDeps(ctx DepsContext, deps Deps) Deps linkerFlags(ctx ModuleContext, flags Flags) Flags linkerProps() []interface{} + baseLinkerProps() BaseLinkerProperties useClangLld(actx ModuleContext) bool link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path appendLdflags([]string) unstrippedOutputFilePath() android.Path + strippedAllOutputFilePath() android.Path nativeCoverage() bool coverageOutputFilePath() android.OptionalPath // Get the deps that have been explicitly specified in the properties. linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps + + moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) } // specifiedDeps is a tuple struct representing dependencies of a linked binary owned by the linker. @@ -628,6 +654,7 @@ const ( headerLibraryDependency = iota sharedLibraryDependency staticLibraryDependency + rlibLibraryDependency ) func (k libraryDependencyKind) String() string { @@ -638,6 +665,8 @@ func (k libraryDependencyKind) String() string { return "sharedLibraryDependency" case staticLibraryDependency: return "staticLibraryDependency" + case rlibLibraryDependency: + return "rlibLibraryDependency" default: panic(fmt.Errorf("unknown libraryDependencyKind %d", k)) } @@ -693,6 +722,8 @@ type libraryDependencyTag struct { // Whether or not this dependency has to be followed for the apex variants excludeInApex bool + // Whether or not this dependency has to be followed for the non-apex variants + excludeInNonApex bool // If true, don't automatically export symbols from the static library into a shared library. unexportedSymbols bool @@ -730,6 +761,12 @@ func (d libraryDependencyTag) InstallDepNeeded() bool { var _ android.InstallNeededDependencyTag = libraryDependencyTag{} +func (d libraryDependencyTag) PropagateAconfigValidation() bool { + return d.static() +} + +var _ android.PropagateAconfigValidationDependencyTag = libraryDependencyTag{} + // dependencyTag is used for tagging miscellaneous dependency types that don't fit into // libraryDependencyTag. Each tag object is created globally and reused for multiple // dependencies (although since the object contains no references, assigning a tag to a @@ -761,10 +798,11 @@ var ( dataLibDepTag = dependencyTag{name: "data lib"} dataBinDepTag = dependencyTag{name: "data bin"} runtimeDepTag = installDependencyTag{name: "runtime lib"} - testPerSrcDepTag = dependencyTag{name: "test_per_src"} stubImplDepTag = dependencyTag{name: "stub_impl"} JniFuzzLibTag = dependencyTag{name: "jni_fuzz_lib_tag"} FdoProfileTag = dependencyTag{name: "fdo_profile"} + aidlLibraryTag = dependencyTag{name: "aidl_library"} + llndkHeaderLibTag = dependencyTag{name: "llndk_header_lib"} ) func IsSharedDepTag(depTag blueprint.DependencyTag) bool { @@ -786,24 +824,6 @@ func IsRuntimeDepTag(depTag blueprint.DependencyTag) bool { return depTag == runtimeDepTag } -func IsTestPerSrcDepTag(depTag blueprint.DependencyTag) bool { - ccDepTag, ok := depTag.(dependencyTag) - return ok && ccDepTag == testPerSrcDepTag -} - -// bazelHandler is the interface for a helper object related to deferring to Bazel for -// processing a cc module (during Bazel mixed builds). Individual module types should define -// their own bazel handler if they support being handled by Bazel. -type BazelHandler interface { - // QueueBazelCall invokes request-queueing functions on the BazelContext - //so that these requests are handled when Bazel's cquery is invoked. - QueueBazelCall(ctx android.BaseModuleContext, label string) - - // ProcessBazelQueryResponse uses information retrieved from Bazel to set properties - // on the current module with given label. - ProcessBazelQueryResponse(ctx android.ModuleContext, label string) -} - // Module contains the properties and members used by all C/C++ module types, and implements // the blueprint.Module interface. It delegates to compiler, linker, and installer interfaces // to construct the output file. Behavior can be customized with a Customizer, or "decorator", @@ -821,15 +841,14 @@ type BazelHandler interface { type Module struct { fuzz.FuzzModule - android.BazelModuleBase - VendorProperties VendorProperties Properties BaseProperties + sourceProperties android.SourceProperties // initialize before calling Init - hod android.HostOrDeviceSupported - multilib android.Multilib - bazelable bool + hod android.HostOrDeviceSupported + multilib android.Multilib + testModule bool // Allowable SdkMemberTypes of this module type. sdkMemberTypes []android.SdkMemberType @@ -839,21 +858,20 @@ type Module struct { // type-specific logic. These members may reference different objects or the same object. // Functions of these decorators will be invoked to initialize and register type-specific // build statements. - compiler compiler - linker linker - installer installer - bazelHandler BazelHandler - - features []feature - stl *stl - sanitize *sanitize - coverage *coverage - fuzzer *fuzzer - sabi *sabi - vndkdep *vndkdep - lto *lto - afdo *afdo - pgo *pgo + generators []Generator + compiler compiler + linker linker + installer installer + + features []feature + stl *stl + sanitize *sanitize + coverage *coverage + fuzzer *fuzzer + sabi *sabi + lto *lto + afdo *afdo + orderfile *orderfile library libraryInterface @@ -884,6 +902,10 @@ type Module struct { apexSdkVersion android.ApiLevel hideApexVariantFromMake bool + + logtagsPaths android.Paths + + WholeRustStaticlib bool } func (c *Module) AddJSONData(d *map[string]interface{}) { @@ -922,14 +944,7 @@ func (c *Module) AddJSONData(d *map[string]interface{}) { "InstallInVendorRamdisk": c.InstallInVendorRamdisk(), "InstallInRecovery": c.InstallInRecovery(), "InstallInRoot": c.InstallInRoot(), - "IsVndk": c.IsVndk(), - "IsVndkExt": c.IsVndkExt(), - "IsVndkPrivate": c.IsVndkPrivate(), - "IsVndkSp": c.IsVndkSp(), "IsLlndk": c.IsLlndk(), - "IsLlndkPublic": c.IsLlndkPublic(), - "IsSnapshotLibrary": c.IsSnapshotLibrary(), - "IsSnapshotPrebuilt": c.IsSnapshotPrebuilt(), "IsVendorPublicLibrary": c.IsVendorPublicLibrary(), "ApexSdkVersion": c.apexSdkVersion, "TestFor": c.TestFor(), @@ -941,6 +956,7 @@ func (c *Module) AddJSONData(d *map[string]interface{}) { "WinMsgSrcs": hasWinMsg, "YaccSrsc": hasYacc, "OnlyCSrcs": !(hasAidl || hasLex || hasProto || hasRenderscript || hasSysprop || hasWinMsg || hasYacc), + "OptimizeForSize": c.OptimizeForSize(), } } @@ -956,8 +972,8 @@ func (c *Module) HiddenFromMake() bool { return c.Properties.HideFromMake } -func (c *Module) RequiredModuleNames() []string { - required := android.CopyOf(c.ModuleBase.RequiredModuleNames()) +func (c *Module) RequiredModuleNames(ctx android.ConfigAndErrorContext) []string { + required := android.CopyOf(c.ModuleBase.RequiredModuleNames(ctx)) if c.ImageVariation().Variation == android.CoreVariation { required = append(required, c.Properties.Target.Platform.Required...) required = removeListFromList(required, c.Properties.Target.Platform.Exclude_required) @@ -1026,6 +1042,10 @@ func (c *Module) StubDecorator() bool { return false } +func (c *Module) OptimizeForSize() bool { + return Bool(c.Properties.Optimize_for_size) +} + func (c *Module) SdkVersion() string { return String(c.Properties.Sdk_version) } @@ -1068,6 +1088,32 @@ func (c *Module) CcLibraryInterface() bool { return false } +func (c *Module) IsNdkPrebuiltStl() bool { + if c.linker == nil { + return false + } + if _, ok := c.linker.(*ndkPrebuiltStlLinker); ok { + return true + } + return false +} + +func (c *Module) RlibStd() bool { + panic(fmt.Errorf("RlibStd called on non-Rust module: %q", c.BaseModuleName())) +} + +func (c *Module) RustLibraryInterface() bool { + return false +} + +func (c *Module) CrateName() string { + panic(fmt.Errorf("CrateName called on non-Rust module: %q", c.BaseModuleName())) +} + +func (c *Module) ExportedCrateLinkDirs() []string { + panic(fmt.Errorf("ExportedCrateLinkDirs called on non-Rust module: %q", c.BaseModuleName())) +} + func (c *Module) IsFuzzModule() bool { if _, ok := c.compiler.(*fuzzBinary); ok { return true @@ -1086,7 +1132,7 @@ func (c *Module) FuzzPackagedModule() fuzz.FuzzPackagedModule { panic(fmt.Errorf("FuzzPackagedModule called on non-fuzz module: %q", c.BaseModuleName())) } -func (c *Module) FuzzSharedLibraries() android.Paths { +func (c *Module) FuzzSharedLibraries() android.RuleBuilderInstalls { if fuzzer, ok := c.compiler.(*fuzzBinary); ok { return fuzzer.sharedLibraries } @@ -1135,6 +1181,16 @@ func (c *Module) BuildSharedVariant() bool { panic(fmt.Errorf("BuildSharedVariant called on non-library module: %q", c.BaseModuleName())) } +func (c *Module) BuildRlibVariant() bool { + // cc modules can never build rlib variants + return false +} + +func (c *Module) IsRustFFI() bool { + // cc modules are not Rust modules + return false +} + func (c *Module) Module() android.Module { return c } @@ -1181,6 +1237,9 @@ func (c *Module) VndkVersion() string { func (c *Module) Init() android.Module { c.AddProperties(&c.Properties, &c.VendorProperties) + for _, generator := range c.generators { + c.AddProperties(generator.GeneratorProps()...) + } if c.compiler != nil { c.AddProperties(c.compiler.compilerProps()...) } @@ -1205,26 +1264,24 @@ func (c *Module) Init() android.Module { if c.sabi != nil { c.AddProperties(c.sabi.props()...) } - if c.vndkdep != nil { - c.AddProperties(c.vndkdep.props()...) - } if c.lto != nil { c.AddProperties(c.lto.props()...) } if c.afdo != nil { c.AddProperties(c.afdo.props()...) } - 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()...) } + // Allow test-only on libraries that are not cc_test_library + if c.library != nil && !c.testLibrary() { + c.AddProperties(&c.sourceProperties) + } android.InitAndroidArchModule(c, c.hod, c.multilib) - if c.bazelable { - android.InitBazelModule(c) - } android.InitApexModule(c) android.InitDefaultableModule(c) @@ -1239,7 +1296,7 @@ func (c *Module) UseVndk() bool { func (c *Module) canUseSdk() bool { return c.Os() == android.Android && c.Target().NativeBridge == android.NativeBridgeDisabled && - !c.UseVndk() && !c.InRamdisk() && !c.InRecovery() && !c.InVendorRamdisk() + !c.InVendorOrProduct() && !c.InRamdisk() && !c.InRecovery() && !c.InVendorRamdisk() } func (c *Module) UseSdk() bool { @@ -1261,10 +1318,6 @@ func (c *Module) IsLlndk() bool { return c.VendorProperties.IsLLNDK } -func (c *Module) IsLlndkPublic() bool { - return c.VendorProperties.IsLLNDK && !c.VendorProperties.IsVNDKPrivate -} - func (m *Module) NeedsLlndkVariants() bool { lib := moduleLibraryInterface(m) return lib != nil && (lib.hasLLNDKStubs() || lib.hasLLNDKHeaders()) @@ -1311,50 +1364,26 @@ func (c *Module) isImplementationForLLNDKPublic() bool { !Bool(library.Properties.Llndk.Private) } -// Returns true for LLNDK-private, VNDK-SP-private, and VNDK-core-private. -func (c *Module) IsVndkPrivate() bool { - // Check if VNDK-core-private or VNDK-SP-private - if c.IsVndk() { - return Bool(c.vndkdep.Properties.Vndk.Private) - } - - // Check if LLNDK-private - if library, ok := c.library.(*libraryDecorator); ok && c.IsLlndk() { - return Bool(library.Properties.Llndk.Private) - } - - return false -} - -// IsVndk() returns true if this module has a vndk variant. -// Note that IsVndk() returns true for all variants of vndk-enabled libraries. Not only vendor variant, -// but also platform and product variants of vndk-enabled libraries return true for IsVndk(). -func (c *Module) IsVndk() bool { - if vndkdep := c.vndkdep; vndkdep != nil { - return vndkdep.isVndk() - } - return false -} - -func (c *Module) isAfdoCompile() bool { +func (c *Module) isAfdoCompile(ctx ModuleContext) bool { if afdo := c.afdo; afdo != nil { - return afdo.Properties.FdoProfilePath != nil + return afdo.isAfdoCompile(ctx) } return false } -func (c *Module) isPgoCompile() bool { - if pgo := c.pgo; pgo != nil { - return pgo.Properties.PgoCompile +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.Sanitize.Cfi) - } - return false + return c.sanitize.isSanitizerEnabled(cfi) +} + +func (c *Module) isFuzzer() bool { + return c.sanitize.isSanitizerEnabled(Fuzzer) } func (c *Module) isNDKStubLibrary() bool { @@ -1364,35 +1393,10 @@ func (c *Module) isNDKStubLibrary() bool { return false } -func (c *Module) IsVndkSp() bool { - if vndkdep := c.vndkdep; vndkdep != nil { - return vndkdep.isVndkSp() - } - return false -} - -func (c *Module) IsVndkExt() bool { - if vndkdep := c.vndkdep; vndkdep != nil { - return vndkdep.isVndkExt() - } - return false -} - func (c *Module) SubName() string { return c.Properties.SubName } -func (c *Module) MustUseVendorVariant() bool { - return c.IsVndkSp() || c.Properties.MustUseVendorVariant -} - -func (c *Module) getVndkExtendsModuleName() string { - if vndkdep := c.vndkdep; vndkdep != nil { - return vndkdep.getVndkExtendsModuleName() - } - return "" -} - func (c *Module) IsStubs() bool { if lib := c.library; lib != nil { return lib.buildStubs() @@ -1456,14 +1460,6 @@ func (c *Module) IsSnapshotPrebuilt() bool { return false } -func (c *Module) ExcludeFromVendorSnapshot() bool { - return Bool(c.Properties.Exclude_from_vendor_snapshot) -} - -func (c *Module) ExcludeFromRecoverySnapshot() bool { - return Bool(c.Properties.Exclude_from_recovery_snapshot) -} - func isBionic(name string) bool { switch name { case "libc", "libm", "libdl", "libdl_android", "linker": @@ -1473,8 +1469,6 @@ func isBionic(name string) bool { } func InstallToBootstrap(name string, config android.Config) bool { - // NOTE: also update //build/bazel/rules/apex/cc.bzl#_installed_to_bootstrap - // if this list is updated. if name == "libclang_rt.hwasan" || name == "libc_hwasan" { return true } @@ -1546,6 +1540,10 @@ func (ctx *moduleContextImpl) object() bool { return ctx.mod.Object() } +func (ctx *moduleContextImpl) optimizeForSize() bool { + return ctx.mod.OptimizeForSize() +} + func (ctx *moduleContextImpl) canUseSdk() bool { return ctx.mod.canUseSdk() } @@ -1556,13 +1554,6 @@ func (ctx *moduleContextImpl) useSdk() bool { func (ctx *moduleContextImpl) sdkVersion() string { if ctx.ctx.Device() { - if ctx.useVndk() { - vndkVer := ctx.mod.VndkVersion() - if inList(vndkVer, ctx.ctx.Config().PlatformVersionActiveCodenames()) { - return "current" - } - return vndkVer - } return String(ctx.mod.Properties.Sdk_version) } return "" @@ -1576,6 +1567,17 @@ func (ctx *moduleContextImpl) minSdkVersion() string { if ver == "apex_inherit" || ver == "" { ver = ctx.sdkVersion() } + + if ctx.ctx.Device() { + config := ctx.ctx.Config() + if ctx.inVendor() { + // If building for vendor with final API, then use the latest _stable_ API as "current". + if config.VendorApiLevelFrozen() && (ver == "" || ver == "current") { + ver = config.PlatformSdkVersion().String() + } + } + } + // For crt objects, the meaning of min_sdk_version is very different from other types of // module. For them, min_sdk_version defines the oldest version that the build system will // create versioned variants for. For example, if min_sdk_version is 16, then sdk variant of @@ -1616,6 +1618,10 @@ func (ctx *moduleContextImpl) useVndk() bool { return ctx.mod.UseVndk() } +func (ctx *moduleContextImpl) InVendorOrProduct() bool { + return ctx.mod.InVendorOrProduct() +} + func (ctx *moduleContextImpl) isNdk(config android.Config) bool { return ctx.mod.IsNdk(config) } @@ -1624,54 +1630,34 @@ func (ctx *moduleContextImpl) IsLlndk() bool { return ctx.mod.IsLlndk() } -func (ctx *moduleContextImpl) IsLlndkPublic() bool { - return ctx.mod.IsLlndkPublic() -} - func (ctx *moduleContextImpl) isImplementationForLLNDKPublic() bool { return ctx.mod.isImplementationForLLNDKPublic() } -func (ctx *moduleContextImpl) IsVndkPrivate() bool { - return ctx.mod.IsVndkPrivate() +func (ctx *moduleContextImpl) isAfdoCompile(mctx ModuleContext) bool { + return ctx.mod.isAfdoCompile(mctx) } -func (ctx *moduleContextImpl) isVndk() bool { - return ctx.mod.IsVndk() -} - -func (ctx *moduleContextImpl) isAfdoCompile() bool { - return ctx.mod.isAfdoCompile() -} - -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() } -func (ctx *moduleContextImpl) isNDKStubLibrary() bool { - return ctx.mod.isNDKStubLibrary() -} - -func (ctx *moduleContextImpl) isVndkSp() bool { - return ctx.mod.IsVndkSp() +func (ctx *moduleContextImpl) isFuzzer() bool { + return ctx.mod.isFuzzer() } -func (ctx *moduleContextImpl) IsVndkExt() bool { - return ctx.mod.IsVndkExt() +func (ctx *moduleContextImpl) isNDKStubLibrary() bool { + return ctx.mod.isNDKStubLibrary() } func (ctx *moduleContextImpl) IsVendorPublicLibrary() bool { return ctx.mod.IsVendorPublicLibrary() } -func (ctx *moduleContextImpl) mustUseVendorVariant() bool { - return ctx.mod.MustUseVendorVariant() -} - func (ctx *moduleContextImpl) selectedStl() string { if stl := ctx.mod.stl; stl != nil { return stl.Properties.SelectedStl @@ -1684,19 +1670,17 @@ func (ctx *moduleContextImpl) useClangLld(actx ModuleContext) bool { } func (ctx *moduleContextImpl) baseModuleName() string { - return ctx.mod.ModuleBase.BaseModuleName() -} - -func (ctx *moduleContextImpl) getVndkExtendsModuleName() string { - return ctx.mod.getVndkExtendsModuleName() + return ctx.mod.BaseModuleName() } func (ctx *moduleContextImpl) isForPlatform() bool { - return ctx.ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() + apexInfo, _ := android.ModuleProvider(ctx.ctx, android.ApexInfoProvider) + return apexInfo.IsForPlatform() } func (ctx *moduleContextImpl) apexVariationName() string { - return ctx.ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).ApexVariationName + apexInfo, _ := android.ModuleProvider(ctx.ctx, android.ApexInfoProvider) + return apexInfo.ApexVariationName } func (ctx *moduleContextImpl) apexSdkVersion() android.ApiLevel { @@ -1732,6 +1716,10 @@ func (ctx *moduleContextImpl) isCfiAssemblySupportEnabled() bool { return ctx.mod.isCfiAssemblySupportEnabled() } +func (ctx *moduleContextImpl) notInPlatform() bool { + return ctx.mod.NotInPlatform() +} + func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module { return &Module{ hod: hod, @@ -1749,10 +1737,9 @@ func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Mo module.coverage = &coverage{} module.fuzzer = &fuzzer{} module.sabi = &sabi{} - module.vndkdep = &vndkdep{} module.lto = <o{} module.afdo = &afdo{} - module.pgo = &pgo{} + module.orderfile = &orderfile{} return module } @@ -1786,11 +1773,6 @@ func (c *Module) Symlinks() []string { return nil } -func (c *Module) IsTestPerSrcAllTestsVariation() bool { - test, ok := c.linker.(testPerSrc) - return ok && test.isAllTestsVariation() -} - func (c *Module) DataPaths() []android.DataPath { if p, ok := c.installer.(interface { dataPaths() []android.DataPath @@ -1803,7 +1785,6 @@ func (c *Module) DataPaths() []android.DataPath { func getNameSuffixWithVndkVersion(ctx android.ModuleContext, c LinkableInterface) string { // Returns the name suffix for product and vendor variants. If the VNDK version is not // "current", it will append the VNDK version to the name suffix. - var vndkVersion string var nameSuffix string if c.InProduct() { if c.ProductSpecific() { @@ -1811,16 +1792,11 @@ func getNameSuffixWithVndkVersion(ctx android.ModuleContext, c LinkableInterface // do not add a name suffix because it is a base module. return "" } - vndkVersion = ctx.DeviceConfig().ProductVndkVersion() - nameSuffix = ProductSuffix + return ProductSuffix } else { - vndkVersion = ctx.DeviceConfig().VndkVersion() nameSuffix = VendorSuffix } - if vndkVersion == "current" { - vndkVersion = ctx.DeviceConfig().PlatformVndkVersion() - } - if c.VndkVersion() != vndkVersion && c.VndkVersion() != "" { + if c.VndkVersion() != "" { // add version suffix only if the module is using different vndk version than the // version in product or vendor partition. nameSuffix += "." + c.VndkVersion() @@ -1836,7 +1812,7 @@ func GetSubnameProperty(actx android.ModuleContext, c LinkableInterface) string } llndk := c.IsLlndk() - if llndk || (c.UseVndk() && c.HasNonSystemVariants()) { + if llndk || (c.InVendorOrProduct() && c.HasNonSystemVariants()) { // .vendor.{version} suffix is added for vendor variant or .product.{version} suffix is // added for product variant only when we have vendor and product variants with core // variant. The suffix is not added for vendor-only or product-only module. @@ -1867,140 +1843,126 @@ func GetSubnameProperty(actx android.ModuleContext, c LinkableInterface) string return subName } -var _ android.MixedBuildBuildable = (*Module)(nil) - -func (c *Module) getBazelModuleLabel(ctx android.BaseModuleContext) string { - var bazelModuleLabel string - if c.typ() == fullLibrary && c.static() { - // cc_library is a special case in bp2build; two targets are generated -- one for each - // of the shared and static variants. The shared variant keeps the module name, but the - // static variant uses a different suffixed name. - bazelModuleLabel = bazelLabelForStaticModule(ctx, c) - } else { - bazelModuleLabel = c.GetBazelLabel(ctx, c) - } - labelNoPrebuilt := bazelModuleLabel - if c.IsPrebuilt() { - labelNoPrebuilt = android.RemoveOptionalPrebuiltPrefixFromBazelLabel(bazelModuleLabel) +func moduleContextFromAndroidModuleContext(actx android.ModuleContext, c *Module) ModuleContext { + ctx := &moduleContext{ + ModuleContext: actx, + moduleContextImpl: moduleContextImpl{ + mod: c, + }, } - return labelNoPrebuilt -} - -func (c *Module) QueueBazelCall(ctx android.BaseModuleContext) { - c.bazelHandler.QueueBazelCall(ctx, c.getBazelModuleLabel(ctx)) + ctx.ctx = ctx + return ctx } +// TODO (b/277651159): Remove this allowlist var ( - mixedBuildSupportedCcTest = []string{ - "adbd_test", - "adb_crypto_test", - "adb_pairing_auth_test", - "adb_pairing_connection_test", - "adb_tls_connection_test", + skipStubLibraryMultipleApexViolation = map[string]bool{ + "libclang_rt.asan": true, + "libclang_rt.hwasan": true, + // runtime apex + "libc": true, + "libc_hwasan": true, + "libdl_android": true, + "libm": true, + "libdl": true, + "libz": true, + // art apex + // TODO(b/234351700): Remove this when com.android.art.debug is gone. + "libandroidio": true, + "libdexfile": true, + "libdexfiled": true, // com.android.art.debug only + "libnativebridge": true, + "libnativehelper": true, + "libnativeloader": true, + "libsigchain": true, } ) -// IsMixedBuildSupported returns true if the module should be analyzed by Bazel -// in any of the --bazel-mode(s). This filters at the module level and takes -// precedence over the allowlists in allowlists/allowlists.go. -func (c *Module) IsMixedBuildSupported(ctx android.BaseModuleContext) bool { - _, isForTesting := ctx.Config().BazelContext.(android.MockBazelContext) - if c.testBinary() && !android.InList(c.Name(), mixedBuildSupportedCcTest) && !isForTesting { - // Per-module rollout of mixed-builds for cc_test modules. +// Returns true if a stub library could be installed in multiple apexes +func (c *Module) stubLibraryMultipleApexViolation(ctx android.ModuleContext) bool { + // If this is not an apex variant, no check necessary + if !c.InAnyApex() { return false } - - // TODO(b/261058727): Remove this (enable mixed builds for modules with UBSan) - // Currently we can only support ubsan when minimum runtime is used. - return c.bazelHandler != nil && (!isUbsanEnabled(c) || c.MinimalRuntimeNeeded()) -} - -func isUbsanEnabled(c *Module) bool { - if c.sanitize == nil { + // If this is not a stub library, no check necessary + if !c.HasStubsVariants() { return false } - sanitizeProps := &c.sanitize.Properties.SanitizeMutated - return Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0 -} - -func GetApexConfigKey(ctx android.BaseModuleContext) *android.ApexConfigKey { - apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) - if !apexInfo.IsForPlatform() { - if !ctx.Config().BazelContext.IsModuleDclaAllowed(ctx.Module().Name()) { - return nil - } - apexKey := android.ApexConfigKey{ - WithinApex: true, - ApexSdkVersion: findApexSdkVersion(ctx, apexInfo).String(), - } - return &apexKey - } - - return nil -} - -func (c *Module) ProcessBazelQueryResponse(ctx android.ModuleContext) { - bazelModuleLabel := c.getBazelModuleLabel(ctx) - c.bazelHandler.ProcessBazelQueryResponse(ctx, bazelModuleLabel) - - c.Properties.SubName = GetSubnameProperty(ctx, c) - apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) - if !apexInfo.IsForPlatform() { - c.hideApexVariantFromMake = true + // Skip the allowlist + // Use BaseModuleName so that this matches prebuilts. + if _, exists := skipStubLibraryMultipleApexViolation[c.BaseModuleName()]; exists { + return false } - c.makeLinkType = GetMakeLinkType(ctx, c) - - mctx := &moduleContext{ - ModuleContext: ctx, - moduleContextImpl: moduleContextImpl{ - mod: c, - }, + _, aaWithoutTestApexes, _ := android.ListSetDifference(c.ApexAvailable(), c.TestApexes()) + // Stub libraries should not have more than one apex_available + if len(aaWithoutTestApexes) > 1 { + return true } - mctx.ctx = mctx - - // TODO(b/244432500): Get the tradefed config from the bazel target instead - // of generating it with Soong. - c.maybeInstall(mctx, apexInfo) -} - -func moduleContextFromAndroidModuleContext(actx android.ModuleContext, c *Module) ModuleContext { - ctx := &moduleContext{ - ModuleContext: actx, - moduleContextImpl: moduleContextImpl{ - mod: c, - }, + // Stub libraries should not use the wildcard + if aaWithoutTestApexes[0] == android.AvailableToAnyApex { + return true } - ctx.ctx = ctx - return ctx + // Default: no violation + return false } func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { - // Handle the case of a test module split by `test_per_src` mutator. - // - // The `test_per_src` mutator adds an extra variation named "", depending on all the other - // `test_per_src` variations of the test module. Set `outputFile` to an empty path for this - // module and return early, as this module does not produce an output file per se. - if c.IsTestPerSrcAllTestsVariation() { - c.outputFile = android.OptionalPath{} - return + ctx := moduleContextFromAndroidModuleContext(actx, c) + + c.logtagsPaths = android.PathsForModuleSrc(actx, c.Properties.Logtags) + android.SetProvider(ctx, android.LogtagsProviderKey, &android.LogtagsInfo{ + Logtags: c.logtagsPaths, + }) + + // If Test_only is set on a module in bp file, respect the setting, otherwise + // see if is a known test module type. + testOnly := c.testModule || c.testLibrary() + if c.sourceProperties.Test_only != nil { + testOnly = Bool(c.sourceProperties.Test_only) } + // Keep before any early returns. + android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ + TestOnly: testOnly, + TopLevelTarget: c.testModule, + }) c.Properties.SubName = GetSubnameProperty(actx, c) - apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo) + apexInfo, _ := android.ModuleProvider(actx, android.ApexInfoProvider) if !apexInfo.IsForPlatform() { c.hideApexVariantFromMake = true } c.makeLinkType = GetMakeLinkType(actx, c) - ctx := moduleContextFromAndroidModuleContext(actx, c) - deps := c.depsToPaths(ctx) if ctx.Failed() { return } + for _, generator := range c.generators { + gen := generator.GeneratorSources(ctx) + deps.IncludeDirs = append(deps.IncludeDirs, gen.IncludeDirs...) + deps.ReexportedDirs = append(deps.ReexportedDirs, gen.ReexportedDirs...) + deps.GeneratedDeps = append(deps.GeneratedDeps, gen.Headers...) + deps.ReexportedGeneratedHeaders = append(deps.ReexportedGeneratedHeaders, gen.Headers...) + deps.ReexportedDeps = append(deps.ReexportedDeps, gen.Headers...) + if len(deps.Objs.objFiles) == 0 { + // If we are reusuing object files (which happens when we're a shared library and we're + // reusing our static variant's object files), then skip adding the actual source files, + // because we already have the object for it. + deps.GeneratedSources = append(deps.GeneratedSources, gen.Sources...) + } + } + + if ctx.Failed() { + return + } + + if c.stubLibraryMultipleApexViolation(actx) { + actx.PropertyErrorf("apex_available", + "Stub libraries should have a single apex_available (test apexes excluded). Got %v", c.ApexAvailable()) + } if c.Properties.Clang != nil && *c.Properties.Clang == false { ctx.PropertyErrorf("clang", "false (GCC) is no longer supported") } else if c.Properties.Clang != nil && !ctx.DeviceConfig().BuildBrokenClangProperty() { @@ -2011,6 +1973,9 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { Toolchain: c.toolchain(ctx), EmitXrefs: ctx.Config().EmitXrefRules(), } + for _, generator := range c.generators { + flags = generator.GeneratorFlags(ctx, flags, deps) + } if c.compiler != nil { flags = c.compiler.compilerFlags(ctx, flags, deps) } @@ -2035,8 +2000,8 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { if c.afdo != nil { flags = c.afdo.flags(ctx, flags) } - 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) @@ -2068,6 +2033,10 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { flags.AssemblerWithCpp = inList("-xassembler-with-cpp", flags.Local.AsFlags) + for _, generator := range c.generators { + generator.GeneratorBuildActions(ctx, flags, deps) + } + var objs Objects if c.compiler != nil { objs = c.compiler.compile(ctx, flags, deps) @@ -2087,17 +2056,101 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { c.outputFile = android.OptionalPathForPath(outputFile) c.maybeUnhideFromMake() + } + if c.testModule { + android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{}) + } + + android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: deps.GeneratedSources.Strings()}) - // glob exported headers for snapshot, if BOARD_VNDK_VERSION is current or - // RECOVERY_SNAPSHOT_VERSION is current. - if i, ok := c.linker.(snapshotLibraryInterface); ok { - if ShouldCollectHeadersForSnapshot(ctx, c, apexInfo) { - i.collectHeadersForSnapshot(ctx) + if Bool(c.Properties.Cmake_snapshot_supported) { + android.SetProvider(ctx, cmakeSnapshotSourcesProvider, android.GlobFiles(ctx, ctx.ModuleDir()+"/**/*", nil)) + } + + c.maybeInstall(ctx, apexInfo) + + if c.linker != nil { + moduleInfoJSON := ctx.ModuleInfoJSON() + c.linker.moduleInfoJSON(ctx, moduleInfoJSON) + moduleInfoJSON.SharedLibs = c.Properties.AndroidMkSharedLibs + moduleInfoJSON.StaticLibs = c.Properties.AndroidMkStaticLibs + moduleInfoJSON.SystemSharedLibs = c.Properties.AndroidMkSystemSharedLibs + moduleInfoJSON.RuntimeDependencies = c.Properties.AndroidMkRuntimeLibs + + moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, c.Properties.AndroidMkSharedLibs...) + moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, c.Properties.AndroidMkStaticLibs...) + moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, c.Properties.AndroidMkHeaderLibs...) + moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, c.Properties.AndroidMkWholeStaticLibs...) + + if c.sanitize != nil && len(moduleInfoJSON.Class) > 0 && + (moduleInfoJSON.Class[0] == "STATIC_LIBRARIES" || moduleInfoJSON.Class[0] == "HEADER_LIBRARIES") { + if Bool(c.sanitize.Properties.SanitizeMutated.Cfi) { + moduleInfoJSON.SubName += ".cfi" + } + if Bool(c.sanitize.Properties.SanitizeMutated.Hwaddress) { + moduleInfoJSON.SubName += ".hwasan" } + if Bool(c.sanitize.Properties.SanitizeMutated.Scs) { + moduleInfoJSON.SubName += ".scs" + } + } + moduleInfoJSON.SubName += c.Properties.SubName + + if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake { + moduleInfoJSON.Uninstallable = true } } - c.maybeInstall(ctx, apexInfo) + buildComplianceMetadataInfo(ctx, c, deps) + + c.setOutputFiles(ctx) +} + +func (c *Module) setOutputFiles(ctx ModuleContext) { + if c.outputFile.Valid() { + ctx.SetOutputFiles(android.Paths{c.outputFile.Path()}, "") + } else { + ctx.SetOutputFiles(android.Paths{}, "") + } + if c.linker != nil { + ctx.SetOutputFiles(android.PathsIfNonNil(c.linker.unstrippedOutputFilePath()), "unstripped") + ctx.SetOutputFiles(android.PathsIfNonNil(c.linker.strippedAllOutputFilePath()), "stripped_all") + } +} + +func buildComplianceMetadataInfo(ctx ModuleContext, c *Module, deps PathDeps) { + // Dump metadata that can not be done in android/compliance-metadata.go + complianceMetadataInfo := ctx.ComplianceMetadataInfo() + complianceMetadataInfo.SetStringValue(android.ComplianceMetadataProp.IS_STATIC_LIB, strconv.FormatBool(ctx.static())) + complianceMetadataInfo.SetStringValue(android.ComplianceMetadataProp.BUILT_FILES, c.outputFile.String()) + + // Static deps + staticDeps := ctx.GetDirectDepsWithTag(StaticDepTag(false)) + staticDepNames := make([]string, 0, len(staticDeps)) + for _, dep := range staticDeps { + staticDepNames = append(staticDepNames, dep.Name()) + } + + staticDepPaths := make([]string, 0, len(deps.StaticLibs)) + for _, dep := range deps.StaticLibs { + staticDepPaths = append(staticDepPaths, dep.String()) + } + complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEPS, android.FirstUniqueStrings(staticDepNames)) + complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEP_FILES, android.FirstUniqueStrings(staticDepPaths)) + + // Whole static deps + wholeStaticDeps := ctx.GetDirectDepsWithTag(StaticDepTag(true)) + wholeStaticDepNames := make([]string, 0, len(wholeStaticDeps)) + for _, dep := range wholeStaticDeps { + wholeStaticDepNames = append(wholeStaticDepNames, dep.Name()) + } + + wholeStaticDepPaths := make([]string, 0, len(deps.WholeStaticLibs)) + for _, dep := range deps.WholeStaticLibs { + wholeStaticDepPaths = append(wholeStaticDepPaths, dep.String()) + } + complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.WHOLE_STATIC_DEPS, android.FirstUniqueStrings(wholeStaticDepNames)) + complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.WHOLE_STATIC_DEP_FILES, android.FirstUniqueStrings(wholeStaticDepPaths)) } func (c *Module) maybeUnhideFromMake() { @@ -2109,16 +2162,15 @@ func (c *Module) maybeUnhideFromMake() { // is explicitly referenced via .bootstrap suffix or the module is marked with // 'bootstrap: true'). if c.HasStubsVariants() && c.NotInPlatform() && !c.InRamdisk() && - !c.InRecovery() && !c.UseVndk() && !c.static() && !c.isCoverageVariant() && + !c.InRecovery() && !c.InVendorOrProduct() && !c.static() && !c.isCoverageVariant() && c.IsStubs() && !c.InVendorRamdisk() { c.Properties.HideFromMake = false // unhide // Note: this is still non-installable } } -// maybeInstall is called at the end of both GenerateAndroidBuildActions and -// ProcessBazelQueryResponse to run the install hooks for installable modules, -// like binaries and tests. +// maybeInstall is called at the end of both GenerateAndroidBuildActions to run the +// install hooks for installable modules, like binaries and tests. func (c *Module) maybeInstall(ctx ModuleContext, apexInfo android.ApexInfo) { if !proptools.BoolDefault(c.Installable(), true) { // If the module has been specifically configure to not be installed then @@ -2141,12 +2193,6 @@ func (c *Module) maybeInstall(ctx ModuleContext, apexInfo android.ApexInfo) { } } -func (c *Module) setAndroidMkVariablesFromCquery(info cquery.CcAndroidMkInfo) { - c.Properties.AndroidMkSharedLibs = info.LocalSharedLibs - c.Properties.AndroidMkStaticLibs = info.LocalStaticLibs - c.Properties.AndroidMkWholeStaticLibs = info.LocalWholeStaticLibs -} - func (c *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain { if c.cachedToolchain == nil { c.cachedToolchain = config.FindToolchainWithContext(ctx) @@ -2155,6 +2201,9 @@ func (c *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain { } func (c *Module) begin(ctx BaseModuleContext) { + for _, generator := range c.generators { + generator.GeneratorInit(ctx) + } if c.compiler != nil { c.compiler.compilerInit(ctx) } @@ -2170,11 +2219,14 @@ func (c *Module) begin(ctx BaseModuleContext) { if c.coverage != nil { c.coverage.begin(ctx) } + if c.afdo != nil { + c.afdo.begin(ctx) + } if c.lto != nil { c.lto.begin(ctx) } - if c.pgo != nil { - c.pgo.begin(ctx) + if c.orderfile != nil { + c.orderfile.begin(ctx) } if ctx.useSdk() && c.IsSdkVariant() { version, err := nativeApiLevelFromUser(ctx, ctx.sdkVersion()) @@ -2190,6 +2242,9 @@ func (c *Module) begin(ctx BaseModuleContext) { func (c *Module) deps(ctx DepsContext) Deps { deps := Deps{} + for _, generator := range c.generators { + deps = generator.GeneratorDeps(ctx, deps) + } if c.compiler != nil { deps = c.compiler.compilerDeps(ctx, deps) } @@ -2210,6 +2265,7 @@ func (c *Module) deps(ctx DepsContext) Deps { deps.LateSharedLibs = android.LastUniqueStrings(deps.LateSharedLibs) deps.HeaderLibs = android.LastUniqueStrings(deps.HeaderLibs) deps.RuntimeLibs = android.LastUniqueStrings(deps.RuntimeLibs) + deps.LlndkHeaderLibs = android.LastUniqueStrings(deps.LlndkHeaderLibs) for _, lib := range deps.ReexportSharedLibHeaders { if !inList(lib, deps.SharedLibs) { @@ -2247,10 +2303,6 @@ func (c *Module) beginMutator(actx android.BottomUpMutatorContext) { } ctx.ctx = ctx - if !actx.Host() || !ctx.static() || ctx.staticBinary() { - c.afdo.addDep(ctx, actx) - } - c.begin(ctx) } @@ -2326,9 +2378,9 @@ func GetApiImports(c LinkableInterface, actx android.BottomUpMutatorContext) mul if actx.OtherModuleExists("api_imports") { apiImportModule = actx.AddDependency(c, nil, "api_imports") if len(apiImportModule) > 0 && apiImportModule[0] != nil { - apiInfo := actx.OtherModuleProvider(apiImportModule[0], multitree.ApiImportsProvider).(multitree.ApiImportInfo) + apiInfo, _ := android.OtherModuleProvider(actx, apiImportModule[0], multitree.ApiImportsProvider) apiImportInfo = apiInfo - actx.SetProvider(multitree.ApiImportsProvider, apiInfo) + android.SetProvider(actx, multitree.ApiImportsProvider, apiInfo) } } } @@ -2336,31 +2388,6 @@ func GetApiImports(c LinkableInterface, actx android.BottomUpMutatorContext) mul return apiImportInfo } -func GetSnapshot(c LinkableInterface, snapshotInfo **SnapshotInfo, actx android.BottomUpMutatorContext) SnapshotInfo { - // Only device modules with BOARD_VNDK_VERSION uses snapshot. Others use the zero value of - // SnapshotInfo, which provides no mappings. - if *snapshotInfo == nil && c.Device() { - // Only retrieve the snapshot on demand in order to avoid circular dependencies - // between the modules in the snapshot and the snapshot itself. - var snapshotModule []blueprint.Module - if c.InVendor() && c.VndkVersion() == actx.DeviceConfig().VndkVersion() { - snapshotModule = actx.AddVariationDependencies(nil, nil, "vendor_snapshot") - } else if recoverySnapshotVersion := actx.DeviceConfig().RecoverySnapshotVersion(); recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" && c.InRecovery() { - snapshotModule = actx.AddVariationDependencies(nil, nil, "recovery_snapshot") - } - if len(snapshotModule) > 0 && snapshotModule[0] != nil { - snapshot := actx.OtherModuleProvider(snapshotModule[0], SnapshotInfoProvider).(SnapshotInfo) - *snapshotInfo = &snapshot - // republish the snapshot for use in later mutators on this module - actx.SetProvider(SnapshotInfoProvider, snapshot) - } - } - if *snapshotInfo == nil { - *snapshotInfo = &SnapshotInfo{} - } - return **snapshotInfo -} - func GetReplaceModuleName(lib string, replaceMap map[string]string) string { if snapshot, ok := replaceMap[lib]; ok { return snapshot @@ -2369,44 +2396,35 @@ func GetReplaceModuleName(lib string, replaceMap map[string]string) string { return lib } -// RewriteLibs takes a list of names of shared libraries and scans it for three types +// FilterNdkLibs takes a list of names of shared libraries and scans it for two types // of names: // -// 1. Name of an NDK library that refers to a prebuilt module. -// -// For each of these, it adds the name of the prebuilt module (which will be in -// prebuilts/ndk) to the list of nonvariant libs. -// -// 2. Name of an NDK library that refers to an ndk_library module. +// 1. Name of an NDK library that refers to an ndk_library module. // // For each of these, it adds the name of the ndk_library module to the list of // variant libs. // -// 3. Anything else (so anything that isn't an NDK library). +// 2. Anything else (so anything that isn't an NDK library). // // It adds these to the nonvariantLibs list. // // The caller can then know to add the variantLibs dependencies differently from the // nonvariantLibs -func RewriteLibs(c LinkableInterface, snapshotInfo **SnapshotInfo, actx android.BottomUpMutatorContext, config android.Config, list []string) (nonvariantLibs []string, variantLibs []string) { +func FilterNdkLibs(c LinkableInterface, config android.Config, list []string) (nonvariantLibs []string, variantLibs []string) { variantLibs = []string{} nonvariantLibs = []string{} for _, entry := range list { // strip #version suffix out name, _ := StubsLibNameAndVersion(entry) - if c.InRecovery() { - nonvariantLibs = append(nonvariantLibs, GetReplaceModuleName(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs)) - } else if c.UseSdk() && inList(name, *getNDKKnownLibs(config)) { + if c.UseSdk() && inList(name, *getNDKKnownLibs(config)) { variantLibs = append(variantLibs, name+ndkLibrarySuffix) - } else if c.UseVndk() { - nonvariantLibs = append(nonvariantLibs, GetReplaceModuleName(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs)) } else { - // put name#version back nonvariantLibs = append(nonvariantLibs, entry) } } return nonvariantLibs, variantLibs + } func rewriteLibsForApiImports(c LinkableInterface, libs []string, replaceList map[string]string, config android.Config) ([]string, []string) { @@ -2450,7 +2468,7 @@ func (c *Module) shouldUseApiSurface() bool { } func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { - if !c.Enabled() { + if !c.Enabled(actx) { return } @@ -2478,18 +2496,12 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs - var snapshotInfo *SnapshotInfo - variantNdkLibs := []string{} variantLateNdkLibs := []string{} if ctx.Os() == android.Android { - deps.SharedLibs, variantNdkLibs = RewriteLibs(c, &snapshotInfo, actx, ctx.Config(), deps.SharedLibs) - deps.LateSharedLibs, variantLateNdkLibs = RewriteLibs(c, &snapshotInfo, actx, ctx.Config(), deps.LateSharedLibs) - deps.ReexportSharedLibHeaders, _ = RewriteLibs(c, &snapshotInfo, actx, ctx.Config(), deps.ReexportSharedLibHeaders) - - for idx, lib := range deps.RuntimeLibs { - deps.RuntimeLibs[idx] = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).SharedLibs) - } + deps.SharedLibs, variantNdkLibs = FilterNdkLibs(c, ctx.Config(), deps.SharedLibs) + deps.LateSharedLibs, variantLateNdkLibs = FilterNdkLibs(c, ctx.Config(), deps.LateSharedLibs) + deps.ReexportSharedLibHeaders, _ = FilterNdkLibs(c, ctx.Config(), deps.ReexportSharedLibHeaders) } for _, lib := range deps.HeaderLibs { @@ -2502,7 +2514,6 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { if c.shouldUseApiSurface() { lib = GetReplaceModuleName(lib, apiImportInfo.HeaderLibs) } - lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).HeaderLibs) if c.isNDKStubLibrary() { // ndk_headers do not have any variations @@ -2525,27 +2536,33 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { ), stubImplementation, c.BaseModuleName()) } + // If this module is an LLNDK implementation library, let it depend on LlndkHeaderLibs. + if c.ImageVariation().Variation == android.CoreVariation && c.Device() && + c.Target().NativeBridge == android.NativeBridgeDisabled { + actx.AddVariationDependencies( + []blueprint.Variation{{Mutator: "image", Variation: android.VendorVariation}}, + llndkHeaderLibTag, + deps.LlndkHeaderLibs...) + } + for _, lib := range deps.WholeStaticLibs { depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true, reexportFlags: true} - lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs) - actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, }, depTag, lib) } for _, lib := range deps.StaticLibs { + // Some dependencies listed in static_libs might actually be rust_ffi rlib variants. depTag := libraryDependencyTag{Kind: staticLibraryDependency} + if inList(lib, deps.ReexportStaticLibHeaders) { depTag.reexportFlags = true } if inList(lib, deps.ExcludeLibsForApex) { depTag.excludeInApex = true } - - lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs) - actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, }, depTag, lib) @@ -2558,7 +2575,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { depTag := libraryDependencyTag{Kind: staticLibraryDependency, staticUnwinder: true} actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, - }, depTag, GetReplaceModuleName(staticUnwinder(actx), GetSnapshot(c, &snapshotInfo, actx).StaticLibs)) + }, depTag, staticUnwinder(actx)) } // shared lib names without the #version suffix @@ -2572,6 +2589,9 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { if inList(lib, deps.ExcludeLibsForApex) { depTag.excludeInApex = true } + if inList(lib, deps.ExcludeLibsForNonApex) { + depTag.excludeInNonApex = true + } name, version := StubsLibNameAndVersion(lib) if apiLibraryName, ok := apiImportInfo.SharedLibs[name]; ok && !ctx.OtherModuleExists(name) { @@ -2596,14 +2616,14 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency} actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, - }, depTag, GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)) + }, depTag, lib) } for _, lib := range deps.UnexportedStaticLibs { depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency, unexportedSymbols: true} actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, - }, depTag, GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)) + }, depTag, lib) } for _, lib := range deps.LateSharedLibs { @@ -2644,11 +2664,11 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { actx.AddVariationDependencies(crtVariations, objDepTag, deps.ObjFiles...) for _, crt := range deps.CrtBegin { actx.AddVariationDependencies(crtVariations, CrtBeginDepTag, - GetReplaceModuleName(crt, GetSnapshot(c, &snapshotInfo, actx).Objects)) + crt) } for _, crt := range deps.CrtEnd { actx.AddVariationDependencies(crtVariations, CrtEndDepTag, - GetReplaceModuleName(crt, GetSnapshot(c, &snapshotInfo, actx).Objects)) + crt) } if deps.DynamicLinker != "" { actx.AddDependency(c, dynamicLinkerDepTag, deps.DynamicLinker) @@ -2676,20 +2696,19 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { {Mutator: "link", Variation: "shared"}, }, ndkLateStubDepTag, apiLateNdkLibs...) - if vndkdep := c.vndkdep; vndkdep != nil { - if vndkdep.isVndkExt() { - actx.AddVariationDependencies([]blueprint.Variation{ - c.ImageVariation(), - {Mutator: "link", Variation: "shared"}, - }, vndkExtDepTag, GetReplaceModuleName(vndkdep.getVndkExtendsModuleName(), GetSnapshot(c, &snapshotInfo, actx).SharedLibs)) - } + if len(deps.AidlLibs) > 0 { + actx.AddDependency( + c, + aidlLibraryTag, + deps.AidlLibs..., + ) } updateImportedLibraryDependency(ctx) } func BeginMutator(ctx android.BottomUpMutatorContext) { - if c, ok := ctx.Module().(*Module); ok && c.Enabled() { + if c, ok := ctx.Module().(*Module); ok && c.Enabled(ctx) { c.beginMutator(ctx) } } @@ -2714,20 +2733,6 @@ func checkLinkType(ctx android.BaseModuleContext, from LinkableInterface, to Lin return } - // VNDK is cc.Module supported only for now. - if ccFrom, ok := from.(*Module); ok && from.UseVndk() { - // Though allowed dependency is limited by the image mutator, - // each vendor and product module needs to check link-type - // for VNDK. - if ccTo, ok := to.(*Module); ok { - if ccFrom.vndkdep != nil { - ccFrom.vndkdep.vndkCheckLinkType(ctx, ccTo, tag) - } - } else if _, ok := to.(LinkableInterface); !ok { - ctx.ModuleErrorf("Attempting to link VNDK cc.Module with unsupported module type") - } - return - } // TODO(b/244244438) : Remove this once all variants are implemented if ccFrom, ok := from.(*Module); ok && ccFrom.isImportedApiLibrary() { return @@ -2790,20 +2795,20 @@ func checkLinkType(ctx android.BaseModuleContext, from LinkableInterface, to Lin ctx.ModuleErrorf("links %q built against newer API version %q", ctx.OtherModuleName(to.Module()), "current") } else { - fromApi, err := strconv.Atoi(from.SdkVersion()) + fromApi, err := android.ApiLevelFromUserWithConfig(ctx.Config(), from.SdkVersion()) if err != nil { ctx.PropertyErrorf("sdk_version", - "Invalid sdk_version value (must be int or current): %q", + "Invalid sdk_version value (must be int, preview or current): %q", from.SdkVersion()) } - toApi, err := strconv.Atoi(to.SdkVersion()) + toApi, err := android.ApiLevelFromUserWithConfig(ctx.Config(), to.SdkVersion()) if err != nil { ctx.PropertyErrorf("sdk_version", - "Invalid sdk_version value (must be int or current): %q", + "Invalid sdk_version value (must be int, preview or current): %q", to.SdkVersion()) } - if toApi > fromApi { + if toApi.GreaterThan(fromApi) { ctx.ModuleErrorf("links %q built against newer API version %q", ctx.OtherModuleName(to.Module()), to.SdkVersion()) } @@ -2865,6 +2870,9 @@ func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) { if depTag == stubImplDepTag { return false } + if depTag == android.RequiredDepTag { + return false + } // Even if target lib has no vendor variant, keep checking dependency // graph in case it depends on vendor_available or product_available @@ -2879,7 +2887,7 @@ func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) { return true } - if to.IsVndkSp() || to.IsLlndk() { + if to.IsLlndk() { return false } @@ -2929,7 +2937,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.ReexportedGeneratedHeaders = append(depPaths.ReexportedGeneratedHeaders, exporter.GeneratedHeaders...) } - apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) + apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) c.apexSdkVersion = findApexSdkVersion(ctx, apexInfo) skipModuleList := map[string]bool{} @@ -2939,7 +2947,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { ctx.VisitDirectDeps(func(dep android.Module) { if dep.Name() == "api_imports" { - apiImportInfo = ctx.OtherModuleProvider(dep, multitree.ApiImportsProvider).(multitree.ApiImportInfo) + apiImportInfo, _ = android.OtherModuleProvider(ctx, dep, multitree.ApiImportsProvider) hasApiImportInfo = true } }) @@ -2989,6 +2997,15 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } + if depTag == aidlLibraryTag { + if aidlLibraryInfo, ok := android.OtherModuleProvider(ctx, dep, aidl_library.AidlLibraryProvider); ok { + depPaths.AidlLibraryInfos = append( + depPaths.AidlLibraryInfos, + aidlLibraryInfo, + ) + } + } + ccDep, ok := dep.(LinkableInterface) if !ok { @@ -3033,6 +3050,10 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } + if depTag == android.RequiredDepTag { + return + } + if dep.Target().Os != ctx.Os() { ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName) return @@ -3049,15 +3070,21 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // version mutator, so the stubs variant is created from the shared variant that // already has the reuseObjTag dependency on the static variant. if !c.library.buildStubs() { - staticAnalogue := ctx.OtherModuleProvider(dep, StaticLibraryInfoProvider).(StaticLibraryInfo) + staticAnalogue, _ := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider) objs := staticAnalogue.ReuseObjects depPaths.Objs = depPaths.Objs.Append(objs) - depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo) + depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider) reexportExporter(depExporterInfo) } return } + if depTag == llndkHeaderLibTag { + depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider) + depPaths.LlndkIncludeDirs = append(depPaths.LlndkIncludeDirs, depExporterInfo.IncludeDirs...) + depPaths.LlndkSystemIncludeDirs = append(depPaths.LlndkSystemIncludeDirs, depExporterInfo.SystemIncludeDirs...) + } + linkFile := ccDep.OutputFile() if libDepTag, ok := depTag.(libraryDependencyTag); ok { @@ -3069,8 +3096,11 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if !apexInfo.IsForPlatform() && libDepTag.excludeInApex { return } + if apexInfo.IsForPlatform() && libDepTag.excludeInNonApex { + return + } - depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo) + depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider) var ptr *android.Paths var depPtr *android.Paths @@ -3079,7 +3109,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { switch { case libDepTag.header(): - if !ctx.OtherModuleHasProvider(dep, HeaderLibraryInfoProvider) { + if _, isHeaderLib := android.OtherModuleProvider(ctx, dep, HeaderLibraryInfoProvider); !isHeaderLib { if !ctx.Config().AllowMissingDependencies() { ctx.ModuleErrorf("module %q is not a header library", depName) } else { @@ -3088,7 +3118,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } case libDepTag.shared(): - if !ctx.OtherModuleHasProvider(dep, SharedLibraryInfoProvider) { + if _, isSharedLib := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider); !isSharedLib { if !ctx.Config().AllowMissingDependencies() { ctx.ModuleErrorf("module %q is not a shared library", depName) } else { @@ -3124,65 +3154,87 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { default: panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order)) } + case libDepTag.static(): - if !ctx.OtherModuleHasProvider(dep, StaticLibraryInfoProvider) { - if !ctx.Config().AllowMissingDependencies() { - ctx.ModuleErrorf("module %q is not a static library", depName) - } else { - ctx.AddMissingDependencies([]string{depName}) + if ccDep.RustLibraryInterface() { + rlibDep := RustRlibDep{LibPath: linkFile.Path(), CrateName: ccDep.CrateName(), LinkDirs: ccDep.ExportedCrateLinkDirs()} + depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, rlibDep) + depPaths.IncludeDirs = append(depPaths.IncludeDirs, depExporterInfo.IncludeDirs...) + if libDepTag.wholeStatic { + depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, depExporterInfo.IncludeDirs...) + depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, rlibDep) + + // If whole_static, track this as we want to make sure that in a final linkage for a shared library, + // exported functions from the rust generated staticlib still exported. + if c.CcLibrary() && c.Shared() { + c.WholeRustStaticlib = true + } } - return - } - // Stubs lib doesn't link to the static lib dependencies. Don't set - // linkFile, depFile, and ptr. - if c.IsStubs() { - break - } + } else { + staticLibraryInfo, isStaticLib := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider) + if !isStaticLib { + if !ctx.Config().AllowMissingDependencies() { + ctx.ModuleErrorf("module %q is not a static library", depName) + } else { + ctx.AddMissingDependencies([]string{depName}) + } + return + } + + // Stubs lib doesn't link to the static lib dependencies. Don't set + // linkFile, depFile, and ptr. + if c.IsStubs() { + break + } - staticLibraryInfo := ctx.OtherModuleProvider(dep, StaticLibraryInfoProvider).(StaticLibraryInfo) - linkFile = android.OptionalPathForPath(staticLibraryInfo.StaticLibrary) - if libDepTag.wholeStatic { - ptr = &depPaths.WholeStaticLibs - if len(staticLibraryInfo.Objects.objFiles) > 0 { - depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLibraryInfo.Objects) + linkFile = android.OptionalPathForPath(staticLibraryInfo.StaticLibrary) + if libDepTag.wholeStatic { + ptr = &depPaths.WholeStaticLibs + if len(staticLibraryInfo.Objects.objFiles) > 0 { + depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLibraryInfo.Objects) + } else { + // This case normally catches prebuilt static + // libraries, but it can also occur when + // AllowMissingDependencies is on and the + // dependencies has no sources of its own + // but has a whole_static_libs dependency + // on a missing library. We want to depend + // on the .a file so that there is something + // in the dependency tree that contains the + // error rule for the missing transitive + // dependency. + depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, linkFile.Path()) + } + depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, + staticLibraryInfo.WholeStaticLibsFromPrebuilts...) } else { - // This case normally catches prebuilt static - // libraries, but it can also occur when - // AllowMissingDependencies is on and the - // dependencies has no sources of its own - // but has a whole_static_libs dependency - // on a missing library. We want to depend - // on the .a file so that there is something - // in the dependency tree that contains the - // error rule for the missing transitive - // dependency. - depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, linkFile.Path()) + switch libDepTag.Order { + case earlyLibraryDependency: + panic(fmt.Errorf("early static libs not supported")) + case normalLibraryDependency: + // static dependencies will be handled separately so they can be ordered + // using transitive dependencies. + ptr = nil + directStaticDeps = append(directStaticDeps, staticLibraryInfo) + case lateLibraryDependency: + ptr = &depPaths.LateStaticLibs + default: + panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order)) + } } - depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, - staticLibraryInfo.WholeStaticLibsFromPrebuilts...) - } else { - switch libDepTag.Order { - case earlyLibraryDependency: - panic(fmt.Errorf("early static libs not suppported")) - case normalLibraryDependency: - // static dependencies will be handled separately so they can be ordered - // using transitive dependencies. - ptr = nil - directStaticDeps = append(directStaticDeps, staticLibraryInfo) - case lateLibraryDependency: - ptr = &depPaths.LateStaticLibs - default: - panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order)) + + // Collect any exported Rust rlib deps from static libraries which have been included as whole_static_libs + depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, depExporterInfo.RustRlibDeps...) + + if libDepTag.unexportedSymbols { + depPaths.LdFlags = append(depPaths.LdFlags, + "-Wl,--exclude-libs="+staticLibraryInfo.StaticLibrary.Base()) } } - if libDepTag.unexportedSymbols { - depPaths.LdFlags = append(depPaths.LdFlags, - "-Wl,--exclude-libs="+staticLibraryInfo.StaticLibrary.Base()) - } } - if libDepTag.static() && !libDepTag.wholeStatic { + if libDepTag.static() && !libDepTag.wholeStatic && !ccDep.RustLibraryInterface() { if !ccDep.CcLibraryInterface() || !ccDep.Static() { ctx.ModuleErrorf("module %q not a static library", depName) return @@ -3228,19 +3280,25 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, depExporterInfo.SystemIncludeDirs...) depPaths.GeneratedDeps = append(depPaths.GeneratedDeps, depExporterInfo.Deps...) depPaths.Flags = append(depPaths.Flags, depExporterInfo.Flags...) + depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, depExporterInfo.RustRlibDeps...) + + // Only re-export RustRlibDeps for cc static libs + if c.static() { + depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, depExporterInfo.RustRlibDeps...) + } if libDepTag.reexportFlags { reexportExporter(depExporterInfo) // Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library. // Re-exported shared library headers must be included as well since they can help us with type information // about template instantiations (instantiated from their headers). - // -isystem headers are not included since for bionic libraries, abi-filtering is taken care of by version - // scripts. c.sabi.Properties.ReexportedIncludes = append( c.sabi.Properties.ReexportedIncludes, depExporterInfo.IncludeDirs.Strings()...) + c.sabi.Properties.ReexportedSystemIncludes = append( + c.sabi.Properties.ReexportedSystemIncludes, depExporterInfo.SystemIncludeDirs.Strings()...) } - makeLibName := MakeLibName(ctx, c, ccDep, depName) + libDepTag.makeSuffix + makeLibName := MakeLibName(ctx, c, ccDep, ccDep.BaseModuleName()) + libDepTag.makeSuffix switch { case libDepTag.header(): c.Properties.AndroidMkHeaderLibs = append( @@ -3250,7 +3308,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if lib.buildStubs() && dep.(android.ApexModule).InAnyApex() { // Add the dependency to the APEX(es) providing the library so that // m <module> can trigger building the APEXes as well. - depApexInfo := ctx.OtherModuleProvider(dep, android.ApexInfoProvider).(android.ApexInfo) + depApexInfo, _ := android.OtherModuleProvider(ctx, dep, android.ApexInfoProvider) for _, an := range depApexInfo.InApexVariants { c.Properties.ApexesProvidingSharedLibs = append( c.Properties.ApexesProvidingSharedLibs, an) @@ -3262,18 +3320,16 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // they merely serve as Make dependencies and do not affect this lib itself. c.Properties.AndroidMkSharedLibs = append( c.Properties.AndroidMkSharedLibs, makeLibName) - // Record BaseLibName for snapshots. - c.Properties.SnapshotSharedLibs = append(c.Properties.SnapshotSharedLibs, BaseLibName(depName)) case libDepTag.static(): - if libDepTag.wholeStatic { - c.Properties.AndroidMkWholeStaticLibs = append( - c.Properties.AndroidMkWholeStaticLibs, makeLibName) - } else { - c.Properties.AndroidMkStaticLibs = append( - c.Properties.AndroidMkStaticLibs, makeLibName) + if !ccDep.RustLibraryInterface() { + if libDepTag.wholeStatic { + c.Properties.AndroidMkWholeStaticLibs = append( + c.Properties.AndroidMkWholeStaticLibs, makeLibName) + } else { + c.Properties.AndroidMkStaticLibs = append( + c.Properties.AndroidMkStaticLibs, makeLibName) + } } - // Record BaseLibName for snapshots. - c.Properties.SnapshotStaticLibs = append(c.Properties.SnapshotStaticLibs, BaseLibName(depName)) } } else if !c.IsStubs() { // Stubs lib doesn't link to the runtime lib, object, crt, etc. dependencies. @@ -3281,9 +3337,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { switch depTag { case runtimeDepTag: c.Properties.AndroidMkRuntimeLibs = append( - c.Properties.AndroidMkRuntimeLibs, MakeLibName(ctx, c, ccDep, depName)+libDepTag.makeSuffix) - // Record BaseLibName for snapshots. - c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, BaseLibName(depName)) + c.Properties.AndroidMkRuntimeLibs, MakeLibName(ctx, c, ccDep, ccDep.BaseModuleName())+libDepTag.makeSuffix) case objDepTag: depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path()) case CrtBeginDepTag: @@ -3306,14 +3360,18 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.IncludeDirs = android.FirstUniquePaths(depPaths.IncludeDirs) depPaths.SystemIncludeDirs = android.FirstUniquePaths(depPaths.SystemIncludeDirs) depPaths.GeneratedDeps = android.FirstUniquePaths(depPaths.GeneratedDeps) + depPaths.RustRlibDeps = android.FirstUniqueFunc(depPaths.RustRlibDeps, EqRustRlibDeps) + depPaths.ReexportedDirs = android.FirstUniquePaths(depPaths.ReexportedDirs) depPaths.ReexportedSystemDirs = android.FirstUniquePaths(depPaths.ReexportedSystemDirs) depPaths.ReexportedFlags = android.FirstUniqueStrings(depPaths.ReexportedFlags) depPaths.ReexportedDeps = android.FirstUniquePaths(depPaths.ReexportedDeps) depPaths.ReexportedGeneratedHeaders = android.FirstUniquePaths(depPaths.ReexportedGeneratedHeaders) + depPaths.ReexportedRustRlibDeps = android.FirstUniqueFunc(depPaths.ReexportedRustRlibDeps, EqRustRlibDeps) if c.sabi != nil { c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes) + c.sabi.Properties.ReexportedSystemIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedSystemIncludes) } return depPaths @@ -3326,20 +3384,20 @@ func ShouldUseStubForApex(ctx android.ModuleContext, dep android.Module) bool { panic(fmt.Errorf("Not an APEX module: %q", ctx.ModuleName())) } - useVndk := false + inVendorOrProduct := false bootstrap := false if linkable, ok := ctx.Module().(LinkableInterface); !ok { panic(fmt.Errorf("Not a Linkable module: %q", ctx.ModuleName())) } else { - useVndk = linkable.UseVndk() + inVendorOrProduct = linkable.InVendorOrProduct() bootstrap = linkable.Bootstrap() } - apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) + apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) useStubs := false - if lib := moduleLibraryInterface(dep); lib.buildStubs() && useVndk { // LLNDK + if lib := moduleLibraryInterface(dep); lib.buildStubs() && inVendorOrProduct { // LLNDK if !apexInfo.IsForPlatform() { // For platform libraries, use current version of LLNDK // If this is for use_vendor apex we will apply the same rules @@ -3369,7 +3427,7 @@ func ShouldUseStubForApex(ctx android.ModuleContext, dep android.Module) bool { // Another exception: if this module is a test for an APEX, then // it is linked with the non-stub variant of a module in the APEX // as if this is part of the APEX. - testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo) + testFor, _ := android.ModuleProvider(ctx, android.ApexTestForInfoProvider) for _, apexContents := range testFor.ApexContents { if apexContents.DirectlyInApex(depName) { useStubs = false @@ -3415,9 +3473,9 @@ func ChooseStubOrImpl(ctx android.ModuleContext, dep android.Module) (SharedLibr panic(fmt.Errorf("Unexpected dependency tag: %T", depTag)) } - sharedLibraryInfo := ctx.OtherModuleProvider(dep, SharedLibraryInfoProvider).(SharedLibraryInfo) - depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo) - sharedLibraryStubsInfo := ctx.OtherModuleProvider(dep, SharedLibraryStubsProvider).(SharedLibraryStubsInfo) + sharedLibraryInfo, _ := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider) + depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider) + sharedLibraryStubsInfo, _ := android.OtherModuleProvider(ctx, dep, SharedLibraryStubsProvider) if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedStubLibraries) > 0 { // when to use (unspecified) stubs, use the latest one. @@ -3435,8 +3493,8 @@ func ChooseStubOrImpl(ctx android.ModuleContext, dep android.Module) (SharedLibr // to match the topological order of the dependency tree, including any static analogues of // direct shared libraries. It returns the ordered static dependencies, and an android.DepSet // of the transitive dependencies. -func orderStaticModuleDeps(staticDeps []StaticLibraryInfo, sharedDeps []SharedLibraryInfo) (ordered android.Paths, transitive *android.DepSet) { - transitiveStaticLibsBuilder := android.NewDepSetBuilder(android.TOPOLOGICAL) +func orderStaticModuleDeps(staticDeps []StaticLibraryInfo, sharedDeps []SharedLibraryInfo) (ordered android.Paths, transitive *android.DepSet[android.Path]) { + transitiveStaticLibsBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL) var staticPaths android.Paths for _, staticDep := range staticDeps { staticPaths = append(staticPaths, staticDep.StaticLibrary) @@ -3486,12 +3544,7 @@ func MakeLibName(ctx android.ModuleContext, c LinkableInterface, ccDep LinkableI } } - if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && - !c.InRamdisk() && !c.InVendorRamdisk() && !c.InRecovery() { - // The vendor module is a no-vendor-variant VNDK library. Depend on the - // core module instead. - return libName - } else if ccDep.UseVndk() && nonSystemVariantsExist { + if ccDep.InVendorOrProduct() && nonSystemVariantsExist { // The vendor and product modules in Make will have been renamed to not conflict with the // core module, so update the dependency name here accordingly. return libName + ccDep.SubName() @@ -3556,23 +3609,6 @@ func (c *Module) IntermPathForModuleOut() android.OptionalPath { return c.outputFile } -func (c *Module) OutputFiles(tag string) (android.Paths, error) { - switch tag { - case "": - if c.outputFile.Valid() { - return android.Paths{c.outputFile.Path()}, nil - } - return android.Paths{}, nil - case "unstripped": - if c.linker != nil { - return android.PathsIfNonNil(c.linker.unstrippedOutputFilePath()), nil - } - return nil, nil - default: - return nil, fmt.Errorf("unsupported module reference tag %q", tag) - } -} - func (c *Module) static() bool { if static, ok := c.linker.(interface { static() bool @@ -3662,18 +3698,17 @@ func (c *Module) Object() bool { return false } +func (m *Module) Dylib() bool { + return false +} + +func (m *Module) Rlib() bool { + return false +} + func GetMakeLinkType(actx android.ModuleContext, c LinkableInterface) string { - if c.UseVndk() { + if c.InVendorOrProduct() { if c.IsLlndk() { - if !c.IsLlndkPublic() { - return "native:vndk_private" - } - return "native:vndk" - } - if c.IsVndk() && !c.IsVndkExt() { - if c.IsVndkPrivate() { - return "native:vndk_private" - } return "native:vndk" } if c.InProduct() { @@ -3691,22 +3726,18 @@ func GetMakeLinkType(actx android.ModuleContext, c LinkableInterface) string { // TODO(b/114741097): use the correct ndk stl once build errors have been fixed //family, link := getNdkStlFamilyAndLinkType(c) //return fmt.Sprintf("native:ndk:%s:%s", family, link) - } else if actx.DeviceConfig().VndkUseCoreVariant() && !c.MustUseVendorVariant() { - return "native:platform_vndk" } else { return "native:platform" } } // Overrides ApexModule.IsInstallabeToApex() -// Only shared/runtime libraries and "test_per_src" tests are installable to APEX. +// Only shared/runtime libraries . func (c *Module) IsInstallableToApex() bool { if lib := c.library; lib != nil { // Stub libs and prebuilt libs in a versioned SDK are not // installable to APEX even though they are shared libs. return lib.shared() && !lib.buildStubs() - } else if _, ok := c.linker.(testPerSrc); ok { - return true } return false } @@ -3877,15 +3908,6 @@ func (c *Module) AlwaysRequiresPlatformApexVariant() bool { return c.IsStubs() || c.Target().NativeBridge == android.NativeBridgeEnabled } -// Overrides android.ApexModuleBase.UniqueApexVariations -func (c *Module) UniqueApexVariations() bool { - // When a vendor APEX needs a VNDK lib in it (use_vndk_as_stable: false), it should be a unique - // APEX variation. Otherwise, another vendor APEX with use_vndk_as_stable:true may use a wrong - // variation of the VNDK lib because APEX variations are merged/grouped. - // TODO(b/274401041) Find a way to merge APEX variations for vendor apexes. - return c.UseVndk() && c.IsVndk() -} - func (c *Module) overriddenModules() []string { if o, ok := c.linker.(overridable); ok { return o.overriddenModules() @@ -3893,8 +3915,6 @@ func (c *Module) overriddenModules() []string { return nil } -var _ snapshot.RelativeInstallPath = (*Module)(nil) - type moduleType int const ( @@ -3907,6 +3927,7 @@ const ( headerLibrary testBin // testBinary already declared ndkLibrary + ndkPrebuiltStl ) func (c *Module) typ() moduleType { @@ -3923,8 +3944,8 @@ func (c *Module) typ() moduleType { // TODO(b/244431896) properly convert cc_test_library to its own macro. This // will let them add implicit compile deps on gtest, for example. // - // For now, treat them as regular shared libraries. - return sharedLibrary + // For now, treat them as regular libraries. + return fullLibrary } else if c.CcLibrary() { static := false shared := false @@ -3945,73 +3966,12 @@ func (c *Module) typ() moduleType { return sharedLibrary } else if c.isNDKStubLibrary() { return ndkLibrary + } else if c.IsNdkPrebuiltStl() { + return ndkPrebuiltStl } return unknownType } -// ConvertWithBp2build converts Module to Bazel for bp2build. -func (c *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - prebuilt := c.IsPrebuilt() - switch c.typ() { - case binary: - if prebuilt { - prebuiltBinaryBp2Build(ctx, c) - } else { - binaryBp2build(ctx, c) - } - case testBin: - if !prebuilt { - testBinaryBp2build(ctx, c) - } - case object: - if prebuilt { - prebuiltObjectBp2Build(ctx, c) - } else { - objectBp2Build(ctx, c) - } - case fullLibrary: - if !prebuilt { - libraryBp2Build(ctx, c) - } else { - prebuiltLibraryBp2Build(ctx, c) - } - case headerLibrary: - libraryHeadersBp2Build(ctx, c) - case staticLibrary: - if prebuilt { - prebuiltLibraryStaticBp2Build(ctx, c, false) - } else { - sharedOrStaticLibraryBp2Build(ctx, c, true) - } - case sharedLibrary: - if prebuilt { - prebuiltLibrarySharedBp2Build(ctx, c) - } else { - sharedOrStaticLibraryBp2Build(ctx, c, false) - } - } -} - -var _ android.ApiProvider = (*Module)(nil) - -func (c *Module) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) { - if c.IsPrebuilt() { - return - } - switch c.typ() { - case fullLibrary: - apiContributionBp2Build(ctx, c) - case sharedLibrary: - apiContributionBp2Build(ctx, c) - case headerLibrary: - // Aggressively generate api targets for all header modules - // This is necessary since the header module does not know if it is a dep of API surface stub library - apiLibraryHeadersBp2Build(ctx, c) - case ndkLibrary: - ndkLibraryBp2build(ctx, c) - } -} - // Defaults type Defaults struct { android.ModuleBase @@ -4055,10 +4015,9 @@ func DefaultsFactory(props ...interface{}) android.Module { &TidyProperties{}, &CoverageProperties{}, &SAbiProperties{}, - &VndkProperties{}, <OProperties{}, &AfdoProperties{}, - &PgoProperties{}, + &OrderfileProperties{}, &android.ProtoProperties{}, // RustBindgenProperties is included here so that cc_defaults can be used for rust_bindgen modules. &RustBindgenClangProperties{}, @@ -4108,6 +4067,18 @@ func (c *Module) Partition() string { return "" } +type sourceModuleName interface { + sourceModuleName() string +} + +func (c *Module) BaseModuleName() string { + if smn, ok := c.linker.(sourceModuleName); ok && smn.sourceModuleName() != "" { + // if the prebuilt module sets a source_module_name in Android.bp, use that + return smn.sourceModuleName() + } + return c.ModuleBase.BaseModuleName() +} + var Bool = proptools.Bool var BoolDefault = proptools.BoolDefault var BoolPtr = proptools.BoolPtr diff --git a/cc/cc_test.go b/cc/cc_test.go index 3ae4b1561..ccdaae58f 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -17,15 +17,16 @@ package cc import ( "fmt" "os" - "path/filepath" "reflect" "regexp" "runtime" "strings" "testing" + "android/soong/aidl_library" "android/soong/android" - "android/soong/bazel/cquery" + + "github.com/google/blueprint" ) func init() { @@ -37,35 +38,21 @@ func TestMain(m *testing.M) { } var prepareForCcTest = android.GroupFixturePreparers( - PrepareForTestWithCcIncludeVndk, + PrepareForIntegrationTestWithCc, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.DeviceVndkVersion = StringPtr("current") - variables.ProductVndkVersion = StringPtr("current") - variables.Platform_vndk_version = StringPtr("29") + variables.VendorApiLevel = StringPtr("202404") }), ) -var ccLibInApex = "cc_lib_in_apex" var apexVariationName = "apex28" var apexVersion = "28" func registerTestMutators(ctx android.RegistrationContext) { ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("apex", testApexMutator).Parallel() - ctx.BottomUp("mixed_builds_prep", mixedBuildsPrepareMutator).Parallel() }) } -func mixedBuildsPrepareMutator(ctx android.BottomUpMutatorContext) { - if m := ctx.Module(); m.Enabled() { - if mixedBuildMod, ok := m.(android.MixedBuildBuildable); ok { - if mixedBuildMod.IsMixedBuildSupported(ctx) && android.MixedBuildsEnabled(ctx) { - mixedBuildMod.QueueBazelCall(ctx) - } - } - } -} - func testApexMutator(mctx android.BottomUpMutatorContext) { modules := mctx.CreateVariations(apexVariationName) apexInfo := android.ApexInfo{ @@ -103,33 +90,6 @@ func testCc(t *testing.T, bp string) *android.TestContext { return result.TestContext } -// testCcNoVndk runs tests using the prepareForCcTest -// -// See testCc for an explanation as to how to stop using this deprecated method. -// -// deprecated -func testCcNoVndk(t *testing.T, bp string) *android.TestContext { - t.Helper() - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - - return testCcWithConfig(t, config) -} - -// testCcNoProductVndk runs tests using the prepareForCcTest -// -// See testCc for an explanation as to how to stop using this deprecated method. -// -// deprecated -func testCcNoProductVndk(t *testing.T, bp string) *android.TestContext { - t.Helper() - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - - return testCcWithConfig(t, config) -} - // testCcErrorWithConfig runs tests using the prepareForCcTest // // See testCc for an explanation as to how to stop using this deprecated method. @@ -151,31 +111,14 @@ func testCcErrorWithConfig(t *testing.T, pattern string, config android.Config) func testCcError(t *testing.T, pattern string, bp string) { t.Helper() config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - testCcErrorWithConfig(t, pattern, config) - return -} - -// testCcErrorProductVndk runs tests using the prepareForCcTest -// -// See testCc for an explanation as to how to stop using this deprecated method. -// -// deprecated -func testCcErrorProductVndk(t *testing.T, pattern string, bp string) { - t.Helper() - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.ProductVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") testCcErrorWithConfig(t, pattern, config) return } const ( coreVariant = "android_arm64_armv8-a_shared" - vendorVariant = "android_vendor.29_arm64_armv8-a_shared" - productVariant = "android_product.29_arm64_armv8-a_shared" + vendorVariant = "android_vendor_arm64_armv8-a_shared" + productVariant = "android_product_arm64_armv8-a_shared" recoveryVariant = "android_recovery_arm64_armv8-a_shared" ) @@ -234,13 +177,13 @@ func checkInstallPartition(t *testing.T, ctx *android.TestContext, name, variant } } socSpecific := func(m *Module) bool { - return m.SocSpecific() || m.socSpecificModuleContext() + return m.SocSpecific() || m.InstallInVendor() } deviceSpecific := func(m *Module) bool { - return m.DeviceSpecific() || m.deviceSpecificModuleContext() + return m.DeviceSpecific() || m.InstallInOdm() } productSpecific := func(m *Module) bool { - return m.ProductSpecific() || m.productSpecificModuleContext() + return m.ProductSpecific() || m.InstallInProduct() } systemExtSpecific := func(m *Module) bool { return m.SystemExtSpecific() @@ -331,388 +274,13 @@ func TestInstallPartition(t *testing.T) { checkInstallPartition(t, ctx, "libproduct_odmavailable", vendorVariant, "odm") } -func checkVndkModule(t *testing.T, ctx *android.TestContext, name, subDir string, - isVndkSp bool, extends string, variant string) { - +func checkWriteFileOutput(t *testing.T, ctx *android.TestContext, params android.TestingBuildParams, expected []string) { t.Helper() - - mod := ctx.ModuleForTests(name, variant).Module().(*Module) - - // Check library properties. - lib, ok := mod.compiler.(*libraryDecorator) - if !ok { - t.Errorf("%q must have libraryDecorator", name) - } else if lib.baseInstaller.subDir != subDir { - t.Errorf("%q must use %q as subdir but it is using %q", name, subDir, - lib.baseInstaller.subDir) - } - - // Check VNDK properties. - if mod.vndkdep == nil { - t.Fatalf("%q must have `vndkdep`", name) - } - if !mod.IsVndk() { - t.Errorf("%q IsVndk() must equal to true", name) - } - if mod.IsVndkSp() != isVndkSp { - t.Errorf("%q IsVndkSp() must equal to %t", name, isVndkSp) - } - - // Check VNDK extension properties. - isVndkExt := extends != "" - if mod.IsVndkExt() != isVndkExt { - t.Errorf("%q IsVndkExt() must equal to %t", name, isVndkExt) - } - - if actualExtends := mod.getVndkExtendsModuleName(); actualExtends != extends { - t.Errorf("%q must extend from %q but get %q", name, extends, actualExtends) - } -} - -func checkWriteFileOutput(t *testing.T, params android.TestingBuildParams, expected []string) { - t.Helper() - content := android.ContentFromFileRuleForTests(t, params) + content := android.ContentFromFileRuleForTests(t, ctx, params) actual := strings.FieldsFunc(content, func(r rune) bool { return r == '\n' }) assertArrayString(t, actual, expected) } -func checkVndkOutput(t *testing.T, ctx *android.TestContext, output string, expected []string) { - t.Helper() - vndkSnapshot := ctx.SingletonForTests("vndk-snapshot") - checkWriteFileOutput(t, vndkSnapshot.Output(output), expected) -} - -func checkVndkLibrariesOutput(t *testing.T, ctx *android.TestContext, module string, expected []string) { - t.Helper() - got := ctx.ModuleForTests(module, "android_common").Module().(*vndkLibrariesTxt).fileNames - assertArrayString(t, got, expected) -} - -func TestVndk(t *testing.T) { - t.Parallel() - bp := ` - cc_library { - name: "libvndk", - vendor_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_private", - vendor_available: true, - vndk: { - enabled: true, - private: true, - }, - nocrt: true, - stem: "libvndk-private", - } - - cc_library { - name: "libvndk_product", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - target: { - vendor: { - cflags: ["-DTEST"], - }, - product: { - cflags: ["-DTEST"], - }, - }, - } - - cc_library { - name: "libvndk_sp", - vendor_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - nocrt: true, - suffix: "-x", - } - - cc_library { - name: "libvndk_sp_private", - vendor_available: true, - vndk: { - enabled: true, - support_system_process: true, - private: true, - }, - nocrt: true, - target: { - vendor: { - suffix: "-x", - }, - }, - } - - cc_library { - name: "libvndk_sp_product_private", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - private: true, - }, - nocrt: true, - target: { - vendor: { - suffix: "-x", - }, - product: { - suffix: "-x", - }, - }, - } - - cc_library { - name: "libllndk", - llndk: { - symbol_file: "libllndk.map.txt", - export_llndk_headers: ["libllndk_headers"], - } - } - - cc_library { - name: "libclang_rt.hwasan-llndk", - llndk: { - symbol_file: "libclang_rt.hwasan.map.txt", - } - } - - cc_library_headers { - name: "libllndk_headers", - llndk: { - llndk_headers: true, - }, - export_include_dirs: ["include"], - } - - llndk_libraries_txt { - name: "llndk.libraries.txt", - } - vndkcore_libraries_txt { - name: "vndkcore.libraries.txt", - } - vndksp_libraries_txt { - name: "vndksp.libraries.txt", - } - vndkprivate_libraries_txt { - name: "vndkprivate.libraries.txt", - } - vndkproduct_libraries_txt { - name: "vndkproduct.libraries.txt", - } - vndkcorevariant_libraries_txt { - name: "vndkcorevariant.libraries.txt", - insert_vndk_version: false, - } - ` - - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.ProductVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - - ctx := testCcWithConfig(t, config) - - // subdir == "" because VNDK libs are not supposed to be installed separately. - // They are installed as part of VNDK APEX instead. - checkVndkModule(t, ctx, "libvndk", "", false, "", vendorVariant) - checkVndkModule(t, ctx, "libvndk_private", "", false, "", vendorVariant) - checkVndkModule(t, ctx, "libvndk_product", "", false, "", vendorVariant) - checkVndkModule(t, ctx, "libvndk_sp", "", true, "", vendorVariant) - checkVndkModule(t, ctx, "libvndk_sp_private", "", true, "", vendorVariant) - checkVndkModule(t, ctx, "libvndk_sp_product_private", "", true, "", vendorVariant) - - checkVndkModule(t, ctx, "libvndk_product", "", false, "", productVariant) - checkVndkModule(t, ctx, "libvndk_sp_product_private", "", true, "", productVariant) - - // Check VNDK snapshot output. - snapshotDir := "vndk-snapshot" - snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") - - vndkLibPath := filepath.Join(snapshotVariantPath, fmt.Sprintf("arch-%s-%s", - "arm64", "armv8-a")) - vndkLib2ndPath := filepath.Join(snapshotVariantPath, fmt.Sprintf("arch-%s-%s", - "arm", "armv7-a-neon")) - - vndkCoreLibPath := filepath.Join(vndkLibPath, "shared", "vndk-core") - vndkSpLibPath := filepath.Join(vndkLibPath, "shared", "vndk-sp") - llndkLibPath := filepath.Join(vndkLibPath, "shared", "llndk-stub") - - vndkCoreLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-core") - vndkSpLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-sp") - llndkLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "llndk-stub") - - variant := "android_vendor.29_arm64_armv8-a_shared" - variant2nd := "android_vendor.29_arm_armv7-a-neon_shared" - - snapshotSingleton := ctx.SingletonForTests("vndk-snapshot") - - CheckSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", vndkCoreLibPath, variant) - CheckSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", vndkCoreLib2ndPath, variant2nd) - CheckSnapshot(t, ctx, snapshotSingleton, "libvndk_product", "libvndk_product.so", vndkCoreLibPath, variant) - CheckSnapshot(t, ctx, snapshotSingleton, "libvndk_product", "libvndk_product.so", vndkCoreLib2ndPath, variant2nd) - CheckSnapshot(t, ctx, snapshotSingleton, "libvndk_sp", "libvndk_sp-x.so", vndkSpLibPath, variant) - CheckSnapshot(t, ctx, snapshotSingleton, "libvndk_sp", "libvndk_sp-x.so", vndkSpLib2ndPath, variant2nd) - CheckSnapshot(t, ctx, snapshotSingleton, "libllndk", "libllndk.so", llndkLibPath, variant) - CheckSnapshot(t, ctx, snapshotSingleton, "libllndk", "libllndk.so", llndkLib2ndPath, variant2nd) - - snapshotConfigsPath := filepath.Join(snapshotVariantPath, "configs") - CheckSnapshot(t, ctx, snapshotSingleton, "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "android_common") - CheckSnapshot(t, ctx, snapshotSingleton, "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "android_common") - CheckSnapshot(t, ctx, snapshotSingleton, "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "android_common") - CheckSnapshot(t, ctx, snapshotSingleton, "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "android_common") - CheckSnapshot(t, ctx, snapshotSingleton, "vndkproduct.libraries.txt", "vndkproduct.libraries.txt", snapshotConfigsPath, "android_common") - - checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{ - "LLNDK: libc.so", - "LLNDK: libdl.so", - "LLNDK: libft2.so", - "LLNDK: libllndk.so", - "LLNDK: libm.so", - "VNDK-SP: libc++.so", - "VNDK-SP: libvndk_sp-x.so", - "VNDK-SP: libvndk_sp_private-x.so", - "VNDK-SP: libvndk_sp_product_private-x.so", - "VNDK-core: libvndk-private.so", - "VNDK-core: libvndk.so", - "VNDK-core: libvndk_product.so", - "VNDK-private: libft2.so", - "VNDK-private: libvndk-private.so", - "VNDK-private: libvndk_sp_private-x.so", - "VNDK-private: libvndk_sp_product_private-x.so", - "VNDK-product: libc++.so", - "VNDK-product: libvndk_product.so", - "VNDK-product: libvndk_sp_product_private-x.so", - }) - checkVndkLibrariesOutput(t, ctx, "llndk.libraries.txt", []string{"libc.so", "libclang_rt.hwasan-llndk.so", "libdl.so", "libft2.so", "libllndk.so", "libm.so"}) - checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", []string{"libvndk-private.so", "libvndk.so", "libvndk_product.so"}) - checkVndkLibrariesOutput(t, ctx, "vndksp.libraries.txt", []string{"libc++.so", "libvndk_sp-x.so", "libvndk_sp_private-x.so", "libvndk_sp_product_private-x.so"}) - checkVndkLibrariesOutput(t, ctx, "vndkprivate.libraries.txt", []string{"libft2.so", "libvndk-private.so", "libvndk_sp_private-x.so", "libvndk_sp_product_private-x.so"}) - checkVndkLibrariesOutput(t, ctx, "vndkproduct.libraries.txt", []string{"libc++.so", "libvndk_product.so", "libvndk_sp_product_private-x.so"}) - checkVndkLibrariesOutput(t, ctx, "vndkcorevariant.libraries.txt", nil) -} - -func TestVndkWithHostSupported(t *testing.T) { - t.Parallel() - ctx := testCc(t, ` - cc_library { - name: "libvndk_host_supported", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - host_supported: true, - } - - cc_library { - name: "libvndk_host_supported_but_disabled_on_device", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - host_supported: true, - enabled: false, - target: { - host: { - enabled: true, - } - } - } - - vndkcore_libraries_txt { - name: "vndkcore.libraries.txt", - } - `) - - checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", []string{"libvndk_host_supported.so"}) -} - -func TestVndkLibrariesTxtAndroidMk(t *testing.T) { - t.Parallel() - bp := ` - llndk_libraries_txt { - name: "llndk.libraries.txt", - insert_vndk_version: true, - }` - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - ctx := testCcWithConfig(t, config) - - module := ctx.ModuleForTests("llndk.libraries.txt", "android_common") - entries := android.AndroidMkEntriesForTest(t, ctx, module.Module())[0] - assertArrayString(t, entries.EntryMap["LOCAL_MODULE_STEM"], []string{"llndk.libraries.29.txt"}) -} - -func TestVndkUsingCoreVariant(t *testing.T) { - t.Parallel() - bp := ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk2", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - private: true, - }, - nocrt: true, - } - - vndkcorevariant_libraries_txt { - name: "vndkcorevariant.libraries.txt", - insert_vndk_version: false, - } - ` - - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true) - - setVndkMustUseVendorVariantListForTest(config, []string{"libvndk"}) - - ctx := testCcWithConfig(t, config) - - checkVndkLibrariesOutput(t, ctx, "vndkcorevariant.libraries.txt", []string{"libc++.so", "libvndk2.so", "libvndk_sp.so"}) -} - func TestDataLibs(t *testing.T) { t.Parallel() bp := ` @@ -730,24 +298,17 @@ func TestDataLibs(t *testing.T) { ` config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true) ctx := testCcWithConfig(t, config) - module := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon").Module() - testBinary := module.(*Module).linker.(*testBinary) - outputFiles, err := module.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Expected cc_test to produce output files, error: %s", err) - return - } + testingModule := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon") + testBinary := testingModule.Module().(*Module).linker.(*testBinary) + outputFiles := testingModule.OutputFiles(t, "") if len(outputFiles) != 1 { t.Errorf("expected exactly one output file. output files: [%s]", outputFiles) return } if len(testBinary.dataPaths()) != 1 { - t.Errorf("expected exactly one test data file. test data files: [%s]", testBinary.dataPaths()) + t.Errorf("expected exactly one test data file. test data files: [%v]", testBinary.dataPaths()) return } @@ -789,22 +350,17 @@ func TestDataLibsRelativeInstallPath(t *testing.T) { ` config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true) ctx := testCcWithConfig(t, config) - module := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon").Module() + testingModule := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon") + module := testingModule.Module() testBinary := module.(*Module).linker.(*testBinary) - outputFiles, err := module.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Fatalf("Expected cc_test to produce output files, error: %s", err) - } + outputFiles := testingModule.OutputFiles(t, "") if len(outputFiles) != 1 { t.Fatalf("expected exactly one output file. output files: [%s]", outputFiles) } if len(testBinary.dataPaths()) != 2 { - t.Fatalf("expected exactly one test data file. test data files: [%s]", testBinary.dataPaths()) + t.Fatalf("expected exactly one test data file. test data files: [%v]", testBinary.dataPaths()) } outputPath := outputFiles[0].String() @@ -887,300 +443,9 @@ func TestTestLibraryTestSuites(t *testing.T) { } } -func TestVndkWhenVndkVersionIsNotSet(t *testing.T) { - t.Parallel() - ctx := testCcNoVndk(t, ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - cc_library { - name: "libvndk-private", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - private: true, - }, - nocrt: true, - } - - cc_library { - name: "libllndk", - llndk: { - symbol_file: "libllndk.map.txt", - export_llndk_headers: ["libllndk_headers"], - } - } - - cc_library_headers { - name: "libllndk_headers", - llndk: { - symbol_file: "libllndk.map.txt", - }, - export_include_dirs: ["include"], - } - `) - - checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{ - "LLNDK: libc.so", - "LLNDK: libdl.so", - "LLNDK: libft2.so", - "LLNDK: libllndk.so", - "LLNDK: libm.so", - "VNDK-SP: libc++.so", - "VNDK-core: libvndk-private.so", - "VNDK-core: libvndk.so", - "VNDK-private: libft2.so", - "VNDK-private: libvndk-private.so", - "VNDK-product: libc++.so", - "VNDK-product: libvndk-private.so", - "VNDK-product: libvndk.so", - }) -} - -func TestVndkModuleError(t *testing.T) { - t.Parallel() - // Check the error message for vendor_available and product_available properties. - testCcErrorProductVndk(t, "vndk: vendor_available must be set to true when `vndk: {enabled: true}`", ` - cc_library { - name: "libvndk", - vndk: { - enabled: true, - }, - nocrt: true, - } - `) - - testCcErrorProductVndk(t, "vndk: vendor_available must be set to true when `vndk: {enabled: true}`", ` - cc_library { - name: "libvndk", - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - `) - - testCcErrorProductVndk(t, "product properties must have the same values with the vendor properties for VNDK modules", ` - cc_library { - name: "libvndkprop", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - target: { - vendor: { - cflags: ["-DTEST",], - }, - }, - } - `) -} - -func TestVndkDepError(t *testing.T) { - t.Parallel() - // Check whether an error is emitted when a VNDK lib depends on a system lib. - testCcError(t, "dependency \".*\" of \".*\" missing variant", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - shared_libs: ["libfwk"], // Cause error - nocrt: true, - } - - cc_library { - name: "libfwk", - nocrt: true, - } - `) - - // Check whether an error is emitted when a VNDK lib depends on a vendor lib. - testCcError(t, "dependency \".*\" of \".*\" missing variant", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - shared_libs: ["libvendor"], // Cause error - nocrt: true, - } - - cc_library { - name: "libvendor", - vendor: true, - nocrt: true, - } - `) - - // Check whether an error is emitted when a VNDK-SP lib depends on a system lib. - testCcError(t, "dependency \".*\" of \".*\" missing variant", ` - cc_library { - name: "libvndk_sp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - shared_libs: ["libfwk"], // Cause error - nocrt: true, - } - - cc_library { - name: "libfwk", - nocrt: true, - } - `) - - // Check whether an error is emitted when a VNDK-SP lib depends on a vendor lib. - testCcError(t, "dependency \".*\" of \".*\" missing variant", ` - cc_library { - name: "libvndk_sp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - shared_libs: ["libvendor"], // Cause error - nocrt: true, - } - - cc_library { - name: "libvendor", - vendor: true, - nocrt: true, - } - `) - - // Check whether an error is emitted when a VNDK-SP lib depends on a VNDK lib. - testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` - cc_library { - name: "libvndk_sp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - shared_libs: ["libvndk"], // Cause error - nocrt: true, - } - - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - `) - - // Check whether an error is emitted when a VNDK lib depends on a non-VNDK lib. - testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - shared_libs: ["libnonvndk"], - nocrt: true, - } - - cc_library { - name: "libnonvndk", - vendor_available: true, - nocrt: true, - } - `) - - // Check whether an error is emitted when a VNDK-private lib depends on a non-VNDK lib. - testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` - cc_library { - name: "libvndkprivate", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - private: true, - }, - shared_libs: ["libnonvndk"], - nocrt: true, - } - - cc_library { - name: "libnonvndk", - vendor_available: true, - nocrt: true, - } - `) - - // Check whether an error is emitted when a VNDK-sp lib depends on a non-VNDK lib. - testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` - cc_library { - name: "libvndksp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - shared_libs: ["libnonvndk"], - nocrt: true, - } - - cc_library { - name: "libnonvndk", - vendor_available: true, - nocrt: true, - } - `) - - // Check whether an error is emitted when a VNDK-sp-private lib depends on a non-VNDK lib. - testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` - cc_library { - name: "libvndkspprivate", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - private: true, - }, - shared_libs: ["libnonvndk"], - nocrt: true, - } - - cc_library { - name: "libnonvndk", - vendor_available: true, - nocrt: true, - } - `) -} - func TestDoubleLoadbleDep(t *testing.T) { t.Parallel() - // okay to link : LLNDK -> double_loadable VNDK + // okay to link : LLNDK -> double_loadable testCc(t, ` cc_library { name: "libllndk", @@ -1194,32 +459,9 @@ func TestDoubleLoadbleDep(t *testing.T) { name: "libdoubleloadable", vendor_available: true, product_available: true, - vndk: { - enabled: true, - }, double_loadable: true, } `) - // okay to link : LLNDK -> VNDK-SP - testCc(t, ` - cc_library { - name: "libllndk", - shared_libs: ["libvndksp"], - llndk: { - symbol_file: "libllndk.map.txt", - } - } - - cc_library { - name: "libvndksp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - } - `) // okay to link : double_loadable -> double_loadable testCc(t, ` cc_library { @@ -1235,15 +477,12 @@ func TestDoubleLoadbleDep(t *testing.T) { double_loadable: true, } `) - // okay to link : double_loadable VNDK -> double_loadable VNDK private + // okay to link : double_loadable -> double_loadable testCc(t, ` cc_library { name: "libdoubleloadable", vendor_available: true, product_available: true, - vndk: { - enabled: true, - }, double_loadable: true, shared_libs: ["libnondoubleloadable"], } @@ -1252,10 +491,6 @@ func TestDoubleLoadbleDep(t *testing.T) { name: "libnondoubleloadable", vendor_available: true, product_available: true, - vndk: { - enabled: true, - private: true, - }, double_loadable: true, } `) @@ -1285,7 +520,7 @@ func TestDoubleLoadbleDep(t *testing.T) { func TestDoubleLoadableDepError(t *testing.T) { t.Parallel() - // Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib. + // Check whether an error is emitted when a LLNDK depends on a non-double_loadable lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` cc_library { name: "libllndk", @@ -1299,9 +534,6 @@ func TestDoubleLoadableDepError(t *testing.T) { name: "libnondoubleloadable", vendor_available: true, product_available: true, - vndk: { - enabled: true, - }, } `) @@ -1366,1062 +598,13 @@ func TestDoubleLoadableDepError(t *testing.T) { `) } -func TestCheckVndkMembershipBeforeDoubleLoadable(t *testing.T) { - t.Parallel() - testCcError(t, "module \"libvndksp\" variant .*: .*: VNDK-SP must only depend on VNDK-SP", ` - cc_library { - name: "libvndksp", - shared_libs: ["libanothervndksp"], - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - } - } - - cc_library { - name: "libllndk", - shared_libs: ["libanothervndksp"], - } - - cc_library { - name: "libanothervndksp", - vendor_available: true, - } - `) -} - -func TestVndkExt(t *testing.T) { - t.Parallel() - // This test checks the VNDK-Ext properties. - bp := ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - cc_library { - name: "libvndk2", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - target: { - vendor: { - suffix: "-suffix", - }, - product: { - suffix: "-suffix", - }, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - nocrt: true, - } - - cc_library { - name: "libvndk2_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk2", - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext_product", - product_specific: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - nocrt: true, - } - - cc_library { - name: "libvndk2_ext_product", - product_specific: true, - vndk: { - enabled: true, - extends: "libvndk2", - }, - nocrt: true, - } - ` - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.ProductVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - - ctx := testCcWithConfig(t, config) - - checkVndkModule(t, ctx, "libvndk_ext", "vndk", false, "libvndk", vendorVariant) - checkVndkModule(t, ctx, "libvndk_ext_product", "vndk", false, "libvndk", productVariant) - - mod_vendor := ctx.ModuleForTests("libvndk2_ext", vendorVariant).Module().(*Module) - assertString(t, mod_vendor.outputFile.Path().Base(), "libvndk2-suffix.so") - - mod_product := ctx.ModuleForTests("libvndk2_ext_product", productVariant).Module().(*Module) - assertString(t, mod_product.outputFile.Path().Base(), "libvndk2-suffix.so") -} - -func TestVndkExtWithoutBoardVndkVersion(t *testing.T) { - t.Parallel() - // This test checks the VNDK-Ext properties when BOARD_VNDK_VERSION is not set. - ctx := testCcNoVndk(t, ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - nocrt: true, - } - `) - - // Ensures that the core variant of "libvndk_ext" can be found. - mod := ctx.ModuleForTests("libvndk_ext", coreVariant).Module().(*Module) - if extends := mod.getVndkExtendsModuleName(); extends != "libvndk" { - t.Errorf("\"libvndk_ext\" must extend from \"libvndk\" but get %q", extends) - } -} - -func TestVndkExtWithoutProductVndkVersion(t *testing.T) { - t.Parallel() - // This test checks the VNDK-Ext properties when PRODUCT_PRODUCT_VNDK_VERSION is not set. - ctx := testCcNoProductVndk(t, ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext_product", - product_specific: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - nocrt: true, - } - `) - - // Ensures that the core variant of "libvndk_ext_product" can be found. - mod := ctx.ModuleForTests("libvndk_ext_product", coreVariant).Module().(*Module) - if extends := mod.getVndkExtendsModuleName(); extends != "libvndk" { - t.Errorf("\"libvndk_ext_product\" must extend from \"libvndk\" but get %q", extends) - } -} - -func TestVndkExtError(t *testing.T) { - t.Parallel() - // This test ensures an error is emitted in ill-formed vndk-ext definition. - testCcError(t, "must set `vendor: true` or `product_specific: true` to set `extends: \".*\"`", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext", - vndk: { - enabled: true, - extends: "libvndk", - }, - nocrt: true, - } - `) - - testCcError(t, "must set `extends: \"\\.\\.\\.\"` to vndk extension", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext", - vendor: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - `) - - testCcErrorProductVndk(t, "must set `extends: \"\\.\\.\\.\"` to vndk extension", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext_product", - product_specific: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - `) - - testCcErrorProductVndk(t, "must not set at the same time as `vndk: {extends: \"\\.\\.\\.\"}`", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext_product", - product_specific: true, - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - nocrt: true, - } - `) -} - -func TestVndkExtInconsistentSupportSystemProcessError(t *testing.T) { - t.Parallel() - // This test ensures an error is emitted for inconsistent support_system_process. - testCcError(t, "module \".*\" with mismatched support_system_process", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk", - support_system_process: true, - }, - nocrt: true, - } - `) - - testCcError(t, "module \".*\" with mismatched support_system_process", ` - cc_library { - name: "libvndk_sp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk_sp", - }, - nocrt: true, - } - `) -} - -func TestVndkExtVendorAvailableFalseError(t *testing.T) { - t.Parallel() - // This test ensures an error is emitted when a VNDK-Ext library extends a VNDK library - // with `private: true`. - testCcError(t, "`extends` refers module \".*\" which has `private: true`", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - private: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - nocrt: true, - } - `) - - testCcErrorProductVndk(t, "`extends` refers module \".*\" which has `private: true`", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - private: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext_product", - product_specific: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - nocrt: true, - } - `) -} - -func TestVendorModuleUseVndkExt(t *testing.T) { - t.Parallel() - // This test ensures a vendor module can depend on a VNDK-Ext library. - testCc(t, ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk_sp", - support_system_process: true, - }, - nocrt: true, - } - - cc_library { - name: "libvendor", - vendor: true, - shared_libs: ["libvndk_ext", "libvndk_sp_ext"], - nocrt: true, - } - `) -} - -func TestVndkExtUseVendorLib(t *testing.T) { - t.Parallel() - // This test ensures a VNDK-Ext library can depend on a vendor library. - testCc(t, ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - shared_libs: ["libvendor"], - nocrt: true, - } - - cc_library { - name: "libvendor", - vendor: true, - nocrt: true, - } - `) - - // This test ensures a VNDK-SP-Ext library can depend on a vendor library. - testCc(t, ` - cc_library { - name: "libvndk_sp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk_sp", - support_system_process: true, - }, - shared_libs: ["libvendor"], // Cause an error - nocrt: true, - } - - cc_library { - name: "libvendor", - vendor: true, - nocrt: true, - } - `) -} - -func TestProductVndkExtDependency(t *testing.T) { - t.Parallel() - bp := ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext_product", - product_specific: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - shared_libs: ["libproduct_for_vndklibs"], - nocrt: true, - } - - cc_library { - name: "libvndk_sp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp_ext_product", - product_specific: true, - vndk: { - enabled: true, - extends: "libvndk_sp", - support_system_process: true, - }, - shared_libs: ["libproduct_for_vndklibs"], - nocrt: true, - } - - cc_library { - name: "libproduct", - product_specific: true, - shared_libs: ["libvndk_ext_product", "libvndk_sp_ext_product"], - nocrt: true, - } - - cc_library { - name: "libproduct_for_vndklibs", - product_specific: true, - nocrt: true, - } - ` - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.ProductVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - - testCcWithConfig(t, config) -} - -func TestVndkSpExtUseVndkError(t *testing.T) { - t.Parallel() - // This test ensures an error is emitted if a VNDK-SP-Ext library depends on a VNDK - // library. - testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk_sp", - support_system_process: true, - }, - shared_libs: ["libvndk"], // Cause an error - nocrt: true, - } - `) - - // This test ensures an error is emitted if a VNDK-SP-Ext library depends on a VNDK-Ext - // library. - testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk_sp", - support_system_process: true, - }, - shared_libs: ["libvndk_ext"], // Cause an error - nocrt: true, - } - `) -} - -func TestVndkUseVndkExtError(t *testing.T) { - t.Parallel() - // This test ensures an error is emitted if a VNDK/VNDK-SP library depends on a - // VNDK-Ext/VNDK-SP-Ext library. - testCcError(t, "dependency \".*\" of \".*\" missing variant", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - nocrt: true, - } - - cc_library { - name: "libvndk2", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - shared_libs: ["libvndk_ext"], - nocrt: true, - } - `) - - testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - nocrt: true, - } - - cc_library { - name: "libvndk2", - vendor_available: true, - vndk: { - enabled: true, - }, - target: { - vendor: { - shared_libs: ["libvndk_ext"], - }, - }, - nocrt: true, - } - `) - - testCcError(t, "dependency \".*\" of \".*\" missing variant", ` - cc_library { - name: "libvndk_sp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk_sp", - support_system_process: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp_2", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - shared_libs: ["libvndk_sp_ext"], - nocrt: true, - } - `) - - testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` - cc_library { - name: "libvndk_sp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp_ext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk_sp", - }, - nocrt: true, - } - - cc_library { - name: "libvndk_sp2", - vendor_available: true, - vndk: { - enabled: true, - }, - target: { - vendor: { - shared_libs: ["libvndk_sp_ext"], - }, - }, - nocrt: true, - } - `) -} - -func TestEnforceProductVndkVersion(t *testing.T) { - t.Parallel() - bp := ` - cc_library { - name: "libllndk", - llndk: { - symbol_file: "libllndk.map.txt", - } - } - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - cc_library { - name: "libvndk_sp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - nocrt: true, - } - cc_library { - name: "libva", - vendor_available: true, - nocrt: true, - } - cc_library { - name: "libpa", - product_available: true, - nocrt: true, - } - cc_library { - name: "libboth_available", - vendor_available: true, - product_available: true, - nocrt: true, - srcs: ["foo.c"], - target: { - vendor: { - suffix: "-vendor", - }, - product: { - suffix: "-product", - }, - } - } - cc_library { - name: "libproduct_va", - product_specific: true, - vendor_available: true, - nocrt: true, - } - cc_library { - name: "libprod", - product_specific: true, - shared_libs: [ - "libllndk", - "libvndk", - "libvndk_sp", - "libpa", - "libboth_available", - "libproduct_va", - ], - nocrt: true, - } - cc_library { - name: "libvendor", - vendor: true, - shared_libs: [ - "libllndk", - "libvndk", - "libvndk_sp", - "libva", - "libboth_available", - "libproduct_va", - ], - nocrt: true, - } - ` - - ctx := prepareForCcTest.RunTestWithBp(t, bp).TestContext - - checkVndkModule(t, ctx, "libvndk", "", false, "", productVariant) - checkVndkModule(t, ctx, "libvndk_sp", "", true, "", productVariant) - - mod_vendor := ctx.ModuleForTests("libboth_available", vendorVariant).Module().(*Module) - assertString(t, mod_vendor.outputFile.Path().Base(), "libboth_available-vendor.so") - - mod_product := ctx.ModuleForTests("libboth_available", productVariant).Module().(*Module) - assertString(t, mod_product.outputFile.Path().Base(), "libboth_available-product.so") - - ensureStringContains := func(t *testing.T, str string, substr string) { - t.Helper() - if !strings.Contains(str, substr) { - t.Errorf("%q is not found in %v", substr, str) - } - } - ensureStringNotContains := func(t *testing.T, str string, substr string) { - t.Helper() - if strings.Contains(str, substr) { - t.Errorf("%q is found in %v", substr, str) - } - } - - // _static variant is used since _shared reuses *.o from the static variant - vendor_static := ctx.ModuleForTests("libboth_available", strings.Replace(vendorVariant, "_shared", "_static", 1)) - product_static := ctx.ModuleForTests("libboth_available", strings.Replace(productVariant, "_shared", "_static", 1)) - - vendor_cflags := vendor_static.Rule("cc").Args["cFlags"] - ensureStringContains(t, vendor_cflags, "-D__ANDROID_VNDK__") - ensureStringContains(t, vendor_cflags, "-D__ANDROID_VENDOR__") - ensureStringNotContains(t, vendor_cflags, "-D__ANDROID_PRODUCT__") - - product_cflags := product_static.Rule("cc").Args["cFlags"] - ensureStringContains(t, product_cflags, "-D__ANDROID_VNDK__") - ensureStringContains(t, product_cflags, "-D__ANDROID_PRODUCT__") - ensureStringNotContains(t, product_cflags, "-D__ANDROID_VENDOR__") -} - -func TestEnforceProductVndkVersionErrors(t *testing.T) { - t.Parallel() - testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", ` - cc_library { - name: "libprod", - product_specific: true, - shared_libs: [ - "libvendor", - ], - nocrt: true, - } - cc_library { - name: "libvendor", - vendor: true, - nocrt: true, - } - `) - testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", ` - cc_library { - name: "libprod", - product_specific: true, - shared_libs: [ - "libsystem", - ], - nocrt: true, - } - cc_library { - name: "libsystem", - nocrt: true, - } - `) - testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", ` - cc_library { - name: "libprod", - product_specific: true, - shared_libs: [ - "libva", - ], - nocrt: true, - } - cc_library { - name: "libva", - vendor_available: true, - nocrt: true, - } - `) - testCcErrorProductVndk(t, "non-VNDK module should not link to \".*\" which has `private: true`", ` - cc_library { - name: "libprod", - product_specific: true, - shared_libs: [ - "libvndk_private", - ], - nocrt: true, - } - cc_library { - name: "libvndk_private", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - private: true, - }, - nocrt: true, - } - `) - testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", ` - cc_library { - name: "libprod", - product_specific: true, - shared_libs: [ - "libsystem_ext", - ], - nocrt: true, - } - cc_library { - name: "libsystem_ext", - system_ext_specific: true, - nocrt: true, - } - `) - testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:", ` - cc_library { - name: "libsystem", - shared_libs: [ - "libproduct_va", - ], - nocrt: true, - } - cc_library { - name: "libproduct_va", - product_specific: true, - vendor_available: true, - nocrt: true, - } - `) -} - func TestMakeLinkType(t *testing.T) { t.Parallel() bp := ` cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - } - cc_library { - name: "libvndksp", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - } - cc_library { - name: "libvndkprivate", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - private: true, - }, - } - cc_library { name: "libvendor", vendor: true, } - cc_library { - name: "libvndkext", - vendor: true, - vndk: { - enabled: true, - extends: "libvndk", - }, - } vndk_prebuilt_shared { name: "prevndk", version: "27", @@ -2451,40 +634,15 @@ func TestMakeLinkType(t *testing.T) { private: true, } } - llndk_libraries_txt { name: "llndk.libraries.txt", } - vndkcore_libraries_txt { - name: "vndkcore.libraries.txt", - } - vndksp_libraries_txt { - name: "vndksp.libraries.txt", - } - vndkprivate_libraries_txt { - name: "vndkprivate.libraries.txt", - } - vndkcorevariant_libraries_txt { - name: "vndkcorevariant.libraries.txt", - insert_vndk_version: false, - } ` config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") // native:vndk ctx := testCcWithConfig(t, config) - checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", - []string{"libvndk.so", "libvndkprivate.so"}) - checkVndkLibrariesOutput(t, ctx, "vndksp.libraries.txt", - []string{"libc++.so", "libvndksp.so"}) - checkVndkLibrariesOutput(t, ctx, "llndk.libraries.txt", - []string{"libc.so", "libdl.so", "libft2.so", "libllndk.so", "libllndkprivate.so", "libm.so"}) - checkVndkLibrariesOutput(t, ctx, "vndkprivate.libraries.txt", - []string{"libft2.so", "libllndkprivate.so", "libvndkprivate.so"}) - vendorVariant27 := "android_vendor.27_arm64_armv8-a_shared" tests := []struct { @@ -2492,15 +650,9 @@ func TestMakeLinkType(t *testing.T) { name string expected string }{ - {vendorVariant, "libvndk", "native:vndk"}, - {vendorVariant, "libvndksp", "native:vndk"}, - {vendorVariant, "libvndkprivate", "native:vndk_private"}, {vendorVariant, "libvendor", "native:vendor"}, - {vendorVariant, "libvndkext", "native:vendor"}, {vendorVariant, "libllndk", "native:vndk"}, - {vendorVariant27, "prevndk.vndk.27.arm.binder32", "native:vndk"}, - {coreVariant, "libvndk", "native:platform"}, - {coreVariant, "libvndkprivate", "native:platform"}, + {vendorVariant27, "prevndk.vndk.27.arm.binder32", "native:vendor"}, {coreVariant, "libllndk", "native:platform"}, } for _, test := range tests { @@ -2699,8 +851,8 @@ func TestStaticLibDepReordering(t *testing.T) { variant := "android_arm64_armv8-a_static" moduleA := ctx.ModuleForTests("a", variant).Module().(*Module) - actual := ctx.ModuleProvider(moduleA, StaticLibraryInfoProvider).(StaticLibraryInfo). - TransitiveStaticLibrariesForOrdering.ToList().RelativeToTop() + staticLibInfo, _ := android.SingletonModuleProvider(ctx, moduleA, StaticLibraryInfoProvider) + actual := android.Paths(staticLibInfo.TransitiveStaticLibrariesForOrdering.ToList()).RelativeToTop() expected := GetOutputPaths(ctx, variant, []string{"a", "c", "b", "d"}) if !reflect.DeepEqual(actual, expected) { @@ -2735,8 +887,8 @@ func TestStaticLibDepReorderingWithShared(t *testing.T) { variant := "android_arm64_armv8-a_static" moduleA := ctx.ModuleForTests("a", variant).Module().(*Module) - actual := ctx.ModuleProvider(moduleA, StaticLibraryInfoProvider).(StaticLibraryInfo). - TransitiveStaticLibrariesForOrdering.ToList().RelativeToTop() + staticLibInfo, _ := android.SingletonModuleProvider(ctx, moduleA, StaticLibraryInfoProvider) + actual := android.Paths(staticLibInfo.TransitiveStaticLibrariesForOrdering.ToList()).RelativeToTop() expected := GetOutputPaths(ctx, variant, []string{"a", "c", "b"}) if !reflect.DeepEqual(actual, expected) { @@ -2795,10 +947,12 @@ func TestLlndkLibrary(t *testing.T) { name: "libexternal_headers", export_include_dirs: ["include"], vendor_available: true, + product_available: true, } cc_library_headers { name: "libexternal_llndk_headers", export_include_dirs: ["include_llndk"], + export_system_include_dirs: ["include_system_llndk"], llndk: { symbol_file: "libllndk.map.txt", }, @@ -2814,39 +968,74 @@ func TestLlndkLibrary(t *testing.T) { }, export_include_dirs: ["include"], } + + cc_library { + name: "libllndk_with_system_headers", + llndk: { + symbol_file: "libllndk.map.txt", + export_llndk_headers: ["libexternal_llndk_headers"], + export_headers_as_system: true, + }, + export_include_dirs: ["include"], + export_system_include_dirs: ["include_system"], + } `) actual := result.ModuleVariantsForTests("libllndk") for i := 0; i < len(actual); i++ { - if !strings.HasPrefix(actual[i], "android_vendor.29_") { + if !strings.HasPrefix(actual[i], "android_vendor_") { actual = append(actual[:i], actual[i+1:]...) i-- } } expected := []string{ - "android_vendor.29_arm64_armv8-a_shared_current", - "android_vendor.29_arm64_armv8-a_shared", - "android_vendor.29_arm_armv7-a-neon_shared_current", - "android_vendor.29_arm_armv7-a-neon_shared", + "android_vendor_arm64_armv8-a_shared", + "android_vendor_arm_armv7-a-neon_shared", } android.AssertArrayString(t, "variants for llndk stubs", expected, actual) - params := result.ModuleForTests("libllndk", "android_vendor.29_arm_armv7-a-neon_shared").Description("generate stub") - android.AssertSame(t, "use VNDK version for default stubs", "current", params.Args["apiLevel"]) + params := result.ModuleForTests("libllndk", "android_vendor_arm_armv7-a-neon_shared").Description("generate stub") + android.AssertSame(t, "use Vendor API level for default stubs", "202404", params.Args["apiLevel"]) - checkExportedIncludeDirs := func(module, variant string, expectedDirs ...string) { + checkExportedIncludeDirs := func(module, variant string, expectedSystemDirs []string, expectedDirs ...string) { t.Helper() m := result.ModuleForTests(module, variant).Module() - f := result.ModuleProvider(m, FlagExporterInfoProvider).(FlagExporterInfo) + f, _ := android.SingletonModuleProvider(result, m, FlagExporterInfoProvider) android.AssertPathsRelativeToTopEquals(t, "exported include dirs for "+module+"["+variant+"]", expectedDirs, f.IncludeDirs) + android.AssertPathsRelativeToTopEquals(t, "exported include dirs for "+module+"["+variant+"]", + expectedSystemDirs, f.SystemIncludeDirs) } - checkExportedIncludeDirs("libllndk", "android_arm64_armv8-a_shared", "include") - checkExportedIncludeDirs("libllndk", "android_vendor.29_arm64_armv8-a_shared", "include") - checkExportedIncludeDirs("libllndk_with_external_headers", "android_arm64_armv8-a_shared", "include") - checkExportedIncludeDirs("libllndk_with_external_headers", "android_vendor.29_arm64_armv8-a_shared", "include_llndk") - checkExportedIncludeDirs("libllndk_with_override_headers", "android_arm64_armv8-a_shared", "include") - checkExportedIncludeDirs("libllndk_with_override_headers", "android_vendor.29_arm64_armv8-a_shared", "include_llndk") + checkExportedIncludeDirs("libllndk", coreVariant, nil, "include") + checkExportedIncludeDirs("libllndk", vendorVariant, nil, "include") + checkExportedIncludeDirs("libllndk_with_external_headers", coreVariant, nil, "include") + checkExportedIncludeDirs("libllndk_with_external_headers", vendorVariant, + []string{"include_system_llndk"}, "include_llndk") + checkExportedIncludeDirs("libllndk_with_override_headers", coreVariant, nil, "include") + checkExportedIncludeDirs("libllndk_with_override_headers", vendorVariant, nil, "include_llndk") + checkExportedIncludeDirs("libllndk_with_system_headers", coreVariant, []string{"include_system"}, "include") + checkExportedIncludeDirs("libllndk_with_system_headers", vendorVariant, + []string{"include_system", "include", "include_system_llndk"}, "include_llndk") + + checkAbiLinkerIncludeDirs := func(module string) { + t.Helper() + coreModule := result.ModuleForTests(module, coreVariant) + abiCheckFlags := "" + for _, output := range coreModule.AllOutputs() { + if strings.HasSuffix(output, ".so.llndk.lsdump") { + abiCheckFlags = coreModule.Output(output).Args["exportedHeaderFlags"] + } + } + vendorModule := result.ModuleForTests(module, vendorVariant).Module() + vendorInfo, _ := android.SingletonModuleProvider(result, vendorModule, FlagExporterInfoProvider) + vendorDirs := android.Concat(vendorInfo.IncludeDirs, vendorInfo.SystemIncludeDirs) + android.AssertStringEquals(t, module+" has different exported include dirs for vendor variant and ABI check", + android.JoinPathsWithPrefix(vendorDirs, "-I"), abiCheckFlags) + } + checkAbiLinkerIncludeDirs("libllndk") + checkAbiLinkerIncludeDirs("libllndk_with_override_headers") + checkAbiLinkerIncludeDirs("libllndk_with_external_headers") + checkAbiLinkerIncludeDirs("libllndk_with_system_headers") } func TestLlndkHeaders(t *testing.T) { @@ -2878,7 +1067,7 @@ func TestLlndkHeaders(t *testing.T) { `) // _static variant is used since _shared reuses *.o from the static variant - cc := ctx.ModuleForTests("libvendor", "android_vendor.29_arm_armv7-a-neon_static").Rule("cc") + cc := ctx.ModuleForTests("libvendor", "android_vendor_arm_armv7-a-neon_static").Rule("cc") cflags := cc.Args["cFlags"] if !strings.Contains(cflags, "-Imy_include") { t.Errorf("cflags for libvendor must contain -Imy_include, but was %#v.", cflags) @@ -3000,7 +1189,7 @@ func TestRuntimeLibs(t *testing.T) { // runtime_libs for vendor variants have '.vendor' suffixes if the modules have both core // and vendor variants. - variant = "android_vendor.29_arm64_armv8-a_shared" + variant = "android_vendor_arm64_armv8-a_shared" module = ctx.ModuleForTests("libvendor_available1", variant).Module().(*Module) checkRuntimeLibs(t, []string{"liball_available.vendor"}, module) @@ -3010,7 +1199,7 @@ func TestRuntimeLibs(t *testing.T) { // runtime_libs for product variants have '.product' suffixes if the modules have both core // and product variants. - variant = "android_product.29_arm64_armv8-a_shared" + variant = "android_product_arm64_armv8-a_shared" module = ctx.ModuleForTests("libproduct_available1", variant).Module().(*Module) checkRuntimeLibs(t, []string{"liball_available.product"}, module) @@ -3027,29 +1216,11 @@ func TestExcludeRuntimeLibs(t *testing.T) { module := ctx.ModuleForTests("libvendor_available2", variant).Module().(*Module) checkRuntimeLibs(t, []string{"liball_available"}, module) - variant = "android_vendor.29_arm64_armv8-a_shared" + variant = "android_vendor_arm64_armv8-a_shared" module = ctx.ModuleForTests("libvendor_available2", variant).Module().(*Module) checkRuntimeLibs(t, nil, module) } -func TestRuntimeLibsNoVndk(t *testing.T) { - t.Parallel() - ctx := testCcNoVndk(t, runtimeLibAndroidBp) - - // If DeviceVndkVersion is not defined, then runtime_libs are copied as-is. - - variant := "android_arm64_armv8-a_shared" - - module := ctx.ModuleForTests("libvendor_available1", variant).Module().(*Module) - checkRuntimeLibs(t, []string{"liball_available"}, module) - - module = ctx.ModuleForTests("libvendor2", variant).Module().(*Module) - checkRuntimeLibs(t, []string{"liball_available", "libvendor1", "libproduct_vendor"}, module) - - module = ctx.ModuleForTests("libproduct2", variant).Module().(*Module) - checkRuntimeLibs(t, []string{"liball_available", "libproduct1", "libproduct_vendor"}, module) -} - func checkStaticLibs(t *testing.T, expected []string, module *Module) { t.Helper() actual := module.Properties.AndroidMkStaticLibs @@ -3089,253 +1260,6 @@ func TestStaticLibDepExport(t *testing.T) { checkStaticLibs(t, []string{"lib1", "libc++_static", "libc++demangle", "libclang_rt.builtins"}, module) } -func TestLibDepAndroidMkExportInMixedBuilds(t *testing.T) { - bp := ` - cc_library { - name: "static_dep", - } - cc_library { - name: "whole_static_dep", - } - cc_library { - name: "shared_dep", - } - cc_library { - name: "lib", - bazel_module: { label: "//:lib" }, - static_libs: ["static_dep"], - whole_static_libs: ["whole_static_dep"], - shared_libs: ["shared_dep"], - } - cc_test { - name: "test", - bazel_module: { label: "//:test" }, - static_libs: ["static_dep"], - whole_static_libs: ["whole_static_dep"], - shared_libs: ["shared_dep"], - gtest: false, - } - cc_binary { - name: "binary", - bazel_module: { label: "//:binary" }, - static_libs: ["static_dep"], - whole_static_libs: ["whole_static_dep"], - shared_libs: ["shared_dep"], - } - cc_library_headers { - name: "lib_headers", - bazel_module: { label: "//:lib_headers" }, - static_libs: ["static_dep"], - whole_static_libs: ["whole_static_dep"], - shared_libs: ["shared_dep"], - } - cc_prebuilt_library { - name: "lib_prebuilt", - bazel_module: { label: "//:lib_prebuilt" }, - static_libs: ["static_dep"], - whole_static_libs: ["whole_static_dep"], - shared_libs: ["shared_dep"], - } - ` - - testCases := []struct { - name string - moduleName string - variant string - androidMkInfo cquery.CcAndroidMkInfo - }{ - { - name: "shared lib", - moduleName: "lib", - variant: "android_arm64_armv8-a_shared", - androidMkInfo: cquery.CcAndroidMkInfo{ - LocalStaticLibs: []string{"static_dep"}, - LocalWholeStaticLibs: []string{"whole_static_dep"}, - LocalSharedLibs: []string{"shared_dep"}, - }, - }, - { - name: "static lib", - moduleName: "lib", - variant: "android_arm64_armv8-a_static", - androidMkInfo: cquery.CcAndroidMkInfo{ - LocalStaticLibs: []string{"static_dep"}, - LocalWholeStaticLibs: []string{"whole_static_dep"}, - LocalSharedLibs: []string{"shared_dep"}, - }, - }, - { - name: "cc_test arm64", - moduleName: "test", - variant: "android_arm64_armv8-a", - androidMkInfo: cquery.CcAndroidMkInfo{ - LocalStaticLibs: []string{"static_dep"}, - LocalWholeStaticLibs: []string{"whole_static_dep"}, - LocalSharedLibs: []string{"shared_dep"}, - }, - }, - { - name: "cc_test arm", - moduleName: "test", - variant: "android_arm_armv7-a-neon", - androidMkInfo: cquery.CcAndroidMkInfo{ - LocalStaticLibs: []string{"static_dep"}, - LocalWholeStaticLibs: []string{"whole_static_dep"}, - LocalSharedLibs: []string{"shared_dep"}, - }, - }, - { - name: "cc_binary", - moduleName: "binary", - variant: "android_arm64_armv8-a", - androidMkInfo: cquery.CcAndroidMkInfo{ - LocalStaticLibs: []string{"static_dep"}, - LocalWholeStaticLibs: []string{"whole_static_dep"}, - LocalSharedLibs: []string{"shared_dep"}, - }, - }, - { - name: "cc_library_headers", - moduleName: "lib_headers", - variant: "android_arm64_armv8-a", - androidMkInfo: cquery.CcAndroidMkInfo{ - LocalStaticLibs: []string{"static_dep"}, - LocalWholeStaticLibs: []string{"whole_static_dep"}, - LocalSharedLibs: []string{"shared_dep"}, - }, - }, - { - name: "prebuilt lib static", - moduleName: "lib_prebuilt", - variant: "android_arm64_armv8-a_static", - androidMkInfo: cquery.CcAndroidMkInfo{ - LocalStaticLibs: []string{"static_dep"}, - LocalWholeStaticLibs: []string{"whole_static_dep"}, - LocalSharedLibs: []string{"shared_dep"}, - }, - }, - { - name: "prebuilt lib shared", - moduleName: "lib_prebuilt", - variant: "android_arm64_armv8-a_shared", - androidMkInfo: cquery.CcAndroidMkInfo{ - LocalStaticLibs: []string{"static_dep"}, - LocalWholeStaticLibs: []string{"whole_static_dep"}, - LocalSharedLibs: []string{"shared_dep"}, - }, - }, - } - - outputBaseDir := "out/bazel" - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - result := android.GroupFixturePreparers( - prepareForCcTest, - android.FixtureModifyConfig(func(config android.Config) { - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: outputBaseDir, - LabelToCcInfo: map[string]cquery.CcInfo{ - "//:lib": cquery.CcInfo{ - CcAndroidMkInfo: tc.androidMkInfo, - RootDynamicLibraries: []string{""}, - }, - "//:lib_bp2build_cc_library_static": cquery.CcInfo{ - CcAndroidMkInfo: tc.androidMkInfo, - RootStaticArchives: []string{""}, - }, - "//:lib_headers": cquery.CcInfo{ - CcAndroidMkInfo: tc.androidMkInfo, - OutputFiles: []string{""}, - }, - "//:lib_prebuilt": cquery.CcInfo{ - CcAndroidMkInfo: tc.androidMkInfo, - }, - "//:lib_prebuilt_bp2build_cc_library_static": cquery.CcInfo{ - CcAndroidMkInfo: tc.androidMkInfo, - }, - }, - LabelToCcBinary: map[string]cquery.CcUnstrippedInfo{ - "//:test": cquery.CcUnstrippedInfo{ - CcAndroidMkInfo: tc.androidMkInfo, - }, - "//:binary": cquery.CcUnstrippedInfo{ - CcAndroidMkInfo: tc.androidMkInfo, - }, - }, - } - }), - ).RunTestWithBp(t, bp) - ctx := result.TestContext - - module := ctx.ModuleForTests(tc.moduleName, tc.variant).Module().(*Module) - entries := android.AndroidMkEntriesForTest(t, ctx, module)[0] - if !reflect.DeepEqual(module.Properties.AndroidMkStaticLibs, tc.androidMkInfo.LocalStaticLibs) { - t.Errorf("incorrect static_libs"+ - "\nactual: %v"+ - "\nexpected: %v", - module.Properties.AndroidMkStaticLibs, - tc.androidMkInfo.LocalStaticLibs, - ) - } - staticDepsDiffer, missingStaticDeps, additionalStaticDeps := android.ListSetDifference( - entries.EntryMap["LOCAL_STATIC_LIBRARIES"], - tc.androidMkInfo.LocalStaticLibs, - ) - if staticDepsDiffer { - t.Errorf( - "expected LOCAL_STATIC_LIBRARIES to be %q but was %q; missing: %q; extra %q", - tc.androidMkInfo.LocalStaticLibs, - entries.EntryMap["LOCAL_STATIC_LIBRARIES"], - missingStaticDeps, - additionalStaticDeps, - ) - } - - if !reflect.DeepEqual(module.Properties.AndroidMkWholeStaticLibs, tc.androidMkInfo.LocalWholeStaticLibs) { - t.Errorf("expected module.Properties.AndroidMkWholeStaticLibs to be %q, but was %q", - tc.androidMkInfo.LocalWholeStaticLibs, - module.Properties.AndroidMkWholeStaticLibs, - ) - } - wholeStaticDepsDiffer, missingWholeStaticDeps, additionalWholeStaticDeps := android.ListSetDifference( - entries.EntryMap["LOCAL_WHOLE_STATIC_LIBRARIES"], - tc.androidMkInfo.LocalWholeStaticLibs, - ) - if wholeStaticDepsDiffer { - t.Errorf( - "expected LOCAL_WHOLE_STATIC_LIBRARIES to be %q but was %q; missing: %q; extra %q", - tc.androidMkInfo.LocalWholeStaticLibs, - entries.EntryMap["LOCAL_WHOLE_STATIC_LIBRARIES"], - missingWholeStaticDeps, - additionalWholeStaticDeps, - ) - } - - if !reflect.DeepEqual(module.Properties.AndroidMkSharedLibs, tc.androidMkInfo.LocalSharedLibs) { - t.Errorf("incorrect shared_libs"+ - "\nactual: %v"+ - "\nexpected: %v", - module.Properties.AndroidMkSharedLibs, - tc.androidMkInfo.LocalSharedLibs, - ) - } - sharedDepsDiffer, missingSharedDeps, additionalSharedDeps := android.ListSetDifference( - entries.EntryMap["LOCAL_SHARED_LIBRARIES"], - tc.androidMkInfo.LocalSharedLibs, - ) - if sharedDepsDiffer { - t.Errorf( - "expected LOCAL_SHARED_LIBRARIES to be %q but was %q; missing %q; extra %q", - tc.androidMkInfo.LocalSharedLibs, - entries.EntryMap["LOCAL_SHARED_LIBRARIES"], - missingSharedDeps, - additionalSharedDeps, - ) - } - }) - } -} - var compilerFlagsTestCases = []struct { in string out bool @@ -3475,22 +1399,17 @@ func TestDataLibsPrebuiltSharedTestLibrary(t *testing.T) { ` config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true) ctx := testCcWithConfig(t, config) - module := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon").Module() + testingModule := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon") + module := testingModule.Module() testBinary := module.(*Module).linker.(*testBinary) - outputFiles, err := module.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Fatalf("Expected cc_test to produce output files, error: %s", err) - } + outputFiles := testingModule.OutputFiles(t, "") if len(outputFiles) != 1 { t.Errorf("expected exactly one output file. output files: [%s]", outputFiles) } if len(testBinary.dataPaths()) != 1 { - t.Errorf("expected exactly one test data file. test data files: [%s]", testBinary.dataPaths()) + t.Errorf("expected exactly one test data file. test data files: [%v]", testBinary.dataPaths()) } outputPath := outputFiles[0].String() @@ -3573,9 +1492,6 @@ func TestVersionedStubs(t *testing.T) { } func TestStubsForLibraryInMultipleApexes(t *testing.T) { - // TODO(b/275313114): Test exposes non-determinism which should be corrected and the test - // reenabled. - t.Skip() t.Parallel() ctx := testCc(t, ` cc_library_shared { @@ -3680,133 +1596,6 @@ func TestStubsForLibraryInMultipleApexes(t *testing.T) { } } -func TestMixedBuildUsesStubs(t *testing.T) { - // TODO(b/275313114): Test exposes non-determinism which should be corrected and the test - // reenabled. - t.Skip() - t.Parallel() - bp := ` - cc_library_shared { - name: "libFoo", - bazel_module: { label: "//:libFoo" }, - srcs: ["foo.c"], - stubs: { - symbol_file: "foo.map.txt", - versions: ["current"], - }, - apex_available: ["bar", "a1"], - } - - cc_library_shared { - name: "libBar", - srcs: ["bar.c"], - shared_libs: ["libFoo"], - apex_available: ["a1"], - } - - cc_library_shared { - name: "libA1", - srcs: ["a1.c"], - shared_libs: ["libFoo"], - apex_available: ["a1"], - } - - cc_library_shared { - name: "libBarA1", - srcs: ["bara1.c"], - shared_libs: ["libFoo"], - apex_available: ["bar", "a1"], - } - - cc_library_shared { - name: "libAnyApex", - srcs: ["anyApex.c"], - shared_libs: ["libFoo"], - apex_available: ["//apex_available:anyapex"], - } - - cc_library_shared { - name: "libBaz", - srcs: ["baz.c"], - shared_libs: ["libFoo"], - apex_available: ["baz"], - } - - cc_library_shared { - name: "libQux", - srcs: ["qux.c"], - shared_libs: ["libFoo"], - apex_available: ["qux", "bar"], - }` - - result := android.GroupFixturePreparers( - prepareForCcTest, - android.FixtureModifyConfig(func(config android.Config) { - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: "out/bazel", - LabelToCcInfo: map[string]cquery.CcInfo{ - "//:libFoo": { - RootDynamicLibraries: []string{"libFoo.so"}, - }, - "//:libFoo_stub_libs-current": { - RootDynamicLibraries: []string{"libFoo_stub_libs-current.so"}, - }, - }, - } - }), - ).RunTestWithBp(t, bp) - ctx := result.TestContext - - variants := ctx.ModuleVariantsForTests("libFoo") - expectedVariants := []string{ - "android_arm64_armv8-a_shared", - "android_arm64_armv8-a_shared_current", - "android_arm_armv7-a-neon_shared", - "android_arm_armv7-a-neon_shared_current", - } - variantsMismatch := false - if len(variants) != len(expectedVariants) { - variantsMismatch = true - } else { - for _, v := range expectedVariants { - if !inList(v, variants) { - variantsMismatch = false - } - } - } - if variantsMismatch { - t.Errorf("variants of libFoo expected:\n") - for _, v := range expectedVariants { - t.Errorf("%q\n", v) - } - t.Errorf(", but got:\n") - for _, v := range variants { - t.Errorf("%q\n", v) - } - } - - linkAgainstFoo := []string{"libBarA1"} - linkAgainstFooStubs := []string{"libBar", "libA1", "libBaz", "libQux", "libAnyApex"} - - libFooPath := "out/bazel/execroot/__main__/libFoo.so" - for _, lib := range linkAgainstFoo { - libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld") - libFlags := libLinkRule.Args["libFlags"] - if !strings.Contains(libFlags, libFooPath) { - t.Errorf("%q: %q is not found in %q", lib, libFooPath, libFlags) - } - } - - libFooStubPath := "out/bazel/execroot/__main__/libFoo_stub_libs-current.so" - for _, lib := range linkAgainstFooStubs { - libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld") - libFlags := libLinkRule.Args["libFlags"] - if !strings.Contains(libFlags, libFooStubPath) { - t.Errorf("%q: %q is not found in %q", lib, libFooStubPath, libFlags) - } - } -} - func TestVersioningMacro(t *testing.T) { t.Parallel() for _, tc := range []struct{ moduleName, expected string }{ @@ -4180,9 +1969,6 @@ func TestDefaults(t *testing.T) { shared: { srcs: ["baz.c"], }, - bazel_module: { - bp2build_available: true, - }, } cc_library_static { @@ -4419,9 +2205,80 @@ func TestStubsLibReexportsHeaders(t *testing.T) { } } +func TestAidlLibraryWithHeaders(t *testing.T) { + t.Parallel() + ctx := android.GroupFixturePreparers( + prepareForCcTest, + aidl_library.PrepareForTestWithAidlLibrary, + android.MockFS{ + "package_bar/Android.bp": []byte(` + aidl_library { + name: "bar", + srcs: ["x/y/Bar.aidl"], + hdrs: ["x/HeaderBar.aidl"], + strip_import_prefix: "x", + } + `)}.AddToFixture(), + android.MockFS{ + "package_foo/Android.bp": []byte(` + aidl_library { + name: "foo", + srcs: ["a/b/Foo.aidl"], + hdrs: ["a/HeaderFoo.aidl"], + strip_import_prefix: "a", + deps: ["bar"], + } + cc_library { + name: "libfoo", + aidl: { + libs: ["foo"], + } + } + `), + }.AddToFixture(), + ).RunTest(t).TestContext + + libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static") + + android.AssertPathsRelativeToTopEquals( + t, + "aidl headers", + []string{ + "package_bar/x/HeaderBar.aidl", + "package_foo/a/HeaderFoo.aidl", + "package_foo/a/b/Foo.aidl", + "out/soong/.intermediates/package_foo/libfoo/android_arm64_armv8-a_static/gen/aidl_library.sbox.textproto", + }, + libfoo.Rule("aidl_library").Implicits, + ) + + manifest := android.RuleBuilderSboxProtoForTests(t, ctx, libfoo.Output("aidl_library.sbox.textproto")) + aidlCommand := manifest.Commands[0].GetCommand() + + expectedAidlFlags := "-Ipackage_foo/a -Ipackage_bar/x" + if !strings.Contains(aidlCommand, expectedAidlFlags) { + t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlags) + } + + outputs := strings.Join(libfoo.AllOutputs(), " ") + + android.AssertStringDoesContain(t, "aidl-generated header", outputs, "gen/aidl_library/b/BpFoo.h") + android.AssertStringDoesContain(t, "aidl-generated header", outputs, "gen/aidl_library/b/BnFoo.h") + android.AssertStringDoesContain(t, "aidl-generated header", outputs, "gen/aidl_library/b/Foo.h") + android.AssertStringDoesContain(t, "aidl-generated cpp", outputs, "b/Foo.cpp") + // Confirm that the aidl header doesn't get compiled to cpp and h files + android.AssertStringDoesNotContain(t, "aidl-generated header", outputs, "gen/aidl_library/y/BpBar.h") + android.AssertStringDoesNotContain(t, "aidl-generated header", outputs, "gen/aidl_library/y/BnBar.h") + android.AssertStringDoesNotContain(t, "aidl-generated header", outputs, "gen/aidl_library/y/Bar.h") + android.AssertStringDoesNotContain(t, "aidl-generated cpp", outputs, "y/Bar.cpp") +} + func TestAidlFlagsPassedToTheAidlCompiler(t *testing.T) { t.Parallel() - ctx := testCc(t, ` + ctx := android.GroupFixturePreparers( + prepareForCcTest, + aidl_library.PrepareForTestWithAidlLibrary, + ).RunTestWithBp(t, ` cc_library { name: "libfoo", srcs: ["a/Foo.aidl"], @@ -4430,7 +2287,7 @@ func TestAidlFlagsPassedToTheAidlCompiler(t *testing.T) { `) libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static") - manifest := android.RuleBuilderSboxProtoForTests(t, libfoo.Output("aidl.sbox.textproto")) + manifest := android.RuleBuilderSboxProtoForTests(t, ctx.TestContext, libfoo.Output("aidl.sbox.textproto")) aidlCommand := manifest.Commands[0].GetCommand() expectedAidlFlag := "-Werror" if !strings.Contains(aidlCommand, expectedAidlFlag) { @@ -4481,7 +2338,7 @@ func TestAidlFlagsWithMinSdkVersion(t *testing.T) { } `) libfoo := ctx.ModuleForTests("libfoo", tc.variant) - manifest := android.RuleBuilderSboxProtoForTests(t, libfoo.Output("aidl.sbox.textproto")) + manifest := android.RuleBuilderSboxProtoForTests(t, ctx, libfoo.Output("aidl.sbox.textproto")) aidlCommand := manifest.Commands[0].GetCommand() expectedAidlFlag := "--min_sdk_version=" + tc.expected if !strings.Contains(aidlCommand, expectedAidlFlag) { @@ -4491,6 +2348,55 @@ func TestAidlFlagsWithMinSdkVersion(t *testing.T) { } } +func TestInvalidAidlProp(t *testing.T) { + t.Parallel() + + testCases := []struct { + description string + bp string + }{ + { + description: "Invalid use of aidl.libs and aidl.include_dirs", + bp: ` + cc_library { + name: "foo", + aidl: { + libs: ["foo_aidl"], + include_dirs: ["bar/include"], + } + } + `, + }, + { + description: "Invalid use of aidl.libs and aidl.local_include_dirs", + bp: ` + cc_library { + name: "foo", + aidl: { + libs: ["foo_aidl"], + local_include_dirs: ["include"], + } + } + `, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.description, func(t *testing.T) { + bp := ` + aidl_library { + name: "foo_aidl", + srcs: ["Foo.aidl"], + } ` + testCase.bp + android.GroupFixturePreparers( + prepareForCcTest, + aidl_library.PrepareForTestWithAidlLibrary. + ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("For aidl headers, please only use aidl.libs prop")), + ).RunTestWithBp(t, bp) + }) + } +} + func TestMinSdkVersionInClangTriple(t *testing.T) { t.Parallel() ctx := testCc(t, ` @@ -4546,7 +2452,7 @@ func TestIncludeDirsExporting(t *testing.T) { checkIncludeDirs := func(t *testing.T, ctx *android.TestContext, module android.Module, checkers ...exportedChecker) { t.Helper() - exported := ctx.ModuleProvider(module, FlagExporterInfoProvider).(FlagExporterInfo) + exported, _ := android.SingletonModuleProvider(ctx, module, FlagExporterInfoProvider) name := module.Name() for _, checker := range checkers { @@ -4706,7 +2612,15 @@ func TestIncludeDirsExporting(t *testing.T) { }) t.Run("ensure only aidl headers are exported", func(t *testing.T) { - ctx := testCc(t, genRuleModules+` + ctx := android.GroupFixturePreparers( + prepareForCcTest, + aidl_library.PrepareForTestWithAidlLibrary, + ).RunTestWithBp(t, ` + aidl_library { + name: "libfoo_aidl", + srcs: ["x/y/Bar.aidl"], + strip_import_prefix: "x", + } cc_library_shared { name: "libfoo", srcs: [ @@ -4715,25 +2629,33 @@ func TestIncludeDirsExporting(t *testing.T) { "a.proto", ], aidl: { + libs: ["libfoo_aidl"], export_aidl_headers: true, } } - `) + `).TestContext foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() checkIncludeDirs(t, ctx, foo, expectedIncludeDirs(` .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl + .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library `), expectedSystemIncludeDirs(``), expectedGeneratedHeaders(` .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/b.h .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bnb.h .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bpb.h + .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library/y/Bar.h + .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library/y/BnBar.h + .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library/y/BpBar.h `), expectedOrderOnlyDeps(` .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/b.h .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bnb.h .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bpb.h + .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library/y/Bar.h + .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library/y/BnBar.h + .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl_library/y/BpBar.h `), ) }) @@ -4845,8 +2767,8 @@ func TestIncludeDirectoryOrdering(t *testing.T) { cppOnly := []string{"-fPIC", "${config.CommonGlobalCppflags}", "${config.DeviceGlobalCppflags}", "${config.ArmCppflags}"} cflags := []string{"-Werror", "-std=candcpp"} - cstd := []string{"-std=gnu11", "-std=conly"} - cppstd := []string{"-std=gnu++17", "-std=cpp", "-fno-rtti"} + cstd := []string{"-std=gnu17", "-std=conly"} + cppstd := []string{"-std=gnu++20", "-std=cpp", "-fno-rtti"} lastIncludes := []string{ "out/soong/ndk/sysroot/usr/include", @@ -4978,8 +2900,6 @@ func TestIncludeDirectoryOrdering(t *testing.T) { PrepareForIntegrationTestWithCc, android.FixtureAddTextFile("external/foo/Android.bp", bp), ).RunTest(t) - // Use the arm variant instead of the arm64 variant so that it gets headers from - // ndk_libandroid_support to test LateStaticLibs. cflags := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_sdk_static").Output("obj/external/foo/foo.o").Args["cFlags"] var includes []string @@ -5176,55 +3096,140 @@ func TestCcBuildBrokenClangCFlags(t *testing.T) { } } -func TestDclaLibraryInApex(t *testing.T) { +func TestStrippedAllOutputFile(t *testing.T) { t.Parallel() bp := ` - cc_library_shared { - name: "cc_lib_in_apex", - srcs: ["foo.cc"], - apex_available: ["myapex"], - bazel_module: { label: "//foo/bar:bar" }, - }` - label := "//foo/bar:bar" - arch64 := "arm64_armv8-a" - arch32 := "arm_armv7-a-neon" - apexCfgKey := android.ApexConfigKey{ - WithinApex: true, - ApexSdkVersion: "28", + cc_library { + name: "test_lib", + srcs: ["test_lib.cpp"], + dist: { + targets: [ "dist_target" ], + tag: "stripped_all", + } + } + ` + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) + ctx := testCcWithConfig(t, config) + testingModule := ctx.ModuleForTests("test_lib", "android_arm_armv7-a-neon_shared") + outputFile := testingModule.OutputFiles(t, "stripped_all") + if !strings.HasSuffix(outputFile.Strings()[0], "/stripped_all/test_lib.so") { + t.Errorf("Unexpected output file: %s", outputFile.Strings()[0]) + return } +} - result := android.GroupFixturePreparers( +func TestImageVariants(t *testing.T) { + t.Parallel() + + bp := ` + cc_binary { + name: "binfoo", + srcs: ["binfoo.cc"], + vendor_available: true, + product_available: true, + shared_libs: ["libbar"] + } + cc_library { + name: "libbar", + srcs: ["libbar.cc"], + vendor_available: true, + product_available: true, + } + ` + + ctx := prepareForCcTest.RunTestWithBp(t, bp) + + hasDep := func(m android.Module, wantDep android.Module) bool { + t.Helper() + var found bool + ctx.VisitDirectDeps(m, func(dep blueprint.Module) { + if dep == wantDep { + found = true + } + }) + return found + } + + testDepWithVariant := func(imageVariant string) { + imageVariantStr := "" + if imageVariant != "core" { + imageVariantStr = "_" + imageVariant + } + binFooModule := ctx.ModuleForTests("binfoo", "android"+imageVariantStr+"_arm64_armv8-a").Module() + libBarModule := ctx.ModuleForTests("libbar", "android"+imageVariantStr+"_arm64_armv8-a_shared").Module() + android.AssertBoolEquals(t, "binfoo should have dependency on libbar with image variant "+imageVariant, true, hasDep(binFooModule, libBarModule)) + } + + testDepWithVariant("core") + testDepWithVariant("vendor") + testDepWithVariant("product") +} + +func TestVendorSdkVersion(t *testing.T) { + t.Parallel() + + bp := ` + cc_library { + name: "libfoo", + srcs: ["libfoo.cc"], + vendor_available: true, + } + + cc_library { + name: "libbar", + srcs: ["libbar.cc"], + vendor_available: true, + min_sdk_version: "29", + } + ` + + ctx := prepareForCcTest.RunTestWithBp(t, bp) + testSdkVersionFlag := func(module, version string) { + flags := ctx.ModuleForTests(module, "android_vendor_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + android.AssertStringDoesContain(t, "min sdk version", flags, "-target aarch64-linux-android"+version) + } + + testSdkVersionFlag("libfoo", "10000") + testSdkVersionFlag("libbar", "29") + + ctx = android.GroupFixturePreparers( prepareForCcTest, - android.FixtureRegisterWithContext(registerTestMutators), - android.FixtureModifyConfig(func(config android.Config) { - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: "outputbase", - LabelToCcInfo: map[string]cquery.CcInfo{ - android.BuildMockBazelContextResultKey(label, arch32, android.Android, apexCfgKey): cquery.CcInfo{ - RootDynamicLibraries: []string{"foo.so"}, - }, - android.BuildMockBazelContextResultKey(label, arch64, android.Android, apexCfgKey): cquery.CcInfo{ - RootDynamicLibraries: []string{"foo.so"}, - }, - }, - BazelRequests: make(map[string]bool), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + if variables.BuildFlags == nil { + variables.BuildFlags = make(map[string]string) } + variables.BuildFlags["RELEASE_BOARD_API_LEVEL_FROZEN"] = "true" }), ).RunTestWithBp(t, bp) - ctx := result.TestContext + testSdkVersionFlag("libfoo", "30") + testSdkVersionFlag("libbar", "29") +} + +func TestClangVerify(t *testing.T) { + t.Parallel() + + ctx := testCc(t, ` + cc_library { + name: "lib_no_clang_verify", + srcs: ["libnocv.cc"], + } + + cc_library { + name: "lib_clang_verify", + srcs: ["libcv.cc"], + clang_verify: true, + } + `) + + module := ctx.ModuleForTests("lib_no_clang_verify", "android_arm64_armv8-a_shared") - // Test if the bazel request is queued correctly - key := android.BuildMockBazelContextRequestKey(label, cquery.GetCcInfo, arch32, android.Android, apexCfgKey) - if !ctx.Config().BazelContext.(android.MockBazelContext).BazelRequests[key] { - t.Errorf("Bazel request was not queued: %s", key) + cFlags_no_cv := module.Rule("cc").Args["cFlags"] + if strings.Contains(cFlags_no_cv, "-Xclang") || strings.Contains(cFlags_no_cv, "-verify") { + t.Errorf("expected %q not in cflags, got %q", "-Xclang -verify", cFlags_no_cv) } - sharedFoo := ctx.ModuleForTests(ccLibInApex, "android_arm_armv7-a-neon_shared_"+apexVariationName).Module() - producer := sharedFoo.(android.OutputFileProducer) - outputFiles, err := producer.OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object outputfiles %s", err) + cFlags_cv := ctx.ModuleForTests("lib_clang_verify", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"] + if strings.Contains(cFlags_cv, "-Xclang") && strings.Contains(cFlags_cv, "-verify") { + t.Errorf("expected %q in cflags, got %q", "-Xclang -verify", cFlags_cv) } - expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.so"} - android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings()) } diff --git a/cc/cc_test_only_property_test.go b/cc/cc_test_only_property_test.go new file mode 100644 index 000000000..972e86bc5 --- /dev/null +++ b/cc/cc_test_only_property_test.go @@ -0,0 +1,187 @@ +// Copyright 2024 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 ( + "android/soong/android" + "android/soong/android/team_proto" + "log" + "strings" + "testing" + + "github.com/google/blueprint" + "google.golang.org/protobuf/proto" +) + +func TestTestOnlyProvider(t *testing.T) { + t.Parallel() + ctx := android.GroupFixturePreparers( + prepareForCcTest, + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("cc_test_host", TestHostFactory) + }), + ).RunTestWithBp(t, ` + // These should be test-only + cc_fuzz { name: "cc-fuzz" } + cc_test { name: "cc-test", gtest:false } + cc_benchmark { name: "cc-benchmark" } + cc_library { name: "cc-library-forced", + test_only: true } + cc_test_library {name: "cc-test-library", gtest: false} + cc_test_host {name: "cc-test-host", gtest: false} + + // These should not be. + cc_genrule { name: "cc_genrule", cmd: "echo foo", out: ["out"] } + cc_library { name: "cc_library" } + cc_library { name: "cc_library_false", test_only: false } + cc_library_static { name: "cc_static" } + cc_library_shared { name: "cc_library_shared" } + + cc_object { name: "cc-object" } + `) + + // Visit all modules and ensure only the ones that should + // marked as test-only are marked as test-only. + + actualTestOnly := []string{} + ctx.VisitAllModules(func(m blueprint.Module) { + if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, android.TestOnlyProviderKey); ok { + if provider.TestOnly { + actualTestOnly = append(actualTestOnly, m.Name()) + } + } + }) + expectedTestOnlyModules := []string{ + "cc-test", + "cc-library-forced", + "cc-fuzz", + "cc-benchmark", + "cc-test-library", + "cc-test-host", + } + + notEqual, left, right := android.ListSetDifference(expectedTestOnlyModules, actualTestOnly) + if notEqual { + t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right) + } +} + +func TestTestOnlyInTeamsProto(t *testing.T) { + t.Parallel() + ctx := android.GroupFixturePreparers( + android.PrepareForTestWithTeamBuildComponents, + prepareForCcTest, + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + ctx.RegisterParallelSingletonType("all_teams", android.AllTeamsFactory) + ctx.RegisterModuleType("cc_test_host", TestHostFactory) + + }), + ).RunTestWithBp(t, ` + package { default_team: "someteam"} + + // These should be test-only + cc_fuzz { name: "cc-fuzz" } + cc_test { name: "cc-test", gtest:false } + cc_benchmark { name: "cc-benchmark" } + cc_library { name: "cc-library-forced", + test_only: true } + cc_test_library {name: "cc-test-library", gtest: false} + cc_test_host {name: "cc-test-host", gtest: false} + + // These should not be. + cc_genrule { name: "cc_genrule", cmd: "echo foo", out: ["out"] } + cc_library { name: "cc_library" } + cc_library_static { name: "cc_static" } + cc_library_shared { name: "cc_library_shared" } + + cc_object { name: "cc-object" } + team { + name: "someteam", + trendy_team_id: "cool_team", + } + `) + + var teams *team_proto.AllTeams + teams = getTeamProtoOutput(t, ctx) + + // map of module name -> trendy team name. + actualTrueModules := []string{} + for _, teamProto := range teams.Teams { + if Bool(teamProto.TestOnly) { + actualTrueModules = append(actualTrueModules, teamProto.GetTargetName()) + } + } + expectedTestOnlyModules := []string{ + "cc-test", + "cc-library-forced", + "cc-fuzz", + "cc-benchmark", + "cc-test-library", + "cc-test-host", + } + + notEqual, left, right := android.ListSetDifference(expectedTestOnlyModules, actualTrueModules) + if notEqual { + t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right) + } +} + +// Don't allow setting test-only on things that are always tests or never tests. +func TestInvalidTestOnlyTargets(t *testing.T) { + testCases := []string{ + ` cc_test { name: "cc-test", test_only: true, gtest: false, srcs: ["foo.cc"], } `, + ` cc_binary { name: "cc-binary", test_only: true, srcs: ["foo.cc"], } `, + ` cc_test_library {name: "cc-test-library", test_only: true, gtest: false} `, + ` cc_test_host {name: "cc-test-host", test_only: true, gtest: false} `, + ` cc_defaults {name: "cc-defaults", test_only: true} `, + } + + for i, bp := range testCases { + ctx := android.GroupFixturePreparers( + prepareForCcTest, + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("cc_test_host", TestHostFactory) + })). + ExtendWithErrorHandler(android.FixtureIgnoreErrors). + RunTestWithBp(t, bp) + if len(ctx.Errs) == 0 { + t.Errorf("Expected err setting test_only in testcase #%d", i) + } + if len(ctx.Errs) > 1 { + t.Errorf("Too many errs: [%s] %v", bp, ctx.Errs) + } + + if len(ctx.Errs) == 1 { + if !strings.Contains(ctx.Errs[0].Error(), "unrecognized property \"test_only\"") { + t.Errorf("ERR: %s bad bp: %s", ctx.Errs[0], bp) + } + } + } +} + +func getTeamProtoOutput(t *testing.T, ctx *android.TestResult) *team_proto.AllTeams { + teams := new(team_proto.AllTeams) + config := ctx.SingletonForTests("all_teams") + allOutputs := config.AllOutputs() + + protoPath := allOutputs[0] + + out := config.MaybeOutput(protoPath) + outProto := []byte(android.ContentFromFileRuleForTests(t, ctx.TestContext, out)) + if err := proto.Unmarshal(outProto, teams); err != nil { + log.Fatalln("Failed to parse teams proto:", err) + } + return teams +} diff --git a/cc/ccdeps.go b/cc/ccdeps.go index 75e1faf0b..d30abbab7 100644 --- a/cc/ccdeps.go +++ b/cc/ccdeps.go @@ -30,7 +30,7 @@ import ( // The info file is generated in $OUT/module_bp_cc_depend.json. func init() { - android.RegisterSingletonType("ccdeps_generator", ccDepsGeneratorSingleton) + android.RegisterParallelSingletonType("ccdeps_generator", ccDepsGeneratorSingleton) } func ccDepsGeneratorSingleton() android.Singleton { diff --git a/cc/check.go b/cc/check.go index 58ff5b2ad..e3af3b288 100644 --- a/cc/check.go +++ b/cc/check.go @@ -45,6 +45,9 @@ func CheckBadCompilerFlags(ctx BaseModuleContext, prop string, flags []string) { ctx.PropertyErrorf(prop, "-Weverything is not allowed in Android.bp files. "+ "Build with `m ANDROID_TEMPORARILY_ALLOW_WEVERYTHING=true` to experiment locally with -Weverything.") } + } else if strings.HasPrefix(flag, "-target ") || strings.HasPrefix(flag, "--target ") || + strings.HasPrefix(flag, "-target=") || strings.HasPrefix(flag, "--target=") { + ctx.PropertyErrorf(prop, "Bad flag: `%s`, use the correct target soong rule.", flag) } else if strings.Contains(flag, " ") { args := strings.Split(flag, " ") if args[0] == "-include" { @@ -61,6 +64,10 @@ func CheckBadCompilerFlags(ctx BaseModuleContext, prop string, flags []string) { if len(args) > 2 { ctx.PropertyErrorf(prop, "`-mllvm` only takes one argument: `%s`", flag) } + } else if args[0] == "-Xclang" { + if len(args) > 2 { + ctx.PropertyErrorf(prop, "`-Xclang` only takes one argument: `%s`", flag) + } } else if strings.HasPrefix(flag, "-D") && strings.Contains(flag, "=") { // Do nothing in this case. // For now, we allow space characters in -DNAME=def form to allow use cases diff --git a/cc/cmake_ext_add_aidl_library.txt b/cc/cmake_ext_add_aidl_library.txt new file mode 100644 index 000000000..d5c134e83 --- /dev/null +++ b/cc/cmake_ext_add_aidl_library.txt @@ -0,0 +1,77 @@ +if ("${CMAKE_HOST_SYSTEM_PROCESSOR}" MATCHES "^(arm|aarch)") + set(PREBUILTS_BIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/prebuilts/host/linux_musl-arm64/bin") +else() + set(PREBUILTS_BIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/prebuilts/host/linux-x86/bin") +endif() +if (NOT AIDL_BIN) + find_program(AIDL_BIN aidl REQUIRED HINTS "${PREBUILTS_BIN_DIR}") +endif() + +function(add_aidl_library NAME LANG AIDLROOT SOURCES AIDLFLAGS) + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.20") + cmake_policy(SET CMP0116 NEW) + endif() + + # Strip trailing slash + get_filename_component(AIDLROOT_TRAILING "${AIDLROOT}" NAME) + if ("${AIDLROOT_TRAILING}" STREQUAL "") + get_filename_component(AIDLROOT "${AIDLROOT}foo" DIRECTORY) + endif() + + set(GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/.intermediates/${NAME}-source") + set(GEN_SOURCES) + foreach (SOURCE ${SOURCES}) + set(SOURCE_FULL ${AIDLROOT}/${SOURCE}) + get_filename_component(SOURCE_WLE ${SOURCE} NAME_WLE) + get_filename_component(SOURCE_SUBDIR ${SOURCE} DIRECTORY) + set(GEN_SOURCE "${GEN_DIR}/${SOURCE_SUBDIR}/${SOURCE_WLE}.cpp") + + file(READ "${SOURCE}" SOURCE_CONTENTS) + string(FIND "${SOURCE_CONTENTS}" "@VintfStability" VINTF_MATCH) + set(STABILITY_FLAG) + if (${VINTF_MATCH} GREATER_EQUAL 0) + set(STABILITY_FLAG --stability vintf) + endif() + + set(DEPFILE_ARG) + if (NOT ${CMAKE_GENERATOR} STREQUAL "Unix Makefiles") + set(DEPFILE_ARG DEPFILE "${GEN_SOURCE}.d") + endif() + + add_custom_command( + OUTPUT "${GEN_SOURCE}" + MAIN_DEPENDENCY "${SOURCE_FULL}" + ${DEPFILE_ARG} + COMMAND "${AIDL_BIN}" + ARGS + --lang=${LANG} + --include="${AIDLROOT}" + --dep="${GEN_SOURCE}.d" + --out="${GEN_DIR}" + --header_out="${GEN_DIR}/include" + --ninja + --structured + --min_sdk_version=current + ${STABILITY_FLAG} + ${AIDLFLAGS} + "${SOURCE_FULL}" + ) + list(APPEND GEN_SOURCES "${GEN_SOURCE}") + endforeach() + + add_library(${NAME} ${GEN_SOURCES}) + + target_include_directories(${NAME} + PUBLIC + "${GEN_DIR}/include" + ) + + if (${LANG} STREQUAL "ndk") + set(BINDER_LIB_NAME "libbinder_ndk_sdk") + else() + set(BINDER_LIB_NAME "libbinder_sdk") + endif() + target_link_libraries(${NAME} + ${BINDER_LIB_NAME} + ) +endfunction() diff --git a/cc/cmake_ext_append_flags.txt b/cc/cmake_ext_append_flags.txt new file mode 100644 index 000000000..2cfb1aca9 --- /dev/null +++ b/cc/cmake_ext_append_flags.txt @@ -0,0 +1,10 @@ +include(CheckCXXCompilerFlag) + +macro(append_cxx_flags_if_supported VAR) + foreach(FLAG ${ARGN}) + check_cxx_compiler_flag(${FLAG} HAS_FLAG${FLAG}) + if(${HAS_FLAG${FLAG}}) + list(APPEND ${VAR} ${FLAG}) + endif() + endforeach() +endmacro() diff --git a/cc/cmake_main.txt b/cc/cmake_main.txt new file mode 100644 index 000000000..eeabf53e1 --- /dev/null +++ b/cc/cmake_main.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.18) +project(<<.M.Name>> CXX) +set(CMAKE_CXX_STANDARD 20) +enable_testing() + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +include(AddAidlLibrary) +include(AppendCxxFlagsIfSupported) +include(FindThreads) + +if (NOT ANDROID_BUILD_TOP) + set(ANDROID_BUILD_TOP "${CMAKE_CURRENT_SOURCE_DIR}") +endif() + +<<cflagsList .M.Name "_CFLAGS" .M.Properties.Cflags .M.Properties.Unportable_flags .M.Properties.Cflags_ignored>> + +<<range .Pprop.SystemPackages ->> +find_package(<<.>> REQUIRED) +<<end >> +<<range .Pprop.PregeneratedPackages ->> +add_subdirectory("${ANDROID_BUILD_TOP}/<<.>>" "<<.>>/build" EXCLUDE_FROM_ALL) +<<end>> +add_compile_options(${<<.M.Name>>_CFLAGS}) +link_libraries(${CMAKE_THREAD_LIBS_INIT}) +<<range $moduleDir, $value := .ModuleDirs ->> +add_subdirectory(<<$moduleDir>>) +<<end>> diff --git a/cc/cmake_module_aidl.txt b/cc/cmake_module_aidl.txt new file mode 100644 index 000000000..84755a32a --- /dev/null +++ b/cc/cmake_module_aidl.txt @@ -0,0 +1,11 @@ +# <<.M.Name>> + +<<setList .M.Name "_SRCS" "" (getAidlSources .M)>> + +<<setList .M.Name "_AIDLFLAGS" "" (getCompilerProperties .M).AidlInterface.Flags>> + +add_aidl_library(<<.M.Name>> <<(getCompilerProperties .M).AidlInterface.Lang>> + "${ANDROID_BUILD_TOP}/<<.Ctx.OtherModuleDir .M>>/<<(getCompilerProperties .M).AidlInterface.AidlRoot>>" + "${<<.M.Name>>_SRCS}" + "${<<.M.Name>>_AIDLFLAGS}") +add_library(android::<<.M.Name>> ALIAS <<.M.Name>>) diff --git a/cc/cmake_module_cc.txt b/cc/cmake_module_cc.txt new file mode 100644 index 000000000..0dc45aed1 --- /dev/null +++ b/cc/cmake_module_cc.txt @@ -0,0 +1,44 @@ +<<$srcs := getSources .M>> +<<$includeDirs := getIncludeDirs .Ctx .M>> +<<$cflags := getCflagsProperty .Ctx .M>> +<<$deps := mapLibraries .Ctx .M (concat5 +(getLinkerProperties .M).Whole_static_libs +(getLinkerProperties .M).Static_libs +(getLinkerProperties .M).Shared_libs +(getLinkerProperties .M).Header_libs +(getExtraLibs .M) +) .Pprop.LibraryMapping>> +<<$moduleType := getModuleType .M>> +<<$moduleTypeCmake := "executable">> +<<if eq $moduleType "library">> +<<$moduleTypeCmake = "library">> +<<end>> + +# <<.M.Name>> +<<if $srcs>> +<<setList .M.Name "_SRCS" "${ANDROID_BUILD_TOP}/" (toStrings $srcs)>> +add_<<$moduleTypeCmake>>(<<.M.Name>> ${<<.M.Name>>_SRCS}) +<<- else>> +add_<<$moduleTypeCmake>>(<<.M.Name>> INTERFACE) +<<- end>> +<<- if eq $moduleType "library">> +add_library(android::<<.M.Name>> ALIAS <<.M.Name>>) +<<- else if eq $moduleType "test">> +add_test(NAME <<.M.Name>> COMMAND <<.M.Name>>) +<<- end>> +<<print "">> + +<<- if $includeDirs>> +<<setList .M.Name "_INCLUDES" "${ANDROID_BUILD_TOP}/" $includeDirs>> +target_include_directories(<<.M.Name>> <<if $srcs>>PUBLIC<<else>>INTERFACE<<end>> ${<<.M.Name>>_INCLUDES}) +<<end>> + +<<- if and $srcs $cflags>> +<<cflagsList .M.Name "_CFLAGS" $cflags .Snapshot.Properties.Unportable_flags .Snapshot.Properties.Cflags_ignored>> +target_compile_options(<<.M.Name>> PRIVATE ${<<.M.Name>>_CFLAGS}) +<<end>> + +<<- if $deps>> +<<setList .M.Name "_DEPENDENCIES" "" $deps>> +target_link_libraries(<<.M.Name>> <<if not $srcs>>INTERFACE <<end ->> ${<<.M.Name>>_DEPENDENCIES}) +<<end>> diff --git a/cc/cmake_snapshot.go b/cc/cmake_snapshot.go new file mode 100644 index 000000000..fb2924a07 --- /dev/null +++ b/cc/cmake_snapshot.go @@ -0,0 +1,573 @@ +// Copyright 2024 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 ( + "bytes" + _ "embed" + "fmt" + "path/filepath" + "slices" + "sort" + "strings" + "text/template" + + "android/soong/android" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +const veryVerbose bool = false + +//go:embed cmake_main.txt +var templateCmakeMainRaw string +var templateCmakeMain *template.Template = parseTemplate(templateCmakeMainRaw) + +//go:embed cmake_module_cc.txt +var templateCmakeModuleCcRaw string +var templateCmakeModuleCc *template.Template = parseTemplate(templateCmakeModuleCcRaw) + +//go:embed cmake_module_aidl.txt +var templateCmakeModuleAidlRaw string +var templateCmakeModuleAidl *template.Template = parseTemplate(templateCmakeModuleAidlRaw) + +//go:embed cmake_ext_add_aidl_library.txt +var cmakeExtAddAidlLibrary string + +//go:embed cmake_ext_append_flags.txt +var cmakeExtAppendFlags string + +var defaultUnportableFlags []string = []string{ + "-Wno-c99-designator", + "-Wno-class-memaccess", + "-Wno-exit-time-destructors", + "-Winconsistent-missing-override", + "-Wno-inconsistent-missing-override", + "-Wreorder-init-list", + "-Wno-reorder-init-list", + "-Wno-restrict", + "-Wno-stringop-overread", + "-Wno-subobject-linkage", +} + +var ignoredSystemLibs []string = []string{ + "crtbegin_dynamic", + "crtend_android", + "libc", + "libc++", + "libc++_static", + "libc++demangle", + "libc_musl", + "libc_musl_crtbegin_so", + "libc_musl_crtbegin_static", + "libc_musl_crtend", + "libc_musl_crtend_so", + "libdl", + "libm", + "prebuilt_libclang_rt.builtins", + "prebuilt_libclang_rt.ubsan_minimal", +} + +// Mapping entry between Android's library name and the one used when building outside Android tree. +type LibraryMappingProperty struct { + // Android library name. + Android_name string + + // Library name used when building outside Android. + Mapped_name string + + // If the make file is already present in Android source tree, specify its location. + Package_pregenerated string + + // If the package is expected to be installed on the build host OS, specify its name. + Package_system string +} + +type CmakeSnapshotProperties struct { + // Host modules to add to the snapshot package. Their dependencies are pulled in automatically. + Modules_host []string + + // System modules to add to the snapshot package. Their dependencies are pulled in automatically. + Modules_system []string + + // Vendor modules to add to the snapshot package. Their dependencies are pulled in automatically. + Modules_vendor []string + + // Host prebuilts to bundle with the snapshot. These are tools needed to build outside Android. + Prebuilts []string + + // Global cflags to add when building outside Android. + Cflags []string + + // Flags to skip when building outside Android. + Cflags_ignored []string + + // Mapping between library names used in Android tree and externally. + Library_mapping []LibraryMappingProperty + + // List of cflags that are not portable between compilers that could potentially be used to + // build a generated package. If left empty, it's initialized with a default list. + Unportable_flags []string + + // Whether to include source code as part of the snapshot package. + Include_sources bool +} + +var cmakeSnapshotSourcesProvider = blueprint.NewProvider[android.Paths]() + +type CmakeSnapshot struct { + android.ModuleBase + + Properties CmakeSnapshotProperties + + zipPath android.WritablePath +} + +type cmakeProcessedProperties struct { + LibraryMapping map[string]LibraryMappingProperty + PregeneratedPackages []string + SystemPackages []string +} + +type cmakeSnapshotDependencyTag struct { + blueprint.BaseDependencyTag + name string +} + +var ( + cmakeSnapshotModuleTag = cmakeSnapshotDependencyTag{name: "cmake-snapshot-module"} + cmakeSnapshotPrebuiltTag = cmakeSnapshotDependencyTag{name: "cmake-snapshot-prebuilt"} +) + +func parseTemplate(templateContents string) *template.Template { + funcMap := template.FuncMap{ + "setList": func(name string, nameSuffix string, itemPrefix string, items []string) string { + var list strings.Builder + list.WriteString("set(" + name + nameSuffix) + templateListBuilder(&list, itemPrefix, items) + return list.String() + }, + "toStrings": func(files android.Paths) []string { + return files.Strings() + }, + "concat5": func(list1 []string, list2 []string, list3 []string, list4 []string, list5 []string) []string { + return append(append(append(append(list1, list2...), list3...), list4...), list5...) + }, + "cflagsList": func(name string, nameSuffix string, flags []string, + unportableFlags []string, ignoredFlags []string) string { + if len(unportableFlags) == 0 { + unportableFlags = defaultUnportableFlags + } + + var filteredPortable []string + var filteredUnportable []string + for _, flag := range flags { + if slices.Contains(ignoredFlags, flag) { + continue + } else if slices.Contains(unportableFlags, flag) { + filteredUnportable = append(filteredUnportable, flag) + } else { + filteredPortable = append(filteredPortable, flag) + } + } + + var list strings.Builder + + list.WriteString("set(" + name + nameSuffix) + templateListBuilder(&list, "", filteredPortable) + + if len(filteredUnportable) > 0 { + list.WriteString("\nappend_cxx_flags_if_supported(" + name + nameSuffix) + templateListBuilder(&list, "", filteredUnportable) + } + + return list.String() + }, + "getSources": func(m *Module) android.Paths { + return m.compiler.(CompiledInterface).Srcs() + }, + "getModuleType": getModuleType, + "getCompilerProperties": func(m *Module) BaseCompilerProperties { + return m.compiler.baseCompilerProps() + }, + "getCflagsProperty": func(ctx android.ModuleContext, m *Module) []string { + cflags := m.compiler.baseCompilerProps().Cflags + return cflags.GetOrDefault(ctx, nil) + }, + "getLinkerProperties": func(m *Module) BaseLinkerProperties { + return m.linker.baseLinkerProps() + }, + "getExtraLibs": getExtraLibs, + "getIncludeDirs": getIncludeDirs, + "mapLibraries": func(ctx android.ModuleContext, m *Module, libs []string, mapping map[string]LibraryMappingProperty) []string { + var mappedLibs []string + for _, lib := range libs { + mappedLib, exists := mapping[lib] + if exists { + lib = mappedLib.Mapped_name + } else { + if !ctx.OtherModuleExists(lib) { + ctx.OtherModuleErrorf(m, "Dependency %s doesn't exist", lib) + } + lib = "android::" + lib + } + if lib == "" { + continue + } + mappedLibs = append(mappedLibs, lib) + } + sort.Strings(mappedLibs) + mappedLibs = slices.Compact(mappedLibs) + return mappedLibs + }, + "getAidlSources": func(m *Module) []string { + aidlInterface := m.compiler.baseCompilerProps().AidlInterface + aidlRoot := aidlInterface.AidlRoot + string(filepath.Separator) + if aidlInterface.AidlRoot == "" { + aidlRoot = "" + } + var sources []string + for _, src := range aidlInterface.Sources { + if !strings.HasPrefix(src, aidlRoot) { + panic(fmt.Sprintf("Aidl source '%v' doesn't start with '%v'", src, aidlRoot)) + } + sources = append(sources, src[len(aidlRoot):]) + } + return sources + }, + } + + return template.Must(template.New("").Delims("<<", ">>").Funcs(funcMap).Parse(templateContents)) +} + +func sliceWithPrefix(prefix string, slice []string) []string { + output := make([]string, len(slice)) + for i, elem := range slice { + output[i] = prefix + elem + } + return output +} + +func templateListBuilder(builder *strings.Builder, itemPrefix string, items []string) { + if len(items) > 0 { + builder.WriteString("\n") + for _, item := range items { + builder.WriteString(" " + itemPrefix + item + "\n") + } + } + builder.WriteString(")") +} + +func executeTemplate(templ *template.Template, buffer *bytes.Buffer, data any) string { + buffer.Reset() + if err := templ.Execute(buffer, data); err != nil { + panic(err) + } + output := strings.TrimSpace(buffer.String()) + buffer.Reset() + return output +} + +func (m *CmakeSnapshot) DepsMutator(ctx android.BottomUpMutatorContext) { + deviceVariations := ctx.Config().AndroidFirstDeviceTarget.Variations() + deviceSystemVariations := append(deviceVariations, blueprint.Variation{"image", ""}) + deviceVendorVariations := append(deviceVariations, blueprint.Variation{"image", "vendor"}) + hostVariations := ctx.Config().BuildOSTarget.Variations() + + ctx.AddVariationDependencies(hostVariations, cmakeSnapshotModuleTag, m.Properties.Modules_host...) + ctx.AddVariationDependencies(deviceSystemVariations, cmakeSnapshotModuleTag, m.Properties.Modules_system...) + ctx.AddVariationDependencies(deviceVendorVariations, cmakeSnapshotModuleTag, m.Properties.Modules_vendor...) + + if len(m.Properties.Prebuilts) > 0 { + prebuilts := append(m.Properties.Prebuilts, "libc++") + ctx.AddVariationDependencies(hostVariations, cmakeSnapshotPrebuiltTag, prebuilts...) + } +} + +func (m *CmakeSnapshot) GenerateAndroidBuildActions(ctx android.ModuleContext) { + var templateBuffer bytes.Buffer + var pprop cmakeProcessedProperties + m.zipPath = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip") + + // Process Library_mapping for more efficient lookups + pprop.LibraryMapping = map[string]LibraryMappingProperty{} + for _, elem := range m.Properties.Library_mapping { + pprop.LibraryMapping[elem.Android_name] = elem + + if elem.Package_pregenerated != "" { + pprop.PregeneratedPackages = append(pprop.PregeneratedPackages, elem.Package_pregenerated) + } + sort.Strings(pprop.PregeneratedPackages) + pprop.PregeneratedPackages = slices.Compact(pprop.PregeneratedPackages) + + if elem.Package_system != "" { + pprop.SystemPackages = append(pprop.SystemPackages, elem.Package_system) + } + sort.Strings(pprop.SystemPackages) + pprop.SystemPackages = slices.Compact(pprop.SystemPackages) + } + + // Generating CMakeLists.txt rules for all modules in dependency tree + moduleDirs := map[string][]string{} + sourceFiles := map[string]android.Path{} + visitedModules := map[string]bool{} + var pregeneratedModules []*Module + ctx.WalkDeps(func(dep_a android.Module, parent android.Module) bool { + moduleName := ctx.OtherModuleName(dep_a) + if visited := visitedModules[moduleName]; visited { + return false // visit only once + } + visitedModules[moduleName] = true + dep, ok := dep_a.(*Module) + if !ok { + return false // not a cc module + } + if mapping, ok := pprop.LibraryMapping[moduleName]; ok { + if mapping.Package_pregenerated != "" { + pregeneratedModules = append(pregeneratedModules, dep) + } + return false // mapped to system or pregenerated (we'll handle these later) + } + if ctx.OtherModuleDependencyTag(dep) == cmakeSnapshotPrebuiltTag { + return false // we'll handle cmakeSnapshotPrebuiltTag later + } + if slices.Contains(ignoredSystemLibs, moduleName) { + return false // system libs built in-tree for Android + } + if dep.compiler == nil { + return false // unsupported module type (e.g. prebuilt) + } + isAidlModule := dep.compiler.baseCompilerProps().AidlInterface.Lang != "" + + if !proptools.Bool(dep.Properties.Cmake_snapshot_supported) { + ctx.OtherModulePropertyErrorf(dep, "cmake_snapshot_supported", + "CMake snapshots not supported, despite being a dependency for %s", + ctx.OtherModuleName(parent)) + return false + } + + if veryVerbose { + fmt.Println("WalkDeps: " + ctx.OtherModuleName(parent) + " -> " + moduleName) + } + + // Generate CMakeLists.txt fragment for this module + templateToUse := templateCmakeModuleCc + if isAidlModule { + templateToUse = templateCmakeModuleAidl + } + moduleFragment := executeTemplate(templateToUse, &templateBuffer, struct { + Ctx *android.ModuleContext + M *Module + Snapshot *CmakeSnapshot + Pprop *cmakeProcessedProperties + }{ + &ctx, + dep, + m, + &pprop, + }) + moduleDir := ctx.OtherModuleDir(dep) + moduleDirs[moduleDir] = append(moduleDirs[moduleDir], moduleFragment) + + if m.Properties.Include_sources { + files, _ := android.OtherModuleProvider(ctx, dep, cmakeSnapshotSourcesProvider) + for _, file := range files { + sourceFiles[file.String()] = file + } + } + + // if it's AIDL module, no need to dive into their dependencies + return !isAidlModule + }) + + // Enumerate sources for pregenerated modules + if m.Properties.Include_sources { + for _, dep := range pregeneratedModules { + if !proptools.Bool(dep.Properties.Cmake_snapshot_supported) { + ctx.OtherModulePropertyErrorf(dep, "cmake_snapshot_supported", + "Pregenerated CMake snapshots not supported, despite being requested for %s", + ctx.ModuleName()) + continue + } + + files, _ := android.OtherModuleProvider(ctx, dep, cmakeSnapshotSourcesProvider) + for _, file := range files { + sourceFiles[file.String()] = file + } + } + } + + // Merging CMakeLists.txt contents for every module directory + var makefilesList android.Paths + for _, moduleDir := range android.SortedKeys(moduleDirs) { + fragments := moduleDirs[moduleDir] + moduleCmakePath := android.PathForModuleGen(ctx, moduleDir, "CMakeLists.txt") + makefilesList = append(makefilesList, moduleCmakePath) + sort.Strings(fragments) + android.WriteFileRule(ctx, moduleCmakePath, strings.Join(fragments, "\n\n\n")) + } + + // Generating top-level CMakeLists.txt + mainCmakePath := android.PathForModuleGen(ctx, "CMakeLists.txt") + makefilesList = append(makefilesList, mainCmakePath) + mainContents := executeTemplate(templateCmakeMain, &templateBuffer, struct { + Ctx *android.ModuleContext + M *CmakeSnapshot + ModuleDirs map[string][]string + Pprop *cmakeProcessedProperties + }{ + &ctx, + m, + moduleDirs, + &pprop, + }) + android.WriteFileRule(ctx, mainCmakePath, mainContents) + + // Generating CMake extensions + extPath := android.PathForModuleGen(ctx, "cmake", "AppendCxxFlagsIfSupported.cmake") + makefilesList = append(makefilesList, extPath) + android.WriteFileRuleVerbatim(ctx, extPath, cmakeExtAppendFlags) + extPath = android.PathForModuleGen(ctx, "cmake", "AddAidlLibrary.cmake") + makefilesList = append(makefilesList, extPath) + android.WriteFileRuleVerbatim(ctx, extPath, cmakeExtAddAidlLibrary) + + // Generating the final zip file + zipRule := android.NewRuleBuilder(pctx, ctx) + zipCmd := zipRule.Command(). + BuiltTool("soong_zip"). + FlagWithOutput("-o ", m.zipPath) + + // Packaging all sources into the zip file + if m.Properties.Include_sources { + var sourcesList android.Paths + for _, file := range android.SortedKeys(sourceFiles) { + path := sourceFiles[file] + sourcesList = append(sourcesList, path) + } + + sourcesRspFile := android.PathForModuleObj(ctx, ctx.ModuleName()+"_sources.rsp") + zipCmd.FlagWithRspFileInputList("-r ", sourcesRspFile, sourcesList) + } + + // Packaging all make files into the zip file + makefilesRspFile := android.PathForModuleObj(ctx, ctx.ModuleName()+"_makefiles.rsp") + zipCmd. + FlagWithArg("-C ", android.PathForModuleGen(ctx).OutputPath.String()). + FlagWithRspFileInputList("-r ", makefilesRspFile, makefilesList) + + // Packaging all prebuilts into the zip file + if len(m.Properties.Prebuilts) > 0 { + var prebuiltsList android.Paths + + ctx.VisitDirectDepsWithTag(cmakeSnapshotPrebuiltTag, func(dep android.Module) { + for _, file := range dep.FilesToInstall() { + prebuiltsList = append(prebuiltsList, file) + } + }) + + prebuiltsRspFile := android.PathForModuleObj(ctx, ctx.ModuleName()+"_prebuilts.rsp") + zipCmd. + FlagWithArg("-C ", android.PathForArbitraryOutput(ctx).String()). + FlagWithArg("-P ", "prebuilts"). + FlagWithRspFileInputList("-r ", prebuiltsRspFile, prebuiltsList) + } + + // Finish generating the final zip file + zipRule.Build(m.zipPath.String(), "archiving "+ctx.ModuleName()) + + ctx.SetOutputFiles(android.Paths{m.zipPath}, "") +} + +func (m *CmakeSnapshot) AndroidMkEntries() []android.AndroidMkEntries { + return []android.AndroidMkEntries{{ + Class: "DATA", + OutputFile: android.OptionalPathForPath(m.zipPath), + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { + entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) + }, + }, + }} +} + +func getModuleType(m *Module) string { + switch m.linker.(type) { + case *binaryDecorator: + return "executable" + case *libraryDecorator: + return "library" + case *testBinary: + return "test" + case *benchmarkDecorator: + return "test" + } + panic(fmt.Sprintf("Unexpected module type: %T", m.linker)) +} + +func getExtraLibs(m *Module) []string { + switch decorator := m.linker.(type) { + case *testBinary: + if decorator.testDecorator.gtest() { + return []string{ + "libgtest", + "libgtest_main", + } + } + case *benchmarkDecorator: + return []string{"libgoogle-benchmark"} + } + return nil +} + +func getIncludeDirs(ctx android.ModuleContext, m *Module) []string { + moduleDir := ctx.OtherModuleDir(m) + string(filepath.Separator) + switch decorator := m.compiler.(type) { + case *libraryDecorator: + return sliceWithPrefix(moduleDir, decorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil)) + } + return nil +} + +func cmakeSnapshotLoadHook(ctx android.LoadHookContext) { + props := struct { + Target struct { + Darwin struct { + Enabled *bool + } + Windows struct { + Enabled *bool + } + } + }{} + props.Target.Darwin.Enabled = proptools.BoolPtr(false) + props.Target.Windows.Enabled = proptools.BoolPtr(false) + ctx.AppendProperties(&props) +} + +// cmake_snapshot allows defining source packages for release outside of Android build tree. +// As a result of cmake_snapshot module build, a zip file is generated with CMake build definitions +// for selected source modules, their dependencies and optionally also the source code itself. +func CmakeSnapshotFactory() android.Module { + module := &CmakeSnapshot{} + module.AddProperties(&module.Properties) + android.AddLoadHook(module, cmakeSnapshotLoadHook) + android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst) + return module +} + +func init() { + android.InitRegistrationContext.RegisterModuleType("cc_cmake_snapshot", CmakeSnapshotFactory) +} diff --git a/cc/cmake_snapshot_test.go b/cc/cmake_snapshot_test.go new file mode 100644 index 000000000..b6f4369b0 --- /dev/null +++ b/cc/cmake_snapshot_test.go @@ -0,0 +1,117 @@ +// Copyright 2024 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 ( + "runtime" + "strings" + "testing" + + "android/soong/android" +) + +func wasGenerated(t *testing.T, m *android.TestingModule, fileName string, ruleType string) { + t.Helper() + ruleName := "<nil>" + if rule := m.MaybeOutput(fileName).Rule; rule != nil { + ruleName = rule.String() + } + if !strings.HasSuffix(ruleName, ruleType) { + t.Errorf("Main Cmake file wasn't generated properly, expected rule %v, found %v", ruleType, ruleName) + } +} + +func TestEmptyCmakeSnapshot(t *testing.T) { + t.Parallel() + result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, ` + cc_cmake_snapshot { + name: "foo", + modules_host: [], + modules_system: [], + modules_vendor: [], + prebuilts: ["libc++"], + include_sources: true, + }`) + + if runtime.GOOS != "linux" { + t.Skip("CMake snapshots are only supported on Linux") + } + + snapshotModule := result.ModuleForTests("foo", "linux_glibc_x86_64") + + wasGenerated(t, &snapshotModule, "CMakeLists.txt", "rawFileCopy") + wasGenerated(t, &snapshotModule, "foo.zip", "") +} + +func TestCmakeSnapshotWithBinary(t *testing.T) { + t.Parallel() + xtra := android.FixtureAddTextFile("some/module/Android.bp", ` + cc_binary { + name: "foo_binary", + host_supported: true, + cmake_snapshot_supported: true, + } + `) + result := android.GroupFixturePreparers(PrepareForIntegrationTestWithCc, xtra).RunTestWithBp(t, ` + cc_cmake_snapshot { + name: "foo", + modules_system: [ + "foo_binary", + ], + include_sources: true, + }`) + + if runtime.GOOS != "linux" { + t.Skip("CMake snapshots are only supported on Linux") + } + + snapshotModule := result.ModuleForTests("foo", "linux_glibc_x86_64") + + wasGenerated(t, &snapshotModule, "some/module/CMakeLists.txt", "rawFileCopy") +} + +func TestCmakeSnapshotAsTestData(t *testing.T) { + t.Parallel() + result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, ` + cc_test { + name: "foo_test", + gtest: false, + srcs: [ + "foo_test.c", + ], + data: [ + ":foo", + ], + target: { + android: {enabled: false}, + }, + } + + cc_cmake_snapshot { + name: "foo", + modules_system: [], + prebuilts: ["libc++"], + include_sources: true, + }`) + + if runtime.GOOS != "linux" { + t.Skip("CMake snapshots are only supported on Linux") + } + + snapshotModule := result.ModuleForTests("foo", "linux_glibc_x86_64") + + wasGenerated(t, &snapshotModule, "CMakeLists.txt", "rawFileCopy") + wasGenerated(t, &snapshotModule, "foo.zip", "") +} diff --git a/cc/cmakelists.go b/cc/cmakelists.go index ad130baaa..0f3f02da5 100644 --- a/cc/cmakelists.go +++ b/cc/cmakelists.go @@ -29,7 +29,7 @@ import ( // structure (see variable CLionOutputProjectsDirectory for root). func init() { - android.RegisterSingletonType("cmakelists_generator", cMakeListsGeneratorSingleton) + android.RegisterParallelSingletonType("cmakelists_generator", cMakeListsGeneratorSingleton) } func cMakeListsGeneratorSingleton() android.Singleton { diff --git a/cc/compdb.go b/cc/compdb.go index ea124438e..da2818324 100644 --- a/cc/compdb.go +++ b/cc/compdb.go @@ -32,7 +32,7 @@ import ( // make SOONG_GEN_COMPDB=1 nothing to get all targets. func init() { - android.RegisterSingletonType("compdb_generator", compDBGeneratorSingleton) + android.RegisterParallelSingletonType("compdb_generator", compDBGeneratorSingleton) } func compDBGeneratorSingleton() android.Singleton { @@ -164,6 +164,7 @@ func getArguments(src android.Path, ctx android.SingletonContext, ccModule *Modu args = append(args, expandAllVars(ctx, ccModule.flags.Local.ConlyFlags)...) } args = append(args, expandAllVars(ctx, ccModule.flags.SystemIncludeFlags)...) + args = append(args, expandAllVars(ctx, ccModule.flags.NoOverrideFlags)...) args = append(args, src.String()) return args } diff --git a/cc/compiler.go b/cc/compiler.go index 88985b6f9..03f9899d8 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -50,7 +50,7 @@ type BaseCompilerProperties struct { Exclude_srcs []string `android:"path,arch_variant"` // list of module-specific flags that will be used for C and C++ compiles. - Cflags []string `android:"arch_variant"` + Cflags proptools.Configurable[[]string] `android:"arch_variant"` // list of module-specific flags that will be used for C++ compiles Cppflags []string `android:"arch_variant"` @@ -98,10 +98,10 @@ type BaseCompilerProperties struct { // list of generated headers to add to the include path. These are the names // of genrule modules. - Generated_headers []string `android:"arch_variant,variant_prepend"` + Generated_headers proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"` // pass -frtti instead of -fno-rtti - Rtti *bool + Rtti *bool `android:"arch_variant"` // C standard version to use. Can be a specific version (such as "gnu11"), // "experimental" (which will use draft versions like C1x when available), @@ -116,10 +116,21 @@ type BaseCompilerProperties struct { // if set to false, use -std=c++* instead of -std=gnu++* Gnu_extensions *bool + // cc Build rules targeting BPF must set this to true. The correct fix is to + // ban targeting bpf in cc rules instead use bpf_rules. (b/323415017) + Bpf_target *bool + + // Add "-Xclang -verify" to the cflags and appends "touch $out" to + // the clang command line. + Clang_verify bool + Yacc *YaccProperties Lex *LexProperties Aidl struct { + // List of aidl_library modules + Libs []string + // list of directories that will be added to the aidl include paths. Include_dirs []string @@ -134,6 +145,22 @@ type BaseCompilerProperties struct { Flags []string } + // Populated by aidl_interface CPP backend to let other modules (e.g. cc_cmake_snapshot) + // access actual source files and not generated cpp intermediary sources. + AidlInterface struct { + // list of aidl_interface sources + Sources []string `blueprint:"mutated"` + + // root directory of AIDL sources + AidlRoot string `blueprint:"mutated"` + + // AIDL backend language (e.g. "cpp", "ndk") + Lang string `blueprint:"mutated"` + + // list of flags passed to AIDL generator + Flags []string `blueprint:"mutated"` + } `blueprint:"mutated"` + Renderscript struct { // list of directories that will be added to the llvm-rs-cc include paths Include_dirs []string @@ -145,12 +172,6 @@ type BaseCompilerProperties struct { Target_api *string } - Debug, Release struct { - // list of module-specific flags that will be used for C and C++ compiles in debug or - // release builds - Cflags []string `android:"arch_variant"` - } `android:"arch_variant"` - Target struct { Vendor, Product struct { // list of source files that should only be used in vendor or @@ -186,13 +207,13 @@ type BaseCompilerProperties struct { // build the recovery variant of the C/C++ module. Exclude_generated_sources []string } - Vendor_ramdisk struct { + Ramdisk, Vendor_ramdisk struct { // list of source files that should not be used to - // build the vendor ramdisk variant of the C/C++ module. + // build the ramdisk variants of the C/C++ module. Exclude_srcs []string `android:"path"` - // List of additional cflags that should be used to build the vendor ramdisk - // variant of the C/C++ module. + // List of additional cflags that should be used to build the ramdisk + // variants of the C/C++ module. Cflags []string } Platform struct { @@ -247,7 +268,7 @@ func (compiler *baseCompiler) Srcs() android.Paths { } func (compiler *baseCompiler) appendCflags(flags []string) { - compiler.Properties.Cflags = append(compiler.Properties.Cflags, flags...) + compiler.Properties.Cflags.AppendSimpleValue(flags) } func (compiler *baseCompiler) appendAsflags(flags []string) { @@ -258,6 +279,10 @@ func (compiler *baseCompiler) compilerProps() []interface{} { return []interface{}{&compiler.Properties, &compiler.Proto} } +func (compiler *baseCompiler) baseCompilerProps() BaseCompilerProperties { + return compiler.Properties +} + func includeBuildDirectory(prop *bool) bool { return proptools.BoolDefault(prop, true) } @@ -271,7 +296,8 @@ func (compiler *baseCompiler) compilerInit(ctx BaseModuleContext) {} func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { deps.GeneratedSources = append(deps.GeneratedSources, compiler.Properties.Generated_sources...) deps.GeneratedSources = removeListFromList(deps.GeneratedSources, compiler.Properties.Exclude_generated_sources) - deps.GeneratedHeaders = append(deps.GeneratedHeaders, compiler.Properties.Generated_headers...) + deps.GeneratedHeaders = append(deps.GeneratedHeaders, compiler.Properties.Generated_headers.GetOrDefault(ctx, nil)...) + deps.AidlLibs = append(deps.AidlLibs, compiler.Properties.Aidl.Libs...) android.ProtoDeps(ctx, &compiler.Proto) if compiler.hasSrcExt(".proto") { @@ -335,24 +361,26 @@ func parseCStd(cStdPtr *string) string { // per-target values, module type values, and per-module Blueprints properties func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags { tc := ctx.toolchain() - modulePath := android.PathForModuleSrc(ctx).String() + modulePath := ctx.ModuleDir() compiler.srcsBeforeGen = android.PathsForModuleSrcExcludes(ctx, compiler.Properties.Srcs, compiler.Properties.Exclude_srcs) compiler.srcsBeforeGen = append(compiler.srcsBeforeGen, deps.GeneratedSources...) - CheckBadCompilerFlags(ctx, "cflags", compiler.Properties.Cflags) + cflags := compiler.Properties.Cflags.GetOrDefault(ctx, nil) + CheckBadCompilerFlags(ctx, "cflags", cflags) CheckBadCompilerFlags(ctx, "cppflags", compiler.Properties.Cppflags) CheckBadCompilerFlags(ctx, "conlyflags", compiler.Properties.Conlyflags) CheckBadCompilerFlags(ctx, "asflags", compiler.Properties.Asflags) CheckBadCompilerFlags(ctx, "vendor.cflags", compiler.Properties.Target.Vendor.Cflags) CheckBadCompilerFlags(ctx, "product.cflags", compiler.Properties.Target.Product.Cflags) CheckBadCompilerFlags(ctx, "recovery.cflags", compiler.Properties.Target.Recovery.Cflags) + CheckBadCompilerFlags(ctx, "ramdisk.cflags", compiler.Properties.Target.Ramdisk.Cflags) CheckBadCompilerFlags(ctx, "vendor_ramdisk.cflags", compiler.Properties.Target.Vendor_ramdisk.Cflags) CheckBadCompilerFlags(ctx, "platform.cflags", compiler.Properties.Target.Platform.Cflags) esc := proptools.NinjaAndShellEscapeList - flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Cflags)...) + flags.Local.CFlags = append(flags.Local.CFlags, esc(cflags)...) flags.Local.CppFlags = append(flags.Local.CppFlags, esc(compiler.Properties.Cppflags)...) flags.Local.ConlyFlags = append(flags.Local.ConlyFlags, esc(compiler.Properties.Conlyflags)...) flags.Local.AsFlags = append(flags.Local.AsFlags, esc(compiler.Properties.Asflags)...) @@ -361,6 +389,11 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Yacc = compiler.Properties.Yacc flags.Lex = compiler.Properties.Lex + flags.ClangVerify = compiler.Properties.Clang_verify + if compiler.Properties.Clang_verify { + flags.Local.CFlags = append(flags.Local.CFlags, "-Xclang", "-verify") + } + // Include dir cflags localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs) if len(localIncludeDirs) > 0 { @@ -380,7 +413,7 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Local.YasmFlags = append(flags.Local.YasmFlags, "-I"+modulePath) } - if !(ctx.useSdk() || ctx.useVndk()) || ctx.Host() { + if !(ctx.useSdk() || ctx.InVendorOrProduct()) || ctx.Host() { flags.SystemIncludeFlags = append(flags.SystemIncludeFlags, "${config.CommonGlobalIncludes}", tc.IncludeFlags()) @@ -397,10 +430,19 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps "-isystem "+getCurrentIncludePath(ctx).Join(ctx, config.NDKTriple(tc)).String()) } - if ctx.useVndk() { + if ctx.InVendorOrProduct() { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_VNDK__") if ctx.inVendor() { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_VENDOR__") + + vendorApiLevel := ctx.Config().VendorApiLevel() + if vendorApiLevel == "" { + // TODO(b/314036847): This is a fallback for UDC targets. + // This must be a build failure when UDC is no longer built + // from this source tree. + vendorApiLevel = ctx.Config().PlatformSdkVersion().String() + } + flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_VENDOR_API__="+vendorApiLevel) } else if ctx.inProduct() { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_PRODUCT__") } @@ -431,11 +473,6 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps ctx.ModuleErrorf("%s", err) } - CheckBadCompilerFlags(ctx, "release.cflags", compiler.Properties.Release.Cflags) - - // TODO: debug - flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Release.Cflags)...) - if !ctx.DeviceConfig().BuildBrokenClangCFlags() && len(compiler.Properties.Clang_cflags) != 0 { ctx.PropertyErrorf("clang_cflags", "property is deprecated, see Changes.md file") } else { @@ -465,10 +502,15 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps target += strconv.Itoa(android.FutureApiLevelInt) } else { apiLevel := nativeApiLevelOrPanic(ctx, version) - target += apiLevel.String() + target += strconv.Itoa(apiLevel.FinalOrFutureInt()) } } + // bpf targets don't need the default target triple. b/308826679 + if proptools.Bool(compiler.Properties.Bpf_target) { + target = "--target=bpf" + } + flags.Global.CFlags = append(flags.Global.CFlags, target) flags.Global.AsFlags = append(flags.Global.AsFlags, target) flags.Global.LdFlags = append(flags.Global.LdFlags, target) @@ -484,8 +526,12 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Global.AsFlags = append(flags.Global.AsFlags, tc.Asflags()) flags.Global.CppFlags = append([]string{"${config.CommonGlobalCppflags}"}, flags.Global.CppFlags...) + + // bpf targets don't need the target specific toolchain cflags. b/308826679 + if !proptools.Bool(compiler.Properties.Bpf_target) { + flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.Cflags()) + } flags.Global.CommonFlags = append(flags.Global.CommonFlags, - tc.Cflags(), "${config.CommonGlobalCflags}", fmt.Sprintf("${config.%sGlobalCflags}", hod)) @@ -493,12 +539,10 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Global.CommonFlags = append(flags.Global.CommonFlags, "${config.ExternalCflags}") } - if tc.Bionic() { - if Bool(compiler.Properties.Rtti) { - flags.Local.CppFlags = append(flags.Local.CppFlags, "-frtti") - } else { - flags.Local.CppFlags = append(flags.Local.CppFlags, "-fno-rtti") - } + if Bool(compiler.Properties.Rtti) { + flags.Local.CppFlags = append(flags.Local.CppFlags, "-frtti") + } else { + flags.Local.CppFlags = append(flags.Local.CppFlags, "-fno-rtti") } flags.Global.AsFlags = append(flags.Global.AsFlags, "${config.CommonGlobalAsflags}") @@ -507,7 +551,10 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Global.YasmFlags = append(flags.Global.YasmFlags, tc.YasmFlags()) - flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.ToolchainCflags()) + // bpf targets don't need the target specific toolchain cflags. b/308826679 + if !proptools.Bool(compiler.Properties.Bpf_target) { + flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.ToolchainCflags()) + } cStd := parseCStd(compiler.Properties.C_std) cppStd := parseCppStd(compiler.Properties.Cpp_std) @@ -532,6 +579,9 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps if ctx.inVendorRamdisk() { flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Vendor_ramdisk.Cflags)...) } + if ctx.inRamdisk() { + flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Ramdisk.Cflags)...) + } if !ctx.useSdk() { flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Platform.Cflags)...) } @@ -561,7 +611,12 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps "-I"+android.PathForModuleGen(ctx, "yacc", ctx.ModuleDir()).String()) } - if compiler.hasSrcExt(".aidl") { + if len(compiler.Properties.Aidl.Libs) > 0 && + (len(compiler.Properties.Aidl.Include_dirs) > 0 || len(compiler.Properties.Aidl.Local_include_dirs) > 0) { + ctx.ModuleErrorf("aidl.libs and (aidl.include_dirs or aidl.local_include_dirs) can't be set at the same time. For aidl headers, please only use aidl.libs prop") + } + + if compiler.hasAidl(deps) { flags.aidlFlags = append(flags.aidlFlags, compiler.Properties.Aidl.Flags...) if len(compiler.Properties.Aidl.Local_include_dirs) > 0 { localAidlIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Aidl.Local_include_dirs) @@ -572,6 +627,14 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.aidlFlags = append(flags.aidlFlags, includeDirsToFlags(rootAidlIncludeDirs)) } + var rootAidlIncludeDirs android.Paths + for _, aidlLibraryInfo := range deps.AidlLibraryInfos { + rootAidlIncludeDirs = append(rootAidlIncludeDirs, aidlLibraryInfo.IncludeDirs.ToList()...) + } + if len(rootAidlIncludeDirs) > 0 { + flags.aidlFlags = append(flags.aidlFlags, includeDirsToFlags(rootAidlIncludeDirs)) + } + if proptools.BoolDefault(compiler.Properties.Aidl.Generate_traces, true) { flags.aidlFlags = append(flags.aidlFlags, "-t") } @@ -582,8 +645,14 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps } flags.aidlFlags = append(flags.aidlFlags, "--min_sdk_version="+aidlMinSdkVersion) - flags.Local.CommonFlags = append(flags.Local.CommonFlags, - "-I"+android.PathForModuleGen(ctx, "aidl").String()) + if compiler.hasSrcExt(".aidl") { + flags.Local.CommonFlags = append(flags.Local.CommonFlags, + "-I"+android.PathForModuleGen(ctx, "aidl").String()) + } + if len(deps.AidlLibraryInfos) > 0 { + flags.Local.CommonFlags = append(flags.Local.CommonFlags, + "-I"+android.PathForModuleGen(ctx, "aidl_library").String()) + } } if compiler.hasSrcExt(".rscript") || compiler.hasSrcExt(".fs") { @@ -612,12 +681,27 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Local.CFlags = append(flags.Local.CFlags, "-fopenmp") } + if ctx.optimizeForSize() { + flags.Local.CFlags = append(flags.Local.CFlags, "-Oz") + flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-enable-ml-inliner=release") + } + // Exclude directories from manual binder interface allowed list. //TODO(b/145621474): Move this check into IInterface.h when clang-tidy no longer uses absolute paths. if android.HasAnyPrefix(ctx.ModuleDir(), allowedManualInterfacePaths) { flags.Local.CFlags = append(flags.Local.CFlags, "-DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES") } + flags.NoOverrideFlags = append(flags.NoOverrideFlags, "${config.NoOverrideGlobalCflags}") + + if flags.Toolchain.Is64Bit() { + flags.NoOverrideFlags = append(flags.NoOverrideFlags, "${config.NoOverride64GlobalCflags}") + } + + if android.IsThirdPartyPath(ctx.ModuleDir()) { + flags.NoOverrideFlags = append(flags.NoOverrideFlags, "${config.NoOverrideExternalGlobalCflags}") + } + return flags } @@ -660,6 +744,10 @@ func ndkPathDeps(ctx ModuleContext) android.Paths { return nil } +func (compiler *baseCompiler) hasAidl(deps PathDeps) bool { + return len(deps.AidlLibraryInfos) > 0 || compiler.hasSrcExt(".aidl") +} + func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects { pathDeps := deps.GeneratedDeps pathDeps = append(pathDeps, ndkPathDeps(ctx)...) @@ -668,7 +756,7 @@ func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathD srcs := append(android.Paths(nil), compiler.srcsBeforeGen...) - srcs, genDeps, info := genSources(ctx, srcs, buildFlags) + srcs, genDeps, info := genSources(ctx, deps.AidlLibraryInfos, srcs, buildFlags) pathDeps = append(pathDeps, genDeps...) compiler.pathDeps = pathDeps @@ -680,7 +768,7 @@ func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathD // Compile files listed in c.Properties.Srcs into objects objs := compileObjs(ctx, buildFlags, "", srcs, - android.PathsForModuleSrc(ctx, compiler.Properties.Tidy_disabled_srcs), + append(android.PathsForModuleSrc(ctx, compiler.Properties.Tidy_disabled_srcs), compiler.generatedSources...), android.PathsForModuleSrc(ctx, compiler.Properties.Tidy_timeout_srcs), pathDeps, compiler.cFlagsDeps) @@ -716,7 +804,7 @@ type RustBindgenClangProperties struct { Header_libs []string `android:"arch_variant,variant_prepend"` // list of clang flags required to correctly interpret the headers. - Cflags []string `android:"arch_variant"` + Cflags proptools.Configurable[[]string] `android:"arch_variant"` // list of c++ specific clang flags required to correctly interpret the headers. // This is provided primarily to make sure cppflags defined in cc_defaults are pulled in. diff --git a/cc/config/Android.bp b/cc/config/Android.bp index fdc94ada8..289409fb3 100644 --- a/cc/config/Android.bp +++ b/cc/config/Android.bp @@ -15,7 +15,6 @@ bootstrap_go_package { "global.go", "tidy.go", "toolchain.go", - "vndk.go", "bionic.go", diff --git a/cc/config/OWNERS b/cc/config/OWNERS index 580f215c7..c78b6d582 100644 --- a/cc/config/OWNERS +++ b/cc/config/OWNERS @@ -1,3 +1,3 @@ per-file vndk.go = smoreland@google.com, victoryang@google.com -per-file clang.go,global.go,tidy.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com +per-file clang.go,global.go,tidy.go = appujee@google.com, pirama@google.com, srhines@google.com, yabinc@google.com, yikong@google.com, zijunzhao@google.com diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go index ca2e05fc3..beb68e19d 100644 --- a/cc/config/arm64_device.go +++ b/cc/config/arm64_device.go @@ -49,8 +49,8 @@ var ( } arm64Ldflags = []string{ - "-Wl,--hash-style=gnu", "-Wl,-z,separate-code", + "-Wl,-z,separate-loadable-segments", } arm64Lldflags = arm64Ldflags @@ -91,35 +91,39 @@ var ( ) func init() { - exportedVars.ExportStringListStaticVariable("Arm64Ldflags", arm64Ldflags) + pctx.StaticVariable("Arm64Ldflags", strings.Join(arm64Ldflags, " ")) - exportedVars.ExportStringList("Arm64Lldflags", arm64Lldflags) pctx.VariableFunc("Arm64Lldflags", func(ctx android.PackageVarContext) string { maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported() flags := append(arm64Lldflags, maxPageSizeFlag) return strings.Join(flags, " ") }) - exportedVars.ExportStringListStaticVariable("Arm64Cflags", arm64Cflags) - exportedVars.ExportStringListStaticVariable("Arm64Cppflags", arm64Cppflags) + pctx.VariableFunc("Arm64Cflags", func(ctx android.PackageVarContext) string { + flags := arm64Cflags + if ctx.Config().NoBionicPageSizeMacro() { + flags = append(flags, "-D__BIONIC_NO_PAGE_SIZE_MACRO") + } else { + flags = append(flags, "-D__BIONIC_DEPRECATED_PAGE_SIZE_MACRO") + } + return strings.Join(flags, " ") + }) - exportedVars.ExportVariableReferenceDict("Arm64ArchVariantCflags", arm64ArchVariantCflagsVar) - exportedVars.ExportVariableReferenceDict("Arm64CpuVariantCflags", arm64CpuVariantCflagsVar) - exportedVars.ExportVariableReferenceDict("Arm64CpuVariantLdflags", arm64CpuVariantLdflags) + pctx.StaticVariable("Arm64Cppflags", strings.Join(arm64Cppflags, " ")) - exportedVars.ExportStringListStaticVariable("Arm64Armv8ACflags", arm64ArchVariantCflags["armv8-a"]) - exportedVars.ExportStringListStaticVariable("Arm64Armv8ABranchProtCflags", arm64ArchVariantCflags["armv8-a-branchprot"]) - exportedVars.ExportStringListStaticVariable("Arm64Armv82ACflags", arm64ArchVariantCflags["armv8-2a"]) - exportedVars.ExportStringListStaticVariable("Arm64Armv82ADotprodCflags", arm64ArchVariantCflags["armv8-2a-dotprod"]) - exportedVars.ExportStringListStaticVariable("Arm64Armv9ACflags", arm64ArchVariantCflags["armv9-a"]) + pctx.StaticVariable("Arm64Armv8ACflags", strings.Join(arm64ArchVariantCflags["armv8-a"], " ")) + pctx.StaticVariable("Arm64Armv8ABranchProtCflags", strings.Join(arm64ArchVariantCflags["armv8-a-branchprot"], " ")) + pctx.StaticVariable("Arm64Armv82ACflags", strings.Join(arm64ArchVariantCflags["armv8-2a"], " ")) + pctx.StaticVariable("Arm64Armv82ADotprodCflags", strings.Join(arm64ArchVariantCflags["armv8-2a-dotprod"], " ")) + pctx.StaticVariable("Arm64Armv9ACflags", strings.Join(arm64ArchVariantCflags["armv9-a"], " ")) - exportedVars.ExportStringListStaticVariable("Arm64CortexA53Cflags", arm64CpuVariantCflags["cortex-a53"]) - exportedVars.ExportStringListStaticVariable("Arm64CortexA55Cflags", arm64CpuVariantCflags["cortex-a55"]) - exportedVars.ExportStringListStaticVariable("Arm64KryoCflags", arm64CpuVariantCflags["kryo"]) - exportedVars.ExportStringListStaticVariable("Arm64ExynosM1Cflags", arm64CpuVariantCflags["exynos-m1"]) - exportedVars.ExportStringListStaticVariable("Arm64ExynosM2Cflags", arm64CpuVariantCflags["exynos-m2"]) + pctx.StaticVariable("Arm64CortexA53Cflags", strings.Join(arm64CpuVariantCflags["cortex-a53"], " ")) + pctx.StaticVariable("Arm64CortexA55Cflags", strings.Join(arm64CpuVariantCflags["cortex-a55"], " ")) + pctx.StaticVariable("Arm64KryoCflags", strings.Join(arm64CpuVariantCflags["kryo"], " ")) + pctx.StaticVariable("Arm64ExynosM1Cflags", strings.Join(arm64CpuVariantCflags["exynos-m1"], " ")) + pctx.StaticVariable("Arm64ExynosM2Cflags", strings.Join(arm64CpuVariantCflags["exynos-m2"], " ")) - exportedVars.ExportStringListStaticVariable("Arm64FixCortexA53Ldflags", []string{"-Wl,--fix-cortex-a53-843419"}) + pctx.StaticVariable("Arm64FixCortexA53Ldflags", "-Wl,--fix-cortex-a53-843419") } var ( diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go index 9f5124bb4..438e0e6b6 100644 --- a/cc/config/arm64_linux_host.go +++ b/cc/config/arm64_linux_host.go @@ -42,10 +42,13 @@ var ( "-Wl,-z,now", "-Wl,--build-id=md5", "-Wl,--fatal-warnings", - "-Wl,--hash-style=gnu", "-Wl,--no-undefined-version", } + linuxCrossLldflags = append(linuxCrossLdflags, + "-Wl,--compress-debug-sections=zstd", + ) + // Embed the linker into host bionic binaries. This is needed to support host bionic, // as the linux kernel requires that the ELF interpreter referenced by PT_INTERP be // either an absolute path, or relative from CWD. To work around this, we extract @@ -58,8 +61,9 @@ var ( ) func init() { - exportedVars.ExportStringListStaticVariable("LinuxBionicArm64Cflags", linuxCrossCflags) - exportedVars.ExportStringListStaticVariable("LinuxBionicArm64Ldflags", linuxCrossLdflags) + pctx.StaticVariable("LinuxBionicArm64Cflags", strings.Join(linuxCrossCflags, " ")) + pctx.StaticVariable("LinuxBionicArm64Ldflags", strings.Join(linuxCrossLdflags, " ")) + pctx.StaticVariable("LinuxBionicArm64Lldflags", strings.Join(linuxCrossLldflags, " ")) } // toolchain config for ARM64 Linux CrossHost. Almost everything is the same as the ARM64 Android diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go index dec2b4552..3cb190966 100644 --- a/cc/config/arm_device.go +++ b/cc/config/arm_device.go @@ -28,13 +28,19 @@ var ( armCflags = []string{ "-fomit-frame-pointer", + // Revert this after b/322359235 is fixed + "-mllvm", "-enable-shrink-wrap=false", } - armCppflags = []string{} + armCppflags = []string{ + // Revert this after b/322359235 is fixed + "-mllvm", "-enable-shrink-wrap=false", + } armLdflags = []string{ - "-Wl,--hash-style=gnu", "-Wl,-m,armelf", + // Revert this after b/322359235 is fixed + "-Wl,-mllvm", "-Wl,-enable-shrink-wrap=false", } armLldflags = armLdflags @@ -43,9 +49,7 @@ var ( armNoFixCortexA8LdFlags = []string{"-Wl,--no-fix-cortex-a8"} - armArmCflags = []string{ - "-fstrict-aliasing", - } + armArmCflags = []string{} armThumbCflags = []string{ "-mthumb", @@ -181,48 +185,37 @@ const ( ) func init() { - // Just exported. Not created as a Ninja static variable. - exportedVars.ExportString("ArmClangTriple", clangTriple) + pctx.StaticVariable("ArmLdflags", strings.Join(armLdflags, " ")) + pctx.StaticVariable("ArmLldflags", strings.Join(armLldflags, " ")) - exportedVars.ExportStringListStaticVariable("ArmLdflags", armLdflags) - exportedVars.ExportStringList("ArmLldflags", armLldflags) - pctx.VariableFunc("ArmLldflags", func(ctx android.PackageVarContext) string { - maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported() - flags := append(armLldflags, maxPageSizeFlag) - return strings.Join(flags, " ") - }) - - exportedVars.ExportStringListStaticVariable("ArmFixCortexA8LdFlags", armFixCortexA8LdFlags) - exportedVars.ExportStringListStaticVariable("ArmNoFixCortexA8LdFlags", armNoFixCortexA8LdFlags) + pctx.StaticVariable("ArmFixCortexA8LdFlags", strings.Join(armFixCortexA8LdFlags, " ")) + pctx.StaticVariable("ArmNoFixCortexA8LdFlags", strings.Join(armNoFixCortexA8LdFlags, " ")) // Clang cflags - exportedVars.ExportStringListStaticVariable("ArmToolchainCflags", armToolchainCflags) - exportedVars.ExportStringListStaticVariable("ArmCflags", armCflags) - exportedVars.ExportStringListStaticVariable("ArmCppflags", armCppflags) + pctx.StaticVariable("ArmToolchainCflags", strings.Join(armToolchainCflags, " ")) + pctx.StaticVariable("ArmCflags", strings.Join(armCflags, " ")) + pctx.StaticVariable("ArmCppflags", strings.Join(armCppflags, " ")) // Clang ARM vs. Thumb instruction set cflags - exportedVars.ExportStringListStaticVariable("ArmArmCflags", armArmCflags) - exportedVars.ExportStringListStaticVariable("ArmThumbCflags", armThumbCflags) - - exportedVars.ExportVariableReferenceDict("ArmArchVariantCflags", armArchVariantCflagsVar) - exportedVars.ExportVariableReferenceDict("ArmCpuVariantCflags", armCpuVariantCflagsVar) + pctx.StaticVariable("ArmArmCflags", strings.Join(armArmCflags, " ")) + pctx.StaticVariable("ArmThumbCflags", strings.Join(armThumbCflags, " ")) // Clang arch variant cflags - exportedVars.ExportStringListStaticVariable("ArmArmv7ACflags", armArchVariantCflags["armv7-a"]) - exportedVars.ExportStringListStaticVariable("ArmArmv7ANeonCflags", armArchVariantCflags["armv7-a-neon"]) - exportedVars.ExportStringListStaticVariable("ArmArmv8ACflags", armArchVariantCflags["armv8-a"]) - exportedVars.ExportStringListStaticVariable("ArmArmv82ACflags", armArchVariantCflags["armv8-2a"]) + pctx.StaticVariable("ArmArmv7ACflags", strings.Join(armArchVariantCflags["armv7-a"], " ")) + pctx.StaticVariable("ArmArmv7ANeonCflags", strings.Join(armArchVariantCflags["armv7-a-neon"], " ")) + pctx.StaticVariable("ArmArmv8ACflags", strings.Join(armArchVariantCflags["armv8-a"], " ")) + pctx.StaticVariable("ArmArmv82ACflags", strings.Join(armArchVariantCflags["armv8-2a"], " ")) // Clang cpu variant cflags - exportedVars.ExportStringListStaticVariable("ArmGenericCflags", armCpuVariantCflags[""]) - exportedVars.ExportStringListStaticVariable("ArmCortexA7Cflags", armCpuVariantCflags["cortex-a7"]) - exportedVars.ExportStringListStaticVariable("ArmCortexA8Cflags", armCpuVariantCflags["cortex-a8"]) - exportedVars.ExportStringListStaticVariable("ArmCortexA15Cflags", armCpuVariantCflags["cortex-a15"]) - exportedVars.ExportStringListStaticVariable("ArmCortexA32Cflags", armCpuVariantCflags["cortex-a32"]) - exportedVars.ExportStringListStaticVariable("ArmCortexA53Cflags", armCpuVariantCflags["cortex-a53"]) - exportedVars.ExportStringListStaticVariable("ArmCortexA55Cflags", armCpuVariantCflags["cortex-a55"]) - exportedVars.ExportStringListStaticVariable("ArmKraitCflags", armCpuVariantCflags["krait"]) - exportedVars.ExportStringListStaticVariable("ArmKryoCflags", armCpuVariantCflags["kryo"]) + pctx.StaticVariable("ArmGenericCflags", strings.Join(armCpuVariantCflags[""], " ")) + pctx.StaticVariable("ArmCortexA7Cflags", strings.Join(armCpuVariantCflags["cortex-a7"], " ")) + pctx.StaticVariable("ArmCortexA8Cflags", strings.Join(armCpuVariantCflags["cortex-a8"], " ")) + pctx.StaticVariable("ArmCortexA15Cflags", strings.Join(armCpuVariantCflags["cortex-a15"], " ")) + pctx.StaticVariable("ArmCortexA32Cflags", strings.Join(armCpuVariantCflags["cortex-a32"], " ")) + pctx.StaticVariable("ArmCortexA53Cflags", strings.Join(armCpuVariantCflags["cortex-a53"], " ")) + pctx.StaticVariable("ArmCortexA55Cflags", strings.Join(armCpuVariantCflags["cortex-a55"], " ")) + pctx.StaticVariable("ArmKraitCflags", strings.Join(armCpuVariantCflags["krait"], " ")) + pctx.StaticVariable("ArmKryoCflags", strings.Join(armCpuVariantCflags["kryo"], " ")) } var ( diff --git a/cc/config/arm_linux_host.go b/cc/config/arm_linux_host.go index 525fb5d5d..e7c7bc466 100644 --- a/cc/config/arm_linux_host.go +++ b/cc/config/arm_linux_host.go @@ -14,7 +14,10 @@ package config -import "android/soong/android" +import ( + "android/soong/android" + "strings" +) var ( linuxArmCflags = []string{ @@ -27,19 +30,27 @@ var ( "-march=armv7a", } + linuxArmLldflags = append(linuxArmLdflags, + "-Wl,--compress-debug-sections=zstd", + ) + linuxArm64Ldflags = []string{} + + linuxArm64Lldflags = append(linuxArm64Ldflags, + "-Wl,--compress-debug-sections=zstd", + ) ) func init() { - exportedVars.ExportStringListStaticVariable("LinuxArmCflags", linuxArmCflags) - exportedVars.ExportStringListStaticVariable("LinuxArm64Cflags", linuxArm64Cflags) - exportedVars.ExportStringListStaticVariable("LinuxArmLdflags", linuxArmLdflags) - exportedVars.ExportStringListStaticVariable("LinuxArmLldflags", linuxArmLdflags) - exportedVars.ExportStringListStaticVariable("LinuxArm64Ldflags", linuxArm64Ldflags) - exportedVars.ExportStringListStaticVariable("LinuxArm64Lldflags", linuxArm64Ldflags) - - exportedVars.ExportStringListStaticVariable("LinuxArmYasmFlags", []string{"-f elf32 -m arm"}) - exportedVars.ExportStringListStaticVariable("LinuxArm64YasmFlags", []string{"-f elf64 -m aarch64"}) + pctx.StaticVariable("LinuxArmCflags", strings.Join(linuxArmCflags, " ")) + pctx.StaticVariable("LinuxArm64Cflags", strings.Join(linuxArm64Cflags, " ")) + pctx.StaticVariable("LinuxArmLdflags", strings.Join(linuxArmLdflags, " ")) + pctx.StaticVariable("LinuxArmLldflags", strings.Join(linuxArmLldflags, " ")) + pctx.StaticVariable("LinuxArm64Ldflags", strings.Join(linuxArm64Ldflags, " ")) + pctx.StaticVariable("LinuxArm64Lldflags", strings.Join(linuxArm64Lldflags, " ")) + + pctx.StaticVariable("LinuxArmYasmFlags", "-f elf32 -m arm") + pctx.StaticVariable("LinuxArm64YasmFlags", "-f elf64 -m aarch64") } diff --git a/cc/config/bionic.go b/cc/config/bionic.go index a1e3851dc..ed724f5af 100644 --- a/cc/config/bionic.go +++ b/cc/config/bionic.go @@ -24,6 +24,7 @@ var ( bionicCrtBeginStaticBinary, bionicCrtEndStaticBinary = []string{"crtbegin_static"}, []string{"crtend_android"} bionicCrtBeginSharedBinary, bionicCrtEndSharedBinary = []string{"crtbegin_dynamic"}, []string{"crtend_android"} bionicCrtBeginSharedLibrary, bionicCrtEndSharedLibrary = []string{"crtbegin_so"}, []string{"crtend_so"} + bionicCrtPadSegmentSharedLibrary = []string{"crt_pad_segment"} ) func (toolchainBionic) Bionic() bool { return true } @@ -36,9 +37,10 @@ func (toolchainBionic) ExecutableSuffix() string { return "" } func (toolchainBionic) AvailableLibraries() []string { return nil } -func (toolchainBionic) CrtBeginStaticBinary() []string { return bionicCrtBeginStaticBinary } -func (toolchainBionic) CrtBeginSharedBinary() []string { return bionicCrtBeginSharedBinary } -func (toolchainBionic) CrtBeginSharedLibrary() []string { return bionicCrtBeginSharedLibrary } -func (toolchainBionic) CrtEndStaticBinary() []string { return bionicCrtEndStaticBinary } -func (toolchainBionic) CrtEndSharedBinary() []string { return bionicCrtEndSharedBinary } -func (toolchainBionic) CrtEndSharedLibrary() []string { return bionicCrtEndSharedLibrary } +func (toolchainBionic) CrtBeginStaticBinary() []string { return bionicCrtBeginStaticBinary } +func (toolchainBionic) CrtBeginSharedBinary() []string { return bionicCrtBeginSharedBinary } +func (toolchainBionic) CrtBeginSharedLibrary() []string { return bionicCrtBeginSharedLibrary } +func (toolchainBionic) CrtEndStaticBinary() []string { return bionicCrtEndStaticBinary } +func (toolchainBionic) CrtEndSharedBinary() []string { return bionicCrtEndSharedBinary } +func (toolchainBionic) CrtEndSharedLibrary() []string { return bionicCrtEndSharedLibrary } +func (toolchainBionic) CrtPadSegmentSharedLibrary() []string { return bionicCrtPadSegmentSharedLibrary } diff --git a/cc/config/darwin_host.go b/cc/config/darwin_host.go index 2cabdc8ac..485666954 100644 --- a/cc/config/darwin_host.go +++ b/cc/config/darwin_host.go @@ -29,11 +29,6 @@ var ( "-fPIC", "-funwind-tables", - // Workaround differences in inttypes.h between host and target. - //See bug 12708004. - "-D__STDC_FORMAT_MACROS", - "-D__STDC_CONSTANT_MACROS", - "-isysroot ${macSdkRoot}", "-mmacosx-version-min=${macMinVersion}", "-DMACOSX_DEPLOYMENT_TARGET=${macMinVersion}", @@ -55,6 +50,8 @@ var ( darwinSupportedSdkVersions = []string{ "11", "12", + "13", + "14", } darwinAvailableLibraries = append( @@ -79,7 +76,7 @@ func init() { pctx.VariableFunc("macSdkRoot", func(ctx android.PackageVarContext) string { return getMacTools(ctx).sdkRoot }) - pctx.StaticVariable("macMinVersion", "10.13") + pctx.StaticVariable("macMinVersion", "10.14") pctx.VariableFunc("MacArPath", func(ctx android.PackageVarContext) string { return getMacTools(ctx).arPath }) diff --git a/cc/config/global.go b/cc/config/global.go index a0fe4b7a0..62a4765f4 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -16,6 +16,7 @@ package config import ( "runtime" + "slices" "strings" "android/soong/android" @@ -23,94 +24,134 @@ import ( ) var ( - pctx = android.NewPackageContext("android/soong/cc/config") - exportedVars = android.NewExportedVariables(pctx) + pctx = android.NewPackageContext("android/soong/cc/config") // Flags used by lots of devices. Putting them in package static variables // will save bytes in build.ninja so they aren't repeated for every file commonGlobalCflags = []string{ - "-DANDROID", - "-fmessage-length=0", - "-W", + // Enable some optimization by default. + "-O2", + + // Warnings enabled by default. Reference: + // https://clang.llvm.org/docs/DiagnosticsReference.html "-Wall", - "-Wno-unused", + "-Wextra", "-Winit-self", "-Wpointer-arith", - "-Wunreachable-code-loop-increment", - - // Make paths in deps files relative - "-no-canonical-prefixes", - - "-DNDEBUG", - "-UDEBUG", - - "-fno-exceptions", - "-Wno-multichar", - - "-O2", - "-g", - "-fdebug-default-version=5", + "-Wunguarded-availability", - "-fno-strict-aliasing", + // Warnings treated as errors by default. + // See also noOverrideGlobalCflags for errors that cannot be disabled + // from Android.bp files. + // Using __DATE__/__TIME__ causes build nondeterminism. "-Werror=date-time", + // Detects forgotten */& that usually cause a crash + "-Werror=int-conversion", + // Detects unterminated alignment modification pragmas, which often lead + // to ABI mismatch between modules and hard-to-debug crashes. "-Werror=pragma-pack", + // Same as above, but detects alignment pragmas around a header + // inclusion. "-Werror=pragma-pack-suspicious-include", + // Detects dividing an array size by itself, which is a common typo that + // leads to bugs. + "-Werror=sizeof-array-div", + // Detects a typo that cuts off a prefix from a string literal. "-Werror=string-plus-int", + // Detects for loops that will never execute more than once (for example + // due to unconditional break), but have a non-empty loop increment + // clause. Often a mistake/bug. "-Werror=unreachable-code-loop-increment", - // Force deprecation warnings to be warnings for code that compiles with -Werror. - // Making deprecated usages an error causes extreme pain when trying to deprecate anything. + // Warnings that should not be errors even for modules with -Werror. + + // Making deprecated usages an error causes extreme pain when trying to + // deprecate anything. "-Wno-error=deprecated-declarations", + // Warnings disabled by default. + + // Designated initializer syntax is recommended by the Google C++ style + // and is OK to use even if not formally supported by the chosen C++ + // version. + "-Wno-c99-designator", + // Detects uses of a GNU C extension equivalent to a limited form of + // constexpr. Enabling this would require replacing many constants with + // macros, which is not a good trade-off. + "-Wno-gnu-folding-constant", + // AIDL generated code redeclares pure virtual methods in each + // subsequent version of an interface, so this warning is currently + // infeasible to enable. + "-Wno-inconsistent-missing-override", + // Detects designated initializers that are in a different order than + // the fields in the initialized type, which causes the side effects + // of initializers to occur out of order with the source code. + // In practice, this warning has extremely poor signal to noise ratio, + // because it is triggered even for initializers with no side effects. + // Individual modules can still opt into it via cflags. + "-Wno-error=reorder-init-list", + "-Wno-reorder-init-list", + // Incompatible with the Google C++ style guidance to use 'int' for loop + // indices; poor signal to noise ratio. + "-Wno-sign-compare", + // Poor signal to noise ratio. + "-Wno-unused", + + // Global preprocessor constants. + + "-DANDROID", + "-DNDEBUG", + "-UDEBUG", "-D__compiler_offsetof=__builtin_offsetof", + // Allows the bionic versioning.h to indirectly determine whether the + // option -Wunguarded-availability is on or not. + "-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__", + + // -f and -g options. // Emit address-significance table which allows linker to perform safe ICF. Clang does // not emit the table by default on Android since NDK still uses GNU binutils. "-faddrsig", - // Turn on -fcommon explicitly, since Clang now defaults to -fno-common. The cleanup bug - // tracking this is http://b/151457797. - "-fcommon", - - // Help catch common 32/64-bit errors. - "-Werror=int-conversion", - - // Disable overly aggressive warning for macros defined with a leading underscore - // This happens in AndroidConfig.h, which is included nearly everywhere. - // TODO: can we remove this now? - "-Wno-reserved-id-macro", + // Emit debugging data in a modern format (DWARF v5). + "-fdebug-default-version=5", // Force clang to always output color diagnostics. Ninja will strip the ANSI // color codes if it is not running in a terminal. "-fcolor-diagnostics", - // Warnings from clang-7.0 - "-Wno-sign-compare", + // Turn off FMA which got enabled by default in clang-r445002 (http://b/218805949) + "-ffp-contract=off", - // Disable -Winconsistent-missing-override until we can clean up the existing - // codebase for it. - "-Wno-inconsistent-missing-override", + // Google C++ style does not allow exceptions, turn them off by default. + "-fno-exceptions", - // Warnings from clang-10 - // Nested and array designated initialization is nice to have. - "-Wno-c99-designator", + // Disable optimizations based on strict aliasing by default. + // The performance benefit of enabling them currently does not outweigh + // the risk of hard-to-reproduce bugs. + "-fno-strict-aliasing", - // Many old files still have GNU designator syntax. - "-Wno-gnu-designator", + // Disable line wrapping for error messages - it interferes with + // displaying logs in web browsers. + "-fmessage-length=0", - // Warnings from clang-12 - "-Wno-gnu-folding-constant", + // Disable C++17 "relaxed template template argument matching" as a workaround for + // our out-dated libcxx. + // http://b/341084395 + "-fno-relaxed-template-template-args", - // Calls to the APIs that are newer than the min sdk version of the caller should be - // guarded with __builtin_available. - "-Wunguarded-availability", - // This macro allows the bionic versioning.h to indirectly determine whether the - // option -Wunguarded-availability is on or not. - "-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__", + // Using simple template names reduces the size of debug builds. + "-gsimple-template-names", - // Turn off FMA which got enabled by default in clang-r445002 (http://b/218805949) - "-ffp-contract=off", + // Use zstd to compress debug data. + "-gz=zstd", + + // Make paths in deps files relative. + "-no-canonical-prefixes", + + // http://b/315250603 temporarily disabled + "-Wno-error=format", } commonGlobalConlyflags = []string{} @@ -122,6 +163,7 @@ var ( "-fdebug-default-version=4", } + // Compilation flags for device code; not applied to host code. deviceGlobalCflags = []string{ "-ffunction-sections", "-fdata-sections", @@ -147,12 +189,14 @@ var ( commonGlobalLldflags = []string{ "-fuse-ld=lld", "-Wl,--icf=safe", + "-Wl,--no-demangle", } deviceGlobalCppflags = []string{ "-fvisibility-inlines-hidden", } + // Linking flags for device code; not applied to host binaries. deviceGlobalLdflags = []string{ "-Wl,-z,noexecstack", "-Wl,-z,relro", @@ -168,7 +212,9 @@ var ( "-Wl,--exclude-libs,libunwind.a", } - deviceGlobalLldflags = append(deviceGlobalLdflags, commonGlobalLldflags...) + deviceGlobalLldflags = append(append(deviceGlobalLdflags, commonGlobalLldflags...), + "-Wl,--compress-debug-sections=zstd", + ) hostGlobalCflags = []string{} @@ -179,8 +225,6 @@ var ( hostGlobalLldflags = commonGlobalLldflags commonGlobalCppflags = []string{ - "-Wsign-promo", - // -Wimplicit-fallthrough is not enabled by -Wall. "-Wimplicit-fallthrough", @@ -191,6 +235,16 @@ var ( "-Wno-gnu-include-next", } + // These flags are appended after the module's cflags, so they cannot be + // overridden from Android.bp files. + // + // NOTE: if you need to disable a warning to unblock a compiler upgrade + // and it is only triggered by third party code, add it to + // extraExternalCflags (if possible) or noOverrideExternalGlobalCflags + // (if the former doesn't work). If the new warning also occurs in first + // party code, try adding it to commonGlobalCflags first. Adding it here + // should be the last resort, because it prevents all code in Android from + // opting into the warning. noOverrideGlobalCflags = []string{ "-Werror=bool-operation", "-Werror=format-insufficient-args", @@ -206,8 +260,15 @@ var ( // http://b/161386391 for -Wno-pointer-to-int-cast "-Wno-pointer-to-int-cast", "-Werror=fortify-source", + // http://b/315246135 temporarily disabled + "-Wno-unused-variable", + // Disabled because it produces many false positives. http://b/323050926 + "-Wno-missing-field-initializers", + // http://b/323050889 + "-Wno-packed-non-pod", "-Werror=address-of-temporary", + "-Werror=incompatible-function-pointer-types", "-Werror=null-dereference", "-Werror=return-type", @@ -215,8 +276,6 @@ var ( // new warnings are fixed. "-Wno-tautological-constant-compare", "-Wno-tautological-type-limit-compare", - // http://b/145210666 - "-Wno-reorder-init-list", // http://b/145211066 "-Wno-implicit-int-float-conversion", // New warnings to be fixed after clang-r377782. @@ -226,7 +285,8 @@ var ( "-Wno-range-loop-construct", // http://b/153747076 "-Wno-zero-as-null-pointer-constant", // http://b/68236239 "-Wno-deprecated-anon-enum-enum-conversion", // http://b/153746485 - "-Wno-pessimizing-move", // http://b/154270751 + "-Wno-deprecated-enum-enum-conversion", + "-Wno-pessimizing-move", // http://b/154270751 // New warnings to be fixed after clang-r399163 "-Wno-non-c-typedef-for-linkage", // http://b/161304145 // New warnings to be fixed after clang-r428724 @@ -240,26 +300,26 @@ var ( // New warnings to be fixed after clang-r475365 "-Wno-error=single-bit-bitfield-constant-conversion", // http://b/243965903 "-Wno-error=enum-constexpr-conversion", // http://b/243964282 + // New warnings to be fixed after clang-r522817 + "-Wno-error=invalid-offsetof", + "-Wno-error=thread-safety-reference-return", + + // Irrelevant on Android because _we_ don't use exceptions, but causes + // lots of build noise because libcxx/libcxxabi do. This can probably + // go away when we're on a new enough libc++, but has to be global + // until then because it causes warnings in the _callers_, not the + // project itself. + "-Wno-deprecated-dynamic-exception-spec", + + // Allow using VLA CXX extension. + "-Wno-vla-cxx-extension", } noOverride64GlobalCflags = []string{} - noOverrideExternalGlobalCflags = []string{ - // http://b/191699019 - "-Wno-format-insufficient-args", - "-Wno-sizeof-array-div", - "-Wno-incompatible-function-pointer-types", - "-Wno-unused-but-set-variable", - "-Wno-unused-but-set-parameter", - "-Wno-unqualified-std-cast-call", - "-Wno-bitwise-instead-of-logical", - "-Wno-misleading-indentation", - "-Wno-array-parameter", - "-Wno-gnu-offsetof-extensions", - } - - // Extra cflags for external third-party projects to disable warnings that - // are infeasible to fix in all the external projects and their upstream repos. + // Extra cflags applied to third-party code (anything for which + // IsThirdPartyPath() in build/soong/android/paths.go returns true; + // includes external/, most of vendor/ and most of hardware/) extraExternalCflags = []string{ "-Wno-enum-compare", "-Wno-enum-compare-switch", @@ -287,26 +347,58 @@ var ( // http://b/239661264 "-Wno-deprecated-non-prototype", + + "-Wno-unused", + "-Wno-deprecated", + } + + // Similar to noOverrideGlobalCflags, but applies only to third-party code + // (see extraExternalCflags). + // This section can unblock compiler upgrades when a third party module that + // enables -Werror and some group of warnings explicitly triggers newly + // added warnings. + noOverrideExternalGlobalCflags = []string{ + // http://b/151457797 + "-fcommon", + // http://b/191699019 + "-Wno-format-insufficient-args", + // http://b/296321508 + // Introduced in response to a critical security vulnerability and + // should be a hard error - it requires only whitespace changes to fix. + "-Wno-misleading-indentation", + // Triggered by old LLVM code in external/llvm. Likely not worth + // enabling since it's a cosmetic issue. + "-Wno-bitwise-instead-of-logical", + + "-Wno-unused", + "-Wno-unused-parameter", + "-Wno-unused-but-set-parameter", + "-Wno-unqualified-std-cast-call", + "-Wno-array-parameter", + "-Wno-gnu-offsetof-extensions", + // TODO: Enable this warning http://b/315245071 + "-Wno-fortify-source", } llvmNextExtraCommonGlobalCflags = []string{ // Do not report warnings when testing with the top of trunk LLVM. - "-Wno-error", + "-Wno-everything", } + // Flags that must not appear in any command line. IllegalFlags = []string{ "-w", } - CStdVersion = "gnu11" - CppStdVersion = "gnu++17" - ExperimentalCStdVersion = "gnu17" - ExperimentalCppStdVersion = "gnu++2a" + CStdVersion = "gnu17" + CppStdVersion = "gnu++20" + ExperimentalCStdVersion = "gnu2x" + ExperimentalCppStdVersion = "gnu++2b" // prebuilts/clang default settings. ClangDefaultBase = "prebuilts/clang/host" - ClangDefaultVersion = "clang-r487747c" - ClangDefaultShortVersion = "17" + ClangDefaultVersion = "clang-r522817" + ClangDefaultShortVersion = "18" // Directories with warnings from Android.bp files. WarningAllowedProjects = []string{ @@ -320,48 +412,35 @@ var ( VisibilityDefaultFlag = "-fvisibility=default" ) -// BazelCcToolchainVars generates bzl file content containing variables for -// Bazel's cc_toolchain configuration. -func BazelCcToolchainVars(config android.Config) string { - return android.BazelToolchainVars(config, exportedVars) -} - -func ExportStringList(name string, value []string) { - exportedVars.ExportStringList(name, value) -} - func init() { if runtime.GOOS == "linux" { commonGlobalCflags = append(commonGlobalCflags, "-fdebug-prefix-map=/proc/self/cwd=") } - exportedVars.ExportStringListStaticVariable("CommonGlobalConlyflags", commonGlobalConlyflags) - exportedVars.ExportStringListStaticVariable("CommonGlobalAsflags", commonGlobalAsflags) - exportedVars.ExportStringListStaticVariable("DeviceGlobalCppflags", deviceGlobalCppflags) - exportedVars.ExportStringListStaticVariable("DeviceGlobalLdflags", deviceGlobalLdflags) - exportedVars.ExportStringListStaticVariable("DeviceGlobalLldflags", deviceGlobalLldflags) - exportedVars.ExportStringListStaticVariable("HostGlobalCppflags", hostGlobalCppflags) - exportedVars.ExportStringListStaticVariable("HostGlobalLdflags", hostGlobalLdflags) - exportedVars.ExportStringListStaticVariable("HostGlobalLldflags", hostGlobalLldflags) - - // Export the static default CommonGlobalCflags to Bazel. - exportedVars.ExportStringList("CommonGlobalCflags", commonGlobalCflags) + pctx.StaticVariable("CommonGlobalConlyflags", strings.Join(commonGlobalConlyflags, " ")) + pctx.StaticVariable("CommonGlobalAsflags", strings.Join(commonGlobalAsflags, " ")) + pctx.StaticVariable("DeviceGlobalCppflags", strings.Join(deviceGlobalCppflags, " ")) + pctx.StaticVariable("DeviceGlobalLdflags", strings.Join(deviceGlobalLdflags, " ")) + pctx.StaticVariable("DeviceGlobalLldflags", strings.Join(deviceGlobalLldflags, " ")) + pctx.StaticVariable("HostGlobalCppflags", strings.Join(hostGlobalCppflags, " ")) + pctx.StaticVariable("HostGlobalLdflags", strings.Join(hostGlobalLdflags, " ")) + pctx.StaticVariable("HostGlobalLldflags", strings.Join(hostGlobalLldflags, " ")) pctx.VariableFunc("CommonGlobalCflags", func(ctx android.PackageVarContext) string { - flags := commonGlobalCflags + flags := slices.Clone(commonGlobalCflags) // http://b/131390872 // Automatically initialize any uninitialized stack variables. // Prefer zero-init if multiple options are set. if ctx.Config().IsEnvTrue("AUTO_ZERO_INITIALIZE") { - flags = append(flags, "-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang -Wno-unused-command-line-argument") + flags = append(flags, "-ftrivial-auto-var-init=zero") } else if ctx.Config().IsEnvTrue("AUTO_PATTERN_INITIALIZE") { flags = append(flags, "-ftrivial-auto-var-init=pattern") } else if ctx.Config().IsEnvTrue("AUTO_UNINITIALIZE") { flags = append(flags, "-ftrivial-auto-var-init=uninitialized") } else { // Default to zero initialization. - flags = append(flags, "-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang -Wno-unused-command-line-argument") + flags = append(flags, "-ftrivial-auto-var-init=zero") } // Workaround for ccache with clang. @@ -374,42 +453,42 @@ func init() { flags = append(flags, "-Wno-error=unknown-warning-option") } + switch ctx.Config().Getenv("CLANG_DEFAULT_DEBUG_LEVEL") { + case "debug_level_0": + flags = append(flags, "-g0") + case "debug_level_1": + flags = append(flags, "-g1") + case "debug_level_2": + flags = append(flags, "-g2") + case "debug_level_3": + flags = append(flags, "-g3") + case "debug_level_g": + flags = append(flags, "-g") + default: + flags = append(flags, "-g") + } + return strings.Join(flags, " ") }) - // Export the static default DeviceGlobalCflags to Bazel. - // TODO(187086342): handle cflags that are set in VariableFuncs. - exportedVars.ExportStringList("DeviceGlobalCflags", deviceGlobalCflags) - pctx.VariableFunc("DeviceGlobalCflags", func(ctx android.PackageVarContext) string { return strings.Join(deviceGlobalCflags, " ") }) - // Export the static default NoOverrideGlobalCflags to Bazel. - exportedVars.ExportStringList("NoOverrideGlobalCflags", noOverrideGlobalCflags) pctx.VariableFunc("NoOverrideGlobalCflags", func(ctx android.PackageVarContext) string { flags := noOverrideGlobalCflags if ctx.Config().IsEnvTrue("LLVM_NEXT") { flags = append(noOverrideGlobalCflags, llvmNextExtraCommonGlobalCflags...) + IllegalFlags = []string{} // Don't fail build while testing a new compiler. } return strings.Join(flags, " ") }) - exportedVars.ExportStringListStaticVariable("NoOverride64GlobalCflags", noOverride64GlobalCflags) - exportedVars.ExportStringListStaticVariable("HostGlobalCflags", hostGlobalCflags) - exportedVars.ExportStringListStaticVariable("NoOverrideExternalGlobalCflags", noOverrideExternalGlobalCflags) - exportedVars.ExportStringListStaticVariable("CommonGlobalCppflags", commonGlobalCppflags) - exportedVars.ExportStringListStaticVariable("ExternalCflags", extraExternalCflags) - - exportedVars.ExportString("CStdVersion", CStdVersion) - exportedVars.ExportString("CppStdVersion", CppStdVersion) - exportedVars.ExportString("ExperimentalCStdVersion", ExperimentalCStdVersion) - exportedVars.ExportString("ExperimentalCppStdVersion", ExperimentalCppStdVersion) - - exportedVars.ExportString("VersionScriptFlagPrefix", VersionScriptFlagPrefix) - - exportedVars.ExportString("VisibilityHiddenFlag", VisibilityHiddenFlag) - exportedVars.ExportString("VisibilityDefaultFlag", VisibilityDefaultFlag) + pctx.StaticVariable("NoOverride64GlobalCflags", strings.Join(noOverride64GlobalCflags, " ")) + pctx.StaticVariable("HostGlobalCflags", strings.Join(hostGlobalCflags, " ")) + pctx.StaticVariable("NoOverrideExternalGlobalCflags", strings.Join(noOverrideExternalGlobalCflags, " ")) + pctx.StaticVariable("CommonGlobalCppflags", strings.Join(commonGlobalCppflags, " ")) + pctx.StaticVariable("ExternalCflags", strings.Join(extraExternalCflags, " ")) // Everything in these lists is a crime against abstraction and dependency tracking. // Do not add anything to this list. @@ -424,17 +503,21 @@ func init() { "frameworks/native/opengl/include", "frameworks/av/include", } - exportedVars.ExportStringList("CommonGlobalIncludes", commonGlobalIncludes) pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I", commonGlobalIncludes) + pctx.StaticVariable("CLANG_DEFAULT_VERSION", ClangDefaultVersion) + pctx.StaticVariable("CLANG_DEFAULT_SHORT_VERSION", ClangDefaultShortVersion) + pctx.StaticVariableWithEnvOverride("ClangBase", "LLVM_PREBUILTS_BASE", ClangDefaultBase) - exportedVars.ExportStringStaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion) + pctx.StaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion) pctx.StaticVariable("ClangPath", "${ClangBase}/${HostPrebuiltTag}/${ClangVersion}") pctx.StaticVariable("ClangBin", "${ClangPath}/bin") - exportedVars.ExportStringStaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion) + pctx.StaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion) pctx.StaticVariable("ClangAsanLibDir", "${ClangBase}/linux-x86/${ClangVersion}/lib/clang/${ClangShortVersion}/lib/linux") + pctx.StaticVariable("WarningAllowedProjects", strings.Join(WarningAllowedProjects, " ")) + // These are tied to the version of LLVM directly in external/llvm, so they might trail the host prebuilts // being used for the rest of the build process. pctx.SourcePathVariable("RSClangBase", "prebuilts/clang/host") @@ -443,11 +526,11 @@ func init() { pctx.StaticVariable("RSLLVMPrebuiltsPath", "${RSClangBase}/${HostPrebuiltTag}/${RSClangVersion}/bin") pctx.StaticVariable("RSIncludePath", "${RSLLVMPrebuiltsPath}/../lib64/clang/${RSReleaseVersion}/include") - pctx.PrefixedExistentPathsForSourcesVariable("RsGlobalIncludes", "-I", - []string{ - "external/clang/lib/Headers", - "frameworks/rs/script_api/include", - }) + rsGlobalIncludes := []string{ + "external/clang/lib/Headers", + "frameworks/rs/script_api/include", + } + pctx.PrefixedExistentPathsForSourcesVariable("RsGlobalIncludes", "-I", rsGlobalIncludes) pctx.VariableFunc("CcWrapper", func(ctx android.PackageVarContext) string { if override := ctx.Config().Getenv("CC_WRAPPER"); override != "" { @@ -465,7 +548,7 @@ func init() { pctx.StaticVariableWithEnvOverride("REAbiLinkerExecStrategy", "RBE_ABI_LINKER_EXEC_STRATEGY", remoteexec.LocalExecStrategy) } -var HostPrebuiltTag = exportedVars.ExportVariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS) +var HostPrebuiltTag = pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS) func ClangPath(ctx android.PathContext, file string) android.SourcePath { type clangToolKey string diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go index a63d5c237..6a5293f4c 100644 --- a/cc/config/riscv64_device.go +++ b/cc/config/riscv64_device.go @@ -23,23 +23,30 @@ import ( var ( riscv64Cflags = []string{ - // Help catch common 32/64-bit errors. + // Help catch common 32/64-bit errors. (This is duplicated in all 64-bit + // architectures' cflags.) "-Werror=implicit-function-declaration", - "-fno-emulated-tls", - // A temporary fix for SExtWRemoval miscompilation bug. - "-mllvm", - "-riscv-disable-sextw-removal=true", + // This is already the driver's Android default, but duplicated here (and + // below) for ease of experimentation with additional extensions. + "-march=rv64gcv_zba_zbb_zbs", + // TODO: remove when qemu V works (https://gitlab.com/qemu-project/qemu/-/issues/1976) + // (Note that we'll probably want to wait for berberis to be good enough + // that most people don't care about qemu's V performance either!) + "-mno-implicit-float", } riscv64ArchVariantCflags = map[string][]string{} riscv64Ldflags = []string{ - "-Wl,--hash-style=gnu", + // This is already the driver's Android default, but duplicated here (and + // above) for ease of experimentation with additional extensions. + "-march=rv64gcv_zba_zbb_zbs", + // TODO: remove when clang default changed (https://github.com/google/android-riscv64/issues/124) + "-Wl,-mllvm -Wl,-jump-is-expensive=false", } riscv64Lldflags = append(riscv64Ldflags, "-Wl,-z,max-page-size=4096", - "-Wl,-plugin-opt,-emulated-tls=0", ) riscv64Cppflags = []string{} @@ -51,15 +58,11 @@ const () func init() { - exportedVars.ExportStringListStaticVariable("Riscv64Ldflags", riscv64Ldflags) - exportedVars.ExportStringListStaticVariable("Riscv64Lldflags", riscv64Lldflags) + pctx.StaticVariable("Riscv64Ldflags", strings.Join(riscv64Ldflags, " ")) + pctx.StaticVariable("Riscv64Lldflags", strings.Join(riscv64Lldflags, " ")) - exportedVars.ExportStringListStaticVariable("Riscv64Cflags", riscv64Cflags) - exportedVars.ExportStringListStaticVariable("Riscv64Cppflags", riscv64Cppflags) - - exportedVars.ExportVariableReferenceDict("Riscv64ArchVariantCflags", riscv64ArchVariantCflagsVar) - exportedVars.ExportVariableReferenceDict("Riscv64CpuVariantCflags", riscv64CpuVariantCflagsVar) - exportedVars.ExportVariableReferenceDict("Riscv64CpuVariantLdflags", riscv64CpuVariantLdflags) + pctx.StaticVariable("Riscv64Cflags", strings.Join(riscv64Cflags, " ")) + pctx.StaticVariable("Riscv64Cppflags", strings.Join(riscv64Cppflags, " ")) } var ( diff --git a/cc/config/tidy.go b/cc/config/tidy.go index d55a13dcf..46d5d909e 100644 --- a/cc/config/tidy.go +++ b/cc/config/tidy.go @@ -16,7 +16,6 @@ package config import ( "android/soong/android" - "regexp" "strings" ) @@ -42,6 +41,8 @@ var ( "-bugprone-unchecked-optional-access", // http://b/265438407 "-misc-use-anonymous-namespace", + // http://b/285005947 + "-performance-avoid-endl", } // Some clang-tidy checks are included in some tidy_checks_as_errors lists, @@ -56,6 +57,14 @@ var ( "-bugprone-signed-char-misuse", // http://b/241819232 "-misc-const-correctness", + // http://b/285356805 + "-bugprone-unsafe-functions", + "-cert-msc24-c", + "-cert-msc33-c", + // http://b/285356799 + "-modernize-type-traits", + // http://b/285361108 + "-readability-avoid-unconditional-preprocessor-if", } extraArgFlags = []string{ @@ -78,7 +87,7 @@ func init() { // The global default tidy checks should include clang-tidy // default checks and tested groups, but exclude known noisy checks. // See https://clang.llvm.org/extra/clang-tidy/checks/list.html - exportedVars.ExportVariableConfigMethod("TidyDefaultGlobalChecks", func(config android.Config) string { + pctx.VariableConfigMethod("TidyDefaultGlobalChecks", func(config android.Config) string { if override := config.Getenv("DEFAULT_GLOBAL_TIDY_CHECKS"); override != "" { return override } @@ -140,7 +149,7 @@ func init() { // There are too many clang-tidy warnings in external and vendor projects, so we only // enable some google checks for these projects. Users can add more checks locally with the // "tidy_checks" list in .bp files, or the "Checks" list in .clang-tidy config files. - exportedVars.ExportVariableConfigMethod("TidyExternalVendorChecks", func(config android.Config) string { + pctx.VariableConfigMethod("TidyExternalVendorChecks", func(config android.Config) string { if override := config.Getenv("DEFAULT_EXTERNAL_VENDOR_TIDY_CHECKS"); override != "" { return override } @@ -154,25 +163,21 @@ func init() { }, ",") }) - exportedVars.ExportVariableFuncVariable("TidyGlobalNoChecks", func() string { - return strings.Join(globalNoCheckList, ",") - }) + pctx.StaticVariable("TidyGlobalNoChecks", strings.Join(globalNoCheckList, ",")) - exportedVars.ExportVariableFuncVariable("TidyGlobalNoErrorChecks", func() string { - return strings.Join(globalNoErrorCheckList, ",") - }) + pctx.StaticVariable("TidyGlobalNoErrorChecks", strings.Join(globalNoErrorCheckList, ",")) - exportedVars.ExportStringListStaticVariable("TidyExtraArgFlags", extraArgFlags) + pctx.StaticVariable("TidyExtraArgFlags", strings.Join(extraArgFlags, " ")) // To reduce duplicate warnings from the same header files, // header-filter will contain only the module directory and // those specified by DEFAULT_TIDY_HEADER_DIRS. - exportedVars.ExportVariableConfigMethod("TidyDefaultHeaderDirs", func(config android.Config) string { + pctx.VariableConfigMethod("TidyDefaultHeaderDirs", func(config android.Config) string { return config.Getenv("DEFAULT_TIDY_HEADER_DIRS") }) // Use WTIH_TIDY_FLAGS to pass extra global default clang-tidy flags. - exportedVars.ExportVariableConfigMethod("TidyWithTidyFlags", func(config android.Config) string { + pctx.VariableConfigMethod("TidyWithTidyFlags", func(config android.Config) string { return config.Getenv("WITH_TIDY_FLAGS") }) } @@ -271,11 +276,3 @@ func TidyFlagsForSrcFile(srcFile android.Path, flags string) string { } return flags } - -var ( - removedCFlags = regexp.MustCompile(" -fsanitize=[^ ]*memtag-[^ ]* ") -) - -func TidyReduceCFlags(flags string) string { - return removedCFlags.ReplaceAllString(flags, " ") -} diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go index 6a10e1474..5d8c351ab 100644 --- a/cc/config/toolchain.go +++ b/cc/config/toolchain.go @@ -16,10 +16,17 @@ package config import ( "fmt" + "strings" "android/soong/android" ) +func init() { + pctx.StaticVariable("DarwinAvailableLibraries", strings.Join(darwinAvailableLibraries, " ")) + pctx.StaticVariable("LinuxAvailableLibraries", strings.Join(linuxAvailableLibraries, " ")) + pctx.StaticVariable("WindowsAvailableLibraries", strings.Join(windowsAvailableLibraries, " ")) +} + type toolchainFactory func(arch android.Arch) Toolchain var toolchainFactories = make(map[android.OsType]map[android.ArchType]toolchainFactory) @@ -94,6 +101,7 @@ type Toolchain interface { CrtEndStaticBinary() []string CrtEndSharedBinary() []string CrtEndSharedLibrary() []string + CrtPadSegmentSharedLibrary() []string // DefaultSharedLibraries returns the list of shared libraries that will be added to all // targets unless they explicitly specify system_shared_libs. @@ -149,12 +157,13 @@ func (toolchainBase) LibclangRuntimeLibraryArch() string { type toolchainNoCrt struct{} -func (toolchainNoCrt) CrtBeginStaticBinary() []string { return nil } -func (toolchainNoCrt) CrtBeginSharedBinary() []string { return nil } -func (toolchainNoCrt) CrtBeginSharedLibrary() []string { return nil } -func (toolchainNoCrt) CrtEndStaticBinary() []string { return nil } -func (toolchainNoCrt) CrtEndSharedBinary() []string { return nil } -func (toolchainNoCrt) CrtEndSharedLibrary() []string { return nil } +func (toolchainNoCrt) CrtBeginStaticBinary() []string { return nil } +func (toolchainNoCrt) CrtBeginSharedBinary() []string { return nil } +func (toolchainNoCrt) CrtBeginSharedLibrary() []string { return nil } +func (toolchainNoCrt) CrtEndStaticBinary() []string { return nil } +func (toolchainNoCrt) CrtEndSharedBinary() []string { return nil } +func (toolchainNoCrt) CrtEndSharedLibrary() []string { return nil } +func (toolchainNoCrt) CrtPadSegmentSharedLibrary() []string { return nil } func (toolchainBase) DefaultSharedLibraries() []string { return nil @@ -200,60 +209,58 @@ func addPrefix(list []string, prefix string) []string { return list } -func LibclangRuntimeLibrary(t Toolchain, library string) string { +func LibclangRuntimeLibrary(library string) string { return "libclang_rt." + library } -func BuiltinsRuntimeLibrary(t Toolchain) string { - return LibclangRuntimeLibrary(t, "builtins") +func BuiltinsRuntimeLibrary() string { + return LibclangRuntimeLibrary("builtins") } -func AddressSanitizerRuntimeLibrary(t Toolchain) string { - return LibclangRuntimeLibrary(t, "asan") +func AddressSanitizerRuntimeLibrary() string { + return LibclangRuntimeLibrary("asan") } -func AddressSanitizerStaticRuntimeLibrary(t Toolchain) string { - return LibclangRuntimeLibrary(t, "asan.static") +func AddressSanitizerStaticRuntimeLibrary() string { + return LibclangRuntimeLibrary("asan.static") } -func AddressSanitizerCXXStaticRuntimeLibrary(t Toolchain) string { - return LibclangRuntimeLibrary(t, "asan_cxx.static") +func AddressSanitizerCXXStaticRuntimeLibrary() string { + return LibclangRuntimeLibrary("asan_cxx.static") } -func HWAddressSanitizerRuntimeLibrary(t Toolchain) string { - return LibclangRuntimeLibrary(t, "hwasan") +func HWAddressSanitizerRuntimeLibrary() string { + return LibclangRuntimeLibrary("hwasan") } -func HWAddressSanitizerStaticLibrary(t Toolchain) string { - return LibclangRuntimeLibrary(t, "hwasan_static") +func HWAddressSanitizerStaticLibrary() string { + return LibclangRuntimeLibrary("hwasan_static") } -func UndefinedBehaviorSanitizerRuntimeLibrary(t Toolchain) string { - return LibclangRuntimeLibrary(t, "ubsan_standalone") +func UndefinedBehaviorSanitizerRuntimeLibrary() string { + return LibclangRuntimeLibrary("ubsan_standalone") } -func UndefinedBehaviorSanitizerMinimalRuntimeLibrary(t Toolchain) string { - return LibclangRuntimeLibrary(t, "ubsan_minimal") +func UndefinedBehaviorSanitizerMinimalRuntimeLibrary() string { + return LibclangRuntimeLibrary("ubsan_minimal") } -func ThreadSanitizerRuntimeLibrary(t Toolchain) string { - return LibclangRuntimeLibrary(t, "tsan") +func ThreadSanitizerRuntimeLibrary() string { + return LibclangRuntimeLibrary("tsan") } -func ScudoRuntimeLibrary(t Toolchain) string { - return LibclangRuntimeLibrary(t, "scudo") +func ScudoRuntimeLibrary() string { + return LibclangRuntimeLibrary("scudo") } -func ScudoMinimalRuntimeLibrary(t Toolchain) string { - return LibclangRuntimeLibrary(t, "scudo_minimal") +func ScudoMinimalRuntimeLibrary() string { + return LibclangRuntimeLibrary("scudo_minimal") } -func LibFuzzerRuntimeLibrary(t Toolchain) string { - return LibclangRuntimeLibrary(t, "fuzzer") +func LibFuzzerRuntimeLibrary() string { + return LibclangRuntimeLibrary("fuzzer") } -func LibFuzzerRuntimeInterceptors(t Toolchain) string { - return LibclangRuntimeLibrary(t, "fuzzer_interceptors") +func LibFuzzerRuntimeInterceptors() string { + return LibclangRuntimeLibrary("fuzzer_interceptors") } - -var inList = android.InList diff --git a/cc/config/vndk.go b/cc/config/vndk.go deleted file mode 100644 index dd612ce63..000000000 --- a/cc/config/vndk.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019 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 config - -// List of VNDK libraries that have different core variant and vendor variant. -// For these libraries, the vendor variants must be installed even if the device -// has VndkUseCoreVariant set. -// Note that AIDL-generated modules must use vendor variants by default. -var VndkMustUseVendorVariantList = []string{ - "android.hardware.nfc@1.2", - "libbinder", - "libcrypto", - "libexpat", - "libgatekeeper", - "libgui", - "libhidlcache", - "libkeymaster_messages", - "libkeymaster_portable", - "libmedia_omx", - "libpuresoftkeymasterdevice", - "libselinux", - "libsoftkeymasterdevice", - "libsqlite", - "libssl", - "libstagefright_bufferpool@2.0", - "libstagefright_bufferqueue_helper", - "libstagefright_foundation", - "libstagefright_omx", - "libstagefright_omx_utils", - "libstagefright_xmlparser", - "libui", - "libxml2", -} diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go index 9f093bb90..5aa2a7e3b 100644 --- a/cc/config/x86_64_device.go +++ b/cc/config/x86_64_device.go @@ -30,9 +30,11 @@ var ( x86_64Cppflags = []string{} x86_64Ldflags = []string{ - "-Wl,--hash-style=gnu", + "-Wl,-z,separate-loadable-segments", } + X86_64Lldflags = x86_64Ldflags + x86_64ArchVariantCflags = map[string][]string{ "": []string{ "-march=x86-64", @@ -47,6 +49,11 @@ var ( "goldmont-plus": []string{ "-march=goldmont-plus", }, + "goldmont-without-sha-xsaves": []string{ + "-march=goldmont", + "-mno-sha", + "-mno-xsaves", + }, "haswell": []string{ "-march=core-avx2", }, @@ -90,26 +97,31 @@ var ( ) func init() { - exportedVars.ExportStringListStaticVariable("X86_64ToolchainCflags", []string{"-m64"}) - exportedVars.ExportStringListStaticVariable("X86_64ToolchainLdflags", []string{"-m64"}) - - exportedVars.ExportStringListStaticVariable("X86_64Ldflags", x86_64Ldflags) - exportedVars.ExportStringListStaticVariable("X86_64Lldflags", x86_64Ldflags) + pctx.StaticVariable("X86_64ToolchainCflags", "-m64") + pctx.StaticVariable("X86_64ToolchainLdflags", "-m64") + + pctx.StaticVariable("X86_64Ldflags", strings.Join(x86_64Ldflags, " ")) + pctx.VariableFunc("X86_64Lldflags", func(ctx android.PackageVarContext) string { + maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported() + flags := append(X86_64Lldflags, maxPageSizeFlag) + return strings.Join(flags, " ") + }) // Clang cflags - exportedVars.ExportStringListStaticVariable("X86_64Cflags", x86_64Cflags) - exportedVars.ExportStringListStaticVariable("X86_64Cppflags", x86_64Cppflags) - - // Yasm flags - exportedVars.ExportStringListStaticVariable("X86_64YasmFlags", []string{ - "-f elf64", - "-m amd64", + pctx.VariableFunc("X86_64Cflags", func(ctx android.PackageVarContext) string { + flags := x86_64Cflags + if ctx.Config().NoBionicPageSizeMacro() { + flags = append(flags, "-D__BIONIC_NO_PAGE_SIZE_MACRO") + } else { + flags = append(flags, "-D__BIONIC_DEPRECATED_PAGE_SIZE_MACRO") + } + return strings.Join(flags, " ") }) - // Extended cflags + pctx.StaticVariable("X86_64Cppflags", strings.Join(x86_64Cppflags, " ")) - exportedVars.ExportStringListDict("X86_64ArchVariantCflags", x86_64ArchVariantCflags) - exportedVars.ExportStringListDict("X86_64ArchFeatureCflags", x86_64ArchFeatureCflags) + // Yasm flags + pctx.StaticVariable("X86_64YasmFlags", "-f elf64 -m amd64") // Architecture variant cflags for variant, cflags := range x86_64ArchVariantCflags { diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go index c826d3c45..4b0041c9e 100644 --- a/cc/config/x86_device.go +++ b/cc/config/x86_device.go @@ -33,9 +33,7 @@ var ( x86Cppflags = []string{} - x86Ldflags = []string{ - "-Wl,--hash-style=gnu", - } + x86Ldflags = []string{} x86ArchVariantCflags = map[string][]string{ "": []string{ @@ -56,6 +54,11 @@ var ( "goldmont-plus": []string{ "-march=goldmont-plus", }, + "goldmont-without-sha-xsaves": []string{ + "-march=goldmont", + "-mno-sha", + "-mno-xsaves", + }, "haswell": []string{ "-march=core-avx2", }, @@ -98,25 +101,18 @@ var ( ) func init() { - exportedVars.ExportStringListStaticVariable("X86ToolchainCflags", []string{"-m32"}) - exportedVars.ExportStringListStaticVariable("X86ToolchainLdflags", []string{"-m32"}) + pctx.StaticVariable("X86ToolchainCflags", "-m32") + pctx.StaticVariable("X86ToolchainLdflags", "-m32") - exportedVars.ExportStringListStaticVariable("X86Ldflags", x86Ldflags) - exportedVars.ExportStringListStaticVariable("X86Lldflags", x86Ldflags) + pctx.StaticVariable("X86Ldflags", strings.Join(x86Ldflags, " ")) + pctx.StaticVariable("X86Lldflags", strings.Join(x86Ldflags, " ")) // Clang cflags - exportedVars.ExportStringListStaticVariable("X86Cflags", x86Cflags) - exportedVars.ExportStringListStaticVariable("X86Cppflags", x86Cppflags) + pctx.StaticVariable("X86Cflags", strings.Join(x86Cflags, " ")) + pctx.StaticVariable("X86Cppflags", strings.Join(x86Cppflags, " ")) // Yasm flags - exportedVars.ExportStringListStaticVariable("X86YasmFlags", []string{ - "-f elf32", - "-m x86", - }) - - // Extended cflags - exportedVars.ExportStringListDict("X86ArchVariantCflags", x86ArchVariantCflags) - exportedVars.ExportStringListDict("X86ArchFeatureCflags", x86ArchFeatureCflags) + pctx.StaticVariable("X86YasmFlags", "-f elf32 -m x86") // Architecture variant cflags for variant, cflags := range x86ArchVariantCflags { diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go index e0064717d..515cb2104 100644 --- a/cc/config/x86_linux_bionic_host.go +++ b/cc/config/x86_linux_bionic_host.go @@ -16,6 +16,7 @@ package config import ( "android/soong/android" + "strings" ) var ( @@ -46,13 +47,16 @@ var ( "-Wl,-z,now", "-Wl,--build-id=md5", "-Wl,--fatal-warnings", - "-Wl,--hash-style=gnu", "-Wl,--no-undefined-version", // Use the device gcc toolchain "--gcc-toolchain=${LinuxBionicGccRoot}", } + linuxBionicLldflags = append(linuxBionicLdflags, + "-Wl,--compress-debug-sections=zstd", + ) + // Embed the linker into host bionic binaries. This is needed to support host bionic, // as the linux kernel requires that the ELF interpreter referenced by PT_INTERP be // either an absolute path, or relative from CWD. To work around this, we extract @@ -69,13 +73,13 @@ const ( ) func init() { - exportedVars.ExportStringListStaticVariable("LinuxBionicCflags", linuxBionicCflags) - exportedVars.ExportStringListStaticVariable("LinuxBionicLdflags", linuxBionicLdflags) - exportedVars.ExportStringListStaticVariable("LinuxBionicLldflags", linuxBionicLdflags) + pctx.StaticVariable("LinuxBionicCflags", strings.Join(linuxBionicCflags, " ")) + pctx.StaticVariable("LinuxBionicLdflags", strings.Join(linuxBionicLdflags, " ")) + pctx.StaticVariable("LinuxBionicLldflags", strings.Join(linuxBionicLldflags, " ")) // Use the device gcc toolchain for now - exportedVars.ExportStringStaticVariable("LinuxBionicGccVersion", x86_64GccVersion) - exportedVars.ExportSourcePathVariable("LinuxBionicGccRoot", + pctx.StaticVariable("LinuxBionicGccVersion", x86_64GccVersion) + pctx.SourcePathVariable("LinuxBionicGccRoot", "prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${LinuxBionicGccVersion}") } diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go index 93aa82ec5..7f22377bf 100644 --- a/cc/config/x86_linux_host.go +++ b/cc/config/x86_linux_host.go @@ -30,11 +30,6 @@ var ( "-D_FORTIFY_SOURCE=2", "-fstack-protector", - // Workaround differences in inttypes.h between host and target. - //See bug 12708004. - "-D__STDC_FORMAT_MACROS", - "-D__STDC_CONSTANT_MACROS", - "--gcc-toolchain=${LinuxGccRoot}", "-fstack-protector-strong", } @@ -59,6 +54,10 @@ var ( "--gcc-toolchain=${LinuxGccRoot}", } + linuxLldflags = append(linuxLdflags, + "-Wl,--compress-debug-sections=zstd", + ) + linuxGlibcLdflags = []string{ "--sysroot ${LinuxGccRoot}/sysroot", } @@ -121,40 +120,40 @@ const ( ) func init() { - exportedVars.ExportStringStaticVariable("LinuxGccVersion", linuxGccVersion) - exportedVars.ExportStringStaticVariable("LinuxGlibcVersion", linuxGlibcVersion) + pctx.StaticVariable("LinuxGccVersion", linuxGccVersion) + pctx.StaticVariable("LinuxGlibcVersion", linuxGlibcVersion) // Most places use the full GCC version. A few only use up to the first two numbers. if p := strings.Split(linuxGccVersion, "."); len(p) > 2 { - exportedVars.ExportStringStaticVariable("ShortLinuxGccVersion", strings.Join(p[:2], ".")) + pctx.StaticVariable("ShortLinuxGccVersion", strings.Join(p[:2], ".")) } else { - exportedVars.ExportStringStaticVariable("ShortLinuxGccVersion", linuxGccVersion) + pctx.StaticVariable("ShortLinuxGccVersion", linuxGccVersion) } - exportedVars.ExportSourcePathVariable("LinuxGccRoot", + pctx.SourcePathVariable("LinuxGccRoot", "prebuilts/gcc/linux-x86/host/x86_64-linux-glibc${LinuxGlibcVersion}-${ShortLinuxGccVersion}") - exportedVars.ExportStringListStaticVariable("LinuxGccTriple", []string{"x86_64-linux"}) - - exportedVars.ExportStringListStaticVariable("LinuxCflags", linuxCflags) - exportedVars.ExportStringListStaticVariable("LinuxLdflags", linuxLdflags) - exportedVars.ExportStringListStaticVariable("LinuxLldflags", linuxLdflags) - exportedVars.ExportStringListStaticVariable("LinuxGlibcCflags", linuxGlibcCflags) - exportedVars.ExportStringListStaticVariable("LinuxGlibcLdflags", linuxGlibcLdflags) - exportedVars.ExportStringListStaticVariable("LinuxGlibcLldflags", linuxGlibcLdflags) - exportedVars.ExportStringListStaticVariable("LinuxMuslCflags", linuxMuslCflags) - exportedVars.ExportStringListStaticVariable("LinuxMuslLdflags", linuxMuslLdflags) - exportedVars.ExportStringListStaticVariable("LinuxMuslLldflags", linuxMuslLdflags) - - exportedVars.ExportStringListStaticVariable("LinuxX86Cflags", linuxX86Cflags) - exportedVars.ExportStringListStaticVariable("LinuxX8664Cflags", linuxX8664Cflags) - exportedVars.ExportStringListStaticVariable("LinuxX86Ldflags", linuxX86Ldflags) - exportedVars.ExportStringListStaticVariable("LinuxX86Lldflags", linuxX86Ldflags) - exportedVars.ExportStringListStaticVariable("LinuxX8664Ldflags", linuxX8664Ldflags) - exportedVars.ExportStringListStaticVariable("LinuxX8664Lldflags", linuxX8664Ldflags) + pctx.StaticVariable("LinuxGccTriple", "x86_64-linux") + + pctx.StaticVariable("LinuxCflags", strings.Join(linuxCflags, " ")) + pctx.StaticVariable("LinuxLdflags", strings.Join(linuxLdflags, " ")) + pctx.StaticVariable("LinuxLldflags", strings.Join(linuxLldflags, " ")) + pctx.StaticVariable("LinuxGlibcCflags", strings.Join(linuxGlibcCflags, " ")) + pctx.StaticVariable("LinuxGlibcLdflags", strings.Join(linuxGlibcLdflags, " ")) + pctx.StaticVariable("LinuxGlibcLldflags", strings.Join(linuxGlibcLdflags, " ")) + pctx.StaticVariable("LinuxMuslCflags", strings.Join(linuxMuslCflags, " ")) + pctx.StaticVariable("LinuxMuslLdflags", strings.Join(linuxMuslLdflags, " ")) + pctx.StaticVariable("LinuxMuslLldflags", strings.Join(linuxMuslLdflags, " ")) + + pctx.StaticVariable("LinuxX86Cflags", strings.Join(linuxX86Cflags, " ")) + pctx.StaticVariable("LinuxX8664Cflags", strings.Join(linuxX8664Cflags, " ")) + pctx.StaticVariable("LinuxX86Ldflags", strings.Join(linuxX86Ldflags, " ")) + pctx.StaticVariable("LinuxX86Lldflags", strings.Join(linuxX86Ldflags, " ")) + pctx.StaticVariable("LinuxX8664Ldflags", strings.Join(linuxX8664Ldflags, " ")) + pctx.StaticVariable("LinuxX8664Lldflags", strings.Join(linuxX8664Ldflags, " ")) // Yasm flags - exportedVars.ExportStringListStaticVariable("LinuxX86YasmFlags", []string{"-f elf32 -m x86"}) - exportedVars.ExportStringListStaticVariable("LinuxX8664YasmFlags", []string{"-f elf64 -m amd64"}) + pctx.StaticVariable("LinuxX86YasmFlags", "-f elf32 -m x86") + pctx.StaticVariable("LinuxX8664YasmFlags", "-f elf64 -m amd64") } type toolchainLinux struct { @@ -324,12 +323,13 @@ type toolchainMusl struct { func (toolchainMusl) Musl() bool { return true } -func (toolchainMusl) CrtBeginStaticBinary() []string { return muslCrtBeginStaticBinary } -func (toolchainMusl) CrtBeginSharedBinary() []string { return muslCrtBeginSharedBinary } -func (toolchainMusl) CrtBeginSharedLibrary() []string { return muslCrtBeginSharedLibrary } -func (toolchainMusl) CrtEndStaticBinary() []string { return muslCrtEndStaticBinary } -func (toolchainMusl) CrtEndSharedBinary() []string { return muslCrtEndSharedBinary } -func (toolchainMusl) CrtEndSharedLibrary() []string { return muslCrtEndSharedLibrary } +func (toolchainMusl) CrtBeginStaticBinary() []string { return muslCrtBeginStaticBinary } +func (toolchainMusl) CrtBeginSharedBinary() []string { return muslCrtBeginSharedBinary } +func (toolchainMusl) CrtBeginSharedLibrary() []string { return muslCrtBeginSharedLibrary } +func (toolchainMusl) CrtEndStaticBinary() []string { return muslCrtEndStaticBinary } +func (toolchainMusl) CrtEndSharedBinary() []string { return muslCrtEndSharedBinary } +func (toolchainMusl) CrtEndSharedLibrary() []string { return muslCrtEndSharedLibrary } +func (toolchainMusl) CrtPadSegmentSharedLibrary() []string { return nil } func (toolchainMusl) DefaultSharedLibraries() []string { return MuslDefaultSharedLibraries } diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go index 561c50099..1e61b01d0 100644 --- a/cc/config/x86_windows_host.go +++ b/cc/config/x86_windows_host.go @@ -27,9 +27,8 @@ var ( "-DWIN32_LEAN_AND_MEAN", "-Wno-unused-parameter", - // Workaround differences in inttypes.h between host and target. - //See bug 12708004. - "-D__STDC_FORMAT_MACROS", + // Workaround differences in <stdint.h> between host and target. + // Context: http://b/12708004 "-D__STDC_CONSTANT_MACROS", // Use C99-compliant printf functions (%zd). diff --git a/cc/coverage.go b/cc/coverage.go index c0f697398..a7618dd96 100644 --- a/cc/coverage.go +++ b/cc/coverage.go @@ -22,6 +22,29 @@ import ( "android/soong/android" ) +var ( + clangCoverageHostLdFlags = []string{ + "-Wl,--no-as-needed", + "-Wl,--wrap,open", + } + clangContinuousCoverageFlags = []string{ + "-mllvm", + "-runtime-counter-relocation", + } + clangCoverageCFlags = []string{ + "-Wno-frame-larger-than=", + } + clangCoverageCommonFlags = []string{ + "-fcoverage-mapping", + "-Wno-pass-failed", + "-D__ANDROID_CLANG_COVERAGE__", + } + clangCoverageHWASanFlags = []string{ + "-mllvm", + "-hwasan-globals=0", + } +) + const profileInstrFlag = "-fprofile-instr-generate=/data/misc/trace/clang-%p-%m.profraw" type CoverageProperties struct { @@ -48,6 +71,7 @@ func (cov *coverage) props() []interface{} { func getGcovProfileLibraryName(ctx ModuleContextIntf) string { // This function should only ever be called for a cc.Module, so the // following statement should always succeed. + // LINT.IfChange if ctx.useSdk() { return "libprofile-extras_ndk" } else { @@ -63,10 +87,11 @@ func getClangProfileLibraryName(ctx ModuleContextIntf) string { } else { return "libprofile-clang-extras" } + // LINT.ThenChange(library.go) } func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps { - if cov.Properties.NeedCoverageVariant { + if cov.Properties.NeedCoverageVariant && ctx.Device() { ctx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, }, CoverageDepTag, getGcovProfileLibraryName(ctx)) @@ -100,19 +125,19 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags // flags that the module may use. flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0") } else if clangCoverage { - flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag, - "-fcoverage-mapping", "-Wno-pass-failed", "-D__ANDROID_CLANG_COVERAGE__") + flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag) + flags.Local.CommonFlags = append(flags.Local.CommonFlags, clangCoverageCommonFlags...) // Override -Wframe-larger-than. We can expect frame size increase after // coverage instrumentation. - flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=") + flags.Local.CFlags = append(flags.Local.CFlags, clangCoverageCFlags...) if EnableContinuousCoverage(ctx) { - flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-mllvm", "-runtime-counter-relocation") + flags.Local.CommonFlags = append(flags.Local.CommonFlags, clangContinuousCoverageFlags...) } // http://b/248022906, http://b/247941801 enabling coverage and hwasan-globals // instrumentation together causes duplicate-symbol errors for __llvm_profile_filename. if c, ok := ctx.Module().(*Module); ok && c.sanitize.isSanitizerEnabled(Hwasan) { - flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-mllvm", "-hwasan-globals=0") + flags.Local.CommonFlags = append(flags.Local.CommonFlags, clangCoverageHWASanFlags...) } } } @@ -159,19 +184,22 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags if gcovCoverage { flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage") - coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), CoverageDepTag).(*Module) - deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path()) - - flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv") + if ctx.Device() { + coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), CoverageDepTag).(*Module) + deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path()) + flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv") + } } else if clangCoverage { flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrFlag) if EnableContinuousCoverage(ctx) { flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm=-runtime-counter-relocation") } - coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module) - deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path()) - flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,open") + if ctx.Device() { + coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module) + deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path()) + flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,open") + } } } @@ -179,7 +207,7 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags } func (cov *coverage) begin(ctx BaseModuleContext) { - if ctx.Host() { + if ctx.Host() && !ctx.Os().Linux() { // TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a // Just turn off for now. } else { @@ -219,9 +247,19 @@ func SetCoverageProperties(ctx android.BaseModuleContext, properties CoveragePro return properties } +type IsNativeCoverageNeededContext interface { + Config() android.Config + DeviceConfig() android.DeviceConfig + Device() bool +} + +var _ IsNativeCoverageNeededContext = android.IncomingTransitionContext(nil) +var _ IsNativeCoverageNeededContext = android.BaseModuleContext(nil) +var _ IsNativeCoverageNeededContext = android.BottomUpMutatorContext(nil) + type UseCoverage interface { android.Module - IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool + IsNativeCoverageNeeded(ctx IsNativeCoverageNeededContext) bool } // Coverage is an interface for non-CC modules to implement to be mutated for coverage @@ -233,43 +271,86 @@ type Coverage interface { EnableCoverageIfNeeded() } -func coverageMutator(mctx android.BottomUpMutatorContext) { - if c, ok := mctx.Module().(*Module); ok && c.coverage != nil { - needCoverageVariant := c.coverage.Properties.NeedCoverageVariant - needCoverageBuild := c.coverage.Properties.NeedCoverageBuild - if needCoverageVariant { - m := mctx.CreateVariations("", "cov") +type coverageTransitionMutator struct{} + +var _ android.TransitionMutator = (*coverageTransitionMutator)(nil) + +func (c coverageTransitionMutator) Split(ctx android.BaseModuleContext) []string { + if c, ok := ctx.Module().(*Module); ok && c.coverage != nil { + if c.coverage.Properties.NeedCoverageVariant { + return []string{"", "cov"} + } + } else if cov, ok := ctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(ctx) { + // APEX and Rust modules fall here + + // Note: variant "" is also created because an APEX can be depended on by another + // module which are split into "" and "cov" variants. e.g. when cc_test refers + // to an APEX via 'data' property. + return []string{"", "cov"} + } else if cov, ok := ctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(ctx) { + // Module itself doesn't have to have "cov" variant, but it should use "cov" variants of + // deps. + return []string{"cov"} + } + + return []string{""} +} + +func (c coverageTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + return sourceVariation +} +func (c coverageTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { + if c, ok := ctx.Module().(*Module); ok && c.coverage != nil { + if !c.coverage.Properties.NeedCoverageVariant { + return "" + } + } else if cov, ok := ctx.Module().(Coverage); ok { + if !cov.IsNativeCoverageNeeded(ctx) { + return "" + } + } else if cov, ok := ctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(ctx) { + // Module only has a "cov" variation, so all incoming variations should use "cov". + return "cov" + } else { + return "" + } + + return incomingVariation +} + +func (c coverageTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { + if c, ok := ctx.Module().(*Module); ok && c.coverage != nil { + if variation == "" && c.coverage.Properties.NeedCoverageVariant { // Setup the non-coverage version and set HideFromMake and // PreventInstall to true. - m[0].(*Module).coverage.Properties.CoverageEnabled = false - m[0].(*Module).coverage.Properties.IsCoverageVariant = false - m[0].(*Module).Properties.HideFromMake = true - m[0].(*Module).Properties.PreventInstall = true - + c.coverage.Properties.CoverageEnabled = false + c.coverage.Properties.IsCoverageVariant = false + c.Properties.HideFromMake = true + c.Properties.PreventInstall = true + } else if variation == "cov" { // The coverage-enabled version inherits HideFromMake, // PreventInstall from the original module. - m[1].(*Module).coverage.Properties.CoverageEnabled = needCoverageBuild - m[1].(*Module).coverage.Properties.IsCoverageVariant = true + c.coverage.Properties.CoverageEnabled = c.coverage.Properties.NeedCoverageBuild + c.coverage.Properties.IsCoverageVariant = true } - } else if cov, ok := mctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(mctx) { + } else if cov, ok := ctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(ctx) { // APEX and Rust modules fall here // Note: variant "" is also created because an APEX can be depended on by another // module which are split into "" and "cov" variants. e.g. when cc_test refers // to an APEX via 'data' property. - m := mctx.CreateVariations("", "cov") - m[0].(Coverage).MarkAsCoverageVariant(false) - m[0].(Coverage).SetPreventInstall() - m[0].(Coverage).HideFromMake() - - m[1].(Coverage).MarkAsCoverageVariant(true) - m[1].(Coverage).EnableCoverageIfNeeded() - } else if cov, ok := mctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(mctx) { + if variation == "" { + cov.MarkAsCoverageVariant(false) + cov.SetPreventInstall() + cov.HideFromMake() + } else if variation == "cov" { + cov.MarkAsCoverageVariant(true) + cov.EnableCoverageIfNeeded() + } + } else if cov, ok := ctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(ctx) { // Module itself doesn't have to have "cov" variant, but it should use "cov" variants of // deps. - mctx.CreateVariations("cov") - mctx.AliasVariation("cov") } } diff --git a/cc/fdo_profile.go b/cc/fdo_profile.go index 7fbe71940..1a3395773 100644 --- a/cc/fdo_profile.go +++ b/cc/fdo_profile.go @@ -16,7 +16,6 @@ package cc import ( "android/soong/android" - "github.com/google/blueprint" ) @@ -25,7 +24,7 @@ func init() { } func RegisterFdoProfileBuildComponents(ctx android.RegistrationContext) { - ctx.RegisterModuleType("fdo_profile", fdoProfileFactory) + ctx.RegisterModuleType("fdo_profile", FdoProfileFactory) } type fdoProfile struct { @@ -44,40 +43,19 @@ type FdoProfileInfo struct { } // FdoProfileProvider is used to provide path to an fdo profile -var FdoProfileProvider = blueprint.NewMutatorProvider(FdoProfileInfo{}, "fdo_profile") - -// FdoProfileMutatorInterface is the interface implemented by fdo_profile module type -// module types that can depend on an fdo_profile module -type FdoProfileMutatorInterface interface { - // FdoProfileMutator eithers set or get FdoProfileProvider - fdoProfileMutator(ctx android.BottomUpMutatorContext) -} - -var _ FdoProfileMutatorInterface = (*fdoProfile)(nil) +var FdoProfileProvider = blueprint.NewProvider[FdoProfileInfo]() // GenerateAndroidBuildActions of fdo_profile does not have any build actions -func (fp *fdoProfile) GenerateAndroidBuildActions(ctx android.ModuleContext) {} - -// FdoProfileMutator sets FdoProfileProvider to fdo_profile module -// or sets afdo.Properties.FdoProfilePath to path in FdoProfileProvider of the depended fdo_profile -func (fp *fdoProfile) fdoProfileMutator(ctx android.BottomUpMutatorContext) { +func (fp *fdoProfile) GenerateAndroidBuildActions(ctx android.ModuleContext) { if fp.properties.Profile != nil { path := android.PathForModuleSrc(ctx, *fp.properties.Profile) - ctx.SetProvider(FdoProfileProvider, FdoProfileInfo{ + android.SetProvider(ctx, FdoProfileProvider, FdoProfileInfo{ Path: path, }) } } -// fdoProfileMutator calls the generic fdoProfileMutator function of fdoProfileMutator -// which is implemented by cc and cc.FdoProfile -func fdoProfileMutator(ctx android.BottomUpMutatorContext) { - if f, ok := ctx.Module().(FdoProfileMutatorInterface); ok { - f.fdoProfileMutator(ctx) - } -} - -func fdoProfileFactory() android.Module { +func FdoProfileFactory() android.Module { m := &fdoProfile{} m.AddProperties(&m.properties) android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibBoth) diff --git a/cc/fuzz.go b/cc/fuzz.go index 7aa8b91c7..92f2c5e44 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -28,7 +28,8 @@ import ( func init() { android.RegisterModuleType("cc_fuzz", LibFuzzFactory) - android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory) + android.RegisterParallelSingletonType("cc_fuzz_packaging", fuzzPackagingFactory) + android.RegisterParallelSingletonType("cc_fuzz_presubmit_packaging", fuzzPackagingFactoryPresubmit) } type FuzzProperties struct { @@ -95,6 +96,7 @@ func fuzzMutatorDeps(mctx android.TopDownMutatorContext) { // your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree. func LibFuzzFactory() android.Module { module := NewFuzzer(android.HostAndDeviceSupported) + module.testModule = true return module.Init() } @@ -103,7 +105,8 @@ type fuzzBinary struct { *baseCompiler fuzzPackagedModule fuzz.FuzzPackagedModule installedSharedDeps []string - sharedLibraries android.Paths + sharedLibraries android.RuleBuilderInstalls + data []android.DataPath } func (fuzz *fuzzBinary) fuzzBinary() bool { @@ -125,13 +128,13 @@ func (fuzzBin *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps { if ctx.Config().Getenv("FUZZ_FRAMEWORK") == "AFL" { deps.HeaderLibs = append(deps.HeaderLibs, "libafl_headers") } else { - deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeLibrary(ctx.toolchain())) + deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeLibrary()) // Fuzzers built with HWASAN should use the interceptors for better // mutation based on signals in strcmp, memcpy, etc. This is only needed for // fuzz targets, not generic HWASAN-ified binaries or libraries. if module, ok := ctx.Module().(*Module); ok { if module.IsSanitizerEnabled(Hwasan) { - deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeInterceptors(ctx.toolchain())) + deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeInterceptors()) } } } @@ -141,25 +144,35 @@ func (fuzzBin *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps { } func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { + subdir := "lib" + if ctx.inVendor() { + subdir = "lib/vendor" + } + flags = fuzz.binaryDecorator.linkerFlags(ctx, flags) // RunPaths on devices isn't instantiated by the base linker. `../lib` for // installed fuzz targets (both host and device), and `./lib` for fuzz // target packages. - flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/lib`) + flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/`+subdir) // When running on device, fuzz targets with vendor: true set will be in // fuzzer_name/vendor/fuzzer_name (note the extra 'vendor' and thus need to // link with libraries in ../../lib/. Non-vendor binaries only need to look // one level up, in ../lib/. if ctx.inVendor() { - flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../../lib`) + flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../../`+subdir) } else { - flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../lib`) + flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../`+subdir) } return flags } +func (fuzz *fuzzBinary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + fuzz.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON) + moduleInfoJSON.Class = []string{"EXECUTABLES"} +} + // IsValidSharedDependency takes a module and determines if it is a unique shared library // that should be installed in the fuzz target output directories. This function // returns true, unless: @@ -213,70 +226,91 @@ func IsValidSharedDependency(dependency android.Module) bool { } func SharedLibraryInstallLocation( - libraryPath android.Path, isHost bool, fuzzDir string, archString string) string { + libraryBase string, isHost bool, isVendor bool, fuzzDir string, archString string) string { installLocation := "$(PRODUCT_OUT)/data" if isHost { installLocation = "$(HOST_OUT)" } + subdir := "lib" + if isVendor { + subdir = "lib/vendor" + } installLocation = filepath.Join( - installLocation, fuzzDir, archString, "lib", libraryPath.Base()) + installLocation, fuzzDir, archString, subdir, libraryBase) return installLocation } // Get the device-only shared library symbols install directory. -func SharedLibrarySymbolsInstallLocation(libraryPath android.Path, fuzzDir string, archString string) string { - return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, "/lib/", libraryPath.Base()) +func SharedLibrarySymbolsInstallLocation(libraryBase string, isVendor bool, fuzzDir string, archString string) string { + subdir := "lib" + if isVendor { + subdir = "lib/vendor" + } + return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, subdir, libraryBase) } func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) { - installBase := "fuzz" - - fuzzBin.binaryDecorator.baseInstaller.dir = filepath.Join( - installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) - fuzzBin.binaryDecorator.baseInstaller.dir64 = filepath.Join( - installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) - fuzzBin.binaryDecorator.baseInstaller.install(ctx, file) - fuzzBin.fuzzPackagedModule = PackageFuzzModule(ctx, fuzzBin.fuzzPackagedModule, pctx) + installBase := "fuzz" + // Grab the list of required shared libraries. fuzzBin.sharedLibraries, _ = CollectAllSharedDependencies(ctx) - for _, lib := range fuzzBin.sharedLibraries { + // TODO: does not mirror Android linkernamespaces + // the logic here has special cases for vendor, but it would need more work to + // work in arbitrary partitions, so just surface errors early for a few cases + // + // Even without these, there are certain situations across linkernamespaces + // that this won't support. For instance, you might have: + // + // my_fuzzer (vendor) -> libbinder_ndk (core) -> libbinder (vendor) + // + // This dependency chain wouldn't be possible to express in the current + // logic because all the deps currently match the variant of the source + // module. + + for _, ruleBuilderInstall := range fuzzBin.sharedLibraries { + install := ruleBuilderInstall.To fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps, SharedLibraryInstallLocation( - lib, ctx.Host(), installBase, ctx.Arch().ArchType.String())) + install, ctx.Host(), ctx.inVendor(), installBase, ctx.Arch().ArchType.String())) // Also add the dependency on the shared library symbols dir. if !ctx.Host() { fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps, - SharedLibrarySymbolsInstallLocation(lib, installBase, ctx.Arch().ArchType.String())) + SharedLibrarySymbolsInstallLocation(install, ctx.inVendor(), installBase, ctx.Arch().ArchType.String())) } } + + for _, d := range fuzzBin.fuzzPackagedModule.Corpus { + fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, RelativeInstallPath: "corpus", WithoutRel: true}) + } + + for _, d := range fuzzBin.fuzzPackagedModule.Data { + fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, RelativeInstallPath: "data"}) + } + + if d := fuzzBin.fuzzPackagedModule.Dictionary; d != nil { + fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, WithoutRel: true}) + } + + if d := fuzzBin.fuzzPackagedModule.Config; d != nil { + fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, WithoutRel: true}) + } + + fuzzBin.binaryDecorator.baseInstaller.dir = filepath.Join( + installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) + fuzzBin.binaryDecorator.baseInstaller.dir64 = filepath.Join( + installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) + fuzzBin.binaryDecorator.baseInstaller.installTestData(ctx, fuzzBin.data) + fuzzBin.binaryDecorator.baseInstaller.install(ctx, file) } func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPackagedModule, pctx android.PackageContext) fuzz.FuzzPackagedModule { fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Corpus) - builder := android.NewRuleBuilder(pctx, ctx) - intermediateDir := android.PathForModuleOut(ctx, "corpus") - for _, entry := range fuzzPackagedModule.Corpus { - builder.Command().Text("cp"). - Input(entry). - Output(intermediateDir.Join(ctx, entry.Base())) - } - builder.Build("copy_corpus", "copy corpus") - fuzzPackagedModule.CorpusIntermediateDir = intermediateDir fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Data) - builder = android.NewRuleBuilder(pctx, ctx) - intermediateDir = android.PathForModuleOut(ctx, "data") - for _, entry := range fuzzPackagedModule.Data { - builder.Command().Text("cp"). - Input(entry). - Output(intermediateDir.Join(ctx, entry.Rel())) - } - builder.Build("copy_data", "copy data") - fuzzPackagedModule.DataIntermediateDir = intermediateDir if fuzzPackagedModule.FuzzProperties.Dictionary != nil { fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzzPackagedModule.FuzzProperties.Dictionary) @@ -296,7 +330,7 @@ func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPa } func NewFuzzer(hod android.HostOrDeviceSupported) *Module { - module, binary := newBinary(hod, false) + module, binary := newBinary(hod) baseInstallerPath := "fuzz" binary.baseInstaller = NewBaseInstaller(baseInstallerPath, baseInstallerPath, InstallInData) @@ -354,6 +388,7 @@ type ccRustFuzzPackager struct { fuzzPackagingArchModules string fuzzTargetSharedDepsInstallPairs string allFuzzTargetsName string + onlyIncludePresubmits bool } func fuzzPackagingFactory() android.Singleton { @@ -362,6 +397,18 @@ func fuzzPackagingFactory() android.Singleton { fuzzPackagingArchModules: "SOONG_FUZZ_PACKAGING_ARCH_MODULES", fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS", allFuzzTargetsName: "ALL_FUZZ_TARGETS", + onlyIncludePresubmits: false, + } + return fuzzPackager +} + +func fuzzPackagingFactoryPresubmit() android.Singleton { + + fuzzPackager := &ccRustFuzzPackager{ + fuzzPackagingArchModules: "SOONG_PRESUBMIT_FUZZ_PACKAGING_ARCH_MODULES", + fuzzTargetSharedDepsInstallPairs: "PRESUBMIT_FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS", + allFuzzTargetsName: "ALL_PRESUBMIT_FUZZ_TARGETS", + onlyIncludePresubmits: true, } return fuzzPackager } @@ -385,21 +432,29 @@ func (s *ccRustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) if !ok || ccModule.PreventInstall() { return } - // Discard non-fuzz targets. - if ok := fuzz.IsValid(ccModule.FuzzModuleStruct()); !ok { + if ok := fuzz.IsValid(ctx, ccModule.FuzzModuleStruct()); !ok { return } sharedLibsInstallDirPrefix := "lib" + if ccModule.InVendor() { + sharedLibsInstallDirPrefix = "lib/vendor" + } + if !ccModule.IsFuzzModule() { return } hostOrTargetString := "target" - if ccModule.Host() { + if ccModule.Target().HostCross { + hostOrTargetString = "host_cross" + } else if ccModule.Host() { hostOrTargetString = "host" } + if s.onlyIncludePresubmits == true { + hostOrTargetString = "presubmit-" + hostOrTargetString + } fpm := fuzz.FuzzPackagedModule{} if ok { @@ -422,8 +477,16 @@ func (s *ccRustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) files = append(files, GetSharedLibsToZip(ccModule.FuzzSharedLibraries(), ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...) // The executable. - files = append(files, fuzz.FileToZip{android.OutputFileForModule(ctx, ccModule, "unstripped"), ""}) + files = append(files, fuzz.FileToZip{SourceFilePath: android.OutputFileForModule(ctx, ccModule, "unstripped")}) + if s.onlyIncludePresubmits == true { + if fpm.FuzzProperties.Fuzz_config == nil { + return + } + if !BoolDefault(fpm.FuzzProperties.Fuzz_config.Use_for_presubmit, false) { + return + } + } archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs) if !ok { return @@ -453,19 +516,25 @@ func (s *ccRustFuzzPackager) MakeVars(ctx android.MakeVarsContext) { // GetSharedLibsToZip finds and marks all the transiently-dependent shared libraries for // packaging. -func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface, s *fuzz.FuzzPackager, archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip { +func GetSharedLibsToZip(sharedLibraries android.RuleBuilderInstalls, module LinkableInterface, s *fuzz.FuzzPackager, archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip { var files []fuzz.FileToZip fuzzDir := "fuzz" - for _, library := range sharedLibraries { - files = append(files, fuzz.FileToZip{library, destinationPathPrefix}) + for _, ruleBuilderInstall := range sharedLibraries { + library := ruleBuilderInstall.From + install := ruleBuilderInstall.To + files = append(files, fuzz.FileToZip{ + SourceFilePath: library, + DestinationPathPrefix: destinationPathPrefix, + DestinationPath: install, + }) // For each architecture-specific shared library dependency, we need to // install it to the output directory. Setup the install destination here, // which will be used by $(copy-many-files) in the Make backend. installDestination := SharedLibraryInstallLocation( - library, module.Host(), fuzzDir, archString) + install, module.Host(), module.InVendor(), fuzzDir, archString) if (*sharedLibraryInstalled)[installDestination] { continue } @@ -483,7 +552,7 @@ func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface, // we want symbolization tools (like `stack`) to be able to find the symbols // in $ANDROID_PRODUCT_OUT/symbols automagically. if !module.Host() { - symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(library, fuzzDir, archString) + symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, module.InVendor(), fuzzDir, archString) symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$") s.SharedLibInstallStrings = append(s.SharedLibInstallStrings, library.String()+":"+symbolsInstallDestination) @@ -497,12 +566,12 @@ func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface, // VisitDirectDeps is used first to avoid incorrectly using the core libraries (sanitizer // runtimes, libc, libdl, etc.) from a dependency. This may cause issues when dependencies // have explicit sanitizer tags, as we may get a dependency on an unsanitized libc, etc. -func CollectAllSharedDependencies(ctx android.ModuleContext) (android.Paths, []android.Module) { +func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilderInstalls, []android.Module) { seen := make(map[string]bool) recursed := make(map[string]bool) deps := []android.Module{} - var sharedLibraries android.Paths + var sharedLibraries android.RuleBuilderInstalls // Enumerate the first level of dependencies, as we discard all non-library // modules in the BFS loop below. @@ -510,22 +579,47 @@ func CollectAllSharedDependencies(ctx android.ModuleContext) (android.Paths, []a if !IsValidSharedDependency(dep) { return } + sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider) + if !hasSharedLibraryInfo { + return + } if seen[ctx.OtherModuleName(dep)] { return } seen[ctx.OtherModuleName(dep)] = true deps = append(deps, dep) - sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, dep, "unstripped")) + + installDestination := sharedLibraryInfo.SharedLibrary.Base() + ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, dep, "unstripped"), installDestination} + sharedLibraries = append(sharedLibraries, ruleBuilderInstall) }) ctx.WalkDeps(func(child, parent android.Module) bool { + + // If this is a Rust module which is not rust_ffi_shared, we still want to bundle any transitive + // shared dependencies (even for rust_ffi_rlib or rust_ffi_static) + if rustmod, ok := child.(LinkableInterface); ok && rustmod.RustLibraryInterface() && !rustmod.Shared() { + if recursed[ctx.OtherModuleName(child)] { + return false + } + recursed[ctx.OtherModuleName(child)] = true + return true + } + if !IsValidSharedDependency(child) { return false } + sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, child, SharedLibraryInfoProvider) + if !hasSharedLibraryInfo { + return false + } if !seen[ctx.OtherModuleName(child)] { seen[ctx.OtherModuleName(child)] = true deps = append(deps, child) - sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, child, "unstripped")) + + installDestination := sharedLibraryInfo.SharedLibrary.Base() + ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, child, "unstripped"), installDestination} + sharedLibraries = append(sharedLibraries, ruleBuilderInstall) } if recursed[ctx.OtherModuleName(child)] { @@ -18,7 +18,7 @@ import ( "path/filepath" "strings" - "android/soong/bazel" + "android/soong/aidl_library" "github.com/google/blueprint" "android/soong/android" @@ -105,7 +105,14 @@ func genYacc(ctx android.ModuleContext, rule *android.RuleBuilder, yaccFile andr return ret } -func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile android.Path, aidlFlags string) (cppFile android.OutputPath, headerFiles android.Paths) { +func genAidl( + ctx android.ModuleContext, + rule *android.RuleBuilder, + outDirBase string, + aidlFile android.Path, + aidlHdrs android.Paths, + aidlFlags string, +) (cppFile android.OutputPath, headerFiles android.Paths) { aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base()) baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext()) shortName := baseName @@ -117,20 +124,17 @@ func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile andr shortName = strings.TrimPrefix(baseName, "I") } - outDir := android.PathForModuleGen(ctx, "aidl") + outDir := android.PathForModuleGen(ctx, outDirBase) cppFile = outDir.Join(ctx, aidlPackage, baseName+".cpp") depFile := outDir.Join(ctx, aidlPackage, baseName+".cpp.d") headerI := outDir.Join(ctx, aidlPackage, baseName+".h") headerBn := outDir.Join(ctx, aidlPackage, "Bn"+shortName+".h") headerBp := outDir.Join(ctx, aidlPackage, "Bp"+shortName+".h") - baseDir := strings.TrimSuffix(aidlFile.String(), aidlFile.Rel()) - if baseDir != "" { - aidlFlags += " -I" + baseDir - } - cmd := rule.Command() cmd.BuiltTool("aidl-cpp"). + // libc++ is default stl for aidl-cpp (a cc_binary_host module) + ImplicitTool(ctx.Config().HostCcSharedLibPath(ctx, "libc++")). FlagWithDepFile("-d", depFile). Flag("--ninja"). Flag(aidlFlags). @@ -143,6 +147,10 @@ func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile andr headerBp, }) + if aidlHdrs != nil { + cmd.Implicits(aidlHdrs) + } + return cppFile, android.Paths{ headerI, headerBn, @@ -170,41 +178,6 @@ func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.Mod }) } -type LexAttrs struct { - Srcs bazel.LabelListAttribute - Lexopts bazel.StringListAttribute -} - -type LexNames struct { - cSrcName bazel.LabelAttribute - srcName bazel.LabelAttribute -} - -func bp2BuildLex(ctx android.Bp2buildMutatorContext, moduleName string, ca compilerAttributes) LexNames { - names := LexNames{} - if !ca.lSrcs.IsEmpty() { - names.cSrcName = createLexTargetModule(ctx, moduleName+"_genlex_l", ca.lSrcs, ca.lexopts) - } - if !ca.llSrcs.IsEmpty() { - names.srcName = createLexTargetModule(ctx, moduleName+"_genlex_ll", ca.llSrcs, ca.lexopts) - } - return names -} - -func createLexTargetModule(ctx android.Bp2buildMutatorContext, name string, srcs bazel.LabelListAttribute, opts bazel.StringListAttribute) bazel.LabelAttribute { - ctx.CreateBazelTargetModule( - bazel.BazelTargetModuleProperties{ - Rule_class: "genlex", - Bzl_load_location: "//build/bazel/rules/cc:flex.bzl", - }, - android.CommonAttributes{Name: name}, - &LexAttrs{ - Srcs: srcs, - Lexopts: opts, - }) - return bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + name}} -} - func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Paths) { headerFile := android.PathForModuleGen(ctx, "sysprop", "include", syspropFile.Rel()+".h") publicHeaderFile := android.PathForModuleGen(ctx, "sysprop/public", "include", syspropFile.Rel()+".h") @@ -229,34 +202,6 @@ func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Pa return cppFile, headers.Paths() } -func bp2buildCcSysprop(ctx android.Bp2buildMutatorContext, moduleName string, minSdkVersion *string, srcs bazel.LabelListAttribute) *bazel.LabelAttribute { - labels := SyspropLibraryLabels{ - SyspropLibraryLabel: moduleName + "_sysprop_library", - StaticLibraryLabel: moduleName + "_cc_sysprop_library_static", - } - Bp2buildSysprop(ctx, labels, srcs, minSdkVersion) - return createLabelAttributeCorrespondingToSrcs(":"+labels.StaticLibraryLabel, srcs) -} - -// Creates a LabelAttribute for a given label where the value is only set for -// the same config values that have values in a given LabelListAttribute -func createLabelAttributeCorrespondingToSrcs(baseLabelName string, srcs bazel.LabelListAttribute) *bazel.LabelAttribute { - baseLabel := bazel.Label{Label: baseLabelName} - label := bazel.LabelAttribute{} - if !srcs.Value.IsNil() && !srcs.Value.IsEmpty() { - label.Value = &baseLabel - return &label - } - for axis, configToSrcs := range srcs.ConfigurableValues { - for config, val := range configToSrcs { - if !val.IsNil() && !val.IsEmpty() { - label.SetSelectValue(axis, config, baseLabel) - } - } - } - return &label -} - // Used to communicate information from the genSources method back to the library code that uses // it. type generatedSourceInfo struct { @@ -280,17 +225,29 @@ type generatedSourceInfo struct { // The files that can be used as order only dependencies in order to ensure that the sysprop // header files are up to date. syspropOrderOnlyDeps android.Paths + + // List of generated code path. + // ex) '*.cpp' files generated from '*.ll / *.yy'. + generatedSources android.Paths } -func genSources(ctx android.ModuleContext, srcFiles android.Paths, - buildFlags builderFlags) (android.Paths, android.Paths, generatedSourceInfo) { +func genSources( + ctx android.ModuleContext, + aidlLibraryInfos []aidl_library.AidlLibraryInfo, + srcFiles android.Paths, + buildFlags builderFlags, +) (android.Paths, android.Paths, generatedSourceInfo) { var info generatedSourceInfo var deps android.Paths var rsFiles android.Paths + // aidlRule supports compiling aidl files from srcs prop while aidlLibraryRule supports + // compiling aidl files from aidl_library modules specified in aidl.libs prop. + // The rules are separated so that they don't wipe out the other's outputDir var aidlRule *android.RuleBuilder + var aidlLibraryRule *android.RuleBuilder var yaccRule_ *android.RuleBuilder yaccRule := func() *android.RuleBuilder { @@ -301,36 +258,51 @@ func genSources(ctx android.ModuleContext, srcFiles android.Paths, return yaccRule_ } + var generatedSources android.Paths = nil + for i, srcFile := range srcFiles { switch srcFile.Ext() { case ".y": cFile := android.GenPathWithExt(ctx, "yacc", srcFile, "c") srcFiles[i] = cFile deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cFile, buildFlags.yacc)...) + generatedSources = append(generatedSources, cFile) case ".yy": cppFile := android.GenPathWithExt(ctx, "yacc", srcFile, "cpp") srcFiles[i] = cppFile deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cppFile, buildFlags.yacc)...) + generatedSources = append(generatedSources, cppFile) case ".l": cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c") srcFiles[i] = cFile genLex(ctx, srcFile, cFile, buildFlags.lex) + generatedSources = append(generatedSources, cFile) case ".ll": cppFile := android.GenPathWithExt(ctx, "lex", srcFile, "cpp") srcFiles[i] = cppFile genLex(ctx, srcFile, cppFile, buildFlags.lex) + generatedSources = append(generatedSources, cppFile) case ".proto": ccFile, headerFile := genProto(ctx, srcFile, buildFlags) srcFiles[i] = ccFile info.protoHeaders = append(info.protoHeaders, headerFile) // Use the generated header as an order only dep to ensure that it is up to date when needed. info.protoOrderOnlyDeps = append(info.protoOrderOnlyDeps, headerFile) + generatedSources = append(generatedSources, ccFile) case ".aidl": if aidlRule == nil { aidlRule = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "aidl"), android.PathForModuleGen(ctx, "aidl.sbox.textproto")) } - cppFile, aidlHeaders := genAidl(ctx, aidlRule, srcFile, buildFlags.aidlFlags) + baseDir := strings.TrimSuffix(srcFile.String(), srcFile.Rel()) + cppFile, aidlHeaders := genAidl( + ctx, + aidlRule, + "aidl", + srcFile, + nil, + buildFlags.aidlFlags+" -I"+baseDir, + ) srcFiles[i] = cppFile info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...) @@ -338,10 +310,12 @@ func genSources(ctx android.ModuleContext, srcFiles android.Paths, // needed. // TODO: Reduce the size of the ninja file by using one order only dep for the whole rule info.aidlOrderOnlyDeps = append(info.aidlOrderOnlyDeps, aidlHeaders...) + generatedSources = append(generatedSources, cppFile) case ".rscript", ".fs": cppFile := rsGeneratedCppFile(ctx, srcFile) rsFiles = append(rsFiles, srcFiles[i]) srcFiles[i] = cppFile + generatedSources = append(generatedSources, cppFile) case ".sysprop": cppFile, headerFiles := genSysprop(ctx, srcFile) srcFiles[i] = cppFile @@ -349,6 +323,35 @@ func genSources(ctx android.ModuleContext, srcFiles android.Paths, // Use the generated headers as order only deps to ensure that they are up to date when // needed. info.syspropOrderOnlyDeps = append(info.syspropOrderOnlyDeps, headerFiles...) + generatedSources = append(generatedSources, cppFile) + } + } + + info.generatedSources = generatedSources + + for _, aidlLibraryInfo := range aidlLibraryInfos { + if aidlLibraryRule == nil { + aidlLibraryRule = android.NewRuleBuilder(pctx, ctx).Sbox( + android.PathForModuleGen(ctx, "aidl_library"), + android.PathForModuleGen(ctx, "aidl_library.sbox.textproto"), + ).SandboxInputs() + } + for _, aidlSrc := range aidlLibraryInfo.Srcs { + cppFile, aidlHeaders := genAidl( + ctx, + aidlLibraryRule, + "aidl_library", + aidlSrc, + aidlLibraryInfo.Hdrs.ToList(), + buildFlags.aidlFlags, + ) + + srcFiles = append(srcFiles, cppFile) + info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...) + // Use the generated headers as order only deps to ensure that they are up to date when + // needed. + // TODO: Reduce the size of the ninja file by using one order only dep for the whole rule + info.aidlOrderOnlyDeps = append(info.aidlOrderOnlyDeps, aidlHeaders...) } } @@ -356,6 +359,10 @@ func genSources(ctx android.ModuleContext, srcFiles android.Paths, aidlRule.Build("aidl", "gen aidl") } + if aidlLibraryRule != nil { + aidlLibraryRule.Build("aidl_library", "gen aidl_library") + } + if yaccRule_ != nil { yaccRule_.Build("yacc", "gen yacc") } diff --git a/cc/gen_test.go b/cc/gen_test.go index 85df33312..439f0a996 100644 --- a/cc/gen_test.go +++ b/cc/gen_test.go @@ -67,7 +67,7 @@ func TestGen(t *testing.T) { t.Errorf("missing aidl includes in global flags") } - aidlCommand := android.RuleBuilderSboxProtoForTests(t, aidlManifest).Commands[0].GetCommand() + aidlCommand := android.RuleBuilderSboxProtoForTests(t, ctx, aidlManifest).Commands[0].GetCommand() if !strings.Contains(aidlCommand, "-Isub") { t.Errorf("aidl command for c.aidl should contain \"-Isub\", but was %q", aidlCommand) } diff --git a/cc/generated_cc_library.go b/cc/generated_cc_library.go new file mode 100644 index 000000000..b1084e4e5 --- /dev/null +++ b/cc/generated_cc_library.go @@ -0,0 +1,34 @@ +// 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 ( + "android/soong/android" +) + +func GeneratedCcLibraryModuleFactory(moduleName string, callbacks Generator) android.Module { + module, _ := NewLibrary(android.HostAndDeviceSupported) + + // Can be used as both a static and a shared library. + module.sdkMemberTypes = []android.SdkMemberType{ + sharedLibrarySdkMemberType, + staticLibrarySdkMemberType, + staticAndSharedLibrarySdkMemberType, + } + + module.generators = append(module.generators, callbacks) + + return module.Init() +} diff --git a/cc/genrule.go b/cc/genrule.go index d1c4c2a2f..fe3b127ea 100644 --- a/cc/genrule.go +++ b/cc/genrule.go @@ -19,7 +19,6 @@ import ( "android/soong/android" "android/soong/genrule" - "android/soong/snapshot" ) func init() { @@ -62,7 +61,8 @@ func GenRuleFactory() android.Module { android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibBoth) android.InitApexModule(module) - android.InitBazelModule(module) + + android.InitDefaultableModule(module) return module } @@ -79,16 +79,16 @@ var _ android.ImageInterface = (*GenruleExtraProperties)(nil) func (g *GenruleExtraProperties) ImageMutatorBegin(ctx android.BaseModuleContext) {} -func (g *GenruleExtraProperties) CoreVariantNeeded(ctx android.BaseModuleContext) bool { - if ctx.DeviceConfig().VndkVersion() == "" { - return true - } +func (g *GenruleExtraProperties) VendorVariantNeeded(ctx android.BaseModuleContext) bool { + return Bool(g.Vendor_available) || Bool(g.Odm_available) || ctx.SocSpecific() || ctx.DeviceSpecific() +} - if ctx.DeviceConfig().ProductVndkVersion() != "" && ctx.ProductSpecific() { - return false - } +func (g *GenruleExtraProperties) ProductVariantNeeded(ctx android.BaseModuleContext) bool { + return Bool(g.Product_available) || ctx.ProductSpecific() +} - return !(ctx.SocSpecific() || ctx.DeviceSpecific()) +func (g *GenruleExtraProperties) CoreVariantNeeded(ctx android.BaseModuleContext) bool { + return !(ctx.SocSpecific() || ctx.DeviceSpecific() || ctx.ProductSpecific()) } func (g *GenruleExtraProperties) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { @@ -106,47 +106,12 @@ func (g *GenruleExtraProperties) DebugRamdiskVariantNeeded(ctx android.BaseModul func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { // If the build is using a snapshot, the recovery variant under AOSP directories // is not needed. - recoverySnapshotVersion := ctx.DeviceConfig().RecoverySnapshotVersion() - if recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" && - !snapshot.IsRecoveryProprietaryModule(ctx) { - return false - } else { - return Bool(g.Recovery_available) - } + return Bool(g.Recovery_available) } func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.BaseModuleContext) []string { - if ctx.DeviceConfig().VndkVersion() == "" { - return nil - } - - var variants []string - if Bool(g.Vendor_available) || Bool(g.Odm_available) || ctx.SocSpecific() || ctx.DeviceSpecific() { - vndkVersion := ctx.DeviceConfig().VndkVersion() - // If vndkVersion is current, we can always use PlatformVndkVersion. - // If not, we assume modules under proprietary paths are compatible for - // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, that is - // PLATFORM_VNDK_VERSION. - if vndkVersion == "current" || !snapshot.IsVendorProprietaryModule(ctx) { - variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion()) - } else { - variants = append(variants, VendorVariationPrefix+vndkVersion) - } - } - - if ctx.DeviceConfig().ProductVndkVersion() == "" { - return variants - } - - if Bool(g.Product_available) || ctx.ProductSpecific() { - variants = append(variants, ProductVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion()) - if vndkVersion := ctx.DeviceConfig().ProductVndkVersion(); vndkVersion != "current" { - variants = append(variants, ProductVariationPrefix+vndkVersion) - } - } - - return variants + return nil } -func (g *GenruleExtraProperties) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) { +func (g *GenruleExtraProperties) SetImageVariation(ctx android.BaseModuleContext, variation string) { } diff --git a/cc/genrule_test.go b/cc/genrule_test.go index 0d16e6261..b3d511679 100644 --- a/cc/genrule_test.go +++ b/cc/genrule_test.go @@ -16,6 +16,7 @@ package cc import ( "reflect" + "slices" "testing" "android/soong/android" @@ -178,7 +179,7 @@ func TestCmdPrefix(t *testing.T) { android.OptionalFixturePreparer(tt.preparer), ).RunTestWithBp(t, bp) gen := result.ModuleForTests("gen", tt.variant) - sboxProto := android.RuleBuilderSboxProtoForTests(t, gen.Output("genrule.sbox.textproto")) + sboxProto := android.RuleBuilderSboxProtoForTests(t, result.TestContext, gen.Output("genrule.sbox.textproto")) cmd := *sboxProto.Commands[0].Command android.AssertStringDoesContain(t, "incorrect CC_ARCH", cmd, "CC_ARCH="+tt.arch+" ") android.AssertStringDoesContain(t, "incorrect CC_NATIVE_BRIDGE", cmd, "CC_NATIVE_BRIDGE="+tt.nativeBridge+" ") @@ -186,3 +187,70 @@ func TestCmdPrefix(t *testing.T) { }) } } + +func TestVendorProductVariantGenrule(t *testing.T) { + bp := ` + cc_genrule { + name: "gen", + tool_files: ["tool"], + cmd: "$(location tool) $(in) $(out)", + out: ["out"], + vendor_available: true, + product_available: true, + } + ` + t.Helper() + ctx := PrepareForIntegrationTestWithCc.RunTestWithBp(t, bp) + + variants := ctx.ModuleVariantsForTests("gen") + if !slices.Contains(variants, "android_vendor_arm64_armv8-a") { + t.Errorf(`expected vendor variant, but does not exist in %v`, variants) + } + if !slices.Contains(variants, "android_product_arm64_armv8-a") { + t.Errorf(`expected product variant, but does not exist in %v`, variants) + } +} + +// cc_genrule is initialized to android.InitAndroidArchModule +// that is an architecture-specific Android module. +// So testing properties tagged with `android:"arch_variant"` +// for cc_genrule. +func TestMultilibGenruleOut(t *testing.T) { + bp := ` + cc_genrule { + name: "gen", + cmd: "cp $(in) $(out)", + srcs: ["foo"], + multilib: { + lib32: { + out: [ + "subdir32/external-module32", + ], + }, + lib64: { + out: [ + "subdir64/external-module64", + ], + }, + }, + } + ` + result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, bp) + gen_32bit := result.ModuleForTests("gen", "android_arm_armv7-a-neon").OutputFiles(t, "") + android.AssertPathsEndWith(t, + "genrule_out", + []string{ + "subdir32/external-module32", + }, + gen_32bit, + ) + + gen_64bit := result.ModuleForTests("gen", "android_arm64_armv8-a").OutputFiles(t, "") + android.AssertPathsEndWith(t, + "genrule_out", + []string{ + "subdir64/external-module64", + }, + gen_64bit, + ) +} diff --git a/cc/image.go b/cc/image.go index e65a9aadb..2e52ccc63 100644 --- a/cc/image.go +++ b/cc/image.go @@ -17,12 +17,11 @@ package cc // functions to determine where a module is installed, etc. import ( - "fmt" - "reflect" "strings" "android/soong/android" - "android/soong/snapshot" + + "github.com/google/blueprint/proptools" ) var _ android.ImageInterface = (*Module)(nil) @@ -49,18 +48,6 @@ const ( ProductVariationPrefix = "product." ) -func (ctx *moduleContext) ProductSpecific() bool { - return ctx.ModuleContext.ProductSpecific() || ctx.mod.productSpecificModuleContext() -} - -func (ctx *moduleContext) SocSpecific() bool { - return ctx.ModuleContext.SocSpecific() || ctx.mod.socSpecificModuleContext() -} - -func (ctx *moduleContext) DeviceSpecific() bool { - return ctx.ModuleContext.DeviceSpecific() || ctx.mod.deviceSpecificModuleContext() -} - func (ctx *moduleContextImpl) inProduct() bool { return ctx.mod.InProduct() } @@ -81,20 +68,20 @@ func (ctx *moduleContextImpl) inRecovery() bool { return ctx.mod.InRecovery() } -func (c *Module) productSpecificModuleContext() bool { +func (c *Module) InstallInProduct() bool { // Additionally check if this module is inProduct() that means it is a "product" variant of a // module. As well as product specific modules, product variants must be installed to /product. return c.InProduct() } -func (c *Module) socSpecificModuleContext() bool { +func (c *Module) InstallInVendor() bool { // Additionally check if this module is inVendor() that means it is a "vendor" variant of a // module. As well as SoC specific modules, vendor variants must be installed to /vendor // unless they have "odm_available: true". return c.HasVendorVariant() && c.InVendor() && !c.VendorVariantToOdm() } -func (c *Module) deviceSpecificModuleContext() bool { +func (c *Module) InstallInOdm() bool { // Some vendor variants want to be installed to /odm by setting "odm_available: true". return c.InVendor() && c.VendorVariantToOdm() } @@ -122,12 +109,18 @@ func (c *Module) HasNonSystemVariants() bool { // Returns true if the module is "product" variant. Usually these modules are installed in /product func (c *Module) InProduct() bool { - return c.Properties.ImageVariationPrefix == ProductVariationPrefix + return c.Properties.ImageVariation == android.ProductVariation } // Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor func (c *Module) InVendor() bool { - return c.Properties.ImageVariationPrefix == VendorVariationPrefix + return c.Properties.ImageVariation == android.VendorVariation +} + +// Returns true if the module is "vendor" or "product" variant. This replaces previous UseVndk usages +// which were misused to check if the module variant is vendor or product. +func (c *Module) InVendorOrProduct() bool { + return c.InVendor() || c.InProduct() } func (c *Module) InRamdisk() bool { @@ -154,52 +147,6 @@ func (c *Module) OnlyInRecovery() bool { return c.ModuleBase.InstallInRecovery() } -func visitPropsAndCompareVendorAndProductProps(v reflect.Value) bool { - if v.Kind() != reflect.Struct { - return true - } - for i := 0; i < v.NumField(); i++ { - prop := v.Field(i) - if prop.Kind() == reflect.Struct && v.Type().Field(i).Name == "Target" { - vendor_prop := prop.FieldByName("Vendor") - product_prop := prop.FieldByName("Product") - if vendor_prop.Kind() != reflect.Struct && product_prop.Kind() != reflect.Struct { - // Neither Target.Vendor nor Target.Product is defined - continue - } - if vendor_prop.Kind() != reflect.Struct || product_prop.Kind() != reflect.Struct || - !reflect.DeepEqual(vendor_prop.Interface(), product_prop.Interface()) { - // If only one of either Target.Vendor or Target.Product is - // defined or they have different values, it fails the build - // since VNDK must have the same properties for both vendor - // and product variants. - return false - } - } else if !visitPropsAndCompareVendorAndProductProps(prop) { - // Visit the substructures to find Target.Vendor and Target.Product - return false - } - } - return true -} - -// In the case of VNDK, vendor and product variants must have the same properties. -// VNDK installs only one file and shares it for both vendor and product modules on -// runtime. We may not define different versions of a VNDK lib for each partition. -// This function is used only for the VNDK modules that is available to both vendor -// and product partitions. -func (c *Module) compareVendorAndProductProps() bool { - if !c.IsVndk() && !Bool(c.VendorProperties.Product_available) { - panic(fmt.Errorf("This is only for product available VNDK libs. %q is not a VNDK library or not product available", c.Name())) - } - for _, properties := range c.GetProperties() { - if !visitPropsAndCompareVendorAndProductProps(reflect.ValueOf(properties).Elem()) { - return false - } - } - return true -} - // ImageMutatableModule provides a common image mutation interface for LinkableInterface modules. type ImageMutatableModule interface { android.Module @@ -252,67 +199,20 @@ type ImageMutatableModule interface { // SetCoreVariantNeeded sets whether the Core Variant is needed. SetCoreVariantNeeded(b bool) + + // SetProductVariantNeeded sets whether the Product Variant is needed. + SetProductVariantNeeded(b bool) + + // SetVendorVariantNeeded sets whether the Vendor Variant is needed. + SetVendorVariantNeeded(b bool) } var _ ImageMutatableModule = (*Module)(nil) func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { - m.CheckVndkProperties(mctx) MutateImage(mctx, m) } -// CheckVndkProperties checks whether the VNDK-related properties are set correctly. -// If properties are not set correctly, results in a module context property error. -func (m *Module) CheckVndkProperties(mctx android.BaseModuleContext) { - vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific() - productSpecific := mctx.ProductSpecific() - - if vndkdep := m.vndkdep; vndkdep != nil { - if vndkdep.isVndk() { - if vendorSpecific || productSpecific { - if !vndkdep.isVndkExt() { - mctx.PropertyErrorf("vndk", - "must set `extends: \"...\"` to vndk extension") - } else if Bool(m.VendorProperties.Vendor_available) { - mctx.PropertyErrorf("vendor_available", - "must not set at the same time as `vndk: {extends: \"...\"}`") - } else if Bool(m.VendorProperties.Product_available) { - mctx.PropertyErrorf("product_available", - "must not set at the same time as `vndk: {extends: \"...\"}`") - } - } else { - if vndkdep.isVndkExt() { - mctx.PropertyErrorf("vndk", - "must set `vendor: true` or `product_specific: true` to set `extends: %q`", - m.getVndkExtendsModuleName()) - } - if !Bool(m.VendorProperties.Vendor_available) { - mctx.PropertyErrorf("vndk", - "vendor_available must be set to true when `vndk: {enabled: true}`") - } - if Bool(m.VendorProperties.Product_available) { - // If a VNDK module creates both product and vendor variants, they - // must have the same properties since they share a single VNDK - // library on runtime. - if !m.compareVendorAndProductProps() { - mctx.ModuleErrorf("product properties must have the same values with the vendor properties for VNDK modules") - } - } - } - } else { - if vndkdep.isVndkSp() { - mctx.PropertyErrorf("vndk", - "must set `enabled: true` to set `support_system_process: true`") - } - if vndkdep.isVndkExt() { - mctx.PropertyErrorf("vndk", - "must set `enabled: true` to set `extends: %q`", - m.getVndkExtendsModuleName()) - } - } - } -} - func (m *Module) VendorAvailable() bool { return Bool(m.VendorProperties.Vendor_available) } @@ -365,6 +265,14 @@ func (m *Module) SetCoreVariantNeeded(b bool) { m.Properties.CoreVariantNeeded = b } +func (m *Module) SetProductVariantNeeded(b bool) { + m.Properties.ProductVariantNeeded = b +} + +func (m *Module) SetVendorVariantNeeded(b bool) { + m.Properties.VendorVariantNeeded = b +} + func (m *Module) SnapshotVersion(mctx android.BaseModuleContext) string { if snapshot, ok := m.linker.(SnapshotInterface); ok { return snapshot.Version() @@ -417,78 +325,36 @@ func MutateImage(mctx android.BaseModuleContext, m ImageMutatableModule) { } } + var vendorVariantNeeded bool = false + var productVariantNeeded bool = false var coreVariantNeeded bool = false var ramdiskVariantNeeded bool = false var vendorRamdiskVariantNeeded bool = false var recoveryVariantNeeded bool = false - var vendorVariants []string - var productVariants []string - - platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion() - boardVndkVersion := mctx.DeviceConfig().VndkVersion() - productVndkVersion := mctx.DeviceConfig().ProductVndkVersion() - recoverySnapshotVersion := mctx.DeviceConfig().RecoverySnapshotVersion() - usingRecoverySnapshot := recoverySnapshotVersion != "current" && - recoverySnapshotVersion != "" - needVndkVersionVendorVariantForLlndk := false - if boardVndkVersion != "" { - boardVndkApiLevel, err := android.ApiLevelFromUser(mctx, boardVndkVersion) - if err == nil && !boardVndkApiLevel.IsPreview() { - // VNDK snapshot newer than v30 has LLNDK stub libraries. - // Only the VNDK version less than or equal to v30 requires generating the vendor - // variant of the VNDK version from the source tree. - needVndkVersionVendorVariantForLlndk = boardVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(mctx, "30")) - } - } - if boardVndkVersion == "current" { - boardVndkVersion = platformVndkVersion - } - if productVndkVersion == "current" { - productVndkVersion = platformVndkVersion - } - if m.NeedsLlndkVariants() { // This is an LLNDK library. The implementation of the library will be on /system, // and vendor and product variants will be created with LLNDK stubs. // The LLNDK libraries need vendor variants even if there is no VNDK. coreVariantNeeded = true - if platformVndkVersion != "" { - vendorVariants = append(vendorVariants, platformVndkVersion) - productVariants = append(productVariants, platformVndkVersion) - } - // Generate vendor variants for boardVndkVersion only if the VNDK snapshot does not - // provide the LLNDK stub libraries. - if needVndkVersionVendorVariantForLlndk { - vendorVariants = append(vendorVariants, boardVndkVersion) - } - if productVndkVersion != "" { - productVariants = append(productVariants, productVndkVersion) - } + vendorVariantNeeded = true + productVariantNeeded = true + } else if m.NeedsVendorPublicLibraryVariants() { // A vendor public library has the implementation on /vendor, with stub variants // for system and product. coreVariantNeeded = true - vendorVariants = append(vendorVariants, boardVndkVersion) - if platformVndkVersion != "" { - productVariants = append(productVariants, platformVndkVersion) - } - if productVndkVersion != "" { - productVariants = append(productVariants, productVndkVersion) - } - } else if boardVndkVersion == "" { - // If the device isn't compiling against the VNDK, we always - // use the core mode. - coreVariantNeeded = true + vendorVariantNeeded = true + productVariantNeeded = true } else if m.IsSnapshotPrebuilt() { // Make vendor variants only for the versions in BOARD_VNDK_VERSION and // PRODUCT_EXTRA_VNDK_VERSIONS. if m.InstallInRecovery() { recoveryVariantNeeded = true } else { - vendorVariants = append(vendorVariants, m.SnapshotVersion(mctx)) + m.AppendExtraVariant(VendorVariationPrefix + m.SnapshotVersion(mctx)) } - } else if m.HasNonSystemVariants() && !m.IsVndkExt() { + } else if m.HasNonSystemVariants() { // This will be available to /system unless it is product_specific // which will be handled later. coreVariantNeeded = true @@ -497,40 +363,16 @@ func MutateImage(mctx android.BaseModuleContext, m ImageMutatableModule) { // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or // PLATFORM_VNDK_VERSION. if m.HasVendorVariant() { - if snapshot.IsVendorProprietaryModule(mctx) { - vendorVariants = append(vendorVariants, boardVndkVersion) - } else { - vendorVariants = append(vendorVariants, platformVndkVersion) - } + vendorVariantNeeded = true } // product_available modules are available to /product. if m.HasProductVariant() { - productVariants = append(productVariants, platformVndkVersion) - // VNDK is always PLATFORM_VNDK_VERSION - if !m.IsVndk() { - productVariants = append(productVariants, productVndkVersion) - } + productVariantNeeded = true } } else if vendorSpecific && m.SdkVersion() == "" { // This will be available in /vendor (or /odm) only - - // kernel_headers is a special module type whose exported headers - // are coming from DeviceKernelHeaders() which is always vendor - // dependent. They'll always have both vendor variants. - // For other modules, we assume that modules under proprietary - // paths are compatible for BOARD_VNDK_VERSION. The other modules - // are regarded as AOSP, which is PLATFORM_VNDK_VERSION. - if m.KernelHeadersDecorator() { - vendorVariants = append(vendorVariants, - platformVndkVersion, - boardVndkVersion, - ) - } else if snapshot.IsVendorProprietaryModule(mctx) { - vendorVariants = append(vendorVariants, boardVndkVersion) - } else { - vendorVariants = append(vendorVariants, platformVndkVersion) - } + vendorVariantNeeded = true } else { // This is either in /system (or similar: /data), or is a // module built with the NDK. Modules built with the NDK @@ -538,17 +380,10 @@ func MutateImage(mctx android.BaseModuleContext, m ImageMutatableModule) { coreVariantNeeded = true } - if boardVndkVersion != "" && productVndkVersion != "" { - if coreVariantNeeded && productSpecific && m.SdkVersion() == "" { - // The module has "product_specific: true" that does not create core variant. - coreVariantNeeded = false - productVariants = append(productVariants, productVndkVersion) - } - } else { - // Unless PRODUCT_PRODUCT_VNDK_VERSION is set, product partition has no - // restriction to use system libs. - // No product variants defined in this case. - productVariants = []string{} + if coreVariantNeeded && productSpecific && m.SdkVersion() == "" { + // The module has "product_specific: true" that does not create core variant. + coreVariantNeeded = false + productVariantNeeded = true } if m.RamdiskAvailable() { @@ -578,37 +413,32 @@ func MutateImage(mctx android.BaseModuleContext, m ImageMutatableModule) { coreVariantNeeded = false } - // If using a snapshot, the recovery variant under AOSP directories is not needed, - // except for kernel headers, which needs all variants. - if !m.KernelHeadersDecorator() && - !m.IsSnapshotPrebuilt() && - usingRecoverySnapshot && - !snapshot.IsRecoveryProprietaryModule(mctx) { - recoveryVariantNeeded = false - } - - for _, variant := range android.FirstUniqueStrings(vendorVariants) { - m.AppendExtraVariant(VendorVariationPrefix + variant) - } - - for _, variant := range android.FirstUniqueStrings(productVariants) { - m.AppendExtraVariant(ProductVariationPrefix + variant) - } - m.SetRamdiskVariantNeeded(ramdiskVariantNeeded) m.SetVendorRamdiskVariantNeeded(vendorRamdiskVariantNeeded) m.SetRecoveryVariantNeeded(recoveryVariantNeeded) m.SetCoreVariantNeeded(coreVariantNeeded) + m.SetProductVariantNeeded(productVariantNeeded) + m.SetVendorVariantNeeded(vendorVariantNeeded) // Disable the module if no variants are needed. if !ramdiskVariantNeeded && !recoveryVariantNeeded && !coreVariantNeeded && + !productVariantNeeded && + !vendorVariantNeeded && len(m.ExtraVariants()) == 0 { m.Disable() } } +func (c *Module) VendorVariantNeeded(ctx android.BaseModuleContext) bool { + return c.Properties.VendorVariantNeeded +} + +func (c *Module) ProductVariantNeeded(ctx android.BaseModuleContext) bool { + return c.Properties.ProductVariantNeeded +} + func (c *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool { return c.Properties.CoreVariantNeeded } @@ -643,6 +473,10 @@ func squashVendorSrcs(m *Module) { lib.baseCompiler.Properties.Exclude_generated_sources = append(lib.baseCompiler.Properties.Exclude_generated_sources, lib.baseCompiler.Properties.Target.Vendor.Exclude_generated_sources...) + + if lib.Properties.Target.Vendor.No_stubs { + proptools.Clear(&lib.Properties.Stubs) + } } } @@ -656,6 +490,10 @@ func squashProductSrcs(m *Module) { lib.baseCompiler.Properties.Exclude_generated_sources = append(lib.baseCompiler.Properties.Exclude_generated_sources, lib.baseCompiler.Properties.Target.Product.Exclude_generated_sources...) + + if lib.Properties.Target.Product.No_stubs { + proptools.Clear(&lib.Properties.Stubs) + } } } @@ -678,32 +516,35 @@ func squashVendorRamdiskSrcs(m *Module) { } } -func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) { - m := module.(*Module) +func squashRamdiskSrcs(m *Module) { + if lib, ok := m.compiler.(*libraryDecorator); ok { + lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs, lib.baseCompiler.Properties.Target.Ramdisk.Exclude_srcs...) + } +} + +func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string) { if variant == android.RamdiskVariation { - m.MakeAsPlatform() + c.MakeAsPlatform() + squashRamdiskSrcs(c) } else if variant == android.VendorRamdiskVariation { - m.MakeAsPlatform() - squashVendorRamdiskSrcs(m) + c.MakeAsPlatform() + squashVendorRamdiskSrcs(c) } else if variant == android.RecoveryVariation { - m.MakeAsPlatform() - squashRecoverySrcs(m) - } else if strings.HasPrefix(variant, VendorVariationPrefix) { - m.Properties.ImageVariationPrefix = VendorVariationPrefix - m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix) - squashVendorSrcs(m) - - // Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION. - // Hide other vendor variants to avoid collision. - vndkVersion := ctx.DeviceConfig().VndkVersion() - if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion { - m.Properties.HideFromMake = true - m.HideFromMake() + c.MakeAsPlatform() + squashRecoverySrcs(c) + } else if strings.HasPrefix(variant, android.VendorVariation) { + c.Properties.ImageVariation = android.VendorVariation + + if strings.HasPrefix(variant, VendorVariationPrefix) { + c.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix) + } + squashVendorSrcs(c) + } else if strings.HasPrefix(variant, android.ProductVariation) { + c.Properties.ImageVariation = android.ProductVariation + if strings.HasPrefix(variant, ProductVariationPrefix) { + c.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix) } - } else if strings.HasPrefix(variant, ProductVariationPrefix) { - m.Properties.ImageVariationPrefix = ProductVariationPrefix - m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix) - squashProductSrcs(m) + squashProductSrcs(c) } if c.NeedsVendorPublicLibraryVariants() && diff --git a/cc/installer.go b/cc/installer.go index 716a0dfc6..30f9612d3 100644 --- a/cc/installer.go +++ b/cc/installer.go @@ -59,6 +59,8 @@ type baseInstaller struct { relative string location installLocation + installDeps android.InstallPaths + path android.InstallPath } @@ -85,7 +87,7 @@ func (installer *baseInstaller) installDir(ctx ModuleContext) android.InstallPat } else if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) { dir = filepath.Join(dir, ctx.Arch().ArchType.String()) } - if installer.location == InstallInData && ctx.useVndk() { + if installer.location == InstallInData && ctx.InVendorOrProduct() { if ctx.inProduct() { dir = filepath.Join(dir, "product") } else { @@ -97,11 +99,12 @@ func (installer *baseInstaller) installDir(ctx ModuleContext) android.InstallPat } func (installer *baseInstaller) install(ctx ModuleContext, file android.Path) { - installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file) + installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file, installer.installDeps...) } -func (installer *baseInstaller) installExecutable(ctx ModuleContext, file android.Path) { - installer.path = ctx.InstallExecutable(installer.installDir(ctx), file.Base(), file) +func (installer *baseInstaller) installTestData(ctx ModuleContext, data []android.DataPath) { + installedData := ctx.InstallTestData(installer.installDir(ctx), data) + installer.installDeps = append(installer.installDeps, installedData...) } func (installer *baseInstaller) everInstallable() bool { diff --git a/cc/kernel_headers.go b/cc/kernel_headers.go index 9ea988a42..4f685becc 100644 --- a/cc/kernel_headers.go +++ b/cc/kernel_headers.go @@ -34,7 +34,7 @@ func (stub *kernelHeadersDecorator) link(ctx ModuleContext, flags Flags, deps Pa // kernel_headers retrieves the list of kernel headers directories from // TARGET_BOARD_KERNEL_HEADERS and TARGET_PRODUCT_KERNEL_HEADERS variables in // a makefile for compilation. See -// https://android.googlesource.com/platform/build/+/master/core/config.mk +// https://android.googlesource.com/platform/build/+/main/core/config.mk // for more details on them. func kernelHeadersFactory() android.Module { module, library := NewLibrary(android.HostAndDeviceSupported) diff --git a/cc/library.go b/cc/library.go index 7051f723c..560b1ae40 100644 --- a/cc/library.go +++ b/cc/library.go @@ -24,8 +24,6 @@ import ( "sync" "android/soong/android" - "android/soong/bazel" - "android/soong/bazel/cquery" "github.com/google/blueprint" "github.com/google/blueprint/pathtools" @@ -93,6 +91,13 @@ type LibraryProperties struct { Suffix *string `android:"arch_variant"` Header_abi_checker headerAbiCheckerProperties + + // Disable stubs for vendor/product variants + // This is a workaround to keep `stubs` only for "core" variant (not product/vendor). + // It would be nice if we could put `stubs` into a `target: { core: {} }` + // block but it's not supported in soong yet. This could be removed/simplified once we have + // a better syntax. + No_stubs bool } Platform struct { @@ -144,7 +149,7 @@ type StaticOrSharedProperties struct { Sanitized Sanitized `android:"arch_variant"` - Cflags []string `android:"arch_variant"` + Cflags proptools.Configurable[[]string] `android:"arch_variant"` Enabled *bool `android:"arch_variant"` Whole_static_libs []string `android:"arch_variant"` @@ -185,7 +190,7 @@ type FlagExporterProperties struct { // be added to the include path (using -I) for this module and any module that links // against this module. Directories listed in export_include_dirs do not need to be // listed in local_include_dirs. - Export_include_dirs []string `android:"arch_variant,variant_prepend"` + Export_include_dirs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"` // list of directories that will be added to the system include path // using -isystem for this module and any module that links against this module. @@ -214,421 +219,6 @@ func RegisterLibraryBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("cc_library_host_shared", LibraryHostSharedFactory) } -// TODO(b/199902614): Can this be factored to share with the other Attributes? -// For bp2build conversion. -type bazelCcLibraryAttributes struct { - // Attributes pertaining to both static and shared variants. - Srcs bazel.LabelListAttribute - Srcs_c bazel.LabelListAttribute - Srcs_as bazel.LabelListAttribute - - Copts bazel.StringListAttribute - Cppflags bazel.StringListAttribute - Conlyflags bazel.StringListAttribute - Asflags bazel.StringListAttribute - - Hdrs bazel.LabelListAttribute - - Deps bazel.LabelListAttribute - Implementation_deps bazel.LabelListAttribute - Dynamic_deps bazel.LabelListAttribute - Implementation_dynamic_deps bazel.LabelListAttribute - Whole_archive_deps bazel.LabelListAttribute - Implementation_whole_archive_deps bazel.LabelListAttribute - System_dynamic_deps bazel.LabelListAttribute - - Export_includes bazel.StringListAttribute - Export_system_includes bazel.StringListAttribute - Local_includes bazel.StringListAttribute - Absolute_includes bazel.StringListAttribute - Linkopts bazel.StringListAttribute - Rtti bazel.BoolAttribute - - Stl *string - Cpp_std *string - C_std *string - - // This is shared only. - Additional_linker_inputs bazel.LabelListAttribute - - // Common properties shared between both shared and static variants. - Shared staticOrSharedAttributes - Static staticOrSharedAttributes - - Strip stripAttributes - - Features bazel.StringListAttribute -} - -type aidlLibraryAttributes struct { - Srcs bazel.LabelListAttribute - Include_dir *string - Tags bazel.StringListAttribute -} - -type ccAidlLibraryAttributes struct { - Deps bazel.LabelListAttribute - Implementation_deps bazel.LabelListAttribute - Implementation_dynamic_deps bazel.LabelListAttribute - Tags bazel.StringListAttribute - sdkAttributes -} - -type stripAttributes struct { - Keep_symbols bazel.BoolAttribute - Keep_symbols_and_debug_frame bazel.BoolAttribute - Keep_symbols_list bazel.StringListAttribute - All bazel.BoolAttribute - None bazel.BoolAttribute -} - -func stripAttrsFromLinkerAttrs(la *linkerAttributes) stripAttributes { - return stripAttributes{ - Keep_symbols: la.stripKeepSymbols, - Keep_symbols_and_debug_frame: la.stripKeepSymbolsAndDebugFrame, - Keep_symbols_list: la.stripKeepSymbolsList, - All: la.stripAll, - None: la.stripNone, - } -} - -func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) { - sharedAttrs := bp2BuildParseSharedProps(ctx, m) - staticAttrs := bp2BuildParseStaticProps(ctx, m) - baseAttributes := bp2BuildParseBaseProps(ctx, m) - compilerAttrs := baseAttributes.compilerAttributes - linkerAttrs := baseAttributes.linkerAttributes - exportedIncludes := bp2BuildParseExportedIncludes(ctx, m, &compilerAttrs.includes) - - srcs := compilerAttrs.srcs - - sharedAttrs.Dynamic_deps.Add(baseAttributes.protoDependency) - staticAttrs.Deps.Add(baseAttributes.protoDependency) - - asFlags := compilerAttrs.asFlags - if compilerAttrs.asSrcs.IsEmpty() && sharedAttrs.Srcs_as.IsEmpty() && staticAttrs.Srcs_as.IsEmpty() { - // Skip asflags for BUILD file simplicity if there are no assembly sources. - asFlags = bazel.MakeStringListAttribute(nil) - } - - staticCommonAttrs := staticOrSharedAttributes{ - Srcs: *srcs.Clone().Append(staticAttrs.Srcs), - Srcs_c: *compilerAttrs.cSrcs.Clone().Append(staticAttrs.Srcs_c), - Srcs_as: *compilerAttrs.asSrcs.Clone().Append(staticAttrs.Srcs_as), - Copts: *compilerAttrs.copts.Clone().Append(staticAttrs.Copts), - Hdrs: *compilerAttrs.hdrs.Clone().Append(staticAttrs.Hdrs), - - Deps: *linkerAttrs.deps.Clone().Append(staticAttrs.Deps), - Implementation_deps: *linkerAttrs.implementationDeps.Clone().Append(staticAttrs.Implementation_deps), - Dynamic_deps: *linkerAttrs.dynamicDeps.Clone().Append(staticAttrs.Dynamic_deps), - Implementation_dynamic_deps: *linkerAttrs.implementationDynamicDeps.Clone().Append(staticAttrs.Implementation_dynamic_deps), - Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps, - Whole_archive_deps: *linkerAttrs.wholeArchiveDeps.Clone().Append(staticAttrs.Whole_archive_deps), - System_dynamic_deps: *linkerAttrs.systemDynamicDeps.Clone().Append(staticAttrs.System_dynamic_deps), - Runtime_deps: linkerAttrs.runtimeDeps, - sdkAttributes: bp2BuildParseSdkAttributes(m), - Native_coverage: baseAttributes.Native_coverage, - } - - sharedCommonAttrs := staticOrSharedAttributes{ - Srcs: *srcs.Clone().Append(sharedAttrs.Srcs), - Srcs_c: *compilerAttrs.cSrcs.Clone().Append(sharedAttrs.Srcs_c), - Srcs_as: *compilerAttrs.asSrcs.Clone().Append(sharedAttrs.Srcs_as), - Copts: *compilerAttrs.copts.Clone().Append(sharedAttrs.Copts), - Hdrs: *compilerAttrs.hdrs.Clone().Append(sharedAttrs.Hdrs), - - Deps: *linkerAttrs.deps.Clone().Append(sharedAttrs.Deps), - Implementation_deps: *linkerAttrs.implementationDeps.Clone().Append(sharedAttrs.Implementation_deps), - Dynamic_deps: *linkerAttrs.dynamicDeps.Clone().Append(sharedAttrs.Dynamic_deps), - Implementation_dynamic_deps: *linkerAttrs.implementationDynamicDeps.Clone().Append(sharedAttrs.Implementation_dynamic_deps), - Whole_archive_deps: *linkerAttrs.wholeArchiveDeps.Clone().Append(sharedAttrs.Whole_archive_deps), - Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps, - System_dynamic_deps: *linkerAttrs.systemDynamicDeps.Clone().Append(sharedAttrs.System_dynamic_deps), - Runtime_deps: linkerAttrs.runtimeDeps, - sdkAttributes: bp2BuildParseSdkAttributes(m), - Native_coverage: baseAttributes.Native_coverage, - } - - staticTargetAttrs := &bazelCcLibraryStaticAttributes{ - staticOrSharedAttributes: staticCommonAttrs, - - Cppflags: compilerAttrs.cppFlags, - Conlyflags: compilerAttrs.conlyFlags, - Asflags: asFlags, - - Export_includes: exportedIncludes.Includes, - Export_absolute_includes: exportedIncludes.AbsoluteIncludes, - Export_system_includes: exportedIncludes.SystemIncludes, - Local_includes: compilerAttrs.localIncludes, - Absolute_includes: compilerAttrs.absoluteIncludes, - Rtti: compilerAttrs.rtti, - Stl: compilerAttrs.stl, - Cpp_std: compilerAttrs.cppStd, - C_std: compilerAttrs.cStd, - - Features: baseAttributes.features, - } - - sharedTargetAttrs := &bazelCcLibrarySharedAttributes{ - staticOrSharedAttributes: sharedCommonAttrs, - Cppflags: compilerAttrs.cppFlags, - Conlyflags: compilerAttrs.conlyFlags, - Asflags: asFlags, - - Export_includes: exportedIncludes.Includes, - Export_absolute_includes: exportedIncludes.AbsoluteIncludes, - Export_system_includes: exportedIncludes.SystemIncludes, - Local_includes: compilerAttrs.localIncludes, - Absolute_includes: compilerAttrs.absoluteIncludes, - Linkopts: linkerAttrs.linkopts, - Rtti: compilerAttrs.rtti, - Stl: compilerAttrs.stl, - Cpp_std: compilerAttrs.cppStd, - C_std: compilerAttrs.cStd, - Use_version_lib: linkerAttrs.useVersionLib, - - Additional_linker_inputs: linkerAttrs.additionalLinkerInputs, - - Strip: stripAttrsFromLinkerAttrs(&linkerAttrs), - Features: baseAttributes.features, - bazelCcHeaderAbiCheckerAttributes: bp2buildParseAbiCheckerProps(ctx, m), - - Fdo_profile: compilerAttrs.fdoProfile, - } - - if compilerAttrs.stubsSymbolFile != nil && len(compilerAttrs.stubsVersions.Value) > 0 { - sharedTargetAttrs.Stubs_symbol_file = compilerAttrs.stubsSymbolFile - } - - sharedTargetAttrs.Suffix = compilerAttrs.suffix - - for axis, configToProps := range m.GetArchVariantProperties(ctx, &LibraryProperties{}) { - for cfg, props := range configToProps { - if props, ok := props.(*LibraryProperties); ok { - if props.Inject_bssl_hash != nil { - // This is an edge case applies only to libcrypto - if m.Name() == "libcrypto" || m.Name() == "libcrypto_for_testing" { - sharedTargetAttrs.Inject_bssl_hash.SetSelectValue(axis, cfg, props.Inject_bssl_hash) - } else { - ctx.PropertyErrorf("inject_bssl_hash", "only applies to libcrypto") - } - } - } - } - } - - staticProps := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_library_static", - Bzl_load_location: "//build/bazel/rules/cc:cc_library_static.bzl", - } - sharedProps := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_library_shared", - Bzl_load_location: "//build/bazel/rules/cc:cc_library_shared.bzl", - } - - var tagsForStaticVariant bazel.StringListAttribute - if compilerAttrs.stubsSymbolFile == nil && len(compilerAttrs.stubsVersions.Value) == 0 { - tagsForStaticVariant = android.ApexAvailableTags(m) - } - tagsForStaticVariant.Append(bazel.StringListAttribute{Value: staticAttrs.Apex_available}) - - tagsForSharedVariant := android.ApexAvailableTags(m) - tagsForSharedVariant.Append(bazel.StringListAttribute{Value: sharedAttrs.Apex_available}) - - ctx.CreateBazelTargetModuleWithRestrictions(staticProps, - android.CommonAttributes{ - Name: m.Name() + "_bp2build_cc_library_static", - Tags: tagsForStaticVariant, - }, - staticTargetAttrs, staticAttrs.Enabled) - ctx.CreateBazelTargetModuleWithRestrictions(sharedProps, - android.CommonAttributes{ - Name: m.Name(), - Tags: tagsForSharedVariant, - }, - sharedTargetAttrs, sharedAttrs.Enabled) - - createStubsBazelTargetIfNeeded(ctx, m, compilerAttrs, exportedIncludes, baseAttributes) -} - -func createStubsBazelTargetIfNeeded(ctx android.TopDownMutatorContext, m *Module, compilerAttrs compilerAttributes, exportedIncludes BazelIncludes, baseAttributes baseAttributes) { - if compilerAttrs.stubsSymbolFile != nil && len(compilerAttrs.stubsVersions.Value) > 0 { - stubSuitesProps := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_stub_suite", - Bzl_load_location: "//build/bazel/rules/cc:cc_stub_library.bzl", - } - soname := m.Name() + ".so" - stubSuitesAttrs := &bazelCcStubSuiteAttributes{ - Symbol_file: compilerAttrs.stubsSymbolFile, - Versions: compilerAttrs.stubsVersions, - Export_includes: exportedIncludes.Includes, - Soname: &soname, - Source_library_label: proptools.StringPtr(m.GetBazelLabel(ctx, m)), - Deps: baseAttributes.deps, - } - ctx.CreateBazelTargetModule(stubSuitesProps, - android.CommonAttributes{Name: m.Name() + "_stub_libs"}, - stubSuitesAttrs) - - // Add alias for the stub shared_library in @api_surfaces repository - currentModuleLibApiDir := ctx.Config().ApiSurfacesDir(android.ModuleLibApi, "current") - actualLabelInMainWorkspace := bazel.Label{ - Label: fmt.Sprintf("@//%s:%s%s", ctx.ModuleDir(), m.Name(), stubsSuffix), - } - ctx.CreateBazelTargetAliasInDir(currentModuleLibApiDir, m.Name(), actualLabelInMainWorkspace) - - // Add alias for headers exported by the stub library - headerLabelInMainWorkspace := bazel.Label{ - // This label is generated from cc_stub_suite macro - Label: fmt.Sprintf("@//%s:%s_stub_libs_%s_headers", ctx.ModuleDir(), m.Name(), android.ModuleLibApi.String()), - } - headerAlias := m.Name() + "_headers" - ctx.CreateBazelTargetAliasInDir(currentModuleLibApiDir, headerAlias, headerLabelInMainWorkspace) - } -} - -func apiContributionBp2Build(ctx android.TopDownMutatorContext, module *Module) { - apiSurfaces := make([]string, 0) - apiHeaders := make([]string, 0) - // module-libapi for apexes (non-null `stubs` property) - if module.HasStubsVariants() { - apiSurfaces = append(apiSurfaces, android.ModuleLibApi.String()) - apiIncludes := getModuleLibApiIncludes(ctx, module) - if !apiIncludes.isEmpty() { - createApiHeaderTarget(ctx, apiIncludes) - apiHeaders = append(apiHeaders, apiIncludes.name) - } - } - // vendorapi (non-null `llndk` property) - if module.HasLlndkStubs() { - apiSurfaces = append(apiSurfaces, android.VendorApi.String()) - apiIncludes := getVendorApiIncludes(ctx, module) - if !apiIncludes.isEmpty() { - createApiHeaderTarget(ctx, apiIncludes) - apiHeaders = append(apiHeaders, apiIncludes.name) - } - } - // create a target only if this module contributes to an api surface - // TODO: Currently this does not distinguish modulelibapi-only headers and vendrorapi-only headers - // TODO: Update so that modulelibapi-only headers do not get exported to vendorapi (and vice-versa) - if len(apiSurfaces) > 0 { - props := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_api_contribution", - Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl", - } - attrs := &bazelCcApiContributionAttributes{ - Library_name: module.Name(), - Api_surfaces: bazel.MakeStringListAttribute(apiSurfaces), - Api: apiLabelAttribute(ctx, module), - Hdrs: bazel.MakeLabelListAttribute( - bazel.MakeLabelListFromTargetNames(apiHeaders), - ), - } - ctx.CreateBazelTargetModule( - props, - android.CommonAttributes{ - Name: android.ApiContributionTargetName(module.Name()), - SkipData: proptools.BoolPtr(true), - }, - attrs, - ) - } -} - -// Native apis are versioned in a single .map.txt for all api surfaces -// Pick any one of the .map.txt files -func apiLabelAttribute(ctx android.TopDownMutatorContext, module *Module) bazel.LabelAttribute { - var apiFile *string - linker := module.linker.(*libraryDecorator) - if llndkApi := linker.Properties.Llndk.Symbol_file; llndkApi != nil { - apiFile = llndkApi - } else if moduleLibApi := linker.Properties.Stubs.Symbol_file; moduleLibApi != nil { - apiFile = moduleLibApi - } else { - ctx.ModuleErrorf("API surface library does not have any API file") - } - apiLabel := android.BazelLabelForModuleSrcSingle(ctx, proptools.String(apiFile)).Label - return *bazel.MakeLabelAttribute(apiLabel) -} - -// wrapper struct to flatten the arch and os specific export_include_dirs -// flattening is necessary since we want to export apis of all arches even when we build for x86 (e.g.) -type bazelCcApiLibraryHeadersAttributes struct { - bazelCcLibraryHeadersAttributes - - Arch *string -} - -func (a *bazelCcApiLibraryHeadersAttributes) isEmpty() bool { - return a.Export_includes.IsEmpty() && - a.Export_system_includes.IsEmpty() && - a.Deps.IsEmpty() -} - -type apiIncludes struct { - name string // name of the Bazel target in the generated bp2build workspace - attrs bazelCcApiLibraryHeadersAttributes -} - -func (includes *apiIncludes) isEmpty() bool { - return includes.attrs.isEmpty() -} - -func (includes *apiIncludes) addDep(name string) { - l := bazel.Label{Label: ":" + name} - ll := bazel.MakeLabelList([]bazel.Label{l}) - lla := bazel.MakeLabelListAttribute(ll) - includes.attrs.Deps.Append(lla) -} - -// includes provided to the module-lib API surface. This API surface is used by apexes. -func getModuleLibApiIncludes(ctx android.TopDownMutatorContext, c *Module) apiIncludes { - flagProps := c.library.(*libraryDecorator).flagExporter.Properties - linkProps := c.library.(*libraryDecorator).baseLinker.Properties - includes := android.FirstUniqueStrings(flagProps.Export_include_dirs) - systemIncludes := android.FirstUniqueStrings(flagProps.Export_system_include_dirs) - headerLibs := android.FirstUniqueStrings(linkProps.Export_header_lib_headers) - attrs := bazelCcLibraryHeadersAttributes{ - Export_includes: bazel.MakeStringListAttribute(includes), - Export_system_includes: bazel.MakeStringListAttribute(systemIncludes), - Deps: bazel.MakeLabelListAttribute(apiHeaderLabels(ctx, headerLibs)), - } - - return apiIncludes{ - name: c.Name() + ".module-libapi.headers", - attrs: bazelCcApiLibraryHeadersAttributes{ - bazelCcLibraryHeadersAttributes: attrs, - }, - } -} - -func getVendorApiIncludes(ctx android.TopDownMutatorContext, c *Module) apiIncludes { - baseProps := c.library.(*libraryDecorator).flagExporter.Properties - llndkProps := c.library.(*libraryDecorator).Properties.Llndk - includes := baseProps.Export_include_dirs - systemIncludes := baseProps.Export_system_include_dirs - // LLNDK can override the base includes - if llndkIncludes := llndkProps.Override_export_include_dirs; llndkIncludes != nil { - includes = llndkIncludes - } - if proptools.Bool(llndkProps.Export_headers_as_system) { - systemIncludes = append(systemIncludes, includes...) - includes = nil - } - - attrs := bazelCcLibraryHeadersAttributes{ - Export_includes: bazel.MakeStringListAttribute(includes), - Export_system_includes: bazel.MakeStringListAttribute(systemIncludes), - Deps: bazel.MakeLabelListAttribute(apiHeaderLabels(ctx, llndkProps.Export_llndk_headers)), - } - return apiIncludes{ - name: c.Name() + ".vendorapi.headers", - attrs: bazelCcApiLibraryHeadersAttributes{ - bazelCcLibraryHeadersAttributes: attrs, - }, - } -} - // cc_library creates both static and/or shared libraries for a device and/or // host. By default, a cc_library has a single variant that targets the device. // Specifying `host_supported: true` also creates a library that targets the @@ -641,8 +231,6 @@ func LibraryFactory() android.Module { staticLibrarySdkMemberType, staticAndSharedLibrarySdkMemberType, } - module.bazelable = true - module.bazelHandler = &ccLibraryBazelHandler{module: module} return module.Init() } @@ -651,8 +239,6 @@ func LibraryStaticFactory() android.Module { module, library := NewLibrary(android.HostAndDeviceSupported) library.BuildOnlyStatic() module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType} - module.bazelable = true - module.bazelHandler = &ccLibraryBazelHandler{module: module} return module.Init() } @@ -661,8 +247,6 @@ func LibrarySharedFactory() android.Module { module, library := NewLibrary(android.HostAndDeviceSupported) library.BuildOnlyShared() module.sdkMemberTypes = []android.SdkMemberType{sharedLibrarySdkMemberType} - module.bazelable = true - module.bazelHandler = &ccLibraryBazelHandler{module: module} return module.Init() } @@ -672,8 +256,6 @@ func LibraryHostStaticFactory() android.Module { module, library := NewLibrary(android.HostSupported) library.BuildOnlyStatic() module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType} - module.bazelable = true - module.bazelHandler = &ccLibraryBazelHandler{module: module} return module.Init() } @@ -682,8 +264,6 @@ func LibraryHostSharedFactory() android.Module { module, library := NewLibrary(android.HostSupported) library.BuildOnlyShared() module.sdkMemberTypes = []android.SdkMemberType{sharedLibrarySdkMemberType} - module.bazelable = true - module.bazelHandler = &ccLibraryBazelHandler{module: module} return module.Init() } @@ -694,11 +274,12 @@ func LibraryHostSharedFactory() android.Module { type flagExporter struct { Properties FlagExporterProperties - dirs android.Paths // Include directories to be included with -I - systemDirs android.Paths // System include directories to be included with -isystem - flags []string // Exported raw flags. - deps android.Paths - headers android.Paths + dirs android.Paths // Include directories to be included with -I + systemDirs android.Paths // System include directories to be included with -isystem + flags []string // Exported raw flags. + deps android.Paths + headers android.Paths + rustRlibDeps []RustRlibDep } // exportedIncludes returns the effective include paths for this module and @@ -711,7 +292,11 @@ func (f *flagExporter) exportedIncludes(ctx ModuleContext) android.Paths { if ctx.inProduct() && f.Properties.Target.Product.Override_export_include_dirs != nil { return android.PathsForModuleSrc(ctx, f.Properties.Target.Product.Override_export_include_dirs) } - return android.PathsForModuleSrc(ctx, f.Properties.Export_include_dirs) + return android.PathsForModuleSrc(ctx, f.Properties.Export_include_dirs.GetOrDefault(ctx, nil)) +} + +func (f *flagExporter) exportedSystemIncludes(ctx ModuleContext) android.Paths { + return android.PathsForModuleSrc(ctx, f.Properties.Export_system_include_dirs) } // exportIncludes registers the include directories and system include directories to be exported @@ -755,6 +340,10 @@ func (f *flagExporter) reexportDeps(deps ...android.Path) { f.deps = append(f.deps, deps...) } +func (f *flagExporter) reexportRustStaticDeps(deps ...RustRlibDep) { + f.rustRlibDeps = append(f.rustRlibDeps, deps...) +} + // addExportedGeneratedHeaders does nothing but collects generated header files. // This can be differ to exportedDeps which may contain phony files to minimize ninja. func (f *flagExporter) addExportedGeneratedHeaders(headers ...android.Path) { @@ -762,7 +351,7 @@ func (f *flagExporter) addExportedGeneratedHeaders(headers ...android.Path) { } func (f *flagExporter) setProvider(ctx android.ModuleContext) { - ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{ + android.SetProvider(ctx, FlagExporterInfoProvider, FlagExporterInfo{ // Comes from Export_include_dirs property, and those of exported transitive deps IncludeDirs: android.FirstUniquePaths(f.dirs), // Comes from Export_system_include_dirs property, and those of exported transitive deps @@ -772,6 +361,8 @@ func (f *flagExporter) setProvider(ctx android.ModuleContext) { // Used sparingly, for extra files that need to be explicitly exported to dependers, // or for phony files to minimize ninja. Deps: f.deps, + // Used for exporting rlib deps of static libraries to dependents. + RustRlibDeps: f.rustRlibDeps, // For exported generated headers, such as exported aidl headers, proto headers, or // sysprop headers. GeneratedHeaders: f.headers, @@ -809,9 +400,6 @@ type libraryDecorator struct { // Output archive of gcno coverage information files coverageOutputFile android.OptionalPath - // linked Source Abi Dump - sAbiOutputFile android.OptionalPath - // Source Abi Diff sAbiDiff android.Paths @@ -821,6 +409,8 @@ type libraryDecorator struct { // Location of the linked, unstripped library for shared libraries unstrippedOutputFile android.Path + // Location of the linked, stripped library for shared libraries, strip: "all" + strippedAllOutputFile android.Path // Location of the file that should be copied to dist dir when requested distFile android.Path @@ -829,11 +419,6 @@ type libraryDecorator struct { postInstallCmds []string - // If useCoreVariant is true, the vendor variant of a VNDK library is - // not installed. - useCoreVariant bool - checkSameCoreVariant bool - skipAPIDefine bool // Decorated interfaces @@ -841,270 +426,9 @@ type libraryDecorator struct { *baseLinker *baseInstaller - collectedSnapshotHeaders android.Paths - apiListCoverageXmlPath android.ModuleOutPath } -type ccLibraryBazelHandler struct { - module *Module -} - -var _ BazelHandler = (*ccLibraryBazelHandler)(nil) - -// generateStaticBazelBuildActions constructs the StaticLibraryInfo Soong -// provider from a Bazel shared library's CcInfo provider. -func (handler *ccLibraryBazelHandler) generateStaticBazelBuildActions(ctx android.ModuleContext, label string, ccInfo cquery.CcInfo) { - rootStaticArchives := ccInfo.RootStaticArchives - if len(rootStaticArchives) != 1 { - ctx.ModuleErrorf("expected exactly one root archive file for '%s', but got %s", label, rootStaticArchives) - return - } - var outputFilePath android.Path = android.PathForBazelOut(ctx, rootStaticArchives[0]) - if len(ccInfo.TidyFiles) > 0 { - handler.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles) - outputFilePath = android.AttachValidationActions(ctx, outputFilePath, handler.module.tidyFiles) - } - handler.module.outputFile = android.OptionalPathForPath(outputFilePath) - - objPaths := ccInfo.CcObjectFiles - objFiles := make(android.Paths, len(objPaths)) - for i, objPath := range objPaths { - objFiles[i] = android.PathForBazelOut(ctx, objPath) - } - objects := Objects{ - objFiles: objFiles, - } - - ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{ - StaticLibrary: outputFilePath, - ReuseObjects: objects, - Objects: objects, - - // TODO(b/190524881): Include transitive static libraries in this provider to support - // static libraries with deps. - TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder(android.TOPOLOGICAL). - Direct(outputFilePath). - Build(), - }) - - return -} - -// generateSharedBazelBuildActions constructs the SharedLibraryInfo Soong -// provider from a Bazel shared library's CcInfo provider. -func (handler *ccLibraryBazelHandler) generateSharedBazelBuildActions(ctx android.ModuleContext, label string, ccInfo cquery.CcInfo) { - rootDynamicLibraries := ccInfo.RootDynamicLibraries - - if len(rootDynamicLibraries) != 1 { - ctx.ModuleErrorf("expected exactly one root dynamic library file for '%s', but got %s", label, rootDynamicLibraries) - return - } - var outputFilePath android.Path = android.PathForBazelOut(ctx, rootDynamicLibraries[0]) - if len(ccInfo.TidyFiles) > 0 { - handler.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles) - outputFilePath = android.AttachValidationActions(ctx, outputFilePath, handler.module.tidyFiles) - } - - handler.module.outputFile = android.OptionalPathForPath(outputFilePath) - handler.module.linker.(*libraryDecorator).unstrippedOutputFile = android.PathForBazelOut(ctx, ccInfo.UnstrippedOutput) - - var tocFile android.OptionalPath - if len(ccInfo.TocFile) > 0 { - tocFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, ccInfo.TocFile)) - } - handler.module.linker.(*libraryDecorator).tocFile = tocFile - - if len(ccInfo.AbiDiffFiles) > 0 { - handler.module.linker.(*libraryDecorator).sAbiDiff = android.PathsForBazelOut(ctx, ccInfo.AbiDiffFiles) - } - - ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{ - TableOfContents: tocFile, - SharedLibrary: outputFilePath, - Target: ctx.Target(), - // TODO(b/190524881): Include transitive static libraries in this provider to support - // static libraries with deps. The provider key for this is TransitiveStaticLibrariesForOrdering. - }) -} - -func (handler *ccLibraryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) { - bazelCtx := ctx.Config().BazelContext - bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx))) - if v := handler.module.library.stubsVersion(); v != "" { - stubsLabel := label + "_stub_libs-" + v - bazelCtx.QueueBazelRequest(stubsLabel, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx))) - } -} - -func (handler *ccLibraryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) { - if v := handler.module.library.stubsVersion(); v != "" { - // if we are a stubs variant, just use the Bazel stubs target - label = label + "_stub_libs-" + v - } - bazelCtx := ctx.Config().BazelContext - ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx))) - if err != nil { - ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err) - return - } - - if handler.module.static() { - handler.generateStaticBazelBuildActions(ctx, label, ccInfo) - } else if handler.module.Shared() { - handler.generateSharedBazelBuildActions(ctx, label, ccInfo) - } else { - ctx.ModuleErrorf("Unhandled bazel case for %s (neither shared nor static!)", ctx.ModuleName()) - } - - handler.module.linker.(*libraryDecorator).setFlagExporterInfoFromCcInfo(ctx, ccInfo) - handler.module.maybeUnhideFromMake() - - if i, ok := handler.module.linker.(snapshotLibraryInterface); ok { - // Dependencies on this library will expect collectedSnapshotHeaders to - // be set, otherwise validation will fail. For now, set this to an empty - // list. - // TODO(b/190533363): More closely mirror the collectHeadersForSnapshot - // implementation. - i.(*libraryDecorator).collectedSnapshotHeaders = android.Paths{} - } - - handler.module.setAndroidMkVariablesFromCquery(ccInfo.CcAndroidMkInfo) - - cctx := moduleContextFromAndroidModuleContext(ctx, handler.module) - addStubDependencyProviders(cctx) -} - -func (library *libraryDecorator) setFlagExporterInfoFromCcInfo(ctx android.ModuleContext, ccInfo cquery.CcInfo) { - flagExporterInfo := flagExporterInfoFromCcInfo(ctx, ccInfo) - // flag exporters consolidates properties like includes, flags, dependencies that should be - // exported from this module to other modules - ctx.SetProvider(FlagExporterInfoProvider, flagExporterInfo) - // Store flag info to be passed along to androidmk - // TODO(b/184387147): Androidmk should be done in Bazel, not Soong. - library.flagExporterInfo = &flagExporterInfo -} - -func GlobHeadersForSnapshot(ctx android.ModuleContext, paths android.Paths) android.Paths { - ret := android.Paths{} - - // Headers in the source tree should be globbed. On the contrast, generated headers - // can't be globbed, and they should be manually collected. - // So, we first filter out intermediate directories (which contains generated headers) - // from exported directories, and then glob headers under remaining directories. - for _, path := range paths { - dir := path.String() - // Skip if dir is for generated headers - if strings.HasPrefix(dir, ctx.Config().OutDir()) { - continue - } - - // Filter out the generated headers from bazel. - if strings.HasPrefix(dir, android.PathForBazelOut(ctx, "bazel-out").String()) { - continue - } - - // libeigen wrongly exports the root directory "external/eigen". But only two - // subdirectories "Eigen" and "unsupported" contain exported header files. Even worse - // some of them have no extension. So we need special treatment for libeigen in order - // to glob correctly. - if dir == "external/eigen" { - // Only these two directories contains exported headers. - for _, subdir := range []string{"Eigen", "unsupported/Eigen"} { - globDir := "external/eigen/" + subdir + "/**/*" - glob, err := ctx.GlobWithDeps(globDir, nil) - if err != nil { - ctx.ModuleErrorf("glob of %q failed: %s", globDir, err) - return nil - } - for _, header := range glob { - if strings.HasSuffix(header, "/") { - continue - } - ext := filepath.Ext(header) - if ext != "" && ext != ".h" { - continue - } - ret = append(ret, android.PathForSource(ctx, header)) - } - } - continue - } - globDir := dir + "/**/*" - glob, err := ctx.GlobWithDeps(globDir, nil) - if err != nil { - ctx.ModuleErrorf("glob of %q failed: %s", globDir, err) - return nil - } - isLibcxx := strings.HasPrefix(dir, "external/libcxx/include") - for _, header := range glob { - if isLibcxx { - // Glob all files under this special directory, because of C++ headers with no - // extension. - if strings.HasSuffix(header, "/") { - continue - } - } else { - // Filter out only the files with extensions that are headers. - found := false - for _, ext := range HeaderExts { - if strings.HasSuffix(header, ext) { - found = true - break - } - } - if !found { - continue - } - } - ret = append(ret, android.PathForSource(ctx, header)) - } - } - return ret -} - -func GlobGeneratedHeadersForSnapshot(_ android.ModuleContext, paths android.Paths) android.Paths { - ret := android.Paths{} - for _, header := range paths { - // TODO(b/148123511): remove exportedDeps after cleaning up genrule - if strings.HasSuffix(header.Base(), "-phony") { - continue - } - ret = append(ret, header) - } - return ret -} - -// collectHeadersForSnapshot collects all exported headers from library. -// It globs header files in the source tree for exported include directories, -// and tracks generated header files separately. -// -// This is to be called from GenerateAndroidBuildActions, and then collected -// header files can be retrieved by snapshotHeaders(). -func (l *libraryDecorator) collectHeadersForSnapshot(ctx android.ModuleContext) { - ret := android.Paths{} - - // Headers in the source tree should be globbed. On the contrast, generated headers - // can't be globbed, and they should be manually collected. - // So, we first filter out intermediate directories (which contains generated headers) - // from exported directories, and then glob headers under remaining directories. - ret = append(ret, GlobHeadersForSnapshot(ctx, append(android.CopyOfPaths(l.flagExporter.dirs), l.flagExporter.systemDirs...))...) - - // Collect generated headers - ret = append(ret, GlobGeneratedHeadersForSnapshot(ctx, append(android.CopyOfPaths(l.flagExporter.headers), l.flagExporter.deps...))...) - - l.collectedSnapshotHeaders = ret -} - -// This returns all exported header files, both generated ones and headers from source tree. -// collectHeadersForSnapshot() must be called before calling this. -func (l *libraryDecorator) snapshotHeaders() android.Paths { - if l.collectedSnapshotHeaders == nil { - panic("snapshotHeaders() must be called after collectHeadersForSnapshot()") - } - return l.collectedSnapshotHeaders -} - // linkerProps returns the list of properties structs relevant for this library. (For example, if // the library is cc_shared_library, then static-library properties are omitted.) func (library *libraryDecorator) linkerProps() []interface{} { @@ -1140,9 +464,9 @@ func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Fla } if library.static() { - flags.Local.CFlags = append(flags.Local.CFlags, library.StaticProperties.Static.Cflags...) + flags.Local.CFlags = append(flags.Local.CFlags, library.StaticProperties.Static.Cflags.GetOrDefault(ctx, nil)...) } else if library.shared() { - flags.Local.CFlags = append(flags.Local.CFlags, library.SharedProperties.Shared.Cflags...) + flags.Local.CFlags = append(flags.Local.CFlags, library.SharedProperties.Shared.Cflags.GetOrDefault(ctx, nil)...) } if library.shared() { @@ -1238,18 +562,16 @@ func (library *libraryDecorator) getHeaderAbiCheckerProperties(ctx android.BaseM func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects { if ctx.IsLlndk() { - // This is the vendor variant of an LLNDK library, build the LLNDK stubs. - vndkVer := ctx.Module().(*Module).VndkVersion() - if !inList(vndkVer, ctx.Config().PlatformVersionActiveCodenames()) || vndkVer == "" { - // For non-enforcing devices, vndkVer is empty. Use "current" in that case, too. - vndkVer = "current" - } - if library.stubsVersion() != "" { - vndkVer = library.stubsVersion() + vendorApiLevel := ctx.Config().VendorApiLevel() + if vendorApiLevel == "" { + // TODO(b/321892570): Some tests relying on old fixtures which + // doesn't set vendorApiLevel. Needs to fix them. + vendorApiLevel = ctx.Config().PlatformSdkVersion().String() } + // This is the vendor variant of an LLNDK library, build the LLNDK stubs. nativeAbiResult := parseNativeAbiDefinition(ctx, String(library.Properties.Llndk.Symbol_file), - android.ApiLevelOrPanic(ctx, vndkVer), "--llndk") + android.ApiLevelOrPanic(ctx, vendorApiLevel), "--llndk") objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc) if !Bool(library.Properties.Llndk.Unversioned) { library.versionScriptPath = android.OptionalPathForPath( @@ -1319,15 +641,11 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa return Objects{} } if library.sabi.shouldCreateSourceAbiDump() { - exportIncludeDirs := library.flagExporter.exportedIncludes(ctx) - var SourceAbiFlags []string - for _, dir := range exportIncludeDirs.Strings() { - SourceAbiFlags = append(SourceAbiFlags, "-I"+dir) - } - for _, reexportedInclude := range library.sabi.Properties.ReexportedIncludes { - SourceAbiFlags = append(SourceAbiFlags, "-I"+reexportedInclude) + dirs := library.exportedIncludeDirsForAbiCheck(ctx) + flags.SAbiFlags = make([]string, 0, len(dirs)) + for _, dir := range dirs { + flags.SAbiFlags = append(flags.SAbiFlags, "-I"+dir) } - flags.SAbiFlags = SourceAbiFlags totalLength := len(library.baseCompiler.Properties.Srcs) + len(deps.GeneratedSources) + len(library.SharedProperties.Shared.Srcs) + len(library.StaticProperties.Static.Srcs) if totalLength > 0 { @@ -1433,14 +751,6 @@ func (library *libraryDecorator) getLibNameHelper(baseModuleName string, inVendo func (library *libraryDecorator) getLibName(ctx BaseModuleContext) string { name := library.getLibNameHelper(ctx.baseModuleName(), ctx.inVendor(), ctx.inProduct()) - if ctx.IsVndkExt() { - // vndk-ext lib should have the same name with original lib - ctx.VisitDirectDepsWithTag(vndkExtDepTag, func(module android.Module) { - originalName := module.(*Module).outputFile.Path() - name = strings.TrimSuffix(originalName.Base(), originalName.Ext()) - }) - } - if ctx.Host() && Bool(library.Properties.Unique_host_soname) { if !strings.HasSuffix(name, "-host") { name = name + "-host" @@ -1529,6 +839,10 @@ func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { if library.baseLinker.Properties.crt() { deps.CrtBegin = append(deps.CrtBegin, ctx.toolchain().CrtBeginSharedLibrary()...) deps.CrtEnd = append(deps.CrtEnd, ctx.toolchain().CrtEndSharedLibrary()...) + + } + if library.baseLinker.Properties.crtPadSegment() { + deps.CrtEnd = append(deps.CrtEnd, ctx.toolchain().CrtPadSegmentSharedLibrary()...) } deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.SharedProperties.Shared.Whole_static_libs...) deps.StaticLibs = append(deps.StaticLibs, library.SharedProperties.Shared.Static_libs...) @@ -1536,6 +850,8 @@ func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.SharedProperties.Shared.Export_shared_lib_headers...) deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.SharedProperties.Shared.Export_static_lib_headers...) + + deps.LlndkHeaderLibs = append(deps.LlndkHeaderLibs, library.Properties.Llndk.Export_llndk_headers...) } if ctx.inVendor() { deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs) @@ -1604,6 +920,40 @@ func (library *libraryDecorator) linkerSpecifiedDeps(specifiedDeps specifiedDeps return specifiedDeps } +func (library *libraryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + if library.static() { + moduleInfoJSON.Class = []string{"STATIC_LIBRARIES"} + moduleInfoJSON.Uninstallable = true + } else if library.shared() { + moduleInfoJSON.Class = []string{"SHARED_LIBRARIES"} + } else if library.header() { + moduleInfoJSON.Class = []string{"HEADER_LIBRARIES"} + moduleInfoJSON.Uninstallable = true + } + + if library.buildStubs() && library.stubsVersion() != "" { + moduleInfoJSON.SubName += "." + library.stubsVersion() + } + + // If a library providing a stub is included in an APEX, the private APIs of the library + // is accessible only inside the APEX. From outside of the APEX, clients can only use the + // public APIs via the stub. To enforce this, the (latest version of the) stub gets the + // name of the library. The impl library instead gets the `.bootstrap` suffix to so that + // they can be exceptionally used directly when APEXes are not available (e.g. during the + // very early stage in the boot process). + if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.notInPlatform() && + !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && !ctx.useVndk() && !ctx.static() { + if library.buildStubs() && library.isLatestStubVersion() { + moduleInfoJSON.SubName = "" + } + if !library.buildStubs() { + moduleInfoJSON.SubName = ".bootstrap" + } + } + + library.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON) +} + func (library *libraryDecorator) linkStatic(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { @@ -1634,13 +984,13 @@ func (library *libraryDecorator) linkStatic(ctx ModuleContext, ctx.CheckbuildFile(outputFile) if library.static() { - ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{ + android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{ StaticLibrary: outputFile, ReuseObjects: library.reuseObjects, Objects: library.objects, WholeStaticLibsFromPrebuilts: library.wholeStaticLibsFromPrebuilts, - TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder(android.TOPOLOGICAL). + TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL). Direct(outputFile). Transitive(deps.TranstiveStaticLibrariesForOrdering). Build(), @@ -1648,7 +998,7 @@ func (library *libraryDecorator) linkStatic(ctx ModuleContext, } if library.header() { - ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{}) + android.SetProvider(ctx, HeaderLibraryInfoProvider, HeaderLibraryInfo{}) } return outputFile @@ -1766,6 +1116,17 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, } } + // Generate an output file for dist as if strip: "all" is set on the module. + // Currently this is for layoutlib release process only. + for _, dist := range ctx.Module().(*Module).Dists() { + if dist.Tag != nil && *dist.Tag == "stripped_all" { + strippedAllOutputFile := android.PathForModuleOut(ctx, "stripped_all", fileName) + transformStrip(ctx, outputFile, strippedAllOutputFile, StripFlags{Toolchain: flags.Toolchain}) + library.strippedAllOutputFile = strippedAllOutputFile + break + } + } + sharedLibs := deps.EarlySharedLibs sharedLibs = append(sharedLibs, deps.SharedLibs...) sharedLibs = append(sharedLibs, deps.LateSharedLibs...) @@ -1773,9 +1134,18 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, linkerDeps = append(linkerDeps, deps.EarlySharedLibsDeps...) linkerDeps = append(linkerDeps, deps.SharedLibsDeps...) linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...) + + if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil && !library.buildStubs() { + if ctx.Module().(*Module).WholeRustStaticlib { + deps.WholeStaticLibs = append(deps.WholeStaticLibs, generatedLib) + } else { + deps.StaticLibs = append(deps.StaticLibs, generatedLib) + } + } + transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, - deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs, - linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs, objs.tidyDepFiles) + deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, + deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs, objs.tidyDepFiles) objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...) objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...) @@ -1783,15 +1153,15 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.WholeStaticLibObjs.sAbiDumpFiles...) library.coverageOutputFile = transformCoverageFilesToZip(ctx, objs, library.getLibName(ctx)) - library.linkSAbiDumpFiles(ctx, objs, fileName, unstrippedOutputFile) + library.linkSAbiDumpFiles(ctx, deps, objs, fileName, unstrippedOutputFile) - var transitiveStaticLibrariesForOrdering *android.DepSet + var transitiveStaticLibrariesForOrdering *android.DepSet[android.Path] if static := ctx.GetDirectDepsWithTag(staticVariantTag); len(static) > 0 { - s := ctx.OtherModuleProvider(static[0], StaticLibraryInfoProvider).(StaticLibraryInfo) + s, _ := android.OtherModuleProvider(ctx, static[0], StaticLibraryInfoProvider) transitiveStaticLibrariesForOrdering = s.TransitiveStaticLibrariesForOrdering } - ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{ + android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{ TableOfContents: android.OptionalPathForPath(tocFile), SharedLibrary: unstrippedOutputFile, TransitiveStaticLibrariesForOrdering: transitiveStaticLibrariesForOrdering, @@ -1808,15 +1178,15 @@ func addStubDependencyProviders(ctx ModuleContext) { if len(stubs) > 0 { var stubsInfo []SharedStubLibrary for _, stub := range stubs { - stubInfo := ctx.OtherModuleProvider(stub, SharedLibraryInfoProvider).(SharedLibraryInfo) - flagInfo := ctx.OtherModuleProvider(stub, FlagExporterInfoProvider).(FlagExporterInfo) + stubInfo, _ := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider) + flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider) stubsInfo = append(stubsInfo, SharedStubLibrary{ Version: moduleLibraryInterface(stub).stubsVersion(), SharedLibraryInfo: stubInfo, FlagExporterInfo: flagInfo, }) } - ctx.SetProvider(SharedLibraryStubsProvider, SharedLibraryStubsInfo{ + android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{ SharedStubLibraries: stubsInfo, IsLLNDK: ctx.IsLlndk(), }) @@ -1827,6 +1197,10 @@ func (library *libraryDecorator) unstrippedOutputFilePath() android.Path { return library.unstrippedOutputFile } +func (library *libraryDecorator) strippedAllOutputFilePath() android.Path { + return library.strippedAllOutputFile +} + func (library *libraryDecorator) disableStripping() { library.stripper.StripProperties.Strip.None = BoolPtr(true) } @@ -1842,6 +1216,75 @@ func (library *libraryDecorator) coverageOutputFilePath() android.OptionalPath { return library.coverageOutputFile } +func (library *libraryDecorator) exportedIncludeDirsForAbiCheck(ctx ModuleContext) []string { + exportIncludeDirs := library.flagExporter.exportedIncludes(ctx).Strings() + exportIncludeDirs = append(exportIncludeDirs, library.sabi.Properties.ReexportedIncludes...) + exportSystemIncludeDirs := library.flagExporter.exportedSystemIncludes(ctx).Strings() + exportSystemIncludeDirs = append(exportSystemIncludeDirs, library.sabi.Properties.ReexportedSystemIncludes...) + // The ABI checker does not distinguish normal and system headers. + return append(exportIncludeDirs, exportSystemIncludeDirs...) +} + +func (library *libraryDecorator) llndkIncludeDirsForAbiCheck(ctx ModuleContext, deps PathDeps) []string { + var includeDirs, systemIncludeDirs []string + + // The ABI checker does not need the preprocess which adds macro guards to function declarations. + preprocessedDirs := android.PathsForModuleSrc(ctx, library.Properties.Llndk.Export_preprocessed_headers).Strings() + if Bool(library.Properties.Llndk.Export_headers_as_system) { + systemIncludeDirs = append(systemIncludeDirs, preprocessedDirs...) + } else { + includeDirs = append(includeDirs, preprocessedDirs...) + } + + if library.Properties.Llndk.Override_export_include_dirs != nil { + includeDirs = append(includeDirs, android.PathsForModuleSrc( + ctx, library.Properties.Llndk.Override_export_include_dirs).Strings()...) + } else { + includeDirs = append(includeDirs, library.flagExporter.exportedIncludes(ctx).Strings()...) + // Ignore library.sabi.Properties.ReexportedIncludes because + // LLNDK does not reexport the implementation's dependencies, such as export_header_libs. + } + + systemIncludeDirs = append(systemIncludeDirs, + library.flagExporter.exportedSystemIncludes(ctx).Strings()...) + if Bool(library.Properties.Llndk.Export_headers_as_system) { + systemIncludeDirs = append(systemIncludeDirs, includeDirs...) + includeDirs = nil + } + // Header libs. + includeDirs = append(includeDirs, deps.LlndkIncludeDirs.Strings()...) + systemIncludeDirs = append(systemIncludeDirs, deps.LlndkSystemIncludeDirs.Strings()...) + // The ABI checker does not distinguish normal and system headers. + return append(includeDirs, systemIncludeDirs...) +} + +func (library *libraryDecorator) linkLlndkSAbiDumpFiles(ctx ModuleContext, + deps PathDeps, sAbiDumpFiles android.Paths, soFile android.Path, libFileName string, + excludeSymbolVersions, excludeSymbolTags []string, + vendorApiLevel string) android.Path { + // NDK symbols in version 34 are LLNDK symbols. Those in version 35 are not. + return transformDumpToLinkedDump(ctx, + sAbiDumpFiles, soFile, libFileName+".llndk", + library.llndkIncludeDirsForAbiCheck(ctx, deps), + android.OptionalPathForModuleSrc(ctx, library.Properties.Llndk.Symbol_file), + append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...), + append([]string{"platform-only"}, excludeSymbolTags...), + []string{"llndk=" + vendorApiLevel}, "34", true /* isLlndk */) +} + +func (library *libraryDecorator) linkApexSAbiDumpFiles(ctx ModuleContext, + deps PathDeps, sAbiDumpFiles android.Paths, soFile android.Path, libFileName string, + excludeSymbolVersions, excludeSymbolTags []string, + sdkVersion string) android.Path { + return transformDumpToLinkedDump(ctx, + sAbiDumpFiles, soFile, libFileName+".apex", + library.exportedIncludeDirsForAbiCheck(ctx), + android.OptionalPathForModuleSrc(ctx, library.Properties.Stubs.Symbol_file), + append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...), + append([]string{"platform-only"}, excludeSymbolTags...), + []string{"apex", "systemapi"}, sdkVersion, false /* isLlndk */) +} + func getRefAbiDumpFile(ctx android.ModuleInstallPathContext, versionedDumpDir, fileName string) android.OptionalPath { @@ -1856,42 +1299,29 @@ func getRefAbiDumpFile(ctx android.ModuleInstallPathContext, fileName+".lsdump") } -func getRefAbiDumpDir(isNdk, isVndk bool) string { - var dirName string - if isNdk { - dirName = "ndk" - } else if isVndk { - dirName = "vndk" - } else { - dirName = "platform" - } - return filepath.Join("prebuilts", "abi-dumps", dirName) -} - -func prevRefAbiDumpVersion(ctx ModuleContext, dumpDir string) int { +// Return the previous and current SDK versions for cross-version ABI diff. +func crossVersionAbiDiffSdkVersions(ctx ModuleContext, dumpDir string) (int, int) { sdkVersionInt := ctx.Config().PlatformSdkVersion().FinalInt() - sdkVersionStr := ctx.Config().PlatformSdkVersion().String() if ctx.Config().PlatformSdkFinal() { - return sdkVersionInt - 1 + return sdkVersionInt - 1, sdkVersionInt } else { // The platform SDK version can be upgraded before finalization while the corresponding abi dumps hasn't // been generated. Thus the Cross-Version Check chooses PLATFORM_SDK_VERION - 1 as previous version. // This situation could be identified by checking the existence of the PLATFORM_SDK_VERION dump directory. - versionedDumpDir := android.ExistentPathForSource(ctx, dumpDir, sdkVersionStr) + versionedDumpDir := android.ExistentPathForSource(ctx, + dumpDir, ctx.Config().PlatformSdkVersion().String()) if versionedDumpDir.Valid() { - return sdkVersionInt + return sdkVersionInt, sdkVersionInt + 1 } else { - return sdkVersionInt - 1 + return sdkVersionInt - 1, sdkVersionInt } } } -func currRefAbiDumpVersion(ctx ModuleContext, isVndk bool) string { - if isVndk { - // Each version of VNDK is independent, so follow the VNDK version which is the codename or PLATFORM_SDK_VERSION. - return ctx.Module().(*Module).VndkVersion() - } else if ctx.Config().PlatformSdkFinal() { +// Return the SDK version for same-version ABI diff. +func currRefAbiDumpSdkVersion(ctx ModuleContext) string { + if ctx.Config().PlatformSdkFinal() { // After sdk finalization, the ABI of the latest API level must be consistent with the source code, // so choose PLATFORM_SDK_VERSION as the current version. return ctx.Config().PlatformSdkVersion().String() @@ -1901,12 +1331,11 @@ func currRefAbiDumpVersion(ctx ModuleContext, isVndk bool) string { } // sourceAbiDiff registers a build statement to compare linked sAbi dump files (.lsdump). -func (library *libraryDecorator) sourceAbiDiff(ctx android.ModuleContext, referenceDump android.Path, - baseName, nameExt string, isLlndkOrNdk, allowExtensions bool, +func (library *libraryDecorator) sourceAbiDiff(ctx android.ModuleContext, + sourceDump, referenceDump android.Path, + baseName, nameExt string, isLlndk, allowExtensions bool, sourceVersion, errorMessage string) { - sourceDump := library.sAbiOutputFile.Path() - extraFlags := []string{"-target-version", sourceVersion} headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx) if Bool(headerAbiChecker.Check_all_apis) { @@ -1916,7 +1345,7 @@ func (library *libraryDecorator) sourceAbiDiff(ctx android.ModuleContext, refere "-allow-unreferenced-changes", "-allow-unreferenced-elf-symbol-changes") } - if isLlndkOrNdk { + if isLlndk { extraFlags = append(extraFlags, "-consider-opaque-types-different") } if allowExtensions { @@ -1930,79 +1359,173 @@ func (library *libraryDecorator) sourceAbiDiff(ctx android.ModuleContext, refere baseName, nameExt, extraFlags, errorMessage)) } -func (library *libraryDecorator) crossVersionAbiDiff(ctx android.ModuleContext, referenceDump android.Path, - baseName string, isLlndkOrNdk bool, sourceVersion, prevVersion string) { +func (library *libraryDecorator) crossVersionAbiDiff(ctx android.ModuleContext, + sourceDump, referenceDump android.Path, + baseName, nameExt string, isLlndk bool, sourceVersion, prevDumpDir string) { - errorMessage := "error: Please follow https://android.googlesource.com/platform/development/+/master/vndk/tools/header-checker/README.md#configure-cross_version-abi-check to resolve the ABI difference between your source code and version " + prevVersion + "." + errorMessage := "error: Please follow https://android.googlesource.com/platform/development/+/main/vndk/tools/header-checker/README.md#configure-cross_version-abi-check to resolve the difference between your source code and the ABI dumps in " + prevDumpDir - library.sourceAbiDiff(ctx, referenceDump, baseName, prevVersion, - isLlndkOrNdk, true /* allowExtensions */, sourceVersion, errorMessage) + library.sourceAbiDiff(ctx, sourceDump, referenceDump, baseName, nameExt, + isLlndk, true /* allowExtensions */, sourceVersion, errorMessage) } -func (library *libraryDecorator) sameVersionAbiDiff(ctx android.ModuleContext, referenceDump android.Path, - baseName string, isLlndkOrNdk, allowExtensions bool) { +func (library *libraryDecorator) sameVersionAbiDiff(ctx android.ModuleContext, + sourceDump, referenceDump android.Path, + baseName, nameExt string, isLlndk bool, lsdumpTagName string) { libName := strings.TrimSuffix(baseName, filepath.Ext(baseName)) - errorMessage := "error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l " + libName + errorMessage := "error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py --lib " + libName + " --lib-variant " + lsdumpTagName + + targetRelease := ctx.Config().Getenv("TARGET_RELEASE") + if targetRelease != "" { + errorMessage += " --release " + targetRelease + } - library.sourceAbiDiff(ctx, referenceDump, baseName, "", - isLlndkOrNdk, allowExtensions, "current", errorMessage) + library.sourceAbiDiff(ctx, sourceDump, referenceDump, baseName, nameExt, + isLlndk, false /* allowExtensions */, "current", errorMessage) } -func (library *libraryDecorator) optInAbiDiff(ctx android.ModuleContext, referenceDump android.Path, - baseName, nameExt string, isLlndkOrNdk bool, refDumpDir string) { +func (library *libraryDecorator) optInAbiDiff(ctx android.ModuleContext, + sourceDump, referenceDump android.Path, + baseName, nameExt string, refDumpDir string, lsdumpTagName string) { libName := strings.TrimSuffix(baseName, filepath.Ext(baseName)) - errorMessage := "error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l " + libName + " -ref-dump-dir $$ANDROID_BUILD_TOP/" + refDumpDir + errorMessage := "error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py --lib " + libName + " --lib-variant " + lsdumpTagName + " --ref-dump-dir $$ANDROID_BUILD_TOP/" + refDumpDir + + targetRelease := ctx.Config().Getenv("TARGET_RELEASE") + if targetRelease != "" { + errorMessage += " --release " + targetRelease + } - library.sourceAbiDiff(ctx, referenceDump, baseName, nameExt, - isLlndkOrNdk, false /* allowExtensions */, "current", errorMessage) + // Most opt-in libraries do not have dumps for all default architectures. + if ctx.Config().HasDeviceProduct() { + errorMessage += " --product " + ctx.Config().DeviceProduct() + } + + library.sourceAbiDiff(ctx, sourceDump, referenceDump, baseName, nameExt, + false /* isLlndk */, false /* allowExtensions */, "current", errorMessage) } -func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) { +func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathDeps, objs Objects, fileName string, soFile android.Path) { if library.sabi.shouldCreateSourceAbiDump() { - exportIncludeDirs := library.flagExporter.exportedIncludes(ctx) - var SourceAbiFlags []string - for _, dir := range exportIncludeDirs.Strings() { - SourceAbiFlags = append(SourceAbiFlags, "-I"+dir) - } - for _, reexportedInclude := range library.sabi.Properties.ReexportedIncludes { - SourceAbiFlags = append(SourceAbiFlags, "-I"+reexportedInclude) - } - exportedHeaderFlags := strings.Join(SourceAbiFlags, " ") + exportedIncludeDirs := library.exportedIncludeDirsForAbiCheck(ctx) headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx) - library.sAbiOutputFile = transformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags, + currSdkVersion := currRefAbiDumpSdkVersion(ctx) + currVendorVersion := ctx.Config().VendorApiLevel() + + // Generate source dumps. + implDump := transformDumpToLinkedDump(ctx, + objs.sAbiDumpFiles, soFile, fileName, + exportedIncludeDirs, android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)), headerAbiChecker.Exclude_symbol_versions, - headerAbiChecker.Exclude_symbol_tags) - - addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String()) - - // The logic must be consistent with classifySourceAbiDump. - isVndk := ctx.useVndk() && ctx.isVndk() - isNdk := ctx.isNdk(ctx.Config()) - isLlndk := ctx.isImplementationForLLNDKPublic() - dumpDir := getRefAbiDumpDir(isNdk, isVndk) - binderBitness := ctx.DeviceConfig().BinderBitness() - // If NDK or PLATFORM library, check against previous version ABI. - if !isVndk { - prevVersionInt := prevRefAbiDumpVersion(ctx, dumpDir) - prevVersion := strconv.Itoa(prevVersionInt) + headerAbiChecker.Exclude_symbol_tags, + []string{} /* includeSymbolTags */, currSdkVersion, false /* isLlndk */) + + var llndkDump, apexVariantDump android.Path + tags := classifySourceAbiDump(ctx) + optInTags := []lsdumpTag{} + for _, tag := range tags { + if tag == llndkLsdumpTag && currVendorVersion != "" { + if llndkDump == nil { + // TODO(b/323447559): Evaluate if replacing sAbiDumpFiles with implDump is faster + llndkDump = library.linkLlndkSAbiDumpFiles(ctx, + deps, objs.sAbiDumpFiles, soFile, fileName, + headerAbiChecker.Exclude_symbol_versions, + headerAbiChecker.Exclude_symbol_tags, + currVendorVersion) + } + addLsdumpPath(string(tag) + ":" + llndkDump.String()) + } else if tag == apexLsdumpTag { + if apexVariantDump == nil { + apexVariantDump = library.linkApexSAbiDumpFiles(ctx, + deps, objs.sAbiDumpFiles, soFile, fileName, + headerAbiChecker.Exclude_symbol_versions, + headerAbiChecker.Exclude_symbol_tags, + currSdkVersion) + } + addLsdumpPath(string(tag) + ":" + apexVariantDump.String()) + } else { + if tag.dirName() == "" { + optInTags = append(optInTags, tag) + } + addLsdumpPath(string(tag) + ":" + implDump.String()) + } + } + + // Diff source dumps and reference dumps. + for _, tag := range tags { + dumpDirName := tag.dirName() + if dumpDirName == "" { + continue + } + dumpDir := filepath.Join("prebuilts", "abi-dumps", dumpDirName) + isLlndk := (tag == llndkLsdumpTag) + isApex := (tag == apexLsdumpTag) + binderBitness := ctx.DeviceConfig().BinderBitness() + nameExt := "" + if isLlndk { + nameExt = "llndk" + } else if isApex { + nameExt = "apex" + } + // Check against the previous version. + var prevVersion, currVersion string + sourceDump := implDump + // If this release config does not define VendorApiLevel, fall back to the old policy. + if isLlndk && currVendorVersion != "" { + prevVersion = ctx.Config().PrevVendorApiLevel() + currVersion = currVendorVersion + // LLNDK dumps are generated by different rules after trunk stable. + if android.IsTrunkStableVendorApiLevel(prevVersion) { + sourceDump = llndkDump + } + } else { + prevVersionInt, currVersionInt := crossVersionAbiDiffSdkVersions(ctx, dumpDir) + prevVersion = strconv.Itoa(prevVersionInt) + currVersion = strconv.Itoa(currVersionInt) + // APEX dumps are generated by different rules after trunk stable. + if isApex && prevVersionInt > 34 { + sourceDump = apexVariantDump + } + } prevDumpDir := filepath.Join(dumpDir, prevVersion, binderBitness) prevDumpFile := getRefAbiDumpFile(ctx, prevDumpDir, fileName) if prevDumpFile.Valid() { - library.crossVersionAbiDiff(ctx, prevDumpFile.Path(), - fileName, isLlndk || isNdk, - strconv.Itoa(prevVersionInt+1), prevVersion) + library.crossVersionAbiDiff(ctx, sourceDump, prevDumpFile.Path(), + fileName, nameExt+prevVersion, isLlndk, currVersion, prevDumpDir) + } + // Check against the current version. + sourceDump = implDump + if isLlndk && currVendorVersion != "" { + currVersion = currVendorVersion + if android.IsTrunkStableVendorApiLevel(currVersion) { + sourceDump = llndkDump + } + } else { + currVersion = currSdkVersion + if isApex && (!ctx.Config().PlatformSdkFinal() || + ctx.Config().PlatformSdkVersion().FinalInt() > 34) { + sourceDump = apexVariantDump + } } + currDumpDir := filepath.Join(dumpDir, currVersion, binderBitness) + currDumpFile := getRefAbiDumpFile(ctx, currDumpDir, fileName) + if currDumpFile.Valid() { + library.sameVersionAbiDiff(ctx, sourceDump, currDumpFile.Path(), + fileName, nameExt, isLlndk, string(tag)) + } + } + + // Assert that a module is tagged with at most one of platformLsdumpTag, productLsdumpTag, or vendorLsdumpTag. + if len(headerAbiChecker.Ref_dump_dirs) > 0 && len(optInTags) != 1 { + ctx.ModuleErrorf("Expect exactly one opt-in lsdump tag when ref_dump_dirs are specified: %s", optInTags) + return } - // Check against the current version. - currVersion := currRefAbiDumpVersion(ctx, isVndk) - currDumpDir := filepath.Join(dumpDir, currVersion, binderBitness) - currDumpFile := getRefAbiDumpFile(ctx, currDumpDir, fileName) - if currDumpFile.Valid() { - library.sameVersionAbiDiff(ctx, currDumpFile.Path(), - fileName, isLlndk || isNdk, ctx.IsVndkExt()) + // Ensure that a module tagged with only platformLsdumpTag has ref_dump_dirs. + // Android.bp in vendor projects should be cleaned up before this is enforced for vendorLsdumpTag and productLsdumpTag. + if len(headerAbiChecker.Ref_dump_dirs) == 0 && len(tags) == 1 && tags[0] == platformLsdumpTag { + ctx.ModuleErrorf("header_abi_checker is explicitly enabled, but no ref_dump_dirs are specified.") } // Check against the opt-in reference dumps. for i, optInDumpDir := range headerAbiChecker.Ref_dump_dirs { @@ -2013,9 +1536,9 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objec if !optInDumpFile.Valid() { continue } - library.optInAbiDiff(ctx, optInDumpFile.Path(), - fileName, "opt"+strconv.Itoa(i), isLlndk || isNdk, - optInDumpDirPath.String()) + library.optInAbiDiff(ctx, + implDump, optInDumpFile.Path(), + fileName, "opt"+strconv.Itoa(i), optInDumpDirPath.String(), string(optInTags[0])) } } } @@ -2069,14 +1592,19 @@ func (library *libraryDecorator) link(ctx ModuleContext, // override the module's export_include_dirs with llndk.override_export_include_dirs // if it is set. if override := library.Properties.Llndk.Override_export_include_dirs; override != nil { - library.flagExporter.Properties.Export_include_dirs = override + library.flagExporter.Properties.Export_include_dirs = proptools.NewConfigurable[[]string]( + nil, + []proptools.ConfigurableCase[[]string]{ + proptools.NewConfigurableCase[[]string](nil, &override), + }, + ) } if Bool(library.Properties.Llndk.Export_headers_as_system) { library.flagExporter.Properties.Export_system_include_dirs = append( library.flagExporter.Properties.Export_system_include_dirs, - library.flagExporter.Properties.Export_include_dirs...) - library.flagExporter.Properties.Export_include_dirs = nil + library.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil)...) + library.flagExporter.Properties.Export_include_dirs = proptools.NewConfigurable[[]string](nil, nil) } } @@ -2084,7 +1612,12 @@ func (library *libraryDecorator) link(ctx ModuleContext, // override the module's export_include_dirs with vendor_public_library.override_export_include_dirs // if it is set. if override := library.Properties.Vendor_public_library.Override_export_include_dirs; override != nil { - library.flagExporter.Properties.Export_include_dirs = override + library.flagExporter.Properties.Export_include_dirs = proptools.NewConfigurable[[]string]( + nil, + []proptools.ConfigurableCase[[]string]{ + proptools.NewConfigurableCase[[]string](nil, &override), + }, + ) } } @@ -2107,11 +1640,21 @@ func (library *libraryDecorator) link(ctx ModuleContext, library.reexportDeps(deps.ReexportedDeps...) library.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...) + if library.static() && len(deps.ReexportedRustRlibDeps) > 0 { + library.reexportRustStaticDeps(deps.ReexportedRustRlibDeps...) + } + // Optionally export aidl headers. if Bool(library.Properties.Aidl.Export_aidl_headers) { - if library.baseCompiler.hasSrcExt(".aidl") { - dir := android.PathForModuleGen(ctx, "aidl") - library.reexportDirs(dir) + if library.baseCompiler.hasAidl(deps) { + if library.baseCompiler.hasSrcExt(".aidl") { + dir := android.PathForModuleGen(ctx, "aidl") + library.reexportDirs(dir) + } + if len(deps.AidlLibraryInfos) > 0 { + dir := android.PathForModuleGen(ctx, "aidl_library") + library.reexportDirs(dir) + } library.reexportDeps(library.baseCompiler.aidlOrderOnlyDeps...) library.addExportedGeneratedHeaders(library.baseCompiler.aidlHeaders...) @@ -2223,43 +1766,7 @@ func (library *libraryDecorator) installSymlinkToRuntimeApex(ctx ModuleContext, func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) { if library.shared() { - if ctx.Device() && ctx.useVndk() { - // set subDir for VNDK extensions - if ctx.IsVndkExt() { - if ctx.isVndkSp() { - library.baseInstaller.subDir = "vndk-sp" - } else { - library.baseInstaller.subDir = "vndk" - } - } - - // In some cases we want to use core variant for VNDK-Core libs. - // Skip product variant since VNDKs use only the vendor variant. - if ctx.isVndk() && !ctx.isVndkSp() && !ctx.IsVndkExt() && !ctx.inProduct() { - mayUseCoreVariant := true - - if ctx.mustUseVendorVariant() { - mayUseCoreVariant = false - } - - if ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) { - mayUseCoreVariant = false - } - - if mayUseCoreVariant { - library.checkSameCoreVariant = true - if ctx.DeviceConfig().VndkUseCoreVariant() { - library.useCoreVariant = true - } - } - } - - // do not install vndk libs - // vndk libs are packaged into VNDK APEX - if ctx.isVndk() && !ctx.IsVndkExt() { - return - } - } else if library.hasStubsVariants() && !ctx.Host() && ctx.directlyInAnyApex() { + if library.hasStubsVariants() && !ctx.Host() && ctx.directlyInAnyApex() { // Bionic libraries (e.g. libc.so) is installed to the bootstrap subdirectory. // The original path becomes a symlink to the corresponding file in the // runtime APEX. @@ -2280,7 +1787,7 @@ func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) { } if Bool(library.Properties.Static_ndk_lib) && library.static() && - !ctx.useVndk() && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && ctx.Device() && + !ctx.InVendorOrProduct() && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && ctx.Device() && library.baseLinker.sanitize.isUnsanitizedVariant() && ctx.isForPlatform() && !ctx.isPreventInstall() { installPath := getUnversionedLibraryInstallPath(ctx).Join(ctx, file.Base()) @@ -2375,12 +1882,13 @@ func (library *libraryDecorator) symbolFileForAbiCheck(ctx ModuleContext) *strin if props := library.getHeaderAbiCheckerProperties(ctx); props.Symbol_file != nil { return props.Symbol_file } - if ctx.Module().(*Module).IsLlndk() { - return library.Properties.Llndk.Symbol_file - } if library.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil { return library.Properties.Stubs.Symbol_file } + // TODO(b/309880485): Distinguish platform, NDK, LLNDK, and APEX version scripts. + if library.baseLinker.Properties.Version_script != nil { + return library.baseLinker.Properties.Version_script + } return nil } @@ -2400,13 +1908,16 @@ func (library *libraryDecorator) stubsVersions(ctx android.BaseMutatorContext) [ return nil } - if library.hasLLNDKStubs() && ctx.Module().(*Module).UseVndk() { - // LLNDK libraries only need a single stubs variant. - return []string{android.FutureApiLevel.String()} + if library.hasLLNDKStubs() && ctx.Module().(*Module).InVendorOrProduct() { + // LLNDK libraries only need a single stubs variant (""), which is + // added automatically in createVersionVariations(). + return nil } // Future API level is implicitly added if there isn't - return addCurrentVersionIfNotPresent(library.Properties.Stubs.Versions) + versions := addCurrentVersionIfNotPresent(library.Properties.Stubs.Versions) + normalizeVersions(ctx, versions) + return versions } func addCurrentVersionIfNotPresent(vers []string) []string { @@ -2559,8 +2070,8 @@ func reuseStaticLibrary(mctx android.BottomUpMutatorContext, static, shared *Mod // Check libraries in addition to cflags, since libraries may be exporting different // include directories. - if len(staticCompiler.StaticProperties.Static.Cflags) == 0 && - len(sharedCompiler.SharedProperties.Shared.Cflags) == 0 && + if len(staticCompiler.StaticProperties.Static.Cflags.GetOrDefault(mctx, nil)) == 0 && + len(sharedCompiler.SharedProperties.Shared.Cflags.GetOrDefault(mctx, nil)) == 0 && len(staticCompiler.StaticProperties.Static.Whole_static_libs) == 0 && len(sharedCompiler.SharedProperties.Shared.Whole_static_libs) == 0 && len(staticCompiler.StaticProperties.Static.Static_libs) == 0 && @@ -2624,14 +2135,12 @@ func LinkageMutator(mctx android.BottomUpMutatorContext) { // Header only } - } else if library, ok := mctx.Module().(LinkableInterface); ok && library.CcLibraryInterface() { - + } else if library, ok := mctx.Module().(LinkableInterface); ok && (library.CcLibraryInterface() || library.RustLibraryInterface()) { // Non-cc.Modules may need an empty variant for their mutators. variations := []string{} if library.NonCcVariants() { variations = append(variations, "") } - isLLNDK := false if m, ok := mctx.Module().(*Module); ok { isLLNDK = m.IsLlndk() @@ -2644,7 +2153,6 @@ func LinkageMutator(mctx android.BottomUpMutatorContext) { modules := mctx.CreateLocalVariations(variations...) static := modules[0].(LinkableInterface) shared := modules[1].(LinkableInterface) - static.SetStatic() shared.SetShared() @@ -2668,13 +2176,19 @@ func LinkageMutator(mctx android.BottomUpMutatorContext) { mctx.CreateLocalVariations(variations...) mctx.AliasVariation(variations[0]) } + if library.BuildRlibVariant() && library.IsRustFFI() && !buildStatic { + // Rust modules do not build static libs, but rlibs are used as if they + // were via `static_libs`. Thus we need to alias the BuildRlibVariant + // to "static" for Rust FFI libraries. + mctx.CreateAliasVariation("static", "") + } } } // normalizeVersions modifies `versions` in place, so that each raw version // string becomes its normalized canonical form. // Validates that the versions in `versions` are specified in least to greatest order. -func normalizeVersions(ctx android.BazelConversionPathContext, versions []string) { +func normalizeVersions(ctx android.BaseModuleContext, versions []string) { var previous android.ApiLevel for i, v := range versions { ver, err := android.ApiLevelFromUser(ctx, v) @@ -2706,8 +2220,12 @@ func createVersionVariations(mctx android.BottomUpMutatorContext, versions []str if variants[i] != "" || isLLNDK || isVendorPublicLibrary || isImportedApiLibrary { // A stubs or LLNDK stubs variant. c := m.(*Module) - c.sanitize = nil - c.stl = nil + if c.sanitize != nil { + c.sanitize.Properties.ForceDisable = true + } + if c.stl != nil { + c.stl.Properties.Stl = StringPtr("none") + } c.Properties.PreventInstall = true lib := moduleLibraryInterface(m) isLatest := i == (len(versions) - 1) @@ -2778,10 +2296,6 @@ func setStubsVersions(mctx android.BottomUpMutatorContext, library libraryInterf return } versions := library.stubsVersions(mctx) - if len(versions) <= 0 { - return - } - normalizeVersions(mctx, versions) if mctx.Failed() { return } @@ -2845,237 +2359,3 @@ func maybeInjectBoringSSLHash(ctx android.ModuleContext, outputFile android.Modu return outputFile } - -func bp2buildParseAbiCheckerProps(ctx android.TopDownMutatorContext, module *Module) bazelCcHeaderAbiCheckerAttributes { - lib, ok := module.linker.(*libraryDecorator) - if !ok { - return bazelCcHeaderAbiCheckerAttributes{} - } - - abiChecker := lib.getHeaderAbiCheckerProperties(ctx) - - abiCheckerAttrs := bazelCcHeaderAbiCheckerAttributes{ - Abi_checker_enabled: abiChecker.Enabled, - Abi_checker_exclude_symbol_versions: abiChecker.Exclude_symbol_versions, - Abi_checker_exclude_symbol_tags: abiChecker.Exclude_symbol_tags, - Abi_checker_check_all_apis: abiChecker.Check_all_apis, - Abi_checker_diff_flags: abiChecker.Diff_flags, - } - if abiChecker.Symbol_file != nil { - symbolFile := android.BazelLabelForModuleSrcSingle(ctx, *abiChecker.Symbol_file) - abiCheckerAttrs.Abi_checker_symbol_file = &symbolFile - } - - return abiCheckerAttrs -} - -func sharedOrStaticLibraryBp2Build(ctx android.TopDownMutatorContext, module *Module, isStatic bool) { - baseAttributes := bp2BuildParseBaseProps(ctx, module) - compilerAttrs := baseAttributes.compilerAttributes - linkerAttrs := baseAttributes.linkerAttributes - - exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, &compilerAttrs.includes) - - // Append shared/static{} stanza properties. These won't be specified on - // cc_library_* itself, but may be specified in cc_defaults that this module - // depends on. - libSharedOrStaticAttrs := bp2BuildParseLibProps(ctx, module, isStatic) - - compilerAttrs.srcs.Append(libSharedOrStaticAttrs.Srcs) - compilerAttrs.cSrcs.Append(libSharedOrStaticAttrs.Srcs_c) - compilerAttrs.asSrcs.Append(libSharedOrStaticAttrs.Srcs_as) - compilerAttrs.copts.Append(libSharedOrStaticAttrs.Copts) - - linkerAttrs.deps.Append(libSharedOrStaticAttrs.Deps) - linkerAttrs.implementationDeps.Append(libSharedOrStaticAttrs.Implementation_deps) - linkerAttrs.dynamicDeps.Append(libSharedOrStaticAttrs.Dynamic_deps) - linkerAttrs.implementationDynamicDeps.Append(libSharedOrStaticAttrs.Implementation_dynamic_deps) - linkerAttrs.systemDynamicDeps.Append(libSharedOrStaticAttrs.System_dynamic_deps) - - asFlags := compilerAttrs.asFlags - if compilerAttrs.asSrcs.IsEmpty() { - // Skip asflags for BUILD file simplicity if there are no assembly sources. - asFlags = bazel.MakeStringListAttribute(nil) - } - - commonAttrs := staticOrSharedAttributes{ - Srcs: compilerAttrs.srcs, - Srcs_c: compilerAttrs.cSrcs, - Srcs_as: compilerAttrs.asSrcs, - Copts: compilerAttrs.copts, - Hdrs: compilerAttrs.hdrs, - - Deps: linkerAttrs.deps, - Implementation_deps: linkerAttrs.implementationDeps, - Dynamic_deps: linkerAttrs.dynamicDeps, - Implementation_dynamic_deps: linkerAttrs.implementationDynamicDeps, - Whole_archive_deps: linkerAttrs.wholeArchiveDeps, - Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps, - System_dynamic_deps: linkerAttrs.systemDynamicDeps, - sdkAttributes: bp2BuildParseSdkAttributes(module), - Runtime_deps: linkerAttrs.runtimeDeps, - Native_coverage: baseAttributes.Native_coverage, - } - - module.convertTidyAttributes(ctx, &commonAttrs.tidyAttributes) - - var attrs interface{} - if isStatic { - commonAttrs.Deps.Add(baseAttributes.protoDependency) - attrs = &bazelCcLibraryStaticAttributes{ - staticOrSharedAttributes: commonAttrs, - Rtti: compilerAttrs.rtti, - Stl: compilerAttrs.stl, - Cpp_std: compilerAttrs.cppStd, - C_std: compilerAttrs.cStd, - - Export_includes: exportedIncludes.Includes, - Export_absolute_includes: exportedIncludes.AbsoluteIncludes, - Export_system_includes: exportedIncludes.SystemIncludes, - Local_includes: compilerAttrs.localIncludes, - Absolute_includes: compilerAttrs.absoluteIncludes, - - Cppflags: compilerAttrs.cppFlags, - Conlyflags: compilerAttrs.conlyFlags, - Asflags: asFlags, - - Features: baseAttributes.features, - } - } else { - commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency) - - sharedLibAttrs := &bazelCcLibrarySharedAttributes{ - staticOrSharedAttributes: commonAttrs, - - Cppflags: compilerAttrs.cppFlags, - Conlyflags: compilerAttrs.conlyFlags, - Asflags: asFlags, - - Linkopts: linkerAttrs.linkopts, - Use_version_lib: linkerAttrs.useVersionLib, - - Rtti: compilerAttrs.rtti, - Stl: compilerAttrs.stl, - Cpp_std: compilerAttrs.cppStd, - C_std: compilerAttrs.cStd, - - Export_includes: exportedIncludes.Includes, - Export_absolute_includes: exportedIncludes.AbsoluteIncludes, - Export_system_includes: exportedIncludes.SystemIncludes, - Local_includes: compilerAttrs.localIncludes, - Absolute_includes: compilerAttrs.absoluteIncludes, - Additional_linker_inputs: linkerAttrs.additionalLinkerInputs, - - Strip: stripAttrsFromLinkerAttrs(&linkerAttrs), - - Features: baseAttributes.features, - - Suffix: compilerAttrs.suffix, - - bazelCcHeaderAbiCheckerAttributes: bp2buildParseAbiCheckerProps(ctx, module), - - Fdo_profile: compilerAttrs.fdoProfile, - } - if compilerAttrs.stubsSymbolFile != nil && len(compilerAttrs.stubsVersions.Value) > 0 { - sharedLibAttrs.Stubs_symbol_file = compilerAttrs.stubsSymbolFile - } - attrs = sharedLibAttrs - } - - var modType string - if isStatic { - modType = "cc_library_static" - } else { - modType = "cc_library_shared" - createStubsBazelTargetIfNeeded(ctx, module, compilerAttrs, exportedIncludes, baseAttributes) - } - props := bazel.BazelTargetModuleProperties{ - Rule_class: modType, - Bzl_load_location: fmt.Sprintf("//build/bazel/rules/cc:%s.bzl", modType), - } - - tags := android.ApexAvailableTags(module) - - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name(), Tags: tags}, attrs) -} - -// TODO(b/199902614): Can this be factored to share with the other Attributes? -type bazelCcLibraryStaticAttributes struct { - staticOrSharedAttributes - - Use_version_lib bazel.BoolAttribute - Rtti bazel.BoolAttribute - Stl *string - Cpp_std *string - C_std *string - - Export_includes bazel.StringListAttribute - Export_absolute_includes bazel.StringListAttribute - Export_system_includes bazel.StringListAttribute - Local_includes bazel.StringListAttribute - Absolute_includes bazel.StringListAttribute - Hdrs bazel.LabelListAttribute - - Cppflags bazel.StringListAttribute - Conlyflags bazel.StringListAttribute - Asflags bazel.StringListAttribute - - Features bazel.StringListAttribute -} - -// TODO(b/199902614): Can this be factored to share with the other Attributes? -type bazelCcLibrarySharedAttributes struct { - staticOrSharedAttributes - - Linkopts bazel.StringListAttribute - Use_version_lib bazel.BoolAttribute - - Rtti bazel.BoolAttribute - Stl *string - Cpp_std *string - C_std *string - - Export_includes bazel.StringListAttribute - Export_absolute_includes bazel.StringListAttribute - Export_system_includes bazel.StringListAttribute - Local_includes bazel.StringListAttribute - Absolute_includes bazel.StringListAttribute - Hdrs bazel.LabelListAttribute - - Strip stripAttributes - Additional_linker_inputs bazel.LabelListAttribute - - Cppflags bazel.StringListAttribute - Conlyflags bazel.StringListAttribute - Asflags bazel.StringListAttribute - - Features bazel.StringListAttribute - - Stubs_symbol_file *string - - Inject_bssl_hash bazel.BoolAttribute - - Suffix bazel.StringAttribute - - bazelCcHeaderAbiCheckerAttributes - - Fdo_profile bazel.LabelAttribute -} - -type bazelCcStubSuiteAttributes struct { - Symbol_file *string - Versions bazel.StringListAttribute - Export_includes bazel.StringListAttribute - Source_library_label *string - Soname *string - Deps bazel.LabelListAttribute -} - -type bazelCcHeaderAbiCheckerAttributes struct { - Abi_checker_enabled *bool - Abi_checker_symbol_file *bazel.Label - Abi_checker_exclude_symbol_versions []string - Abi_checker_exclude_symbol_tags []string - Abi_checker_check_all_apis *bool - Abi_checker_diff_flags []string -} diff --git a/cc/library_headers.go b/cc/library_headers.go index 1dee72679..98533b248 100644 --- a/cc/library_headers.go +++ b/cc/library_headers.go @@ -15,11 +15,7 @@ package cc import ( - "github.com/google/blueprint/proptools" - "android/soong/android" - "android/soong/bazel" - "android/soong/bazel/cquery" ) func init() { @@ -50,52 +46,6 @@ func RegisterLibraryHeadersBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("cc_prebuilt_library_headers", prebuiltLibraryHeaderFactory) } -type libraryHeaderBazelHandler struct { - module *Module - library *libraryDecorator -} - -var _ BazelHandler = (*libraryHeaderBazelHandler)(nil) - -func (handler *libraryHeaderBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) { - bazelCtx := ctx.Config().BazelContext - bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx))) -} - -func (h *libraryHeaderBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) { - bazelCtx := ctx.Config().BazelContext - ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx))) - if err != nil { - ctx.ModuleErrorf(err.Error()) - return - } - - outputPaths := ccInfo.OutputFiles - if len(outputPaths) != 1 { - ctx.ModuleErrorf("expected exactly one output file for %q, but got %q", label, outputPaths) - return - } - - var outputPath android.Path = android.PathForBazelOut(ctx, outputPaths[0]) - if len(ccInfo.TidyFiles) > 0 { - h.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles) - outputPath = android.AttachValidationActions(ctx, outputPath, h.module.tidyFiles) - } - h.module.outputFile = android.OptionalPathForPath(outputPath) - - // HeaderLibraryInfo is an empty struct to indicate to dependencies that this is a header library - ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{}) - - h.library.setFlagExporterInfoFromCcInfo(ctx, ccInfo) - - // Dependencies on this library will expect collectedSnapshotHeaders to be set, otherwise - // validation will fail. For now, set this to an empty list. - // TODO(cparsons): More closely mirror the collectHeadersForSnapshot implementation. - h.library.collectedSnapshotHeaders = android.Paths{} - - h.module.setAndroidMkVariablesFromCquery(ccInfo.CcAndroidMkInfo) -} - // cc_library_headers contains a set of c/c++ headers which are imported by // other soong cc modules using the header_libs property. For best practices, // use export_include_dirs property or LOCAL_EXPORT_C_INCLUDE_DIRS for @@ -104,8 +54,6 @@ func LibraryHeaderFactory() android.Module { module, library := NewLibrary(android.HostAndDeviceSupported) library.HeaderOnly() module.sdkMemberTypes = []android.SdkMemberType{headersLibrarySdkMemberType} - module.bazelable = true - module.bazelHandler = &libraryHeaderBazelHandler{module: module, library: library} return module.Init() } @@ -113,163 +61,5 @@ func LibraryHeaderFactory() android.Module { func prebuiltLibraryHeaderFactory() android.Module { module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported, "") library.HeaderOnly() - module.bazelable = true - module.bazelHandler = &ccLibraryBazelHandler{module: module} return module.Init() } - -type bazelCcLibraryHeadersAttributes struct { - Hdrs bazel.LabelListAttribute - Export_includes bazel.StringListAttribute - Export_absolute_includes bazel.StringListAttribute - Export_system_includes bazel.StringListAttribute - Deps bazel.LabelListAttribute - Implementation_deps bazel.LabelListAttribute - System_dynamic_deps bazel.LabelListAttribute - sdkAttributes -} - -func libraryHeadersBp2Build(ctx android.TopDownMutatorContext, module *Module) { - baseAttributes := bp2BuildParseBaseProps(ctx, module) - exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, &baseAttributes.includes) - linkerAttrs := baseAttributes.linkerAttributes - (&linkerAttrs.deps).Append(linkerAttrs.dynamicDeps) - (&linkerAttrs.deps).Append(linkerAttrs.wholeArchiveDeps) - - attrs := &bazelCcLibraryHeadersAttributes{ - Export_includes: exportedIncludes.Includes, - Export_absolute_includes: exportedIncludes.AbsoluteIncludes, - Export_system_includes: exportedIncludes.SystemIncludes, - Deps: linkerAttrs.deps, - System_dynamic_deps: linkerAttrs.systemDynamicDeps, - Hdrs: baseAttributes.hdrs, - sdkAttributes: bp2BuildParseSdkAttributes(module), - } - - props := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_library_headers", - Bzl_load_location: "//build/bazel/rules/cc:cc_library_headers.bzl", - } - - tags := android.ApexAvailableTags(module) - - ctx.CreateBazelTargetModule(props, android.CommonAttributes{ - Name: module.Name(), - Tags: tags, - }, attrs) -} - -// Append .contribution suffix to input labels -func apiBazelTargets(ll bazel.LabelList) bazel.LabelList { - labels := make([]bazel.Label, 0) - for _, l := range ll.Includes { - labels = append(labels, bazel.Label{ - Label: android.ApiContributionTargetName(l.Label), - }) - } - return bazel.MakeLabelList(labels) -} - -func apiLibraryHeadersBp2Build(ctx android.TopDownMutatorContext, module *Module) { - // cc_api_library_headers have a 1:1 mapping to arch/no-arch - // For API export, create a top-level arch-agnostic target and list the arch-specific targets as its deps - - // arch-agnostic includes - apiIncludes := getModuleLibApiIncludes(ctx, module) - // arch and os specific includes - archApiIncludes, androidOsIncludes := archOsSpecificApiIncludes(ctx, module) - for _, arch := range allArches { // sorted iteration - archApiInclude := archApiIncludes[arch] - if !archApiInclude.isEmpty() { - createApiHeaderTarget(ctx, archApiInclude) - apiIncludes.addDep(archApiInclude.name) - } - } - // os==android includes - if !androidOsIncludes.isEmpty() { - createApiHeaderTarget(ctx, androidOsIncludes) - apiIncludes.addDep(androidOsIncludes.name) - } - - if !apiIncludes.isEmpty() { - // override the name from <mod>.module-libapi.headers --> <mod>.contribution - apiIncludes.name = android.ApiContributionTargetName(module.Name()) - createApiHeaderTarget(ctx, apiIncludes) - } -} - -func createApiHeaderTarget(ctx android.TopDownMutatorContext, includes apiIncludes) { - props := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_api_library_headers", - Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl", - } - ctx.CreateBazelTargetModule( - props, - android.CommonAttributes{ - Name: includes.name, - SkipData: proptools.BoolPtr(true), - }, - &includes.attrs, - ) -} - -var ( - allArches = []string{"arm", "arm64", "x86", "x86_64"} -) - -type archApiIncludes map[string]apiIncludes - -func archOsSpecificApiIncludes(ctx android.TopDownMutatorContext, module *Module) (archApiIncludes, apiIncludes) { - baseProps := bp2BuildParseBaseProps(ctx, module) - i := bp2BuildParseExportedIncludes(ctx, module, &baseProps.includes) - archRet := archApiIncludes{} - for _, arch := range allArches { - includes := i.Includes.SelectValue( - bazel.ArchConfigurationAxis, - arch) - systemIncludes := i.SystemIncludes.SelectValue( - bazel.ArchConfigurationAxis, - arch) - deps := baseProps.deps.SelectValue( - bazel.ArchConfigurationAxis, - arch) - attrs := bazelCcLibraryHeadersAttributes{ - Export_includes: bazel.MakeStringListAttribute(includes), - Export_system_includes: bazel.MakeStringListAttribute(systemIncludes), - } - apiDeps := apiBazelTargets(deps) - if !apiDeps.IsEmpty() { - attrs.Deps = bazel.MakeLabelListAttribute(apiDeps) - } - apiIncludes := apiIncludes{ - name: android.ApiContributionTargetName(module.Name()) + "." + arch, - attrs: bazelCcApiLibraryHeadersAttributes{ - bazelCcLibraryHeadersAttributes: attrs, - Arch: proptools.StringPtr(arch), - }, - } - archRet[arch] = apiIncludes - } - - // apiIncludes for os == Android - androidOsDeps := baseProps.deps.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid) - androidOsAttrs := bazelCcLibraryHeadersAttributes{ - Export_includes: bazel.MakeStringListAttribute( - i.Includes.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid), - ), - Export_system_includes: bazel.MakeStringListAttribute( - i.SystemIncludes.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid), - ), - } - androidOsApiDeps := apiBazelTargets(androidOsDeps) - if !androidOsApiDeps.IsEmpty() { - androidOsAttrs.Deps = bazel.MakeLabelListAttribute(androidOsApiDeps) - } - osRet := apiIncludes{ - name: android.ApiContributionTargetName(module.Name()) + ".androidos", - attrs: bazelCcApiLibraryHeadersAttributes{ - bazelCcLibraryHeadersAttributes: androidOsAttrs, - }, - } - return archRet, osRet -} diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go index e743bb6ce..1f71c1922 100644 --- a/cc/library_sdk_member.go +++ b/cc/library_sdk_member.go @@ -31,6 +31,7 @@ var sharedLibrarySdkMemberType = &librarySdkMemberType{ SupportsSdk: true, HostOsDependent: true, SupportedLinkageNames: []string{"shared"}, + StripDisabled: true, }, prebuiltModuleType: "cc_prebuilt_library_shared", } @@ -251,16 +252,9 @@ func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMembe return &nativeLibInfoProperties{memberType: mt} } -func isBazelOutDirectory(p android.Path) bool { - _, bazel := p.(android.BazelOutPath) - return bazel -} - func isGeneratedHeaderDirectory(p android.Path) bool { _, gen := p.(android.WritablePath) - // TODO(b/183213331): Here we assume that bazel-based headers are not generated; we need - // to support generated headers in mixed builds. - return gen && !isBazelOutDirectory(p) + return gen } type includeDirsProperty struct { @@ -518,7 +512,7 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte } } - exportedInfo := ctx.SdkModuleContext().OtherModuleProvider(variant, FlagExporterInfoProvider).(FlagExporterInfo) + exportedInfo, _ := android.OtherModuleProvider(ctx.SdkModuleContext(), variant, FlagExporterInfoProvider) // Separate out the generated include dirs (which are arch specific) from the // include dirs (which may not be). diff --git a/cc/library_stub.go b/cc/library_stub.go index 18d3f210c..6f06333ac 100644 --- a/cc/library_stub.go +++ b/cc/library_stub.go @@ -20,6 +20,8 @@ import ( "android/soong/android" "android/soong/multitree" + + "github.com/google/blueprint/proptools" ) var ( @@ -48,7 +50,7 @@ func updateImportedLibraryDependency(ctx android.BottomUpMutatorContext) { return } - if m.UseVndk() && apiLibrary.hasLLNDKStubs() { + if m.InVendorOrProduct() && apiLibrary.hasLLNDKStubs() { // Add LLNDK variant dependency if inList("llndk", apiLibrary.properties.Variants) { variantName := BuildApiVariantName(m.BaseModuleName(), "llndk", "") @@ -122,7 +124,7 @@ func (d *apiLibraryDecorator) Name(basename string) string { // The directories are not guaranteed to exist during Soong analysis. func (d *apiLibraryDecorator) exportIncludes(ctx ModuleContext) { exporterProps := d.flagExporter.Properties - for _, dir := range exporterProps.Export_include_dirs { + for _, dir := range exporterProps.Export_include_dirs.GetOrDefault(ctx, nil) { d.dirs = append(d.dirs, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), dir)) } // system headers @@ -178,22 +180,27 @@ func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps in = variantMod.Src() // Copy LLDNK properties to cc_api_library module - d.libraryDecorator.flagExporter.Properties.Export_include_dirs = append( - d.libraryDecorator.flagExporter.Properties.Export_include_dirs, + exportIncludeDirs := append(d.libraryDecorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil), variantMod.exportProperties.Export_include_dirs...) + d.libraryDecorator.flagExporter.Properties.Export_include_dirs = proptools.NewConfigurable[[]string]( + nil, + []proptools.ConfigurableCase[[]string]{ + proptools.NewConfigurableCase[[]string](nil, &exportIncludeDirs), + }, + ) // Export headers as system include dirs if specified. Mostly for libc if Bool(variantMod.exportProperties.Export_headers_as_system) { d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append( d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs, - d.libraryDecorator.flagExporter.Properties.Export_include_dirs...) - d.libraryDecorator.flagExporter.Properties.Export_include_dirs = nil + d.libraryDecorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil)...) + d.libraryDecorator.flagExporter.Properties.Export_include_dirs = proptools.NewConfigurable[[]string](nil, nil) } } } } - if m.UseVndk() && d.hasLLNDKStubs() { + if m.InVendorOrProduct() && d.hasLLNDKStubs() { // LLNDK variant load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "llndk", "")) } else if m.IsSdkVariant() { @@ -244,7 +251,7 @@ func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps }, }) - ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{ + android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{ SharedLibrary: outputFile, Target: ctx.Target(), @@ -262,15 +269,15 @@ func (d *apiLibraryDecorator) shareStubs(ctx ModuleContext) { if len(stubs) > 0 { var stubsInfo []SharedStubLibrary for _, stub := range stubs { - stubInfo := ctx.OtherModuleProvider(stub, SharedLibraryInfoProvider).(SharedLibraryInfo) - flagInfo := ctx.OtherModuleProvider(stub, FlagExporterInfoProvider).(FlagExporterInfo) + stubInfo, _ := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider) + flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider) stubsInfo = append(stubsInfo, SharedStubLibrary{ Version: moduleLibraryInterface(stub).stubsVersion(), SharedLibraryInfo: stubInfo, FlagExporterInfo: flagInfo, }) } - ctx.SetProvider(SharedLibraryStubsProvider, SharedLibraryStubsInfo{ + android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{ SharedStubLibraries: stubsInfo, IsLLNDK: ctx.IsLlndk(), @@ -312,7 +319,7 @@ func (d *apiLibraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []st } } - if d.hasLLNDKStubs() && m.UseVndk() { + if d.hasLLNDKStubs() && m.InVendorOrProduct() { // LLNDK libraries only need a single stubs variant. return []string{android.FutureApiLevel.String()} } @@ -487,6 +494,12 @@ func BuildApiVariantName(baseName string, variant string, version string) string // Implement ImageInterface to generate image variants func (v *CcApiVariant) ImageMutatorBegin(ctx android.BaseModuleContext) {} +func (v *CcApiVariant) VendorVariantNeeded(ctx android.BaseModuleContext) bool { + return String(v.properties.Variant) == "llndk" +} +func (v *CcApiVariant) ProductVariantNeeded(ctx android.BaseModuleContext) bool { + return String(v.properties.Variant) == "llndk" +} func (v *CcApiVariant) CoreVariantNeeded(ctx android.BaseModuleContext) bool { return inList(String(v.properties.Variant), []string{"ndk", "apex"}) } @@ -494,16 +507,6 @@ func (v *CcApiVariant) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool func (v *CcApiVariant) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false } func (v *CcApiVariant) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false } func (v *CcApiVariant) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { return false } -func (v *CcApiVariant) ExtraImageVariations(ctx android.BaseModuleContext) []string { - var variations []string - platformVndkVersion := ctx.DeviceConfig().PlatformVndkVersion() - - if String(v.properties.Variant) == "llndk" { - variations = append(variations, VendorVariationPrefix+platformVndkVersion) - variations = append(variations, ProductVariationPrefix+platformVndkVersion) - } - - return variations -} -func (v *CcApiVariant) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) { +func (v *CcApiVariant) ExtraImageVariations(ctx android.BaseModuleContext) []string { return nil } +func (v *CcApiVariant) SetImageVariation(ctx android.BaseModuleContext, variation string) { } diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go deleted file mode 100644 index 528577a21..000000000 --- a/cc/library_stub_test.go +++ /dev/null @@ -1,459 +0,0 @@ -// 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 ( - _ "fmt" - _ "sort" - - "testing" - - "android/soong/android" - - "github.com/google/blueprint" -) - -func hasDirectDependency(t *testing.T, ctx *android.TestResult, from android.Module, to android.Module) bool { - t.Helper() - var found bool - ctx.VisitDirectDeps(from, func(dep blueprint.Module) { - if dep == to { - found = true - } - }) - return found -} - -func TestApiLibraryReplacesExistingModule(t *testing.T) { - bp := ` - cc_library { - name: "libfoo", - shared_libs: ["libbar"], - vendor_available: true, - } - - cc_library { - name: "libbar", - } - - cc_api_library { - name: "libbar", - vendor_available: true, - src: "libbar.so", - } - - api_imports { - name: "api_imports", - shared_libs: [ - "libbar", - ], - } - ` - - ctx := prepareForCcTest.RunTestWithBp(t, bp) - - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() - libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module() - libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module() - - android.AssertBoolEquals(t, "original library should be linked with non-stub variant", true, hasDirectDependency(t, ctx, libfoo, libbar)) - android.AssertBoolEquals(t, "Stub library from API surface should be not linked with non-stub variant", false, hasDirectDependency(t, ctx, libfoo, libbarApiImport)) - - libfooVendor := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_shared").Module() - libbarApiImportVendor := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module() - - android.AssertBoolEquals(t, "original library should not be linked", false, hasDirectDependency(t, ctx, libfooVendor, libbar)) - android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfooVendor, libbarApiImportVendor)) -} - -func TestApiLibraryDoNotRequireOriginalModule(t *testing.T) { - bp := ` - cc_library { - name: "libfoo", - shared_libs: ["libbar"], - vendor: true, - } - - cc_api_library { - name: "libbar", - src: "libbar.so", - vendor_available: true, - } - - api_imports { - name: "api_imports", - shared_libs: [ - "libbar", - ], - } - ` - - ctx := prepareForCcTest.RunTestWithBp(t, bp) - - libfoo := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_shared").Module() - libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module() - - android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport)) -} - -func TestApiLibraryShouldNotReplaceWithoutApiImport(t *testing.T) { - bp := ` - cc_library { - name: "libfoo", - shared_libs: ["libbar"], - vendor_available: true, - } - - cc_library { - name: "libbar", - vendor_available: true, - } - - cc_api_library { - name: "libbar", - src: "libbar.so", - vendor_available: true, - } - - api_imports { - name: "api_imports", - shared_libs: [], - } - ` - - ctx := prepareForCcTest.RunTestWithBp(t, bp) - - libfoo := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_shared").Module() - libbar := ctx.ModuleForTests("libbar", "android_vendor.29_arm64_armv8-a_shared").Module() - libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module() - - android.AssertBoolEquals(t, "original library should be linked", true, hasDirectDependency(t, ctx, libfoo, libbar)) - android.AssertBoolEquals(t, "Stub library from API surface should not be linked", false, hasDirectDependency(t, ctx, libfoo, libbarApiImport)) -} - -func TestExportDirFromStubLibrary(t *testing.T) { - bp := ` - cc_library { - name: "libfoo", - export_include_dirs: ["source_include_dir"], - export_system_include_dirs: ["source_system_include_dir"], - vendor_available: true, - } - cc_api_library { - name: "libfoo", - export_include_dirs: ["stub_include_dir"], - export_system_include_dirs: ["stub_system_include_dir"], - vendor_available: true, - src: "libfoo.so", - } - api_imports { - name: "api_imports", - shared_libs: [ - "libfoo", - ], - header_libs: [], - } - // vendor binary - cc_binary { - name: "vendorbin", - vendor: true, - srcs: ["vendor.cc"], - shared_libs: ["libfoo"], - } - ` - ctx := prepareForCcTest.RunTestWithBp(t, bp) - vendorCFlags := ctx.ModuleForTests("vendorbin", "android_vendor.29_arm64_armv8-a").Rule("cc").Args["cFlags"] - android.AssertStringDoesContain(t, "Vendor binary should compile using headers provided by stub", vendorCFlags, "-Istub_include_dir") - android.AssertStringDoesNotContain(t, "Vendor binary should not compile using headers of source", vendorCFlags, "-Isource_include_dir") - android.AssertStringDoesContain(t, "Vendor binary should compile using system headers provided by stub", vendorCFlags, "-isystem stub_system_include_dir") - android.AssertStringDoesNotContain(t, "Vendor binary should not compile using system headers of source", vendorCFlags, "-isystem source_system_include_dir") - - vendorImplicits := ctx.ModuleForTests("vendorbin", "android_vendor.29_arm64_armv8-a").Rule("cc").OrderOnly.Strings() - // Building the stub.so file first assembles its .h files in multi-tree out. - // These header files are required for compiling the other API domain (vendor in this case) - android.AssertStringListContains(t, "Vendor binary compilation should have an implicit dep on the stub .so file", vendorImplicits, "libfoo.so") -} - -func TestApiLibraryWithLlndkVariant(t *testing.T) { - bp := ` - cc_binary { - name: "binfoo", - vendor: true, - srcs: ["binfoo.cc"], - shared_libs: ["libbar"], - } - - cc_api_library { - name: "libbar", - // TODO(b/244244438) Remove src property once all variants are implemented. - src: "libbar.so", - vendor_available: true, - variants: [ - "llndk", - ], - } - - cc_api_variant { - name: "libbar", - variant: "llndk", - src: "libbar_llndk.so", - export_include_dirs: ["libbar_llndk_include"] - } - - api_imports { - name: "api_imports", - shared_libs: [ - "libbar", - ], - header_libs: [], - } - ` - - ctx := prepareForCcTest.RunTestWithBp(t, bp) - - binfoo := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Module() - libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module() - libbarApiVariant := ctx.ModuleForTests("libbar.llndk.apiimport", "android_vendor.29_arm64_armv8-a").Module() - - android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, binfoo, libbarApiImport)) - android.AssertBoolEquals(t, "Stub library variant from API surface should be linked", true, hasDirectDependency(t, ctx, libbarApiImport, libbarApiVariant)) - - binFooLibFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("ld").Args["libFlags"] - android.AssertStringDoesContain(t, "Vendor binary should be linked with LLNDK variant source", binFooLibFlags, "libbar.llndk.apiimport.so") - - binFooCFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("cc").Args["cFlags"] - android.AssertStringDoesContain(t, "Vendor binary should include headers from the LLNDK variant source", binFooCFlags, "-Ilibbar_llndk_include") -} - -func TestApiLibraryWithNdkVariant(t *testing.T) { - bp := ` - cc_binary { - name: "binfoo", - sdk_version: "29", - srcs: ["binfoo.cc"], - shared_libs: ["libbar"], - stl: "c++_shared", - } - - cc_binary { - name: "binbaz", - sdk_version: "30", - srcs: ["binbaz.cc"], - shared_libs: ["libbar"], - stl: "c++_shared", - } - - cc_binary { - name: "binqux", - srcs: ["binfoo.cc"], - shared_libs: ["libbar"], - } - - cc_library { - name: "libbar", - srcs: ["libbar.cc"], - } - - cc_api_library { - name: "libbar", - // TODO(b/244244438) Remove src property once all variants are implemented. - src: "libbar.so", - variants: [ - "ndk.29", - "ndk.30", - "ndk.current", - ], - } - - cc_api_variant { - name: "libbar", - variant: "ndk", - version: "29", - src: "libbar_ndk_29.so", - export_include_dirs: ["libbar_ndk_29_include"] - } - - cc_api_variant { - name: "libbar", - variant: "ndk", - version: "30", - src: "libbar_ndk_30.so", - export_include_dirs: ["libbar_ndk_30_include"] - } - - cc_api_variant { - name: "libbar", - variant: "ndk", - version: "current", - src: "libbar_ndk_current.so", - export_include_dirs: ["libbar_ndk_current_include"] - } - - api_imports { - name: "api_imports", - shared_libs: [ - "libbar", - ], - header_libs: [], - } - ` - - ctx := prepareForCcTest.RunTestWithBp(t, bp) - - binfoo := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Module() - libbarApiImportv29 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_29").Module() - libbarApiVariantv29 := ctx.ModuleForTests("libbar.ndk.29.apiimport", "android_arm64_armv8-a_sdk").Module() - libbarApiImportv30 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_30").Module() - libbarApiVariantv30 := ctx.ModuleForTests("libbar.ndk.30.apiimport", "android_arm64_armv8-a_sdk").Module() - - android.AssertBoolEquals(t, "Stub library from API surface should be linked with target version", true, hasDirectDependency(t, ctx, binfoo, libbarApiImportv29)) - android.AssertBoolEquals(t, "Stub library variant from API surface should be linked with target version", true, hasDirectDependency(t, ctx, libbarApiImportv29, libbarApiVariantv29)) - android.AssertBoolEquals(t, "Stub library from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, binfoo, libbarApiImportv30)) - android.AssertBoolEquals(t, "Stub library variant from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, libbarApiImportv29, libbarApiVariantv30)) - - binbaz := ctx.ModuleForTests("binbaz", "android_arm64_armv8-a_sdk").Module() - - android.AssertBoolEquals(t, "Stub library from API surface should be linked with target version", true, hasDirectDependency(t, ctx, binbaz, libbarApiImportv30)) - android.AssertBoolEquals(t, "Stub library from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, binbaz, libbarApiImportv29)) - - binFooLibFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("ld").Args["libFlags"] - android.AssertStringDoesContain(t, "Binary using sdk should be linked with NDK variant source", binFooLibFlags, "libbar.ndk.29.apiimport.so") - - binFooCFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("cc").Args["cFlags"] - android.AssertStringDoesContain(t, "Binary using sdk should include headers from the NDK variant source", binFooCFlags, "-Ilibbar_ndk_29_include") - - binQux := ctx.ModuleForTests("binqux", "android_arm64_armv8-a").Module() - android.AssertBoolEquals(t, "NDK Stub library from API surface should not be linked with nonSdk binary", false, - (hasDirectDependency(t, ctx, binQux, libbarApiImportv30) || hasDirectDependency(t, ctx, binQux, libbarApiImportv29))) -} - -func TestApiLibraryWithMultipleVariants(t *testing.T) { - bp := ` - cc_binary { - name: "binfoo", - sdk_version: "29", - srcs: ["binfoo.cc"], - shared_libs: ["libbar"], - stl: "c++_shared", - } - - cc_binary { - name: "binbaz", - vendor: true, - srcs: ["binbaz.cc"], - shared_libs: ["libbar"], - } - - cc_library { - name: "libbar", - srcs: ["libbar.cc"], - } - - cc_api_library { - name: "libbar", - // TODO(b/244244438) Remove src property once all variants are implemented. - src: "libbar.so", - vendor_available: true, - variants: [ - "llndk", - "ndk.29", - "ndk.30", - "ndk.current", - "apex.29", - "apex.30", - "apex.current", - ], - } - - cc_api_variant { - name: "libbar", - variant: "ndk", - version: "29", - src: "libbar_ndk_29.so", - export_include_dirs: ["libbar_ndk_29_include"] - } - - cc_api_variant { - name: "libbar", - variant: "ndk", - version: "30", - src: "libbar_ndk_30.so", - export_include_dirs: ["libbar_ndk_30_include"] - } - - cc_api_variant { - name: "libbar", - variant: "ndk", - version: "current", - src: "libbar_ndk_current.so", - export_include_dirs: ["libbar_ndk_current_include"] - } - - cc_api_variant { - name: "libbar", - variant: "apex", - version: "29", - src: "libbar_apex_29.so", - export_include_dirs: ["libbar_apex_29_include"] - } - - cc_api_variant { - name: "libbar", - variant: "apex", - version: "30", - src: "libbar_apex_30.so", - export_include_dirs: ["libbar_apex_30_include"] - } - - cc_api_variant { - name: "libbar", - variant: "apex", - version: "current", - src: "libbar_apex_current.so", - export_include_dirs: ["libbar_apex_current_include"] - } - - cc_api_variant { - name: "libbar", - variant: "llndk", - src: "libbar_llndk.so", - export_include_dirs: ["libbar_llndk_include"] - } - - api_imports { - name: "api_imports", - shared_libs: [ - "libbar", - ], - apex_shared_libs: [ - "libbar", - ], - } - ` - ctx := prepareForCcTest.RunTestWithBp(t, bp) - - binfoo := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Module() - libbarApiImportv29 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_29").Module() - libbarApiImportLlndk := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module() - - android.AssertBoolEquals(t, "Binary using SDK should be linked with API library from NDK variant", true, hasDirectDependency(t, ctx, binfoo, libbarApiImportv29)) - android.AssertBoolEquals(t, "Binary using SDK should not be linked with API library from LLNDK variant", false, hasDirectDependency(t, ctx, binfoo, libbarApiImportLlndk)) - - binbaz := ctx.ModuleForTests("binbaz", "android_vendor.29_arm64_armv8-a").Module() - - android.AssertBoolEquals(t, "Vendor binary should be linked with API library from LLNDK variant", true, hasDirectDependency(t, ctx, binbaz, libbarApiImportLlndk)) - android.AssertBoolEquals(t, "Vendor binary should not be linked with API library from NDK variant", false, hasDirectDependency(t, ctx, binbaz, libbarApiImportv29)) - -} diff --git a/cc/library_test.go b/cc/library_test.go index dbe2be899..2ed2d761c 100644 --- a/cc/library_test.go +++ b/cc/library_test.go @@ -19,7 +19,6 @@ import ( "testing" "android/soong/android" - "android/soong/bazel/cquery" ) func TestLibraryReuse(t *testing.T) { @@ -246,137 +245,6 @@ func TestStubsVersions_ParseError(t *testing.T) { testCcError(t, `"libfoo" .*: versions: "X" could not be parsed as an integer and is not a recognized codename`, bp) } -func TestCcLibraryWithBazel(t *testing.T) { - t.Parallel() - bp := ` -cc_library { - name: "foo", - srcs: ["foo.cc"], - bazel_module: { label: "//foo/bar:bar" }, -}` - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: "outputbase", - LabelToCcInfo: map[string]cquery.CcInfo{ - "//foo/bar:bar": cquery.CcInfo{ - CcObjectFiles: []string{"foo.o"}, - Includes: []string{"include"}, - SystemIncludes: []string{"system_include"}, - Headers: []string{"foo.h"}, - RootDynamicLibraries: []string{"foo.so"}, - UnstrippedOutput: "foo_unstripped.so", - }, - "//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{ - CcObjectFiles: []string{"foo.o"}, - Includes: []string{"include"}, - SystemIncludes: []string{"system_include"}, - Headers: []string{"foo.h"}, - RootStaticArchives: []string{"foo.a"}, - }, - }, - } - ctx := testCcWithConfig(t, config) - - staticFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module() - outputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object outputfiles %s", err) - } - - expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.a"} - android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings()) - - flagExporter := ctx.ModuleProvider(staticFoo, FlagExporterInfoProvider).(FlagExporterInfo) - android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs) - android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs) - android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders) - android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps) - - sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module() - outputFiles, err = sharedFoo.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_library outputfiles %s", err) - } - expectedOutputFiles = []string{"outputbase/execroot/__main__/foo.so"} - android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings()) - - android.AssertStringEquals(t, "unstripped shared library", "outputbase/execroot/__main__/foo_unstripped.so", sharedFoo.(*Module).linker.unstrippedOutputFilePath().String()) - flagExporter = ctx.ModuleProvider(sharedFoo, FlagExporterInfoProvider).(FlagExporterInfo) - android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs) - android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs) - android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders) - android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps) -} - -func TestCcLibraryWithBazelValidations(t *testing.T) { - t.Parallel() - bp := ` -cc_library { - name: "foo", - srcs: ["foo.cc"], - bazel_module: { label: "//foo/bar:bar" }, - tidy: true, -}` - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: "outputbase", - LabelToCcInfo: map[string]cquery.CcInfo{ - "//foo/bar:bar": cquery.CcInfo{ - CcObjectFiles: []string{"foo.o"}, - Includes: []string{"include"}, - SystemIncludes: []string{"system_include"}, - Headers: []string{"foo.h"}, - RootDynamicLibraries: []string{"foo.so"}, - UnstrippedOutput: "foo_unstripped.so", - }, - "//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{ - CcObjectFiles: []string{"foo.o"}, - Includes: []string{"include"}, - SystemIncludes: []string{"system_include"}, - Headers: []string{"foo.h"}, - RootStaticArchives: []string{"foo.a"}, - TidyFiles: []string{"foo.c.tidy"}, - }, - }, - } - ctx := android.GroupFixturePreparers( - prepareForCcTest, - android.FixtureMergeEnv(map[string]string{ - "ALLOW_LOCAL_TIDY_TRUE": "1", - }), - ).RunTestWithConfig(t, config).TestContext - - staticFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module() - outputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object outputfiles %s", err) - } - - expectedOutputFiles := []string{"out/soong/.intermediates/foo/android_arm_armv7-a-neon_static/validated/foo.a"} - android.AssertPathsRelativeToTopEquals(t, "output files", expectedOutputFiles, outputFiles) - - flagExporter := ctx.ModuleProvider(staticFoo, FlagExporterInfoProvider).(FlagExporterInfo) - android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs) - android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs) - android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders) - android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps) - - sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module() - outputFiles, err = sharedFoo.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_library outputfiles %s", err) - } - expectedOutputFiles = []string{"outputbase/execroot/__main__/foo.so"} - android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings()) - - android.AssertStringEquals(t, "unstripped shared library", "outputbase/execroot/__main__/foo_unstripped.so", sharedFoo.(*Module).linker.unstrippedOutputFilePath().String()) - flagExporter = ctx.ModuleProvider(sharedFoo, FlagExporterInfoProvider).(FlagExporterInfo) - android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs) - android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs) - android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders) - android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps) -} - func TestLibraryVersionScript(t *testing.T) { t.Parallel() result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, ` @@ -413,107 +281,6 @@ func TestLibraryDynamicList(t *testing.T) { } -func TestCcLibrarySharedWithBazelValidations(t *testing.T) { - t.Parallel() - bp := ` -cc_library_shared { - name: "foo", - srcs: ["foo.cc"], - bazel_module: { label: "//foo/bar:bar" }, - tidy: true, -}` - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: "outputbase", - LabelToCcInfo: map[string]cquery.CcInfo{ - "//foo/bar:bar": cquery.CcInfo{ - CcObjectFiles: []string{"foo.o"}, - Includes: []string{"include"}, - SystemIncludes: []string{"system_include"}, - RootDynamicLibraries: []string{"foo.so"}, - TocFile: "foo.so.toc", - TidyFiles: []string{"foo.c.tidy"}, - }, - }, - } - ctx := android.GroupFixturePreparers( - prepareForCcTest, - android.FixtureMergeEnv(map[string]string{ - "ALLOW_LOCAL_TIDY_TRUE": "1", - }), - ).RunTestWithConfig(t, config).TestContext - - sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module() - producer := sharedFoo.(android.OutputFileProducer) - outputFiles, err := producer.OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object outputfiles %s", err) - } - expectedOutputFiles := []string{"out/soong/.intermediates/foo/android_arm_armv7-a-neon_shared/validated/foo.so"} - android.AssertPathsRelativeToTopEquals(t, "output files", expectedOutputFiles, outputFiles) - - tocFilePath := sharedFoo.(*Module).Toc() - if !tocFilePath.Valid() { - t.Errorf("Invalid tocFilePath: %s", tocFilePath) - } - tocFile := tocFilePath.Path() - expectedToc := "outputbase/execroot/__main__/foo.so.toc" - android.AssertStringEquals(t, "toc file", expectedToc, tocFile.String()) - - entries := android.AndroidMkEntriesForTest(t, ctx, sharedFoo)[0] - expectedFlags := []string{"-Ioutputbase/execroot/__main__/include", "-isystem outputbase/execroot/__main__/system_include"} - gotFlags := entries.EntryMap["LOCAL_EXPORT_CFLAGS"] - android.AssertDeepEquals(t, "androidmk exported cflags", expectedFlags, gotFlags) - android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_library_shared", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0]) -} - -func TestCcLibrarySharedWithBazel(t *testing.T) { - t.Parallel() - bp := ` -cc_library_shared { - name: "foo", - srcs: ["foo.cc"], - bazel_module: { label: "//foo/bar:bar" }, -}` - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: "outputbase", - LabelToCcInfo: map[string]cquery.CcInfo{ - "//foo/bar:bar": cquery.CcInfo{ - CcObjectFiles: []string{"foo.o"}, - Includes: []string{"include"}, - SystemIncludes: []string{"system_include"}, - RootDynamicLibraries: []string{"foo.so"}, - TocFile: "foo.so.toc", - }, - }, - } - ctx := testCcWithConfig(t, config) - - sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module() - producer := sharedFoo.(android.OutputFileProducer) - outputFiles, err := producer.OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object outputfiles %s", err) - } - expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.so"} - android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings()) - - tocFilePath := sharedFoo.(*Module).Toc() - if !tocFilePath.Valid() { - t.Errorf("Invalid tocFilePath: %s", tocFilePath) - } - tocFile := tocFilePath.Path() - expectedToc := "outputbase/execroot/__main__/foo.so.toc" - android.AssertStringEquals(t, "toc file", expectedToc, tocFile.String()) - - entries := android.AndroidMkEntriesForTest(t, ctx, sharedFoo)[0] - expectedFlags := []string{"-Ioutputbase/execroot/__main__/include", "-isystem outputbase/execroot/__main__/system_include"} - gotFlags := entries.EntryMap["LOCAL_EXPORT_CFLAGS"] - android.AssertDeepEquals(t, "androidmk exported cflags", expectedFlags, gotFlags) - android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_library_shared", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0]) -} - func TestWholeStaticLibPrebuilts(t *testing.T) { t.Parallel() result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, ` diff --git a/cc/linkable.go b/cc/linkable.go index 9578807f8..1672366a7 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -2,9 +2,7 @@ package cc import ( "android/soong/android" - "android/soong/bazel/cquery" "android/soong/fuzz" - "android/soong/snapshot" "github.com/google/blueprint" ) @@ -64,42 +62,23 @@ type PlatformSanitizeable interface { // implementation should handle tags from both. type SantizableDependencyTagChecker func(tag blueprint.DependencyTag) bool -// Snapshottable defines those functions necessary for handling module snapshots. -type Snapshottable interface { - snapshot.VendorSnapshotModuleInterface - snapshot.RecoverySnapshotModuleInterface - - // SnapshotHeaders returns a list of header paths provided by this module. - SnapshotHeaders() android.Paths - - // SnapshotLibrary returns true if this module is a snapshot library. - IsSnapshotLibrary() bool - - // EffectiveLicenseFiles returns the list of License files for this module. - EffectiveLicenseFiles() android.Paths - - // SnapshotRuntimeLibs returns a list of libraries needed by this module at runtime but which aren't build dependencies. - SnapshotRuntimeLibs() []string - - // SnapshotSharedLibs returns the list of shared library dependencies for this module. - SnapshotSharedLibs() []string - - // SnapshotStaticLibs returns the list of static library dependencies for this module. - SnapshotStaticLibs() []string - - // IsSnapshotPrebuilt returns true if this module is a snapshot prebuilt. - IsSnapshotPrebuilt() bool -} - // LinkableInterface is an interface for a type of module that is linkable in a C++ library. type LinkableInterface interface { android.Module - Snapshottable Module() android.Module CcLibrary() bool CcLibraryInterface() bool + // RustLibraryInterface returns true if this is a Rust library module + RustLibraryInterface() bool + + // CrateName returns the crateName for a Rust library, panics if not a Rust library. + CrateName() string + + // DepFlags returns a slice of Rustc string flags, panics if not a Rust library + ExportedCrateLinkDirs() []string + // BaseModuleName returns the android.ModuleBase.BaseModuleName() value for this module. BaseModuleName() string @@ -115,12 +94,16 @@ type LinkableInterface interface { SelectedStl() string BuildStaticVariant() bool + BuildRlibVariant() bool BuildSharedVariant() bool SetStatic() SetShared() IsPrebuilt() bool Toc() android.OptionalPath + // IsRustFFI returns true if this is a Rust FFI library. + IsRustFFI() bool + // IsFuzzModule returns true if this a *_fuzz module. IsFuzzModule() bool @@ -130,7 +113,7 @@ type LinkableInterface interface { // FuzzSharedLibraries returns the shared library dependencies for this module. // Expects that IsFuzzModule returns true. - FuzzSharedLibraries() android.Paths + FuzzSharedLibraries() android.RuleBuilderInstalls Device() bool Host() bool @@ -157,9 +140,6 @@ type LinkableInterface interface { // IsLlndk returns true for both LLNDK (public) and LLNDK-private libs. IsLlndk() bool - // IsLlndkPublic returns true only for LLNDK (public) libs. - IsLlndkPublic() bool - // HasLlndkStubs returns true if this library has a variant that will build LLNDK stubs. HasLlndkStubs() bool @@ -183,13 +163,6 @@ type LinkableInterface interface { // Bootstrap tests if this module is allowed to use non-APEX version of libraries. Bootstrap() bool - // IsVndkSp returns true if this is a VNDK-SP module. - IsVndkSp() bool - - MustUseVendorVariant() bool - IsVndk() bool - IsVndkExt() bool - IsVndkPrivate() bool IsVendorPublicLibrary() bool IsVndkPrebuiltLibrary() bool HasVendorVariant() bool @@ -198,6 +171,7 @@ type LinkableInterface interface { ProductSpecific() bool InProduct() bool SdkAndPlatformVariantVisibleToMake() bool + InVendorOrProduct() bool // SubName returns the modules SubName, used for image and NDK/SDK variations. SubName() string @@ -236,6 +210,9 @@ type LinkableInterface interface { // Dylib returns true if this is an dylib module. Dylib() bool + // RlibStd returns true if this is an rlib which links against an rlib libstd. + RlibStd() bool + // Static returns true if this is a static library module. Static() bool @@ -342,10 +319,10 @@ type SharedLibraryInfo struct { TableOfContents android.OptionalPath // should be obtained from static analogue - TransitiveStaticLibrariesForOrdering *android.DepSet + TransitiveStaticLibrariesForOrdering *android.DepSet[android.Path] } -var SharedLibraryInfoProvider = blueprint.NewProvider(SharedLibraryInfo{}) +var SharedLibraryInfoProvider = blueprint.NewProvider[SharedLibraryInfo]() // SharedStubLibrary is a struct containing information about a stub shared library. // Stub libraries are used for cross-APEX dependencies; when a library is to depend on a shared @@ -368,7 +345,7 @@ type SharedLibraryStubsInfo struct { IsLLNDK bool } -var SharedLibraryStubsProvider = blueprint.NewProvider(SharedLibraryStubsInfo{}) +var SharedLibraryStubsProvider = blueprint.NewProvider[SharedLibraryStubsInfo]() // StaticLibraryInfo is a provider to propagate information about a static C++ library. type StaticLibraryInfo struct { @@ -384,17 +361,17 @@ type StaticLibraryInfo struct { // This isn't the actual transitive DepSet, shared library dependencies have been // converted into static library analogues. It is only used to order the static // library dependencies that were specified for the current module. - TransitiveStaticLibrariesForOrdering *android.DepSet + TransitiveStaticLibrariesForOrdering *android.DepSet[android.Path] } -var StaticLibraryInfoProvider = blueprint.NewProvider(StaticLibraryInfo{}) +var StaticLibraryInfoProvider = blueprint.NewProvider[StaticLibraryInfo]() // HeaderLibraryInfo is a marker provider that identifies a module as a header library. type HeaderLibraryInfo struct { } // HeaderLibraryInfoProvider is a marker provider that identifies a module as a header library. -var HeaderLibraryInfoProvider = blueprint.NewProvider(HeaderLibraryInfo{}) +var HeaderLibraryInfoProvider = blueprint.NewProvider[HeaderLibraryInfo]() // FlagExporterInfo is a provider to propagate transitive library information // pertaining to exported include paths and flags. @@ -403,23 +380,8 @@ type FlagExporterInfo struct { SystemIncludeDirs android.Paths // System include directories to be included with -isystem Flags []string // Exported raw flags. Deps android.Paths + RustRlibDeps []RustRlibDep GeneratedHeaders android.Paths } -var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{}) - -// flagExporterInfoFromCcInfo populates FlagExporterInfo provider with information from Bazel. -func flagExporterInfoFromCcInfo(ctx android.ModuleContext, ccInfo cquery.CcInfo) FlagExporterInfo { - - includes := android.PathsForBazelOut(ctx, ccInfo.Includes) - systemIncludes := android.PathsForBazelOut(ctx, ccInfo.SystemIncludes) - headers := android.PathsForBazelOut(ctx, ccInfo.Headers) - - return FlagExporterInfo{ - IncludeDirs: android.FirstUniquePaths(includes), - SystemIncludeDirs: android.FirstUniquePaths(systemIncludes), - GeneratedHeaders: headers, - // necessary to ensure generated headers are considered implicit deps of dependent actions - Deps: headers, - } -} +var FlagExporterInfoProvider = blueprint.NewProvider[FlagExporterInfo]() diff --git a/cc/linker.go b/cc/linker.go index 257fe86cf..d2974c204 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -62,6 +62,10 @@ type BaseLinkerProperties struct { // This flag should only be necessary for compiling low-level libraries like libc. Allow_undefined_symbols *bool `android:"arch_variant"` + // ignore max page size. By default, max page size must be the + // max page size set for the target. + Ignore_max_page_size *bool `android:"arch_variant"` + // don't link in libclang_rt.builtins-*.a No_libcrt *bool `android:"arch_variant"` @@ -91,6 +95,10 @@ type BaseLinkerProperties struct { // compiling crt or libc. Nocrt *bool `android:"arch_variant"` + // don't link in crt_pad_segment. This flag is currently only used internal to + // soong for testing and for vndk prebuilt shared libraries. + No_crt_pad_segment *bool `android:"arch_variant"` + // deprecated and ignored because lld makes it unnecessary. See b/189475744. Group_static_libs *bool `android:"arch_variant"` @@ -112,7 +120,7 @@ type BaseLinkerProperties struct { // product variant of the C/C++ module. Static_libs []string - // list of ehader libs that only should be used to build vendor or product + // list of header libs that only should be used to build vendor or product // variant of the C/C++ module. Header_libs []string @@ -161,7 +169,7 @@ type BaseLinkerProperties struct { Exclude_runtime_libs []string } Ramdisk struct { - // list of static libs that only should be used to build the recovery + // list of static libs that only should be used to build the ramdisk // variant of the C/C++ module. Static_libs []string @@ -179,7 +187,7 @@ type BaseLinkerProperties struct { } Vendor_ramdisk struct { // list of shared libs that should not be used to build - // the recovery variant of the C/C++ module. + // the vendor ramdisk variant of the C/C++ module. Exclude_shared_libs []string // list of static libs that should not be used to build @@ -214,6 +222,11 @@ type BaseLinkerProperties struct { // variant of the C/C++ module. Exclude_static_libs []string } + Non_apex struct { + // list of shared libs that should not be used to build the non-apex + // variant of the C/C++ module. + Exclude_shared_libs []string + } } `android:"arch_variant"` // make android::build:GetBuildNumber() available containing the build ID. @@ -248,6 +261,10 @@ func (blp *BaseLinkerProperties) libCrt() bool { return blp.No_libcrt == nil || !*blp.No_libcrt } +func (blp *BaseLinkerProperties) crtPadSegment() bool { + return blp.No_crt_pad_segment == nil || !*blp.No_crt_pad_segment +} + func NewBaseLinker(sanitize *sanitize) *baseLinker { return &baseLinker{sanitize: sanitize} } @@ -274,6 +291,10 @@ func (linker *baseLinker) linkerProps() []interface{} { return []interface{}{&linker.Properties, &linker.dynamicProperties} } +func (linker *baseLinker) baseLinkerProps() BaseLinkerProperties { + return linker.Properties +} + func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { deps.WholeStaticLibs = append(deps.WholeStaticLibs, linker.Properties.Whole_static_libs...) deps.HeaderLibs = append(deps.HeaderLibs, linker.Properties.Header_libs...) @@ -300,6 +321,10 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { // variants. deps.ExcludeLibsForApex = append(deps.ExcludeLibsForApex, linker.Properties.Target.Apex.Exclude_shared_libs...) deps.ExcludeLibsForApex = append(deps.ExcludeLibsForApex, linker.Properties.Target.Apex.Exclude_static_libs...) + // Record the libraries that need to be excluded when building for non-APEX variants + // for the same reason above. This is used for marking deps and marked deps are + // ignored for non-apex variants. + deps.ExcludeLibsForNonApex = append(deps.ExcludeLibsForNonApex, linker.Properties.Target.Non_apex.Exclude_shared_libs...) if Bool(linker.Properties.Use_version_lib) { deps.WholeStaticLibs = append(deps.WholeStaticLibs, "libbuildversion") @@ -313,6 +338,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Vendor.Exclude_static_libs) deps.HeaderLibs = append(deps.HeaderLibs, linker.Properties.Target.Vendor.Header_libs...) deps.HeaderLibs = removeListFromList(deps.HeaderLibs, linker.Properties.Target.Vendor.Exclude_header_libs) + deps.ReexportHeaderLibHeaders = removeListFromList(deps.ReexportHeaderLibHeaders, linker.Properties.Target.Vendor.Exclude_header_libs) deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor.Exclude_static_libs) deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Vendor.Exclude_static_libs) deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Vendor.Exclude_runtime_libs) @@ -325,6 +351,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Target.Product.Static_libs...) deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Product.Exclude_static_libs) deps.HeaderLibs = removeListFromList(deps.HeaderLibs, linker.Properties.Target.Product.Exclude_header_libs) + deps.ReexportHeaderLibHeaders = removeListFromList(deps.ReexportHeaderLibHeaders, linker.Properties.Target.Product.Exclude_header_libs) deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Product.Exclude_static_libs) deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Product.Exclude_static_libs) deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Product.Exclude_runtime_libs) @@ -379,7 +406,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { if ctx.toolchain().Bionic() { // libclang_rt.builtins has to be last on the command line if linker.Properties.libCrt() && !ctx.header() { - deps.UnexportedStaticLibs = append(deps.UnexportedStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain())) + deps.UnexportedStaticLibs = append(deps.UnexportedStaticLibs, config.BuiltinsRuntimeLibrary()) } if inList("libdl", deps.SharedLibs) { @@ -402,7 +429,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { } } else if ctx.toolchain().Musl() { if linker.Properties.libCrt() && !ctx.header() { - deps.UnexportedStaticLibs = append(deps.UnexportedStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain())) + deps.UnexportedStaticLibs = append(deps.UnexportedStaticLibs, config.BuiltinsRuntimeLibrary()) } } @@ -513,13 +540,6 @@ func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { flags.Global.LdFlags = append(flags.Global.LdFlags, RpathFlags(ctx)...) } - if ctx.useSdk() { - // The bionic linker now has support gnu style hashes (which are much faster!), but shipping - // to older devices requires the old style hash. Fortunately, we can build with both and - // it'll work anywhere. - flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--hash-style=both") - } - flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.ToolchainLdflags()) // Version_script is not needed when linking stubs lib where the version @@ -639,6 +659,9 @@ func (linker *baseLinker) linkerSpecifiedDeps(specifiedDeps specifiedDeps) speci return specifiedDeps } +func (linker *baseLinker) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { +} + // Injecting version symbols // Some host modules want a version number, but we don't want to rebuild it every time. Optionally add a step // after linking that injects a constant placeholder with the current version number. diff --git a/cc/llndk_library.go b/cc/llndk_library.go index c30741078..85c3edf8b 100644 --- a/cc/llndk_library.go +++ b/cc/llndk_library.go @@ -14,9 +14,16 @@ package cc +import ( + "fmt" + "strings" + + "android/soong/android" + "android/soong/etc" +) + var ( llndkLibrarySuffix = ".llndk" - llndkHeadersSuffix = ".llndk" ) // Holds properties to describe a stub shared library based on the provided version file. @@ -55,3 +62,165 @@ type llndkLibraryProperties struct { // llndk.symbol_file. Llndk_headers *bool } + +func makeLlndkVars(ctx android.MakeVarsContext) { + // Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if + // they been moved to an apex. + movedToApexLlndkLibraries := make(map[string]bool) + ctx.VisitAllModules(func(module android.Module) { + if library := moduleLibraryInterface(module); library != nil && library.hasLLNDKStubs() { + // Skip bionic libs, they are handled in different manner + name := library.implementationModuleName(module.(*Module).BaseModuleName()) + if module.(android.ApexModule).DirectlyInAnyApex() && !isBionic(name) { + movedToApexLlndkLibraries[name] = true + } + } + }) + + ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", + strings.Join(android.SortedKeys(movedToApexLlndkLibraries), " ")) +} + +func init() { + RegisterLlndkLibraryTxtType(android.InitRegistrationContext) +} + +func RegisterLlndkLibraryTxtType(ctx android.RegistrationContext) { + ctx.RegisterParallelSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory) +} + +type llndkLibrariesTxtModule struct { + android.SingletonModuleBase + + outputFile android.OutputPath + moduleNames []string + fileNames []string +} + +var _ etc.PrebuiltEtcModule = &llndkLibrariesTxtModule{} + +// llndk_libraries_txt is a singleton module whose content is a list of LLNDK libraries +// generated by Soong but can be referenced by other modules. +// For example, apex_vndk can depend on these files as prebuilt. +// Make uses LLNDK_LIBRARIES to determine which libraries to install. +// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN. +// Therefore, by removing the library here, we cause it to only be installed if libc +// depends on it. +func llndkLibrariesTxtFactory() android.SingletonModule { + m := &llndkLibrariesTxtModule{} + android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) + return m +} + +func (txt *llndkLibrariesTxtModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + filename := txt.Name() + + txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath + + installPath := android.PathForModuleInstall(ctx, "etc") + ctx.InstallFile(installPath, filename, txt.outputFile) + + ctx.SetOutputFiles(android.Paths{txt.outputFile}, "") +} + +func getVndkFileName(m *Module) (string, error) { + if library, ok := m.linker.(*libraryDecorator); ok { + return library.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil + } + if prebuilt, ok := m.linker.(*prebuiltLibraryLinker); ok { + return prebuilt.libraryDecorator.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil + } + return "", fmt.Errorf("VNDK library should have libraryDecorator or prebuiltLibraryLinker as linker: %T", m.linker) +} + +func (txt *llndkLibrariesTxtModule) GenerateSingletonBuildActions(ctx android.SingletonContext) { + if txt.outputFile.String() == "" { + // Skip if target file path is empty + return + } + + ctx.VisitAllModules(func(m android.Module) { + if c, ok := m.(*Module); ok && c.VendorProperties.IsLLNDK && !c.Header() && !c.IsVndkPrebuiltLibrary() { + filename, err := getVndkFileName(c) + if err != nil { + ctx.ModuleErrorf(m, "%s", err) + } + + if !strings.HasPrefix(ctx.ModuleName(m), "libclang_rt.hwasan") { + txt.moduleNames = append(txt.moduleNames, ctx.ModuleName(m)) + } + txt.fileNames = append(txt.fileNames, filename) + } + }) + txt.moduleNames = android.SortedUniqueStrings(txt.moduleNames) + txt.fileNames = android.SortedUniqueStrings(txt.fileNames) + + android.WriteFileRule(ctx, txt.outputFile, strings.Join(txt.fileNames, "\n")) +} + +func (txt *llndkLibrariesTxtModule) AndroidMkEntries() []android.AndroidMkEntries { + return []android.AndroidMkEntries{{ + Class: "ETC", + OutputFile: android.OptionalPathForPath(txt.outputFile), + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { + entries.SetString("LOCAL_MODULE_STEM", txt.outputFile.Base()) + }, + }, + }} +} + +func (txt *llndkLibrariesTxtModule) MakeVars(ctx android.MakeVarsContext) { + ctx.Strict("LLNDK_LIBRARIES", strings.Join(txt.moduleNames, " ")) +} + +// PrebuiltEtcModule interface +func (txt *llndkLibrariesTxtModule) BaseDir() string { + return "etc" +} + +// PrebuiltEtcModule interface +func (txt *llndkLibrariesTxtModule) SubDir() string { + return "" +} + +func llndkMutator(mctx android.BottomUpMutatorContext) { + m, ok := mctx.Module().(*Module) + if !ok { + return + } + + if shouldSkipLlndkMutator(mctx, m) { + return + } + + lib, isLib := m.linker.(*libraryDecorator) + prebuiltLib, isPrebuiltLib := m.linker.(*prebuiltLibraryLinker) + + if m.InVendorOrProduct() && isLib && lib.hasLLNDKStubs() { + m.VendorProperties.IsLLNDK = true + } + if m.InVendorOrProduct() && isPrebuiltLib && prebuiltLib.hasLLNDKStubs() { + m.VendorProperties.IsLLNDK = true + } + + if vndkprebuilt, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok { + if !Bool(vndkprebuilt.properties.Vndk.Enabled) { + m.VendorProperties.IsLLNDK = true + } + } +} + +// Check for modules that mustn't be LLNDK +func shouldSkipLlndkMutator(mctx android.BottomUpMutatorContext, m *Module) bool { + if !m.Enabled(mctx) { + return true + } + if !m.Device() { + return true + } + if m.Target().NativeBridge == android.NativeBridgeEnabled { + return true + } + return false +} @@ -15,9 +15,12 @@ package cc import ( - "android/soong/android" + "fmt" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" + + "android/soong/android" ) // LTO (link-time optimization) allows the compiler to optimize and generate @@ -35,32 +38,25 @@ import ( // optimized at link time and may not be compatible with features that require // LTO, such as CFI. // -// This file adds support to soong to automatically propogate LTO options to a +// This file adds support to soong to automatically propagate LTO options to a // new variant of all static dependencies for each module with LTO enabled. type LTOProperties struct { - // Lto must violate capitialization style for acronyms so that it can be + // Lto must violate capitalization style for acronyms so that it can be // referred to in blueprint files as "lto" Lto struct { Never *bool `android:"arch_variant"` - Full *bool `android:"arch_variant"` Thin *bool `android:"arch_variant"` } `android:"arch_variant"` - // Dep properties indicate that this module needs to be built with LTO - // since it is an object dependency of an LTO module. - FullEnabled bool `blueprint:"mutated"` - ThinEnabled bool `blueprint:"mutated"` - NoLtoEnabled bool `blueprint:"mutated"` - FullDep bool `blueprint:"mutated"` - ThinDep bool `blueprint:"mutated"` - NoLtoDep bool `blueprint:"mutated"` - - // Use clang lld instead of gnu ld. - Use_clang_lld *bool + LtoEnabled bool `blueprint:"mutated"` + LtoDefault bool `blueprint:"mutated"` // Use -fwhole-program-vtables cflag. Whole_program_vtables *bool + + // Use --lto-O0 flag. + Lto_O0 *bool } type lto struct { @@ -72,211 +68,184 @@ func (lto *lto) props() []interface{} { } func (lto *lto) begin(ctx BaseModuleContext) { + // First, determine the module independent default LTO mode. + ltoDefault := true if ctx.Config().IsEnvTrue("DISABLE_LTO") { - lto.Properties.NoLtoEnabled = true + ltoDefault = false + } else if lto.Never() { + ltoDefault = false + } else if ctx.Host() { + // Performance and binary size are less important for host binaries. + ltoDefault = false + } else if ctx.Arch().ArchType.Multilib == "lib32" { + // LP32 has many subtle issues and less test coverage. + ltoDefault = false } -} -func (lto *lto) useClangLld(ctx BaseModuleContext) bool { - if lto.Properties.Use_clang_lld != nil { - return Bool(lto.Properties.Use_clang_lld) + // Then, determine the actual LTO mode to use. If different from `ltoDefault`, a variant needs + // to be created. + ltoEnabled := ltoDefault + if lto.Never() { + ltoEnabled = false + } else if lto.ThinLTO() { + // Module explicitly requests for LTO. + ltoEnabled = true + } else if ctx.testBinary() || ctx.testLibrary() { + // Do not enable LTO for tests for better debugging. + ltoEnabled = false } - return true -} -func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { - // TODO(b/131771163): Disable LTO when using explicit fuzzing configurations. - // LTO breaks fuzzer builds. - if inList("-fsanitize=fuzzer-no-link", flags.Local.CFlags) { - return flags - } + lto.Properties.LtoDefault = ltoDefault + lto.Properties.LtoEnabled = ltoEnabled +} - // TODO(b/254713216): LTO doesn't work on riscv64 yet. - if ctx.Arch().ArchType == android.Riscv64 { +func (lto *lto) flags(ctx ModuleContext, flags Flags) Flags { + // TODO(b/131771163): CFI and Fuzzer controls LTO flags by themselves. + // This has be checked late because these properties can be mutated. + if ctx.isCfi() || ctx.isFuzzer() { return flags } + if lto.Properties.LtoEnabled { + ltoCFlags := []string{"-flto=thin", "-fsplit-lto-unit"} + var ltoLdFlags []string - if lto.LTO(ctx) { - var ltoCFlag string - var ltoLdFlag string - if lto.ThinLTO() { - ltoCFlag = "-flto=thin -fsplit-lto-unit" - } else if lto.FullLTO() { - ltoCFlag = "-flto" - } else { - ltoCFlag = "-flto=thin -fsplit-lto-unit" - ltoLdFlag = "-Wl,--lto-O0" + // Do not perform costly LTO optimizations for Eng builds. + if Bool(lto.Properties.Lto_O0) || ctx.optimizeForSize() || ctx.Config().Eng() { + ltoLdFlags = append(ltoLdFlags, "-Wl,--lto-O0") } - flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlag) - flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlag) - flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlag) - flags.Local.LdFlags = append(flags.Local.LdFlags, ltoLdFlag) - if Bool(lto.Properties.Whole_program_vtables) { - flags.Local.CFlags = append(flags.Local.CFlags, "-fwhole-program-vtables") + ltoCFlags = append(ltoCFlags, "-fwhole-program-vtables") } - if (lto.DefaultThinLTO(ctx) || lto.ThinLTO()) && ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && lto.useClangLld(ctx) { + if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") { // Set appropriate ThinLTO cache policy cacheDirFormat := "-Wl,--thinlto-cache-dir=" cacheDir := android.PathForOutput(ctx, "thinlto-cache").String() - flags.Local.LdFlags = append(flags.Local.LdFlags, cacheDirFormat+cacheDir) + ltoLdFlags = append(ltoLdFlags, cacheDirFormat+cacheDir) // Limit the size of the ThinLTO cache to the lesser of 10% of available // disk space and 10GB. cachePolicyFormat := "-Wl,--thinlto-cache-policy=" policy := "cache_size=10%:cache_size_bytes=10g" - flags.Local.LdFlags = append(flags.Local.LdFlags, cachePolicyFormat+policy) + ltoLdFlags = append(ltoLdFlags, cachePolicyFormat+policy) } - // If the module does not have a profile, be conservative and limit cross TU inline - // limit to 5 LLVM IR instructions, to balance binary size increase and performance. - if !ctx.isPgoCompile() && !ctx.isAfdoCompile() { - flags.Local.LdFlags = append(flags.Local.LdFlags, - "-Wl,-plugin-opt,-import-instr-limit=5") + // Reduce the inlining threshold for a better balance of binary size and + // performance. + if !ctx.Darwin() { + if ctx.isAfdoCompile(ctx) { + ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=40") + } else { + ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5") + } } - } - return flags -} -func (lto *lto) LTO(ctx BaseModuleContext) bool { - return lto.ThinLTO() || lto.FullLTO() || lto.DefaultThinLTO(ctx) -} - -func (lto *lto) DefaultThinLTO(ctx BaseModuleContext) bool { - // LP32 has many subtle issues and less test coverage. - lib32 := ctx.Arch().ArchType.Multilib == "lib32" - // CFI enables full LTO. - cfi := ctx.isCfi() - // Performance and binary size are less important for host binaries and tests. - host := ctx.Host() - test := ctx.testBinary() || ctx.testLibrary() - // FIXME: ThinLTO for VNDK produces different output. - // b/169217596 - vndk := ctx.isVndk() - return GlobalThinLTO(ctx) && !lto.Never() && !lib32 && !cfi && !host && !test && !vndk -} + if !ctx.Config().IsEnvFalse("THINLTO_USE_MLGO") { + // Register allocation MLGO flags for ARM64. + if ctx.Arch().ArchType == android.Arm64 && !ctx.optimizeForSize() { + ltoLdFlags = append(ltoLdFlags, "-Wl,-mllvm,-regalloc-enable-advisor=release") + } + // Flags for training MLGO model. + if ctx.Config().IsEnvTrue("THINLTO_EMIT_INDEXES_AND_IMPORTS") { + ltoLdFlags = append(ltoLdFlags, "-Wl,--save-temps=import") + ltoLdFlags = append(ltoLdFlags, "-Wl,--thinlto-emit-index-files") + } + } -func (lto *lto) FullLTO() bool { - return lto != nil && (proptools.Bool(lto.Properties.Lto.Full) || lto.Properties.FullEnabled) + flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...) + flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlags...) + flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlags...) + flags.Local.LdFlags = append(flags.Local.LdFlags, ltoLdFlags...) + } + return flags } func (lto *lto) ThinLTO() bool { - return lto != nil && (proptools.Bool(lto.Properties.Lto.Thin) || lto.Properties.ThinEnabled) + return lto != nil && proptools.Bool(lto.Properties.Lto.Thin) } func (lto *lto) Never() bool { - return lto != nil && (proptools.Bool(lto.Properties.Lto.Never) || lto.Properties.NoLtoEnabled) + return lto != nil && proptools.Bool(lto.Properties.Lto.Never) } -func GlobalThinLTO(ctx android.BaseModuleContext) bool { - return ctx.Config().IsEnvTrue("GLOBAL_THINLTO") +func ltoPropagateViaDepTag(tag blueprint.DependencyTag) bool { + libTag, isLibTag := tag.(libraryDependencyTag) + // Do not recurse down non-static dependencies + if isLibTag { + return libTag.static() + } else { + return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag + } } -// Propagate lto requirements down from binaries -func ltoDepsMutator(mctx android.TopDownMutatorContext) { - globalThinLTO := GlobalThinLTO(mctx) +// ltoTransitionMutator creates LTO variants of cc modules. Variant "" is the default variant, which may +// or may not have LTO enabled depending on the config and the module's type and properties. "lto-thin" or +// "lto-none" variants are created when a module needs to compile in the non-default state for that module. +type ltoTransitionMutator struct{} - if m, ok := mctx.Module().(*Module); ok { - full := m.lto.FullLTO() - thin := m.lto.ThinLTO() - never := m.lto.Never() - if full && thin { - mctx.PropertyErrorf("LTO", "FullLTO and ThinLTO are mutually exclusive") - } +const LTO_NONE_VARIATION = "lto-none" +const LTO_THIN_VARIATION = "lto-thin" - mctx.WalkDeps(func(dep android.Module, parent android.Module) bool { - tag := mctx.OtherModuleDependencyTag(dep) - libTag, isLibTag := tag.(libraryDependencyTag) +func (l *ltoTransitionMutator) Split(ctx android.BaseModuleContext) []string { + return []string{""} +} - // Do not recurse down non-static dependencies - if isLibTag { - if !libTag.static() { - return false - } - } else { - if tag != objDepTag && tag != reuseObjTag { - return false - } - } +func (l *ltoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + if m, ok := ctx.Module().(*Module); ok && m.lto != nil { + if !ltoPropagateViaDepTag(ctx.DepTag()) { + return "" + } - if dep, ok := dep.(*Module); ok { - if full && !dep.lto.FullLTO() { - dep.lto.Properties.FullDep = true - } - if !globalThinLTO && thin && !dep.lto.ThinLTO() { - dep.lto.Properties.ThinDep = true - } - if globalThinLTO && never && !dep.lto.Never() { - dep.lto.Properties.NoLtoDep = true - } - } + if sourceVariation != "" { + return sourceVariation + } - // Recursively walk static dependencies - return true - }) + // Always request an explicit variation, IncomingTransition will rewrite it back to the default variation + // if necessary. + if m.lto.Properties.LtoEnabled { + return LTO_THIN_VARIATION + } else { + return LTO_NONE_VARIATION + } } + return "" } -// Create lto variants for modules that need them -func ltoMutator(mctx android.BottomUpMutatorContext) { - globalThinLTO := GlobalThinLTO(mctx) - - if m, ok := mctx.Module().(*Module); ok && m.lto != nil { - // Create variations for LTO types required as static - // dependencies - variationNames := []string{""} - if m.lto.Properties.FullDep && !m.lto.FullLTO() { - variationNames = append(variationNames, "lto-full") +func (l *ltoTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { + if m, ok := ctx.Module().(*Module); ok && m.lto != nil { + if m.lto.Never() { + return "" } - if !globalThinLTO && m.lto.Properties.ThinDep && !m.lto.ThinLTO() { - variationNames = append(variationNames, "lto-thin") - } - if globalThinLTO && m.lto.Properties.NoLtoDep && !m.lto.Never() { - variationNames = append(variationNames, "lto-none") + // Rewrite explicit variations back to the default variation if the default variation matches. + if incomingVariation == LTO_THIN_VARIATION && m.lto.Properties.LtoDefault { + return "" + } else if incomingVariation == LTO_NONE_VARIATION && !m.lto.Properties.LtoDefault { + return "" } + return incomingVariation + } + return "" +} - // Use correct dependencies if LTO property is explicitly set - // (mutually exclusive) - if m.lto.FullLTO() { - mctx.SetDependencyVariation("lto-full") - } - if !globalThinLTO && m.lto.ThinLTO() { - mctx.SetDependencyVariation("lto-thin") - } - // Never must be the last, it overrides Thin or Full. - if globalThinLTO && m.lto.Never() { - mctx.SetDependencyVariation("lto-none") - } +func (l *ltoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { + // Default module which will be installed. Variation set above according to explicit LTO properties. + if variation == "" { + return + } - if len(variationNames) > 1 { - modules := mctx.CreateVariations(variationNames...) - for i, name := range variationNames { - variation := modules[i].(*Module) - // Default module which will be - // installed. Variation set above according to - // explicit LTO properties - if name == "" { - continue - } - - // LTO properties for dependencies - if name == "lto-full" { - variation.lto.Properties.FullEnabled = true - } - if name == "lto-thin" { - variation.lto.Properties.ThinEnabled = true - } - if name == "lto-none" { - variation.lto.Properties.NoLtoEnabled = true - } - variation.Properties.PreventInstall = true - variation.Properties.HideFromMake = true - variation.lto.Properties.FullDep = false - variation.lto.Properties.ThinDep = false - variation.lto.Properties.NoLtoDep = false - } + if m, ok := ctx.Module().(*Module); ok && m.lto != nil { + // Non-default variation, set the LTO properties to match the variation. + switch variation { + case LTO_THIN_VARIATION: + m.lto.Properties.LtoEnabled = true + case LTO_NONE_VARIATION: + m.lto.Properties.LtoEnabled = false + default: + panic(fmt.Errorf("unknown variation %s", variation)) } + // Non-default variations are never installed. + m.Properties.PreventInstall = true + m.Properties.HideFromMake = true } } diff --git a/cc/lto_test.go b/cc/lto_test.go index 4220f3255..e4b5a3a01 100644 --- a/cc/lto_test.go +++ b/cc/lto_test.go @@ -23,6 +23,20 @@ import ( "github.com/google/blueprint" ) +var LTOPreparer = android.GroupFixturePreparers( + prepareForCcTest, +) + +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 +} + func TestThinLtoDeps(t *testing.T) { t.Parallel() bp := ` @@ -31,9 +45,6 @@ func TestThinLtoDeps(t *testing.T) { srcs: ["src.c"], static_libs: ["foo", "lib_never_lto"], shared_libs: ["bar"], - lto: { - thin: true, - } } cc_library_static { name: "foo", @@ -57,52 +68,40 @@ func TestThinLtoDeps(t *testing.T) { } ` - result := android.GroupFixturePreparers( - prepareForCcTest, - ).RunTestWithBp(t, bp) + result := LTOPreparer.RunTestWithBp(t, bp) libLto := result.ModuleForTests("lto_enabled", "android_arm64_armv8-a_shared").Module() - hasDep := func(m android.Module, wantDep android.Module) bool { - var found bool - result.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found - } - - libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static_lto-thin").Module() - if !hasDep(libLto, libFoo) { - t.Errorf("'lto_enabled' missing dependency on thin lto variant of 'foo'") + 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'") } - libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin").Module() - if !hasDep(libFoo, libBaz) { - t.Errorf("'foo' missing dependency on thin lto variant of transitive dep 'baz'") + 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'") } - libNeverLto := result.ModuleForTests("lib_never_lto", "android_arm64_armv8-a_static_lto-thin").Module() - if !hasDep(libLto, libNeverLto) { - t.Errorf("'lto_enabled' missing dependency on NO-thin lto variant of 'lib_never_lto'") + 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'") } libBar := result.ModuleForTests("bar", "android_arm64_armv8-a_shared").Module() - if !hasDep(libLto, libBar) { - t.Errorf("'lto_enabled' missing dependency on non-thin lto variant of 'bar'") + if !hasDep(result, libLto, libBar) { + t.Errorf("'lto_enabled' missing dependency on the default variant of 'bar'") } barVariants := result.ModuleVariantsForTests("bar") for _, v := range barVariants { - if strings.Contains(v, "lto-thin") { - t.Errorf("Expected variants for 'bar' to not contain 'lto-thin', but found %q", v) + if strings.Contains(v, "lto-none") { + t.Errorf("Expected variants for 'bar' to not contain 'lto-none', but found %q", v) } } quxVariants := result.ModuleVariantsForTests("qux") for _, v := range quxVariants { - if strings.Contains(v, "lto-thin") { - t.Errorf("Expected variants for 'qux' to not contain 'lto-thin', but found %q", v) + if strings.Contains(v, "lto-none") { + t.Errorf("Expected variants for 'qux' to not contain 'lto-none', but found %q", v) } } } @@ -137,30 +136,19 @@ func TestThinLtoOnlyOnStaticDep(t *testing.T) { } ` - result := android.GroupFixturePreparers( - prepareForCcTest, - ).RunTestWithBp(t, bp) + result := LTOPreparer.RunTestWithBp(t, bp) libRoot := result.ModuleForTests("root", "android_arm64_armv8-a_shared").Module() libRootLtoNever := result.ModuleForTests("root_no_lto", "android_arm64_armv8-a_shared").Module() - hasDep := func(m android.Module, wantDep android.Module) bool { - var found bool - result.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found - } - libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static") - if !hasDep(libRoot, libFoo.Module()) { - t.Errorf("'root' missing dependency on thin lto variant of 'foo'") + if !hasDep(result, libRoot, libFoo.Module()) { + t.Errorf("'root' missing dependency on the default variant of 'foo'") } - if !hasDep(libRootLtoNever, libFoo.Module()) { - t.Errorf("'root_no_lto' missing dependency on thin lto variant of 'foo'") + libFooNoLto := result.ModuleForTests("foo", "android_arm64_armv8-a_static_lto-none") + if !hasDep(result, libRootLtoNever, libFooNoLto.Module()) { + t.Errorf("'root_no_lto' missing dependency on the lto_none variant of 'foo'") } libFooCFlags := libFoo.Rule("cc").Args["cFlags"] @@ -168,9 +156,9 @@ func TestThinLtoOnlyOnStaticDep(t *testing.T) { t.Errorf("'foo' expected to have flags %q, but got %q", w, libFooCFlags) } - libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin") - if !hasDep(libFoo.Module(), libBaz.Module()) { - t.Errorf("'foo' missing dependency on thin lto variant of transitive dep 'baz'") + 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'") } libBazCFlags := libFoo.Rule("cc").Args["cFlags"] @@ -197,9 +185,7 @@ func TestLtoDisabledButEnabledForArch(t *testing.T) { }, }, }` - result := android.GroupFixturePreparers( - prepareForCcTest, - ).RunTestWithBp(t, bp) + result := LTOPreparer.RunTestWithBp(t, bp) libFooWithLto := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") libFooWithoutLto := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld") @@ -227,9 +213,7 @@ func TestLtoDoesNotPropagateToRuntimeLibs(t *testing.T) { }, }` - result := android.GroupFixturePreparers( - prepareForCcTest, - ).RunTestWithBp(t, bp) + result := LTOPreparer.RunTestWithBp(t, bp) 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") diff --git a/cc/makevars.go b/cc/makevars.go index 6c3f551d7..cd1396521 100644 --- a/cc/makevars.go +++ b/cc/makevars.go @@ -28,6 +28,16 @@ var ( modulesWarningsAllowedKey = android.NewOnceKey("ModulesWarningsAllowed") modulesUsingWnoErrorKey = android.NewOnceKey("ModulesUsingWnoError") modulesMissingProfileFileKey = android.NewOnceKey("ModulesMissingProfileFile") + sanitizerVariables = map[string]string{ + "ADDRESS_SANITIZER_RUNTIME_LIBRARY": config.AddressSanitizerRuntimeLibrary(), + "HWADDRESS_SANITIZER_RUNTIME_LIBRARY": config.HWAddressSanitizerRuntimeLibrary(), + "HWADDRESS_SANITIZER_STATIC_LIBRARY": config.HWAddressSanitizerStaticLibrary(), + "UBSAN_RUNTIME_LIBRARY": config.UndefinedBehaviorSanitizerRuntimeLibrary(), + "UBSAN_MINIMAL_RUNTIME_LIBRARY": config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(), + "TSAN_RUNTIME_LIBRARY": config.ThreadSanitizerRuntimeLibrary(), + "SCUDO_RUNTIME_LIBRARY": config.ScudoRuntimeLibrary(), + "SCUDO_MINIMAL_RUNTIME_LIBRARY": config.ScudoMinimalRuntimeLibrary(), + } ) func init() { @@ -97,9 +107,6 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("GLOBAL_CLANG_CPPFLAGS_NO_OVERRIDE", "") ctx.Strict("GLOBAL_CLANG_EXTERNAL_CFLAGS_NO_OVERRIDE", "${config.NoOverrideExternalGlobalCflags}") - ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion()) - ctx.Strict("RECOVERY_SNAPSHOT_VERSION", ctx.DeviceConfig().RecoverySnapshotVersion()) - // Filter vendor_public_library that are exported to make exportedVendorPublicLibraries := []string{} ctx.VisitAllModules(func(module android.Module) { @@ -123,8 +130,14 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeStringOfKeys(ctx, modulesUsingWnoErrorKey)) ctx.Strict("SOONG_MODULES_MISSING_PGO_PROFILE_FILE", makeStringOfKeys(ctx, modulesMissingProfileFileKey)) + ctx.Strict("CLANG_COVERAGE_CONFIG_CFLAGS", strings.Join(clangCoverageCFlags, " ")) + ctx.Strict("CLANG_COVERAGE_CONFIG_COMMFLAGS", strings.Join(clangCoverageCommonFlags, " ")) + ctx.Strict("CLANG_COVERAGE_HOST_LDFLAGS", strings.Join(clangCoverageHostLdFlags, " ")) + ctx.Strict("CLANG_COVERAGE_INSTR_PROFILE", profileInstrFlag) + ctx.Strict("CLANG_COVERAGE_CONTINUOUS_FLAGS", strings.Join(clangContinuousCoverageFlags, " ")) + ctx.Strict("CLANG_COVERAGE_HWASAN_FLAGS", strings.Join(clangCoverageHWASanFlags, " ")) + ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " ")) - ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", strings.Join(asanLdflags, " ")) ctx.Strict("HWADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(hwasanCflags, " ")) ctx.Strict("HWADDRESS_SANITIZER_GLOBAL_OPTIONS", strings.Join(hwasanGlobalOptions, ",")) @@ -177,6 +190,8 @@ func makeVarsProvider(ctx android.MakeVarsContext) { if len(deviceTargets) > 1 { makeVarsToolchain(ctx, "2ND_", deviceTargets[1]) } + + makeLlndkVars(ctx) } func makeVarsToolchain(ctx android.MakeVarsContext, secondPrefix string, @@ -255,43 +270,9 @@ func makeVarsToolchain(ctx android.MakeVarsContext, secondPrefix string, }, " ")) if target.Os.Class == android.Device { - sanitizerVariables := map[string]string{ - "ADDRESS_SANITIZER_RUNTIME_LIBRARY": config.AddressSanitizerRuntimeLibrary(toolchain), - "HWADDRESS_SANITIZER_RUNTIME_LIBRARY": config.HWAddressSanitizerRuntimeLibrary(toolchain), - "HWADDRESS_SANITIZER_STATIC_LIBRARY": config.HWAddressSanitizerStaticLibrary(toolchain), - "UBSAN_RUNTIME_LIBRARY": config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain), - "UBSAN_MINIMAL_RUNTIME_LIBRARY": config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(toolchain), - "TSAN_RUNTIME_LIBRARY": config.ThreadSanitizerRuntimeLibrary(toolchain), - "SCUDO_RUNTIME_LIBRARY": config.ScudoRuntimeLibrary(toolchain), - "SCUDO_MINIMAL_RUNTIME_LIBRARY": config.ScudoMinimalRuntimeLibrary(toolchain), - } - for variable, value := range sanitizerVariables { ctx.Strict(secondPrefix+variable, value) } - - sanitizerLibs := android.SortedStringValues(sanitizerVariables) - var sanitizerLibStems []string - ctx.VisitAllModules(func(m android.Module) { - if !m.Enabled() { - return - } - - ccModule, _ := m.(*Module) - if ccModule == nil || ccModule.library == nil || !ccModule.library.shared() { - return - } - - if android.InList(strings.TrimPrefix(ctx.ModuleName(m), "prebuilt_"), sanitizerLibs) && - m.Target().Os == target.Os && m.Target().Arch.ArchType == target.Arch.ArchType { - outputFile := ccModule.outputFile - if outputFile.Valid() { - sanitizerLibStems = append(sanitizerLibStems, outputFile.Path().Base()) - } - } - }) - sanitizerLibStems = android.SortedUniqueStrings(sanitizerLibStems) - ctx.Strict(secondPrefix+"SANITIZER_STEMS", strings.Join(sanitizerLibStems, " ")) } // This is used by external/gentoo/... diff --git a/cc/ndk_abi.go b/cc/ndk_abi.go index 3456c32bb..5beeab1ee 100644 --- a/cc/ndk_abi.go +++ b/cc/ndk_abi.go @@ -19,8 +19,8 @@ import ( ) func init() { - android.RegisterSingletonType("ndk_abi_dump", NdkAbiDumpSingleton) - android.RegisterSingletonType("ndk_abi_diff", NdkAbiDiffSingleton) + android.RegisterParallelSingletonType("ndk_abi_dump", NdkAbiDumpSingleton) + android.RegisterParallelSingletonType("ndk_abi_diff", NdkAbiDiffSingleton) } func getNdkAbiDumpInstallBase(ctx android.PathContext) android.OutputPath { @@ -40,7 +40,7 @@ type ndkAbiDumpSingleton struct{} func (n *ndkAbiDumpSingleton) GenerateBuildActions(ctx android.SingletonContext) { var depPaths android.Paths ctx.VisitAllModules(func(module android.Module) { - if !module.Enabled() { + if !module.Enabled(ctx) { return } @@ -78,7 +78,7 @@ type ndkAbiDiffSingleton struct{} func (n *ndkAbiDiffSingleton) GenerateBuildActions(ctx android.SingletonContext) { var depPaths android.Paths ctx.VisitAllModules(func(module android.Module) { - if m, ok := module.(android.Module); ok && !m.Enabled() { + if m, ok := module.(android.Module); ok && !m.Enabled(ctx) { return } diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go index 7354be9f7..57a3b3a9c 100644 --- a/cc/ndk_headers.go +++ b/cc/ndk_headers.go @@ -15,14 +15,10 @@ package cc import ( - "fmt" "path/filepath" - "github.com/google/blueprint" - "github.com/google/blueprint/proptools" - "android/soong/android" - "android/soong/bazel" + "github.com/google/blueprint" ) var ( @@ -48,7 +44,7 @@ func init() { } // Returns the NDK base include path for use with sdk_version current. Usable with -I. -func getCurrentIncludePath(ctx android.ModuleContext) android.InstallPath { +func getCurrentIncludePath(ctx android.ModuleContext) android.OutputPath { return getNdkSysrootBase(ctx).Join(ctx, "usr/include") } @@ -81,16 +77,16 @@ type headerProperties struct { type headerModule struct { android.ModuleBase - android.BazelModuleBase properties headerProperties + srcPaths android.Paths installPaths android.Paths licensePath android.Path } func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string, - to string) android.InstallPath { + to string) android.OutputPath { // Output path is the sysroot base + "usr/include" + to directory + directory component // of the file without the leading from directory stripped. // @@ -128,17 +124,16 @@ func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License)) - srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs) - for _, header := range srcFiles { + m.srcPaths = android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs) + for _, header := range m.srcPaths { installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To)) - installedPath := ctx.InstallFile(installDir, header.Base(), header) installPath := installDir.Join(ctx, header.Base()) - if installPath != installedPath { - panic(fmt.Sprintf( - "expected header install path (%q) not equal to actual install path %q", - installPath, installedPath)) - } + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: header, + Output: installPath, + }) m.installPaths = append(m.installPaths, installPath) } @@ -147,39 +142,6 @@ func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } -// TODO(b/243196151): Populate `system` and `arch` metadata -type bazelCcApiHeadersAttributes struct { - Hdrs bazel.LabelListAttribute - Include_dir *string -} - -func createCcApiHeadersTarget(ctx android.TopDownMutatorContext, includes []string, excludes []string, include_dir *string) { - props := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_api_headers", - Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl", - } - attrs := &bazelCcApiHeadersAttributes{ - Hdrs: bazel.MakeLabelListAttribute( - android.BazelLabelForModuleSrcExcludes( - ctx, - includes, - excludes, - ), - ), - Include_dir: include_dir, - } - ctx.CreateBazelTargetModule(props, android.CommonAttributes{ - Name: android.ApiContributionTargetName(ctx.ModuleName()), - }, attrs) -} - -var _ android.ApiProvider = (*headerModule)(nil) - -func (h *headerModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) { - // Generate `cc_api_headers` target for Multi-tree API export - createCcApiHeadersTarget(ctx, h.properties.Srcs, h.properties.Exclude_srcs, h.properties.From) -} - // ndk_headers installs the sets of ndk headers defined in the srcs property // to the sysroot base + "usr/include" + to directory + directory component. // ndk_headers requires the license file to be specified. Example: @@ -190,7 +152,7 @@ func (h *headerModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) // to = "bar" // header = "include/foo/woodly/doodly.h" // output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h" -func ndkHeadersFactory() android.Module { +func NdkHeadersFactory() android.Module { module := &headerModule{} module.AddProperties(&module.properties) android.InitAndroidModule(module) @@ -218,7 +180,7 @@ type versionedHeaderProperties struct { } // Like ndk_headers, but preprocesses the headers with the bionic versioner: -// https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md. +// https://android.googlesource.com/platform/bionic/+/main/tools/versioner/README.md. // // Unlike ndk_headers, we don't operate on a list of sources but rather a whole directory, the // module does not have the srcs property, and operates on a full directory (the `from` property). @@ -226,10 +188,10 @@ type versionedHeaderProperties struct { // Note that this is really only built to handle bionic/libc/include. type versionedHeaderModule struct { android.ModuleBase - android.BazelModuleBase properties versionedHeaderProperties + srcPaths android.Paths installPaths android.Paths licensePath android.Path } @@ -248,9 +210,9 @@ func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleCo fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From)) toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To)) - srcFiles := ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil) + m.srcPaths = ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil) var installPaths []android.WritablePath - for _, header := range srcFiles { + for _, header := range m.srcPaths { installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To)) installPath := installDir.Join(ctx, header.Base()) installPaths = append(installPaths, installPath) @@ -261,20 +223,11 @@ func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleCo ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From)) } - processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, srcFiles, installPaths) -} - -var _ android.ApiProvider = (*versionedHeaderModule)(nil) - -func (h *versionedHeaderModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) { - // Glob all .h files under `From` - includePattern := headerGlobPattern(proptools.String(h.properties.From)) - // Generate `cc_api_headers` target for Multi-tree API export - createCcApiHeadersTarget(ctx, []string{includePattern}, []string{}, h.properties.From) + processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, m.srcPaths, installPaths) } func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path, - srcFiles android.Paths, installPaths []android.WritablePath) android.Path { + srcPaths android.Paths, installPaths []android.WritablePath) android.Path { // The versioner depends on a dependencies directory to simplify determining include paths // when parsing headers. This directory contains architecture specific directories as well // as a common directory, each of which contains symlinks to the actually directories to @@ -299,7 +252,7 @@ func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir andro Rule: versionBionicHeaders, Description: "versioner preprocess " + srcDir.Rel(), Output: timestampFile, - Implicits: append(srcFiles, depsGlob...), + Implicits: append(srcPaths, depsGlob...), ImplicitOutputs: installPaths, Args: map[string]string{ "depsPath": depsPath.String(), @@ -312,11 +265,11 @@ func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir andro } // versioned_ndk_headers preprocesses the headers with the bionic versioner: -// https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md. +// https://android.googlesource.com/platform/bionic/+/main/tools/versioner/README.md. // Unlike the ndk_headers soong module, versioned_ndk_headers operates on a // directory level specified in `from` property. This is only used to process // the bionic/libc/include directory. -func versionedNdkHeadersFactory() android.Module { +func VersionedNdkHeadersFactory() android.Module { module := &versionedHeaderModule{} module.AddProperties(&module.properties) @@ -363,6 +316,7 @@ type preprocessedHeadersModule struct { properties preprocessedHeadersProperties + srcPaths android.Paths installPaths android.Paths licensePath android.Path } @@ -375,9 +329,9 @@ func (m *preprocessedHeadersModule) GenerateAndroidBuildActions(ctx android.Modu preprocessor := android.PathForModuleSrc(ctx, String(m.properties.Preprocessor)) m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License)) - srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs) + m.srcPaths = android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs) installDir := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To)) - for _, src := range srcFiles { + for _, src := range m.srcPaths { installPath := installDir.Join(ctx, src.Base()) m.installPaths = append(m.installPaths, installPath) diff --git a/cc/ndk_library.go b/cc/ndk_library.go index f8a355950..f32606814 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -25,15 +25,13 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" - "android/soong/bazel" "android/soong/cc/config" ) func init() { pctx.HostBinToolVariable("ndkStubGenerator", "ndkstubgen") - pctx.HostBinToolVariable("abidiff", "abidiff") - pctx.HostBinToolVariable("abitidy", "abitidy") - pctx.HostBinToolVariable("abidw", "abidw") + pctx.HostBinToolVariable("stg", "stg") + pctx.HostBinToolVariable("stgdiff", "stgdiff") } var ( @@ -44,28 +42,26 @@ var ( CommandDeps: []string{"$ndkStubGenerator"}, }, "arch", "apiLevel", "apiMap", "flags") - abidw = pctx.AndroidStaticRule("abidw", + // $headersList should include paths to public headers. All types + // that are defined outside of public headers will be excluded from + // ABI monitoring. + // + // STG tool doesn't access content of files listed in $headersList, + // so there is no need to add them to dependencies. + stg = pctx.AndroidStaticRule("stg", blueprint.RuleParams{ - Command: "$abidw --type-id-style hash --no-corpus-path " + - "--no-show-locs --no-comp-dir-path -w $symbolList " + - "$in --out-file $out", - CommandDeps: []string{"$abidw"}, - }, "symbolList") + Command: "$stg -S :$symbolList --file-filter :$headersList --elf $in -o $out", + CommandDeps: []string{"$stg"}, + }, "symbolList", "headersList") - abitidy = pctx.AndroidStaticRule("abitidy", - blueprint.RuleParams{ - Command: "$abitidy --all $flags -i $in -o $out", - CommandDeps: []string{"$abitidy"}, - }, "flags") - - abidiff = pctx.AndroidStaticRule("abidiff", + stgdiff = pctx.AndroidStaticRule("stgdiff", blueprint.RuleParams{ // Need to create *some* output for ninja. We don't want to use tee // because we don't want to spam the build output with "nothing // changed" messages, so redirect output message to $out, and if // changes were detected print the output and fail. - Command: "$abidiff $args $in > $out || (cat $out && false)", - CommandDeps: []string{"$abidiff"}, + Command: "$stgdiff $args --stg $in -o $out || (cat $out && echo 'Run $$ANDROID_BUILD_TOP/development/tools/ndk/update_ndk_abi.sh to update the ABI dumps.' && false)", + CommandDeps: []string{"$stgdiff"}, }, "args") ndkLibrarySuffix = ".ndk" @@ -107,12 +103,6 @@ type libraryProperties struct { // https://github.com/android-ndk/ndk/issues/265. Unversioned_until *string - // If true, does not emit errors when APIs lacking type information are - // found. This is false by default and should not be enabled outside bionic, - // where it is enabled pending a fix for http://b/190554910 (no debug info - // for asm implemented symbols). - Allow_untyped_symbols *bool - // Headers presented by this library to the Public API Surface Export_header_libs []string } @@ -158,7 +148,7 @@ func ndkLibraryVersions(ctx android.BaseMutatorContext, from android.ApiLevel) [ } func (this *stubDecorator) stubsVersions(ctx android.BaseMutatorContext) []string { - if !ctx.Module().Enabled() { + if !ctx.Module().Enabled(ctx) { return nil } if ctx.Target().NativeBridge == android.NativeBridgeEnabled { @@ -235,7 +225,7 @@ var stubLibraryCompilerFlags = []string{ } func init() { - config.ExportStringList("StubLibraryCompilerFlags", stubLibraryCompilerFlags) + pctx.StaticVariable("StubLibraryCompilerFlags", strings.Join(stubLibraryCompilerFlags, " ")) } func addStubLibraryCompilerFlags(flags Flags) Flags { @@ -326,7 +316,7 @@ func (this *stubDecorator) findPrebuiltAbiDump(ctx ModuleContext, apiLevel android.ApiLevel) android.OptionalPath { subpath := filepath.Join("prebuilts/abi-dumps/ndk", apiLevel.String(), - ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.xml") + ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.stg") return android.ExistentPathForSource(ctx, subpath) } @@ -335,58 +325,33 @@ func canDumpAbi(config android.Config) bool { if runtime.GOOS == "darwin" { return false } - // abidw doesn't currently handle top-byte-ignore correctly. Disable ABI - // dumping for those configs while we wait for a fix. We'll still have ABI - // checking coverage from non-hwasan builds. - // http://b/190554910 - if android.InList("hwaddress", config.SanitizeDevice()) { - return false - } // http://b/156513478 - // http://b/277624006 - // This step is expensive. We're not able to do anything with the outputs of - // this step yet (canDiffAbi is flagged off because libabigail isn't able to - // handle all our libraries), disable it. There's no sense in protecting - // against checking in code that breaks abidw since by the time any of this - // can be turned on we'll need to migrate to STG anyway. - return false + return config.ReleaseNdkAbiMonitored() } // Feature flag to disable diffing against prebuilts. -func canDiffAbi() bool { - return false +func canDiffAbi(config android.Config) bool { + return config.ReleaseNdkAbiMonitored() } func (this *stubDecorator) dumpAbi(ctx ModuleContext, symbolList android.Path) { implementationLibrary := this.findImplementationLibrary(ctx) - abiRawPath := getNdkAbiDumpInstallBase(ctx).Join(ctx, + this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx, this.apiLevel.String(), ctx.Arch().ArchType.String(), - this.libraryName(ctx), "abi.raw.xml") + this.libraryName(ctx), "abi.stg") + headersList := getNdkABIHeadersFile(ctx) ctx.Build(pctx, android.BuildParams{ - Rule: abidw, - Description: fmt.Sprintf("abidw %s", implementationLibrary), + Rule: stg, + Description: fmt.Sprintf("stg %s", implementationLibrary), Input: implementationLibrary, - Output: abiRawPath, - Implicit: symbolList, - Args: map[string]string{ - "symbolList": symbolList.String(), + Implicits: []android.Path{ + symbolList, + headersList, }, - }) - - this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx, - this.apiLevel.String(), ctx.Arch().ArchType.String(), - this.libraryName(ctx), "abi.xml") - untypedFlag := "--abort-on-untyped-symbols" - if proptools.BoolDefault(this.properties.Allow_untyped_symbols, false) { - untypedFlag = "" - } - ctx.Build(pctx, android.BuildParams{ - Rule: abitidy, - Description: fmt.Sprintf("abitidy %s", implementationLibrary), - Input: abiRawPath, - Output: this.abiDumpPath, + Output: this.abiDumpPath, Args: map[string]string{ - "flags": untypedFlag, + "symbolList": symbolList.String(), + "headersList": headersList.String(), }, }) } @@ -405,11 +370,13 @@ func findNextApiLevel(ctx ModuleContext, apiLevel android.ApiLevel) *android.Api func (this *stubDecorator) diffAbi(ctx ModuleContext) { // Catch any ABI changes compared to the checked-in definition of this API // level. - abiDiffPath := android.PathForModuleOut(ctx, "abidiff.timestamp") + abiDiffPath := android.PathForModuleOut(ctx, "stgdiff.timestamp") prebuiltAbiDump := this.findPrebuiltAbiDump(ctx, this.apiLevel) + missingPrebuiltErrorTemplate := + "Did not find prebuilt ABI dump for %q (%q). Generate with " + + "//development/tools/ndk/update_ndk_abi.sh." missingPrebuiltError := fmt.Sprintf( - "Did not find prebuilt ABI dump for %q (%q). Generate with "+ - "//development/tools/ndk/update_ndk_abi.sh.", this.libraryName(ctx), + missingPrebuiltErrorTemplate, this.libraryName(ctx), prebuiltAbiDump.InvalidReason()) if !prebuiltAbiDump.Valid() { ctx.Build(pctx, android.BuildParams{ @@ -421,11 +388,14 @@ func (this *stubDecorator) diffAbi(ctx ModuleContext) { }) } else { ctx.Build(pctx, android.BuildParams{ - Rule: abidiff, - Description: fmt.Sprintf("abidiff %s %s", prebuiltAbiDump, + Rule: stgdiff, + Description: fmt.Sprintf("Comparing ABI %s %s", prebuiltAbiDump, this.abiDumpPath), Output: abiDiffPath, Inputs: android.Paths{prebuiltAbiDump.Path(), this.abiDumpPath}, + Args: map[string]string{ + "args": "--format=small", + }, }) } this.abiDiffPaths = append(this.abiDiffPaths, abiDiffPath) @@ -433,7 +403,7 @@ func (this *stubDecorator) diffAbi(ctx ModuleContext) { // Also ensure that the ABI of the next API level (if there is one) matches // this API level. *New* ABI is allowed, but any changes to APIs that exist // in this API level are disallowed. - if !this.apiLevel.IsCurrent() { + if !this.apiLevel.IsCurrent() && prebuiltAbiDump.Valid() { nextApiLevel := findNextApiLevel(ctx, this.apiLevel) if nextApiLevel == nil { panic(fmt.Errorf("could not determine which API level follows "+ @@ -442,23 +412,28 @@ func (this *stubDecorator) diffAbi(ctx ModuleContext) { nextAbiDiffPath := android.PathForModuleOut(ctx, "abidiff_next.timestamp") nextAbiDump := this.findPrebuiltAbiDump(ctx, *nextApiLevel) + missingNextPrebuiltError := fmt.Sprintf( + missingPrebuiltErrorTemplate, this.libraryName(ctx), + nextAbiDump.InvalidReason()) if !nextAbiDump.Valid() { ctx.Build(pctx, android.BuildParams{ Rule: android.ErrorRule, Output: nextAbiDiffPath, Args: map[string]string{ - "error": missingPrebuiltError, + "error": missingNextPrebuiltError, }, }) } else { ctx.Build(pctx, android.BuildParams{ - Rule: abidiff, - Description: fmt.Sprintf("abidiff %s %s", this.abiDumpPath, - nextAbiDump), + Rule: stgdiff, + Description: fmt.Sprintf( + "Comparing ABI to the next API level %s %s", + prebuiltAbiDump, nextAbiDump), Output: nextAbiDiffPath, - Inputs: android.Paths{this.abiDumpPath, nextAbiDump.Path()}, + Inputs: android.Paths{ + prebuiltAbiDump.Path(), nextAbiDump.Path()}, Args: map[string]string{ - "args": "--no-added-syms", + "args": "--format=small --ignore=interface_addition", }, }) } @@ -487,7 +462,7 @@ func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) O c.versionScriptPath = nativeAbiResult.versionScript if canDumpAbi(ctx.Config()) { c.dumpAbi(ctx, nativeAbiResult.symbolList) - if canDiffAbi() { + if canDiffAbi(ctx.Config()) { c.diffAbi(ctx) } } @@ -504,6 +479,12 @@ func (linker *stubDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { } } +func (linker *stubDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + linker.libraryDecorator.moduleInfoJSON(ctx, moduleInfoJSON) + // Overwrites the SubName computed by libraryDecorator + moduleInfoJSON.SubName = ndkLibrarySuffix + "." + linker.apiLevel.String() +} + func (linker *stubDecorator) Name(name string) string { return name + ndkLibrarySuffix } @@ -537,19 +518,25 @@ func (stub *stubDecorator) nativeCoverage() bool { // Returns the install path for unversioned NDK libraries (currently only static // libraries). -func getUnversionedLibraryInstallPath(ctx ModuleContext) android.InstallPath { +func getUnversionedLibraryInstallPath(ctx ModuleContext) android.OutputPath { return getNdkSysrootBase(ctx).Join(ctx, "usr/lib", config.NDKTriple(ctx.toolchain())) } // Returns the install path for versioned NDK libraries. These are most often // stubs, but the same paths are used for CRT objects. -func getVersionedLibraryInstallPath(ctx ModuleContext, apiLevel android.ApiLevel) android.InstallPath { +func getVersionedLibraryInstallPath(ctx ModuleContext, apiLevel android.ApiLevel) android.OutputPath { return getUnversionedLibraryInstallPath(ctx).Join(ctx, apiLevel.String()) } func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) { installDir := getVersionedLibraryInstallPath(ctx, stub.apiLevel) - stub.installPath = ctx.InstallFile(installDir, path.Base(), path) + out := installDir.Join(ctx, path.Base()) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: path, + Output: out, + }) + stub.installPath = out } func newStubLibrary() *Module { @@ -580,43 +567,5 @@ func newStubLibrary() *Module { func NdkLibraryFactory() android.Module { module := newStubLibrary() android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth) - android.InitBazelModule(module) return module } - -type bazelCcApiContributionAttributes struct { - Api bazel.LabelAttribute - Api_surfaces bazel.StringListAttribute - Hdrs bazel.LabelListAttribute - Library_name string -} - -// Names of the cc_api_header targets in the bp2build workspace -func apiHeaderLabels(ctx android.TopDownMutatorContext, hdrLibs []string) bazel.LabelList { - addSuffix := func(ctx android.BazelConversionPathContext, module blueprint.Module) string { - label := android.BazelModuleLabel(ctx, module) - return android.ApiContributionTargetName(label) - } - return android.BazelLabelForModuleDepsWithFn(ctx, hdrLibs, addSuffix) -} - -func ndkLibraryBp2build(ctx android.TopDownMutatorContext, m *Module) { - props := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_api_contribution", - Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl", - } - stubLibrary := m.compiler.(*stubDecorator) - attrs := &bazelCcApiContributionAttributes{ - Library_name: stubLibrary.implementationModuleName(m.Name()), - Api_surfaces: bazel.MakeStringListAttribute( - []string{android.PublicApi.String()}), - } - if symbolFile := stubLibrary.properties.Symbol_file; symbolFile != nil { - apiLabel := android.BazelLabelForModuleSrcSingle(ctx, proptools.String(symbolFile)).Label - attrs.Api = *bazel.MakeLabelAttribute(apiLabel) - } - apiHeaders := apiHeaderLabels(ctx, stubLibrary.properties.Export_header_libs) - attrs.Hdrs = bazel.MakeLabelListAttribute(apiHeaders) - apiContributionTargetName := android.ApiContributionTargetName(ctx.ModuleName()) - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: apiContributionTargetName}, attrs) -} diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go index 1d15cf83f..f503982cd 100644 --- a/cc/ndk_prebuilt.go +++ b/cc/ndk_prebuilt.go @@ -87,9 +87,12 @@ func NdkPrebuiltStaticStlFactory() android.Module { return module.Init() } +const ( + libDir = "current/sources/cxx-stl/llvm-libc++/libs" +) + func getNdkStlLibDir(ctx android.ModuleContext) android.SourcePath { - libDir := "prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs" - return android.PathForSource(ctx, libDir).Join(ctx, ctx.Arch().Abi[0]) + return android.PathForSource(ctx, ctx.ModuleDir(), libDir).Join(ctx, ctx.Arch().Abi[0]) } func (ndk *ndkPrebuiltStlLinker) link(ctx ModuleContext, flags Flags, @@ -113,14 +116,14 @@ func (ndk *ndkPrebuiltStlLinker) link(ctx ModuleContext, flags Flags, ndk.libraryDecorator.flagExporter.setProvider(ctx) if ndk.static() { - depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(lib).Build() - ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{ + depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(lib).Build() + android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{ StaticLibrary: lib, TransitiveStaticLibrariesForOrdering: depSet, }) } else { - ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{ + android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{ SharedLibrary: lib, Target: ctx.Target(), }) diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go index dffc6c614..3c48f6881 100644 --- a/cc/ndk_sysroot.go +++ b/cc/ndk_sysroot.go @@ -54,27 +54,27 @@ package cc import ( "android/soong/android" + "strings" ) func init() { RegisterNdkModuleTypes(android.InitRegistrationContext) - pctx.Import("android/soong/android") } func RegisterNdkModuleTypes(ctx android.RegistrationContext) { - ctx.RegisterModuleType("ndk_headers", ndkHeadersFactory) + ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory) ctx.RegisterModuleType("ndk_library", NdkLibraryFactory) - ctx.RegisterModuleType("versioned_ndk_headers", versionedNdkHeadersFactory) + ctx.RegisterModuleType("versioned_ndk_headers", VersionedNdkHeadersFactory) ctx.RegisterModuleType("preprocessed_ndk_headers", preprocessedNdkHeadersFactory) - ctx.RegisterSingletonType("ndk", NdkSingleton) + ctx.RegisterParallelSingletonType("ndk", NdkSingleton) } -func getNdkInstallBase(ctx android.PathContext) android.InstallPath { +func getNdkInstallBase(ctx android.PathContext) android.OutputPath { return android.PathForNdkInstall(ctx) } // Returns the main install directory for the NDK sysroot. Usable with --sysroot. -func getNdkSysrootBase(ctx android.PathContext) android.InstallPath { +func getNdkSysrootBase(ctx android.PathContext) android.OutputPath { return getNdkInstallBase(ctx).Join(ctx, "sysroot") } @@ -97,36 +97,80 @@ func getNdkFullTimestampFile(ctx android.PathContext) android.WritablePath { return android.PathForOutput(ctx, "ndk.timestamp") } +// The list of all NDK headers as they are located in the repo. +// Used for ABI monitoring to track only structures defined in NDK headers. +func getNdkABIHeadersFile(ctx android.PathContext) android.WritablePath { + return android.PathForOutput(ctx, "ndk_abi_headers.txt") +} + func NdkSingleton() android.Singleton { return &ndkSingleton{} } +// Collect all NDK exported headers paths into a file that is used to +// detect public types that should be ABI monitored. +// +// Assume that we have the following code in exported header: +// +// typedef struct Context Context; +// typedef struct Output { +// ... +// } Output; +// void DoSomething(Context* ctx, Output* output); +// +// If none of public headers exported to end-users contain definition of +// "struct Context", then "struct Context" layout and members shouldn't be +// monitored. However we use DWARF information from a real library, which +// may have access to the definition of "string Context" from +// implementation headers, and it will leak to ABI. +// +// STG tool doesn't access source and header files, only DWARF information +// from compiled library. And the DWARF contains file name where a type is +// defined. So we need a rule to build a list of paths to public headers, +// so STG can distinguish private types from public and do not monitor +// private types that are not accessible to library users. +func writeNdkAbiSrcFilter(ctx android.BuilderContext, + headerSrcPaths android.Paths, outputFile android.WritablePath) { + var filterBuilder strings.Builder + filterBuilder.WriteString("[decl_file_allowlist]\n") + for _, headerSrcPath := range headerSrcPaths { + filterBuilder.WriteString(headerSrcPath.String()) + filterBuilder.WriteString("\n") + } + + android.WriteFileRule(ctx, outputFile, filterBuilder.String()) +} + type ndkSingleton struct{} func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) { var staticLibInstallPaths android.Paths - var headerPaths android.Paths + var headerSrcPaths android.Paths + var headerInstallPaths android.Paths var installPaths android.Paths var licensePaths android.Paths ctx.VisitAllModules(func(module android.Module) { - if m, ok := module.(android.Module); ok && !m.Enabled() { + if m, ok := module.(android.Module); ok && !m.Enabled(ctx) { return } if m, ok := module.(*headerModule); ok { - headerPaths = append(headerPaths, m.installPaths...) + headerSrcPaths = append(headerSrcPaths, m.srcPaths...) + headerInstallPaths = append(headerInstallPaths, m.installPaths...) installPaths = append(installPaths, m.installPaths...) licensePaths = append(licensePaths, m.licensePath) } if m, ok := module.(*versionedHeaderModule); ok { - headerPaths = append(headerPaths, m.installPaths...) + headerSrcPaths = append(headerSrcPaths, m.srcPaths...) + headerInstallPaths = append(headerInstallPaths, m.installPaths...) installPaths = append(installPaths, m.installPaths...) licensePaths = append(licensePaths, m.licensePath) } if m, ok := module.(*preprocessedHeadersModule); ok { - headerPaths = append(headerPaths, m.installPaths...) + headerSrcPaths = append(headerSrcPaths, m.srcPaths...) + headerInstallPaths = append(headerInstallPaths, m.installPaths...) installPaths = append(installPaths, m.installPaths...) licensePaths = append(licensePaths, m.licensePath) } @@ -176,9 +220,11 @@ func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) { ctx.Build(pctx, android.BuildParams{ Rule: android.Touch, Output: getNdkHeadersTimestampFile(ctx), - Implicits: headerPaths, + Implicits: headerInstallPaths, }) + writeNdkAbiSrcFilter(ctx, headerSrcPaths, getNdkABIHeadersFile(ctx)) + fullDepPaths := append(staticLibInstallPaths, getNdkBaseTimestampFile(ctx)) // There's a phony "ndk" rule defined in core/main.mk that depends on this. diff --git a/cc/ndkstubgen/test_ndkstubgen.py b/cc/ndkstubgen/test_ndkstubgen.py index 1e0bdf3ff..22f31d9f1 100755 --- a/cc/ndkstubgen/test_ndkstubgen.py +++ b/cc/ndkstubgen/test_ndkstubgen.py @@ -463,6 +463,98 @@ class IntegrationTest(unittest.TestCase): """) self.assertEqual(expected_version, version_file.getvalue()) + def test_integration_with_llndk(self) -> None: + input_file = io.StringIO(textwrap.dedent("""\ + VERSION_34 { # introduced=34 + global: + foo; + bar; # llndk + }; + VERSION_35 { # introduced=35 + global: + wiggle; + waggle; + waggle; # llndk=202404 + bubble; # llndk=202404 + duddle; + duddle; # llndk=202504 + } VERSION_34; + """)) + f = copy(self.filter) + f.llndk = True + f.api = 202404 + parser = symbolfile.SymbolFileParser(input_file, {}, f) + versions = parser.parse() + + src_file = io.StringIO() + version_file = io.StringIO() + symbol_list_file = io.StringIO() + + generator = ndkstubgen.Generator(src_file, + version_file, symbol_list_file, f) + generator.write(versions) + + expected_src = textwrap.dedent("""\ + void foo() {} + void bar() {} + void waggle() {} + void bubble() {} + """) + self.assertEqual(expected_src, src_file.getvalue()) + + expected_version = textwrap.dedent("""\ + VERSION_34 { + global: + foo; + bar; + }; + VERSION_35 { + global: + waggle; + bubble; + } VERSION_34; + """) + self.assertEqual(expected_version, version_file.getvalue()) + + def test_integration_with_llndk_with_single_version_block(self) -> None: + input_file = io.StringIO(textwrap.dedent("""\ + LIBANDROID { + global: + foo; # introduced=34 + bar; # introduced=35 + bar; # llndk=202404 + baz; # introduced=35 + }; + """)) + f = copy(self.filter) + f.llndk = True + f.api = 202404 + parser = symbolfile.SymbolFileParser(input_file, {}, f) + versions = parser.parse() + + src_file = io.StringIO() + version_file = io.StringIO() + symbol_list_file = io.StringIO() + + generator = ndkstubgen.Generator(src_file, + version_file, symbol_list_file, f) + generator.write(versions) + + expected_src = textwrap.dedent("""\ + void foo() {} + void bar() {} + """) + self.assertEqual(expected_src, src_file.getvalue()) + + expected_version = textwrap.dedent("""\ + LIBANDROID { + global: + foo; + bar; + }; + """) + self.assertEqual(expected_version, version_file.getvalue()) + def test_empty_stub(self) -> None: """Tests that empty stubs can be generated. diff --git a/cc/object.go b/cc/object.go index d65cdea74..8b23295c7 100644 --- a/cc/object.go +++ b/cc/object.go @@ -19,8 +19,6 @@ import ( "strings" "android/soong/android" - "android/soong/bazel" - "android/soong/bazel/cquery" ) // @@ -50,33 +48,6 @@ type objectLinker struct { ndkSysrootPath android.Path } -type objectBazelHandler struct { - module *Module -} - -var _ BazelHandler = (*objectBazelHandler)(nil) - -func (handler *objectBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) { - bazelCtx := ctx.Config().BazelContext - bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx))) -} - -func (handler *objectBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) { - bazelCtx := ctx.Config().BazelContext - objPaths, err := bazelCtx.GetOutputFiles(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx))) - if err != nil { - ctx.ModuleErrorf(err.Error()) - return - } - - if len(objPaths) != 1 { - ctx.ModuleErrorf("expected exactly one object file for '%s', but got %s", label, objPaths) - return - } - - handler.module.outputFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, objPaths[0])) -} - type ObjectLinkerProperties struct { // list of static library modules that should only provide headers for this module. Static_libs []string `android:"arch_variant,variant_prepend"` @@ -125,115 +96,15 @@ func ObjectFactory() android.Module { baseLinker: NewBaseLinker(module.sanitize), } module.compiler = NewBaseCompiler() - module.bazelHandler = &objectBazelHandler{module: module} // Clang's address-significance tables are incompatible with ld -r. module.compiler.appendCflags([]string{"-fno-addrsig"}) module.sdkMemberTypes = []android.SdkMemberType{ccObjectSdkMemberType} - module.bazelable = true return module.Init() } -// For bp2build conversion. -type bazelObjectAttributes struct { - Srcs bazel.LabelListAttribute - Srcs_as bazel.LabelListAttribute - Hdrs bazel.LabelListAttribute - Objs bazel.LabelListAttribute - Deps bazel.LabelListAttribute - System_dynamic_deps bazel.LabelListAttribute - Copts bazel.StringListAttribute - Asflags bazel.StringListAttribute - Local_includes bazel.StringListAttribute - Absolute_includes bazel.StringListAttribute - Stl *string - Linker_script bazel.LabelAttribute - Crt *bool - sdkAttributes -} - -// objectBp2Build is the bp2build converter from cc_object modules to the -// Bazel equivalent target, plus any necessary include deps for the cc_object. -func objectBp2Build(ctx android.TopDownMutatorContext, m *Module) { - if m.compiler == nil { - // a cc_object must have access to the compiler decorator for its props. - ctx.ModuleErrorf("compiler must not be nil for a cc_object module") - } - - // Set arch-specific configurable attributes - baseAttributes := bp2BuildParseBaseProps(ctx, m) - compilerAttrs := baseAttributes.compilerAttributes - var objs bazel.LabelListAttribute - var deps bazel.LabelListAttribute - systemDynamicDeps := bazel.LabelListAttribute{ForceSpecifyEmptyList: true} - - var linkerScript bazel.LabelAttribute - - for axis, configToProps := range m.GetArchVariantProperties(ctx, &ObjectLinkerProperties{}) { - for config, props := range configToProps { - if objectLinkerProps, ok := props.(*ObjectLinkerProperties); ok { - if objectLinkerProps.Linker_script != nil { - label := android.BazelLabelForModuleSrcSingle(ctx, *objectLinkerProps.Linker_script) - linkerScript.SetSelectValue(axis, config, label) - } - objs.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, objectLinkerProps.Objs)) - systemSharedLibs := objectLinkerProps.System_shared_libs - if len(systemSharedLibs) > 0 { - systemSharedLibs = android.FirstUniqueStrings(systemSharedLibs) - } - systemDynamicDeps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, systemSharedLibs)) - deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, objectLinkerProps.Static_libs)) - deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, objectLinkerProps.Shared_libs)) - deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, objectLinkerProps.Header_libs)) - // static_libs, shared_libs, and header_libs have variant_prepend tag - deps.Prepend = true - } - } - } - objs.ResolveExcludes() - - // Don't split cc_object srcs across languages. Doing so would add complexity, - // and this isn't typically done for cc_object. - srcs := compilerAttrs.srcs - srcs.Append(compilerAttrs.cSrcs) - - asFlags := compilerAttrs.asFlags - if compilerAttrs.asSrcs.IsEmpty() { - // Skip asflags for BUILD file simplicity if there are no assembly sources. - asFlags = bazel.MakeStringListAttribute(nil) - } - - attrs := &bazelObjectAttributes{ - Srcs: srcs, - Srcs_as: compilerAttrs.asSrcs, - Objs: objs, - Deps: deps, - System_dynamic_deps: systemDynamicDeps, - Copts: compilerAttrs.copts, - Asflags: asFlags, - Local_includes: compilerAttrs.localIncludes, - Absolute_includes: compilerAttrs.absoluteIncludes, - Stl: compilerAttrs.stl, - Linker_script: linkerScript, - Crt: m.linker.(*objectLinker).Properties.Crt, - sdkAttributes: bp2BuildParseSdkAttributes(m), - } - - props := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_object", - Bzl_load_location: "//build/bazel/rules/cc:cc_object.bzl", - } - - tags := android.ApexAvailableTags(m) - - ctx.CreateBazelTargetModule(props, android.CommonAttributes{ - Name: m.Name(), - Tags: tags, - }, attrs) -} - func (object *objectLinker) appendLdflags(flags []string) { panic(fmt.Errorf("appendLdflags on objectLinker not supported")) } @@ -309,6 +180,8 @@ func (object *objectLinker) link(ctx ModuleContext, }) } } else { + outputAddrSig := android.PathForModuleOut(ctx, "addrsig", outputName) + if String(object.Properties.Prefix_symbols) != "" { input := android.PathForModuleOut(ctx, "unprefixed", outputName) transformBinaryPrefixSymbols(ctx, String(object.Properties.Prefix_symbols), input, @@ -316,7 +189,12 @@ func (object *objectLinker) link(ctx ModuleContext, output = input } - transformObjsToObj(ctx, objs.objFiles, builderFlags, output, flags.LdFlagsDeps) + transformObjsToObj(ctx, objs.objFiles, builderFlags, outputAddrSig, flags.LdFlagsDeps) + + // ld -r reorders symbols and invalidates the .llvm_addrsig section, which then causes warnings + // if the resulting object is used with ld --icf=safe. Strip the .llvm_addrsig section to + // prevent the warnings. + transformObjectNoAddrSig(ctx, outputAddrSig, output) } ctx.CheckbuildFile(outputFile) @@ -341,6 +219,10 @@ func (object *objectLinker) unstrippedOutputFilePath() android.Path { return nil } +func (object *objectLinker) strippedAllOutputFilePath() android.Path { + return nil +} + func (object *objectLinker) nativeCoverage() bool { return true } @@ -356,3 +238,8 @@ func (object *objectLinker) object() bool { func (object *objectLinker) isCrt() bool { return Bool(object.Properties.Crt) } + +func (object *objectLinker) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + object.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON) + moduleInfoJSON.Class = []string{"STATIC_LIBRARIES"} +} diff --git a/cc/object_test.go b/cc/object_test.go index b1e2a0fd2..004dfd3e7 100644 --- a/cc/object_test.go +++ b/cc/object_test.go @@ -22,7 +22,7 @@ import ( ) func TestMinSdkVersionsOfCrtObjects(t *testing.T) { - ctx := testCc(t, ` + bp := ` cc_object { name: "crt_foo", srcs: ["foo.c"], @@ -30,8 +30,8 @@ func TestMinSdkVersionsOfCrtObjects(t *testing.T) { stl: "none", min_sdk_version: "28", vendor_available: true, - }`) - + } + ` variants := []struct { variant string num string @@ -41,13 +41,19 @@ func TestMinSdkVersionsOfCrtObjects(t *testing.T) { {"android_arm64_armv8-a_sdk_29", "29"}, {"android_arm64_armv8-a_sdk_30", "30"}, {"android_arm64_armv8-a_sdk_current", "10000"}, - {"android_vendor.29_arm64_armv8-a", "29"}, + {"android_vendor_arm64_armv8-a", "10000"}, } + + ctx := prepareForCcTest.RunTestWithBp(t, bp) for _, v := range variants { cflags := ctx.ModuleForTests("crt_foo", v.variant).Rule("cc").Args["cFlags"] expected := "-target aarch64-linux-android" + v.num + " " android.AssertStringDoesContain(t, "cflag", cflags, expected) } + ctx = prepareForCcTest.RunTestWithBp(t, bp) + android.AssertStringDoesContain(t, "cflag", + ctx.ModuleForTests("crt_foo", "android_vendor_arm64_armv8-a").Rule("cc").Args["cFlags"], + "-target aarch64-linux-android10000 ") } func TestUseCrtObjectOfCorrectVersion(t *testing.T) { @@ -85,30 +91,6 @@ func TestLinkerScript(t *testing.T) { }) } -func TestCcObjectWithBazel(t *testing.T) { - bp := ` -cc_object { - name: "foo", - srcs: ["baz.o"], - bazel_module: { label: "//foo/bar:bar" }, -}` - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: "outputbase", - LabelToOutputFiles: map[string][]string{ - "//foo/bar:bar": []string{"bazel_out.o"}}} - ctx := testCcWithConfig(t, config) - - module := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon").Module() - outputFiles, err := module.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object outputfiles %s", err) - } - - expectedOutputFiles := []string{"outputbase/execroot/__main__/bazel_out.o"} - android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings()) -} - func TestCcObjectOutputFile(t *testing.T) { testcases := []struct { name string diff --git a/cc/orderfile.go b/cc/orderfile.go new file mode 100644 index 000000000..38b89059b --- /dev/null +++ b/cc/orderfile.go @@ -0,0 +1,252 @@ +// 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" + + "github.com/google/blueprint" + + "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, orderfileProfileFlag) + flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm -enable-order-file-instrumentation") + flags.Local.CFlags = append(flags.Local.CFlags, props.Orderfile.Cflags...) + 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.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 +} + +func orderfilePropagateViaDepTag(tag blueprint.DependencyTag) bool { + libTag, isLibTag := tag.(libraryDependencyTag) + // Do not recurse down non-static dependencies + if isLibTag { + return libTag.static() + } else { + return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag + } +} + +// orderfileTransitionMutator creates orderfile variants of cc modules. +type orderfileTransitionMutator struct{} + +const ORDERFILE_VARIATION = "orderfile" + +func (o *orderfileTransitionMutator) Split(ctx android.BaseModuleContext) []string { + return []string{""} +} + +func (o *orderfileTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + if m, ok := ctx.Module().(*Module); ok && m.orderfile != nil { + if !orderfilePropagateViaDepTag(ctx.DepTag()) { + return "" + } + + if sourceVariation != "" { + return sourceVariation + } + + // Propagate profile orderfile flags down from binaries and shared libraries + if m.orderfile.orderfileLinkEnabled() { + return ORDERFILE_VARIATION + } + } + return "" +} + +func (o *orderfileTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { + if m, ok := ctx.Module().(*Module); ok && m.orderfile != nil { + return incomingVariation + } + return "" +} + +func (o *orderfileTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { + if variation == "" { + return + } + + if m, ok := ctx.Module().(*Module); ok && m.orderfile != nil { + m.Properties.PreventInstall = true + m.Properties.HideFromMake = true + m.orderfile.Properties.ShouldProfileModule = true + // We do not allow propagation for load flags because the orderfile is specific + // to the module (binary / shared library) + m.orderfile.Properties.OrderfileLoad = false + } +} diff --git a/cc/orderfile_test.go b/cc/orderfile_test.go new file mode 100644 index 000000000..3486f964c --- /dev/null +++ b/cc/orderfile_test.go @@ -0,0 +1,470 @@ +// 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) + } + } +} diff --git a/cc/pgo.go b/cc/pgo.go deleted file mode 100644 index 463e2e623..000000000 --- a/cc/pgo.go +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2017 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 ( - "fmt" - "path/filepath" - "strings" - - "github.com/google/blueprint/proptools" - - "android/soong/android" -) - -var ( - // Add flags to ignore warnings that profiles are old or missing for - // some functions. - profileUseOtherFlags = []string{ - "-Wno-backend-plugin", - } - - globalPgoProfileProjects = []string{ - "toolchain/pgo-profiles/pgo", - "vendor/google_data/pgo_profile/pgo", - } -) - -var pgoProfileProjectsConfigKey = android.NewOnceKey("PgoProfileProjects") - -const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp" -const profileUseInstrumentFormat = "-fprofile-use=%s" - -func getPgoProfileProjects(config android.DeviceConfig) []string { - return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string { - return append(globalPgoProfileProjects, config.PgoAdditionalProfileDirs()...) - }) -} - -func recordMissingProfileFile(ctx BaseModuleContext, missing string) { - getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true) -} - -type PgoProperties struct { - Pgo struct { - Instrumentation *bool - Profile_file *string `android:"arch_variant"` - Benchmarks []string - Enable_profile_use *bool `android:"arch_variant"` - // Additional compiler flags to use when building this module - // for profiling. - Cflags []string `android:"arch_variant"` - } `android:"arch_variant"` - - PgoPresent bool `blueprint:"mutated"` - ShouldProfileModule bool `blueprint:"mutated"` - PgoCompile bool `blueprint:"mutated"` - PgoInstrLink bool `blueprint:"mutated"` -} - -type pgo struct { - Properties PgoProperties -} - -func (props *PgoProperties) isInstrumentation() bool { - return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true -} - -func (pgo *pgo) props() []interface{} { - return []interface{}{&pgo.Properties} -} - -func (props *PgoProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags { - // Add to C flags iff PGO is explicitly enabled for this module. - if props.ShouldProfileModule { - flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...) - flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag) - } - flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrumentFlag) - return flags -} - -func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath { - profileFile := *props.Pgo.Profile_file - - // Test if the profile_file is present in any of the PGO profile projects - for _, profileProject := range getPgoProfileProjects(ctx.DeviceConfig()) { - // Bug: http://b/74395273 If the profile_file is unavailable, - // use a versioned file named - // <profile_file>.<arbitrary-version> when available. This - // works around an issue where ccache serves stale cache - // entries when the profile file has changed. - globPattern := filepath.Join(profileProject, profileFile+".*") - versionedProfiles, err := ctx.GlobWithDeps(globPattern, nil) - if err != nil { - ctx.ModuleErrorf("glob: %s", err.Error()) - } - - path := android.ExistentPathForSource(ctx, profileProject, profileFile) - if path.Valid() { - if len(versionedProfiles) != 0 { - ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+filepath.Join(profileProject, profileFile)+", "+strings.Join(versionedProfiles, ", ")) - } - return path - } - - if len(versionedProfiles) > 1 { - ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+strings.Join(versionedProfiles, ", ")) - } else if len(versionedProfiles) == 1 { - return android.OptionalPathForPath(android.PathForSource(ctx, versionedProfiles[0])) - } - } - - // Record that this module's profile file is absent - missing := *props.Pgo.Profile_file + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName() - recordMissingProfileFile(ctx, missing) - - return android.OptionalPathForPath(nil) -} - -func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string { - flags := []string{fmt.Sprintf(profileUseInstrumentFormat, file)} - flags = append(flags, profileUseOtherFlags...) - return flags -} - -func (props *PgoProperties) addProfileUseFlags(ctx ModuleContext, flags Flags) Flags { - // Return if 'pgo' property is not present in this module. - if !props.PgoPresent { - return flags - } - - if props.PgoCompile { - profileFile := props.getPgoProfileFile(ctx) - profileFilePath := profileFile.Path() - profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String()) - - flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlags...) - flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlags...) - - // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt - // if profileFile gets updated - flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath) - flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath) - } - return flags -} - -func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool { - isInstrumentation := props.isInstrumentation() - - profileKindPresent := isInstrumentation - filePresent := props.Pgo.Profile_file != nil - benchmarksPresent := len(props.Pgo.Benchmarks) > 0 - - // If all three properties are absent, PGO is OFF for this module - if !profileKindPresent && !filePresent && !benchmarksPresent { - return false - } - - // profileKindPresent and filePresent are mandatory properties. - if !profileKindPresent || !filePresent { - var missing []string - if !profileKindPresent { - missing = append(missing, "profile kind") - } - if !filePresent { - missing = append(missing, "profile_file property") - } - missingProps := strings.Join(missing, ", ") - ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps) - } - - // Benchmark property is mandatory for instrumentation PGO. - if isInstrumentation && !benchmarksPresent { - ctx.ModuleErrorf("Instrumentation PGO specification is missing benchmark property") - } - - return true -} - -func (pgo *pgo) begin(ctx BaseModuleContext) { - // TODO Evaluate if we need to support PGO for host modules - if ctx.Host() { - return - } - - // Check if PGO is needed for this module - pgo.Properties.PgoPresent = pgo.Properties.isPGO(ctx) - - if !pgo.Properties.PgoPresent { - return - } - - // This module should be instrumented if ANDROID_PGO_INSTRUMENT is set - // and includes 'all', 'ALL' or a benchmark listed for this module. - // - // TODO Validate that each benchmark instruments at least one module - pgo.Properties.ShouldProfileModule = false - pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT") - pgoBenchmarksMap := make(map[string]bool) - for _, b := range strings.Split(pgoBenchmarks, ",") { - pgoBenchmarksMap[b] = true - } - - if pgoBenchmarksMap["all"] == true || pgoBenchmarksMap["ALL"] == true { - pgo.Properties.ShouldProfileModule = true - pgo.Properties.PgoInstrLink = pgo.Properties.isInstrumentation() - } else { - for _, b := range pgo.Properties.Pgo.Benchmarks { - if pgoBenchmarksMap[b] == true { - pgo.Properties.ShouldProfileModule = true - pgo.Properties.PgoInstrLink = pgo.Properties.isInstrumentation() - break - } - } - } - - // PGO profile use is not feasible for a Clang coverage build because - // -fprofile-use and -fprofile-instr-generate are incompatible. - if ctx.DeviceConfig().ClangCoverageEnabled() { - return - } - - if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") && - proptools.BoolDefault(pgo.Properties.Pgo.Enable_profile_use, true) { - if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() { - pgo.Properties.PgoCompile = true - } - } -} - -func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags { - if ctx.Host() { - return flags - } - - // Deduce PgoInstrLink property i.e. whether this module needs to be - // linked with profile-generation flags. Here, we're setting it if any - // dependency needs PGO instrumentation. It is initially set in - // begin() if PGO is directly enabled for this module. - if ctx.static() && !ctx.staticBinary() { - // For static libraries, check if any whole_static_libs are - // linked with profile generation - ctx.VisitDirectDeps(func(m android.Module) { - if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok { - if depTag.static() && depTag.wholeStatic { - if cc, ok := m.(*Module); ok { - if cc.pgo.Properties.PgoInstrLink { - pgo.Properties.PgoInstrLink = true - } - } - } - } - }) - } else { - // For executables and shared libraries, check all static dependencies. - ctx.VisitDirectDeps(func(m android.Module) { - if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok { - if depTag.static() { - if cc, ok := m.(*Module); ok { - if cc.pgo.Properties.PgoInstrLink { - pgo.Properties.PgoInstrLink = true - } - } - } - } - }) - } - - props := pgo.Properties - // Add flags to profile this module based on its profile_kind - if (props.ShouldProfileModule && props.isInstrumentation()) || props.PgoInstrLink { - // Instrumentation PGO use and gather flags cannot coexist. - return props.addInstrumentationProfileGatherFlags(ctx, flags) - } - - if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") { - flags = props.addProfileUseFlags(ctx, flags) - } - - return flags -} diff --git a/cc/prebuilt.go b/cc/prebuilt.go index 0b5841ef0..e9f790f73 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -17,9 +17,9 @@ package cc import ( "path/filepath" + "github.com/google/blueprint/proptools" + "android/soong/android" - "android/soong/bazel" - "android/soong/bazel/cquery" ) func init() { @@ -38,9 +38,15 @@ func RegisterPrebuiltBuildComponents(ctx android.RegistrationContext) { type prebuiltLinkerInterface interface { Name(string) string prebuilt() *android.Prebuilt + sourceModuleName() string } type prebuiltLinkerProperties struct { + // Name of the source soong module that gets shadowed by this prebuilt + // If unspecified, follows the naming convention that the source module of + // the prebuilt is Name() without "prebuilt_" prefix + Source_module_name *string + // a prebuilt library or binary. Can reference a genrule module that generates an executable file. Srcs []string `android:"path,arch_variant"` @@ -57,13 +63,6 @@ type prebuiltLinkerProperties struct { // This is needed only if this library is linked by other modules in build time. // Only makes sense for the Windows target. Windows_import_lib *string `android:"path,arch_variant"` - - // MixedBuildsDisabled is true if and only if building this prebuilt is explicitly disabled in mixed builds for either - // its static or shared version on the current build variant. This is to prevent Bazel targets for build variants with - // which either the static or shared version is incompatible from participating in mixed buiods. Please note that this - // is an override and does not fully determine whether Bazel or Soong will be used. For the full determination, see - // cc.ProcessBazelQueryResponse, cc.QueueBazelCall, and cc.MixedBuildsDisabled. - MixedBuildsDisabled bool `blueprint:"mutated"` } type prebuiltLinker struct { @@ -140,8 +139,8 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, } if p.static() { - depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(in).Build() - ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{ + depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(in).Build() + android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{ StaticLibrary: in, TransitiveStaticLibrariesForOrdering: depSet, @@ -178,7 +177,7 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, implicits = append(implicits, importLibOutputFile) ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, + Rule: android.CpExecutable, Description: "prebuilt import library", Input: importLibSrc, Output: importLibOutputFile, @@ -189,7 +188,7 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, } ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, + Rule: android.CpExecutable, Description: "prebuilt shared library", Implicits: implicits, Input: in, @@ -199,7 +198,7 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, }, }) - ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{ + android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{ SharedLibrary: outputFile, Target: ctx.Target(), @@ -222,7 +221,7 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, } if p.header() { - ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{}) + android.SetProvider(ctx, HeaderLibraryInfoProvider, HeaderLibraryInfo{}) // Need to return an output path so that the AndroidMk logic doesn't skip // the prebuilt header. For compatibility, in case Android.mk files use a @@ -261,7 +260,9 @@ func (p *prebuiltLibraryLinker) nativeCoverage() bool { func (p *prebuiltLibraryLinker) disablePrebuilt() { p.properties.Srcs = nil - p.properties.MixedBuildsDisabled = true + p.properties.Sanitized.None.Srcs = nil + p.properties.Sanitized.Address.Srcs = nil + p.properties.Sanitized.Hwaddress.Srcs = nil } // Implements versionedInterface @@ -272,8 +273,6 @@ func (p *prebuiltLibraryLinker) implementationModuleName(name string) string { func NewPrebuiltLibrary(hod android.HostOrDeviceSupported, srcsProperty string) (*Module, *libraryDecorator) { module, library := NewLibrary(hod) module.compiler = nil - module.bazelable = true - module.bazelHandler = &prebuiltLibraryBazelHandler{module: module, library: library} prebuilt := &prebuiltLibraryLinker{ libraryDecorator: library, @@ -348,84 +347,12 @@ func NewPrebuiltStaticLibrary(hod android.HostOrDeviceSupported) (*Module, *libr return module, library } -type bazelPrebuiltLibraryStaticAttributes struct { - Static_library bazel.LabelAttribute - Export_includes bazel.StringListAttribute - Export_system_includes bazel.StringListAttribute - Alwayslink bazel.BoolAttribute -} - -// TODO(b/228623543): The below is not entirely true until the bug is fixed. For now, both targets are always generated -// Implements bp2build for cc_prebuilt_library modules. This will generate: -// - Only a cc_prebuilt_library_static if the shared.enabled property is set to false across all variants. -// - Only a cc_prebuilt_library_shared if the static.enabled property is set to false across all variants -// - Both a cc_prebuilt_library_static and cc_prebuilt_library_shared if the aforementioned properties are not false across -// all variants -// -// In all cases, cc_prebuilt_library_static target names will be appended with "_bp2build_cc_library_static". -func prebuiltLibraryBp2Build(ctx android.TopDownMutatorContext, module *Module) { - prebuiltLibraryStaticBp2Build(ctx, module, true) - prebuiltLibrarySharedBp2Build(ctx, module) -} - -func prebuiltLibraryStaticBp2Build(ctx android.TopDownMutatorContext, module *Module, fullBuild bool) { - prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module, true) - exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, nil) - - attrs := &bazelPrebuiltLibraryStaticAttributes{ - Static_library: prebuiltAttrs.Src, - Export_includes: exportedIncludes.Includes, - Export_system_includes: exportedIncludes.SystemIncludes, - // TODO: ¿Alwayslink? - } - - props := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_prebuilt_library_static", - Bzl_load_location: "//build/bazel/rules/cc:cc_prebuilt_library_static.bzl", - } - - name := android.RemoveOptionalPrebuiltPrefix(module.Name()) - if fullBuild { - name += "_bp2build_cc_library_static" - } - - tags := android.ApexAvailableTags(module) - ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name, Tags: tags}, attrs, prebuiltAttrs.Enabled) - - _true := true - alwayslinkAttrs := *attrs - alwayslinkAttrs.Alwayslink.SetValue(&_true) - ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name + "_alwayslink", Tags: tags}, &alwayslinkAttrs, prebuiltAttrs.Enabled) -} - -type bazelPrebuiltLibrarySharedAttributes struct { - Shared_library bazel.LabelAttribute - Export_includes bazel.StringListAttribute - Export_system_includes bazel.StringListAttribute -} - -func prebuiltLibrarySharedBp2Build(ctx android.TopDownMutatorContext, module *Module) { - prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module, false) - exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, nil) - - attrs := &bazelPrebuiltLibrarySharedAttributes{ - Shared_library: prebuiltAttrs.Src, - Export_includes: exportedIncludes.Includes, - Export_system_includes: exportedIncludes.SystemIncludes, - } - - props := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_prebuilt_library_shared", - Bzl_load_location: "//build/bazel/rules/cc:cc_prebuilt_library_shared.bzl", - } - - name := android.RemoveOptionalPrebuiltPrefix(module.Name()) - tags := android.ApexAvailableTags(module) - ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name, Tags: tags}, attrs, prebuiltAttrs.Enabled) -} - type prebuiltObjectProperties struct { - Srcs []string `android:"path,arch_variant"` + // Name of the source soong module that gets shadowed by this prebuilt + // If unspecified, follows the naming convention that the source module of + // the prebuilt is Name() without "prebuilt_" prefix + Source_module_name *string + Srcs []string `android:"path,arch_variant"` } type prebuiltObjectLinker struct { @@ -435,139 +362,14 @@ type prebuiltObjectLinker struct { properties prebuiltObjectProperties } -type prebuiltLibraryBazelHandler struct { - module *Module - library *libraryDecorator -} - -var _ BazelHandler = (*prebuiltLibraryBazelHandler)(nil) - -func (h *prebuiltLibraryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) { - if h.module.linker.(*prebuiltLibraryLinker).properties.MixedBuildsDisabled { - return - } - bazelCtx := ctx.Config().BazelContext - bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKey(ctx)) -} - -func (h *prebuiltLibraryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) { - if h.module.linker.(*prebuiltLibraryLinker).properties.MixedBuildsDisabled { - return - } - bazelCtx := ctx.Config().BazelContext - ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKey(ctx)) - if err != nil { - ctx.ModuleErrorf(err.Error()) - return - } - - if h.module.static() { - if ok := h.processStaticBazelQueryResponse(ctx, label, ccInfo); !ok { - return - } - } else if h.module.Shared() { - if ok := h.processSharedBazelQueryResponse(ctx, label, ccInfo); !ok { - return - } - } else { - return - } - - h.module.maybeUnhideFromMake() - - h.module.setAndroidMkVariablesFromCquery(ccInfo.CcAndroidMkInfo) -} - -func (h *prebuiltLibraryBazelHandler) processStaticBazelQueryResponse(ctx android.ModuleContext, label string, ccInfo cquery.CcInfo) bool { - staticLibs := ccInfo.CcStaticLibraryFiles - if len(staticLibs) > 1 { - ctx.ModuleErrorf("expected 1 static library from bazel target %q, got %s", label, staticLibs) - return false - } - - // TODO(b/184543518): cc_prebuilt_library_static may have properties for re-exporting flags - - // TODO(eakammer):Add stub-related flags if this library is a stub library. - // h.library.exportVersioningMacroIfNeeded(ctx) - - // Dependencies on this library will expect collectedSnapshotHeaders to be set, otherwise - // validation will fail. For now, set this to an empty list. - // TODO(cparsons): More closely mirror the collectHeadersForSnapshot implementation. - h.library.collectedSnapshotHeaders = android.Paths{} - - if len(staticLibs) == 0 { - h.module.outputFile = android.OptionalPath{} - return true - } - - var outputPath android.Path = android.PathForBazelOut(ctx, staticLibs[0]) - if len(ccInfo.TidyFiles) > 0 { - h.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles) - outputPath = android.AttachValidationActions(ctx, outputPath, h.module.tidyFiles) - } - - h.module.outputFile = android.OptionalPathForPath(outputPath) - - depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(outputPath).Build() - ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{ - StaticLibrary: outputPath, - TransitiveStaticLibrariesForOrdering: depSet, - }) - - return true -} - -func (h *prebuiltLibraryBazelHandler) processSharedBazelQueryResponse(ctx android.ModuleContext, label string, ccInfo cquery.CcInfo) bool { - sharedLibs := ccInfo.CcSharedLibraryFiles - if len(sharedLibs) > 1 { - ctx.ModuleErrorf("expected 1 shared library from bazel target %s, got %q", label, sharedLibs) - return false - } - - // TODO(b/184543518): cc_prebuilt_library_shared may have properties for re-exporting flags - - // TODO(eakammer):Add stub-related flags if this library is a stub library. - // h.library.exportVersioningMacroIfNeeded(ctx) - - if len(sharedLibs) == 0 { - h.module.outputFile = android.OptionalPath{} - return true - } - - var outputPath android.Path = android.PathForBazelOut(ctx, sharedLibs[0]) - if len(ccInfo.TidyFiles) > 0 { - h.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles) - outputPath = android.AttachValidationActions(ctx, outputPath, h.module.tidyFiles) - } - - h.module.outputFile = android.OptionalPathForPath(outputPath) - - // FIXME(b/214600441): We don't yet strip prebuilt shared libraries - h.library.unstrippedOutputFile = outputPath - - var toc android.Path - if len(ccInfo.TocFile) > 0 { - toc = android.PathForBazelOut(ctx, ccInfo.TocFile) - } else { - toc = outputPath // Just reuse `out` so ninja still gets an input but won't matter - } - - info := SharedLibraryInfo{ - SharedLibrary: outputPath, - TableOfContents: android.OptionalPathForPath(toc), - Target: ctx.Target(), - } - ctx.SetProvider(SharedLibraryInfoProvider, info) - - h.library.setFlagExporterInfoFromCcInfo(ctx, ccInfo) - h.module.maybeUnhideFromMake() - return true -} - func (p *prebuiltObjectLinker) prebuilt() *android.Prebuilt { return &p.Prebuilt } +func (p *prebuiltObjectLinker) sourceModuleName() string { + return proptools.String(p.properties.Source_module_name) +} + var _ prebuiltLinkerInterface = (*prebuiltObjectLinker)(nil) func (p *prebuiltObjectLinker) link(ctx ModuleContext, @@ -593,8 +395,6 @@ func (p *prebuiltObjectLinker) object() bool { func NewPrebuiltObject(hod android.HostOrDeviceSupported) *Module { module := newObject(hod) - module.bazelHandler = &prebuiltObjectBazelHandler{module: module} - module.bazelable = true prebuilt := &prebuiltObjectLinker{ objectLinker: objectLinker{ baseLinker: NewBaseLinker(nil), @@ -606,54 +406,6 @@ func NewPrebuiltObject(hod android.HostOrDeviceSupported) *Module { return module } -type prebuiltObjectBazelHandler struct { - module *Module -} - -var _ BazelHandler = (*prebuiltObjectBazelHandler)(nil) - -func (h *prebuiltObjectBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) { - bazelCtx := ctx.Config().BazelContext - bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKey(ctx)) -} - -func (h *prebuiltObjectBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) { - bazelCtx := ctx.Config().BazelContext - outputs, err := bazelCtx.GetOutputFiles(label, android.GetConfigKey(ctx)) - if err != nil { - ctx.ModuleErrorf(err.Error()) - return - } - if len(outputs) != 1 { - ctx.ModuleErrorf("Expected a single output for `%s`, but got:\n%v", label, outputs) - return - } - out := android.PathForBazelOut(ctx, outputs[0]) - h.module.outputFile = android.OptionalPathForPath(out) - h.module.maybeUnhideFromMake() -} - -type bazelPrebuiltObjectAttributes struct { - Src bazel.LabelAttribute -} - -func prebuiltObjectBp2Build(ctx android.TopDownMutatorContext, module *Module) { - prebuiltAttrs := bp2BuildParsePrebuiltObjectProps(ctx, module) - - attrs := &bazelPrebuiltObjectAttributes{ - Src: prebuiltAttrs.Src, - } - - props := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_prebuilt_object", - Bzl_load_location: "//build/bazel/rules/cc:cc_prebuilt_object.bzl", - } - - name := android.RemoveOptionalPrebuiltPrefix(module.Name()) - tags := android.ApexAvailableTags(module) - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name, Tags: tags}, attrs) -} - func PrebuiltObjectFactory() android.Module { module := NewPrebuiltObject(android.HostAndDeviceSupported) return module.Init() @@ -747,15 +499,9 @@ func PrebuiltBinaryFactory() android.Module { return module.Init() } -type prebuiltBinaryBazelHandler struct { - module *Module - decorator *binaryDecorator -} - func NewPrebuiltBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { - module, binary := newBinary(hod, true) + module, binary := newBinary(hod) module.compiler = nil - module.bazelHandler = &prebuiltBinaryBazelHandler{module, binary} prebuilt := &prebuiltBinaryLinker{ binaryDecorator: binary, @@ -769,54 +515,6 @@ func NewPrebuiltBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecor return module, binary } -var _ BazelHandler = (*prebuiltBinaryBazelHandler)(nil) - -func (h *prebuiltBinaryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) { - bazelCtx := ctx.Config().BazelContext - bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx))) -} - -func (h *prebuiltBinaryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) { - bazelCtx := ctx.Config().BazelContext - outputs, err := bazelCtx.GetOutputFiles(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx))) - if err != nil { - ctx.ModuleErrorf(err.Error()) - return - } - if len(outputs) != 1 { - ctx.ModuleErrorf("Expected a single output for `%s`, but got:\n%v", label, outputs) - return - } - out := android.PathForBazelOut(ctx, outputs[0]) - h.module.outputFile = android.OptionalPathForPath(out) - h.module.maybeUnhideFromMake() -} - -type bazelPrebuiltBinaryAttributes struct { - Src bazel.LabelAttribute - Strip stripAttributes -} - -func prebuiltBinaryBp2Build(ctx android.TopDownMutatorContext, module *Module) { - prebuiltAttrs := bp2BuildParsePrebuiltBinaryProps(ctx, module) - - var la linkerAttributes - la.convertStripProps(ctx, module) - attrs := &bazelPrebuiltBinaryAttributes{ - Src: prebuiltAttrs.Src, - Strip: stripAttrsFromLinkerAttrs(&la), - } - - props := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_prebuilt_binary", - Bzl_load_location: "//build/bazel/rules/cc:cc_prebuilt_binary.bzl", - } - - name := android.RemoveOptionalPrebuiltPrefix(module.Name()) - tags := android.ApexAvailableTags(module) - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name, Tags: tags}, attrs) -} - type Sanitized struct { None struct { Srcs []string `android:"path,arch_variant"` @@ -841,3 +539,7 @@ func srcsForSanitizer(sanitize *sanitize, sanitized Sanitized) []string { } return sanitized.None.Srcs } + +func (p *prebuiltLinker) sourceModuleName() string { + return proptools.String(p.properties.Source_module_name) +} diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go index 0c79e55d6..71b7e4369 100644 --- a/cc/prebuilt_test.go +++ b/cc/prebuilt_test.go @@ -15,12 +15,11 @@ package cc import ( + "fmt" "runtime" "testing" "android/soong/android" - "android/soong/bazel/cquery" - "github.com/google/blueprint" ) @@ -386,289 +385,6 @@ func TestPrebuiltLibrarySanitized(t *testing.T) { assertString(t, static2.OutputFile().Path().Base(), "libf.hwasan.a") } -func TestPrebuiltLibraryWithBazel(t *testing.T) { - const bp = ` -cc_prebuilt_library { - name: "foo", - shared: { - srcs: ["foo.so"], - }, - static: { - srcs: ["foo.a"], - }, - bazel_module: { label: "//foo/bar:bar" }, -}` - outBaseDir := "outputbase" - result := android.GroupFixturePreparers( - prepareForPrebuiltTest, - android.FixtureModifyConfig(func(config android.Config) { - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: outBaseDir, - LabelToCcInfo: map[string]cquery.CcInfo{ - "//foo/bar:bar": cquery.CcInfo{ - CcSharedLibraryFiles: []string{"foo.so"}, - }, - "//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{ - CcStaticLibraryFiles: []string{"foo.a"}, - }, - }, - } - }), - ).RunTestWithBp(t, bp) - sharedFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module() - pathPrefix := outBaseDir + "/execroot/__main__/" - - sharedInfo := result.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo) - android.AssertPathRelativeToTopEquals(t, - "prebuilt library shared target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.", - pathPrefix+"foo.so", sharedInfo.SharedLibrary) - - outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object outputfiles %s", err) - } - expectedOutputFiles := []string{pathPrefix + "foo.so"} - android.AssertDeepEquals(t, - "prebuilt library shared target output files did not match expected.", - expectedOutputFiles, outputFiles.Strings()) - - staticFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module() - staticInfo := result.ModuleProvider(staticFoo, StaticLibraryInfoProvider).(StaticLibraryInfo) - android.AssertPathRelativeToTopEquals(t, - "prebuilt library static target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.", - pathPrefix+"foo.a", staticInfo.StaticLibrary) - - staticOutputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object staticOutputFiles %s", err) - } - expectedStaticOutputFiles := []string{pathPrefix + "foo.a"} - android.AssertDeepEquals(t, - "prebuilt library static target output files did not match expected.", - expectedStaticOutputFiles, staticOutputFiles.Strings()) -} - -func TestPrebuiltLibraryWithBazelValidations(t *testing.T) { - const bp = ` -cc_prebuilt_library { - name: "foo", - shared: { - srcs: ["foo.so"], - }, - static: { - srcs: ["foo.a"], - }, - bazel_module: { label: "//foo/bar:bar" }, - tidy: true, -}` - outBaseDir := "outputbase" - result := android.GroupFixturePreparers( - prepareForPrebuiltTest, - android.FixtureMergeEnv(map[string]string{ - "ALLOW_LOCAL_TIDY_TRUE": "1", - }), - android.FixtureModifyConfig(func(config android.Config) { - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: outBaseDir, - LabelToCcInfo: map[string]cquery.CcInfo{ - "//foo/bar:bar": cquery.CcInfo{ - CcSharedLibraryFiles: []string{"foo.so"}, - TidyFiles: []string{"foo.c.tidy"}, - }, - "//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{ - CcStaticLibraryFiles: []string{"foo.a"}, - TidyFiles: []string{"foo.c.tidy"}, - }, - }, - } - }), - ).RunTestWithBp(t, bp) - sharedFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module() - - expectedOutputFile := "out/soong/.intermediates/foo/android_arm_armv7-a-neon_shared/validated/foo.so" - sharedInfo := result.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo) - android.AssertPathRelativeToTopEquals(t, - "prebuilt library shared target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.", - expectedOutputFile, sharedInfo.SharedLibrary) - - outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object outputfiles %s", err) - } - expectedOutputFiles := []string{expectedOutputFile} - android.AssertPathsRelativeToTopEquals(t, - "prebuilt library shared target output files did not match expected.", - expectedOutputFiles, outputFiles) - - staticFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module() - staticInfo := result.ModuleProvider(staticFoo, StaticLibraryInfoProvider).(StaticLibraryInfo) - expectedStaticOutputFile := "out/soong/.intermediates/foo/android_arm_armv7-a-neon_static/validated/foo.a" - android.AssertPathRelativeToTopEquals(t, - "prebuilt library static target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.", - expectedStaticOutputFile, staticInfo.StaticLibrary) - - staticOutputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object staticOutputFiles %s", err) - } - expectedStaticOutputFiles := []string{expectedStaticOutputFile} - android.AssertPathsRelativeToTopEquals(t, - "prebuilt library static target output files did not match expected.", - expectedStaticOutputFiles, staticOutputFiles) -} - -func TestPrebuiltLibraryWithBazelStaticDisabled(t *testing.T) { - const bp = ` -cc_prebuilt_library { - name: "foo", - shared: { - srcs: ["foo.so"], - }, - static: { - enabled: false - }, - bazel_module: { label: "//foo/bar:bar" }, -}` - outBaseDir := "outputbase" - result := android.GroupFixturePreparers( - prepareForPrebuiltTest, - android.FixtureModifyConfig(func(config android.Config) { - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: outBaseDir, - LabelToCcInfo: map[string]cquery.CcInfo{ - "//foo/bar:bar": cquery.CcInfo{ - CcSharedLibraryFiles: []string{"foo.so"}, - }, - }, - } - }), - ).RunTestWithBp(t, bp) - sharedFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module() - pathPrefix := outBaseDir + "/execroot/__main__/" - - sharedInfo := result.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo) - android.AssertPathRelativeToTopEquals(t, - "prebuilt library shared target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.", - pathPrefix+"foo.so", sharedInfo.SharedLibrary) - - outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object outputfiles %s", err) - } - expectedOutputFiles := []string{pathPrefix + "foo.so"} - android.AssertDeepEquals(t, - "prebuilt library shared target output files did not match expected.", - expectedOutputFiles, outputFiles.Strings()) -} - -func TestPrebuiltLibraryStaticWithBazel(t *testing.T) { - const bp = ` -cc_prebuilt_library_static { - name: "foo", - srcs: ["foo.so"], - bazel_module: { label: "//foo/bar:bar" }, -}` - outBaseDir := "outputbase" - result := android.GroupFixturePreparers( - prepareForPrebuiltTest, - android.FixtureModifyConfig(func(config android.Config) { - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: outBaseDir, - LabelToCcInfo: map[string]cquery.CcInfo{ - "//foo/bar:bar": cquery.CcInfo{ - CcStaticLibraryFiles: []string{"foo.so"}, - }, - }, - } - }), - ).RunTestWithBp(t, bp) - staticFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module() - pathPrefix := outBaseDir + "/execroot/__main__/" - - info := result.ModuleProvider(staticFoo, StaticLibraryInfoProvider).(StaticLibraryInfo) - android.AssertPathRelativeToTopEquals(t, - "prebuilt library static path did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.", - pathPrefix+"foo.so", info.StaticLibrary) - - outputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object outputfiles %s", err) - } - expectedOutputFiles := []string{pathPrefix + "foo.so"} - android.AssertDeepEquals(t, "prebuilt library static output files did not match expected.", expectedOutputFiles, outputFiles.Strings()) -} - -func TestPrebuiltLibrarySharedWithBazelWithoutToc(t *testing.T) { - const bp = ` -cc_prebuilt_library_shared { - name: "foo", - srcs: ["foo.so"], - bazel_module: { label: "//foo/bar:bar" }, -}` - outBaseDir := "outputbase" - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: outBaseDir, - LabelToCcInfo: map[string]cquery.CcInfo{ - "//foo/bar:bar": cquery.CcInfo{ - CcSharedLibraryFiles: []string{"foo.so"}, - }, - }, - } - ctx := testCcWithConfig(t, config) - sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module() - pathPrefix := outBaseDir + "/execroot/__main__/" - - info := ctx.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo) - android.AssertPathRelativeToTopEquals(t, "prebuilt shared library", - pathPrefix+"foo.so", info.SharedLibrary) - android.AssertPathRelativeToTopEquals(t, "prebuilt's 'nullary' ToC", - pathPrefix+"foo.so", info.TableOfContents.Path()) - - outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object outputfiles %s", err) - } - expectedOutputFiles := []string{pathPrefix + "foo.so"} - android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings()) -} - -func TestPrebuiltLibrarySharedWithBazelWithToc(t *testing.T) { - const bp = ` -cc_prebuilt_library_shared { - name: "foo", - srcs: ["foo.so"], - bazel_module: { label: "//foo/bar:bar" }, -}` - outBaseDir := "outputbase" - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: outBaseDir, - LabelToCcInfo: map[string]cquery.CcInfo{ - "//foo/bar:bar": cquery.CcInfo{ - CcSharedLibraryFiles: []string{"foo.so"}, - TocFile: "toc", - }, - }, - } - ctx := testCcWithConfig(t, config) - sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module() - pathPrefix := outBaseDir + "/execroot/__main__/" - - info := ctx.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo) - android.AssertPathRelativeToTopEquals(t, "prebuilt shared library's ToC", - pathPrefix+"toc", info.TableOfContents.Path()) - android.AssertPathRelativeToTopEquals(t, "prebuilt shared library", - pathPrefix+"foo.so", info.SharedLibrary) - - outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("") - if err != nil { - t.Errorf("Unexpected error getting cc_object outputfiles %s", err) - } - expectedOutputFiles := []string{pathPrefix + "foo.so"} - android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings()) -} - func TestPrebuiltStubNoinstall(t *testing.T) { testFunc := func(t *testing.T, expectLibfooOnSystemLib bool, fs android.MockFS) { result := android.GroupFixturePreparers( @@ -795,26 +511,252 @@ cc_prebuilt_binary { testCcError(t, `Android.bp:4:6: module "bintest" variant "android_arm64_armv8-a": srcs: multiple prebuilt source files`, bp) } -func TestPrebuiltBinaryWithBazel(t *testing.T) { - const bp = ` -cc_prebuilt_binary { - name: "bintest", - srcs: ["bin"], - bazel_module: { label: "//bin/foo:foo" }, -}` - const outBaseDir = "outputbase" - const expectedOut = outBaseDir + "/execroot/__main__/bin" - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.BazelContext = android.MockBazelContext{ - OutputBaseDir: outBaseDir, - LabelToOutputFiles: map[string][]string{"//bin/foo:foo": []string{"bin"}}, +func TestMultiplePrebuilts(t *testing.T) { + bp := ` + // an rdep + cc_library { + name: "libfoo", + shared_libs: ["libbar"], + } + + // multiple variations of dep + // source + cc_library { + name: "libbar", + } + // prebuilt "v1" + cc_prebuilt_library_shared { + name: "libbar", + srcs: ["libbar.so"], + } + // prebuilt "v2" + cc_prebuilt_library_shared { + name: "libbar.v2", + stem: "libbar", + source_module_name: "libbar", + srcs: ["libbar.so"], + } + + // selectors + apex_contributions { + name: "myapex_contributions", + contents: ["%v"], + } + all_apex_contributions {name: "all_apex_contributions"} + ` + hasDep := func(ctx *android.TestContext, m android.Module, wantDep android.Module) bool { + t.Helper() + var found bool + ctx.VisitDirectDeps(m, func(dep blueprint.Module) { + if dep == wantDep { + found = true + } + }) + return found + } + + testCases := []struct { + desc string + selectedDependencyName string + expectedDependencyName string + }{ + { + desc: "Source library is selected using apex_contributions", + selectedDependencyName: "libbar", + expectedDependencyName: "libbar", + }, + { + desc: "Prebuilt library v1 is selected using apex_contributions", + selectedDependencyName: "prebuilt_libbar", + expectedDependencyName: "prebuilt_libbar", + }, + { + desc: "Prebuilt library v2 is selected using apex_contributions", + selectedDependencyName: "prebuilt_libbar.v2", + expectedDependencyName: "prebuilt_libbar.v2", + }, + } + + for _, tc := range testCases { + preparer := android.GroupFixturePreparers( + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + android.RegisterApexContributionsBuildComponents(ctx) + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "myapex_contributions", + } + }), + ) + ctx := testPrebuilt(t, fmt.Sprintf(bp, tc.selectedDependencyName), map[string][]byte{ + "libbar.so": nil, + "crtx.o": nil, + }, preparer) + libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() + expectedDependency := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module() + android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", libfoo.Name(), tc.expectedDependencyName), true, hasDep(ctx, libfoo, expectedDependency)) + // check that LOCAL_SHARED_LIBRARIES contains libbar and not libbar.v<N> + entries := android.AndroidMkEntriesForTest(t, ctx, libfoo)[0] + android.AssertStringListContains(t, "Version should not be present in LOCAL_SHARED_LIBRARIES", entries.EntryMap["LOCAL_SHARED_LIBRARIES"], "libbar") + + // check installation rules + // the selected soong module should be exported to make + libbar := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module() + android.AssertBoolEquals(t, fmt.Sprintf("dependency %s should be exported to make\n", expectedDependency), true, !libbar.IsHideFromMake()) + + // check LOCAL_MODULE of the selected module name + // the prebuilt should have the same LOCAL_MODULE when exported to make + entries = android.AndroidMkEntriesForTest(t, ctx, libbar)[0] + android.AssertStringEquals(t, "unexpected LOCAL_MODULE", "libbar", entries.EntryMap["LOCAL_MODULE"][0]) + } +} + +// Setting prefer on multiple prebuilts is an error, unless one of them is also listed in apex_contributions +func TestMultiplePrebuiltsPreferredUsingLegacyFlags(t *testing.T) { + bp := ` + // an rdep + cc_library { + name: "libfoo", + shared_libs: ["libbar"], + } + + // multiple variations of dep + // source + cc_library { + name: "libbar", + } + // prebuilt "v1" + cc_prebuilt_library_shared { + name: "libbar", + srcs: ["libbar.so"], + prefer: true, + } + // prebuilt "v2" + cc_prebuilt_library_shared { + name: "libbar.v2", + stem: "libbar", + source_module_name: "libbar", + srcs: ["libbar.so"], + prefer: true, + } + + // selectors + apex_contributions { + name: "myapex_contributions", + contents: [%v], + } + all_apex_contributions {name: "all_apex_contributions"} + ` + hasDep := func(ctx *android.TestContext, m android.Module, wantDep android.Module) bool { + t.Helper() + var found bool + ctx.VisitDirectDeps(m, func(dep blueprint.Module) { + if dep == wantDep { + found = true + } + }) + return found } - ctx := testCcWithConfig(t, config) - bin := ctx.ModuleForTests("bintest", "android_arm64_armv8-a").Module().(*Module) - out := bin.OutputFile() - if !out.Valid() { - t.Error("Invalid output file") - return + + testCases := []struct { + desc string + selectedDependencyName string + expectedDependencyName string + expectedErr string + }{ + { + desc: "Multiple prebuilts have prefer: true", + expectedErr: "Multiple prebuilt modules prebuilt_libbar and prebuilt_libbar.v2 have been marked as preferred for this source module", + }, + { + desc: "Multiple prebuilts have prefer: true. The prebuilt listed in apex_contributions wins.", + selectedDependencyName: `"prebuilt_libbar"`, + expectedDependencyName: "prebuilt_libbar", + }, + } + + for _, tc := range testCases { + preparer := android.GroupFixturePreparers( + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + android.RegisterApexContributionsBuildComponents(ctx) + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "myapex_contributions", + } + }), + ) + if tc.expectedErr != "" { + preparer = preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(tc.expectedErr)) + } + + ctx := testPrebuilt(t, fmt.Sprintf(bp, tc.selectedDependencyName), map[string][]byte{ + "libbar.so": nil, + "crtx.o": nil, + }, preparer) + if tc.expectedErr != "" { + return // the fixture will assert that the excepted err has been raised + } + libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() + expectedDependency := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module() + android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", libfoo.Name(), tc.expectedDependencyName), true, hasDep(ctx, libfoo, expectedDependency)) + } +} + +// If module sdk cannot provide a cc module variant (e.g. static), then the module variant from source should be used +func TestMissingVariantInModuleSdk(t *testing.T) { + bp := ` + // an rdep + cc_library { + name: "libfoo", + static_libs: ["libbar"], + } + + // source + cc_library { + name: "libbar", + } + // prebuilt + // libbar only exists as a shared library + cc_prebuilt_library_shared { + name: "libbar", + srcs: ["libbar.so"], + } + // selectors + apex_contributions { + name: "myapex_contributions", + contents: ["prebuilt_libbar"], + } + all_apex_contributions {name: "all_apex_contributions"} + ` + hasDep := func(ctx *android.TestContext, m android.Module, wantDep android.Module) bool { + t.Helper() + var found bool + ctx.VisitDirectDeps(m, func(dep blueprint.Module) { + if dep == wantDep { + found = true + } + }) + return found } - android.AssertStringEquals(t, "output file", expectedOut, out.String()) + + preparer := android.GroupFixturePreparers( + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + android.RegisterApexContributionsBuildComponents(ctx) + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "myapex_contributions", + } + }), + ) + ctx := testPrebuilt(t, bp, map[string][]byte{ + "libbar.so": nil, + "crtx.o": nil, + }, preparer) + libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() + sourceLibBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Module() + // Even though the prebuilt is listed in apex_contributions, the prebuilt does not have a static variant. + // Therefore source of libbar should be used. + android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from libfoo to source libbar"), true, hasDep(ctx, libfoo, sourceLibBar)) } diff --git a/cc/proto.go b/cc/proto.go index 97470e5ea..4d72f2665 100644 --- a/cc/proto.go +++ b/cc/proto.go @@ -19,7 +19,6 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" - "android/soong/bazel" ) const ( @@ -163,70 +162,3 @@ func protoFlags(ctx ModuleContext, flags Flags, p *android.ProtoProperties) Flag return flags } - -type protoAttributes struct { - Deps bazel.LabelListAttribute - Min_sdk_version *string -} - -type bp2buildProtoDeps struct { - wholeStaticLib *bazel.LabelAttribute - implementationWholeStaticLib *bazel.LabelAttribute - protoDep *bazel.LabelAttribute -} - -func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) bp2buildProtoDeps { - var ret bp2buildProtoDeps - - protoInfo, ok := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, protoSrcs) - if !ok || protoInfo.Proto_libs.IsEmpty() { - return ret - } - - var depName string - typ := proptools.StringDefault(protoInfo.Type, protoTypeDefault) - var rule_class string - suffix := "_cc_proto" - switch typ { - case "lite": - suffix += "_lite" - rule_class = "cc_lite_proto_library" - depName = "libprotobuf-cpp-lite" - case "full": - rule_class = "cc_proto_library" - depName = "libprotobuf-cpp-full" - default: - ctx.PropertyErrorf("proto.type", "cannot handle conversion at this time: %q", typ) - } - - dep := android.BazelLabelForModuleDepSingle(ctx, depName) - ret.protoDep = &bazel.LabelAttribute{Value: &dep} - - var protoAttrs protoAttributes - protoAttrs.Deps.SetValue(protoInfo.Proto_libs) - protoAttrs.Min_sdk_version = m.Properties.Min_sdk_version - - name := m.Name() + suffix - tags := android.ApexAvailableTags(m) - ctx.CreateBazelTargetModule( - bazel.BazelTargetModuleProperties{ - Rule_class: rule_class, - Bzl_load_location: "//build/bazel/rules/cc:cc_proto.bzl", - }, - android.CommonAttributes{Name: name, Tags: tags}, - &protoAttrs) - - var privateHdrs bool - if lib, ok := m.linker.(*libraryDecorator); ok { - privateHdrs = !proptools.Bool(lib.Properties.Proto.Export_proto_headers) - } - - labelAttr := &bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + name}} - if privateHdrs { - ret.implementationWholeStaticLib = labelAttr - } else { - ret.wholeStaticLib = labelAttr - } - - return ret -} @@ -15,11 +15,11 @@ package cc import ( - "android/soong/android" "path/filepath" "runtime" "strings" + "android/soong/android" "github.com/google/blueprint" ) @@ -100,11 +100,12 @@ func rsGenerateCpp(ctx android.ModuleContext, rsFiles android.Paths, rsFlags str func rsFlags(ctx ModuleContext, flags Flags, properties *BaseCompilerProperties) Flags { targetApi := String(properties.Renderscript.Target_api) if targetApi == "" && ctx.useSdk() { - switch ctx.sdkVersion() { - case "current", "system_current", "test_current": - // Nothing - default: - targetApi = android.GetNumericSdkVersion(ctx.sdkVersion()) + targetApiLevel := android.ApiLevelOrPanic(ctx, ctx.sdkVersion()) + if targetApiLevel.IsCurrent() || targetApiLevel.IsPreview() { + // If the target level is current or preview, leave the 'target-api' unset. + // This signals to llvm-rs-cc that the development API should be used. + } else { + targetApi = targetApiLevel.String() } } diff --git a/cc/sabi.go b/cc/sabi.go index 4cd776a25..64eab4160 100644 --- a/cc/sabi.go +++ b/cc/sabi.go @@ -26,6 +26,28 @@ var ( lsdumpPathsLock sync.Mutex ) +type lsdumpTag string + +const ( + apexLsdumpTag lsdumpTag = "APEX" + llndkLsdumpTag lsdumpTag = "LLNDK" + platformLsdumpTag lsdumpTag = "PLATFORM" + productLsdumpTag lsdumpTag = "PRODUCT" + vendorLsdumpTag lsdumpTag = "VENDOR" +) + +// Return the prebuilt ABI dump directory for a tag; an empty string for an opt-in dump. +func (tag *lsdumpTag) dirName() string { + switch *tag { + case apexLsdumpTag: + return "platform" + case llndkLsdumpTag: + return "vndk" + default: + return "" + } +} + // Properties for ABI compatibility checker in Android.bp. type headerAbiCheckerProperties struct { // Enable ABI checks (even if this is not an LLNDK/VNDK lib) @@ -68,7 +90,8 @@ type SAbiProperties struct { // Include directories that may contain ABI information exported by a library. // These directories are passed to the header-abi-dumper. - ReexportedIncludes []string `blueprint:"mutated"` + ReexportedIncludes []string `blueprint:"mutated"` + ReexportedSystemIncludes []string `blueprint:"mutated"` } type sabi struct { @@ -97,49 +120,33 @@ func (sabi *sabi) shouldCreateSourceAbiDump() bool { return sabi != nil && sabi.Properties.ShouldCreateSourceAbiDump } -// Returns a string that represents the class of the ABI dump. -// Returns an empty string if ABI check is disabled for this library. -func classifySourceAbiDump(ctx android.BaseModuleContext) string { +// Returns a slice of strings that represent the ABI dumps generated for this module. +func classifySourceAbiDump(ctx android.BaseModuleContext) []lsdumpTag { + result := []lsdumpTag{} m := ctx.Module().(*Module) headerAbiChecker := m.library.getHeaderAbiCheckerProperties(ctx) if headerAbiChecker.explicitlyDisabled() { - return "" + return result } - // Return NDK if the library is both NDK and LLNDK. - if m.IsNdk(ctx.Config()) { - return "NDK" - } - if m.isImplementationForLLNDKPublic() { - return "LLNDK" - } - if m.UseVndk() && m.IsVndk() && !m.IsVndkPrivate() { - if m.IsVndkSp() { - if m.IsVndkExt() { - return "VNDK-SP-ext" - } else { - return "VNDK-SP" - } - } else { - if m.IsVndkExt() { - return "VNDK-ext" - } else { - return "VNDK-core" - } + if !m.InProduct() && !m.InVendor() { + if m.isImplementationForLLNDKPublic() { + result = append(result, llndkLsdumpTag) } - } - if m.library.hasStubsVariants() && !m.InProduct() && !m.InVendor() { - return "PLATFORM" - } - if headerAbiChecker.enabled() { + if m.library.hasStubsVariants() { + result = append(result, apexLsdumpTag) + } + if headerAbiChecker.enabled() { + result = append(result, platformLsdumpTag) + } + } else if headerAbiChecker.enabled() { if m.InProduct() { - return "PRODUCT" + result = append(result, productLsdumpTag) } if m.InVendor() { - return "VENDOR" + result = append(result, vendorLsdumpTag) } - return "PLATFORM" } - return "" + return result } // Called from sabiDepsMutator to check whether ABI dumps should be created for this module. @@ -194,8 +201,8 @@ func shouldCreateSourceAbiDumpForLibrary(ctx android.BaseModuleContext) bool { return false } - isPlatformVariant := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() - if isPlatformVariant { + apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) + if apexInfo.IsForPlatform() { // Bionic libraries that are installed to the bootstrap directory are not ABI checked. // Only the runtime APEX variants, which are the implementation libraries of bionic NDK stubs, // are checked. @@ -208,7 +215,7 @@ func shouldCreateSourceAbiDumpForLibrary(ctx android.BaseModuleContext) bool { return false } } - return classifySourceAbiDump(ctx) != "" + return len(classifySourceAbiDump(ctx)) > 0 } // Mark the direct and transitive dependencies of libraries that need ABI check, so that ABI dumps diff --git a/cc/sanitize.go b/cc/sanitize.go index 7fddc1b83..64a313bc2 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -25,7 +25,7 @@ import ( "android/soong/android" "android/soong/cc/config" - "android/soong/snapshot" + "android/soong/etc" ) var ( @@ -36,13 +36,12 @@ var ( asanCflags = []string{ "-fno-omit-frame-pointer", } - asanLdflags = []string{"-Wl,-u,__asan_preinit"} + // DO NOT ADD MLLVM FLAGS HERE! ADD THEM BELOW TO hwasanCommonFlags. hwasanCflags = []string{ "-fno-omit-frame-pointer", "-Wno-frame-larger-than=", "-fsanitize-hwaddress-abi=platform", - "-mllvm", "-hwasan-use-after-scope=1", } // ThinLTO performs codegen during link time, thus these flags need to @@ -56,21 +55,21 @@ var ( // higher number of "optimized out" stack variables. // b/112437883. "-instcombine-lower-dbg-declare=0", - // TODO(b/159343917): HWASan and GlobalISel don't play nicely, and - // GlobalISel is the default at -O0 on aarch64. - "--aarch64-enable-global-isel-at-O=-1", - "-fast-isel=false", + "-dom-tree-reachability-max-bbs-to-explore=128", } + sanitizeIgnorelistPrefix = "-fsanitize-ignorelist=" + cfiBlocklistPath = "external/compiler-rt/lib/cfi" cfiBlocklistFilename = "cfi_blocklist.txt" + cfiEnableFlag = "-fsanitize=cfi" cfiCrossDsoFlag = "-fsanitize-cfi-cross-dso" cfiCflags = []string{"-flto", cfiCrossDsoFlag, - "-fsanitize-ignorelist=" + cfiBlocklistPath + "/" + cfiBlocklistFilename} + sanitizeIgnorelistPrefix + cfiBlocklistPath + "/" + cfiBlocklistFilename} // -flto and -fvisibility are required by clang when -fsanitize=cfi is // used, but have no effect on assembly files cfiAsflags = []string{"-flto", "-fvisibility=default"} - cfiLdflags = []string{"-flto", cfiCrossDsoFlag, "-fsanitize=cfi", + cfiLdflags = []string{"-flto", cfiCrossDsoFlag, cfiEnableFlag, "-Wl,-plugin-opt,O1"} cfiExportsMapPath = "build/soong/cc/config" cfiExportsMapFilename = "cfi_exports.map" @@ -82,10 +81,13 @@ var ( "-fno-sanitize-recover=integer,undefined"} hwasanGlobalOptions = []string{"heap_history_size=1023", "stack_history_size=512", "export_memory_stats=0", "max_malloc_fill_size=131072", "malloc_fill_byte=0"} - memtagStackCommonFlags = []string{"-march=armv8-a+memtag", "-mllvm", "-dom-tree-reachability-max-bbs-to-explore=128"} + memtagStackCommonFlags = []string{"-march=armv8-a+memtag"} + memtagStackLlvmFlags = []string{"-dom-tree-reachability-max-bbs-to-explore=128"} hostOnlySanitizeFlags = []string{"-fno-sanitize-recover=all"} - deviceOnlySanitizeFlags = []string{"-fsanitize-trap=all", "-ftrap-function=abort"} + deviceOnlySanitizeFlags = []string{"-fsanitize-trap=all"} + + noSanitizeLinkRuntimeFlag = "-fno-sanitize-link-runtime" ) type SanitizerType int @@ -99,6 +101,7 @@ const ( Fuzzer Memtag_heap Memtag_stack + Memtag_globals cfi // cfi is last to prevent it running before incompatible mutators ) @@ -111,6 +114,7 @@ var Sanitizers = []SanitizerType{ Fuzzer, Memtag_heap, Memtag_stack, + Memtag_globals, cfi, // cfi is last to prevent it running before incompatible mutators } @@ -133,6 +137,8 @@ func (t SanitizerType) variationName() string { return "memtag_heap" case Memtag_stack: return "memtag_stack" + case Memtag_globals: + return "memtag_globals" case Fuzzer: return "fuzzer" default: @@ -151,6 +157,8 @@ func (t SanitizerType) name() string { return "memtag_heap" case Memtag_stack: return "memtag_stack" + case Memtag_globals: + return "memtag_globals" case tsan: return "thread" case intOverflow: @@ -168,11 +176,11 @@ func (t SanitizerType) name() string { func (t SanitizerType) registerMutators(ctx android.RegisterMutatorsContext) { switch t { - case cfi, Hwasan, Asan, tsan, Fuzzer, scs: + case cfi, Hwasan, Asan, tsan, Fuzzer, scs, Memtag_stack: sanitizer := &sanitizerSplitMutator{t} ctx.TopDown(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator) ctx.Transition(t.variationName(), sanitizer) - case Memtag_heap, Memtag_stack, intOverflow: + case Memtag_heap, Memtag_globals, intOverflow: // do nothing default: panic(fmt.Errorf("unknown SanitizerType %d", t)) @@ -213,6 +221,8 @@ func (*Module) SanitizerSupported(t SanitizerType) bool { return true case Memtag_stack: return true + case Memtag_globals: + return true default: return false } @@ -267,6 +277,9 @@ type SanitizeUserProps struct { // Memory-tagging stack instrumentation, only available on arm64 // Adds instrumentation to detect stack buffer overflows and use-after-scope using MTE. Memtag_stack *bool `android:"arch_variant"` + // Memory-tagging globals instrumentation, only available on arm64 + // Adds instrumentation to detect global buffer overflows using MTE. + Memtag_globals *bool `android:"arch_variant"` // A modifier for ASAN and HWASAN for write only instrumentation Writeonly *bool `android:"arch_variant"` @@ -342,6 +355,8 @@ type sanitizeMutatedProperties struct { Memtag_heap *bool `blueprint:"mutated"` // Whether Memory-tagging stack instrumentation is enabled for this module Memtag_stack *bool `blueprint:"mutated"` + // Whether Memory-tagging globals instrumentation is enabled for this module + Memtag_globals *bool `android:"arch_variant"` // Whether a modifier for ASAN and HWASAN for write only instrumentation is enabled for this // module @@ -367,7 +382,19 @@ type SanitizeProperties struct { Sanitize SanitizeUserProps `android:"arch_variant"` SanitizeMutated sanitizeMutatedProperties `blueprint:"mutated"` - SanitizerEnabled bool `blueprint:"mutated"` + // ForceDisable is set by the version mutator to disable sanitization of stubs variants + ForceDisable bool `blueprint:"mutated"` + + // SanitizerEnabled is set by begin() if any of the sanitize boolean properties are set after + // applying the logic that enables globally enabled sanitizers and disables any unsupported + // sanitizers. + // TODO(b/349906293): this has some unintuitive behavior. It is set in begin() before the sanitize + // mutator is run if any of the individual sanitizes properties are set, and then the individual + // sanitize properties are cleared in the non-sanitized variants, but this value is never cleared. + // That results in SanitizerEnabled being set in variants that have no sanitizers enabled, causing + // some of the sanitizer logic in flags() to be applied to the non-sanitized variant. + SanitizerEnabled bool `blueprint:"mutated"` + MinimalRuntimeDep bool `blueprint:"mutated"` BuiltinsDep bool `blueprint:"mutated"` UbsanRuntimeDep bool `blueprint:"mutated"` @@ -387,28 +414,14 @@ func (t libraryDependencyTag) SkipApexAllowedDependenciesCheck() bool { var _ android.SkipApexAllowedDependenciesCheck = (*libraryDependencyTag)(nil) -var exportedVars = android.NewExportedVariables(pctx) - func init() { - exportedVars.ExportStringListStaticVariable("HostOnlySanitizeFlags", hostOnlySanitizeFlags) - exportedVars.ExportStringList("DeviceOnlySanitizeFlags", deviceOnlySanitizeFlags) - - // Leave out "-flto" from the slices exported to bazel, as we will use the - // dedicated LTO feature for this. For C Flags and Linker Flags, also leave - // out the cross DSO flag which will be added separately by transitions. - exportedVars.ExportStringList("CfiCFlags", cfiCflags[2:]) - exportedVars.ExportStringList("CfiLdFlags", cfiLdflags[2:]) - exportedVars.ExportStringList("CfiAsFlags", cfiAsflags[1:]) - - exportedVars.ExportString("CfiCrossDsoFlag", cfiCrossDsoFlag) - exportedVars.ExportString("CfiBlocklistPath", cfiBlocklistPath) - exportedVars.ExportString("CfiBlocklistFilename", cfiBlocklistFilename) - exportedVars.ExportString("CfiExportsMapPath", cfiExportsMapPath) - exportedVars.ExportString("CfiExportsMapFilename", cfiExportsMapFilename) - exportedVars.ExportString("CfiAssemblySupportFlag", cfiAssemblySupportFlag) + pctx.StaticVariable("HostOnlySanitizeFlags", strings.Join(hostOnlySanitizeFlags, " ")) android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider) android.RegisterMakeVarsProvider(pctx, hwasanMakeVarsProvider) + android.RegisterMakeVarsProvider(pctx, memtagStackMakeVarsProvider) + + RegisterSanitizerLibrariesTxtType(android.InitRegistrationContext) } func (sanitize *sanitize) props() []interface{} { @@ -425,6 +438,7 @@ func (p *sanitizeMutatedProperties) copyUserPropertiesToMutated(userProps *Sanit p.Integer_overflow = userProps.Integer_overflow p.Memtag_heap = userProps.Memtag_heap p.Memtag_stack = userProps.Memtag_stack + p.Memtag_globals = userProps.Memtag_globals p.Safestack = userProps.Safestack p.Scs = userProps.Scs p.Scudo = userProps.Scudo @@ -452,6 +466,10 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s := &sanitize.Properties.SanitizeMutated s.copyUserPropertiesToMutated(&sanitize.Properties.Sanitize) + if sanitize.Properties.ForceDisable { + return + } + // Don't apply sanitizers to NDK code. if ctx.useSdk() { s.Never = BoolPtr(true) @@ -531,7 +549,9 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { } if found, globalSanitizers = removeFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil { - s.Hwaddress = proptools.BoolPtr(true) + if !ctx.Config().HWASanDisabledForPath(ctx.ModuleDir()) { + s.Hwaddress = proptools.BoolPtr(true) + } } if found, globalSanitizers = removeFromList("writeonly", globalSanitizers); found && s.Writeonly == nil { @@ -552,6 +572,10 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s.Memtag_stack = proptools.BoolPtr(true) } + if found, globalSanitizers = removeFromList("memtag_globals", globalSanitizers); found && s.Memtag_globals == nil { + s.Memtag_globals = proptools.BoolPtr(true) + } + if len(globalSanitizers) > 0 { ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0]) } @@ -622,16 +646,13 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { if (ctx.Arch().ArchType != android.Arm64 && ctx.Arch().ArchType != android.Riscv64) || !ctx.toolchain().Bionic() { s.Scs = nil } - // ...but temporarily globally disabled on riscv64 (http://b/277909695). - if ctx.Arch().ArchType == android.Riscv64 { - s.Scs = nil - } // Memtag_heap is only implemented on AArch64. // Memtag ABI is Android specific for now, so disable for host. if ctx.Arch().ArchType != android.Arm64 || !ctx.toolchain().Bionic() || ctx.Host() { s.Memtag_heap = nil s.Memtag_stack = nil + s.Memtag_globals = nil } // Also disable CFI if ASAN is enabled. @@ -641,6 +662,7 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { // HWASAN and ASAN win against MTE. s.Memtag_heap = nil s.Memtag_stack = nil + s.Memtag_globals = nil } // Disable sanitizers that depend on the UBSan runtime for windows/darwin builds. @@ -653,28 +675,35 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s.Integer_overflow = nil } - // TODO(b/254713216): CFI doesn't work for riscv64 yet because LTO doesn't work. - if ctx.Arch().ArchType == android.Riscv64 { - s.Cfi = nil - s.Diag.Cfi = nil - } - // Disable CFI for musl if ctx.toolchain().Musl() { s.Cfi = nil s.Diag.Cfi = nil } - // Also disable CFI for VNDK variants of components - if ctx.isVndk() && ctx.useVndk() { + // TODO(b/280478629): runtimes don't exist for musl arm64 yet. + if ctx.toolchain().Musl() && ctx.Arch().ArchType == android.Arm64 { + s.Address = nil + s.Hwaddress = nil + s.Thread = nil + s.Scudo = nil + s.Fuzzer = nil s.Cfi = nil s.Diag.Cfi = nil + s.Misc_undefined = nil + s.Undefined = nil + s.All_undefined = nil + s.Integer_overflow = nil } - // HWASan ramdisk (which is built from recovery) goes over some bootloader limit. - // Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary. - if (ctx.inRamdisk() || ctx.inVendorRamdisk() || ctx.inRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") { - s.Hwaddress = nil + if ctx.inRamdisk() || ctx.inVendorRamdisk() || ctx.inRecovery() { + // HWASan ramdisk (which is built from recovery) goes over some bootloader limit. + // Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary. + if !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") { + s.Hwaddress = nil + } + // Memtag stack in ramdisk makes pKVM unhappy. + s.Memtag_stack = nil } if ctx.staticBinary() { @@ -696,7 +725,8 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { if ctx.Os() != android.Windows && (Bool(s.All_undefined) || Bool(s.Undefined) || Bool(s.Address) || Bool(s.Thread) || Bool(s.Fuzzer) || Bool(s.Safestack) || Bool(s.Cfi) || Bool(s.Integer_overflow) || len(s.Misc_undefined) > 0 || - Bool(s.Scudo) || Bool(s.Hwaddress) || Bool(s.Scs) || Bool(s.Memtag_heap) || Bool(s.Memtag_stack)) { + Bool(s.Scudo) || Bool(s.Hwaddress) || Bool(s.Scs) || Bool(s.Memtag_heap) || Bool(s.Memtag_stack) || + Bool(s.Memtag_globals)) { sanitize.Properties.SanitizerEnabled = true } @@ -750,6 +780,10 @@ func toDisableUnsignedShiftBaseChange(flags []string) bool { } func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags { + if s.Properties.ForceDisable { + return flags + } + if !s.Properties.SanitizerEnabled && !s.Properties.UbsanRuntimeDep { return flags } @@ -762,16 +796,17 @@ func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags { flags.RequiredInstructionSet = "arm" } flags.Local.CFlags = append(flags.Local.CFlags, asanCflags...) - flags.Local.LdFlags = append(flags.Local.LdFlags, asanLdflags...) if Bool(sanProps.Writeonly) { flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-instrument-reads=0") } if ctx.Host() { - // -nodefaultlibs (provided with libc++) prevents the driver from linking - // libraries needed with -fsanitize=address. http://b/18650275 (WAI) - flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-as-needed") + if !ctx.Darwin() { // ld64.lld doesn't know about '--no-as-needed' + // -nodefaultlibs (provided with libc++) prevents the driver from linking + // libraries needed with -fsanitize=address. http://b/18650275 (WAI) + flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-as-needed") + } } else { flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-globals=0") if ctx.bootstrap() { @@ -845,6 +880,7 @@ func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags { flags.Local.CFlags = append(flags.Local.CFlags, cfiCflags...) flags.Local.AsFlags = append(flags.Local.AsFlags, cfiAsflags...) + flags.CFlagsDeps = append(flags.CFlagsDeps, android.PathForSource(ctx, cfiBlocklistPath+"/"+cfiBlocklistFilename)) if Bool(s.Properties.Sanitize.Config.Cfi_assembly_support) { flags.Local.CFlags = append(flags.Local.CFlags, cfiAssemblySupportFlag) } @@ -863,16 +899,18 @@ func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags { if Bool(sanProps.Memtag_stack) { flags.Local.CFlags = append(flags.Local.CFlags, memtagStackCommonFlags...) - // TODO(fmayer): remove -Wno-error once https://reviews.llvm.org/D127917 is in Android toolchain. - flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-error=frame-larger-than") flags.Local.AsFlags = append(flags.Local.AsFlags, memtagStackCommonFlags...) flags.Local.LdFlags = append(flags.Local.LdFlags, memtagStackCommonFlags...) - // This works around LLD complaining about the stack frame size. - // TODO(fmayer): remove once https://reviews.llvm.org/D127917 is in Android toolchain. - flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-fatal-warnings") + + for _, flag := range memtagStackLlvmFlags { + flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", flag) + } + for _, flag := range memtagStackLlvmFlags { + flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,"+flag) + } } - if (Bool(sanProps.Memtag_heap) || Bool(sanProps.Memtag_stack)) && ctx.binary() { + if (Bool(sanProps.Memtag_heap) || Bool(sanProps.Memtag_stack) || Bool(sanProps.Memtag_globals)) && ctx.binary() { if Bool(sanProps.Diag.Memtag_heap) { flags.Local.LdFlags = append(flags.Local.LdFlags, "-fsanitize-memtag-mode=sync") } else { @@ -894,7 +932,7 @@ func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags { // Bionic and musl sanitizer runtimes have already been added as dependencies so that // the right variant of the runtime will be used (with the "-android" or "-musl" // suffixes), so don't let clang the runtime library. - flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-sanitize-link-runtime") + flags.Local.LdFlags = append(flags.Local.LdFlags, noSanitizeLinkRuntimeFlag) } else { // Host sanitizers only link symbols in the final executable, so // there will always be undefined symbols in intermediate libraries. @@ -949,7 +987,7 @@ func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags { blocklist := android.OptionalPathForModuleSrc(ctx, s.Properties.Sanitize.Blocklist) if blocklist.Valid() { - flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-ignorelist="+blocklist.String()) + flags.Local.CFlags = append(flags.Local.CFlags, sanitizeIgnorelistPrefix+blocklist.String()) flags.CFlagsDeps = append(flags.CFlagsDeps, blocklist.Path()) } @@ -995,6 +1033,8 @@ func (s *sanitize) getSanitizerBoolPtr(t SanitizerType) *bool { return s.Properties.SanitizeMutated.Memtag_heap case Memtag_stack: return s.Properties.SanitizeMutated.Memtag_stack + case Memtag_globals: + return s.Properties.SanitizeMutated.Memtag_globals case Fuzzer: return s.Properties.SanitizeMutated.Fuzzer default: @@ -1011,6 +1051,7 @@ func (sanitize *sanitize) isUnsanitizedVariant() bool { !sanitize.isSanitizerEnabled(scs) && !sanitize.isSanitizerEnabled(Memtag_heap) && !sanitize.isSanitizerEnabled(Memtag_stack) && + !sanitize.isSanitizerEnabled(Memtag_globals) && !sanitize.isSanitizerEnabled(Fuzzer) } @@ -1032,10 +1073,12 @@ func (sanitize *sanitize) SetSanitizer(t SanitizerType, b bool) { sanitize.Properties.SanitizeMutated.Address = bPtr // For ASAN variant, we need to disable Memtag_stack sanitize.Properties.SanitizeMutated.Memtag_stack = nil + sanitize.Properties.SanitizeMutated.Memtag_globals = nil case Hwasan: sanitize.Properties.SanitizeMutated.Hwaddress = bPtr // For HWAsan variant, we need to disable Memtag_stack sanitize.Properties.SanitizeMutated.Memtag_stack = nil + sanitize.Properties.SanitizeMutated.Memtag_globals = nil case tsan: sanitize.Properties.SanitizeMutated.Thread = bPtr case intOverflow: @@ -1049,6 +1092,8 @@ func (sanitize *sanitize) SetSanitizer(t SanitizerType, b bool) { case Memtag_stack: sanitize.Properties.SanitizeMutated.Memtag_stack = bPtr // We do not need to disable ASAN or HWASan here, as there is no Memtag_stack variant. + case Memtag_globals: + sanitize.Properties.Sanitize.Memtag_globals = bPtr case Fuzzer: sanitize.Properties.SanitizeMutated.Fuzzer = bPtr default: @@ -1075,12 +1120,15 @@ func (sanitize *sanitize) isSanitizerExplicitlyDisabled(t SanitizerType) bool { // indirectly (via a mutator) sets the bool ptr to true, and you can't // distinguish between the cases. It isn't needed though - both cases can be // treated identically. -func (sanitize *sanitize) isSanitizerEnabled(t SanitizerType) bool { - if sanitize == nil { +func (s *sanitize) isSanitizerEnabled(t SanitizerType) bool { + if s == nil { + return false + } + if s.Properties.ForceDisable || proptools.Bool(s.Properties.SanitizeMutated.Never) { return false } - sanitizerVal := sanitize.getSanitizerBoolPtr(t) + sanitizerVal := s.getSanitizerBoolPtr(t) return sanitizerVal != nil && *sanitizerVal == true } @@ -1100,42 +1148,6 @@ func (m *Module) SanitizableDepTagChecker() SantizableDependencyTagChecker { return IsSanitizableDependencyTag } -// Determines if the current module is a static library going to be captured -// as vendor snapshot. Such modules must create both cfi and non-cfi variants, -// except for ones which explicitly disable cfi. -func needsCfiForVendorSnapshot(mctx android.BaseModuleContext) bool { - if inList("hwaddress", mctx.Config().SanitizeDevice()) { - // cfi will not be built if SANITIZE_TARGET=hwaddress is set - return false - } - - if snapshot.IsVendorProprietaryModule(mctx) { - return false - } - - c := mctx.Module().(PlatformSanitizeable) - - if !c.InVendor() { - return false - } - - if !c.StaticallyLinked() { - return false - } - - if c.IsPrebuilt() { - return false - } - - if !c.SanitizerSupported(cfi) { - return false - } - - return c.SanitizePropDefined() && - !c.SanitizeNever() && - !c.IsSanitizerExplicitlyDisabled(cfi) -} - type sanitizerSplitMutator struct { sanitizer SanitizerType } @@ -1147,7 +1159,7 @@ func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.TopDown if sanitizeable, ok := ctx.Module().(Sanitizeable); ok { enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name()) ctx.VisitDirectDeps(func(dep android.Module) { - if c, ok := dep.(*Module); ok && c.sanitize.isSanitizerEnabled(s.sanitizer) { + if c, ok := dep.(PlatformSanitizeable); ok && c.IsSanitizerEnabled(s.sanitizer) { enabled = true } }) @@ -1160,10 +1172,6 @@ func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.TopDown func (s *sanitizerSplitMutator) Split(ctx android.BaseModuleContext) []string { if c, ok := ctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() { - if s.sanitizer == cfi && needsCfiForVendorSnapshot(ctx) { - return []string{"", s.sanitizer.variationName()} - } - // If the given sanitizer is not requested in the .bp file for a module, it // won't automatically build the sanitized variation. if !c.IsSanitizerEnabled(s.sanitizer) { @@ -1201,19 +1209,6 @@ func (s *sanitizerSplitMutator) Split(ctx android.BaseModuleContext) []string { } } - if c, ok := ctx.Module().(*Module); ok { - //TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable - - // Check if it's a snapshot module supporting sanitizer - if ss, ok := c.linker.(snapshotSanitizer); ok { - if ss.isSanitizerAvailable(s.sanitizer) { - return []string{"", s.sanitizer.variationName()} - } else { - return []string{""} - } - } - } - return []string{""} } @@ -1238,12 +1233,6 @@ func (s *sanitizerSplitMutator) OutgoingTransition(ctx android.OutgoingTransitio func (s *sanitizerSplitMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { if d, ok := ctx.Module().(PlatformSanitizeable); ok { - if dm, ok := ctx.Module().(*Module); ok { - if ss, ok := dm.linker.(snapshotSanitizer); ok && ss.isSanitizerAvailable(s.sanitizer) { - return incomingVariation - } - } - if !d.SanitizePropDefined() || d.SanitizeNever() || d.IsSanitizerExplicitlyDisabled(s.sanitizer) || @@ -1343,6 +1332,8 @@ func (s *sanitizerSplitMutator) Mutate(mctx android.BottomUpMutatorContext, vari hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name()) } else if s.sanitizer == cfi { cfiStaticLibs(mctx.Config()).add(c, c.Module().Name()) + } else if s.sanitizer == Memtag_stack { + memtagStackStaticLibs(mctx.Config()).add(c, c.Module().Name()) } } } else if c.IsSanitizerEnabled(s.sanitizer) { @@ -1354,32 +1345,11 @@ func (s *sanitizerSplitMutator) Mutate(mctx android.BottomUpMutatorContext, vari if sanitizerVariation { sanitizeable.AddSanitizerDependencies(mctx, s.sanitizer.name()) } - } else if c, ok := mctx.Module().(*Module); ok { - if ss, ok := c.linker.(snapshotSanitizer); ok && ss.isSanitizerAvailable(s.sanitizer) { - if !ss.isUnsanitizedVariant() { - // Snapshot sanitizer may have only one variantion. - // Skip exporting the module if it already has a sanitizer variation. - c.SetPreventInstall() - c.SetHideFromMake() - return - } - c.linker.(snapshotSanitizer).setSanitizerVariation(s.sanitizer, sanitizerVariation) - - // Export the static lib name to make - if c.static() && c.ExportedToMake() { - // use BaseModuleName which is the name for Make. - if s.sanitizer == cfi { - cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName()) - } else if s.sanitizer == Hwasan { - hwasanStaticLibs(mctx.Config()).add(c, c.BaseModuleName()) - } - } - } } } func (c *Module) SanitizeNever() bool { - return Bool(c.sanitize.Properties.SanitizeMutated.Never) + return c.sanitize.Properties.ForceDisable || Bool(c.sanitize.Properties.SanitizeMutated.Never) } func (c *Module) IsSanitizerExplicitlyDisabled(t SanitizerType) bool { @@ -1390,6 +1360,9 @@ func (c *Module) IsSanitizerExplicitlyDisabled(t SanitizerType) bool { func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) { // Change this to PlatformSanitizable when/if non-cc modules support ubsan sanitizers. if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil { + if c.sanitize.Properties.ForceDisable { + return + } isSanitizableDependencyTag := c.SanitizableDepTagChecker() mctx.WalkDeps(func(child, parent android.Module) bool { if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) { @@ -1400,7 +1373,7 @@ func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) { if !ok || !d.static() { return false } - if d.sanitize != nil { + if d.sanitize != nil && !d.sanitize.Properties.ForceDisable { if enableMinimalRuntime(d.sanitize) { // If a static dependency is built with the minimal runtime, // make sure we include the ubsan minimal runtime. @@ -1424,15 +1397,6 @@ func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) { return true } - if p, ok := d.linker.(*snapshotLibraryDecorator); ok { - if Bool(p.properties.Sanitize_minimal_dep) { - c.sanitize.Properties.MinimalRuntimeDep = true - } - if Bool(p.properties.Sanitize_ubsan_dep) { - c.sanitize.Properties.UbsanRuntimeDep = true - } - } - return false }) } @@ -1441,9 +1405,13 @@ func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) { // Add the dependency to the runtime library for each of the sanitizer variants func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil { - if !c.Enabled() { + if !c.Enabled(mctx) { + return + } + if c.sanitize.Properties.ForceDisable { return } + var sanitizers []string var diagSanitizers []string @@ -1536,6 +1504,13 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { sanitizers = append(sanitizers, "memtag-stack") } + if Bool(sanProps.Memtag_globals) { + sanitizers = append(sanitizers, "memtag-globals") + // TODO(mitchp): For now, enable memtag-heap with memtag-globals because the linker + // isn't new enough (https://reviews.llvm.org/differential/changeset/?ref=4243566). + sanitizers = append(sanitizers, "memtag-heap") + } + if Bool(sanProps.Fuzzer) { sanitizers = append(sanitizers, "fuzzer-no-link") } @@ -1551,12 +1526,6 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { } addStaticDeps := func(dep string, hideSymbols bool) { - // If we're using snapshots, redirect to snapshot whenever possible - snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo) - if lib, ok := snapshot.StaticLibs[dep]; ok { - dep = lib - } - // static executable gets static runtime libs depTag := libraryDependencyTag{Kind: staticLibraryDependency, unexportedSymbols: hideSymbols} variations := append(mctx.Target().Variations(), @@ -1577,51 +1546,51 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { if Bool(sanProps.Address) { if toolchain.Musl() || (c.staticBinary() && toolchain.Bionic()) { // Use a static runtime for musl to match what clang does for glibc. - addStaticDeps(config.AddressSanitizerStaticRuntimeLibrary(toolchain), false) - addStaticDeps(config.AddressSanitizerCXXStaticRuntimeLibrary(toolchain), false) + addStaticDeps(config.AddressSanitizerStaticRuntimeLibrary(), false) + addStaticDeps(config.AddressSanitizerCXXStaticRuntimeLibrary(), false) } else { - runtimeSharedLibrary = config.AddressSanitizerRuntimeLibrary(toolchain) + runtimeSharedLibrary = config.AddressSanitizerRuntimeLibrary() } } else if Bool(sanProps.Hwaddress) { if c.staticBinary() { - addStaticDeps(config.HWAddressSanitizerStaticLibrary(toolchain), true) + addStaticDeps(config.HWAddressSanitizerStaticLibrary(), true) addStaticDeps("libdl", false) } else { - runtimeSharedLibrary = config.HWAddressSanitizerRuntimeLibrary(toolchain) + runtimeSharedLibrary = config.HWAddressSanitizerRuntimeLibrary() } } else if Bool(sanProps.Thread) { - runtimeSharedLibrary = config.ThreadSanitizerRuntimeLibrary(toolchain) + runtimeSharedLibrary = config.ThreadSanitizerRuntimeLibrary() } else if Bool(sanProps.Scudo) { if len(diagSanitizers) == 0 && !c.sanitize.Properties.UbsanRuntimeDep { - runtimeSharedLibrary = config.ScudoMinimalRuntimeLibrary(toolchain) + runtimeSharedLibrary = config.ScudoMinimalRuntimeLibrary() } else { - runtimeSharedLibrary = config.ScudoRuntimeLibrary(toolchain) + runtimeSharedLibrary = config.ScudoRuntimeLibrary() } } else if len(diagSanitizers) > 0 || c.sanitize.Properties.UbsanRuntimeDep || Bool(sanProps.Fuzzer) || Bool(sanProps.Undefined) || Bool(sanProps.All_undefined) { - if toolchain.Musl() || (c.staticBinary() && toolchain.Bionic()) { - // Use a static runtime for static binaries. - // Also use a static runtime for musl to match - // what clang does for glibc. Otherwise dlopening - // libraries that depend on libclang_rt.ubsan_standalone.so - // fails with: + if toolchain.Musl() || c.staticBinary() { + // Use a static runtime for static binaries. For sanitized glibc binaries the runtime is + // added automatically by clang, but for static glibc binaries that are not sanitized but + // have a sanitized dependency the runtime needs to be added manually. + // Also manually add a static runtime for musl to match what clang does for glibc. + // Otherwise dlopening libraries that depend on libclang_rt.ubsan_standalone.so fails with: // Error relocating ...: initial-exec TLS resolves to dynamic definition - addStaticDeps(config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain)+".static", true) + addStaticDeps(config.UndefinedBehaviorSanitizerRuntimeLibrary()+".static", true) } else { - runtimeSharedLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain) + runtimeSharedLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary() } } if enableMinimalRuntime(c.sanitize) || c.sanitize.Properties.MinimalRuntimeDep { - addStaticDeps(config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(toolchain), true) + addStaticDeps(config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(), true) } if c.sanitize.Properties.BuiltinsDep { - addStaticDeps(config.BuiltinsRuntimeLibrary(toolchain), true) + addStaticDeps(config.BuiltinsRuntimeLibrary(), true) } - if runtimeSharedLibrary != "" && (toolchain.Bionic() || toolchain.Musl() || c.sanitize.Properties.UbsanRuntimeDep) { + if runtimeSharedLibrary != "" && (toolchain.Bionic() || toolchain.Musl()) { // UBSan is supported on non-bionic linux host builds as well // Adding dependency to the runtime library. We are using *FarVariation* @@ -1638,12 +1607,6 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { // the best. addStaticDeps(runtimeSharedLibrary, true) } else if !c.static() && !c.Header() { - // If we're using snapshots, redirect to snapshot whenever possible - snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo) - if lib, ok := snapshot.SharedLibs[runtimeSharedLibrary]; ok { - runtimeSharedLibrary = lib - } - // Skip apex dependency check for sharedLibraryDependency // when sanitizer diags are enabled. Skipping the check will allow // building with diag libraries without having to list the @@ -1790,6 +1753,14 @@ func hwasanStaticLibs(config android.Config) *sanitizerStaticLibsMap { }).(*sanitizerStaticLibsMap) } +var memtagStackStaticLibsKey = android.NewOnceKey("memtagStackStaticLibs") + +func memtagStackStaticLibs(config android.Config) *sanitizerStaticLibsMap { + return config.Once(memtagStackStaticLibsKey, func() interface{} { + return newSanitizerStaticLibsMap(Memtag_stack) + }).(*sanitizerStaticLibsMap) +} + func enableMinimalRuntime(sanitize *sanitize) bool { if sanitize.isSanitizerEnabled(Asan) { return false @@ -1837,6 +1808,121 @@ func hwasanMakeVarsProvider(ctx android.MakeVarsContext) { hwasanStaticLibs(ctx.Config()).exportToMake(ctx) } -func BazelCcSanitizerToolchainVars(config android.Config) string { - return android.BazelToolchainVars(config, exportedVars) +func memtagStackMakeVarsProvider(ctx android.MakeVarsContext) { + memtagStackStaticLibs(ctx.Config()).exportToMake(ctx) +} + +type sanitizerLibrariesTxtModule struct { + android.ModuleBase + + outputFile android.OutputPath +} + +var _ etc.PrebuiltEtcModule = (*sanitizerLibrariesTxtModule)(nil) + +func RegisterSanitizerLibrariesTxtType(ctx android.RegistrationContext) { + ctx.RegisterModuleType("sanitizer_libraries_txt", sanitizerLibrariesTxtFactory) +} + +func sanitizerLibrariesTxtFactory() android.Module { + m := &sanitizerLibrariesTxtModule{} + android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) + return m +} + +type sanitizerLibraryDependencyTag struct { + blueprint.BaseDependencyTag +} + +func (t sanitizerLibraryDependencyTag) AllowDisabledModuleDependency(target android.Module) bool { + return true +} + +var _ android.AllowDisabledModuleDependency = (*sanitizerLibraryDependencyTag)(nil) + +func (txt *sanitizerLibrariesTxtModule) DepsMutator(actx android.BottomUpMutatorContext) { + targets := actx.Config().Targets[android.Android] + depTag := sanitizerLibraryDependencyTag{} + + for _, target := range targets { + variation := append(target.Variations(), + blueprint.Variation{Mutator: "image", Variation: ""}, + blueprint.Variation{Mutator: "sdk", Variation: ""}, + blueprint.Variation{Mutator: "link", Variation: "shared"}, + ) + for _, lib := range android.SortedStringValues(sanitizerVariables) { + if actx.OtherModuleFarDependencyVariantExists(variation, lib) { + actx.AddFarVariationDependencies(variation, depTag, lib) + } + + prebuiltLibName := "prebuilt_" + lib + if actx.OtherModuleFarDependencyVariantExists(variation, prebuiltLibName) { + actx.AddFarVariationDependencies(variation, depTag, prebuiltLibName) + } + } + } + +} + +func (txt *sanitizerLibrariesTxtModule) getSanitizerLibs(ctx android.ModuleContext) string { + var sanitizerLibStems []string + + ctx.VisitDirectDepsIf(func(m android.Module) bool { + if !m.Enabled(ctx) { + return false + } + + ccModule, _ := m.(*Module) + if ccModule == nil || ccModule.library == nil || !ccModule.library.shared() { + return false + } + + targets := ctx.Config().Targets[android.Android] + + for _, target := range targets { + if m.Target().Os == target.Os && m.Target().Arch.ArchType == target.Arch.ArchType { + return true + } + } + + return false + }, func(m android.Module) { + ccModule, _ := m.(*Module) + outputFile := ccModule.outputFile + if outputFile.Valid() { + sanitizerLibStems = append(sanitizerLibStems, outputFile.Path().Base()) + } + }) + + sanitizerLibStems = android.SortedUniqueStrings(sanitizerLibStems) + return strings.Join(sanitizerLibStems, "\n") +} + +func (txt *sanitizerLibrariesTxtModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + filename := txt.Name() + + txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath + android.WriteFileRule(ctx, txt.outputFile, txt.getSanitizerLibs(ctx)) + + installPath := android.PathForModuleInstall(ctx, "etc") + ctx.InstallFile(installPath, filename, txt.outputFile) + + ctx.SetOutputFiles(android.Paths{txt.outputFile}, "") +} + +func (txt *sanitizerLibrariesTxtModule) AndroidMkEntries() []android.AndroidMkEntries { + return []android.AndroidMkEntries{{ + Class: "ETC", + OutputFile: android.OptionalPathForPath(txt.outputFile), + }} +} + +// PrebuiltEtcModule interface +func (txt *sanitizerLibrariesTxtModule) BaseDir() string { + return "etc" +} + +// PrebuiltEtcModule interface +func (txt *sanitizerLibrariesTxtModule) SubDir() string { + return "" } diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go index 29b17d415..44f38e10a 100644 --- a/cc/sanitize_test.go +++ b/cc/sanitize_test.go @@ -16,13 +16,12 @@ package cc import ( "fmt" + "reflect" "runtime" "strings" "testing" "android/soong/android" - - "github.com/google/blueprint" ) var prepareForAsanTest = android.FixtureAddFile("asan/Android.bp", []byte(` @@ -48,7 +47,7 @@ var prepareForTsanTest = android.FixtureAddFile("tsan/Android.bp", []byte(` `)) type providerInterface interface { - ModuleProvider(blueprint.Module, blueprint.ProviderKey) interface{} + android.SingletonModuleProviderContext } // expectSharedLinkDep verifies that the from module links against the to module as a @@ -56,7 +55,7 @@ type providerInterface interface { func expectSharedLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) { t.Helper() fromLink := from.Description("link") - toInfo := ctx.ModuleProvider(to.Module(), SharedLibraryInfoProvider).(SharedLibraryInfo) + toInfo, _ := android.SingletonModuleProvider(ctx, to.Module(), SharedLibraryInfoProvider) if g, w := fromLink.OrderOnly.Strings(), toInfo.SharedLibrary.RelativeToTop().String(); !android.InList(w, g) { t.Errorf("%s should link against %s, expected %q, got %q", @@ -69,7 +68,7 @@ func expectSharedLinkDep(t *testing.T, ctx providerInterface, from, to android.T func expectNoSharedLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) { t.Helper() fromLink := from.Description("link") - toInfo := ctx.ModuleProvider(to.Module(), SharedLibraryInfoProvider).(SharedLibraryInfo) + toInfo, _ := android.SingletonModuleProvider(ctx, to.Module(), SharedLibraryInfoProvider) if g, w := fromLink.OrderOnly.Strings(), toInfo.SharedLibrary.RelativeToTop().String(); android.InList(w, g) { t.Errorf("%s should not link against %s, expected %q, got %q", @@ -82,7 +81,7 @@ func expectNoSharedLinkDep(t *testing.T, ctx providerInterface, from, to android func expectStaticLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) { t.Helper() fromLink := from.Description("link") - toInfo := ctx.ModuleProvider(to.Module(), StaticLibraryInfoProvider).(StaticLibraryInfo) + toInfo, _ := android.SingletonModuleProvider(ctx, to.Module(), StaticLibraryInfoProvider) if g, w := fromLink.Implicits.Strings(), toInfo.StaticLibrary.RelativeToTop().String(); !android.InList(w, g) { t.Errorf("%s should link against %s, expected %q, got %q", @@ -96,7 +95,7 @@ func expectStaticLinkDep(t *testing.T, ctx providerInterface, from, to android.T func expectNoStaticLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) { t.Helper() fromLink := from.Description("link") - toInfo := ctx.ModuleProvider(to.Module(), StaticLibraryInfoProvider).(StaticLibraryInfo) + toInfo, _ := android.SingletonModuleProvider(ctx, to.Module(), StaticLibraryInfoProvider) if g, w := fromLink.Implicits.Strings(), toInfo.StaticLibrary.RelativeToTop().String(); android.InList(w, g) { t.Errorf("%s should not link against %s, expected %q, got %q", @@ -714,6 +713,15 @@ func TestUbsan(t *testing.T) { ], } + cc_binary { + name: "static_bin_with_ubsan_dep", + static_executable: true, + host_supported: true, + static_libs: [ + "libubsan_diag", + ], + } + cc_library_shared { name: "libshared", host_supported: true, @@ -742,6 +750,17 @@ func TestUbsan(t *testing.T) { } cc_library_static { + name: "libubsan_diag", + host_supported: true, + sanitize: { + undefined: true, + diag: { + undefined: true, + }, + }, + } + + cc_library_static { name: "libstatic", host_supported: true, } @@ -763,6 +782,7 @@ func TestUbsan(t *testing.T) { sharedVariant := variant + "_shared" minimalRuntime := result.ModuleForTests("libclang_rt.ubsan_minimal", staticVariant) + standaloneRuntime := result.ModuleForTests("libclang_rt.ubsan_standalone.static", staticVariant) // The binaries, one with ubsan and one without binWithUbsan := result.ModuleForTests("bin_with_ubsan", variant) @@ -770,6 +790,7 @@ func TestUbsan(t *testing.T) { libSharedUbsan := result.ModuleForTests("libsharedubsan", sharedVariant) binDependsUbsanShared := result.ModuleForTests("bin_depends_ubsan_shared", variant) binNoUbsan := result.ModuleForTests("bin_no_ubsan", variant) + staticBin := result.ModuleForTests("static_bin_with_ubsan_dep", variant) android.AssertStringListContains(t, "missing libclang_rt.ubsan_minimal in bin_with_ubsan static libs", strings.Split(binWithUbsan.Rule("ld").Args["libFlags"], " "), @@ -810,6 +831,11 @@ func TestUbsan(t *testing.T) { android.AssertStringListDoesNotContain(t, "unexpected -Wl,--exclude-libs for minimal runtime in bin_no_ubsan static libs", strings.Split(binNoUbsan.Rule("ld").Args["ldFlags"], " "), "-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base()) + + android.AssertStringListContains(t, "missing libclang_rt.ubsan_standalone.static in static_bin_with_ubsan_dep static libs", + strings.Split(staticBin.Rule("ld").Args["libFlags"], " "), + standaloneRuntime.OutputFiles(t, "")[0].String()) + } t.Run("host", func(t *testing.T) { check(t, buildOS, preparer) }) @@ -1246,3 +1272,122 @@ func TestCfi(t *testing.T) { t.Errorf("non-CFI variant of baz not expected to contain CFI flags ") } } + +func TestHwasan(t *testing.T) { + t.Parallel() + + bp := ` + cc_library_shared { + name: "shared_with_hwaddress", + static_libs: [ + "static_dep_with_hwaddress", + "static_dep_no_hwaddress", + ], + sanitize: { + hwaddress: true, + }, + sdk_version: "current", + stl: "c++_shared", + } + + cc_library_static { + name: "static_dep_with_hwaddress", + sanitize: { + hwaddress: true, + }, + sdk_version: "current", + stl: "c++_shared", + } + + cc_library_static { + name: "static_dep_no_hwaddress", + sdk_version: "current", + stl: "c++_shared", + } +` + + androidArm := "android_arm_armv7-a-neon" + androidArm64 := "android_arm64_armv8-a" + androidX86 := "android_x86_silvermont" + sharedSuffix := "_shared" + hwasanSuffix := "_hwasan" + staticSuffix := "_static" + sdkSuffix := "_sdk" + + sharedWithHwasanVariant := sharedSuffix + hwasanSuffix + sharedWithSdkVariant := sdkSuffix + sharedSuffix + staticWithHwasanVariant := staticSuffix + hwasanSuffix + staticWithSdkVariant := sdkSuffix + staticSuffix + + testCases := []struct { + buildOs string + extraPreparer android.FixturePreparer + expectedVariants map[string][]string + }{ + { + buildOs: androidArm64, + expectedVariants: map[string][]string{ + "shared_with_hwaddress": []string{ + androidArm64 + sharedWithHwasanVariant, + androidArm64 + sharedWithSdkVariant, + androidArm + sharedSuffix, + androidArm + sharedWithSdkVariant, + }, + "static_dep_with_hwaddress": []string{ + androidArm64 + staticSuffix, + androidArm64 + staticWithHwasanVariant, + androidArm64 + staticWithSdkVariant, + androidArm + staticSuffix, + androidArm + staticWithSdkVariant, + }, + "static_dep_no_hwaddress": []string{ + androidArm64 + staticSuffix, + androidArm64 + staticWithHwasanVariant, + androidArm64 + staticWithSdkVariant, + androidArm + staticSuffix, + androidArm + staticWithSdkVariant, + }, + }, + }, + { + buildOs: androidX86, + extraPreparer: android.FixtureModifyConfig(func(config android.Config) { + config.Targets[android.Android] = []android.Target{ + { + android.Android, + android.Arch{ + ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, android.NativeBridgeDisabled, "", "", false}, + } + }), + expectedVariants: map[string][]string{ + "shared_with_hwaddress": []string{ + androidX86 + sharedSuffix, + androidX86 + sharedWithSdkVariant, + }, + "static_dep_with_hwaddress": []string{ + androidX86 + staticSuffix, + androidX86 + staticWithSdkVariant, + }, + "static_dep_no_hwaddress": []string{ + androidX86 + staticSuffix, + androidX86 + staticWithSdkVariant, + }, + }, + }, + } + + for _, tc := range testCases { + preparer := android.GroupFixturePreparers( + prepareForCcTest, + android.OptionalFixturePreparer(tc.extraPreparer), + ) + result := preparer.RunTestWithBp(t, bp) + + for m, v := range tc.expectedVariants { + variants := result.ModuleVariantsForTests(m) + if !reflect.DeepEqual(variants, v) { + t.Errorf("Expected variants of %q to be %q, but got %q", m, v, variants) + } + } + } +} @@ -47,47 +47,21 @@ func sdkMutator(ctx android.BottomUpMutatorContext) { // Mark the SDK variant. modules[1].(*Module).Properties.IsSdkVariant = true - // SDK variant is not supposed to be installed - modules[1].(*Module).Properties.PreventInstall = true if ctx.Config().UnbundledBuildApps() { - // For an unbundled apps build, hide the platform variant from Make. + // For an unbundled apps build, hide the platform variant from Make + // so that other Make modules don't link against it, but against the + // SDK variant. modules[0].(*Module).Properties.HideFromMake = true } else { // For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when // exposed to Make. modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true } + // SDK variant never gets installed because the variant is to be embedded in + // APKs, not to be installed to the platform. + modules[1].(*Module).Properties.PreventInstall = true ctx.AliasVariation("") - } else if isCcModule && ccModule.isImportedApiLibrary() { - apiLibrary, _ := ccModule.linker.(*apiLibraryDecorator) - if apiLibrary.hasNDKStubs() && ccModule.canUseSdk() { - variations := []string{"sdk"} - if apiLibrary.hasApexStubs() { - variations = append(variations, "") - } - // Handle cc_api_library module with NDK stubs and variants only which can use SDK - modules := ctx.CreateVariations(variations...) - // Mark the SDK variant. - modules[0].(*Module).Properties.IsSdkVariant = true - if ctx.Config().UnbundledBuildApps() { - if apiLibrary.hasApexStubs() { - // For an unbundled apps build, hide the platform variant from Make. - modules[1].(*Module).Properties.HideFromMake = true - modules[1].(*Module).Properties.PreventInstall = true - } - } else { - // For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when - // exposed to Make. - modules[0].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true - // SDK variant is not supposed to be installed - modules[0].(*Module).Properties.PreventInstall = true - } - } else { - ccModule.Properties.Sdk_version = nil - ctx.CreateVariations("") - ctx.AliasVariation("") - } } else { if isCcModule { // Clear the sdk_version property for modules that don't have an SDK variant so @@ -106,8 +80,6 @@ func sdkMutator(ctx android.BottomUpMutatorContext) { } ctx.AliasVariation("") } - case *snapshotModule: - ctx.CreateVariations("") case *CcApiVariant: ccApiVariant, _ := ctx.Module().(*CcApiVariant) if String(ccApiVariant.properties.Variant) == "ndk" { diff --git a/cc/sdk_test.go b/cc/sdk_test.go index 790440cb9..61925e30c 100644 --- a/cc/sdk_test.go +++ b/cc/sdk_test.go @@ -101,95 +101,3 @@ func TestSdkMutator(t *testing.T) { assertDep(t, libsdkNDK, libcxxNDK) assertDep(t, libsdkPlatform, libcxxPlatform) } - -func TestMakeModuleNameForSdkVariant(t *testing.T) { - bp := ` - cc_library { - name: "libfoo", - srcs: ["main_test.cpp"], - sdk_version: "current", - stl: "none", - } - ` - platformVariant := "android_arm64_armv8-a_shared" - sdkVariant := "android_arm64_armv8-a_sdk_shared" - testCases := []struct { - name string - unbundledApps []string - variant string - skipInstall bool // soong skips install - hideFromMake bool // no make entry - makeUninstallable bool // make skips install - makeModuleName string - }{ - { - name: "platform variant in normal builds", - unbundledApps: nil, - variant: platformVariant, - // installable in soong - skipInstall: false, - // visiable in Make as "libfoo" - hideFromMake: false, - makeModuleName: "libfoo", - // installable in Make - makeUninstallable: false, - }, - { - name: "sdk variant in normal builds", - unbundledApps: nil, - variant: sdkVariant, - // soong doesn't install - skipInstall: true, - // visible in Make as "libfoo.sdk" - hideFromMake: false, - makeModuleName: "libfoo.sdk", - // but not installed - makeUninstallable: true, - }, - { - name: "platform variant in unbunded builds", - unbundledApps: []string{"bar"}, - variant: platformVariant, - // installable in soong - skipInstall: false, - // hidden from make - hideFromMake: true, - }, - { - name: "sdk variant in unbunded builds", - unbundledApps: []string{"bar"}, - variant: sdkVariant, - // soong doesn't install - skipInstall: true, - // visible in Make as "libfoo" - hideFromMake: false, - makeModuleName: "libfoo", - // but not installed - makeUninstallable: true, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - fixture := android.GroupFixturePreparers(prepareForCcTest, - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.Unbundled_build_apps = tc.unbundledApps - }), - ) - ctx := fixture.RunTestWithBp(t, bp).TestContext - module := ctx.ModuleForTests("libfoo", tc.variant).Module().(*Module) - android.AssertBoolEquals(t, "IsSkipInstall", tc.skipInstall, module.IsSkipInstall()) - android.AssertBoolEquals(t, "HideFromMake", tc.hideFromMake, module.HiddenFromMake()) - if !tc.hideFromMake { - entries := android.AndroidMkEntriesForTest(t, ctx, module)[0] - android.AssertStringEquals(t, "LOCAL_MODULE", - tc.makeModuleName, entries.EntryMap["LOCAL_MODULE"][0]) - actualUninstallable := false - if actual, ok := entries.EntryMap["LOCAL_UNINSTALLABLE_MODULE"]; ok { - actualUninstallable = "true" == actual[0] - } - android.AssertBoolEquals(t, "LOCAL_UNINSTALLABLE_MODULE", - tc.makeUninstallable, actualUninstallable) - } - }) - } -} diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go index bb6e257e5..f4a3d889f 100644 --- a/cc/snapshot_prebuilt.go +++ b/cc/snapshot_prebuilt.go @@ -18,814 +18,9 @@ package cc // snapshot mutators and snapshot information maps which are also defined in this file. import ( - "fmt" - "strings" - "android/soong/android" - "android/soong/snapshot" - - "github.com/google/blueprint" ) -// This interface overrides snapshot.SnapshotImage to implement cc module specific functions -type SnapshotImage interface { - snapshot.SnapshotImage - - // The image variant name for this snapshot image. - // For example, recovery snapshot image will return "recovery", and vendor snapshot image will - // return "vendor." + version. - imageVariantName(cfg android.DeviceConfig) string - - // The variant suffix for snapshot modules. For example, vendor snapshot modules will have - // ".vendor" as their suffix. - moduleNameSuffix() string -} - -type vendorSnapshotImage struct { - *snapshot.VendorSnapshotImage -} - -type recoverySnapshotImage struct { - *snapshot.RecoverySnapshotImage -} - -func (vendorSnapshotImage) imageVariantName(cfg android.DeviceConfig) string { - return VendorVariationPrefix + cfg.VndkVersion() -} - -func (vendorSnapshotImage) moduleNameSuffix() string { - return VendorSuffix -} - -func (recoverySnapshotImage) imageVariantName(cfg android.DeviceConfig) string { - return android.RecoveryVariation -} - -func (recoverySnapshotImage) moduleNameSuffix() string { - return RecoverySuffix -} - -// Override existing vendor and recovery snapshot for cc module specific extra functions -var VendorSnapshotImageSingleton vendorSnapshotImage = vendorSnapshotImage{&snapshot.VendorSnapshotImageSingleton} -var RecoverySnapshotImageSingleton recoverySnapshotImage = recoverySnapshotImage{&snapshot.RecoverySnapshotImageSingleton} - -func RegisterVendorSnapshotModules(ctx android.RegistrationContext) { - ctx.RegisterModuleType("vendor_snapshot", vendorSnapshotFactory) - ctx.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory) - ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory) - ctx.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory) - ctx.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory) - ctx.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory) -} - -func RegisterRecoverySnapshotModules(ctx android.RegistrationContext) { - ctx.RegisterModuleType("recovery_snapshot", recoverySnapshotFactory) - ctx.RegisterModuleType("recovery_snapshot_shared", RecoverySnapshotSharedFactory) - ctx.RegisterModuleType("recovery_snapshot_static", RecoverySnapshotStaticFactory) - ctx.RegisterModuleType("recovery_snapshot_header", RecoverySnapshotHeaderFactory) - ctx.RegisterModuleType("recovery_snapshot_binary", RecoverySnapshotBinaryFactory) - ctx.RegisterModuleType("recovery_snapshot_object", RecoverySnapshotObjectFactory) -} - -func init() { - RegisterVendorSnapshotModules(android.InitRegistrationContext) - RegisterRecoverySnapshotModules(android.InitRegistrationContext) - android.RegisterMakeVarsProvider(pctx, snapshotMakeVarsProvider) -} - -const ( - snapshotHeaderSuffix = "_header." - SnapshotSharedSuffix = "_shared." - SnapshotStaticSuffix = "_static." - snapshotBinarySuffix = "_binary." - snapshotObjectSuffix = "_object." - SnapshotRlibSuffix = "_rlib." -) - -type SnapshotProperties struct { - Header_libs []string `android:"arch_variant"` - Static_libs []string `android:"arch_variant"` - Shared_libs []string `android:"arch_variant"` - Rlibs []string `android:"arch_variant"` - Vndk_libs []string `android:"arch_variant"` - Binaries []string `android:"arch_variant"` - Objects []string `android:"arch_variant"` -} -type snapshotModule struct { - android.ModuleBase - - properties SnapshotProperties - - baseSnapshot BaseSnapshotDecorator - - image SnapshotImage -} - -func (s *snapshotModule) ImageMutatorBegin(ctx android.BaseModuleContext) { - cfg := ctx.DeviceConfig() - if !s.image.IsUsingSnapshot(cfg) || s.image.TargetSnapshotVersion(cfg) != s.baseSnapshot.Version() { - s.Disable() - } -} - -func (s *snapshotModule) CoreVariantNeeded(ctx android.BaseModuleContext) bool { - return false -} - -func (s *snapshotModule) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { - return false -} - -func (s *snapshotModule) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { - return false -} - -func (s *snapshotModule) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { - return false -} - -func (s *snapshotModule) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { - return false -} - -func (s *snapshotModule) ExtraImageVariations(ctx android.BaseModuleContext) []string { - return []string{s.image.imageVariantName(ctx.DeviceConfig())} -} - -func (s *snapshotModule) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) { -} - -func (s *snapshotModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { - // Nothing, the snapshot module is only used to forward dependency information in DepsMutator. -} - -func getSnapshotNameSuffix(moduleSuffix, version, arch string) string { - versionSuffix := version - if arch != "" { - versionSuffix += "." + arch - } - return moduleSuffix + versionSuffix -} - -func (s *snapshotModule) DepsMutator(ctx android.BottomUpMutatorContext) { - collectSnapshotMap := func(names []string, snapshotSuffix, moduleSuffix string) map[string]string { - snapshotMap := make(map[string]string) - for _, name := range names { - snapshotMap[name] = name + - getSnapshotNameSuffix(snapshotSuffix+moduleSuffix, - s.baseSnapshot.Version(), - ctx.DeviceConfig().Arches()[0].ArchType.String()) - } - return snapshotMap - } - - snapshotSuffix := s.image.moduleNameSuffix() - headers := collectSnapshotMap(s.properties.Header_libs, snapshotSuffix, snapshotHeaderSuffix) - binaries := collectSnapshotMap(s.properties.Binaries, snapshotSuffix, snapshotBinarySuffix) - objects := collectSnapshotMap(s.properties.Objects, snapshotSuffix, snapshotObjectSuffix) - staticLibs := collectSnapshotMap(s.properties.Static_libs, snapshotSuffix, SnapshotStaticSuffix) - sharedLibs := collectSnapshotMap(s.properties.Shared_libs, snapshotSuffix, SnapshotSharedSuffix) - rlibs := collectSnapshotMap(s.properties.Rlibs, snapshotSuffix, SnapshotRlibSuffix) - vndkLibs := collectSnapshotMap(s.properties.Vndk_libs, "", vndkSuffix) - for k, v := range vndkLibs { - sharedLibs[k] = v - } - - ctx.SetProvider(SnapshotInfoProvider, SnapshotInfo{ - HeaderLibs: headers, - Binaries: binaries, - Objects: objects, - StaticLibs: staticLibs, - SharedLibs: sharedLibs, - Rlibs: rlibs, - }) -} - -type SnapshotInfo struct { - HeaderLibs, Binaries, Objects, StaticLibs, SharedLibs, Rlibs map[string]string -} - -var SnapshotInfoProvider = blueprint.NewMutatorProvider(SnapshotInfo{}, "deps") - -var _ android.ImageInterface = (*snapshotModule)(nil) - -func snapshotMakeVarsProvider(ctx android.MakeVarsContext) { - snapshotSet := map[string]struct{}{} - ctx.VisitAllModules(func(m android.Module) { - if s, ok := m.(*snapshotModule); ok { - if _, ok := snapshotSet[s.Name()]; ok { - // arch variant generates duplicated modules - // skip this as we only need to know the path of the module. - return - } - snapshotSet[s.Name()] = struct{}{} - imageNameVersion := strings.Split(s.image.imageVariantName(ctx.DeviceConfig()), ".") - ctx.Strict( - strings.Join([]string{strings.ToUpper(imageNameVersion[0]), s.baseSnapshot.Version(), "SNAPSHOT_DIR"}, "_"), - ctx.ModuleDir(s)) - } - }) -} - -func vendorSnapshotFactory() android.Module { - return snapshotFactory(VendorSnapshotImageSingleton) -} - -func recoverySnapshotFactory() android.Module { - return snapshotFactory(RecoverySnapshotImageSingleton) -} - -func snapshotFactory(image SnapshotImage) android.Module { - snapshotModule := &snapshotModule{} - snapshotModule.image = image - snapshotModule.AddProperties( - &snapshotModule.properties, - &snapshotModule.baseSnapshot.baseProperties) - android.InitAndroidArchModule(snapshotModule, android.DeviceSupported, android.MultilibBoth) - return snapshotModule -} - -type BaseSnapshotDecoratorProperties struct { - // snapshot version. - Version string - - // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64') - Target_arch string - - // Suffix to be added to the module name when exporting to Android.mk, e.g. ".vendor". - Androidmk_suffix string `blueprint:"mutated"` - - // Suffix to be added to the module name, e.g., vendor_shared, - // recovery_shared, etc. - ModuleSuffix string `blueprint:"mutated"` -} - -// BaseSnapshotDecorator provides common basic functions for all snapshot modules, such as snapshot -// version, snapshot arch, etc. It also adds a special suffix to Soong module name, so it doesn't -// collide with source modules. e.g. the following example module, -// -// vendor_snapshot_static { -// name: "libbase", -// arch: "arm64", -// version: 30, -// ... -// } -// -// will be seen as "libbase.vendor_static.30.arm64" by Soong. -type BaseSnapshotDecorator struct { - baseProperties BaseSnapshotDecoratorProperties - Image SnapshotImage -} - -func (p *BaseSnapshotDecorator) Name(name string) string { - return name + p.NameSuffix() -} - -func (p *BaseSnapshotDecorator) NameSuffix() string { - return getSnapshotNameSuffix(p.moduleSuffix(), p.Version(), p.Arch()) -} - -func (p *BaseSnapshotDecorator) Version() string { - return p.baseProperties.Version -} - -func (p *BaseSnapshotDecorator) Arch() string { - return p.baseProperties.Target_arch -} - -func (p *BaseSnapshotDecorator) moduleSuffix() string { - return p.baseProperties.ModuleSuffix -} - -func (p *BaseSnapshotDecorator) IsSnapshotPrebuilt() bool { - return true -} - -func (p *BaseSnapshotDecorator) SnapshotAndroidMkSuffix() string { - return p.baseProperties.Androidmk_suffix -} - -func (p *BaseSnapshotDecorator) SetSnapshotAndroidMkSuffix(ctx android.ModuleContext, variant string) { - // If there are any 2 or more variations among {core, product, vendor, recovery} - // we have to add the androidmk suffix to avoid duplicate modules with the same - // name. - variations := append(ctx.Target().Variations(), blueprint.Variation{ - Mutator: "image", - Variation: android.CoreVariation}) - - if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(LinkableInterface).BaseModuleName()) { - p.baseProperties.Androidmk_suffix = p.Image.moduleNameSuffix() - return - } - - variations = append(ctx.Target().Variations(), blueprint.Variation{ - Mutator: "image", - Variation: ProductVariationPrefix + ctx.DeviceConfig().PlatformVndkVersion()}) - - if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(LinkableInterface).BaseModuleName()) { - p.baseProperties.Androidmk_suffix = p.Image.moduleNameSuffix() - return - } - - images := []SnapshotImage{VendorSnapshotImageSingleton, RecoverySnapshotImageSingleton} - - for _, image := range images { - if p.Image == image { - continue - } - variations = append(ctx.Target().Variations(), blueprint.Variation{ - Mutator: "image", - Variation: image.imageVariantName(ctx.DeviceConfig())}) - - if ctx.OtherModuleFarDependencyVariantExists(variations, - ctx.Module().(LinkableInterface).BaseModuleName()+ - getSnapshotNameSuffix( - image.moduleNameSuffix()+variant, - p.Version(), - ctx.DeviceConfig().Arches()[0].ArchType.String())) { - p.baseProperties.Androidmk_suffix = p.Image.moduleNameSuffix() - return - } - } - - p.baseProperties.Androidmk_suffix = "" -} - -// Call this with a module suffix after creating a snapshot module, such as -// vendorSnapshotSharedSuffix, recoverySnapshotBinarySuffix, etc. -func (p *BaseSnapshotDecorator) Init(m LinkableInterface, image SnapshotImage, moduleSuffix string) { - p.Image = image - p.baseProperties.ModuleSuffix = image.moduleNameSuffix() + moduleSuffix - m.AddProperties(&p.baseProperties) - android.AddLoadHook(m, func(ctx android.LoadHookContext) { - vendorSnapshotLoadHook(ctx, p) - }) -} - -// vendorSnapshotLoadHook disables snapshots if it's not BOARD_VNDK_VERSION. -// As vendor snapshot is only for vendor, such modules won't be used at all. -func vendorSnapshotLoadHook(ctx android.LoadHookContext, p *BaseSnapshotDecorator) { - if p.Version() != ctx.DeviceConfig().VndkVersion() { - ctx.Module().Disable() - return - } -} - -// Module definitions for snapshots of libraries (shared, static, header). -// -// Modules (vendor|recovery)_snapshot_(shared|static|header) are defined here. Shared libraries and -// static libraries have their prebuilt library files (.so for shared, .a for static) as their src, -// which can be installed or linked against. Also they export flags needed when linked, such as -// include directories, c flags, sanitize dependency information, etc. -// -// These modules are auto-generated by development/vendor_snapshot/update.py. -type SnapshotLibraryProperties struct { - // Prebuilt file for each arch. - Src *string `android:"arch_variant"` - - // list of directories that will be added to the include path (using -I). - Export_include_dirs []string `android:"arch_variant"` - - // list of directories that will be added to the system path (using -isystem). - Export_system_include_dirs []string `android:"arch_variant"` - - // list of flags that will be used for any module that links against this module. - Export_flags []string `android:"arch_variant"` - - // Whether this prebuilt needs to depend on sanitize ubsan runtime or not. - Sanitize_ubsan_dep *bool `android:"arch_variant"` - - // Whether this prebuilt needs to depend on sanitize minimal runtime or not. - Sanitize_minimal_dep *bool `android:"arch_variant"` -} - -type snapshotSanitizer interface { - isSanitizerAvailable(t SanitizerType) bool - setSanitizerVariation(t SanitizerType, enabled bool) - isSanitizerEnabled(t SanitizerType) bool - isUnsanitizedVariant() bool -} - -type snapshotLibraryDecorator struct { - BaseSnapshotDecorator - *libraryDecorator - properties SnapshotLibraryProperties - sanitizerProperties struct { - SanitizerVariation SanitizerType `blueprint:"mutated"` - - // Library flags for cfi variant. - Cfi SnapshotLibraryProperties `android:"arch_variant"` - - // Library flags for hwasan variant. - Hwasan SnapshotLibraryProperties `android:"arch_variant"` - } -} - -func (p *snapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { - p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), p.NameSuffix()) - return p.libraryDecorator.linkerFlags(ctx, flags) -} - -func (p *snapshotLibraryDecorator) MatchesWithDevice(config android.DeviceConfig) bool { - arches := config.Arches() - if len(arches) == 0 || arches[0].ArchType.String() != p.Arch() { - return false - } - if !p.header() && p.properties.Src == nil { - return false - } - return true -} - -// cc modules' link functions are to link compiled objects into final binaries. -// As snapshots are prebuilts, this just returns the prebuilt binary after doing things which are -// done by normal library decorator, e.g. exporting flags. -func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { - var variant string - if p.shared() { - variant = SnapshotSharedSuffix - } else if p.static() { - variant = SnapshotStaticSuffix - } else { - variant = snapshotHeaderSuffix - } - - p.SetSnapshotAndroidMkSuffix(ctx, variant) - - if p.header() { - return p.libraryDecorator.link(ctx, flags, deps, objs) - } - - if p.isSanitizerEnabled(cfi) { - p.properties = p.sanitizerProperties.Cfi - } else if p.isSanitizerEnabled(Hwasan) { - p.properties = p.sanitizerProperties.Hwasan - } - - if !p.MatchesWithDevice(ctx.DeviceConfig()) { - return nil - } - - // Flags specified directly to this module. - p.libraryDecorator.reexportDirs(android.PathsForModuleSrc(ctx, p.properties.Export_include_dirs)...) - p.libraryDecorator.reexportSystemDirs(android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...) - p.libraryDecorator.reexportFlags(p.properties.Export_flags...) - - // Flags reexported from dependencies. (e.g. vndk_prebuilt_shared) - p.libraryDecorator.reexportDirs(deps.ReexportedDirs...) - p.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...) - p.libraryDecorator.reexportFlags(deps.ReexportedFlags...) - p.libraryDecorator.reexportDeps(deps.ReexportedDeps...) - p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...) - - in := android.PathForModuleSrc(ctx, *p.properties.Src) - p.unstrippedOutputFile = in - - if p.shared() { - libName := in.Base() - - // Optimize out relinking against shared libraries whose interface hasn't changed by - // depending on a table of contents file instead of the library itself. - tocFile := android.PathForModuleOut(ctx, libName+".toc") - p.tocFile = android.OptionalPathForPath(tocFile) - TransformSharedObjectToToc(ctx, in, tocFile) - - ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{ - SharedLibrary: in, - Target: ctx.Target(), - - TableOfContents: p.tocFile, - }) - } - - if p.static() { - depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(in).Build() - ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{ - StaticLibrary: in, - - TransitiveStaticLibrariesForOrdering: depSet, - }) - } - - p.libraryDecorator.flagExporter.setProvider(ctx) - - return in -} - -func (p *snapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) { - if p.MatchesWithDevice(ctx.DeviceConfig()) && p.shared() { - p.baseInstaller.install(ctx, file) - } -} - -func (p *snapshotLibraryDecorator) nativeCoverage() bool { - return false -} - -var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil) - -func (p *snapshotLibraryDecorator) isSanitizerAvailable(t SanitizerType) bool { - switch t { - case cfi: - return p.sanitizerProperties.Cfi.Src != nil - case Hwasan: - return p.sanitizerProperties.Hwasan.Src != nil - default: - return false - } -} - -func (p *snapshotLibraryDecorator) setSanitizerVariation(t SanitizerType, enabled bool) { - if !enabled || p.isSanitizerEnabled(t) { - return - } - if !p.isUnsanitizedVariant() { - panic(fmt.Errorf("snapshot Sanitizer must be one of Cfi or Hwasan but not both")) - } - p.sanitizerProperties.SanitizerVariation = t -} - -func (p *snapshotLibraryDecorator) isSanitizerEnabled(t SanitizerType) bool { - return p.sanitizerProperties.SanitizerVariation == t -} - -func (p *snapshotLibraryDecorator) isUnsanitizedVariant() bool { - return !p.isSanitizerEnabled(Asan) && - !p.isSanitizerEnabled(Hwasan) -} - -func snapshotLibraryFactory(image SnapshotImage, moduleSuffix string) (*Module, *snapshotLibraryDecorator) { - module, library := NewLibrary(android.DeviceSupported) - - module.stl = nil - module.sanitize = nil - library.disableStripping() - - prebuilt := &snapshotLibraryDecorator{ - libraryDecorator: library, - } - - prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true) - prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true) - - // Prevent default system libs (libc, libm, and libdl) from being linked - if prebuilt.baseLinker.Properties.System_shared_libs == nil { - prebuilt.baseLinker.Properties.System_shared_libs = []string{} - } - - module.compiler = nil - module.linker = prebuilt - module.installer = prebuilt - - prebuilt.Init(module, image, moduleSuffix) - module.AddProperties( - &prebuilt.properties, - &prebuilt.sanitizerProperties, - ) - - return module, prebuilt -} - -// vendor_snapshot_shared is a special prebuilt shared library which is auto-generated by -// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_shared -// overrides the vendor variant of the cc shared library with the same name, if BOARD_VNDK_VERSION -// is set. -func VendorSnapshotSharedFactory() android.Module { - module, prebuilt := snapshotLibraryFactory(VendorSnapshotImageSingleton, SnapshotSharedSuffix) - prebuilt.libraryDecorator.BuildOnlyShared() - return module.Init() -} - -// recovery_snapshot_shared is a special prebuilt shared library which is auto-generated by -// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_shared -// overrides the recovery variant of the cc shared library with the same name, if BOARD_VNDK_VERSION -// is set. -func RecoverySnapshotSharedFactory() android.Module { - module, prebuilt := snapshotLibraryFactory(RecoverySnapshotImageSingleton, SnapshotSharedSuffix) - prebuilt.libraryDecorator.BuildOnlyShared() - return module.Init() -} - -// vendor_snapshot_static is a special prebuilt static library which is auto-generated by -// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_static -// overrides the vendor variant of the cc static library with the same name, if BOARD_VNDK_VERSION -// is set. -func VendorSnapshotStaticFactory() android.Module { - module, prebuilt := snapshotLibraryFactory(VendorSnapshotImageSingleton, SnapshotStaticSuffix) - prebuilt.libraryDecorator.BuildOnlyStatic() - return module.Init() -} - -// recovery_snapshot_static is a special prebuilt static library which is auto-generated by -// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_static -// overrides the recovery variant of the cc static library with the same name, if BOARD_VNDK_VERSION -// is set. -func RecoverySnapshotStaticFactory() android.Module { - module, prebuilt := snapshotLibraryFactory(RecoverySnapshotImageSingleton, SnapshotStaticSuffix) - prebuilt.libraryDecorator.BuildOnlyStatic() - return module.Init() -} - -// vendor_snapshot_header is a special header library which is auto-generated by -// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_header -// overrides the vendor variant of the cc header library with the same name, if BOARD_VNDK_VERSION -// is set. -func VendorSnapshotHeaderFactory() android.Module { - module, prebuilt := snapshotLibraryFactory(VendorSnapshotImageSingleton, snapshotHeaderSuffix) - prebuilt.libraryDecorator.HeaderOnly() - return module.Init() -} - -// recovery_snapshot_header is a special header library which is auto-generated by -// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_header -// overrides the recovery variant of the cc header library with the same name, if BOARD_VNDK_VERSION -// is set. -func RecoverySnapshotHeaderFactory() android.Module { - module, prebuilt := snapshotLibraryFactory(RecoverySnapshotImageSingleton, snapshotHeaderSuffix) - prebuilt.libraryDecorator.HeaderOnly() - return module.Init() -} - -// Module definitions for snapshots of executable binaries. -// -// Modules (vendor|recovery)_snapshot_binary are defined here. They have their prebuilt executable -// binaries (e.g. toybox, sh) as their src, which can be installed. -// -// These modules are auto-generated by development/vendor_snapshot/update.py. -type snapshotBinaryProperties struct { - // Prebuilt file for each arch. - Src *string `android:"arch_variant"` -} - -type snapshotBinaryDecorator struct { - BaseSnapshotDecorator - *binaryDecorator - properties snapshotBinaryProperties -} - -func (p *snapshotBinaryDecorator) MatchesWithDevice(config android.DeviceConfig) bool { - if config.DeviceArch() != p.Arch() { - return false - } - if p.properties.Src == nil { - return false - } - return true -} - -// cc modules' link functions are to link compiled objects into final binaries. -// As snapshots are prebuilts, this just returns the prebuilt binary -func (p *snapshotBinaryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { - p.SetSnapshotAndroidMkSuffix(ctx, snapshotBinarySuffix) - - if !p.MatchesWithDevice(ctx.DeviceConfig()) { - return nil - } - - in := android.PathForModuleSrc(ctx, *p.properties.Src) - p.unstrippedOutputFile = in - binName := in.Base() - - // use cpExecutable to make it executable - outputFile := android.PathForModuleOut(ctx, binName) - ctx.Build(pctx, android.BuildParams{ - Rule: android.CpExecutable, - Description: "prebuilt", - Output: outputFile, - Input: in, - }) - - // binary snapshots need symlinking - p.setSymlinkList(ctx) - - return outputFile -} - -func (p *snapshotBinaryDecorator) nativeCoverage() bool { - return false -} - -// vendor_snapshot_binary is a special prebuilt executable binary which is auto-generated by -// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_binary -// overrides the vendor variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set. -func VendorSnapshotBinaryFactory() android.Module { - return snapshotBinaryFactory(VendorSnapshotImageSingleton, snapshotBinarySuffix) -} - -// recovery_snapshot_binary is a special prebuilt executable binary which is auto-generated by -// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_binary -// overrides the recovery variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set. -func RecoverySnapshotBinaryFactory() android.Module { - return snapshotBinaryFactory(RecoverySnapshotImageSingleton, snapshotBinarySuffix) -} - -func snapshotBinaryFactory(image SnapshotImage, moduleSuffix string) android.Module { - module, binary := NewBinary(android.DeviceSupported) - binary.baseLinker.Properties.No_libcrt = BoolPtr(true) - binary.baseLinker.Properties.Nocrt = BoolPtr(true) - - // Prevent default system libs (libc, libm, and libdl) from being linked - if binary.baseLinker.Properties.System_shared_libs == nil { - binary.baseLinker.Properties.System_shared_libs = []string{} - } - - prebuilt := &snapshotBinaryDecorator{ - binaryDecorator: binary, - } - - module.compiler = nil - module.sanitize = nil - module.stl = nil - module.linker = prebuilt - - prebuilt.Init(module, image, moduleSuffix) - module.AddProperties(&prebuilt.properties) - return module.Init() -} - -// Module definitions for snapshots of object files (*.o). -// -// Modules (vendor|recovery)_snapshot_object are defined here. They have their prebuilt object -// files (*.o) as their src. -// -// These modules are auto-generated by development/vendor_snapshot/update.py. -type vendorSnapshotObjectProperties struct { - // Prebuilt file for each arch. - Src *string `android:"arch_variant"` -} - -type snapshotObjectLinker struct { - BaseSnapshotDecorator - objectLinker - properties vendorSnapshotObjectProperties -} - -func (p *snapshotObjectLinker) MatchesWithDevice(config android.DeviceConfig) bool { - if config.DeviceArch() != p.Arch() { - return false - } - if p.properties.Src == nil { - return false - } - return true -} - -// cc modules' link functions are to link compiled objects into final binaries. -// As snapshots are prebuilts, this just returns the prebuilt binary -func (p *snapshotObjectLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { - p.SetSnapshotAndroidMkSuffix(ctx, snapshotObjectSuffix) - - if !p.MatchesWithDevice(ctx.DeviceConfig()) { - return nil - } - - return android.PathForModuleSrc(ctx, *p.properties.Src) -} - -func (p *snapshotObjectLinker) nativeCoverage() bool { - return false -} - -// vendor_snapshot_object is a special prebuilt compiled object file which is auto-generated by -// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_object -// overrides the vendor variant of the cc object with the same name, if BOARD_VNDK_VERSION is set. -func VendorSnapshotObjectFactory() android.Module { - module := newObject(android.DeviceSupported) - - prebuilt := &snapshotObjectLinker{ - objectLinker: objectLinker{ - baseLinker: NewBaseLinker(nil), - }, - } - module.linker = prebuilt - - prebuilt.Init(module, VendorSnapshotImageSingleton, snapshotObjectSuffix) - module.AddProperties(&prebuilt.properties) - - // vendor_snapshot_object module does not provide sanitizer variants - module.sanitize.Properties.Sanitize.Never = BoolPtr(true) - - return module.Init() -} - -// recovery_snapshot_object is a special prebuilt compiled object file which is auto-generated by -// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_object -// overrides the recovery variant of the cc object with the same name, if BOARD_VNDK_VERSION is set. -func RecoverySnapshotObjectFactory() android.Module { - module := newObject(android.DeviceSupported) - - prebuilt := &snapshotObjectLinker{ - objectLinker: objectLinker{ - baseLinker: NewBaseLinker(nil), - }, - } - module.linker = prebuilt - - prebuilt.Init(module, RecoverySnapshotImageSingleton, snapshotObjectSuffix) - module.AddProperties(&prebuilt.properties) - return module.Init() -} - type SnapshotInterface interface { MatchesWithDevice(config android.DeviceConfig) bool IsSnapshotPrebuilt() bool @@ -834,6 +29,3 @@ type SnapshotInterface interface { } var _ SnapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil) -var _ SnapshotInterface = (*snapshotLibraryDecorator)(nil) -var _ SnapshotInterface = (*snapshotBinaryDecorator)(nil) -var _ SnapshotInterface = (*snapshotObjectLinker)(nil) diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go deleted file mode 100644 index cf4617da3..000000000 --- a/cc/snapshot_utils.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2020 The Android Open Source Project -// -// 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 - -// This file contains utility types and functions for VNDK / vendor snapshot. - -import ( - "android/soong/android" -) - -var ( - HeaderExts = []string{".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"} -) - -func (m *Module) IsSnapshotLibrary() bool { - if _, ok := m.linker.(snapshotLibraryInterface); ok { - return true - } - return false -} - -func (m *Module) SnapshotHeaders() android.Paths { - if m.IsSnapshotLibrary() { - return m.linker.(snapshotLibraryInterface).snapshotHeaders() - } - return android.Paths{} -} - -func (m *Module) Dylib() bool { - return false -} - -func (m *Module) Rlib() bool { - return false -} - -func (m *Module) SnapshotRuntimeLibs() []string { - return m.Properties.SnapshotRuntimeLibs -} - -func (m *Module) SnapshotSharedLibs() []string { - return m.Properties.SnapshotSharedLibs -} - -func (m *Module) SnapshotStaticLibs() []string { - return m.Properties.SnapshotStaticLibs -} - -// snapshotLibraryInterface is an interface for libraries captured to VNDK / vendor snapshots. -type snapshotLibraryInterface interface { - libraryInterface - - // collectHeadersForSnapshot is called in GenerateAndroidBuildActions for snapshot aware - // modules (See isSnapshotAware below). - // This function should gather all headers needed for snapshot. - collectHeadersForSnapshot(ctx android.ModuleContext) - - // snapshotHeaders should return collected headers by collectHeadersForSnapshot. - // Calling snapshotHeaders before collectHeadersForSnapshot is an error. - snapshotHeaders() android.Paths -} - -var _ snapshotLibraryInterface = (*prebuiltLibraryLinker)(nil) -var _ snapshotLibraryInterface = (*libraryDecorator)(nil) - -// snapshotMap is a helper wrapper to a map from base module name to snapshot module name. -type snapshotMap struct { - snapshots map[string]string -} - -func newSnapshotMap() *snapshotMap { - return &snapshotMap{ - snapshots: make(map[string]string), - } -} - -func snapshotMapKey(name string, arch android.ArchType) string { - return name + ":" + arch.String() -} - -// Adds a snapshot name for given module name and architecture. -// e.g. add("libbase", X86, "libbase.vndk.29.x86") -func (s *snapshotMap) add(name string, arch android.ArchType, snapshot string) { - s.snapshots[snapshotMapKey(name, arch)] = snapshot -} - -// Returns snapshot name for given module name and architecture, if found. -// e.g. get("libcutils", X86) => "libcutils.vndk.29.x86", true -func (s *snapshotMap) get(name string, arch android.ArchType) (snapshot string, found bool) { - snapshot, found = s.snapshots[snapshotMapKey(name, arch)] - return snapshot, found -} - -// ShouldCollectHeadersForSnapshot determines if the module is a possible candidate for snapshot. -// If it's true, collectHeadersForSnapshot will be called in GenerateAndroidBuildActions. -func ShouldCollectHeadersForSnapshot(ctx android.ModuleContext, m LinkableInterface, apexInfo android.ApexInfo) bool { - if ctx.DeviceConfig().VndkVersion() != "current" && - ctx.DeviceConfig().RecoverySnapshotVersion() != "current" { - return false - } - if _, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo); ok { - return ctx.Config().VndkSnapshotBuildArtifacts() - } - - for _, image := range []SnapshotImage{VendorSnapshotImageSingleton, RecoverySnapshotImageSingleton} { - if isSnapshotAware(ctx.DeviceConfig(), m, image.IsProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()), apexInfo, image) { - return true - } - } - return false -} @@ -80,8 +80,7 @@ func (stl *stl) begin(ctx BaseModuleContext) { return "" } s = deduplicateStlInput(s) - archHasNDKStl := ctx.Arch().ArchType != android.Riscv64 - if ctx.useSdk() && ctx.Device() && archHasNDKStl { + if ctx.useSdk() && ctx.Device() { switch s { case "", "system": return "ndk_system" @@ -120,11 +119,6 @@ func (stl *stl) begin(ctx BaseModuleContext) { }() } -func needsLibAndroidSupport(ctx BaseModuleContext) bool { - version := nativeApiLevelOrPanic(ctx, ctx.sdkVersion()) - return version.LessThan(android.FirstNonLibAndroidSupportVersion) -} - func staticUnwinder(ctx android.BaseModuleContext) string { vndkVersion := ctx.Module().(*Module).VndkVersion() @@ -140,8 +134,6 @@ func staticUnwinder(ctx android.BaseModuleContext) string { return "libunwind" } -// Should be kept up to date with -// https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/cc/stl.bzl;l=46;drc=21771b671ae08565033768a6d3d151c54f887fa2 func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps { switch stl.Properties.SelectedStl { case "libstdc++": @@ -178,17 +170,13 @@ func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps { // The system STL doesn't have a prebuilt (it uses the system's libstdc++), but it does have // its own includes. The includes are handled in CCBase.Flags(). deps.SharedLibs = append([]string{"libstdc++"}, deps.SharedLibs...) + deps.HeaderLibs = append([]string{"ndk_system"}, deps.HeaderLibs...) case "ndk_libc++_shared", "ndk_libc++_static": if stl.Properties.SelectedStl == "ndk_libc++_shared" { deps.SharedLibs = append(deps.SharedLibs, stl.Properties.SelectedStl) } else { deps.StaticLibs = append(deps.StaticLibs, stl.Properties.SelectedStl, "ndk_libc++abi") } - if needsLibAndroidSupport(ctx) { - // Use LateStaticLibs for ndk_libandroid_support so that its include directories - // come after ndk_libc++_static or ndk_libc++_shared. - deps.LateStaticLibs = append(deps.LateStaticLibs, "ndk_libandroid_support") - } deps.StaticLibs = append(deps.StaticLibs, "ndk_libunwind") default: panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl)) @@ -197,8 +185,6 @@ func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps { return deps } -// Should be kept up to date with -// https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/cc/stl.bzl;l=94;drc=5bc8e39d2637927dc57dd0850210d43d348a1341 func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags { switch stl.Properties.SelectedStl { case "libc++", "libc++_static": @@ -219,19 +205,20 @@ func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags { flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++") if ctx.Windows() { flags.Local.CppFlags = append(flags.Local.CppFlags, - // Disable visiblity annotations since we're using static - // libc++. - "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS", - "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", + // These macros can also be defined by libc++'s __config + // or __config_site headers so define them the same way + // (i.e. to nothing). Disable visibility annotations since + // we're using static libc++. + "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS=", + "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS=", // Use Win32 threads in libc++. - "-D_LIBCPP_HAS_THREAD_API_WIN32") + "-D_LIBCPP_HAS_THREAD_API_WIN32=") } } case "libstdc++": // Nothing case "ndk_system": - ndkSrcRoot := android.PathForSource(ctx, "prebuilts/ndk/current/sources/cxx-stl/system/include") - flags.Local.CFlags = append(flags.Local.CFlags, "-isystem "+ndkSrcRoot.String()) + // Nothing: The exports of ndk_system will be added automatically to the local cflags case "ndk_libc++_shared", "ndk_libc++_static": if ctx.Arch().ArchType == android.Arm { // Make sure the _Unwind_XXX symbols are not re-exported. diff --git a/cc/strip.go b/cc/strip.go index c60e13530..b1f34bb89 100644 --- a/cc/strip.go +++ b/cc/strip.go @@ -59,7 +59,6 @@ func (stripper *Stripper) NeedsStrip(actx android.ModuleContext) bool { return !forceDisable && (forceEnable || defaultEnable) } -// Keep this consistent with //build/bazel/rules/stripped_shared_library.bzl. func (stripper *Stripper) strip(actx android.ModuleContext, in android.Path, out android.ModuleOutPath, flags StripFlags, isStaticLib bool) { if actx.Darwin() { diff --git a/cc/stub_library.go b/cc/stub_library.go index f324dcc9b..47c6cb9a1 100644 --- a/cc/stub_library.go +++ b/cc/stub_library.go @@ -23,11 +23,12 @@ import ( func init() { // Use singleton type to gather all generated soong modules. - android.RegisterSingletonType("stublibraries", stubLibrariesSingleton) + android.RegisterParallelSingletonType("stublibraries", stubLibrariesSingleton) } type stubLibraries struct { - stubLibraryMap map[string]bool + stubLibraryMap map[string]bool + stubVendorLibraryMap map[string]bool apiListCoverageXmlPaths []string } @@ -54,6 +55,9 @@ func (s *stubLibraries) GenerateBuildActions(ctx android.SingletonContext) { if IsStubTarget(m) { if name := getInstalledFileName(m); name != "" { s.stubLibraryMap[name] = true + if m.InVendor() { + s.stubVendorLibraryMap[name] = true + } } } if m.library != nil { @@ -67,13 +71,15 @@ func (s *stubLibraries) GenerateBuildActions(ctx android.SingletonContext) { func stubLibrariesSingleton() android.Singleton { return &stubLibraries{ - stubLibraryMap: make(map[string]bool), + stubLibraryMap: make(map[string]bool), + stubVendorLibraryMap: make(map[string]bool), } } func (s *stubLibraries) MakeVars(ctx android.MakeVarsContext) { // Convert stub library file names into Makefile variable. ctx.Strict("STUB_LIBRARIES", strings.Join(android.SortedKeys(s.stubLibraryMap), " ")) + ctx.Strict("SOONG_STUB_VENDOR_LIBRARIES", strings.Join(android.SortedKeys(s.stubVendorLibraryMap), " ")) // Export the list of API XML files to Make. sort.Strings(s.apiListCoverageXmlPaths) diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py index 94c856726..4553616ac 100644 --- a/cc/symbolfile/__init__.py +++ b/cc/symbolfile/__init__.py @@ -46,6 +46,15 @@ ALL_ARCHITECTURES = ( Arch('x86_64'), ) +# TODO: it would be nice to dedupe with 'has_*_tag' property methods +SUPPORTED_TAGS = ALL_ARCHITECTURES + ( + Tag('apex'), + Tag('llndk'), + Tag('platform-only'), + Tag('systemapi'), + Tag('var'), + Tag('weak'), +) # Arbitrary magic number. We use the same one in api-level.h for this purpose. FUTURE_API_LEVEL = 10000 @@ -94,13 +103,24 @@ class Tags: @property def has_llndk_tags(self) -> bool: """Returns True if any LL-NDK tags are set.""" - return 'llndk' in self.tags + for tag in self.tags: + if tag == 'llndk' or tag.startswith('llndk='): + return True + return False @property def has_platform_only_tags(self) -> bool: """Returns True if any platform-only tags are set.""" return 'platform-only' in self.tags + def copy_introduced_from(self, tags: Tags) -> None: + """Copies introduced= or introduced-*= tags.""" + for tag in tags: + if tag.startswith('introduced=') or tag.startswith('introduced-'): + name, _ = split_tag(tag) + if not any(self_tag.startswith(name + '=') for self_tag in self.tags): + self.tags += (tag,) + @dataclass class Symbol: @@ -136,6 +156,10 @@ def get_tags(line: str, api_map: ApiMap) -> Tags: def is_api_level_tag(tag: Tag) -> bool: """Returns true if this tag has an API level that may need decoding.""" + if tag.startswith('llndk-deprecated='): + return True + if tag.startswith('llndk='): + return True if tag.startswith('introduced='): return True if tag.startswith('introduced-'): @@ -170,6 +194,9 @@ def decode_api_level_tag(tag: Tag, api_map: ApiMap) -> Tag: ParseError: An unknown version name was found in a tag. """ if not is_api_level_tag(tag): + if tag not in SUPPORTED_TAGS: + raise ParseError(f'Unsupported tag: {tag}') + return tag name, value = split_tag(tag) @@ -223,15 +250,22 @@ class Filter: This defines the rules shared between version tagging and symbol tagging. """ - # The apex and llndk tags will only exclude APIs from other modes. If in + # LLNDK mode/tags follow the similar filtering except that API level checking + # is based llndk= instead of introduced=. + if self.llndk: + if tags.has_mode_tags and not tags.has_llndk_tags: + return True + if not symbol_in_arch(tags, self.arch): + return True + if not symbol_in_llndk_api(tags, self.arch, self.api): + return True + return False # APEX or LLNDK mode and neither tag is provided, we fall back to the # default behavior because all NDK symbols are implicitly available to # APEX and LLNDK. if tags.has_mode_tags: if self.apex and tags.has_apex_tags: return False - if self.llndk and tags.has_llndk_tags: - return False if self.systemapi and tags.has_systemapi_tags: return False return True @@ -252,6 +286,10 @@ class Filter: return True if version.tags.has_platform_only_tags: return True + # Include all versions when targeting LLNDK because LLNDK symbols are self-versioned. + # Empty version block will be handled separately. + if self.llndk: + return False return self._should_omit_tags(version.tags) def should_omit_symbol(self, symbol: Symbol) -> bool: @@ -278,6 +316,14 @@ def symbol_in_arch(tags: Tags, arch: Arch) -> bool: # for the tagged architectures. return not has_arch_tags +def symbol_in_llndk_api(tags: Iterable[Tag], arch: Arch, api: int) -> bool: + """Returns true if the symbol is present for the given LLNDK API level.""" + # Check llndk= first. + for tag in tags: + if tag.startswith('llndk='): + return api >= int(get_tag_value(tag)) + # If not, we keep old behavior: NDK symbols in <= 34 are LLNDK symbols. + return symbol_in_api(tags, arch, 34) def symbol_in_api(tags: Iterable[Tag], arch: Arch, api: int) -> bool: """Returns true if the symbol is present for the given API level.""" @@ -354,6 +400,7 @@ class SymbolFileParser: f'Unexpected contents at top level: {self.current_line}') self.check_no_duplicate_symbols(versions) + self.check_llndk_introduced(versions) return versions def check_no_duplicate_symbols(self, versions: Iterable[Version]) -> None: @@ -382,6 +429,31 @@ class SymbolFileParser: raise MultiplyDefinedSymbolError( sorted(list(multiply_defined_symbols))) + def check_llndk_introduced(self, versions: Iterable[Version]) -> None: + """Raises errors when llndk= is missing for new llndk symbols.""" + if not self.filter.llndk: + return + + def assert_llndk_with_version(tags: Tags, name: str) -> None: + has_llndk_introduced = False + for tag in tags: + if tag.startswith('llndk='): + has_llndk_introduced = True + break + if not has_llndk_introduced: + raise ParseError(f'{name}: missing version. `llndk=yyyymm`') + + arch = self.filter.arch + for version in versions: + # llndk symbols >= introduced=35 should be tagged + # explicitly with llndk=yyyymm. + for symbol in version.symbols: + if not symbol.tags.has_llndk_tags: + continue + if symbol_in_api(symbol.tags, arch, 34): + continue + assert_llndk_with_version(symbol.tags, symbol.name) + def parse_version(self) -> Version: """Parses a single version section and returns a Version object.""" assert self.current_line is not None @@ -415,7 +487,9 @@ class SymbolFileParser: else: raise ParseError('Unknown visiblity label: ' + visibility) elif global_scope and not cpp_symbols: - symbols.append(self.parse_symbol()) + symbol = self.parse_symbol() + symbol.tags.copy_introduced_from(tags) + symbols.append(symbol) else: # We're in a hidden scope or in 'extern "C++"' block. Ignore # everything. diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py index 856b9d76b..8b412b98a 100644 --- a/cc/symbolfile/test_symbolfile.py +++ b/cc/symbolfile/test_symbolfile.py @@ -40,10 +40,20 @@ class TagsTest(unittest.TestCase): self.assertEqual(Tags(), symbolfile.get_tags('foo bar baz', {})) def test_get_tags(self) -> None: - self.assertEqual(Tags.from_strs(['foo', 'bar']), - symbolfile.get_tags('# foo bar', {})) - self.assertEqual(Tags.from_strs(['bar', 'baz']), - symbolfile.get_tags('foo # bar baz', {})) + self.assertEqual(Tags.from_strs(['llndk', 'apex']), + symbolfile.get_tags('# llndk apex', {})) + self.assertEqual(Tags.from_strs(['llndk', 'apex']), + symbolfile.get_tags('foo # llndk apex', {})) + + def test_get_unrecognized_tags(self) -> None: + with self.assertRaises(symbolfile.ParseError): + symbolfile.get_tags('# bar', {}) + with self.assertRaises(symbolfile.ParseError): + symbolfile.get_tags('foo # bar', {}) + with self.assertRaises(symbolfile.ParseError): + symbolfile.get_tags('# #', {}) + with self.assertRaises(symbolfile.ParseError): + symbolfile.get_tags('# apex # llndk', {}) def test_split_tag(self) -> None: self.assertTupleEqual(('foo', 'bar'), @@ -334,6 +344,45 @@ class OmitSymbolTest(unittest.TestCase): self.assertInclude(f_llndk, s_none) self.assertInclude(f_llndk, s_llndk) + def test_omit_llndk_versioned(self) -> None: + f_ndk = self.filter + f_ndk.api = 35 + + f_llndk = copy(f_ndk) + f_llndk.llndk = True + f_llndk.api = 202404 + + s = Symbol('foo', Tags()) + s_llndk = Symbol('foo', Tags.from_strs(['llndk'])) + s_llndk_202404 = Symbol('foo', Tags.from_strs(['llndk=202404'])) + s_34 = Symbol('foo', Tags.from_strs(['introduced=34'])) + s_34_llndk = Symbol('foo', Tags.from_strs(['introduced=34', 'llndk'])) + s_35 = Symbol('foo', Tags.from_strs(['introduced=35'])) + s_35_llndk_202404 = Symbol('foo', Tags.from_strs(['introduced=35', 'llndk=202404'])) + s_35_llndk_202504 = Symbol('foo', Tags.from_strs(['introduced=35', 'llndk=202504'])) + + # When targeting NDK, omit LLNDK tags + self.assertInclude(f_ndk, s) + self.assertOmit(f_ndk, s_llndk) + self.assertOmit(f_ndk, s_llndk_202404) + self.assertInclude(f_ndk, s_34) + self.assertOmit(f_ndk, s_34_llndk) + self.assertInclude(f_ndk, s_35) + self.assertOmit(f_ndk, s_35_llndk_202404) + self.assertOmit(f_ndk, s_35_llndk_202504) + + # When targeting LLNDK, old symbols without any mode tags are included as LLNDK + self.assertInclude(f_llndk, s) + # When targeting LLNDK, old symbols with #llndk are included as LLNDK + self.assertInclude(f_llndk, s_llndk) + self.assertInclude(f_llndk, s_llndk_202404) + self.assertInclude(f_llndk, s_34) + self.assertInclude(f_llndk, s_34_llndk) + # When targeting LLNDK, new symbols(>=35) should be tagged with llndk-introduced=. + self.assertOmit(f_llndk, s_35) + self.assertInclude(f_llndk, s_35_llndk_202404) + self.assertOmit(f_llndk, s_35_llndk_202504) + def test_omit_apex(self) -> None: f_none = self.filter f_apex = copy(f_none) @@ -425,13 +474,13 @@ class SymbolFileParseTest(unittest.TestCase): def test_parse_version(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ - VERSION_1 { # foo bar + VERSION_1 { # weak introduced=35 baz; - qux; # woodly doodly + qux; # apex llndk }; VERSION_2 { - } VERSION_1; # asdf + } VERSION_1; # not-a-tag """)) parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) @@ -439,11 +488,14 @@ class SymbolFileParseTest(unittest.TestCase): version = parser.parse_version() self.assertEqual('VERSION_1', version.name) self.assertIsNone(version.base) - self.assertEqual(Tags.from_strs(['foo', 'bar']), version.tags) + self.assertEqual(Tags.from_strs(['weak', 'introduced=35']), version.tags) + # Inherit introduced= tags from version block so that + # should_omit_tags() can differently based on introduced API level when treating + # LLNDK-available symbols. expected_symbols = [ - Symbol('baz', Tags()), - Symbol('qux', Tags.from_strs(['woodly', 'doodly'])), + Symbol('baz', Tags.from_strs(['introduced=35'])), + Symbol('qux', Tags.from_strs(['apex', 'llndk', 'introduced=35'])), ] self.assertEqual(expected_symbols, version.symbols) @@ -476,7 +528,7 @@ class SymbolFileParseTest(unittest.TestCase): def test_parse_symbol(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ foo; - bar; # baz qux + bar; # llndk apex """)) parser = symbolfile.SymbolFileParser(input_file, {}, self.filter) @@ -488,7 +540,7 @@ class SymbolFileParseTest(unittest.TestCase): parser.next_line() symbol = parser.parse_symbol() self.assertEqual('bar', symbol.name) - self.assertEqual(Tags.from_strs(['baz', 'qux']), symbol.tags) + self.assertEqual(Tags.from_strs(['llndk', 'apex']), symbol.tags) def test_wildcard_symbol_global(self) -> None: input_file = io.StringIO(textwrap.dedent("""\ @@ -537,13 +589,13 @@ class SymbolFileParseTest(unittest.TestCase): hidden1; global: foo; - bar; # baz + bar; # llndk }; - VERSION_2 { # wasd + VERSION_2 { # weak # Implicit global scope. woodly; - doodly; # asdf + doodly; # llndk local: qwerty; } VERSION_1; @@ -554,12 +606,12 @@ class SymbolFileParseTest(unittest.TestCase): expected = [ symbolfile.Version('VERSION_1', None, Tags(), [ Symbol('foo', Tags()), - Symbol('bar', Tags.from_strs(['baz'])), + Symbol('bar', Tags.from_strs(['llndk'])), ]), symbolfile.Version( - 'VERSION_2', 'VERSION_1', Tags.from_strs(['wasd']), [ + 'VERSION_2', 'VERSION_1', Tags.from_strs(['weak']), [ Symbol('woodly', Tags()), - Symbol('doodly', Tags.from_strs(['asdf'])), + Symbol('doodly', Tags.from_strs(['llndk'])), ]), ] @@ -591,6 +643,19 @@ class SymbolFileParseTest(unittest.TestCase): ] self.assertEqual(expected_symbols, version.symbols) + def test_parse_llndk_version_is_missing(self) -> None: + input_file = io.StringIO(textwrap.dedent("""\ + VERSION_1 { # introduced=35 + foo; + bar; # llndk + }; + """)) + f = copy(self.filter) + f.llndk = True + parser = symbolfile.SymbolFileParser(input_file, {}, f) + with self.assertRaises(symbolfile.ParseError): + parser.parse() + def main() -> None: suite = unittest.TestLoader().loadTestsFromName(__name__) diff --git a/cc/sysprop.go b/cc/sysprop.go deleted file mode 100644 index 0df290afa..000000000 --- a/cc/sysprop.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// 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 ( - "android/soong/android" - "android/soong/bazel" -) - -// TODO(b/240463568): Additional properties will be added for API validation -type bazelSyspropLibraryAttributes struct { - Srcs bazel.LabelListAttribute - Tags bazel.StringListAttribute -} - -type bazelCcSyspropLibraryAttributes struct { - Dep bazel.LabelAttribute - Min_sdk_version *string - Tags bazel.StringListAttribute -} - -type SyspropLibraryLabels struct { - SyspropLibraryLabel string - SharedLibraryLabel string - StaticLibraryLabel string -} - -func Bp2buildSysprop(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, srcs bazel.LabelListAttribute, minSdkVersion *string) { - apexAvailableTags := android.ApexAvailableTags(ctx.Module()) - ctx.CreateBazelTargetModule( - bazel.BazelTargetModuleProperties{ - Rule_class: "sysprop_library", - Bzl_load_location: "//build/bazel/rules/sysprop:sysprop_library.bzl", - }, - android.CommonAttributes{Name: labels.SyspropLibraryLabel}, - &bazelSyspropLibraryAttributes{ - Srcs: srcs, - Tags: apexAvailableTags, - }, - ) - - attrs := &bazelCcSyspropLibraryAttributes{ - Dep: *bazel.MakeLabelAttribute(":" + labels.SyspropLibraryLabel), - Min_sdk_version: minSdkVersion, - Tags: apexAvailableTags, - } - - if labels.SharedLibraryLabel != "" { - ctx.CreateBazelTargetModule( - bazel.BazelTargetModuleProperties{ - Rule_class: "cc_sysprop_library_shared", - Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl", - }, - android.CommonAttributes{Name: labels.SharedLibraryLabel}, - attrs) - } - - ctx.CreateBazelTargetModule( - bazel.BazelTargetModuleProperties{ - Rule_class: "cc_sysprop_library_static", - Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl", - }, - android.CommonAttributes{Name: labels.StaticLibraryLabel}, - attrs) -} diff --git a/cc/test.go b/cc/test.go index 3f5f71007..f5bb7610c 100644 --- a/cc/test.go +++ b/cc/test.go @@ -15,15 +15,11 @@ package cc import ( + "github.com/google/blueprint/proptools" "path/filepath" "strconv" - "strings" - - "github.com/google/blueprint/proptools" "android/soong/android" - "android/soong/bazel" - "android/soong/bazel/cquery" "android/soong/tradefed" ) @@ -77,13 +73,9 @@ type TestOptions struct { } type TestBinaryProperties struct { - // Create a separate binary for each source file. Useful when there is - // global state that can not be torn down and reset between each test suite. - Test_per_src *bool - // Disables the creation of a test-specific directory when used with // relative_install_path. Useful if several tests need to be in the same - // directory, but test_per_src doesn't work. + // directory. No_named_install_directory *bool // list of files or filegroup modules that provide data that should be installed alongside @@ -139,8 +131,7 @@ func init() { // specific functionality on a device. The executable binary gets an implicit // static_libs dependency on libgtests unless the gtest flag is set to false. func TestFactory() android.Module { - module := NewTest(android.HostAndDeviceSupported, true) - module.bazelHandler = &ccTestBazelHandler{module: module} + module := NewTest(android.HostAndDeviceSupported) return module.Init() } @@ -158,12 +149,13 @@ func TestLibraryFactory() android.Module { // binary. func BenchmarkFactory() android.Module { module := NewBenchmark(android.HostAndDeviceSupported) + module.testModule = true return module.Init() } // cc_test_host compiles a test host binary. func TestHostFactory() android.Module { - module := NewTest(android.HostSupported, true) + module := NewTest(android.HostSupported) return module.Init() } @@ -176,86 +168,14 @@ func BenchmarkHostFactory() android.Module { return module.Init() } -type testPerSrc interface { - testPerSrc() bool - srcs() []string - isAllTestsVariation() bool - setSrc(string, string) - unsetSrc() -} - -func (test *testBinary) testPerSrc() bool { - return Bool(test.Properties.Test_per_src) -} - -func (test *testBinary) srcs() []string { - return test.baseCompiler.Properties.Srcs -} - func (test *testBinary) dataPaths() []android.DataPath { return test.data } -func (test *testBinary) isAllTestsVariation() bool { - stem := test.binaryDecorator.Properties.Stem - return stem != nil && *stem == "" -} - -func (test *testBinary) setSrc(name, src string) { - test.baseCompiler.Properties.Srcs = []string{src} - test.binaryDecorator.Properties.Stem = StringPtr(name) -} - -func (test *testBinary) unsetSrc() { - test.baseCompiler.Properties.Srcs = nil - test.binaryDecorator.Properties.Stem = StringPtr("") -} - func (test *testBinary) testBinary() bool { return true } -var _ testPerSrc = (*testBinary)(nil) - -func TestPerSrcMutator(mctx android.BottomUpMutatorContext) { - if m, ok := mctx.Module().(*Module); ok { - if test, ok := m.linker.(testPerSrc); ok { - numTests := len(test.srcs()) - if test.testPerSrc() && numTests > 0 { - if duplicate, found := android.CheckDuplicate(test.srcs()); found { - mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate) - return - } - testNames := make([]string, numTests) - for i, src := range test.srcs() { - testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src)) - } - // In addition to creating one variation per test source file, - // create an additional "all tests" variation named "", and have it - // depends on all other test_per_src variations. This is useful to - // create subsequent dependencies of a given module on all - // test_per_src variations created above: by depending on - // variation "", that module will transitively depend on all the - // other test_per_src variations without the need to know their - // name or even their number. - testNames = append(testNames, "") - tests := mctx.CreateLocalVariations(testNames...) - allTests := tests[numTests] - allTests.(*Module).linker.(testPerSrc).unsetSrc() - // Prevent the "all tests" variation from being installable nor - // exporting to Make, as it won't create any output file. - allTests.(*Module).Properties.PreventInstall = true - allTests.(*Module).Properties.HideFromMake = true - for i, src := range test.srcs() { - tests[i].(*Module).linker.(testPerSrc).setSrc(testNames[i], src) - mctx.AddInterVariantDependency(testPerSrcDepTag, allTests, tests[i]) - } - mctx.AliasVariation("") - } - } - } -} - type testDecorator struct { LinkerProperties TestLinkerProperties InstallerProperties TestInstallerProperties @@ -267,7 +187,7 @@ func (test *testDecorator) gtest() bool { return BoolDefault(test.LinkerProperties.Gtest, true) } -func (test *testDecorator) isolated(ctx BaseModuleContext) bool { +func (test *testDecorator) isolated(ctx android.EarlyModuleContext) bool { return BoolDefault(test.LinkerProperties.Isolated, false) } @@ -323,6 +243,13 @@ func (test *testDecorator) installerProps() []interface{} { return []interface{}{&test.InstallerProperties} } +func (test *testDecorator) moduleInfoJSON(ctx android.ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + if android.PrefixInList(moduleInfoJSON.CompatibilitySuites, "mts-") && + !android.InList("mts", moduleInfoJSON.CompatibilitySuites) { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "mts") + } +} + func NewTestInstaller() *baseInstaller { return NewBaseInstaller("nativetest", "nativetest64", InstallInData) } @@ -354,9 +281,43 @@ func (test *testBinary) linkerDeps(ctx DepsContext, deps Deps) Deps { func (test *testBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { flags = test.binaryDecorator.linkerFlags(ctx, flags) flags = test.testDecorator.linkerFlags(ctx, flags) + + // Add a default rpath to allow tests to dlopen libraries specified in data_libs. + // Host modules already get an rpath specified in linker.go. + if !ctx.Host() { + flags.Global.LdFlags = append(flags.Global.LdFlags, `-Wl,-rpath,\$$ORIGIN`) + } return flags } +func (test *testBinary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + if ctx.Host() && Bool(test.Properties.Test_options.Unit_test) { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests") + } + moduleInfoJSON.TestOptionsTags = append(moduleInfoJSON.TestOptionsTags, test.Properties.Test_options.Tags...) + moduleInfoJSON.TestMainlineModules = append(moduleInfoJSON.TestMainlineModules, test.Properties.Test_mainline_modules...) + if test.testConfig != nil { + if _, ok := test.testConfig.(android.WritablePath); ok { + moduleInfoJSON.AutoTestConfig = []string{"true"} + } + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, test.testConfig.String()) + } + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, test.extraTestConfigs.Strings()...) + + moduleInfoJSON.DataDependencies = append(moduleInfoJSON.DataDependencies, test.Properties.Data_bins...) + + if len(test.InstallerProperties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, test.InstallerProperties.Test_suites...) + } else { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") + } + + test.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON) + test.testDecorator.moduleInfoJSON(ctx, moduleInfoJSON) + moduleInfoJSON.Class = []string{"NATIVE_TESTS"} + +} + func (test *testBinary) installerProps() []interface{} { return append(test.baseInstaller.installerProps(), test.testDecorator.installerProps()...) } @@ -393,9 +354,8 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { } }) - useVendor := ctx.inVendor() || ctx.useVndk() - testInstallBase := getTestInstallBase(useVendor) - configs := getTradefedConfigOptions(ctx, &test.Properties, test.isolated(ctx)) + testInstallBase := getTestInstallBase(ctx.InVendorOrProduct()) + configs := getTradefedConfigOptions(ctx, &test.Properties, test.isolated(ctx), ctx.Device()) test.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{ TestConfigProp: test.Properties.Test_config, @@ -423,6 +383,8 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { if ctx.Host() && test.gtest() && test.Properties.Test_options.Unit_test == nil { test.Properties.Test_options.Unit_test = proptools.BoolPtr(true) } + + test.binaryDecorator.baseInstaller.installTestData(ctx, test.data) test.binaryDecorator.baseInstaller.install(ctx, file) } @@ -435,22 +397,24 @@ func getTestInstallBase(useVendor bool) string { return testInstallBase } -func getTradefedConfigOptions(ctx android.EarlyModuleContext, properties *TestBinaryProperties, isolated bool) []tradefed.Config { +func getTradefedConfigOptions(ctx android.EarlyModuleContext, properties *TestBinaryProperties, isolated bool, device bool) []tradefed.Config { var configs []tradefed.Config for _, module := range properties.Test_mainline_modules { configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: "mainline-param", Value: module}) } - if Bool(properties.Require_root) { - configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil}) - } else { - var options []tradefed.Option - options = append(options, tradefed.Option{Name: "force-root", Value: "false"}) - configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options}) - } - if Bool(properties.Disable_framework) { - var options []tradefed.Option - configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.StopServicesSetup", options}) + if device { + if Bool(properties.Require_root) { + configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil}) + } else { + var options []tradefed.Option + options = append(options, tradefed.Option{Name: "force-root", Value: "false"}) + configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options}) + } + if Bool(properties.Disable_framework) { + var options []tradefed.Option + configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.StopServicesSetup", options}) + } } if isolated { configs = append(configs, tradefed.Option{Name: "not-shardable", Value: "true"}) @@ -483,10 +447,10 @@ func getTradefedConfigOptions(ctx android.EarlyModuleContext, properties *TestBi return configs } -func NewTest(hod android.HostOrDeviceSupported, bazelable bool) *Module { - module, binary := newBinary(hod, bazelable) - module.bazelable = bazelable +func NewTest(hod android.HostOrDeviceSupported) *Module { + module, binary := newBinary(hod) module.multilib = android.MultilibBoth + module.testModule = true binary.baseInstaller = NewTestInstaller() test := &testBinary{ @@ -530,6 +494,15 @@ func (test *testLibrary) linkerFlags(ctx ModuleContext, flags Flags) Flags { return flags } +func (test *testLibrary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + if len(test.InstallerProperties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, test.InstallerProperties.Test_suites...) + } + + test.libraryDecorator.moduleInfoJSON(ctx, moduleInfoJSON) + test.testDecorator.moduleInfoJSON(ctx, moduleInfoJSON) +} + func (test *testLibrary) installerProps() []interface{} { return append(test.baseInstaller.installerProps(), test.testDecorator.installerProps()...) } @@ -546,7 +519,6 @@ func NewTestLibrary(hod android.HostOrDeviceSupported) *Module { } module.linker = test module.installer = test - module.bazelable = true return module } @@ -580,7 +552,7 @@ type BenchmarkProperties struct { type benchmarkDecorator struct { *binaryDecorator Properties BenchmarkProperties - data android.Paths + data []android.DataPath testConfig android.Path } @@ -601,7 +573,9 @@ func (benchmark *benchmarkDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps } func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Path) { - benchmark.data = android.PathsForModuleSrc(ctx, benchmark.Properties.Data) + for _, d := range android.PathsForModuleSrc(ctx, benchmark.Properties.Data) { + benchmark.data = append(benchmark.data, android.DataPath{SrcPath: d}) + } var configs []tradefed.Config if Bool(benchmark.Properties.Require_root) { @@ -619,131 +593,42 @@ func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Pat benchmark.binaryDecorator.baseInstaller.dir = filepath.Join("benchmarktest", ctx.ModuleName()) benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("benchmarktest64", ctx.ModuleName()) + benchmark.binaryDecorator.baseInstaller.installTestData(ctx, benchmark.data) benchmark.binaryDecorator.baseInstaller.install(ctx, file) } -func NewBenchmark(hod android.HostOrDeviceSupported) *Module { - module, binary := newBinary(hod, false) - module.multilib = android.MultilibBoth - binary.baseInstaller = NewBaseInstaller("benchmarktest", "benchmarktest64", InstallInData) +func (benchmark *benchmarkDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + benchmark.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON) - benchmark := &benchmarkDecorator{ - binaryDecorator: binary, - } - module.linker = benchmark - module.installer = benchmark - return module -} - -type ccTestBazelHandler struct { - module *Module -} - -var _ BazelHandler = (*ccTestBazelHandler)(nil) - -func (handler *ccTestBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) { - bazelCtx := ctx.Config().BazelContext - bazelCtx.QueueBazelRequest(label, cquery.GetCcUnstrippedInfo, android.GetConfigKey(ctx)) -} - -func (handler *ccTestBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) { - bazelCtx := ctx.Config().BazelContext - info, err := bazelCtx.GetCcUnstrippedInfo(label, android.GetConfigKey(ctx)) - if err != nil { - ctx.ModuleErrorf(err.Error()) - return + moduleInfoJSON.Class = []string{"NATIVE_TESTS"} + if len(benchmark.Properties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, benchmark.Properties.Test_suites...) + } else { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") } - var outputFilePath android.Path = android.PathForBazelOut(ctx, info.OutputFile) - if len(info.TidyFiles) > 0 { - handler.module.tidyFiles = android.PathsForBazelOut(ctx, info.TidyFiles) - outputFilePath = android.AttachValidationActions(ctx, outputFilePath, handler.module.tidyFiles) + if android.PrefixInList(moduleInfoJSON.CompatibilitySuites, "mts-") && + !android.InList("mts", moduleInfoJSON.CompatibilitySuites) { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "mts") } - handler.module.outputFile = android.OptionalPathForPath(outputFilePath) - handler.module.linker.(*testBinary).unstrippedOutputFile = android.PathForBazelOut(ctx, info.UnstrippedOutput) - handler.module.setAndroidMkVariablesFromCquery(info.CcAndroidMkInfo) -} - -// binaryAttributes contains Bazel attributes corresponding to a cc test -type testBinaryAttributes struct { - binaryAttributes - - Gtest bool - Isolated bool - - tidyAttributes - tradefed.TestConfigAttributes -} - -// testBinaryBp2build is the bp2build converter for cc_test modules. A cc_test's -// dependency graph and compilation/linking steps are functionally similar to a -// cc_binary, but has additional dependencies on test deps like gtest, and -// produces additional runfiles like XML plans for Tradefed orchestration -// -// TODO(b/244432609): handle `isolated` property. -// TODO(b/244432134): handle custom runpaths for tests that assume runfile layouts not -// default to bazel. (see linkerInit function) -func testBinaryBp2build(ctx android.TopDownMutatorContext, m *Module) { - var testBinaryAttrs testBinaryAttributes - testBinaryAttrs.binaryAttributes = binaryBp2buildAttrs(ctx, m) - - var data bazel.LabelListAttribute - var tags bazel.StringListAttribute - - testBinaryProps := m.GetArchVariantProperties(ctx, &TestBinaryProperties{}) - for axis, configToProps := range testBinaryProps { - for config, props := range configToProps { - if p, ok := props.(*TestBinaryProperties); ok { - // Combine data, data_bins and data_libs into a single 'data' attribute. - var combinedData bazel.LabelList - combinedData.Append(android.BazelLabelForModuleSrc(ctx, p.Data)) - combinedData.Append(android.BazelLabelForModuleDeps(ctx, p.Data_bins)) - combinedData.Append(android.BazelLabelForModuleDeps(ctx, p.Data_libs)) - data.SetSelectValue(axis, config, combinedData) - tags.SetSelectValue(axis, config, p.Test_options.Tags) - } + if benchmark.testConfig != nil { + if _, ok := benchmark.testConfig.(android.WritablePath); ok { + moduleInfoJSON.AutoTestConfig = []string{"true"} } + moduleInfoJSON.TestConfig = []string{benchmark.testConfig.String()} } +} - m.convertTidyAttributes(ctx, &testBinaryAttrs.tidyAttributes) - - for _, propIntf := range m.GetProperties() { - if testLinkerProps, ok := propIntf.(*TestLinkerProperties); ok { - testBinaryAttrs.Gtest = proptools.BoolDefault(testLinkerProps.Gtest, true) - testBinaryAttrs.Isolated = proptools.BoolDefault(testLinkerProps.Isolated, true) - break - } - } +func NewBenchmark(hod android.HostOrDeviceSupported) *Module { + module, binary := newBinary(hod) + module.multilib = android.MultilibBoth + binary.baseInstaller = NewBaseInstaller("benchmarktest", "benchmarktest64", InstallInData) - for _, testProps := range m.GetProperties() { - if p, ok := testProps.(*TestBinaryProperties); ok { - useVendor := false // TODO Bug: 262914724 - testInstallBase := getTestInstallBase(useVendor) - testConfigAttributes := tradefed.GetTestConfigAttributes( - ctx, - p.Test_config, - p.Test_options.Extra_test_configs, - p.Auto_gen_config, - p.Test_options.Test_suite_tag, - p.Test_config_template, - getTradefedConfigOptions(ctx, p, testBinaryAttrs.Isolated), - &testInstallBase, - ) - testBinaryAttrs.TestConfigAttributes = testConfigAttributes - } + benchmark := &benchmarkDecorator{ + binaryDecorator: binary, } - - // TODO (b/262914724): convert to tradefed_cc_test and tradefed_cc_test_host - ctx.CreateBazelTargetModule( - bazel.BazelTargetModuleProperties{ - Rule_class: "cc_test", - Bzl_load_location: "//build/bazel/rules/cc:cc_test.bzl", - }, - android.CommonAttributes{ - Name: m.Name(), - Data: data, - Tags: tags, - }, - &testBinaryAttrs) + module.linker = benchmark + module.installer = benchmark + return module } diff --git a/cc/testing.go b/cc/testing.go index ced09290f..02f992426 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -15,14 +15,12 @@ package cc import ( - "encoding/json" "path/filepath" "testing" "android/soong/android" "android/soong/genrule" "android/soong/multitree" - "android/soong/snapshot" ) func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { @@ -35,13 +33,15 @@ func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { multitree.RegisterApiImportsModule(ctx) + ctx.RegisterModuleType("prebuilt_build_tool", android.NewPrebuiltBuildTool) ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory) + ctx.RegisterModuleType("cc_cmake_snapshot", CmakeSnapshotFactory) ctx.RegisterModuleType("cc_object", ObjectFactory) ctx.RegisterModuleType("cc_genrule", GenRuleFactory) ctx.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory) ctx.RegisterModuleType("ndk_prebuilt_static_stl", NdkPrebuiltStaticStlFactory) ctx.RegisterModuleType("ndk_library", NdkLibraryFactory) - ctx.RegisterModuleType("ndk_headers", ndkHeadersFactory) + ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory) } func GatherRequiredDepsForTest(oses ...android.OsType) string { @@ -76,12 +76,17 @@ func commonDefaultModules() string { no_libcrt: true, sdk_version: "minimum", nocrt: true, + no_crt_pad_segment: true, system_shared_libs: [], stl: "none", check_elf_files: false, sanitize: { never: true, }, + apex_available: [ + "//apex_available:anyapex", + "//apex_available:platform", + ], } cc_prebuilt_library_static { @@ -295,14 +300,12 @@ func commonDefaultModules() string { system_shared_libs: [], stl: "none", vendor_available: true, + vendor_ramdisk_available: true, product_available: true, recovery_available: true, host_supported: true, min_sdk_version: "29", - vndk: { - enabled: true, - support_system_process: true, - }, + double_loadable: true, apex_available: [ "//apex_available:platform", "//apex_available:anyapex", @@ -380,6 +383,11 @@ func commonDefaultModules() string { } cc_object { + name: "crt_pad_segment", + defaults: ["crt_defaults"], + } + + cc_object { name: "crtbrand", defaults: ["crt_defaults"], srcs: ["crtbrand.c"], @@ -419,11 +427,6 @@ func commonDefaultModules() string { export_include_dirs: ["ndk_libc++_shared"], } - ndk_prebuilt_static_stl { - name: "ndk_libandroid_support", - export_include_dirs: ["ndk_libandroid_support"], - } - cc_library_static { name: "libgoogle-benchmark", sdk_version: "current", @@ -552,14 +555,14 @@ var PrepareForTestWithCcBuildComponents = android.GroupFixturePreparers( ctx.RegisterModuleType("cc_test_library", TestLibraryFactory) ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory) - RegisterVndkLibraryTxtTypes(ctx) + RegisterLlndkLibraryTxtType(ctx) }), // Additional files needed in tests that disallow non-existent source files. // This includes files that are needed by all, or at least most, instances of a cc module type. android.MockFS{ // Needed for ndk_prebuilt_(shared|static)_stl. - "prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs": nil, + "defaults/cc/common/current/sources/cxx-stl/llvm-libc++/libs": nil, }.AddToFixture(), ) @@ -569,16 +572,17 @@ var PrepareForTestWithCcDefaultModules = android.GroupFixturePreparers( // Additional files needed in tests that disallow non-existent source. android.MockFS{ - "defaults/cc/common/libc.map.txt": nil, - "defaults/cc/common/libdl.map.txt": nil, - "defaults/cc/common/libm.map.txt": nil, - "defaults/cc/common/ndk_libandroid_support": nil, - "defaults/cc/common/ndk_libc++_shared": nil, - "defaults/cc/common/crtbegin_so.c": nil, - "defaults/cc/common/crtbegin.c": nil, - "defaults/cc/common/crtend_so.c": nil, - "defaults/cc/common/crtend.c": nil, - "defaults/cc/common/crtbrand.c": nil, + "defaults/cc/common/libc.map.txt": nil, + "defaults/cc/common/libdl.map.txt": nil, + "defaults/cc/common/libft2.map.txt": nil, + "defaults/cc/common/libm.map.txt": nil, + "defaults/cc/common/ndk_libc++_shared": nil, + "defaults/cc/common/crtbegin_so.c": nil, + "defaults/cc/common/crtbegin.c": nil, + "defaults/cc/common/crtend_so.c": nil, + "defaults/cc/common/crtend.c": nil, + "defaults/cc/common/crtbrand.c": nil, + "external/compiler-rt/lib/cfi/cfi_blocklist.txt": nil, "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm64.a": nil, "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm.a": nil, @@ -618,19 +622,6 @@ var PrepareForTestOnLinuxBionic = android.GroupFixturePreparers( android.FixtureOverrideTextFile(linuxBionicDefaultsPath, withLinuxBionic()), ) -// This adds some additional modules and singletons which might negatively impact the performance -// of tests so they are not included in the PrepareForIntegrationTestWithCc. -var PrepareForTestWithCcIncludeVndk = android.GroupFixturePreparers( - PrepareForIntegrationTestWithCc, - android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { - snapshot.VendorSnapshotImageSingleton.Init(ctx) - snapshot.RecoverySnapshotImageSingleton.Init(ctx) - RegisterVendorSnapshotModules(ctx) - RegisterRecoverySnapshotModules(ctx) - ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton) - }), -) - // PrepareForTestWithHostMusl sets the host configuration to musl libc instead of glibc. It also disables the test // on mac, which doesn't support musl libc, and adds musl modules. var PrepareForTestWithHostMusl = android.GroupFixturePreparers( @@ -673,7 +664,7 @@ var PrepareForTestWithHostMusl = android.GroupFixturePreparers( // PrepareForTestWithFdoProfile registers module types to test with fdo_profile var PrepareForTestWithFdoProfile = android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { ctx.RegisterModuleType("soong_namespace", android.NamespaceFactory) - ctx.RegisterModuleType("fdo_profile", fdoProfileFactory) + ctx.RegisterModuleType("fdo_profile", FdoProfileFactory) }) // TestConfig is the legacy way of creating a test Config for testing cc modules. @@ -712,12 +703,7 @@ func CreateTestContext(config android.Config) *android.TestContext { ctx.RegisterModuleType("filegroup", android.FileGroupFactory) ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory) - snapshot.VendorSnapshotImageSingleton.Init(ctx) - snapshot.RecoverySnapshotImageSingleton.Init(ctx) - RegisterVendorSnapshotModules(ctx) - RegisterRecoverySnapshotModules(ctx) - ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton) - RegisterVndkLibraryTxtTypes(ctx) + RegisterLlndkLibraryTxtType(ctx) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) android.RegisterPrebuiltMutators(ctx) @@ -770,14 +756,6 @@ func CheckSnapshotRule(t *testing.T, ctx *android.TestContext, singleton android checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true, true) } -func AssertExcludeFromVendorSnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool, variant string) { - t.Helper() - m := ctx.ModuleForTests(name, variant).Module().(LinkableInterface) - if m.ExcludeFromVendorSnapshot() != expected { - t.Errorf("expected %q ExcludeFromVendorSnapshot to be %t", m.String(), expected) - } -} - func GetOutputPaths(ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) { for _, moduleName := range moduleNames { module := ctx.ModuleForTests(moduleName, variant).Module().(*Module) @@ -786,30 +764,3 @@ func GetOutputPaths(ctx *android.TestContext, variant string, moduleNames []stri } return paths } - -func AssertExcludeFromRecoverySnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool, variant string) { - t.Helper() - m := ctx.ModuleForTests(name, variant).Module().(LinkableInterface) - if m.ExcludeFromRecoverySnapshot() != expected { - t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", m.String(), expected) - } -} - -func checkOverrides(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, jsonPath string, expected []string) { - t.Helper() - out := singleton.MaybeOutput(jsonPath) - content := android.ContentFromFileRuleForTests(t, out) - - var flags snapshotJsonFlags - if err := json.Unmarshal([]byte(content), &flags); err != nil { - t.Errorf("Error while unmarshalling json %q: %s", jsonPath, err.Error()) - return - } - - for _, moduleName := range expected { - if !android.InList(moduleName, flags.Overrides) { - t.Errorf("expected %q to be in %q: %q", moduleName, flags.Overrides, content) - return - } - } -} diff --git a/cc/tidy.go b/cc/tidy.go index bbcaece24..ec1e8a206 100644 --- a/cc/tidy.go +++ b/cc/tidy.go @@ -68,7 +68,6 @@ func (tidy *tidyFeature) props() []interface{} { // Then, that old style usage will be obsolete and an error. const NoWarningsAsErrorsInTidyFlags = true -// keep this up to date with https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/cc/clang_tidy.bzl func (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags { CheckBadTidyFlags(ctx, "tidy_flags", tidy.Properties.Tidy_flags) CheckBadTidyChecks(ctx, "tidy_checks", tidy.Properties.Tidy_checks) @@ -201,7 +200,7 @@ func (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags { } func init() { - android.RegisterSingletonType("tidy_phony_targets", TidyPhonySingleton) + android.RegisterParallelSingletonType("tidy_phony_targets", TidyPhonySingleton) } // This TidyPhonySingleton generates both tidy-* and obj-* phony targets for C/C++ files. @@ -221,7 +220,7 @@ func collectTidyObjModuleTargets(ctx android.SingletonContext, module android.Mo // (1) Collect all obj/tidy files into OS-specific groups. ctx.VisitAllModuleVariants(module, func(variant android.Module) { - if ctx.Config().KatiEnabled() && android.ShouldSkipAndroidMkProcessing(variant) { + if ctx.Config().KatiEnabled() && android.ShouldSkipAndroidMkProcessing(ctx, variant) { return } if m, ok := variant.(*Module); ok { diff --git a/cc/tidy_test.go b/cc/tidy_test.go index 7036ecb1a..9481778a2 100644 --- a/cc/tidy_test.go +++ b/cc/tidy_test.go @@ -244,3 +244,30 @@ func TestWithTidy(t *testing.T) { }) } } + +func TestWithGeneratedCode(t *testing.T) { + bp := ` + cc_library_shared { + name: "libfoo", + srcs: ["foo_1.y", "foo_2.yy", "foo_3.l", "foo_4.ll", "foo_5.proto", + "foo_6.aidl", "foo_7.rscript", "foo_8.fs", "foo_9.sysprop", + "foo_src.cpp"], + tidy: true, + }` + variant := "android_arm64_armv8-a_shared" + + testEnv := map[string]string{} + testEnv["ALLOW_LOCAL_TIDY_TRUE"] = "1" + + ctx := android.GroupFixturePreparers(prepareForCcTest, android.FixtureMergeEnv(testEnv)).RunTestWithBp(t, bp) + + t.Run("tidy should be only run for source code, not for generated code", func(t *testing.T) { + depFiles := ctx.ModuleForTests("libfoo", variant).Rule("ld").Validations.Strings() + + tidyFileForCpp := "out/soong/.intermediates/libfoo/" + variant + "/obj/foo_src.tidy" + + android.AssertArrayString(t, + "only one .tidy file for source code should exist for libfoo", + []string{tidyFileForCpp}, depFiles) + }) +} diff --git a/cc/util.go b/cc/util.go index 6d8ac435f..8ffacae7d 100644 --- a/cc/util.go +++ b/cc/util.go @@ -19,7 +19,6 @@ import ( "strings" "android/soong/android" - "android/soong/snapshot" ) // Efficiently converts a list of include directories to a single string @@ -28,8 +27,8 @@ func includeDirsToFlags(dirs android.Paths) string { return android.JoinWithPrefix(dirs.Strings(), "-I") } -var indexList = android.IndexList -var inList = android.InList +var indexList = android.IndexList[string] +var inList = android.InList[string] var filterList = android.FilterList var removeListFromList = android.RemoveListFromList var removeFromList = android.RemoveFromList @@ -56,18 +55,20 @@ func flagsToBuilderFlags(in Flags) builderFlags { localCppFlags: strings.Join(in.Local.CppFlags, " "), localLdFlags: strings.Join(in.Local.LdFlags, " "), - aidlFlags: strings.Join(in.aidlFlags, " "), - rsFlags: strings.Join(in.rsFlags, " "), - libFlags: strings.Join(in.libFlags, " "), - extraLibFlags: strings.Join(in.extraLibFlags, " "), - tidyFlags: strings.Join(in.TidyFlags, " "), - sAbiFlags: strings.Join(in.SAbiFlags, " "), - toolchain: in.Toolchain, - gcovCoverage: in.GcovCoverage, - tidy: in.Tidy, - needTidyFiles: in.NeedTidyFiles, - sAbiDump: in.SAbiDump, - emitXrefs: in.EmitXrefs, + noOverrideFlags: strings.Join(in.NoOverrideFlags, " "), + aidlFlags: strings.Join(in.aidlFlags, " "), + rsFlags: strings.Join(in.rsFlags, " "), + libFlags: strings.Join(in.libFlags, " "), + extraLibFlags: strings.Join(in.extraLibFlags, " "), + tidyFlags: strings.Join(in.TidyFlags, " "), + sAbiFlags: strings.Join(in.SAbiFlags, " "), + toolchain: in.Toolchain, + gcovCoverage: in.GcovCoverage, + tidy: in.Tidy, + needTidyFiles: in.NeedTidyFiles, + sAbiDump: in.SAbiDump, + emitXrefs: in.EmitXrefs, + clangVerify: in.ClangVerify, systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "), @@ -100,6 +101,12 @@ func makeSymlinkCmd(linkDirOnDevice string, linkName string, target string) stri "ln -sf " + target + " " + filepath.Join(dir, linkName) } +func WriteStringToFileRule(ctx android.SingletonContext, content, out string) android.OutputPath { + outPath := android.PathForOutput(ctx, out) + android.WriteFileRule(ctx, outPath, content) + return outPath +} + // Dump a map to a list file as: // // {key1} {value1} @@ -115,5 +122,5 @@ func installMapListFileRule(ctx android.SingletonContext, m map[string]string, p txtBuilder.WriteString(" ") txtBuilder.WriteString(m[k]) } - return snapshot.WriteStringToFileRule(ctx, txtBuilder.String(), path) + return WriteStringToFileRule(ctx, txtBuilder.String(), path) } diff --git a/cc/vendor_public_library_test.go b/cc/vendor_public_library_test.go index 769be0973..7385f2b88 100644 --- a/cc/vendor_public_library_test.go +++ b/cc/vendor_public_library_test.go @@ -65,8 +65,8 @@ func TestVendorPublicLibraries(t *testing.T) { `) coreVariant := "android_arm64_armv8-a_shared" - vendorVariant := "android_vendor.29_arm64_armv8-a_shared" - productVariant := "android_product.29_arm64_armv8-a_shared" + vendorVariant := "android_vendor_arm64_armv8-a_shared" + productVariant := "android_product_arm64_armv8-a_shared" // test if header search paths are correctly added // _static variant is used since _shared reuses *.o from the static variant diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go deleted file mode 100644 index d2531c03d..000000000 --- a/cc/vendor_snapshot.go +++ /dev/null @@ -1,431 +0,0 @@ -// Copyright 2020 The Android Open Source Project -// -// 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 ( - "encoding/json" - "path/filepath" - "strings" - - "android/soong/android" - "android/soong/snapshot" -) - -// This file defines how to capture cc modules into snapshot package. - -// Checks if the target image would contain VNDK -func includeVndk(image snapshot.SnapshotImage) bool { - if image.ImageName() == snapshot.VendorSnapshotImageName { - return true - } - - return false -} - -// Check if the module is VNDK private -func isPrivate(image snapshot.SnapshotImage, m LinkableInterface) bool { - if image.ImageName() == snapshot.VendorSnapshotImageName && m.IsVndkPrivate() { - return true - } - - return false -} - -// Checks if target image supports VNDK Ext -func supportsVndkExt(image snapshot.SnapshotImage) bool { - if image.ImageName() == snapshot.VendorSnapshotImageName { - return true - } - - return false -} - -// Determines if the module is a candidate for snapshot. -func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietaryPath bool, apexInfo android.ApexInfo, image snapshot.SnapshotImage) bool { - if !m.Enabled() || m.HiddenFromMake() { - return false - } - // When android/prebuilt.go selects between source and prebuilt, it sets - // HideFromMake on the other one to avoid duplicate install rules in make. - if m.IsHideFromMake() { - return false - } - // skip proprietary modules, but (for the vendor snapshot only) - // include all VNDK (static) - if inProprietaryPath && (!includeVndk(image) || !m.IsVndk()) { - return false - } - // If the module would be included based on its path, check to see if - // the module is marked to be excluded. If so, skip it. - if image.ExcludeFromSnapshot(m) { - return false - } - if m.Target().Os.Class != android.Device { - return false - } - if m.Target().NativeBridge == android.NativeBridgeEnabled { - return false - } - // the module must be installed in target image - if !apexInfo.IsForPlatform() || m.IsSnapshotPrebuilt() || !image.InImage(m)() { - return false - } - // skip kernel_headers which always depend on vendor - if m.KernelHeadersDecorator() { - return false - } - - if m.IsLlndk() { - return false - } - - // Libraries - if sanitizable, ok := m.(PlatformSanitizeable); ok && sanitizable.IsSnapshotLibrary() { - if sanitizable.SanitizePropDefined() { - // scs exports both sanitized and unsanitized variants for static and header - // Always use unsanitized variant of it. - if !sanitizable.Shared() && sanitizable.IsSanitizerEnabled(scs) { - return false - } - // cfi and hwasan also export both variants. But for static, we capture both. - // This is because cfi static libraries can't be linked from non-cfi modules, - // and vice versa. - // hwasan is captured as well to support hwasan build. - if !sanitizable.Static() && - !sanitizable.Shared() && - (sanitizable.IsSanitizerEnabled(cfi) || sanitizable.IsSanitizerEnabled(Hwasan)) { - return false - } - } - if sanitizable.Static() { - return sanitizable.OutputFile().Valid() && !isPrivate(image, m) - } - if sanitizable.Shared() || sanitizable.Rlib() { - if !sanitizable.OutputFile().Valid() { - return false - } - if includeVndk(image) { - if !sanitizable.IsVndk() { - return true - } - return sanitizable.IsVndkExt() - } - } - return true - } - - // Binaries and Objects - if m.Binary() || m.Object() { - return m.OutputFile().Valid() - } - - return false -} - -// Extend the snapshot.SnapshotJsonFlags to include cc specific fields. -type snapshotJsonFlags struct { - snapshot.SnapshotJsonFlags - // library flags - ExportedDirs []string `json:",omitempty"` - ExportedSystemDirs []string `json:",omitempty"` - ExportedFlags []string `json:",omitempty"` - Sanitize string `json:",omitempty"` - SanitizeMinimalDep bool `json:",omitempty"` - SanitizeUbsanDep bool `json:",omitempty"` - - // binary flags - Symlinks []string `json:",omitempty"` - StaticExecutable bool `json:",omitempty"` - InstallInRoot bool `json:",omitempty"` - - // dependencies - SharedLibs []string `json:",omitempty"` - StaticLibs []string `json:",omitempty"` - RuntimeLibs []string `json:",omitempty"` - - // extra config files - InitRc []string `json:",omitempty"` - VintfFragments []string `json:",omitempty"` - MinSdkVersion string `json:",omitempty"` -} - -var ccSnapshotAction snapshot.GenerateSnapshotAction = func(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) snapshot.SnapshotPaths { - /* - Vendor snapshot zipped artifacts directory structure for cc modules: - {SNAPSHOT_ARCH}/ - arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/ - shared/ - (.so shared libraries) - static/ - (.a static libraries) - header/ - (header only libraries) - binary/ - (executable binaries) - object/ - (.o object files) - arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/ - shared/ - (.so shared libraries) - static/ - (.a static libraries) - header/ - (header only libraries) - binary/ - (executable binaries) - object/ - (.o object files) - NOTICE_FILES/ - (notice files, e.g. libbase.txt) - configs/ - (config files, e.g. init.rc files, vintf_fragments.xml files, etc.) - include/ - (header files of same directory structure with source tree) - */ - - var snapshotOutputs android.Paths - var snapshotNotices android.Paths - - includeDir := filepath.Join(snapshotArchDir, "include") - configsDir := filepath.Join(snapshotArchDir, "configs") - - installedNotices := make(map[string]bool) - installedConfigs := make(map[string]bool) - - var headers android.Paths - - copyFile := func(ctx android.SingletonContext, path android.Path, out string, fake bool) android.OutputPath { - if fake { - // All prebuilt binaries and headers are installed by copyFile function. This makes a fake - // snapshot just touch prebuilts and headers, rather than installing real files. - return snapshot.WriteStringToFileRule(ctx, "", out) - } else { - return snapshot.CopyFileRule(pctx, ctx, path, out) - } - } - - // installSnapshot function copies prebuilt file (.so, .a, or executable) and json flag file. - // For executables, init_rc and vintf_fragments files are also copied. - installSnapshot := func(m LinkableInterface, fake bool) android.Paths { - targetArch := "arch-" + m.Target().Arch.ArchType.String() - if m.Target().Arch.ArchVariant != "" { - targetArch += "-" + m.Target().Arch.ArchVariant - } - - var ret android.Paths - - prop := snapshotJsonFlags{} - - // Common properties among snapshots. - prop.InitBaseSnapshotPropsWithName(m, ctx.ModuleName(m)) - if supportsVndkExt(s.Image) && m.IsVndkExt() { - // vndk exts are installed to /vendor/lib(64)?/vndk(-sp)? - if m.IsVndkSp() { - prop.RelativeInstallPath = "vndk-sp" - } else { - prop.RelativeInstallPath = "vndk" - } - } else { - prop.RelativeInstallPath = m.RelativeInstallPath() - } - prop.RuntimeLibs = m.SnapshotRuntimeLibs() - prop.Required = m.RequiredModuleNames() - if o, ok := m.(overridable); ok { - prop.Overrides = o.overriddenModules() - } - for _, path := range m.InitRc() { - prop.InitRc = append(prop.InitRc, filepath.Join("configs", path.Base())) - } - for _, path := range m.VintfFragments() { - prop.VintfFragments = append(prop.VintfFragments, filepath.Join("configs", path.Base())) - } - if m.IsPrebuilt() { - prop.MinSdkVersion = "apex_inherit" - } else { - prop.MinSdkVersion = m.MinSdkVersion() - } - - // install config files. ignores any duplicates. - for _, path := range append(m.InitRc(), m.VintfFragments()...) { - out := filepath.Join(configsDir, path.Base()) - if !installedConfigs[out] { - installedConfigs[out] = true - ret = append(ret, copyFile(ctx, path, out, fake)) - } - } - - var propOut string - - if m.IsSnapshotLibrary() { - exporterInfo := ctx.ModuleProvider(m.Module(), FlagExporterInfoProvider).(FlagExporterInfo) - - // library flags - prop.ExportedFlags = exporterInfo.Flags - for _, dir := range exporterInfo.IncludeDirs { - prop.ExportedDirs = append(prop.ExportedDirs, filepath.Join("include", dir.String())) - } - for _, dir := range exporterInfo.SystemIncludeDirs { - prop.ExportedSystemDirs = append(prop.ExportedSystemDirs, filepath.Join("include", dir.String())) - } - - // shared libs dependencies aren't meaningful on static or header libs - if m.Shared() { - prop.SharedLibs = m.SnapshotSharedLibs() - } - // static libs dependencies are required to collect the NOTICE files. - prop.StaticLibs = m.SnapshotStaticLibs() - if sanitizable, ok := m.(PlatformSanitizeable); ok { - if sanitizable.Static() && sanitizable.SanitizePropDefined() { - prop.SanitizeMinimalDep = sanitizable.MinimalRuntimeDep() || sanitizable.MinimalRuntimeNeeded() - prop.SanitizeUbsanDep = sanitizable.UbsanRuntimeDep() || sanitizable.UbsanRuntimeNeeded() - } - } - - var libType string - if m.Static() { - libType = "static" - } else if m.Shared() { - libType = "shared" - } else if m.Rlib() { - libType = "rlib" - } else { - libType = "header" - } - - var stem string - - // install .a or .so - if libType != "header" { - libPath := m.OutputFile().Path() - stem = libPath.Base() - if sanitizable, ok := m.(PlatformSanitizeable); ok { - if (sanitizable.Static() || sanitizable.Rlib()) && sanitizable.SanitizePropDefined() { - if sanitizable.IsSanitizerEnabled(cfi) { - // both cfi and non-cfi variant for static libraries can exist. - // attach .cfi to distinguish between cfi and non-cfi. - // e.g. libbase.a -> libbase.cfi.a - ext := filepath.Ext(stem) - stem = strings.TrimSuffix(stem, ext) + ".cfi" + ext - prop.Sanitize = "cfi" - prop.ModuleName += ".cfi" - } else if sanitizable.IsSanitizerEnabled(Hwasan) { - // Same for the hwasan - ext := filepath.Ext(stem) - stem = strings.TrimSuffix(stem, ext) + ".hwasan" + ext - prop.Sanitize = "hwasan" - prop.ModuleName += ".hwasan" - } - } - } - snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, m.RelativeInstallPath(), stem) - ret = append(ret, copyFile(ctx, libPath, snapshotLibOut, fake)) - } else { - stem = ctx.ModuleName(m) - } - - propOut = filepath.Join(snapshotArchDir, targetArch, libType, m.RelativeInstallPath(), stem+".json") - } else if m.Binary() { - // binary flags - prop.Symlinks = m.Symlinks() - prop.StaticExecutable = m.StaticExecutable() - prop.InstallInRoot = m.InstallInRoot() - prop.SharedLibs = m.SnapshotSharedLibs() - // static libs dependencies are required to collect the NOTICE files. - prop.StaticLibs = m.SnapshotStaticLibs() - // install bin - binPath := m.OutputFile().Path() - snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base()) - ret = append(ret, copyFile(ctx, binPath, snapshotBinOut, fake)) - propOut = snapshotBinOut + ".json" - } else if m.Object() { - // object files aren't installed to the device, so their names can conflict. - // Use module name as stem. - objPath := m.OutputFile().Path() - snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object", - ctx.ModuleName(m)+filepath.Ext(objPath.Base())) - ret = append(ret, copyFile(ctx, objPath, snapshotObjOut, fake)) - propOut = snapshotObjOut + ".json" - } else { - ctx.Errorf("unknown module %q in vendor snapshot", m.String()) - return nil - } - - j, err := json.Marshal(prop) - if err != nil { - ctx.Errorf("json marshal to %q failed: %#v", propOut, err) - return nil - } - ret = append(ret, snapshot.WriteStringToFileRule(ctx, string(j), propOut)) - - return ret - } - - ctx.VisitAllModules(func(module android.Module) { - m, ok := module.(LinkableInterface) - if !ok { - return - } - - moduleDir := ctx.ModuleDir(module) - inProprietaryPath := s.Image.IsProprietaryPath(moduleDir, ctx.DeviceConfig()) - apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo) - - if s.Image.ExcludeFromSnapshot(m) { - if inProprietaryPath { - // Error: exclude_from_vendor_snapshot applies - // to framework-path modules only. - ctx.Errorf("module %q in vendor proprietary path %q may not use \"exclude_from_vendor_snapshot: true\"", m.String(), moduleDir) - return - } - } - - if !isSnapshotAware(ctx.DeviceConfig(), m, inProprietaryPath, apexInfo, s.Image) { - return - } - - // If we are using directed snapshot and a module is not included in the - // list, we will still include the module as if it was a fake module. - // The reason is that soong needs all the dependencies to be present, even - // if they are not using during the build. - installAsFake := s.Fake - if s.Image.ExcludeFromDirectedSnapshot(ctx.DeviceConfig(), m.BaseModuleName()) { - installAsFake = true - } - - // installSnapshot installs prebuilts and json flag files - snapshotOutputs = append(snapshotOutputs, installSnapshot(m, installAsFake)...) - // just gather headers and notice files here, because they are to be deduplicated - if m.IsSnapshotLibrary() { - headers = append(headers, m.SnapshotHeaders()...) - } - - for _, notice := range m.EffectiveLicenseFiles() { - if _, ok := installedNotices[notice.String()]; !ok { - installedNotices[notice.String()] = true - snapshotNotices = append(snapshotNotices, notice) - } - } - }) - - // install all headers after removing duplicates - for _, header := range android.FirstUniquePaths(headers) { - snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String()), s.Fake)) - } - - return snapshot.SnapshotPaths{OutputFiles: snapshotOutputs, NoticeFiles: snapshotNotices} -} - -func init() { - snapshot.RegisterSnapshotAction(ccSnapshotAction) -} diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go deleted file mode 100644 index c5431b3d3..000000000 --- a/cc/vendor_snapshot_test.go +++ /dev/null @@ -1,1740 +0,0 @@ -// 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 ( - "android/soong/android" - "fmt" - "path/filepath" - "reflect" - "strings" - "testing" -) - -func checkJsonContents(t *testing.T, ctx android.TestingSingleton, jsonPath string, key string, value string) { - jsonOut := ctx.MaybeOutput(jsonPath) - if jsonOut.Rule == nil { - t.Errorf("%q expected but not found", jsonPath) - return - } - if !strings.Contains(jsonOut.Args["content"], fmt.Sprintf("%q:%q", key, value)) { - t.Errorf("%q must include %q:%q but it only has %v", jsonPath, key, value, jsonOut.Args["content"]) - } -} - -func TestVendorSnapshotCapture(t *testing.T) { - bp := ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvendor", - vendor: true, - nocrt: true, - } - - cc_library { - name: "libvendor_override", - vendor: true, - nocrt: true, - overrides: ["libvendor"], - } - - cc_library { - name: "libvendor_available", - vendor_available: true, - nocrt: true, - min_sdk_version: "29", - } - - cc_library_headers { - name: "libvendor_headers", - vendor_available: true, - nocrt: true, - } - - cc_binary { - name: "vendor_bin", - vendor: true, - nocrt: true, - } - - cc_binary { - name: "vendor_available_bin", - vendor_available: true, - nocrt: true, - } - - cc_binary { - name: "vendor_bin_override", - vendor: true, - nocrt: true, - overrides: ["vendor_bin"], - } - - cc_prebuilt_library_static { - name: "libb", - vendor_available: true, - srcs: ["libb.a"], - nocrt: true, - no_libcrt: true, - stl: "none", - } - - cc_object { - name: "obj", - vendor_available: true, - } - - cc_library { - name: "libllndk", - llndk: { - symbol_file: "libllndk.map.txt", - }, - } -` - - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - ctx := testCcWithConfig(t, config) - - // Check Vendor snapshot output. - - snapshotDir := "vendor-snapshot" - snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") - snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") - - var jsonFiles []string - - for _, arch := range [][]string{ - []string{"arm64", "armv8-a"}, - []string{"arm", "armv7-a-neon"}, - } { - archType := arch[0] - archVariant := arch[1] - archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) - - // For shared libraries, only non-VNDK vendor_available modules are captured - sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) - sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") - CheckSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant) - jsonFiles = append(jsonFiles, - filepath.Join(sharedDir, "libvendor.so.json"), - filepath.Join(sharedDir, "libvendor_available.so.json")) - - // LLNDK modules are not captured - CheckSnapshotExclude(t, ctx, snapshotSingleton, "libllndk", "libllndk.so", sharedDir, sharedVariant) - - // For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured. - // Also cfi variants are captured, except for prebuilts like toolchain_library - staticVariant := fmt.Sprintf("android_vendor.29_%s_%s_static", archType, archVariant) - staticCfiVariant := fmt.Sprintf("android_vendor.29_%s_%s_static_cfi", archType, archVariant) - staticDir := filepath.Join(snapshotVariantPath, archDir, "static") - CheckSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.a", staticDir, staticVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.cfi.a", staticDir, staticCfiVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.a", staticDir, staticVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.cfi.a", staticDir, staticCfiVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.a", staticDir, staticVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.cfi.a", staticDir, staticCfiVariant) - jsonFiles = append(jsonFiles, - filepath.Join(staticDir, "libb.a.json"), - filepath.Join(staticDir, "libvndk.a.json"), - filepath.Join(staticDir, "libvndk.cfi.a.json"), - filepath.Join(staticDir, "libvendor.a.json"), - filepath.Join(staticDir, "libvendor.cfi.a.json"), - filepath.Join(staticDir, "libvendor_available.a.json"), - filepath.Join(staticDir, "libvendor_available.cfi.a.json")) - - checkJsonContents(t, snapshotSingleton, filepath.Join(staticDir, "libb.a.json"), "MinSdkVersion", "apex_inherit") - checkJsonContents(t, snapshotSingleton, filepath.Join(staticDir, "libvendor_available.a.json"), "MinSdkVersion", "29") - - // For binary executables, all vendor:true and vendor_available modules are captured. - if archType == "arm64" { - binaryVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant) - binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary") - CheckSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant) - jsonFiles = append(jsonFiles, - filepath.Join(binaryDir, "vendor_bin.json"), - filepath.Join(binaryDir, "vendor_available_bin.json")) - - checkOverrides(t, ctx, snapshotSingleton, filepath.Join(binaryDir, "vendor_bin_override.json"), []string{"vendor_bin"}) - } - - // For header libraries, all vendor:true and vendor_available modules are captured. - headerDir := filepath.Join(snapshotVariantPath, archDir, "header") - jsonFiles = append(jsonFiles, filepath.Join(headerDir, "libvendor_headers.json")) - - // For object modules, all vendor:true and vendor_available modules are captured. - objectVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant) - objectDir := filepath.Join(snapshotVariantPath, archDir, "object") - CheckSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant) - jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json")) - - checkOverrides(t, ctx, snapshotSingleton, filepath.Join(sharedDir, "libvendor_override.so.json"), []string{"libvendor"}) - } - - for _, jsonFile := range jsonFiles { - // verify all json files exist - if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { - t.Errorf("%q expected but not found", jsonFile) - } - } - - // fake snapshot should have all outputs in the normal snapshot. - fakeSnapshotSingleton := ctx.SingletonForTests("vendor-fake-snapshot") - for _, output := range snapshotSingleton.AllOutputs() { - fakeOutput := strings.Replace(output, "/vendor-snapshot/", "/fake/vendor-snapshot/", 1) - if fakeSnapshotSingleton.MaybeOutput(fakeOutput).Rule == nil { - t.Errorf("%q expected but not found", fakeOutput) - } - } -} - -func TestVendorSnapshotDirected(t *testing.T) { - bp := ` - cc_library_shared { - name: "libvendor", - vendor: true, - nocrt: true, - } - - cc_library_shared { - name: "libvendor_available", - vendor_available: true, - nocrt: true, - } - - genrule { - name: "libfoo_gen", - cmd: "", - out: ["libfoo.so"], - } - - cc_prebuilt_library_shared { - name: "libfoo", - vendor: true, - prefer: true, - srcs: [":libfoo_gen"], - } - - cc_library_shared { - name: "libfoo", - vendor: true, - nocrt: true, - } -` - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - config.TestProductVariables.DirectedVendorSnapshot = true - config.TestProductVariables.VendorSnapshotModules = make(map[string]bool) - config.TestProductVariables.VendorSnapshotModules["libvendor"] = true - config.TestProductVariables.VendorSnapshotModules["libfoo"] = true - ctx := testCcWithConfig(t, config) - - // Check Vendor snapshot output. - - snapshotDir := "vendor-snapshot" - snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") - snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") - - var includeJsonFiles []string - - for _, arch := range [][]string{ - []string{"arm64", "armv8-a"}, - []string{"arm", "armv7-a-neon"}, - } { - archType := arch[0] - archVariant := arch[1] - archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) - - sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) - sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") - - // Included modules - CheckSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant) - includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json")) - // Check that snapshot captures "prefer: true" prebuilt - CheckSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant) - includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json")) - - // Excluded modules. Modules not included in the directed vendor snapshot - // are still include as fake modules. - CheckSnapshotRule(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant) - includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libvendor_available.so.json")) - } - - // Verify that each json file for an included module has a rule. - for _, jsonFile := range includeJsonFiles { - if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { - t.Errorf("include json file %q not found", jsonFile) - } - } -} - -func TestVendorSnapshotUse(t *testing.T) { - frameworkBp := ` - cc_library { - name: "libvndk", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "libvendor", - vendor: true, - nocrt: true, - no_libcrt: true, - stl: "none", - system_shared_libs: [], - } - - cc_library { - name: "libvendor_available", - vendor_available: true, - nocrt: true, - no_libcrt: true, - stl: "none", - system_shared_libs: [], - } - - cc_library { - name: "lib32", - vendor: true, - nocrt: true, - no_libcrt: true, - stl: "none", - system_shared_libs: [], - compile_multilib: "32", - } - - cc_library { - name: "lib64", - vendor: true, - nocrt: true, - no_libcrt: true, - stl: "none", - system_shared_libs: [], - compile_multilib: "64", - } - - cc_library { - name: "libllndk", - llndk: { - symbol_file: "libllndk.map.txt", - }, - } - - cc_binary { - name: "bin", - vendor: true, - nocrt: true, - no_libcrt: true, - stl: "none", - system_shared_libs: [], - } - - cc_binary { - name: "bin32", - vendor: true, - nocrt: true, - no_libcrt: true, - stl: "none", - system_shared_libs: [], - compile_multilib: "32", - } -` - - vndkBp := ` - vndk_prebuilt_shared { - name: "libvndk", - version: "31", - target_arch: "arm64", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - arch: { - arm64: { - srcs: ["libvndk.so"], - export_include_dirs: ["include/libvndk"], - }, - arm: { - srcs: ["libvndk.so"], - export_include_dirs: ["include/libvndk"], - }, - }, - } - - // old snapshot module which has to be ignored - vndk_prebuilt_shared { - name: "libvndk", - version: "26", - target_arch: "arm64", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - arch: { - arm64: { - srcs: ["libvndk.so"], - export_include_dirs: ["include/libvndk"], - }, - arm: { - srcs: ["libvndk.so"], - export_include_dirs: ["include/libvndk"], - }, - }, - } - - // different arch snapshot which has to be ignored - vndk_prebuilt_shared { - name: "libvndk", - version: "31", - target_arch: "arm", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - arch: { - arm: { - srcs: ["libvndk.so"], - export_include_dirs: ["include/libvndk"], - }, - }, - } - - vndk_prebuilt_shared { - name: "libllndk", - version: "31", - target_arch: "arm64", - vendor_available: true, - product_available: true, - arch: { - arm64: { - srcs: ["libllndk.so"], - }, - arm: { - srcs: ["libllndk.so"], - }, - }, - } -` - - vendorProprietaryBp := ` - cc_library { - name: "libvendor_without_snapshot", - vendor: true, - nocrt: true, - no_libcrt: true, - stl: "none", - system_shared_libs: [], - } - - cc_library_shared { - name: "libclient", - vendor: true, - nocrt: true, - no_libcrt: true, - stl: "none", - system_shared_libs: [], - shared_libs: ["libvndk", "libvendor_available", "libllndk"], - static_libs: ["libvendor", "libvendor_without_snapshot"], - arch: { - arm64: { - shared_libs: ["lib64"], - }, - arm: { - shared_libs: ["lib32"], - }, - }, - srcs: ["client.cpp"], - } - - cc_library_shared { - name: "libclient_cfi", - vendor: true, - nocrt: true, - no_libcrt: true, - stl: "none", - system_shared_libs: [], - static_libs: ["libvendor"], - sanitize: { - cfi: true, - }, - srcs: ["client.cpp"], - } - - cc_library_shared { - name: "libvndkext", - vendor: true, - nocrt: true, - no_libcrt: true, - stl: "none", - system_shared_libs: [], - vndk: { - extends: "libvndk", - enabled: true, - } - } - - cc_binary { - name: "bin_without_snapshot", - vendor: true, - nocrt: true, - no_libcrt: true, - stl: "libc++_static", - system_shared_libs: [], - static_libs: ["libvndk"], - srcs: ["bin.cpp"], - } - - vendor_snapshot { - name: "vendor_snapshot", - version: "31", - arch: { - arm64: { - vndk_libs: [ - "libvndk", - "libllndk", - ], - static_libs: [ - "libc++_static", - "libc++demangle", - "libunwind", - "libvendor", - "libvendor_available", - "libvndk", - "lib64", - ], - shared_libs: [ - "libvendor", - "libvendor_override", - "libvendor_available", - "lib64", - ], - binaries: [ - "bin", - "bin_override", - ], - }, - arm: { - vndk_libs: [ - "libvndk", - "libllndk", - ], - static_libs: [ - "libvendor", - "libvendor_available", - "libvndk", - "lib32", - ], - shared_libs: [ - "libvendor", - "libvendor_override", - "libvendor_available", - "lib32", - ], - binaries: [ - "bin32", - ], - }, - } - } - - vendor_snapshot_static { - name: "libvndk", - version: "31", - target_arch: "arm64", - compile_multilib: "both", - vendor: true, - arch: { - arm64: { - src: "libvndk.a", - }, - arm: { - src: "libvndk.a", - }, - }, - shared_libs: ["libvndk"], - export_shared_lib_headers: ["libvndk"], - } - - vendor_snapshot_shared { - name: "libvendor", - version: "31", - target_arch: "arm64", - compile_multilib: "both", - vendor: true, - shared_libs: [ - "libvendor_without_snapshot", - "libvendor_available", - "libvndk", - ], - arch: { - arm64: { - src: "libvendor.so", - export_include_dirs: ["include/libvendor"], - }, - arm: { - src: "libvendor.so", - export_include_dirs: ["include/libvendor"], - }, - }, - } - - vendor_snapshot_shared { - name: "libvendor_override", - version: "31", - target_arch: "arm64", - compile_multilib: "both", - vendor: true, - overrides: ["libvendor"], - shared_libs: [ - "libvendor_without_snapshot", - "libvendor_available", - "libvndk", - ], - arch: { - arm64: { - src: "override/libvendor.so", - export_include_dirs: ["include/libvendor"], - }, - arm: { - src: "override/libvendor.so", - export_include_dirs: ["include/libvendor"], - }, - }, - } - - vendor_snapshot_static { - name: "lib32", - version: "31", - target_arch: "arm64", - compile_multilib: "32", - vendor: true, - arch: { - arm: { - src: "lib32.a", - }, - }, - } - - vendor_snapshot_shared { - name: "lib32", - version: "31", - target_arch: "arm64", - compile_multilib: "32", - vendor: true, - arch: { - arm: { - src: "lib32.so", - }, - }, - } - - vendor_snapshot_static { - name: "lib64", - version: "31", - target_arch: "arm64", - compile_multilib: "64", - vendor: true, - arch: { - arm64: { - src: "lib64.a", - }, - }, - } - - vendor_snapshot_shared { - name: "lib64", - version: "31", - target_arch: "arm64", - compile_multilib: "64", - vendor: true, - arch: { - arm64: { - src: "lib64.so", - }, - }, - } - - vendor_snapshot_static { - name: "libvendor", - version: "31", - target_arch: "arm64", - compile_multilib: "both", - vendor: true, - arch: { - arm64: { - cfi: { - src: "libvendor.cfi.a", - export_include_dirs: ["include/libvendor_cfi"], - }, - src: "libvendor.a", - export_include_dirs: ["include/libvendor"], - }, - arm: { - cfi: { - src: "libvendor.cfi.a", - export_include_dirs: ["include/libvendor_cfi"], - }, - src: "libvendor.a", - export_include_dirs: ["include/libvendor"], - }, - }, - } - - vendor_snapshot_shared { - name: "libvendor_available", - version: "31", - target_arch: "arm64", - compile_multilib: "both", - vendor: true, - arch: { - arm64: { - src: "libvendor_available.so", - export_include_dirs: ["include/libvendor"], - }, - arm: { - src: "libvendor_available.so", - export_include_dirs: ["include/libvendor"], - }, - }, - } - - vendor_snapshot_static { - name: "libvendor_available", - version: "31", - target_arch: "arm64", - compile_multilib: "both", - vendor: true, - arch: { - arm64: { - src: "libvendor_available.a", - export_include_dirs: ["include/libvendor"], - }, - arm: { - src: "libvendor_available.so", - export_include_dirs: ["include/libvendor"], - }, - }, - } - - vendor_snapshot_static { - name: "libc++_static", - version: "31", - target_arch: "arm64", - compile_multilib: "64", - vendor: true, - arch: { - arm64: { - src: "libc++_static.a", - }, - }, - } - - vendor_snapshot_static { - name: "libc++demangle", - version: "31", - target_arch: "arm64", - compile_multilib: "64", - vendor: true, - arch: { - arm64: { - src: "libc++demangle.a", - }, - }, - } - - vendor_snapshot_static { - name: "libunwind", - version: "31", - target_arch: "arm64", - compile_multilib: "64", - vendor: true, - arch: { - arm64: { - src: "libunwind.a", - }, - }, - } - - vendor_snapshot_binary { - name: "bin", - version: "31", - target_arch: "arm64", - compile_multilib: "64", - vendor: true, - arch: { - arm64: { - src: "bin", - }, - }, - symlinks: ["binfoo", "binbar"], - } - - vendor_snapshot_binary { - name: "bin_override", - version: "31", - target_arch: "arm64", - compile_multilib: "64", - vendor: true, - overrides: ["bin"], - arch: { - arm64: { - src: "override/bin", - }, - }, - symlinks: ["binfoo", "binbar"], - } - - vendor_snapshot_binary { - name: "bin32", - version: "31", - target_arch: "arm64", - compile_multilib: "32", - vendor: true, - arch: { - arm: { - src: "bin32", - }, - }, - } - - // old snapshot module which has to be ignored - vendor_snapshot_binary { - name: "bin", - version: "26", - target_arch: "arm64", - compile_multilib: "first", - vendor: true, - arch: { - arm64: { - src: "bin", - }, - }, - } - - // different arch snapshot which has to be ignored - vendor_snapshot_binary { - name: "bin", - version: "31", - target_arch: "arm", - compile_multilib: "first", - vendor: true, - arch: { - arm64: { - src: "bin", - }, - }, - } -` - depsBp := GatherRequiredDepsForTest(android.Android) - - mockFS := map[string][]byte{ - "deps/Android.bp": []byte(depsBp), - "framework/Android.bp": []byte(frameworkBp), - "framework/symbol.txt": nil, - "vendor/Android.bp": []byte(vendorProprietaryBp), - "vendor/bin": nil, - "vendor/override/bin": nil, - "vendor/bin32": nil, - "vendor/bin.cpp": nil, - "vendor/client.cpp": nil, - "vendor/include/libvndk/a.h": nil, - "vendor/include/libvendor/b.h": nil, - "vendor/include/libvendor_cfi/c.h": nil, - "vendor/libc++_static.a": nil, - "vendor/libc++demangle.a": nil, - "vendor/libunwind.a": nil, - "vendor/libvndk.a": nil, - "vendor/libvendor.a": nil, - "vendor/libvendor.cfi.a": nil, - "vendor/libvendor.so": nil, - "vendor/override/libvendor.so": nil, - "vendor/lib32.a": nil, - "vendor/lib32.so": nil, - "vendor/lib64.a": nil, - "vendor/lib64.so": nil, - "vndk/Android.bp": []byte(vndkBp), - "vndk/include/libvndk/a.h": nil, - "vndk/libvndk.so": nil, - "vndk/libllndk.so": nil, - } - - config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS) - config.TestProductVariables.DeviceVndkVersion = StringPtr("31") - config.TestProductVariables.Platform_vndk_version = StringPtr("32") - ctx := CreateTestContext(config) - ctx.Register() - - _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "vendor/Android.bp", "vndk/Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) - - sharedVariant := "android_vendor.31_arm64_armv8-a_shared" - staticVariant := "android_vendor.31_arm64_armv8-a_static" - binaryVariant := "android_vendor.31_arm64_armv8-a" - - sharedCfiVariant := "android_vendor.31_arm64_armv8-a_shared_cfi" - staticCfiVariant := "android_vendor.31_arm64_armv8-a_static_cfi" - - shared32Variant := "android_vendor.31_arm_armv7-a-neon_shared" - binary32Variant := "android_vendor.31_arm_armv7-a-neon" - - // libclient uses libvndk.vndk.31.arm64, libvendor.vendor_static.31.arm64, libvendor_without_snapshot - libclientCcFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("cc").Args["cFlags"] - for _, includeFlags := range []string{ - "-Ivndk/include/libvndk", // libvndk - "-Ivendor/include/libvendor", // libvendor - } { - if !strings.Contains(libclientCcFlags, includeFlags) { - t.Errorf("flags for libclient must contain %#v, but was %#v.", - includeFlags, libclientCcFlags) - } - } - - libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld").Args["libFlags"] - for _, input := range [][]string{ - []string{sharedVariant, "libvndk.vndk.31.arm64"}, - []string{sharedVariant, "libllndk.vndk.31.arm64"}, - []string{staticVariant, "libvendor.vendor_static.31.arm64"}, - []string{staticVariant, "libvendor_without_snapshot"}, - } { - outputPaths := GetOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */) - if !strings.Contains(libclientLdFlags, outputPaths[0].String()) { - t.Errorf("libflags for libclient must contain %#v, but was %#v", outputPaths[0], libclientLdFlags) - } - - } - - libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkSharedLibs - if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "libllndk.vendor", "lib64"}; !reflect.DeepEqual(g, w) { - t.Errorf("wanted libclient AndroidMkSharedLibs %q, got %q", w, g) - } - - libclientAndroidMkStaticLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkStaticLibs - if g, w := libclientAndroidMkStaticLibs, []string{"libvendor", "libvendor_without_snapshot"}; !reflect.DeepEqual(g, w) { - t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g) - } - - libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).Properties.AndroidMkSharedLibs - if g, w := libclient32AndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "libllndk.vendor", "lib32"}; !reflect.DeepEqual(g, w) { - t.Errorf("wanted libclient32 AndroidMkSharedLibs %q, got %q", w, g) - } - - // libclient_cfi uses libvendor.vendor_static.31.arm64's cfi variant - libclientCfiCcFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("cc").Args["cFlags"] - if !strings.Contains(libclientCfiCcFlags, "-Ivendor/include/libvendor_cfi") { - t.Errorf("flags for libclient_cfi must contain %#v, but was %#v.", - "-Ivendor/include/libvendor_cfi", libclientCfiCcFlags) - } - - libclientCfiLdFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("ld").Args["libFlags"] - libvendorCfiOutputPaths := GetOutputPaths(ctx, staticCfiVariant, []string{"libvendor.vendor_static.31.arm64"}) - if !strings.Contains(libclientCfiLdFlags, libvendorCfiOutputPaths[0].String()) { - t.Errorf("libflags for libclientCfi must contain %#v, but was %#v", libvendorCfiOutputPaths[0], libclientCfiLdFlags) - } - - // bin_without_snapshot uses libvndk.vendor_static.31.arm64 (which reexports vndk's exported headers) - binWithoutSnapshotCcFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("cc").Args["cFlags"] - if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivndk/include/libvndk") { - t.Errorf("flags for bin_without_snapshot must contain %#v, but was %#v.", - "-Ivendor/include/libvndk", binWithoutSnapshotCcFlags) - } - - binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld").Args["libFlags"] - libVndkStaticOutputPaths := GetOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.31.arm64"}) - if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) { - t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v", - libVndkStaticOutputPaths[0], binWithoutSnapshotLdFlags) - } - - // libvendor.so is installed by libvendor.vendor_shared.31.arm64 - ctx.ModuleForTests("libvendor.vendor_shared.31.arm64", sharedVariant).Output("libvendor.so") - - // lib64.so is installed by lib64.vendor_shared.31.arm64 - ctx.ModuleForTests("lib64.vendor_shared.31.arm64", sharedVariant).Output("lib64.so") - - // lib32.so is installed by lib32.vendor_shared.31.arm64 - ctx.ModuleForTests("lib32.vendor_shared.31.arm64", shared32Variant).Output("lib32.so") - - // libvendor_available.so is installed by libvendor_available.vendor_shared.31.arm64 - ctx.ModuleForTests("libvendor_available.vendor_shared.31.arm64", sharedVariant).Output("libvendor_available.so") - - // libvendor_without_snapshot.so is installed by libvendor_without_snapshot - ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so") - - // bin is installed by bin.vendor_binary.31.arm64 - bin64Module := ctx.ModuleForTests("bin.vendor_binary.31.arm64", binaryVariant) - bin64Module.Output("bin") - - // also test symlinks - bin64MkEntries := android.AndroidMkEntriesForTest(t, ctx, bin64Module.Module()) - bin64KatiSymlinks := bin64MkEntries[0].EntryMap["LOCAL_SOONG_INSTALL_SYMLINKS"] - - // Either AndroidMk entries contain symlinks, or symlinks should be installed by Soong - for _, symlink := range []string{"binfoo", "binbar"} { - if inList(symlink, bin64KatiSymlinks) { - continue - } - - bin64Module.Output(symlink) - } - - // bin32 is installed by bin32.vendor_binary.31.arm64 - ctx.ModuleForTests("bin32.vendor_binary.31.arm64", binary32Variant).Output("bin32") - - // bin_without_snapshot is installed by bin_without_snapshot - ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot") - - // libvendor, libvendor_available and bin don't have vendor.31 variant - libvendorVariants := ctx.ModuleVariantsForTests("libvendor") - if inList(sharedVariant, libvendorVariants) { - t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant) - } - - libvendorAvailableVariants := ctx.ModuleVariantsForTests("libvendor_available") - if inList(sharedVariant, libvendorAvailableVariants) { - t.Errorf("libvendor_available must not have variant %#v, but it does", sharedVariant) - } - - binVariants := ctx.ModuleVariantsForTests("bin") - if inList(binaryVariant, binVariants) { - t.Errorf("bin must not have variant %#v, but it does", sharedVariant) - } - - // test overrides property - binOverrideModule := ctx.ModuleForTests("bin_override.vendor_binary.31.arm64", binaryVariant) - binOverrideModule.Output("bin") - binOverrideMkEntries := android.AndroidMkEntriesForTest(t, ctx, binOverrideModule.Module()) - binOverrideEntry := binOverrideMkEntries[0].EntryMap["LOCAL_OVERRIDES_MODULES"] - if !inList("bin", binOverrideEntry) { - t.Errorf("bin_override must override bin but was %q\n", binOverrideEntry) - } - - libvendorOverrideModule := ctx.ModuleForTests("libvendor_override.vendor_shared.31.arm64", sharedVariant) - libvendorOverrideModule.Output("libvendor.so") - libvendorOverrideMkEntries := android.AndroidMkEntriesForTest(t, ctx, libvendorOverrideModule.Module()) - libvendorOverrideEntry := libvendorOverrideMkEntries[0].EntryMap["LOCAL_OVERRIDES_MODULES"] - if !inList("libvendor", libvendorOverrideEntry) { - t.Errorf("libvendor_override must override libvendor but was %q\n", libvendorOverrideEntry) - } -} - -func TestVendorSnapshotSanitizer(t *testing.T) { - bp := ` - vendor_snapshot { - name: "vendor_snapshot", - version: "28", - arch: { - arm64: { - static_libs: [ - "libsnapshot", - "note_memtag_heap_sync", - ], - objects: [ - "snapshot_object", - ], - vndk_libs: [ - "libclang_rt.hwasan", - ], - }, - }, - } - - vendor_snapshot_static { - name: "libsnapshot", - vendor: true, - target_arch: "arm64", - version: "28", - arch: { - arm64: { - src: "libsnapshot.a", - cfi: { - src: "libsnapshot.cfi.a", - }, - hwasan: { - src: "libsnapshot.hwasan.a", - }, - }, - }, - } - - vendor_snapshot_static { - name: "note_memtag_heap_sync", - vendor: true, - target_arch: "arm64", - version: "28", - arch: { - arm64: { - src: "note_memtag_heap_sync.a", - }, - }, - } - - vndk_prebuilt_shared { - name: "libclang_rt.hwasan", - version: "28", - target_arch: "arm64", - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - arch: { - arm64: { - srcs: ["libclang_rt.hwasan.so"], - }, - }, - } - - vendor_snapshot_object { - name: "snapshot_object", - vendor: true, - target_arch: "arm64", - version: "28", - arch: { - arm64: { - src: "snapshot_object.o", - }, - }, - stl: "none", - } - - cc_test { - name: "vstest", - gtest: false, - vendor: true, - compile_multilib: "64", - nocrt: true, - no_libcrt: true, - stl: "none", - static_libs: ["libsnapshot"], - system_shared_libs: [], - } -` - - mockFS := map[string][]byte{ - "vendor/Android.bp": []byte(bp), - "vendor/libc++demangle.a": nil, - "vendor/libclang_rt.hwasan.so": nil, - "vendor/libsnapshot.a": nil, - "vendor/libsnapshot.cfi.a": nil, - "vendor/libsnapshot.hwasan.a": nil, - "vendor/note_memtag_heap_sync.a": nil, - "vendor/snapshot_object.o": nil, - } - - config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS) - config.TestProductVariables.DeviceVndkVersion = StringPtr("28") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - config.TestProductVariables.SanitizeDevice = []string{"hwaddress"} - ctx := testCcWithConfig(t, config) - - // Check non-cfi, cfi and hwasan variant. - staticVariant := "android_vendor.28_arm64_armv8-a_static" - staticCfiVariant := "android_vendor.28_arm64_armv8-a_static_cfi" - staticHwasanVariant := "android_vendor.28_arm64_armv8-a_static_hwasan" - staticHwasanCfiVariant := "android_vendor.28_arm64_armv8-a_static_hwasan_cfi" - - staticModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticVariant).Module().(*Module) - assertString(t, staticModule.outputFile.Path().Base(), "libsnapshot.a") - - staticCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticCfiVariant).Module().(*Module) - assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a") - - staticHwasanModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticHwasanVariant).Module().(*Module) - assertString(t, staticHwasanModule.outputFile.Path().Base(), "libsnapshot.hwasan.a") - - staticHwasanCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticHwasanCfiVariant).Module().(*Module) - if !staticHwasanCfiModule.HiddenFromMake() || !staticHwasanCfiModule.PreventInstall() { - t.Errorf("Hwasan and Cfi cannot enabled at the same time.") - } - - snapshotObjModule := ctx.ModuleForTests("snapshot_object.vendor_object.28.arm64", "android_vendor.28_arm64_armv8-a").Module() - snapshotObjMkEntries := android.AndroidMkEntriesForTest(t, ctx, snapshotObjModule) - // snapshot object must not add ".hwasan" suffix - assertString(t, snapshotObjMkEntries[0].EntryMap["LOCAL_MODULE"][0], "snapshot_object") -} - -func TestVendorSnapshotExclude(t *testing.T) { - - // This test verifies that the exclude_from_vendor_snapshot property - // makes its way from the Android.bp source file into the module data - // structure. It also verifies that modules are correctly included or - // excluded in the vendor snapshot based on their path (framework or - // vendor) and the exclude_from_vendor_snapshot property. - - frameworkBp := ` - cc_library_shared { - name: "libinclude", - srcs: ["src/include.cpp"], - vendor_available: true, - } - cc_library_shared { - name: "libexclude", - srcs: ["src/exclude.cpp"], - vendor: true, - exclude_from_vendor_snapshot: true, - } - cc_library_shared { - name: "libavailable_exclude", - srcs: ["src/exclude.cpp"], - vendor_available: true, - exclude_from_vendor_snapshot: true, - } - ` - - vendorProprietaryBp := ` - cc_library_shared { - name: "libvendor", - srcs: ["vendor.cpp"], - vendor: true, - } - ` - - depsBp := GatherRequiredDepsForTest(android.Android) - - mockFS := map[string][]byte{ - "deps/Android.bp": []byte(depsBp), - "framework/Android.bp": []byte(frameworkBp), - "framework/include.cpp": nil, - "framework/exclude.cpp": nil, - "device/Android.bp": []byte(vendorProprietaryBp), - "device/vendor.cpp": nil, - } - - config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - ctx := CreateTestContext(config) - ctx.Register() - - _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) - - // Test an include and exclude framework module. - AssertExcludeFromVendorSnapshotIs(t, ctx, "libinclude", false, vendorVariant) - AssertExcludeFromVendorSnapshotIs(t, ctx, "libexclude", true, vendorVariant) - AssertExcludeFromVendorSnapshotIs(t, ctx, "libavailable_exclude", true, vendorVariant) - - // A vendor module is excluded, but by its path, not the - // exclude_from_vendor_snapshot property. - AssertExcludeFromVendorSnapshotIs(t, ctx, "libvendor", false, vendorVariant) - - // Verify the content of the vendor snapshot. - - snapshotDir := "vendor-snapshot" - snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") - snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") - - var includeJsonFiles []string - var excludeJsonFiles []string - - for _, arch := range [][]string{ - []string{"arm64", "armv8-a"}, - []string{"arm", "armv7-a-neon"}, - } { - archType := arch[0] - archVariant := arch[1] - archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) - - sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) - sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") - - // Included modules - CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) - includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) - - // Excluded modules - CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) - excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json")) - CheckSnapshotExclude(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant) - excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json")) - CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant) - excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json")) - } - - // Verify that each json file for an included module has a rule. - for _, jsonFile := range includeJsonFiles { - if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { - t.Errorf("include json file %q not found", jsonFile) - } - } - - // Verify that each json file for an excluded module has no rule. - for _, jsonFile := range excludeJsonFiles { - if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil { - t.Errorf("exclude json file %q found", jsonFile) - } - } -} - -func TestVendorSnapshotExcludeInVendorProprietaryPathErrors(t *testing.T) { - - // This test verifies that using the exclude_from_vendor_snapshot - // property on a module in a vendor proprietary path generates an - // error. These modules are already excluded, so we prohibit using the - // property in this way, which could add to confusion. - - vendorProprietaryBp := ` - cc_library_shared { - name: "libvendor", - srcs: ["vendor.cpp"], - vendor: true, - exclude_from_vendor_snapshot: true, - } - ` - - depsBp := GatherRequiredDepsForTest(android.Android) - - mockFS := map[string][]byte{ - "deps/Android.bp": []byte(depsBp), - "device/Android.bp": []byte(vendorProprietaryBp), - "device/vendor.cpp": nil, - } - - config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - ctx := CreateTestContext(config) - ctx.Register() - - _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "device/Android.bp"}) - android.FailIfErrored(t, errs) - - _, errs = ctx.PrepareBuildActions(config) - android.CheckErrorsAgainstExpectations(t, errs, []string{ - `module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, - `module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, - `module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, - `module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, - `module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, - `module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, - }) -} - -func TestRecoverySnapshotCapture(t *testing.T) { - bp := ` - cc_library { - name: "libvndk", - vendor_available: true, - recovery_available: true, - product_available: true, - vndk: { - enabled: true, - }, - nocrt: true, - } - - cc_library { - name: "librecovery", - recovery: true, - nocrt: true, - } - - cc_library { - name: "librecovery_available", - recovery_available: true, - nocrt: true, - } - - cc_library_headers { - name: "librecovery_headers", - recovery_available: true, - nocrt: true, - } - - cc_binary { - name: "recovery_bin", - recovery: true, - nocrt: true, - } - - cc_binary { - name: "recovery_available_bin", - recovery_available: true, - nocrt: true, - } - - cc_prebuilt_library_static { - name: "libb", - recovery_available: true, - srcs: ["libb.a"], - nocrt: true, - no_libcrt: true, - stl: "none", - } - - cc_object { - name: "obj", - recovery_available: true, - } -` - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - ctx := testCcWithConfig(t, config) - - // Check Recovery snapshot output. - - snapshotDir := "recovery-snapshot" - snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") - snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") - - var jsonFiles []string - - for _, arch := range [][]string{ - []string{"arm64", "armv8-a"}, - } { - archType := arch[0] - archVariant := arch[1] - archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) - - // For shared libraries, only recovery_available modules are captured. - sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) - sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") - CheckSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", sharedDir, sharedVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant) - jsonFiles = append(jsonFiles, - filepath.Join(sharedDir, "libvndk.so.json"), - filepath.Join(sharedDir, "librecovery.so.json"), - filepath.Join(sharedDir, "librecovery_available.so.json")) - - // For static libraries, all recovery:true and recovery_available modules are captured. - staticVariant := fmt.Sprintf("android_recovery_%s_%s_static", archType, archVariant) - staticDir := filepath.Join(snapshotVariantPath, archDir, "static") - CheckSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.a", staticDir, staticVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.a", staticDir, staticVariant) - jsonFiles = append(jsonFiles, - filepath.Join(staticDir, "libb.a.json"), - filepath.Join(staticDir, "librecovery.a.json"), - filepath.Join(staticDir, "librecovery_available.a.json")) - - // For binary executables, all recovery:true and recovery_available modules are captured. - if archType == "arm64" { - binaryVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant) - binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary") - CheckSnapshot(t, ctx, snapshotSingleton, "recovery_bin", "recovery_bin", binaryDir, binaryVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "recovery_available_bin", "recovery_available_bin", binaryDir, binaryVariant) - jsonFiles = append(jsonFiles, - filepath.Join(binaryDir, "recovery_bin.json"), - filepath.Join(binaryDir, "recovery_available_bin.json")) - } - - // For header libraries, all vendor:true and vendor_available modules are captured. - headerDir := filepath.Join(snapshotVariantPath, archDir, "header") - jsonFiles = append(jsonFiles, filepath.Join(headerDir, "librecovery_headers.json")) - - // For object modules, all vendor:true and vendor_available modules are captured. - objectVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant) - objectDir := filepath.Join(snapshotVariantPath, archDir, "object") - CheckSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant) - jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json")) - } - - for _, jsonFile := range jsonFiles { - // verify all json files exist - if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { - t.Errorf("%q expected but not found", jsonFile) - } - } -} - -func TestRecoverySnapshotExclude(t *testing.T) { - // This test verifies that the exclude_from_recovery_snapshot property - // makes its way from the Android.bp source file into the module data - // structure. It also verifies that modules are correctly included or - // excluded in the recovery snapshot based on their path (framework or - // vendor) and the exclude_from_recovery_snapshot property. - - frameworkBp := ` - cc_library_shared { - name: "libinclude", - srcs: ["src/include.cpp"], - recovery_available: true, - } - cc_library_shared { - name: "libexclude", - srcs: ["src/exclude.cpp"], - recovery: true, - exclude_from_recovery_snapshot: true, - } - cc_library_shared { - name: "libavailable_exclude", - srcs: ["src/exclude.cpp"], - recovery_available: true, - exclude_from_recovery_snapshot: true, - } - ` - - vendorProprietaryBp := ` - cc_library_shared { - name: "librecovery", - srcs: ["recovery.cpp"], - recovery: true, - } - ` - - depsBp := GatherRequiredDepsForTest(android.Android) - - mockFS := map[string][]byte{ - "deps/Android.bp": []byte(depsBp), - "framework/Android.bp": []byte(frameworkBp), - "framework/include.cpp": nil, - "framework/exclude.cpp": nil, - "device/Android.bp": []byte(vendorProprietaryBp), - "device/recovery.cpp": nil, - } - - config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS) - config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - ctx := CreateTestContext(config) - ctx.Register() - - _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) - - // Test an include and exclude framework module. - AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false, recoveryVariant) - AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true, recoveryVariant) - AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true, recoveryVariant) - - // A recovery module is excluded, but by its path, not the - // exclude_from_recovery_snapshot property. - AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false, recoveryVariant) - - // Verify the content of the recovery snapshot. - - snapshotDir := "recovery-snapshot" - snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") - snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") - - var includeJsonFiles []string - var excludeJsonFiles []string - - for _, arch := range [][]string{ - []string{"arm64", "armv8-a"}, - } { - archType := arch[0] - archVariant := arch[1] - archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) - - sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) - sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") - - // Included modules - CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) - includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) - - // Excluded modules - CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) - excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json")) - CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) - excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json")) - CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant) - excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json")) - } - - // Verify that each json file for an included module has a rule. - for _, jsonFile := range includeJsonFiles { - if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { - t.Errorf("include json file %q not found", jsonFile) - } - } - - // Verify that each json file for an excluded module has no rule. - for _, jsonFile := range excludeJsonFiles { - if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil { - t.Errorf("exclude json file %q found", jsonFile) - } - } -} - -func TestRecoverySnapshotDirected(t *testing.T) { - bp := ` - cc_library_shared { - name: "librecovery", - recovery: true, - nocrt: true, - } - - cc_library_shared { - name: "librecovery_available", - recovery_available: true, - nocrt: true, - } - - genrule { - name: "libfoo_gen", - cmd: "", - out: ["libfoo.so"], - } - - cc_prebuilt_library_shared { - name: "libfoo", - recovery: true, - prefer: true, - srcs: [":libfoo_gen"], - } - - cc_library_shared { - name: "libfoo", - recovery: true, - nocrt: true, - } -` - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - config.TestProductVariables.DirectedRecoverySnapshot = true - config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool) - config.TestProductVariables.RecoverySnapshotModules["librecovery"] = true - config.TestProductVariables.RecoverySnapshotModules["libfoo"] = true - ctx := testCcWithConfig(t, config) - - // Check recovery snapshot output. - - snapshotDir := "recovery-snapshot" - snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") - snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") - - var includeJsonFiles []string - - for _, arch := range [][]string{ - []string{"arm64", "armv8-a"}, - } { - archType := arch[0] - archVariant := arch[1] - archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) - - sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) - sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") - - // Included modules - CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) - includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json")) - // Check that snapshot captures "prefer: true" prebuilt - CheckSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant) - includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json")) - - // Excluded modules. Modules not included in the directed recovery snapshot - // are still include as fake modules. - CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant) - includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery_available.so.json")) - } - - // Verify that each json file for an included module has a rule. - for _, jsonFile := range includeJsonFiles { - if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { - t.Errorf("include json file %q not found", jsonFile) - } - } -} - -func TestSnapshotInRelativeInstallPath(t *testing.T) { - bp := ` - cc_library { - name: "libvendor_available", - vendor_available: true, - nocrt: true, - } - - cc_library { - name: "libvendor_available_var", - vendor_available: true, - stem: "libvendor_available", - relative_install_path: "var", - nocrt: true, - } -` - - config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("29") - ctx := testCcWithConfig(t, config) - - // Check Vendor snapshot output. - - snapshotDir := "vendor-snapshot" - snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") - snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") - - var jsonFiles []string - - for _, arch := range [][]string{ - []string{"arm64", "armv8-a"}, - []string{"arm", "armv7-a-neon"}, - } { - archType := arch[0] - archVariant := arch[1] - archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) - - // For shared libraries, only non-VNDK vendor_available modules are captured - sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant) - sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") - sharedDirVar := filepath.Join(sharedDir, "var") - CheckSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant) - CheckSnapshot(t, ctx, snapshotSingleton, "libvendor_available_var", "libvendor_available.so", sharedDirVar, sharedVariant) - jsonFiles = append(jsonFiles, - filepath.Join(sharedDir, "libvendor_available.so.json"), - filepath.Join(sharedDirVar, "libvendor_available.so.json")) - } - - for _, jsonFile := range jsonFiles { - // verify all json files exist - if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { - t.Errorf("%q expected but not found", jsonFile) - } - } - - // fake snapshot should have all outputs in the normal snapshot. - fakeSnapshotSingleton := ctx.SingletonForTests("vendor-fake-snapshot") - for _, output := range snapshotSingleton.AllOutputs() { - fakeOutput := strings.Replace(output, "/vendor-snapshot/", "/fake/vendor-snapshot/", 1) - if fakeSnapshotSingleton.MaybeOutput(fakeOutput).Rule == nil { - t.Errorf("%q expected but not found", fakeOutput) - } - } -} diff --git a/cc/vndk.go b/cc/vndk.go index 9b70004c5..9d196a0f8 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -15,49 +15,31 @@ package cc import ( - "encoding/json" - "errors" - "fmt" - "path/filepath" - "sort" "strings" "android/soong/android" - "android/soong/cc/config" - "android/soong/etc" - "android/soong/snapshot" - - "github.com/google/blueprint" ) const ( - llndkLibrariesTxt = "llndk.libraries.txt" - vndkCoreLibrariesTxt = "vndkcore.libraries.txt" - vndkSpLibrariesTxt = "vndksp.libraries.txt" - vndkPrivateLibrariesTxt = "vndkprivate.libraries.txt" - vndkProductLibrariesTxt = "vndkproduct.libraries.txt" - vndkUsingCoreVariantLibrariesTxt = "vndkcorevariant.libraries.txt" + llndkLibrariesTxt = "llndk.libraries.txt" + vndkCoreLibrariesTxt = "vndkcore.libraries.txt" + vndkSpLibrariesTxt = "vndksp.libraries.txt" + vndkPrivateLibrariesTxt = "vndkprivate.libraries.txt" + vndkProductLibrariesTxt = "vndkproduct.libraries.txt" ) -func VndkLibrariesTxtModules(vndkVersion string) []string { - if vndkVersion == "current" { - return []string{ - llndkLibrariesTxt, - vndkCoreLibrariesTxt, - vndkSpLibrariesTxt, - vndkPrivateLibrariesTxt, - vndkProductLibrariesTxt, - } - } +func VndkLibrariesTxtModules(vndkVersion string, ctx android.BaseModuleContext) []string { // Snapshot vndks have their own *.libraries.VER.txt files. // Note that snapshots don't have "vndkcorevariant.libraries.VER.txt" - return []string{ - insertVndkVersion(llndkLibrariesTxt, vndkVersion), + result := []string{ insertVndkVersion(vndkCoreLibrariesTxt, vndkVersion), insertVndkVersion(vndkSpLibrariesTxt, vndkVersion), insertVndkVersion(vndkPrivateLibrariesTxt, vndkVersion), insertVndkVersion(vndkProductLibrariesTxt, vndkVersion), + insertVndkVersion(llndkLibrariesTxt, vndkVersion), } + + return result } type VndkProperties struct { @@ -93,818 +75,9 @@ type VndkProperties struct { } } -type vndkdep struct { - Properties VndkProperties -} - -func (vndk *vndkdep) props() []interface{} { - return []interface{}{&vndk.Properties} -} - -func (vndk *vndkdep) isVndk() bool { - return Bool(vndk.Properties.Vndk.Enabled) -} - -func (vndk *vndkdep) isVndkSp() bool { - return Bool(vndk.Properties.Vndk.Support_system_process) -} - -func (vndk *vndkdep) isVndkExt() bool { - return vndk.Properties.Vndk.Extends != nil -} - -func (vndk *vndkdep) getVndkExtendsModuleName() string { - return String(vndk.Properties.Vndk.Extends) -} - -func (vndk *vndkdep) typeName() string { - if !vndk.isVndk() { - return "native:vendor" - } - if !vndk.isVndkExt() { - if !vndk.isVndkSp() { - return "native:vendor:vndk" - } - return "native:vendor:vndksp" - } - if !vndk.isVndkSp() { - return "native:vendor:vndkext" - } - return "native:vendor:vndkspext" -} - -// VNDK link type check from a module with UseVndk() == true. -func (vndk *vndkdep) vndkCheckLinkType(ctx android.BaseModuleContext, to *Module, tag blueprint.DependencyTag) { - if to.linker == nil { - return - } - if !vndk.isVndk() { - // Non-VNDK modules those installed to /vendor, /system/vendor, - // /product or /system/product cannot depend on VNDK-private modules - // that include VNDK-core-private, VNDK-SP-private and LLNDK-private. - if to.IsVndkPrivate() { - ctx.ModuleErrorf("non-VNDK module should not link to %q which has `private: true`", to.Name()) - } - } - if lib, ok := to.linker.(*libraryDecorator); !ok || !lib.shared() { - // Check only shared libraries. - // Other (static) libraries are allowed to link. - return - } - - if to.IsLlndk() { - // LL-NDK libraries are allowed to link - return - } - - if !to.UseVndk() { - ctx.ModuleErrorf("(%s) should not link to %q which is not a vendor-available library", - vndk.typeName(), to.Name()) - return - } - if tag == vndkExtDepTag { - // Ensure `extends: "name"` property refers a vndk module that has vendor_available - // and has identical vndk properties. - if to.vndkdep == nil || !to.vndkdep.isVndk() { - ctx.ModuleErrorf("`extends` refers a non-vndk module %q", to.Name()) - return - } - if vndk.isVndkSp() != to.vndkdep.isVndkSp() { - ctx.ModuleErrorf( - "`extends` refers a module %q with mismatched support_system_process", - to.Name()) - return - } - if to.IsVndkPrivate() { - ctx.ModuleErrorf( - "`extends` refers module %q which has `private: true`", - to.Name()) - return - } - } - if to.vndkdep == nil { - return - } - - // Check the dependencies of VNDK shared libraries. - if err := vndkIsVndkDepAllowed(vndk, to.vndkdep); err != nil { - ctx.ModuleErrorf("(%s) should not link to %q (%s): %v", - vndk.typeName(), to.Name(), to.vndkdep.typeName(), err) - return - } -} - -func vndkIsVndkDepAllowed(from *vndkdep, to *vndkdep) error { - // Check the dependencies of VNDK, VNDK-Ext, VNDK-SP, VNDK-SP-Ext and vendor modules. - if from.isVndkExt() { - if from.isVndkSp() { - if to.isVndk() && !to.isVndkSp() { - return errors.New("VNDK-SP extensions must not depend on VNDK or VNDK extensions") - } - return nil - } - // VNDK-Ext may depend on VNDK, VNDK-Ext, VNDK-SP, VNDK-SP-Ext, or vendor libs. - return nil - } - if from.isVndk() { - if to.isVndkExt() { - return errors.New("VNDK-core and VNDK-SP must not depend on VNDK extensions") - } - if from.isVndkSp() { - if !to.isVndkSp() { - return errors.New("VNDK-SP must only depend on VNDK-SP") - } - return nil - } - if !to.isVndk() { - return errors.New("VNDK-core must only depend on VNDK-core or VNDK-SP") - } - return nil - } - // Vendor modules may depend on VNDK, VNDK-Ext, VNDK-SP, VNDK-SP-Ext, or vendor libs. - return nil -} - -type moduleListerFunc func(ctx android.SingletonContext) (moduleNames, fileNames []string) - -var ( - llndkLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsLLNDK && !m.Header() }) - vndkSPLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKSP }) - vndkCoreLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKCore }) - vndkPrivateLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKPrivate }) - vndkProductLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKProduct }) - vndkUsingCoreVariantLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKUsingCoreVariant }) -) - -// vndkModuleLister takes a predicate that operates on a Module and returns a moduleListerFunc -// that produces a list of module names and output file names for which the predicate returns true. -func vndkModuleLister(predicate func(*Module) bool) moduleListerFunc { - return func(ctx android.SingletonContext) (moduleNames, fileNames []string) { - ctx.VisitAllModules(func(m android.Module) { - if c, ok := m.(*Module); ok && predicate(c) && !c.IsVndkPrebuiltLibrary() { - filename, err := getVndkFileName(c) - if err != nil { - ctx.ModuleErrorf(m, "%s", err) - } - moduleNames = append(moduleNames, ctx.ModuleName(m)) - fileNames = append(fileNames, filename) - } - }) - moduleNames = android.SortedUniqueStrings(moduleNames) - fileNames = android.SortedUniqueStrings(fileNames) - return - } -} - -// vndkModuleListRemover takes a moduleListerFunc and a prefix and returns a moduleListerFunc -// that returns the same lists as the input moduleListerFunc, but with modules with the -// given prefix removed. -func vndkModuleListRemover(lister moduleListerFunc, prefix string) moduleListerFunc { - return func(ctx android.SingletonContext) (moduleNames, fileNames []string) { - moduleNames, fileNames = lister(ctx) - filter := func(in []string) []string { - out := make([]string, 0, len(in)) - for _, lib := range in { - if strings.HasPrefix(lib, prefix) { - continue - } - out = append(out, lib) - } - return out - } - return filter(moduleNames), filter(fileNames) - } -} - -var vndkMustUseVendorVariantListKey = android.NewOnceKey("vndkMustUseVendorVariantListKey") - -func vndkMustUseVendorVariantList(cfg android.Config) []string { - return cfg.Once(vndkMustUseVendorVariantListKey, func() interface{} { - return config.VndkMustUseVendorVariantList - }).([]string) -} - -// test may call this to override global configuration(config.VndkMustUseVendorVariantList) -// when it is called, it must be before the first call to vndkMustUseVendorVariantList() -func setVndkMustUseVendorVariantListForTest(config android.Config, mustUseVendorVariantList []string) { - config.Once(vndkMustUseVendorVariantListKey, func() interface{} { - return mustUseVendorVariantList - }) -} - -func processVndkLibrary(mctx android.BottomUpMutatorContext, m *Module) { - if m.InProduct() { - // We may skip the steps for the product variants because they - // are already covered by the vendor variants. - return - } - - name := m.BaseModuleName() - - if lib := m.library; lib != nil && lib.hasStubsVariants() && name != "libz" { - // b/155456180 libz is the ONLY exception here. We don't want to make - // libz an LLNDK library because we in general can't guarantee that - // libz will behave consistently especially about the compression. - // i.e. the compressed output might be different across releases. - // As the library is an external one, it's risky to keep the compatibility - // promise if it becomes an LLNDK. - mctx.PropertyErrorf("vndk.enabled", "This library provides stubs. Shouldn't be VNDK. Consider making it as LLNDK") - } - - if inList(name, vndkMustUseVendorVariantList(mctx.Config())) { - m.Properties.MustUseVendorVariant = true - } - if mctx.DeviceConfig().VndkUseCoreVariant() && !m.Properties.MustUseVendorVariant { - m.VendorProperties.IsVNDKUsingCoreVariant = true - } - - if m.vndkdep.isVndkSp() { - m.VendorProperties.IsVNDKSP = true - } else { - m.VendorProperties.IsVNDKCore = true - } - if m.IsVndkPrivate() { - m.VendorProperties.IsVNDKPrivate = true - } - if Bool(m.VendorProperties.Product_available) { - m.VendorProperties.IsVNDKProduct = true - } -} - -// Check for modules that mustn't be VNDK -func shouldSkipVndkMutator(m *Module) bool { - if !m.Enabled() { - return true - } - if !m.Device() { - // Skip non-device modules - return true - } - if m.Target().NativeBridge == android.NativeBridgeEnabled { - // Skip native_bridge modules - return true - } - return false -} - -func IsForVndkApex(mctx android.BottomUpMutatorContext, m *Module) bool { - if shouldSkipVndkMutator(m) { - return false - } - - // prebuilt vndk modules should match with device - // TODO(b/142675459): Use enabled: to select target device in vndk_prebuilt_shared - // When b/142675459 is landed, remove following check - if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok && !p.MatchesWithDevice(mctx.DeviceConfig()) { - return false - } - - if lib, ok := m.linker.(libraryInterface); ok { - // VNDK APEX for VNDK-Lite devices will have VNDK-SP libraries from core variants - if mctx.DeviceConfig().VndkVersion() == "" { - // b/73296261: filter out libz.so because it is considered as LLNDK for VNDK-lite devices - if mctx.ModuleName() == "libz" { - return false - } - return m.ImageVariation().Variation == android.CoreVariation && lib.shared() && m.IsVndkSp() && !m.IsVndkExt() - } - // VNDK APEX doesn't need stub variants - if lib.buildStubs() { - return false - } - useCoreVariant := m.VndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() && - mctx.DeviceConfig().VndkUseCoreVariant() && !m.MustUseVendorVariant() - return lib.shared() && m.InVendor() && m.IsVndk() && !m.IsVndkExt() && !useCoreVariant - } - return false -} - -// gather list of vndk-core, vndk-sp, and ll-ndk libs -func VndkMutator(mctx android.BottomUpMutatorContext) { - m, ok := mctx.Module().(*Module) - if !ok { - return - } - - if shouldSkipVndkMutator(m) { - return - } - - lib, isLib := m.linker.(*libraryDecorator) - prebuiltLib, isPrebuiltLib := m.linker.(*prebuiltLibraryLinker) - - if m.UseVndk() && isLib && lib.hasLLNDKStubs() { - m.VendorProperties.IsLLNDK = true - m.VendorProperties.IsVNDKPrivate = Bool(lib.Properties.Llndk.Private) - } - if m.UseVndk() && isPrebuiltLib && prebuiltLib.hasLLNDKStubs() { - m.VendorProperties.IsLLNDK = true - m.VendorProperties.IsVNDKPrivate = Bool(prebuiltLib.Properties.Llndk.Private) - } - - if m.IsVndkPrebuiltLibrary() && !m.IsVndk() { - m.VendorProperties.IsLLNDK = true - // TODO(b/280697209): copy "llndk.private" flag to vndk_prebuilt_shared - } - - if (isLib && lib.buildShared()) || (isPrebuiltLib && prebuiltLib.buildShared()) { - if m.vndkdep != nil && m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() { - processVndkLibrary(mctx, m) - return - } - } -} - -func init() { - RegisterVndkLibraryTxtTypes(android.InitRegistrationContext) - android.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton) -} - -func RegisterVndkLibraryTxtTypes(ctx android.RegistrationContext) { - ctx.RegisterSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory) - ctx.RegisterSingletonModuleType("vndksp_libraries_txt", vndkSPLibrariesTxtFactory) - ctx.RegisterSingletonModuleType("vndkcore_libraries_txt", vndkCoreLibrariesTxtFactory) - ctx.RegisterSingletonModuleType("vndkprivate_libraries_txt", vndkPrivateLibrariesTxtFactory) - ctx.RegisterSingletonModuleType("vndkproduct_libraries_txt", vndkProductLibrariesTxtFactory) - ctx.RegisterSingletonModuleType("vndkcorevariant_libraries_txt", vndkUsingCoreVariantLibrariesTxtFactory) -} - -type vndkLibrariesTxt struct { - android.SingletonModuleBase - - lister moduleListerFunc - makeVarName string - filterOutFromMakeVar string - - properties VndkLibrariesTxtProperties - - outputFile android.OutputPath - moduleNames []string - fileNames []string -} - -type VndkLibrariesTxtProperties struct { - Insert_vndk_version *bool -} - -var _ etc.PrebuiltEtcModule = &vndkLibrariesTxt{} -var _ android.OutputFileProducer = &vndkLibrariesTxt{} - -// llndk_libraries_txt is a singleton module whose content is a list of LLNDK libraries -// generated by Soong but can be referenced by other modules. -// For example, apex_vndk can depend on these files as prebuilt. -// Make uses LLNDK_LIBRARIES to determine which libraries to install. -// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN. -// Therefore, by removing the library here, we cause it to only be installed if libc -// depends on it. -func llndkLibrariesTxtFactory() android.SingletonModule { - return newVndkLibrariesWithMakeVarFilter(llndkLibraries, "LLNDK_LIBRARIES", "libclang_rt.hwasan") -} - -// vndksp_libraries_txt is a singleton module whose content is a list of VNDKSP libraries -// generated by Soong but can be referenced by other modules. -// For example, apex_vndk can depend on these files as prebuilt. -func vndkSPLibrariesTxtFactory() android.SingletonModule { - return newVndkLibrariesTxt(vndkSPLibraries, "VNDK_SAMEPROCESS_LIBRARIES") -} - -// vndkcore_libraries_txt is a singleton module whose content is a list of VNDK core libraries -// generated by Soong but can be referenced by other modules. -// For example, apex_vndk can depend on these files as prebuilt. -func vndkCoreLibrariesTxtFactory() android.SingletonModule { - return newVndkLibrariesTxt(vndkCoreLibraries, "VNDK_CORE_LIBRARIES") -} - -// vndkprivate_libraries_txt is a singleton module whose content is a list of VNDK private libraries -// generated by Soong but can be referenced by other modules. -// For example, apex_vndk can depend on these files as prebuilt. -func vndkPrivateLibrariesTxtFactory() android.SingletonModule { - return newVndkLibrariesTxt(vndkPrivateLibraries, "VNDK_PRIVATE_LIBRARIES") -} - -// vndkproduct_libraries_txt is a singleton module whose content is a list of VNDK product libraries -// generated by Soong but can be referenced by other modules. -// For example, apex_vndk can depend on these files as prebuilt. -func vndkProductLibrariesTxtFactory() android.SingletonModule { - return newVndkLibrariesTxt(vndkProductLibraries, "VNDK_PRODUCT_LIBRARIES") -} - -// vndkcorevariant_libraries_txt is a singleton module whose content is a list of VNDK libraries -// that are using the core variant, generated by Soong but can be referenced by other modules. -// For example, apex_vndk can depend on these files as prebuilt. -func vndkUsingCoreVariantLibrariesTxtFactory() android.SingletonModule { - return newVndkLibrariesTxt(vndkUsingCoreVariantLibraries, "VNDK_USING_CORE_VARIANT_LIBRARIES") -} - -func newVndkLibrariesWithMakeVarFilter(lister moduleListerFunc, makeVarName string, filter string) android.SingletonModule { - m := &vndkLibrariesTxt{ - lister: lister, - makeVarName: makeVarName, - filterOutFromMakeVar: filter, - } - m.AddProperties(&m.properties) - android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) - return m -} - -func newVndkLibrariesTxt(lister moduleListerFunc, makeVarName string) android.SingletonModule { - return newVndkLibrariesWithMakeVarFilter(lister, makeVarName, "") -} - func insertVndkVersion(filename string, vndkVersion string) string { if index := strings.LastIndex(filename, "."); index != -1 { return filename[:index] + "." + vndkVersion + filename[index:] } return filename } - -func (txt *vndkLibrariesTxt) GenerateAndroidBuildActions(ctx android.ModuleContext) { - var filename string - if BoolDefault(txt.properties.Insert_vndk_version, true) { - filename = insertVndkVersion(txt.Name(), ctx.DeviceConfig().PlatformVndkVersion()) - } else { - filename = txt.Name() - } - - txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath - - installPath := android.PathForModuleInstall(ctx, "etc") - ctx.InstallFile(installPath, filename, txt.outputFile) -} - -func (txt *vndkLibrariesTxt) GenerateSingletonBuildActions(ctx android.SingletonContext) { - txt.moduleNames, txt.fileNames = txt.lister(ctx) - android.WriteFileRule(ctx, txt.outputFile, strings.Join(txt.fileNames, "\n")) -} - -func (txt *vndkLibrariesTxt) AndroidMkEntries() []android.AndroidMkEntries { - return []android.AndroidMkEntries{android.AndroidMkEntries{ - Class: "ETC", - OutputFile: android.OptionalPathForPath(txt.outputFile), - ExtraEntries: []android.AndroidMkExtraEntriesFunc{ - func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - entries.SetString("LOCAL_MODULE_STEM", txt.outputFile.Base()) - }, - }, - }} -} - -func (txt *vndkLibrariesTxt) MakeVars(ctx android.MakeVarsContext) { - filter := func(modules []string, prefix string) []string { - if prefix == "" { - return modules - } - var result []string - for _, module := range modules { - if strings.HasPrefix(module, prefix) { - continue - } else { - result = append(result, module) - } - } - return result - } - ctx.Strict(txt.makeVarName, strings.Join(filter(txt.moduleNames, txt.filterOutFromMakeVar), " ")) -} - -// PrebuiltEtcModule interface -func (txt *vndkLibrariesTxt) OutputFile() android.OutputPath { - return txt.outputFile -} - -// PrebuiltEtcModule interface -func (txt *vndkLibrariesTxt) BaseDir() string { - return "etc" -} - -// PrebuiltEtcModule interface -func (txt *vndkLibrariesTxt) SubDir() string { - return "" -} - -func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) { - return android.Paths{txt.outputFile}, nil -} - -func VndkSnapshotSingleton() android.Singleton { - return &vndkSnapshotSingleton{} -} - -type vndkSnapshotSingleton struct { - vndkLibrariesFile android.OutputPath - vndkSnapshotZipFile android.OptionalPath -} - -func isVndkSnapshotAware(config android.DeviceConfig, m LinkableInterface, - apexInfo android.ApexInfo) (vndkType string, isVndkSnapshotLib bool) { - - if m.Target().NativeBridge == android.NativeBridgeEnabled { - return "", false - } - // !inVendor: There's product/vendor variants for VNDK libs. We only care about vendor variants. - // !installable: Snapshot only cares about "installable" modules. - // !m.IsLlndk: llndk stubs are required for building against snapshots. - // IsSnapshotPrebuilt: Snapshotting a snapshot doesn't make sense. - // !outputFile.Valid: Snapshot requires valid output file. - if !m.InVendor() || (!installable(m, apexInfo) && !m.IsLlndk()) || m.IsSnapshotPrebuilt() || !m.OutputFile().Valid() { - return "", false - } - if !m.IsSnapshotLibrary() || !m.Shared() { - return "", false - } - if m.VndkVersion() == config.PlatformVndkVersion() { - if m.IsVndk() && !m.IsVndkExt() { - if m.IsVndkSp() { - return "vndk-sp", true - } else { - return "vndk-core", true - } - } else if m.HasLlndkStubs() && m.StubsVersion() == "" { - // Use default version for the snapshot. - return "llndk-stub", true - } - } - - return "", false -} - -func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { - // build these files even if PlatformVndkVersion or BoardVndkVersion is not set - c.buildVndkLibrariesTxtFiles(ctx) - - // BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot. - if ctx.DeviceConfig().VndkVersion() != "current" { - return - } - - if ctx.DeviceConfig().PlatformVndkVersion() == "" { - return - } - - var snapshotOutputs android.Paths - - /* - VNDK snapshot zipped artifacts directory structure: - {SNAPSHOT_ARCH}/ - arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/ - shared/ - vndk-core/ - (VNDK-core libraries, e.g. libbinder.so) - vndk-sp/ - (VNDK-SP libraries, e.g. libc++.so) - llndk-stub/ - (LLNDK stub libraries) - arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/ - shared/ - vndk-core/ - (VNDK-core libraries, e.g. libbinder.so) - vndk-sp/ - (VNDK-SP libraries, e.g. libc++.so) - llndk-stub/ - (LLNDK stub libraries) - binder32/ - (This directory is newly introduced in v28 (Android P) to hold - prebuilts built for 32-bit binder interface.) - arch-{TARGET_ARCH}-{TARGE_ARCH_VARIANT}/ - ... - configs/ - (various *.txt configuration files) - include/ - (header files of same directory structure with source tree) - NOTICE_FILES/ - (notice files of libraries, e.g. libcutils.so.txt) - */ - - snapshotDir := "vndk-snapshot" - snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch()) - - configsDir := filepath.Join(snapshotArchDir, "configs") - noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES") - includeDir := filepath.Join(snapshotArchDir, "include") - - // set of notice files copied. - noticeBuilt := make(map[string]bool) - - // paths of VNDK modules for GPL license checking - modulePaths := make(map[string]string) - - // actual module names of .so files - // e.g. moduleNames["libprotobuf-cpp-full-3.9.1.so"] = "libprotobuf-cpp-full" - moduleNames := make(map[string]string) - - var headers android.Paths - - // installVndkSnapshotLib copies built .so file from the module. - // Also, if the build artifacts is on, write a json file which contains all exported flags - // with FlagExporterInfo. - installVndkSnapshotLib := func(m *Module, vndkType string) (android.Paths, bool) { - var ret android.Paths - - targetArch := "arch-" + m.Target().Arch.ArchType.String() - if m.Target().Arch.ArchVariant != "" { - targetArch += "-" + m.Target().Arch.ArchVariant - } - - libPath := m.outputFile.Path() - snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "shared", vndkType, libPath.Base()) - ret = append(ret, snapshot.CopyFileRule(pctx, ctx, libPath, snapshotLibOut)) - - // json struct to export snapshot information - prop := struct { - MinSdkVersion string `json:",omitempty"` - LicenseKinds []string `json:",omitempty"` - LicenseTexts []string `json:",omitempty"` - ExportedDirs []string `json:",omitempty"` - ExportedSystemDirs []string `json:",omitempty"` - ExportedFlags []string `json:",omitempty"` - RelativeInstallPath string `json:",omitempty"` - }{} - - prop.LicenseKinds = m.EffectiveLicenseKinds() - prop.LicenseTexts = m.EffectiveLicenseFiles().Strings() - prop.MinSdkVersion = m.MinSdkVersion() - - if ctx.Config().VndkSnapshotBuildArtifacts() { - exportedInfo := ctx.ModuleProvider(m, FlagExporterInfoProvider).(FlagExporterInfo) - prop.ExportedFlags = exportedInfo.Flags - prop.ExportedDirs = exportedInfo.IncludeDirs.Strings() - prop.ExportedSystemDirs = exportedInfo.SystemIncludeDirs.Strings() - prop.RelativeInstallPath = m.RelativeInstallPath() - } - - propOut := snapshotLibOut + ".json" - - j, err := json.Marshal(prop) - if err != nil { - ctx.Errorf("json marshal to %q failed: %#v", propOut, err) - return nil, false - } - ret = append(ret, snapshot.WriteStringToFileRule(ctx, string(j), propOut)) - - return ret, true - } - - ctx.VisitAllModules(func(module android.Module) { - m, ok := module.(*Module) - if !ok || !m.Enabled() { - return - } - - apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo) - - vndkType, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo) - if !ok { - return - } - - // For all snapshot candidates, the followings are captured. - // - .so files - // - notice files - // - // The followings are also captured if VNDK_SNAPSHOT_BUILD_ARTIFACTS. - // - .json files containing exported flags - // - exported headers from collectHeadersForSnapshot() - // - // Headers are deduplicated after visiting all modules. - - // install .so files for appropriate modules. - // Also install .json files if VNDK_SNAPSHOT_BUILD_ARTIFACTS - libs, ok := installVndkSnapshotLib(m, vndkType) - if !ok { - return - } - snapshotOutputs = append(snapshotOutputs, libs...) - - // These are for generating module_names.txt and module_paths.txt - stem := m.outputFile.Path().Base() - moduleNames[stem] = ctx.ModuleName(m) - modulePaths[stem] = ctx.ModuleDir(m) - - for _, notice := range m.EffectiveLicenseFiles() { - if _, ok := noticeBuilt[notice.String()]; !ok { - noticeBuilt[notice.String()] = true - snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule( - pctx, ctx, notice, filepath.Join(noticeDir, notice.String()))) - } - } - - if ctx.Config().VndkSnapshotBuildArtifacts() { - headers = append(headers, m.SnapshotHeaders()...) - } - }) - - // install all headers after removing duplicates - for _, header := range android.FirstUniquePaths(headers) { - snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule( - pctx, ctx, header, filepath.Join(includeDir, header.String()))) - } - - // install *.libraries.txt except vndkcorevariant.libraries.txt - ctx.VisitAllModules(func(module android.Module) { - m, ok := module.(*vndkLibrariesTxt) - if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt { - return - } - snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule( - pctx, ctx, m.OutputFile(), filepath.Join(configsDir, m.Name()))) - }) - - /* - module_paths.txt contains paths on which VNDK modules are defined. - e.g., - libbase.so system/libbase - libc.so bionic/libc - ... - */ - snapshotOutputs = append(snapshotOutputs, installMapListFileRule(ctx, modulePaths, filepath.Join(configsDir, "module_paths.txt"))) - - /* - module_names.txt contains names as which VNDK modules are defined, - because output filename and module name can be different with stem and suffix properties. - - e.g., - libcutils.so libcutils - libprotobuf-cpp-full-3.9.2.so libprotobuf-cpp-full - ... - */ - snapshotOutputs = append(snapshotOutputs, installMapListFileRule(ctx, moduleNames, filepath.Join(configsDir, "module_names.txt"))) - - // All artifacts are ready. Sort them to normalize ninja and then zip. - sort.Slice(snapshotOutputs, func(i, j int) bool { - return snapshotOutputs[i].String() < snapshotOutputs[j].String() - }) - - zipPath := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+".zip") - zipRule := android.NewRuleBuilder(pctx, ctx) - - // filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr - snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+"_list") - rspFile := snapshotOutputList.ReplaceExtension(ctx, "rsp") - zipRule.Command(). - Text("tr"). - FlagWithArg("-d ", "\\'"). - FlagWithRspFileInputList("< ", rspFile, snapshotOutputs). - FlagWithOutput("> ", snapshotOutputList) - - zipRule.Temporary(snapshotOutputList) - - zipRule.Command(). - BuiltTool("soong_zip"). - FlagWithOutput("-o ", zipPath). - FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()). - FlagWithInput("-l ", snapshotOutputList) - - zipRule.Build(zipPath.String(), "vndk snapshot "+zipPath.String()) - zipRule.DeleteTemporaryFiles() - c.vndkSnapshotZipFile = android.OptionalPathForPath(zipPath) -} - -func getVndkFileName(m *Module) (string, error) { - if library, ok := m.linker.(*libraryDecorator); ok { - return library.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil - } - if prebuilt, ok := m.linker.(*prebuiltLibraryLinker); ok { - return prebuilt.libraryDecorator.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil - } - return "", fmt.Errorf("VNDK library should have libraryDecorator or prebuiltLibraryLinker as linker: %T", m.linker) -} - -func (c *vndkSnapshotSingleton) buildVndkLibrariesTxtFiles(ctx android.SingletonContext) { - // Build list of vndk libs as merged & tagged & filter-out(libclang_rt): - // Since each target have different set of libclang_rt.* files, - // keep the common set of files in vndk.libraries.txt - _, llndk := vndkModuleListRemover(llndkLibraries, "libclang_rt.")(ctx) - _, vndkcore := vndkModuleListRemover(vndkCoreLibraries, "libclang_rt.")(ctx) - _, vndksp := vndkSPLibraries(ctx) - _, vndkprivate := vndkPrivateLibraries(ctx) - _, vndkproduct := vndkModuleListRemover(vndkProductLibraries, "libclang_rt.")(ctx) - var merged []string - merged = append(merged, addPrefix(llndk, "LLNDK: ")...) - merged = append(merged, addPrefix(vndksp, "VNDK-SP: ")...) - merged = append(merged, addPrefix(vndkcore, "VNDK-core: ")...) - merged = append(merged, addPrefix(vndkprivate, "VNDK-private: ")...) - merged = append(merged, addPrefix(vndkproduct, "VNDK-product: ")...) - c.vndkLibrariesFile = android.PathForOutput(ctx, "vndk", "vndk.libraries.txt") - android.WriteFileRule(ctx, c.vndkLibrariesFile, strings.Join(merged, "\n")) -} - -func (c *vndkSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) { - // Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if - // they been moved to an apex. - movedToApexLlndkLibraries := make(map[string]bool) - ctx.VisitAllModules(func(module android.Module) { - if library := moduleLibraryInterface(module); library != nil && library.hasLLNDKStubs() { - // Skip bionic libs, they are handled in different manner - name := library.implementationModuleName(module.(*Module).BaseModuleName()) - if module.(android.ApexModule).DirectlyInAnyApex() && !isBionic(name) { - movedToApexLlndkLibraries[name] = true - } - } - }) - - ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", - strings.Join(android.SortedKeys(movedToApexLlndkLibraries), " ")) - - ctx.Strict("VNDK_LIBRARIES_FILE", c.vndkLibrariesFile.String()) - ctx.Strict("SOONG_VNDK_SNAPSHOT_ZIP", c.vndkSnapshotZipFile.String()) -} diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go index 37819a4be..e7dff4012 100644 --- a/cc/vndk_prebuilt.go +++ b/cc/vndk_prebuilt.go @@ -49,6 +49,8 @@ var ( // }, // } type vndkPrebuiltProperties struct { + VndkProperties + // VNDK snapshot version. Version *string @@ -131,7 +133,6 @@ func (p *vndkPrebuiltLibraryDecorator) singleSourcePath(ctx ModuleContext) andro func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { - if !p.MatchesWithDevice(ctx.DeviceConfig()) { ctx.Module().HideFromMake() return nil @@ -160,12 +161,7 @@ func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, p.androidMkSuffix = p.NameSuffix() - vndkVersion := ctx.DeviceConfig().VndkVersion() - if vndkVersion == p.Version() { - p.androidMkSuffix = "" - } - - ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{ + android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{ SharedLibrary: in, Target: ctx.Target(), @@ -181,6 +177,11 @@ func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, return nil } +func (p *vndkPrebuiltLibraryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + p.libraryDecorator.moduleInfoJSON(ctx, moduleInfoJSON) + moduleInfoJSON.SubName += p.androidMkSuffix +} + func (p *vndkPrebuiltLibraryDecorator) MatchesWithDevice(config android.DeviceConfig) bool { arches := config.Arches() if len(arches) == 0 || arches[0].ArchType.String() != p.arch() { @@ -221,6 +222,7 @@ func vndkPrebuiltSharedLibrary() *Module { prebuilt.properties.Check_elf_files = BoolPtr(false) prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true) prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true) + prebuilt.baseLinker.Properties.No_crt_pad_segment = BoolPtr(true) // Prevent default system libs (libc, libm, and libdl) from being linked if prebuilt.baseLinker.Properties.System_shared_libs == nil { @@ -235,14 +237,6 @@ func vndkPrebuiltSharedLibrary() *Module { &prebuilt.properties, ) - android.AddLoadHook(module, func(ctx android.LoadHookContext) { - // empty BOARD_VNDK_VERSION implies that the device won't support - // system only OTA. In this case, VNDK snapshots aren't needed. - if ctx.DeviceConfig().VndkVersion() == "" { - ctx.Module().Disable() - } - }) - return module } @@ -276,3 +270,14 @@ func VndkPrebuiltSharedFactory() android.Module { func init() { android.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory) } + +func IsForVndkApex(mctx android.BottomUpMutatorContext, m *Module) bool { + if !m.Enabled(mctx) { + return true + } + + if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok { + return p.MatchesWithDevice(mctx.DeviceConfig()) && Bool(p.properties.Vndk.Enabled) + } + return false +} |