diff options
178 files changed, 8737 insertions, 3066 deletions
diff --git a/android/Android.bp b/android/Android.bp index 977345b6b..a1b515940 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -15,6 +15,7 @@ bootstrap_go_package { "apex.go", "api_levels.go", "arch.go", + "bazel_overlay.go", "config.go", "csuite_config.go", "defaults.go", @@ -24,6 +25,7 @@ bootstrap_go_package { "filegroup.go", "hooks.go", "image.go", + "makefile_goal.go", "makevars.go", "metrics.go", "module.go", @@ -39,6 +41,7 @@ bootstrap_go_package { "paths.go", "phony.go", "prebuilt.go", + "prebuilt_build_tool.go", "proto.go", "register.go", "rule_builder.go", @@ -46,6 +49,7 @@ bootstrap_go_package { "sdk.go", "singleton.go", "soong_config_modules.go", + "test_suites.go", "testing.go", "util.go", "variable.go", diff --git a/android/androidmk.go b/android/androidmk.go index dfc68c437..fafbfd61e 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -126,6 +126,26 @@ func (a *AndroidMkEntries) AddOptionalPath(name string, path OptionalPath) { } } +func (a *AndroidMkEntries) SetPaths(name string, paths Paths) { + if _, ok := a.EntryMap[name]; !ok { + a.entryOrder = append(a.entryOrder, name) + } + a.EntryMap[name] = paths.Strings() +} + +func (a *AndroidMkEntries) SetOptionalPaths(name string, paths Paths) { + if len(paths) > 0 { + a.SetPaths(name, paths) + } +} + +func (a *AndroidMkEntries) AddPaths(name string, paths Paths) { + if _, ok := a.EntryMap[name]; !ok { + a.entryOrder = append(a.entryOrder, name) + } + a.EntryMap[name] = append(a.EntryMap[name], paths.Strings()...) +} + func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) { if flag { if _, ok := a.EntryMap[name]; !ok { @@ -163,12 +183,15 @@ func (a *AndroidMkEntries) GetDistForGoals(mod blueprint.Module) []string { name := amod.BaseModuleName() var ret []string + var availableTaggedDists TaggedDistFiles - availableTaggedDists := TaggedDistFiles{} - if a.DistFiles != nil && len(a.DistFiles[""]) > 0 { + if a.DistFiles != nil { availableTaggedDists = a.DistFiles } else if a.OutputFile.Valid() { availableTaggedDists = MakeDefaultDistFiles(a.OutputFile.Path()) + } else { + // Nothing dist-able for this module. + return nil } // Iterate over this module's dist structs, merged from the dist and dists properties. diff --git a/android/androidmk_test.go b/android/androidmk_test.go index 250f086e5..a558f453f 100644 --- a/android/androidmk_test.go +++ b/android/androidmk_test.go @@ -45,6 +45,8 @@ func (m *customModule) OutputFiles(tag string) (Paths, error) { return PathsForTesting("one.out"), nil case ".multiple": return PathsForTesting("two.out", "three/four.out"), nil + case ".another-tag": + return PathsForTesting("another.out"), nil default: return nil, fmt.Errorf("unsupported module reference tag %q", tag) } @@ -123,6 +125,38 @@ func TestGetDistForGoals(t *testing.T) { bp: ` custom { name: "foo", + dist: { + targets: ["my_goal"], + tag: ".another-tag", + } + } + `, + expectedAndroidMkLines: []string{ + ".PHONY: my_goal\n", + "$(call dist-for-goals,my_goal,another.out:another.out)\n", + }, + }, + { + bp: ` + custom { + name: "foo", + dists: [ + { + targets: ["my_goal"], + tag: ".another-tag", + }, + ], + } + `, + expectedAndroidMkLines: []string{ + ".PHONY: my_goal\n", + "$(call dist-for-goals,my_goal,another.out:another.out)\n", + }, + }, + { + bp: ` + custom { + name: "foo", dists: [ { targets: ["my_goal"], diff --git a/android/apex.go b/android/apex.go index 47f07ca96..f857ec692 100644 --- a/android/apex.go +++ b/android/apex.go @@ -29,11 +29,22 @@ const ( ) type ApexInfo struct { - // Name of the apex variant that this module is mutated into - ApexName string + // Name of the apex variation that this module is mutated into + ApexVariationName string MinSdkVersion int Updatable bool + RequiredSdks SdkRefs + + InApexes []string +} + +func (i ApexInfo) mergedName() string { + name := "apex" + strconv.Itoa(i.MinSdkVersion) + for _, sdk := range i.RequiredSdks { + name += "_" + sdk.Name + "_" + sdk.Version + } + return name } // Extracted from ApexModule to make it easier to define custom subsets of the @@ -65,23 +76,26 @@ type ApexModule interface { apexModuleBase() *ApexModuleBase - // Marks that this module should be built for the specified APEXes. + // Marks that this module should be built for the specified APEX. // Call this before apex.apexMutator is run. - BuildForApexes(apexes []ApexInfo) - - // Returns the APEXes that this module will be built for - ApexVariations() []ApexInfo + BuildForApex(apex ApexInfo) + + // Returns the name of APEX variation that this module will be built for. + // Empty string is returned when 'IsForPlatform() == true'. Note that a + // module can beincluded in multiple APEXes, in which case, the module + // is mutated into one or more variants, each of which is for one or + // more APEXes. This method returns the name of the APEX variation of + // the module. + // Call this after apex.apexMutator is run. + ApexVariationName() string - // Returns the name of APEX that this module will be built for. Empty string - // is returned when 'IsForPlatform() == true'. Note that a module can be - // included in multiple APEXes, in which case, the module is mutated into - // multiple modules each of which for an APEX. This method returns the - // name of the APEX that a variant module is for. + // Returns the name of the APEX modules that this variant of this module + // is present in. // Call this after apex.apexMutator is run. - ApexName() string + InApexes() []string // Tests whether this module will be built for the platform or not. - // This is a shortcut for ApexName() == "" + // This is a shortcut for ApexVariationName() == "" IsForPlatform() bool // Tests if this module could have APEX variants. APEX variants are @@ -96,7 +110,7 @@ type ApexModule interface { IsInstallableToApex() bool // Mutate this module into one or more variants each of which is built - // for an APEX marked via BuildForApexes(). + // for an APEX marked via BuildForApex(). CreateApexVariations(mctx BottomUpMutatorContext) []Module // Tests if this module is available for the specified APEX or ":platform" @@ -128,6 +142,15 @@ type ApexModule interface { // Returns nil if this module supports sdkVersion // Otherwise, returns error with reason ShouldSupportSdkVersion(ctx BaseModuleContext, sdkVersion int) error + + // Returns true if this module needs a unique variation per apex, for example if + // use_apex_name_macro is set. + UniqueApexVariations() bool + + // UpdateUniqueApexVariationsForDeps sets UniqueApexVariationsForDeps if any dependencies + // that are in the same APEX have unique APEX variations so that the module can link against + // the right variant. + UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext) } type ApexProperties struct { @@ -137,12 +160,15 @@ type ApexProperties struct { // // "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX. // "//apex_available:platform" refers to non-APEX partitions like "system.img". + // "com.android.gki.*" matches any APEX module name with the prefix "com.android.gki.". // Default is ["//apex_available:platform"]. Apex_available []string Info ApexInfo `blueprint:"mutated"` NotAvailableForPlatform bool `blueprint:"mutated"` + + UniqueApexVariationsForDeps bool `blueprint:"mutated"` } // Marker interface that identifies dependencies that are excluded from APEX @@ -178,30 +204,68 @@ func (m *ApexModuleBase) TestFor() []string { return nil } -func (m *ApexModuleBase) BuildForApexes(apexes []ApexInfo) { +func (m *ApexModuleBase) UniqueApexVariations() bool { + return false +} + +func (m *ApexModuleBase) UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext) { + // anyInSameApex returns true if the two ApexInfo lists contain any values in an InApexes list + // in common. It is used instead of DepIsInSameApex because it needs to determine if the dep + // is in the same APEX due to being directly included, not only if it is included _because_ it + // is a dependency. + anyInSameApex := func(a, b []ApexInfo) bool { + collectApexes := func(infos []ApexInfo) []string { + var ret []string + for _, info := range infos { + ret = append(ret, info.InApexes...) + } + return ret + } + + aApexes := collectApexes(a) + bApexes := collectApexes(b) + sort.Strings(bApexes) + for _, aApex := range aApexes { + index := sort.SearchStrings(bApexes, aApex) + if index < len(bApexes) && bApexes[index] == aApex { + return true + } + } + return false + } + + mctx.VisitDirectDeps(func(dep Module) { + if depApexModule, ok := dep.(ApexModule); ok { + if anyInSameApex(depApexModule.apexModuleBase().apexVariations, m.apexVariations) && + (depApexModule.UniqueApexVariations() || + depApexModule.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps) { + m.ApexProperties.UniqueApexVariationsForDeps = true + } + } + }) +} + +func (m *ApexModuleBase) BuildForApex(apex ApexInfo) { m.apexVariationsLock.Lock() defer m.apexVariationsLock.Unlock() -nextApex: - for _, apex := range apexes { - for _, v := range m.apexVariations { - if v.ApexName == apex.ApexName { - continue nextApex - } + for _, v := range m.apexVariations { + if v.ApexVariationName == apex.ApexVariationName { + return } - m.apexVariations = append(m.apexVariations, apex) } + m.apexVariations = append(m.apexVariations, apex) } -func (m *ApexModuleBase) ApexVariations() []ApexInfo { - return m.apexVariations +func (m *ApexModuleBase) ApexVariationName() string { + return m.ApexProperties.Info.ApexVariationName } -func (m *ApexModuleBase) ApexName() string { - return m.ApexProperties.Info.ApexName +func (m *ApexModuleBase) InApexes() []string { + return m.ApexProperties.Info.InApexes } func (m *ApexModuleBase) IsForPlatform() bool { - return m.ApexProperties.Info.ApexName == "" + return m.ApexProperties.Info.ApexVariationName == "" } func (m *ApexModuleBase) CanHaveApexVariants() bool { @@ -216,6 +280,7 @@ func (m *ApexModuleBase) IsInstallableToApex() bool { const ( AvailableToPlatform = "//apex_available:platform" AvailableToAnyApex = "//apex_available:anyapex" + AvailableToGkiApex = "com.android.gki.*" ) func CheckAvailableForApex(what string, apex_available []string) bool { @@ -225,7 +290,8 @@ func CheckAvailableForApex(what string, apex_available []string) bool { return what == AvailableToPlatform } return InList(what, apex_available) || - (what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available)) + (what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available)) || + (strings.HasPrefix(what, "com.android.gki.") && InList(AvailableToGkiApex, apex_available)) } func (m *ApexModuleBase) AvailableFor(what string) bool { @@ -259,7 +325,7 @@ func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, maxSdkVersion in func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) { for _, n := range m.ApexProperties.Apex_available { - if n == AvailableToPlatform || n == AvailableToAnyApex { + if n == AvailableToPlatform || n == AvailableToAnyApex || n == AvailableToGkiApex { continue } if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() { @@ -276,17 +342,48 @@ type byApexName []ApexInfo func (a byApexName) Len() int { return len(a) } func (a byApexName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byApexName) Less(i, j int) bool { return a[i].ApexName < a[j].ApexName } +func (a byApexName) Less(i, j int) bool { return a[i].ApexVariationName < a[j].ApexVariationName } + +// mergeApexVariations deduplicates APEX variations that would build identically into a common +// variation. It returns the reduced list of variations and a list of aliases from the original +// variation names to the new variation names. +func mergeApexVariations(apexVariations []ApexInfo) (merged []ApexInfo, aliases [][2]string) { + sort.Sort(byApexName(apexVariations)) + seen := make(map[string]int) + for _, apexInfo := range apexVariations { + apexName := apexInfo.ApexVariationName + mergedName := apexInfo.mergedName() + if index, exists := seen[mergedName]; exists { + merged[index].InApexes = append(merged[index].InApexes, apexName) + merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable + } else { + seen[mergedName] = len(merged) + apexInfo.ApexVariationName = apexInfo.mergedName() + apexInfo.InApexes = CopyOf(apexInfo.InApexes) + merged = append(merged, apexInfo) + } + aliases = append(aliases, [2]string{apexName, mergedName}) + } + return merged, aliases +} func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Module { if len(m.apexVariations) > 0 { m.checkApexAvailableProperty(mctx) - sort.Sort(byApexName(m.apexVariations)) + var apexVariations []ApexInfo + var aliases [][2]string + if !mctx.Module().(ApexModule).UniqueApexVariations() && !m.ApexProperties.UniqueApexVariationsForDeps { + apexVariations, aliases = mergeApexVariations(m.apexVariations) + } else { + apexVariations = m.apexVariations + } + + sort.Sort(byApexName(apexVariations)) variations := []string{} variations = append(variations, "") // Original variation for platform - for _, apex := range m.apexVariations { - variations = append(variations, apex.ApexName) + for _, apex := range apexVariations { + variations = append(variations, apex.ApexVariationName) } defaultVariation := "" @@ -296,12 +393,20 @@ func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Mod for i, mod := range modules { platformVariation := i == 0 if platformVariation && !mctx.Host() && !mod.(ApexModule).AvailableFor(AvailableToPlatform) { - mod.SkipInstall() + // Do not install the module for platform, but still allow it to output + // uninstallable AndroidMk entries in certain cases when they have + // side effects. + mod.MakeUninstallable() } if !platformVariation { - mod.(ApexModule).apexModuleBase().ApexProperties.Info = m.apexVariations[i-1] + mod.(ApexModule).apexModuleBase().ApexProperties.Info = apexVariations[i-1] } } + + for _, alias := range aliases { + mctx.CreateAliasVariation(alias[0], alias[1]) + } + return modules } return nil @@ -327,16 +432,17 @@ func apexNamesMap() map[string]map[string]bool { // depended on by the specified APEXes. Directly depending means that a module // is explicitly listed in the build definition of the APEX via properties like // native_shared_libs, java_libs, etc. -func UpdateApexDependency(apexes []ApexInfo, moduleName string, directDep bool) { +func UpdateApexDependency(apex ApexInfo, moduleName string, directDep bool) { apexNamesMapMutex.Lock() defer apexNamesMapMutex.Unlock() - for _, apex := range apexes { - apexesForModule, ok := apexNamesMap()[moduleName] - if !ok { - apexesForModule = make(map[string]bool) - apexNamesMap()[moduleName] = apexesForModule - } - apexesForModule[apex.ApexName] = apexesForModule[apex.ApexName] || directDep + apexesForModule, ok := apexNamesMap()[moduleName] + if !ok { + apexesForModule = make(map[string]bool) + apexNamesMap()[moduleName] = apexesForModule + } + apexesForModule[apex.ApexVariationName] = apexesForModule[apex.ApexVariationName] || directDep + for _, apexName := range apex.InApexes { + apexesForModule[apexName] = apexesForModule[apex.ApexVariationName] || directDep } } @@ -353,12 +459,26 @@ func ClearApexDependency() { func DirectlyInApex(apexName string, moduleName string) bool { apexNamesMapMutex.Lock() defer apexNamesMapMutex.Unlock() - if apexNames, ok := apexNamesMap()[moduleName]; ok { - return apexNames[apexName] + if apexNamesForModule, ok := apexNamesMap()[moduleName]; ok { + return apexNamesForModule[apexName] } return false } +// Tests whether a module named moduleName is directly depended on by all APEXes +// in a list of apexNames. +func DirectlyInAllApexes(apexNames []string, moduleName string) bool { + apexNamesMapMutex.Lock() + defer apexNamesMapMutex.Unlock() + for _, apexName := range apexNames { + apexNamesForModule := apexNamesMap()[moduleName] + if !apexNamesForModule[apexName] { + return false + } + } + return true +} + type hostContext interface { Host() bool } diff --git a/android/apex_test.go b/android/apex_test.go new file mode 100644 index 000000000..db02833e7 --- /dev/null +++ b/android/apex_test.go @@ -0,0 +1,111 @@ +// Copyright 2020 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 android + +import ( + "reflect" + "testing" +) + +func Test_mergeApexVariations(t *testing.T) { + tests := []struct { + name string + in []ApexInfo + wantMerged []ApexInfo + wantAliases [][2]string + }{ + { + name: "single", + in: []ApexInfo{ + {"foo", 10000, false, nil, []string{"foo"}}, + }, + wantMerged: []ApexInfo{ + {"apex10000", 10000, false, nil, []string{"foo"}}, + }, + wantAliases: [][2]string{ + {"foo", "apex10000"}, + }, + }, + { + name: "merge", + in: []ApexInfo{ + {"foo", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}}, + {"bar", 10000, false, SdkRefs{{"baz", "1"}}, []string{"bar"}}, + }, + wantMerged: []ApexInfo{ + {"apex10000_baz_1", 10000, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}}, + }, + wantAliases: [][2]string{ + {"bar", "apex10000_baz_1"}, + {"foo", "apex10000_baz_1"}, + }, + }, + { + name: "don't merge version", + in: []ApexInfo{ + {"foo", 10000, false, nil, []string{"foo"}}, + {"bar", 30, false, nil, []string{"bar"}}, + }, + wantMerged: []ApexInfo{ + {"apex30", 30, false, nil, []string{"bar"}}, + {"apex10000", 10000, false, nil, []string{"foo"}}, + }, + wantAliases: [][2]string{ + {"bar", "apex30"}, + {"foo", "apex10000"}, + }, + }, + { + name: "merge updatable", + in: []ApexInfo{ + {"foo", 10000, false, nil, []string{"foo"}}, + {"bar", 10000, true, nil, []string{"bar"}}, + }, + wantMerged: []ApexInfo{ + {"apex10000", 10000, true, nil, []string{"bar", "foo"}}, + }, + wantAliases: [][2]string{ + {"bar", "apex10000"}, + {"foo", "apex10000"}, + }, + }, + { + name: "don't merge sdks", + in: []ApexInfo{ + {"foo", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}}, + {"bar", 10000, false, SdkRefs{{"baz", "2"}}, []string{"bar"}}, + }, + wantMerged: []ApexInfo{ + {"apex10000_baz_2", 10000, false, SdkRefs{{"baz", "2"}}, []string{"bar"}}, + {"apex10000_baz_1", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}}, + }, + wantAliases: [][2]string{ + {"bar", "apex10000_baz_2"}, + {"foo", "apex10000_baz_1"}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotMerged, gotAliases := mergeApexVariations(tt.in) + if !reflect.DeepEqual(gotMerged, tt.wantMerged) { + t.Errorf("mergeApexVariations() gotMerged = %v, want %v", gotMerged, tt.wantMerged) + } + if !reflect.DeepEqual(gotAliases, tt.wantAliases) { + t.Errorf("mergeApexVariations() gotAliases = %v, want %v", gotAliases, tt.wantAliases) + } + }) + } +} diff --git a/android/bazel_overlay.go b/android/bazel_overlay.go new file mode 100644 index 000000000..a0342826d --- /dev/null +++ b/android/bazel_overlay.go @@ -0,0 +1,76 @@ +// Copyright 2020 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 android + +import ( + "fmt" + "os" + "strings" + + "github.com/google/blueprint" +) + +// The Bazel Overlay singleton is responsible for generating the Ninja actions +// for calling the soong_build primary builder in the main build.ninja file. +func init() { + RegisterSingletonType("bazel_overlay", BazelOverlaySingleton) +} + +func BazelOverlaySingleton() Singleton { + return &bazelOverlaySingleton{} +} + +type bazelOverlaySingleton struct{} + +func (c *bazelOverlaySingleton) GenerateBuildActions(ctx SingletonContext) { + // Create a build and rule statement, using the Bazel overlay's WORKSPACE + // file as the output file marker. + var deps Paths + moduleListFilePath := pathForBuildToolDep(ctx, ctx.Config().moduleListFile) + deps = append(deps, moduleListFilePath) + deps = append(deps, pathForBuildToolDep(ctx, ctx.Config().ProductVariablesFileName)) + + bazelOverlayDirectory := PathForOutput(ctx, "bazel_overlay") + bazelOverlayWorkspaceFile := bazelOverlayDirectory.Join(ctx, "WORKSPACE") + primaryBuilder := primaryBuilderPath(ctx) + bazelOverlay := ctx.Rule(pctx, "bazelOverlay", + blueprint.RuleParams{ + Command: fmt.Sprintf( + "rm -rf ${outDir}/* && %s --bazel_overlay_dir ${outDir} %s && echo WORKSPACE: `cat %s` > ${outDir}/.overlay-depfile.d", + primaryBuilder.String(), + strings.Join(os.Args[1:], " "), + moduleListFilePath.String(), // Use the contents of Android.bp.list as the depfile. + ), + CommandDeps: []string{primaryBuilder.String()}, + Description: fmt.Sprintf( + "Creating the Bazel overlay workspace with %s at $outDir", + primaryBuilder.Base()), + Deps: blueprint.DepsGCC, + Depfile: "${outDir}/.overlay-depfile.d", + }, + "outDir") + + ctx.Build(pctx, BuildParams{ + Rule: bazelOverlay, + Output: bazelOverlayWorkspaceFile, + Inputs: deps, + Args: map[string]string{ + "outDir": bazelOverlayDirectory.String(), + }, + }) + + // Add a phony target for building the bazel overlay + ctx.Phony("bazel_overlay", bazelOverlayWorkspaceFile) +} diff --git a/android/config.go b/android/config.go index d680b652b..dd622e5b2 100644 --- a/android/config.go +++ b/android/config.go @@ -35,6 +35,7 @@ import ( var Bool = proptools.Bool var String = proptools.String +var StringDefault = proptools.StringDefault const FutureApiLevel = 10000 @@ -337,8 +338,8 @@ func NewConfig(srcDir, buildDir string, moduleListFile string) (Config, error) { config: config, } - // Sanity check the build and source directories. This won't catch strange - // configurations with symlinks, but at least checks the obvious cases. + // Soundness check of the build and source directories. This won't catch strange + // configurations with symlinks, but at least checks the obvious case. absBuildDir, err := filepath.Abs(buildDir) if err != nil { return Config{}, err @@ -722,7 +723,7 @@ func (c *config) AllowMissingDependencies() bool { return Bool(c.productVariables.Allow_missing_dependencies) } -// Returns true if building without full platform sources. +// Returns true if a full platform source tree cannot be assumed. func (c *config) UnbundledBuild() bool { return Bool(c.productVariables.Unbundled_build) } @@ -733,18 +734,15 @@ func (c *config) UnbundledBuildApps() bool { return Bool(c.productVariables.Unbundled_build_apps) } -func (c *config) UnbundledBuildUsePrebuiltSdks() bool { - return Bool(c.productVariables.Unbundled_build) && !Bool(c.productVariables.Unbundled_build_sdks_from_source) +// Returns true if building modules against prebuilt SDKs. +func (c *config) AlwaysUsePrebuiltSdks() bool { + return Bool(c.productVariables.Always_use_prebuilt_sdks) } func (c *config) Fuchsia() bool { return Bool(c.productVariables.Fuchsia) } -func (c *config) IsPdkBuild() bool { - return Bool(c.productVariables.Pdk) -} - func (c *config) MinimizeJavaDebugInfo() bool { return Bool(c.productVariables.MinimizeJavaDebugInfo) && !Bool(c.productVariables.Eng) } @@ -913,34 +911,6 @@ func (c *config) ModulesLoadedByPrivilegedModules() []string { return c.productVariables.ModulesLoadedByPrivilegedModules } -// Expected format for apexJarValue = <apex name>:<jar name> -func SplitApexJarPair(ctx PathContext, str string) (string, string) { - pair := strings.SplitN(str, ":", 2) - if len(pair) == 2 { - return pair[0], pair[1] - } else { - reportPathErrorf(ctx, "malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str) - return "error-apex", "error-jar" - } -} - -func GetJarsFromApexJarPairs(ctx PathContext, apexJarPairs []string) []string { - modules := make([]string, len(apexJarPairs)) - for i, p := range apexJarPairs { - _, jar := SplitApexJarPair(ctx, p) - modules[i] = jar - } - return modules -} - -func (c *config) BootJars() []string { - ctx := NullPathContext{Config{ - config: c, - }} - return append(GetJarsFromApexJarPairs(ctx, c.productVariables.BootJars), - GetJarsFromApexJarPairs(ctx, c.productVariables.UpdatableBootJars)...) -} - func (c *config) DexpreoptGlobalConfig(ctx PathContext) ([]byte, error) { if c.productVariables.DexpreoptGlobalConfig == nil { return nil, nil @@ -989,6 +959,10 @@ func (c *deviceConfig) VndkVersion() string { return String(c.config.productVariables.DeviceVndkVersion) } +func (c *deviceConfig) CurrentApiLevelForVendorModules() string { + return StringDefault(c.config.productVariables.DeviceCurrentApiLevelForVendorModules, "current") +} + func (c *deviceConfig) PlatformVndkVersion() string { return String(c.config.productVariables.Platform_vndk_version) } @@ -1252,10 +1226,6 @@ func (c *config) MissingUsesLibraries() []string { return c.productVariables.MissingUsesLibraries } -func (c *deviceConfig) BoardVndkRuntimeDisable() bool { - return Bool(c.config.productVariables.BoardVndkRuntimeDisable) -} - func (c *deviceConfig) DeviceArch() string { return String(c.config.productVariables.DeviceArch) } @@ -1275,3 +1245,189 @@ func (c *deviceConfig) DeviceSecondaryArchVariant() string { func (c *deviceConfig) BoardUsesRecoveryAsBoot() bool { return Bool(c.config.productVariables.BoardUsesRecoveryAsBoot) } + +func (c *deviceConfig) BoardKernelBinaries() []string { + return c.config.productVariables.BoardKernelBinaries +} + +func (c *deviceConfig) BoardKernelModuleInterfaceVersions() []string { + return c.config.productVariables.BoardKernelModuleInterfaceVersions +} + +// The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs. +// Such lists are used in the build system for things like bootclasspath jars or system server jars. +// The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a +// module name. The pairs come from Make product variables as a list of colon-separated strings. +// +// Examples: +// - "com.android.art:core-oj" +// - "platform:framework" +// - "system_ext:foo" +// +type ConfiguredJarList struct { + apexes []string // A list of apex components. + jars []string // A list of jar components. +} + +// The length of the list. +func (l *ConfiguredJarList) Len() int { + return len(l.jars) +} + +// Apex component of idx-th pair on the list. +func (l *ConfiguredJarList) apex(idx int) string { + return l.apexes[idx] +} + +// Jar component of idx-th pair on the list. +func (l *ConfiguredJarList) Jar(idx int) string { + return l.jars[idx] +} + +// If the list contains a pair with the given jar. +func (l *ConfiguredJarList) ContainsJar(jar string) bool { + return InList(jar, l.jars) +} + +// If the list contains the given (apex, jar) pair. +func (l *ConfiguredJarList) containsApexJarPair(apex, jar string) bool { + for i := 0; i < l.Len(); i++ { + if apex == l.apex(i) && jar == l.Jar(i) { + return true + } + } + return false +} + +// Index of the first pair with the given jar on the list, or -1 if none. +func (l *ConfiguredJarList) IndexOfJar(jar string) int { + return IndexList(jar, l.jars) +} + +// Append an (apex, jar) pair to the list. +func (l *ConfiguredJarList) Append(apex string, jar string) { + l.apexes = append(l.apexes, apex) + l.jars = append(l.jars, jar) +} + +// Filter out sublist. +func (l *ConfiguredJarList) RemoveList(list ConfiguredJarList) { + apexes := make([]string, 0, l.Len()) + jars := make([]string, 0, l.Len()) + + for i, jar := range l.jars { + apex := l.apex(i) + if !list.containsApexJarPair(apex, jar) { + apexes = append(apexes, apex) + jars = append(jars, jar) + } + } + + l.apexes = apexes + l.jars = jars +} + +// A copy of itself. +func (l *ConfiguredJarList) CopyOf() ConfiguredJarList { + return ConfiguredJarList{CopyOf(l.apexes), CopyOf(l.jars)} +} + +// A copy of the list of strings containing jar components. +func (l *ConfiguredJarList) CopyOfJars() []string { + return CopyOf(l.jars) +} + +// A copy of the list of strings with colon-separated (apex, jar) pairs. +func (l *ConfiguredJarList) CopyOfApexJarPairs() []string { + pairs := make([]string, 0, l.Len()) + + for i, jar := range l.jars { + apex := l.apex(i) + pairs = append(pairs, apex+":"+jar) + } + + return pairs +} + +// A list of build paths based on the given directory prefix. +func (l *ConfiguredJarList) BuildPaths(ctx PathContext, dir OutputPath) WritablePaths { + paths := make(WritablePaths, l.Len()) + for i, jar := range l.jars { + paths[i] = dir.Join(ctx, ModuleStem(jar)+".jar") + } + return paths +} + +func ModuleStem(module string) string { + // b/139391334: the stem of framework-minus-apex is framework. This is hard coded here until we + // find a good way to query the stem of a module before any other mutators are run. + if module == "framework-minus-apex" { + return "framework" + } + return module +} + +// A list of on-device paths. +func (l *ConfiguredJarList) DevicePaths(cfg Config, ostype OsType) []string { + paths := make([]string, l.Len()) + for i, jar := range l.jars { + apex := l.apexes[i] + name := ModuleStem(jar) + ".jar" + + var subdir string + if apex == "platform" { + subdir = "system/framework" + } else if apex == "system_ext" { + subdir = "system_ext/framework" + } else { + subdir = filepath.Join("apex", apex, "javalib") + } + + if ostype.Class == Host { + paths[i] = filepath.Join(cfg.Getenv("OUT_DIR"), "host", cfg.PrebuiltOS(), subdir, name) + } else { + paths[i] = filepath.Join("/", subdir, name) + } + } + return paths +} + +// Expected format for apexJarValue = <apex name>:<jar name> +func splitConfiguredJarPair(ctx PathContext, str string) (string, string) { + pair := strings.SplitN(str, ":", 2) + if len(pair) == 2 { + return pair[0], pair[1] + } else { + ReportPathErrorf(ctx, "malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str) + return "error-apex", "error-jar" + } +} + +func CreateConfiguredJarList(ctx PathContext, list []string) ConfiguredJarList { + apexes := make([]string, 0, len(list)) + jars := make([]string, 0, len(list)) + + l := ConfiguredJarList{apexes, jars} + + for _, apexjar := range list { + apex, jar := splitConfiguredJarPair(ctx, apexjar) + l.Append(apex, jar) + } + + return l +} + +func EmptyConfiguredJarList() ConfiguredJarList { + return ConfiguredJarList{} +} + +var earlyBootJarsKey = NewOnceKey("earlyBootJars") + +func (c *config) BootJars() []string { + return c.Once(earlyBootJarsKey, func() interface{} { + ctx := NullPathContext{Config{c}} + list := CreateConfiguredJarList(ctx, + append(CopyOf(c.productVariables.BootJars), c.productVariables.UpdatableBootJars...)) + return list.CopyOfJars() + }).([]string) +} diff --git a/android/defs.go b/android/defs.go index 45522246f..83daa0368 100644 --- a/android/defs.go +++ b/android/defs.go @@ -69,7 +69,7 @@ var ( // A symlink rule. Symlink = pctx.AndroidStaticRule("Symlink", blueprint.RuleParams{ - Command: "ln -f -s $fromPath $out", + Command: "rm -f $out && ln -f -s $fromPath $out", Description: "symlink $out", }, "fromPath") diff --git a/android/filegroup.go b/android/filegroup.go index ec522fc06..68311e39a 100644 --- a/android/filegroup.go +++ b/android/filegroup.go @@ -15,9 +15,7 @@ package android import ( - "io" "strings" - "text/template" ) func init() { @@ -71,23 +69,8 @@ func (fg *fileGroup) Srcs() Paths { return append(Paths{}, fg.srcs...) } -var androidMkTemplate = template.Must(template.New("filegroup").Parse(` -ifdef {{.makeVar}} - $(error variable {{.makeVar}} set by soong module is already set in make) -endif -{{.makeVar}} := {{.value}} -.KATI_READONLY := {{.makeVar}} -`)) - -func (fg *fileGroup) AndroidMk() AndroidMkData { - return AndroidMkData{ - Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) { - if makeVar := String(fg.properties.Export_to_make_var); makeVar != "" { - androidMkTemplate.Execute(w, map[string]string{ - "makeVar": makeVar, - "value": strings.Join(fg.srcs.Strings(), " "), - }) - } - }, +func (fg *fileGroup) MakeVars(ctx MakeVarsModuleContext) { + if makeVar := String(fg.properties.Export_to_make_var); makeVar != "" { + ctx.StrictRaw(makeVar, strings.Join(fg.srcs.Strings(), " ")) } } diff --git a/android/makefile_goal.go b/android/makefile_goal.go new file mode 100644 index 000000000..eae3976a8 --- /dev/null +++ b/android/makefile_goal.go @@ -0,0 +1,99 @@ +// Copyright 2020 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 android + +import ( + "fmt" + "io" + "path/filepath" + + "github.com/google/blueprint/proptools" +) + +func init() { + RegisterModuleType("makefile_goal", MakefileGoalFactory) +} + +type makefileGoalProperties struct { + // Sources. + + // Makefile goal output file path, relative to PRODUCT_OUT. + Product_out_path *string +} + +type makefileGoal struct { + ModuleBase + + properties makefileGoalProperties + + // Destination. Output file path of this module. + outputFilePath OutputPath +} + +var _ AndroidMkEntriesProvider = (*makefileGoal)(nil) +var _ OutputFileProducer = (*makefileGoal)(nil) + +// Input file of this makefile_goal module. Nil if none specified. May use variable names in makefiles. +func (p *makefileGoal) inputPath() *string { + if p.properties.Product_out_path != nil { + return proptools.StringPtr(filepath.Join("$(PRODUCT_OUT)", proptools.String(p.properties.Product_out_path))) + } + return nil +} + +// OutputFileProducer +func (p *makefileGoal) OutputFiles(tag string) (Paths, error) { + if tag != "" { + return nil, fmt.Errorf("unsupported tag %q", tag) + } + return Paths{p.outputFilePath}, nil +} + +// AndroidMkEntriesProvider +func (p *makefileGoal) DepsMutator(ctx BottomUpMutatorContext) { + if p.inputPath() == nil { + ctx.PropertyErrorf("product_out_path", "Path relative to PRODUCT_OUT required") + } +} + +func (p *makefileGoal) GenerateAndroidBuildActions(ctx ModuleContext) { + filename := filepath.Base(proptools.String(p.inputPath())) + p.outputFilePath = PathForModuleOut(ctx, filename).OutputPath + + ctx.InstallFile(PathForModuleInstall(ctx, "etc"), ctx.ModuleName(), p.outputFilePath) +} + +func (p *makefileGoal) AndroidMkEntries() []AndroidMkEntries { + return []AndroidMkEntries{AndroidMkEntries{ + Class: "ETC", + OutputFile: OptionalPathForPath(p.outputFilePath), + ExtraFooters: []AndroidMkExtraFootersFunc{ + func(w io.Writer, name, prefix, moduleDir string, entries *AndroidMkEntries) { + // Can't use Cp because inputPath() is not a valid Path. + fmt.Fprintf(w, "$(eval $(call copy-one-file,%s,%s))\n", proptools.String(p.inputPath()), p.outputFilePath) + }, + }, + }} +} + +// Import a Makefile goal to Soong by copying the file built by +// the goal to a path visible to Soong. This rule only works on boot images. +func MakefileGoalFactory() Module { + module := &makefileGoal{} + module.AddProperties(&module.properties) + // This module is device-only + InitAndroidArchModule(module, DeviceSupported, MultilibFirst) + return module +} diff --git a/android/makevars.go b/android/makevars.go index ff7c8e4a7..86f4b424b 100644 --- a/android/makevars.go +++ b/android/makevars.go @@ -17,6 +17,7 @@ package android import ( "bytes" "fmt" + "sort" "strconv" "strings" @@ -34,43 +35,16 @@ func androidMakeVarsProvider(ctx MakeVarsContext) { } /////////////////////////////////////////////////////////////////////////////// -// Interface for other packages to use to declare make variables -type MakeVarsContext interface { + +// BaseMakeVarsContext contains the common functions for other packages to use +// to declare make variables +type BaseMakeVarsContext interface { Config() Config DeviceConfig() DeviceConfig AddNinjaFileDeps(deps ...string) - ModuleName(module blueprint.Module) string - ModuleDir(module blueprint.Module) string - ModuleSubDir(module blueprint.Module) string - ModuleType(module blueprint.Module) string - BlueprintFile(module blueprint.Module) string - - ModuleErrorf(module blueprint.Module, format string, args ...interface{}) - Errorf(format string, args ...interface{}) Failed() bool - VisitAllModules(visit func(Module)) - VisitAllModulesIf(pred func(Module) bool, visit func(Module)) - - // Verify the make variable matches the Soong version, fail the build - // if it does not. If the make variable is empty, just set it. - Strict(name, ninjaStr string) - // Check to see if the make variable matches the Soong version, warn if - // it does not. If the make variable is empty, just set it. - Check(name, ninjaStr string) - - // These are equivalent to the above, but sort the make and soong - // variables before comparing them. They also show the unique entries - // in each list when displaying the difference, instead of the entire - // string. - StrictSorted(name, ninjaStr string) - CheckSorted(name, ninjaStr string) - - // Evaluates a ninja string and returns the result. Used if more - // complicated modification needs to happen before giving it to Make. - Eval(ninjaStr string) (string, error) - // These are equivalent to Strict and Check, but do not attempt to // evaluate the values before writing them to the Makefile. They can // be used when all ninja variables have already been evaluated through @@ -108,6 +82,48 @@ type MakeVarsContext interface { DistForGoalsWithFilename(goals []string, path Path, filename string) } +// MakeVarsContext contains the set of functions available for MakeVarsProvider +// and SingletonMakeVarsProvider implementations. +type MakeVarsContext interface { + BaseMakeVarsContext + + ModuleName(module blueprint.Module) string + ModuleDir(module blueprint.Module) string + ModuleSubDir(module blueprint.Module) string + ModuleType(module blueprint.Module) string + BlueprintFile(module blueprint.Module) string + + ModuleErrorf(module blueprint.Module, format string, args ...interface{}) + Errorf(format string, args ...interface{}) + + VisitAllModules(visit func(Module)) + VisitAllModulesIf(pred func(Module) bool, visit func(Module)) + + // Verify the make variable matches the Soong version, fail the build + // if it does not. If the make variable is empty, just set it. + Strict(name, ninjaStr string) + // Check to see if the make variable matches the Soong version, warn if + // it does not. If the make variable is empty, just set it. + Check(name, ninjaStr string) + + // These are equivalent to the above, but sort the make and soong + // variables before comparing them. They also show the unique entries + // in each list when displaying the difference, instead of the entire + // string. + StrictSorted(name, ninjaStr string) + CheckSorted(name, ninjaStr string) + + // Evaluates a ninja string and returns the result. Used if more + // complicated modification needs to happen before giving it to Make. + Eval(ninjaStr string) (string, error) +} + +// MakeVarsModuleContext contains the set of functions available for modules +// implementing the ModuleMakeVarsProvider interface. +type MakeVarsModuleContext interface { + BaseMakeVarsContext +} + var _ PathContext = MakeVarsContext(nil) type MakeVarsProvider func(ctx MakeVarsContext) @@ -135,6 +151,14 @@ func SingletonmakeVarsProviderAdapter(singleton SingletonMakeVarsProvider) MakeV return func(ctx MakeVarsContext) { singleton.MakeVars(ctx) } } +// ModuleMakeVarsProvider is a Module with an extra method to provide extra values to be exported to Make. +type ModuleMakeVarsProvider interface { + Module + + // MakeVars uses a MakeVarsModuleContext to provide extra values to be exported to Make. + MakeVars(ctx MakeVarsModuleContext) +} + /////////////////////////////////////////////////////////////////////////////// func makeVarsSingletonFunc() Singleton { @@ -209,10 +233,45 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { dists = append(dists, mctx.dists...) } + ctx.VisitAllModules(func(m Module) { + if provider, ok := m.(ModuleMakeVarsProvider); ok { + mctx := &makeVarsContext{ + SingletonContext: ctx, + } + + provider.MakeVars(mctx) + + vars = append(vars, mctx.vars...) + phonies = append(phonies, mctx.phonies...) + dists = append(dists, mctx.dists...) + } + }) + if ctx.Failed() { return } + sort.Slice(vars, func(i, j int) bool { + return vars[i].name < vars[j].name + }) + sort.Slice(phonies, func(i, j int) bool { + return phonies[i].name < phonies[j].name + }) + lessArr := func(a, b []string) bool { + if len(a) == len(b) { + for i := range a { + if a[i] < b[i] { + return true + } + } + return false + } + return len(a) < len(b) + } + sort.Slice(dists, func(i, j int) bool { + return lessArr(dists[i].goals, dists[j].goals) || lessArr(dists[i].paths, dists[j].paths) + }) + outBytes := s.writeVars(vars) if err := pathtools.WriteFileIfChanged(outFile, outBytes, 0666); err != nil { diff --git a/android/module.go b/android/module.go index 634538f49..32d49fb72 100644 --- a/android/module.go +++ b/android/module.go @@ -97,6 +97,8 @@ type EarlyModuleContext interface { GlobFiles(globPattern string, excludes []string) Paths IsSymlink(path Path) bool Readlink(path Path) string + + Namespace() *Namespace } // BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns @@ -219,7 +221,6 @@ type ModuleContext interface { VisitAllModuleVariants(visit func(Module)) GetMissingDependencies() []string - Namespace() blueprint.Namespace } type Module interface { @@ -257,6 +258,7 @@ type Module interface { InstallForceOS() *OsType SkipInstall() IsSkipInstall() bool + MakeUninstallable() ExportedToMake() bool InitRc() Paths VintfFragments() Paths @@ -549,6 +551,9 @@ type commonProperties struct { SkipInstall bool `blueprint:"mutated"` + // Disabled by mutators. If set to true, it overrides Enabled property. + ForcedDisabled bool `blueprint:"mutated"` + NamespaceExportedToMake bool `blueprint:"mutated"` MissingDeps []string `blueprint:"mutated"` @@ -566,6 +571,12 @@ type commonProperties struct { type TaggedDistFiles map[string]Paths func MakeDefaultDistFiles(paths ...Path) TaggedDistFiles { + for _, path := range paths { + if path == nil { + panic("The path to a dist file cannot be nil.") + } + } + // The default OutputFile tag is the empty "" string. return TaggedDistFiles{"": paths} } @@ -1023,6 +1034,9 @@ func (m *ModuleBase) PartitionTag(config DeviceConfig) string { } func (m *ModuleBase) Enabled() bool { + if m.commonProperties.ForcedDisabled { + return false + } if m.commonProperties.Enabled == nil { return !m.Os().DefaultDisabled } @@ -1030,7 +1044,7 @@ func (m *ModuleBase) Enabled() bool { } func (m *ModuleBase) Disable() { - m.commonProperties.Enabled = proptools.BoolPtr(false) + m.commonProperties.ForcedDisabled = true } func (m *ModuleBase) SkipInstall() { @@ -1041,6 +1055,15 @@ func (m *ModuleBase) IsSkipInstall() bool { return m.commonProperties.SkipInstall == true } +// Similar to SkipInstall, but if the AndroidMk entry would set +// LOCAL_UNINSTALLABLE_MODULE then this variant may still output that entry +// rather than leaving it out altogether. That happens in cases where it would +// have other side effects, in particular when it adds a NOTICE file target, +// which other install targets might depend on. +func (m *ModuleBase) MakeUninstallable() { + m.SkipInstall() +} + func (m *ModuleBase) ExportedToMake() bool { return m.commonProperties.NamespaceExportedToMake } @@ -1166,7 +1189,7 @@ func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) { var deps Paths - namespacePrefix := ctx.Namespace().(*Namespace).id + namespacePrefix := ctx.Namespace().id if namespacePrefix != "" { namespacePrefix = namespacePrefix + "-" } @@ -1310,7 +1333,7 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) suffix = append(suffix, ctx.Arch().ArchType.String()) } if apex, ok := m.module.(ApexModule); ok && !apex.IsForPlatform() { - suffix = append(suffix, apex.ApexName()) + suffix = append(suffix, apex.ApexVariationName()) } ctx.Variable(pctx, "moduleDesc", desc) @@ -1477,6 +1500,10 @@ func (e *earlyModuleContext) SystemExtSpecific() bool { return e.kind == systemExtSpecificModule } +func (e *earlyModuleContext) Namespace() *Namespace { + return e.EarlyModuleContext.Namespace().(*Namespace) +} + type baseModuleContext struct { bp blueprint.BaseModuleContext earlyModuleContext @@ -1834,7 +1861,7 @@ func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag { // A regexp for removing boilerplate from BaseDependencyTag from the string representation of // a dependency tag. -var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`) +var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`) // PrettyPrintTag returns string representation of the tag, but prefers // custom String() method if available. @@ -1845,7 +1872,7 @@ func PrettyPrintTag(tag blueprint.DependencyTag) string { } // Otherwise, get a default string representation of the tag's struct. - tagString := fmt.Sprintf("%#v", tag) + tagString := fmt.Sprintf("%T: %+v", tag, tag) // Remove the boilerplate from BaseDependencyTag as it adds no value. tagString = tagCleaner.ReplaceAllString(tagString, "") @@ -2220,7 +2247,7 @@ func OutputFileForModule(ctx PathContext, module blueprint.Module, tag string) P return nil } if len(paths) > 1 { - reportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one", + ReportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one", pathContextName(ctx, module)) return nil } diff --git a/android/mutator.go b/android/mutator.go index b70c4ff64..40e61deb2 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -216,6 +216,7 @@ type BottomUpMutatorContext interface { ReplaceDependencies(string) ReplaceDependenciesIf(string, blueprint.ReplaceDependencyPredicate) AliasVariation(variationName string) + CreateAliasVariation(fromVariationName, toVariationName string) } type bottomUpMutatorContext struct { @@ -436,3 +437,7 @@ func (b *bottomUpMutatorContext) ReplaceDependenciesIf(name string, predicate bl func (b *bottomUpMutatorContext) AliasVariation(variationName string) { b.bp.AliasVariation(variationName) } + +func (b *bottomUpMutatorContext) CreateAliasVariation(fromVariationName, toVariationName string) { + b.bp.CreateAliasVariation(fromVariationName, toVariationName) +} diff --git a/android/neverallow.go b/android/neverallow.go index 425303153..8b8e1accf 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -56,6 +56,7 @@ func init() { AddNeverAllowRules(createJavaDeviceForHostRules()...) AddNeverAllowRules(createCcSdkVariantRules()...) AddNeverAllowRules(createUncompressDexRules()...) + AddNeverAllowRules(createMakefileGoalRules()...) } // Add a NeverAllow rule to the set of rules to apply. @@ -193,7 +194,7 @@ func createCcSdkVariantRules() []Rule { // This sometimes works because the APEX modules that contain derive_sdk and // derive_sdk_prefer32 suppress the platform installation rules, but fails when // the APEX modules contain the SDK variant and the platform variant still exists. - "frameworks/base/apex/sdkextensions/derive_sdk", + "packages/modules/SdkExtensions/derive_sdk", // These are for apps and shouldn't be used by non-SDK variant modules. "prebuilts/ndk", "tools/test/graphicsbenchmark/apps/sample_app", @@ -232,6 +233,15 @@ func createUncompressDexRules() []Rule { } } +func createMakefileGoalRules() []Rule { + return []Rule{ + NeverAllow(). + ModuleType("makefile_goal"). + WithoutMatcher("product_out_path", Regexp("^boot[0-9a-zA-Z.-]*[.]img$")). + Because("Only boot images may be imported as a makefile goal."), + } +} + func neverallowMutator(ctx BottomUpMutatorContext) { m, ok := ctx.Module().(Module) if !ok { diff --git a/android/neverallow_test.go b/android/neverallow_test.go index 45d36a69b..56a07dc9d 100644 --- a/android/neverallow_test.go +++ b/android/neverallow_test.go @@ -326,6 +326,20 @@ var neverallowTests = []struct { "module \"outside_art_libraries\": violates neverallow", }, }, + { + name: "disallowed makefile_goal", + fs: map[string][]byte{ + "Android.bp": []byte(` + makefile_goal { + name: "foo", + product_out_path: "boot/trap.img" + } + `), + }, + expectedErrors: []string{ + "Only boot images may be imported as a makefile goal.", + }, + }, } func TestNeverallow(t *testing.T) { @@ -350,6 +364,7 @@ func testNeverallow(config Config) (*TestContext, []error) { ctx.RegisterModuleType("java_library", newMockJavaLibraryModule) ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule) ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule) + ctx.RegisterModuleType("makefile_goal", newMockMakefileGoalModule) ctx.PostDepsMutators(RegisterNeverallowMutator) ctx.Register(config) @@ -438,3 +453,22 @@ func newMockJavaLibraryModule() Module { func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) { } + +type mockMakefileGoalProperties struct { + Product_out_path *string +} + +type mockMakefileGoalModule struct { + ModuleBase + properties mockMakefileGoalProperties +} + +func newMockMakefileGoalModule() Module { + m := &mockMakefileGoalModule{} + m.AddProperties(&m.properties) + InitAndroidModule(m) + return m +} + +func (p *mockMakefileGoalModule) GenerateAndroidBuildActions(ModuleContext) { +} diff --git a/android/override_module.go b/android/override_module.go index 3994084a8..f8342d52d 100644 --- a/android/override_module.go +++ b/android/override_module.go @@ -313,3 +313,15 @@ func replaceDepsOnOverridingModuleMutator(ctx BottomUpMutatorContext) { } } } + +// ModuleNameWithPossibleOverride returns the name of the OverrideModule that overrides the current +// variant of this OverridableModule, or ctx.ModuleName() if this module is not an OverridableModule +// or if this variant is not overridden. +func ModuleNameWithPossibleOverride(ctx ModuleContext) string { + if overridable, ok := ctx.Module().(OverridableModule); ok { + if o := overridable.GetOverriddenBy(); o != "" { + return o + } + } + return ctx.ModuleName() +} diff --git a/android/paths.go b/android/paths.go index 20ff55e85..6b603ba41 100644 --- a/android/paths.go +++ b/android/paths.go @@ -86,13 +86,13 @@ var _ moduleErrorf = blueprint.ModuleContext(nil) // attempts ctx.ModuleErrorf for a better error message first, then falls // back to ctx.Errorf. func reportPathError(ctx PathContext, err error) { - reportPathErrorf(ctx, "%s", err.Error()) + ReportPathErrorf(ctx, "%s", err.Error()) } -// reportPathErrorf will register an error with the attached context. It +// ReportPathErrorf will register an error with the attached context. It // attempts ctx.ModuleErrorf for a better error message first, then falls // back to ctx.Errorf. -func reportPathErrorf(ctx PathContext, format string, args ...interface{}) { +func ReportPathErrorf(ctx PathContext, format string, args ...interface{}) { if mctx, ok := ctx.(moduleErrorf); ok { mctx.ModuleErrorf(format, args...) } else if ectx, ok := ctx.(errorfContext); ok { @@ -155,7 +155,7 @@ func GenPathWithExt(ctx ModuleContext, subdir string, p Path, ext string) Module if path, ok := p.(genPathProvider); ok { return path.genPathWithExt(ctx, subdir, ext) } - reportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p) + ReportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p) return PathForModuleGen(ctx) } @@ -165,7 +165,7 @@ func ObjPathWithExt(ctx ModuleContext, subdir string, p Path, ext string) Module if path, ok := p.(objPathProvider); ok { return path.objPathWithExt(ctx, subdir, ext) } - reportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p) + ReportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p) return PathForModuleObj(ctx) } @@ -176,7 +176,7 @@ func ResPathWithName(ctx ModuleContext, p Path, name string) ModuleResPath { if path, ok := p.(resPathProvider); ok { return path.resPathWithName(ctx, name) } - reportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p) + ReportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p) return PathForModuleRes(ctx) } @@ -416,9 +416,9 @@ func expandOneSrcPath(ctx ModuleContext, s string, expandedExcludes []string) (P } else { p := pathForModuleSrc(ctx, s) if exists, _, err := ctx.Config().fs.Exists(p.String()); err != nil { - reportPathErrorf(ctx, "%s: %s", p, err.Error()) + ReportPathErrorf(ctx, "%s: %s", p, err.Error()) } else if !exists && !ctx.Config().testAllowNonExistentPaths { - reportPathErrorf(ctx, "module source path %q does not exist", p) + ReportPathErrorf(ctx, "module source path %q does not exist", p) } if InList(p.String(), expandedExcludes) { @@ -445,7 +445,7 @@ func pathsForModuleSrcFromFullPath(ctx EarlyModuleContext, paths []string, incDi } path := filepath.Clean(p) if !strings.HasPrefix(path, prefix) { - reportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix) + ReportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix) continue } @@ -801,7 +801,7 @@ func PathForSource(ctx PathContext, pathComponents ...string) SourcePath { } if pathtools.IsGlob(path.String()) { - reportPathErrorf(ctx, "path may not contain a glob: %s", path.String()) + ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String()) } if modCtx, ok := ctx.(ModuleContext); ok && ctx.Config().AllowMissingDependencies() { @@ -813,9 +813,9 @@ func PathForSource(ctx PathContext, pathComponents ...string) SourcePath { modCtx.AddMissingDependencies([]string{path.String()}) } } else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil { - reportPathErrorf(ctx, "%s: %s", path, err.Error()) + ReportPathErrorf(ctx, "%s: %s", path, err.Error()) } else if !exists && !ctx.Config().testAllowNonExistentPaths { - reportPathErrorf(ctx, "source path %q does not exist", path) + ReportPathErrorf(ctx, "source path %q does not exist", path) } return path } @@ -831,7 +831,7 @@ func ExistentPathForSource(ctx PathContext, pathComponents ...string) OptionalPa } if pathtools.IsGlob(path.String()) { - reportPathErrorf(ctx, "path may not contain a glob: %s", path.String()) + ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String()) return OptionalPath{} } @@ -876,17 +876,17 @@ func (p SourcePath) OverlayPath(ctx ModuleContext, path Path) OptionalPath { if srcPath, ok := path.(SourcePath); ok { relDir = srcPath.path } else { - reportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path) + ReportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path) return OptionalPath{} } dir := filepath.Join(p.config.srcDir, p.path, relDir) // Use Glob so that we are run again if the directory is added. if pathtools.IsGlob(dir) { - reportPathErrorf(ctx, "Path may not contain a glob: %s", dir) + ReportPathErrorf(ctx, "Path may not contain a glob: %s", dir) } paths, err := ctx.GlobWithDeps(dir, nil) if err != nil { - reportPathErrorf(ctx, "glob: %s", err.Error()) + ReportPathErrorf(ctx, "glob: %s", err.Error()) return OptionalPath{} } if len(paths) == 0 { @@ -977,7 +977,7 @@ func (p OutputPath) Join(ctx PathContext, paths ...string) OutputPath { // ReplaceExtension creates a new OutputPath with the extension replaced with ext. func (p OutputPath) ReplaceExtension(ctx PathContext, ext string) OutputPath { if strings.Contains(ext, "/") { - reportPathErrorf(ctx, "extension %q cannot contain /", ext) + ReportPathErrorf(ctx, "extension %q cannot contain /", ext) } ret := PathForOutput(ctx, pathtools.ReplaceExtension(p.path, ext)) ret.rel = pathtools.ReplaceExtension(p.rel, ext) @@ -1030,10 +1030,10 @@ func PathForModuleSrc(ctx ModuleContext, pathComponents ...string) Path { } return nil } else if len(paths) == 0 { - reportPathErrorf(ctx, "%q produced no files, expected exactly one", p) + ReportPathErrorf(ctx, "%q produced no files, expected exactly one", p) return nil } else if len(paths) > 1 { - reportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths)) + ReportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths)) } return paths[0] } @@ -1447,7 +1447,7 @@ func validatePath(pathComponents ...string) (string, error) { func PathForPhony(ctx PathContext, phony string) WritablePath { if strings.ContainsAny(phony, "$/") { - reportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony) + ReportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony) } return PhonyPath{basePath{phony, ctx.Config(), ""}} } @@ -1513,7 +1513,7 @@ func PathContextForTesting(config Config) PathContext { func Rel(ctx PathContext, basePath string, targetPath string) string { rel, isRel := MaybeRel(ctx, basePath, targetPath) if !isRel { - reportPathErrorf(ctx, "path %q is not under path %q", targetPath, basePath) + ReportPathErrorf(ctx, "path %q is not under path %q", targetPath, basePath) return "" } return rel @@ -1555,3 +1555,15 @@ func absolutePath(path string) string { } return filepath.Join(absSrcDir, path) } + +// A DataPath represents the path of a file to be used as data, for example +// a test library to be installed alongside a test. +// The data file should be installed (copied from `<SrcPath>`) to +// `<install_root>/<RelativeInstallPath>/<filename>`, or +// `<install_root>/<filename>` if RelativeInstallPath is empty. +type DataPath struct { + // The path of the data file that should be copied into the data directory + SrcPath Path + // The install path of the data file, relative to the install root. + RelativeInstallPath string +} diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go new file mode 100644 index 000000000..1dcf1996b --- /dev/null +++ b/android/prebuilt_build_tool.go @@ -0,0 +1,94 @@ +// Copyright 2020 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 android + +func init() { + RegisterModuleType("prebuilt_build_tool", prebuiltBuildToolFactory) +} + +type prebuiltBuildToolProperties struct { + // Source file to be executed for this build tool + Src *string `android:"path,arch_variant"` + + // Extra files that should trigger rules using this tool to rebuild + Deps []string `android:"path,arch_variant"` + + // Create a make variable with the specified name that contains the path to + // this prebuilt built tool, relative to the root of the source tree. + Export_to_make_var *string +} + +type prebuiltBuildTool struct { + ModuleBase + prebuilt Prebuilt + + properties prebuiltBuildToolProperties + + toolPath OptionalPath +} + +func (t *prebuiltBuildTool) Name() string { + return t.prebuilt.Name(t.ModuleBase.Name()) +} + +func (t *prebuiltBuildTool) Prebuilt() *Prebuilt { + return &t.prebuilt +} + +func (t *prebuiltBuildTool) DepsMutator(ctx BottomUpMutatorContext) { + if t.properties.Src == nil { + ctx.PropertyErrorf("src", "missing prebuilt source file") + } +} + +func (t *prebuiltBuildTool) GenerateAndroidBuildActions(ctx ModuleContext) { + sourcePath := t.prebuilt.SingleSourcePath(ctx) + installedPath := PathForModuleOut(ctx, t.ModuleBase.Name()) + deps := PathsForModuleSrc(ctx, t.properties.Deps) + + ctx.Build(pctx, BuildParams{ + Rule: Symlink, + Output: installedPath, + Input: sourcePath, + Implicits: deps, + Args: map[string]string{ + "fromPath": "$$PWD/" + sourcePath.String(), + }, + }) + + t.toolPath = OptionalPathForPath(installedPath) +} + +func (t *prebuiltBuildTool) MakeVars(ctx MakeVarsModuleContext) { + if makeVar := String(t.properties.Export_to_make_var); makeVar != "" { + ctx.StrictRaw(makeVar, t.toolPath.String()) + } +} + +func (t *prebuiltBuildTool) HostToolPath() OptionalPath { + return t.toolPath +} + +var _ HostToolProvider = &prebuiltBuildTool{} + +// prebuilt_build_tool is to declare prebuilts to be used during the build, particularly for use +// in genrules with the "tools" property. +func prebuiltBuildToolFactory() Module { + module := &prebuiltBuildTool{} + module.AddProperties(&module.properties) + InitSingleSourcePrebuiltModule(module, &module.properties, "Src") + InitAndroidArchModule(module, HostSupportedNoCross, MultilibFirst) + return module +} diff --git a/android/sdk.go b/android/sdk.go index 8115b690b..9ea7ff49c 100644 --- a/android/sdk.go +++ b/android/sdk.go @@ -34,10 +34,8 @@ type RequiredSdks interface { RequiredSdks() SdkRefs } -// SdkAware is the interface that must be supported by any module to become a member of SDK or to be -// built with SDK -type SdkAware interface { - Module +// Provided to improve code navigation with the IDE. +type sdkAwareWithoutModule interface { RequiredSdks sdkBase() *SdkBase @@ -48,6 +46,13 @@ type SdkAware interface { BuildWithSdks(sdks SdkRefs) } +// SdkAware is the interface that must be supported by any module to become a member of SDK or to be +// built with SDK +type SdkAware interface { + Module + sdkAwareWithoutModule +} + // SdkRef refers to a version of an SDK type SdkRef struct { Name string @@ -322,6 +327,12 @@ type SdkMemberType interface { // SdkAware and be added with an SdkMemberTypeDependencyTag tag. HasTransitiveSdkMembers() bool + // Return true if prebuilt host artifacts may be specific to the host OS. Only + // applicable to modules where HostSupported() is true. If this is true, + // snapshots will list each host OS variant explicitly and disable all other + // host OS'es. + IsHostOsDependent() bool + // Add dependencies from the SDK module to all the module variants the member // type contributes to the SDK. `names` is the list of module names given in // the member type property (as returned by SdkPropertyName()) in the SDK @@ -384,6 +395,7 @@ type SdkMemberTypeBase struct { PropertyName string SupportsSdk bool TransitiveSdkMembers bool + HostOsDependent bool } func (b *SdkMemberTypeBase) SdkPropertyName() string { @@ -398,6 +410,10 @@ func (b *SdkMemberTypeBase) HasTransitiveSdkMembers() bool { return b.TransitiveSdkMembers } +func (b *SdkMemberTypeBase) IsHostOsDependent() bool { + return b.HostOsDependent +} + // Encapsulates the information about registered SdkMemberTypes. type SdkMemberTypesRegistry struct { // The list of types sorted by property name. @@ -466,8 +482,7 @@ func RegisterSdkMemberType(memberType SdkMemberType) { // Base structure for all implementations of SdkMemberProperties. // -// Contains common properties that apply across many different member types. These -// are not affected by the optimization to extract common values. +// Contains common properties that apply across many different member types. type SdkMemberPropertiesBase struct { // The number of unique os types supported by the member variants. // @@ -489,9 +504,7 @@ type SdkMemberPropertiesBase struct { Os OsType `sdk:"keep"` // The setting to use for the compile_multilib property. - // - // This property is set after optimization so there is no point in trying to optimize it. - Compile_multilib string `sdk:"keep"` + Compile_multilib string `android:"arch_variant"` } // The os prefix to use for any file paths in the sdk. diff --git a/android/test_suites.go b/android/test_suites.go new file mode 100644 index 000000000..79d0fbc60 --- /dev/null +++ b/android/test_suites.go @@ -0,0 +1,75 @@ +// Copyright 2020 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 android + +func init() { + RegisterSingletonType("testsuites", testSuiteFilesFactory) +} + +func testSuiteFilesFactory() Singleton { + return &testSuiteFiles{} +} + +type testSuiteFiles struct { + robolectric WritablePath +} + +type TestSuiteModule interface { + Module + TestSuites() []string +} + +func (t *testSuiteFiles) GenerateBuildActions(ctx SingletonContext) { + files := make(map[string]map[string]InstallPaths) + + ctx.VisitAllModules(func(m Module) { + if tsm, ok := m.(TestSuiteModule); ok { + for _, testSuite := range tsm.TestSuites() { + if files[testSuite] == nil { + files[testSuite] = make(map[string]InstallPaths) + } + name := ctx.ModuleName(m) + files[testSuite][name] = append(files[testSuite][name], tsm.filesToInstall()...) + } + } + }) + + t.robolectric = robolectricTestSuite(ctx, files["robolectric-tests"]) + + ctx.Phony("robolectric-tests", t.robolectric) +} + +func (t *testSuiteFiles) MakeVars(ctx MakeVarsContext) { + ctx.DistForGoal("robolectric-tests", t.robolectric) +} + +func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) WritablePath { + var installedPaths InstallPaths + for _, module := range SortedStringKeys(files) { + installedPaths = append(installedPaths, files[module]...) + } + testCasesDir := pathForInstall(ctx, BuildOs, "testcases", false).ToMakePath() + + outputFile := PathForOutput(ctx, "packaging", "robolectric-tests.zip") + rule := NewRuleBuilder() + rule.Command().BuiltTool(ctx, "soong_zip"). + FlagWithOutput("-o ", outputFile). + FlagWithArg("-P ", "host/testcases"). + FlagWithArg("-C ", testCasesDir.String()). + FlagWithRspFileInputList("-r ", installedPaths.Paths()) + rule.Build(pctx, ctx, "robolectric_tests_zip", "robolectric-tests.zip") + + return outputFile +} diff --git a/android/testing.go b/android/testing.go index 696efb6f8..8ea4168d1 100644 --- a/android/testing.go +++ b/android/testing.go @@ -119,14 +119,24 @@ func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule { if module == nil { // find all the modules that do exist - allModuleNames := []string{} + var allModuleNames []string + var allVariants []string ctx.VisitAllModules(func(m blueprint.Module) { - allModuleNames = append(allModuleNames, m.(Module).Name()+"("+ctx.ModuleSubDir(m)+")") + allModuleNames = append(allModuleNames, ctx.ModuleName(m)) + if ctx.ModuleName(m) == name { + allVariants = append(allVariants, ctx.ModuleSubDir(m)) + } }) sort.Strings(allModuleNames) - - panic(fmt.Errorf("failed to find module %q variant %q. All modules:\n %s", - name, variant, strings.Join(allModuleNames, "\n "))) + sort.Strings(allVariants) + + if len(allVariants) == 0 { + panic(fmt.Errorf("failed to find module %q. All modules:\n %s", + name, strings.Join(allModuleNames, "\n "))) + } else { + panic(fmt.Errorf("failed to find module %q variant %q. All variants:\n %s", + name, variant, strings.Join(allVariants, "\n "))) + } } return TestingModule{module} @@ -177,19 +187,21 @@ func newTestingBuildParams(provider testBuildProvider, bparams BuildParams) Test } } -func maybeBuildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams { +func maybeBuildParamsFromRule(provider testBuildProvider, rule string) (TestingBuildParams, []string) { + var searchedRules []string for _, p := range provider.BuildParamsForTests() { + searchedRules = append(searchedRules, p.Rule.String()) if strings.Contains(p.Rule.String(), rule) { - return newTestingBuildParams(provider, p) + return newTestingBuildParams(provider, p), searchedRules } } - return TestingBuildParams{} + return TestingBuildParams{}, searchedRules } func buildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams { - p := maybeBuildParamsFromRule(provider, rule) + p, searchRules := maybeBuildParamsFromRule(provider, rule) if p.Rule == nil { - panic(fmt.Errorf("couldn't find rule %q", rule)) + panic(fmt.Errorf("couldn't find rule %q.\nall rules: %v", rule, searchRules)) } return p } @@ -265,7 +277,8 @@ func (m TestingModule) Module() Module { // MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Returns an empty // BuildParams if no rule is found. func (m TestingModule) MaybeRule(rule string) TestingBuildParams { - return maybeBuildParamsFromRule(m.module, rule) + r, _ := maybeBuildParamsFromRule(m.module, rule) + return r } // Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Panics if no rule is found. @@ -318,7 +331,8 @@ func (s TestingSingleton) Singleton() Singleton { // MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Returns an empty // BuildParams if no rule is found. func (s TestingSingleton) MaybeRule(rule string) TestingBuildParams { - return maybeBuildParamsFromRule(s.provider, rule) + r, _ := maybeBuildParamsFromRule(s.provider, rule) + return r } // Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Panics if no rule is found. @@ -384,7 +398,7 @@ func FailIfNoMatchingErrors(t *testing.T, pattern string, errs []error) { if !found { t.Errorf("missing the expected error %q (checked %d error(s))", pattern, len(errs)) for i, err := range errs { - t.Errorf("errs[%d] = %s", i, err) + t.Errorf("errs[%d] = %q", i, err) } } } diff --git a/android/util.go b/android/util.go index 8dbf21459..65c5f1b28 100644 --- a/android/util.go +++ b/android/util.go @@ -79,6 +79,20 @@ func JoinWithSuffix(strs []string, suffix string, separator string) string { return string(ret) } +func SortedIntKeys(m interface{}) []int { + v := reflect.ValueOf(m) + if v.Kind() != reflect.Map { + panic(fmt.Sprintf("%#v is not a map", m)) + } + keys := v.MapKeys() + s := make([]int, 0, len(keys)) + for _, key := range keys { + s = append(s, int(key.Int())) + } + sort.Ints(s) + return s +} + func SortedStringKeys(m interface{}) []string { v := reflect.ValueOf(m) if v.Kind() != reflect.Map { diff --git a/android/variable.go b/android/variable.go index 2c8bd0720..53f081e8c 100644 --- a/android/variable.go +++ b/android/variable.go @@ -166,13 +166,14 @@ type productVariables struct { Platform_min_supported_target_sdk_version *string `json:",omitempty"` Platform_base_os *string `json:",omitempty"` - DeviceName *string `json:",omitempty"` - DeviceArch *string `json:",omitempty"` - DeviceArchVariant *string `json:",omitempty"` - DeviceCpuVariant *string `json:",omitempty"` - DeviceAbi []string `json:",omitempty"` - DeviceVndkVersion *string `json:",omitempty"` - DeviceSystemSdkVersions []string `json:",omitempty"` + DeviceName *string `json:",omitempty"` + DeviceArch *string `json:",omitempty"` + DeviceArchVariant *string `json:",omitempty"` + DeviceCpuVariant *string `json:",omitempty"` + DeviceAbi []string `json:",omitempty"` + DeviceVndkVersion *string `json:",omitempty"` + DeviceCurrentApiLevelForVendorModules *string `json:",omitempty"` + DeviceSystemSdkVersions []string `json:",omitempty"` DeviceSecondaryArch *string `json:",omitempty"` DeviceSecondaryArchVariant *string `json:",omitempty"` @@ -214,30 +215,29 @@ type productVariables struct { AppsDefaultVersionName *string `json:",omitempty"` - Allow_missing_dependencies *bool `json:",omitempty"` - Unbundled_build *bool `json:",omitempty"` - Unbundled_build_apps *bool `json:",omitempty"` - Unbundled_build_sdks_from_source *bool `json:",omitempty"` - Malloc_not_svelte *bool `json:",omitempty"` - Malloc_zero_contents *bool `json:",omitempty"` - Malloc_pattern_fill_contents *bool `json:",omitempty"` - Safestack *bool `json:",omitempty"` - HostStaticBinaries *bool `json:",omitempty"` - Binder32bit *bool `json:",omitempty"` - UseGoma *bool `json:",omitempty"` - UseRBE *bool `json:",omitempty"` - UseRBEJAVAC *bool `json:",omitempty"` - UseRBER8 *bool `json:",omitempty"` - UseRBED8 *bool `json:",omitempty"` - Debuggable *bool `json:",omitempty"` - Eng *bool `json:",omitempty"` - Treble_linker_namespaces *bool `json:",omitempty"` - Enforce_vintf_manifest *bool `json:",omitempty"` - Pdk *bool `json:",omitempty"` - Uml *bool `json:",omitempty"` - Use_lmkd_stats_log *bool `json:",omitempty"` - Arc *bool `json:",omitempty"` - MinimizeJavaDebugInfo *bool `json:",omitempty"` + Allow_missing_dependencies *bool `json:",omitempty"` + Unbundled_build *bool `json:",omitempty"` + Unbundled_build_apps *bool `json:",omitempty"` + Always_use_prebuilt_sdks *bool `json:",omitempty"` + Malloc_not_svelte *bool `json:",omitempty"` + Malloc_zero_contents *bool `json:",omitempty"` + Malloc_pattern_fill_contents *bool `json:",omitempty"` + Safestack *bool `json:",omitempty"` + HostStaticBinaries *bool `json:",omitempty"` + Binder32bit *bool `json:",omitempty"` + UseGoma *bool `json:",omitempty"` + UseRBE *bool `json:",omitempty"` + UseRBEJAVAC *bool `json:",omitempty"` + UseRBER8 *bool `json:",omitempty"` + UseRBED8 *bool `json:",omitempty"` + Debuggable *bool `json:",omitempty"` + Eng *bool `json:",omitempty"` + Treble_linker_namespaces *bool `json:",omitempty"` + Enforce_vintf_manifest *bool `json:",omitempty"` + Uml *bool `json:",omitempty"` + Use_lmkd_stats_log *bool `json:",omitempty"` + Arc *bool `json:",omitempty"` + MinimizeJavaDebugInfo *bool `json:",omitempty"` Check_elf_files *bool `json:",omitempty"` @@ -308,8 +308,6 @@ type productVariables struct { BoardPlatPrivateSepolicyDirs []string `json:",omitempty"` BoardSepolicyM4Defs []string `json:",omitempty"` - BoardVndkRuntimeDisable *bool `json:",omitempty"` - VendorVars map[string]map[string]string `json:",omitempty"` Ndk_abis *bool `json:",omitempty"` @@ -346,6 +344,9 @@ type productVariables struct { InstallExtraFlattenedApexes *bool `json:",omitempty"` BoardUsesRecoveryAsBoot *bool `json:",omitempty"` + + BoardKernelBinaries []string `json:",omitempty"` + BoardKernelModuleInterfaceVersions []string `json:",omitempty"` } func boolPtr(v bool) *bool { diff --git a/apex/androidmk.go b/apex/androidmk.go index 00a38aa4e..af2ec3d2a 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -50,6 +50,11 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo return moduleNames } + // b/162366062. Prevent GKI APEXes to emit make rules to avoid conflicts. + if strings.HasPrefix(apexName, "com.android.gki.") && apexType != flattenedApex { + return moduleNames + } + // b/140136207. When there are overriding APEXes for a VNDK APEX, the symbols file for the overridden // APEX and the overriding APEX will have the same installation paths at /apex/com.android.vndk.v<ver> // as their apexName will be the same. To avoid the path conflicts, skip installing the symbol files @@ -82,9 +87,9 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo var moduleName string if linkToSystemLib { - moduleName = fi.moduleName + moduleName = fi.androidMkModuleName } else { - moduleName = fi.moduleName + "." + apexBundleName + a.suffix + moduleName = fi.androidMkModuleName + "." + apexBundleName + a.suffix } if !android.InList(moduleName, moduleNames) { @@ -119,9 +124,9 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo if len(fi.symlinks) > 0 { fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS :=", strings.Join(fi.symlinks, " ")) } - newDataPaths := []android.Path{} + newDataPaths := []android.DataPath{} for _, path := range fi.dataPaths { - dataOutPath := modulePath + ":" + path.Rel() + dataOutPath := modulePath + ":" + path.SrcPath.Rel() if ok := seenDataOutPaths[dataOutPath]; !ok { newDataPaths = append(newDataPaths, path) seenDataOutPaths[dataOutPath] = true @@ -212,7 +217,7 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo if !ok { panic(fmt.Sprintf("Expected %s to be AndroidAppSet", fi.module)) } - fmt.Fprintln(w, "LOCAL_APK_SET_MASTER_FILE :=", as.MasterFile()) + fmt.Fprintln(w, "LOCAL_APK_SET_INSTALL_FILE :=", as.InstallFile()) fmt.Fprintln(w, "LOCAL_APKCERTS_FILE :=", as.APKCertsFile().String()) fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk") case nativeSharedLib, nativeExecutable, nativeTest: @@ -253,9 +258,9 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo } // m <module_name> will build <module_name>.<apex_name> as well. - if fi.moduleName != moduleName && a.primaryApexType { - fmt.Fprintln(w, ".PHONY: "+fi.moduleName) - fmt.Fprintln(w, fi.moduleName+": "+moduleName) + if fi.androidMkModuleName != moduleName && a.primaryApexType { + fmt.Fprintf(w, ".PHONY: %s\n", fi.androidMkModuleName) + fmt.Fprintf(w, "%s: %s\n", fi.androidMkModuleName, moduleName) } } return moduleNames @@ -356,6 +361,10 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { if apexType == imageApex { fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).BUNDLE :=", a.bundleModuleFile.String()) } + if len(a.lintReports) > 0 { + fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).LINT_REPORTS :=", + strings.Join(a.lintReports.Strings(), " ")) + } if a.installedFilesFile != nil { goal := "checkbuild" diff --git a/apex/apex.go b/apex/apex.go index da309ca9e..1b995c3f2 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -41,6 +41,9 @@ const ( imageApexType = "image" zipApexType = "zip" flattenedApexType = "flattened" + + ext4FsType = "ext4" + f2fsFsType = "f2fs" ) type dependencyTag struct { @@ -584,7 +587,6 @@ func makeApexAvailableBaseline() map[string][]string { "android.hardware.tetheroffload.config-V1.0-java", "android.hardware.tetheroffload.control-V1.0-java", "android.hidl.base-V1.0-java", - "ipmemorystore-aidl-interfaces-java", "libcgrouprc", "libcgrouprc_format", "libtetherutilsjni", @@ -771,7 +773,8 @@ func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { } func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { - ctx.TopDown("apex_deps", apexDepsMutator) + ctx.TopDown("apex_deps", apexDepsMutator).Parallel() + ctx.BottomUp("apex_unique", apexUniqueVariationsMutator).Parallel() ctx.BottomUp("apex", apexMutator).Parallel() ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel() ctx.BottomUp("apex_uses", apexUsesMutator).Parallel() @@ -784,36 +787,59 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) { if !mctx.Module().Enabled() { return } - var apexBundles []android.ApexInfo - var directDep bool - if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex { - apexBundles = []android.ApexInfo{{ - ApexName: mctx.ModuleName(), - MinSdkVersion: a.minSdkVersion(mctx), - Updatable: a.Updatable(), - }} - directDep = true - } else if am, ok := mctx.Module().(android.ApexModule); ok { - apexBundles = am.ApexVariations() - directDep = false - } - - if len(apexBundles) == 0 { + a, ok := mctx.Module().(*apexBundle) + if !ok || a.vndkApex { return } + apexInfo := android.ApexInfo{ + ApexVariationName: mctx.ModuleName(), + MinSdkVersion: a.minSdkVersion(mctx), + RequiredSdks: a.RequiredSdks(), + Updatable: a.Updatable(), + InApexes: []string{mctx.ModuleName()}, + } - cur := mctx.Module().(android.DepIsInSameApex) + useVndk := a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && mctx.Config().EnforceProductPartitionInterface()) + excludeVndkLibs := useVndk && proptools.Bool(a.properties.Use_vndk_as_stable) + if !useVndk && proptools.Bool(a.properties.Use_vndk_as_stable) { + mctx.PropertyErrorf("use_vndk_as_stable", "not supported for system/system_ext APEXes") + return + } - mctx.VisitDirectDeps(func(child android.Module) { - depName := mctx.OtherModuleName(child) - if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && - (cur.DepIsInSameApex(mctx, child) || inAnySdk(child)) { - android.UpdateApexDependency(apexBundles, depName, directDep) - am.BuildForApexes(apexBundles) + mctx.WalkDeps(func(child, parent android.Module) bool { + am, ok := child.(android.ApexModule) + if !ok || !am.CanHaveApexVariants() { + return false } + if !parent.(android.DepIsInSameApex).DepIsInSameApex(mctx, child) { + return false + } + if excludeVndkLibs { + if c, ok := child.(*cc.Module); ok && c.IsVndk() { + return false + } + } + + depName := mctx.OtherModuleName(child) + // If the parent is apexBundle, this child is directly depended. + _, directDep := parent.(*apexBundle) + android.UpdateApexDependency(apexInfo, depName, directDep) + am.BuildForApex(apexInfo) + return true }) } +func apexUniqueVariationsMutator(mctx android.BottomUpMutatorContext) { + if !mctx.Module().Enabled() { + return + } + if am, ok := mctx.Module().(android.ApexModule); ok { + // Check if any dependencies use unique apex variations. If so, use unique apex variations + // for this module. + am.UpdateUniqueApexVariationsForDeps(mctx) + } +} + // mark if a module cannot be available to platform. A module cannot be available // to platform if 1) it is explicitly marked as not available (i.e. "//apex_available:platform" // is absent) or 2) it depends on another module that isn't (or can't be) available to platform @@ -1114,6 +1140,15 @@ type apexBundleProperties struct { // The minimum SDK version that this apex must be compatibile with. Min_sdk_version *string + + // If set true, VNDK libs are considered as stable libs and are not included in this apex. + // Should be only used in non-system apexes (e.g. vendor: true). + // Default is false. + Use_vndk_as_stable *bool + + // The type of filesystem to use for an image apex. Either 'ext4' or 'f2fs'. + // Default 'ext4'. + Payload_fs_type *string } type apexTargetBundleProperties struct { @@ -1239,15 +1274,17 @@ func (class apexFileClass) NameInMake() string { // apexFile represents a file in an APEX bundle type apexFile struct { - builtFile android.Path - stem string - moduleName string - installDir string - class apexFileClass - module android.Module + builtFile android.Path + stem string + // Module name of `module` in AndroidMk. Note the generated AndroidMk module for + // apexFile is named something like <AndroidMk module name>.<apex name>[<apex suffix>] + androidMkModuleName string + installDir string + class apexFileClass + module android.Module // list of symlinks that will be created in installDir that point to this apexFile symlinks []string - dataPaths android.Paths + dataPaths []android.DataPath transitiveDep bool moduleDir string @@ -1256,19 +1293,20 @@ type apexFile struct { hostRequiredModuleNames []string jacocoReportClassesFile android.Path // only for javalibs and apps + lintDepSets java.LintDepSets // only for javalibs and apps certificate java.Certificate // only for apps overriddenPackageName string // only for apps isJniLib bool } -func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, moduleName string, installDir string, class apexFileClass, module android.Module) apexFile { +func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidMkModuleName string, installDir string, class apexFileClass, module android.Module) apexFile { ret := apexFile{ - builtFile: builtFile, - moduleName: moduleName, - installDir: installDir, - class: class, - module: module, + builtFile: builtFile, + androidMkModuleName: androidMkModuleName, + installDir: installDir, + class: class, + module: module, } if module != nil { ret.moduleDir = ctx.OtherModuleDir(module) @@ -1318,6 +1356,24 @@ func (af *apexFile) AvailableToPlatform() bool { return false } +type fsType int + +const ( + ext4 fsType = iota + f2fs +) + +func (f fsType) string() string { + switch f { + case ext4: + return ext4FsType + case f2fs: + return f2fsFsType + default: + panic(fmt.Errorf("unknown APEX payload type %d", f)) + } +} + type apexBundle struct { android.ModuleBase android.DefaultableModuleBase @@ -1380,6 +1436,11 @@ type apexBundle struct { // Struct holding the merged notice file paths in different formats mergedNotices android.NoticeOutputs + + // Optional list of lint report zip files for apexes that contain java or app modules + lintReports android.Paths + + payloadFsType fsType } func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, @@ -1722,7 +1783,8 @@ func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod *cc.Module, h } fileToCopy := ccMod.OutputFile().Path() - return newApexFile(ctx, fileToCopy, ccMod.Name(), dirInApex, nativeSharedLib, ccMod) + androidMkModuleName := ccMod.BaseModuleName() + ccMod.Properties.SubName + return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, ccMod) } func apexFileForExecutable(ctx android.BaseModuleContext, cc *cc.Module) apexFile { @@ -1732,7 +1794,8 @@ func apexFileForExecutable(ctx android.BaseModuleContext, cc *cc.Module) apexFil } dirInApex = filepath.Join(dirInApex, cc.RelativeInstallPath()) fileToCopy := cc.OutputFile().Path() - af := newApexFile(ctx, fileToCopy, cc.Name(), dirInApex, nativeExecutable, cc) + androidMkModuleName := cc.BaseModuleName() + cc.Properties.SubName + af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, cc) af.symlinks = cc.Symlinks() af.dataPaths = cc.DataPaths() return af @@ -1741,7 +1804,7 @@ func apexFileForExecutable(ctx android.BaseModuleContext, cc *cc.Module) apexFil func apexFileForPyBinary(ctx android.BaseModuleContext, py *python.Module) apexFile { dirInApex := "bin" fileToCopy := py.HostToolPath().Path() - return newApexFile(ctx, fileToCopy, py.Name(), dirInApex, pyBinary, py) + return newApexFile(ctx, fileToCopy, py.BaseModuleName(), dirInApex, pyBinary, py) } func apexFileForGoBinary(ctx android.BaseModuleContext, depName string, gb bootstrap.GoBinaryTool) apexFile { dirInApex := "bin" @@ -1760,25 +1823,33 @@ func apexFileForGoBinary(ctx android.BaseModuleContext, depName string, gb boots func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFile { dirInApex := filepath.Join("bin", sh.SubDir()) fileToCopy := sh.OutputFile() - af := newApexFile(ctx, fileToCopy, sh.Name(), dirInApex, shBinary, sh) + af := newApexFile(ctx, fileToCopy, sh.BaseModuleName(), dirInApex, shBinary, sh) af.symlinks = sh.Symlinks() return af } -type javaDependency interface { +type javaModule interface { + android.Module + BaseModuleName() string DexJarBuildPath() android.Path JacocoReportClassesFile() android.Path + LintDepSets() java.LintDepSets + Stem() string } -func apexFileForJavaLibrary(ctx android.BaseModuleContext, lib javaDependency, module android.Module) apexFile { +var _ javaModule = (*java.Library)(nil) +var _ javaModule = (*java.SdkLibrary)(nil) +var _ javaModule = (*java.DexImport)(nil) +var _ javaModule = (*java.SdkLibraryImport)(nil) + +func apexFileForJavaLibrary(ctx android.BaseModuleContext, module javaModule) apexFile { dirInApex := "javalib" - fileToCopy := lib.DexJarBuildPath() - // Remove prebuilt_ if necessary so the source and prebuilt modules have the same name. - name := strings.TrimPrefix(module.Name(), "prebuilt_") - af := newApexFile(ctx, fileToCopy, name, dirInApex, javaSharedLib, module) - af.jacocoReportClassesFile = lib.JacocoReportClassesFile() - af.stem = lib.Stem() + ".jar" + fileToCopy := module.DexJarBuildPath() + af := newApexFile(ctx, fileToCopy, module.BaseModuleName(), dirInApex, javaSharedLib, module) + af.jacocoReportClassesFile = module.JacocoReportClassesFile() + af.lintDepSets = module.LintDepSets() + af.stem = module.Stem() + ".jar" return af } @@ -1801,6 +1872,7 @@ func apexFileForAndroidApp(ctx android.BaseModuleContext, aapp interface { OutputFile() android.Path JacocoReportClassesFile() android.Path Certificate() java.Certificate + BaseModuleName() string }) apexFile { appDir := "app" if aapp.Privileged() { @@ -1808,7 +1880,7 @@ func apexFileForAndroidApp(ctx android.BaseModuleContext, aapp interface { } dirInApex := filepath.Join(appDir, aapp.InstallApkName()) fileToCopy := aapp.OutputFile() - af := newApexFile(ctx, fileToCopy, aapp.Name(), dirInApex, app, aapp) + af := newApexFile(ctx, fileToCopy, aapp.BaseModuleName(), dirInApex, app, aapp) af.jacocoReportClassesFile = aapp.JacocoReportClassesFile() af.certificate = aapp.Certificate() @@ -1868,7 +1940,7 @@ func (a *apexBundle) WalkPayloadDeps(ctx android.ModuleContext, do android.Paylo } // Check for the indirect dependencies if it is considered as part of the APEX - if am.ApexName() != "" { + if android.InList(ctx.ModuleName(), am.InApexes()) { return do(ctx, parent, am, false /* externalDep */) } @@ -1914,7 +1986,8 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { // Because APEXes targeting other than system/system_ext partitions // can't set apex_available, we skip checks for these APEXes - if ctx.SocSpecific() || ctx.DeviceSpecific() || ctx.ProductSpecific() { + if a.SocSpecific() || a.DeviceSpecific() || + (a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) { return } @@ -2126,7 +2199,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { case javaLibTag: switch child.(type) { case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport: - af := apexFileForJavaLibrary(ctx, child.(javaDependency), child.(android.Module)) + af := apexFileForJavaLibrary(ctx, child.(javaModule)) if !af.Ok() { ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName) return false @@ -2149,7 +2222,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { if ap.Privileged() { appDir = "priv-app" } - af := newApexFile(ctx, ap.OutputFile(), ap.Name(), + af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), filepath.Join(appDir, ap.BaseModuleName()), appSet, ap) af.certificate = java.PresignedCertificate filesInfo = append(filesInfo, af) @@ -2207,7 +2280,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { case android.PrebuiltDepTag: // If the prebuilt is force disabled, remember to delete the prebuilt file // that might have been installed in the previous builds - if prebuilt, ok := child.(*Prebuilt); ok && prebuilt.isForceDisabled() { + if prebuilt, ok := child.(prebuilt); ok && prebuilt.isForceDisabled() { a.prebuiltFileToDelete = prebuilt.InstallFilename() } } @@ -2223,6 +2296,10 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // don't include it in this APEX return false } + if cc.UseVndk() && proptools.Bool(a.properties.Use_vndk_as_stable) && cc.IsVndk() { + requireNativeLibs = append(requireNativeLibs, ":vndk") + return false + } af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs) af.transitiveDep = true if !a.Host() && !android.DirectlyInApex(ctx.ModuleName(), depName) && (cc.IsStubs() || cc.HasStubsVariants()) { @@ -2259,7 +2336,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // use the name of the generated test binary (`fileToCopy`) instead of the name // of the original test module (`depName`, shared by all `test_per_src` // variations of that module). - af.moduleName = filepath.Base(af.builtFile.String()) + af.androidMkModuleName = filepath.Base(af.builtFile.String()) // these are not considered transitive dep af.transitiveDep = false filesInfo = append(filesInfo, af) @@ -2329,6 +2406,15 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.installDir = android.PathForModuleInstall(ctx, "apex") a.filesInfo = filesInfo + switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) { + case ext4FsType: + a.payloadFsType = ext4 + case f2fsFsType: + a.payloadFsType = f2fs + default: + ctx.PropertyErrorf("payload_fs_type", "%q is not a valid filesystem for apex [ext4, f2fs]", *a.properties.Payload_fs_type) + } + // Optimization. If we are building bundled APEX, for the files that are gathered due to the // transitive dependencies, don't place them inside the APEX, but place a symlink pointing // the same library in the system partition, thus effectively sharing the same libraries @@ -2340,7 +2426,8 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // APEXes targeting other than system/system_ext partitions use vendor/product variants. // So we can't link them to /system/lib libs which are core variants. - if a.SocSpecific() || a.DeviceSpecific() || a.ProductSpecific() { + if a.SocSpecific() || a.DeviceSpecific() || + (a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) { a.linkToSystemLib = false } @@ -2370,6 +2457,8 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx) a.buildApexDependencyInfo(ctx) + + a.buildLintReports(ctx) } // Enforce that Java deps of the apex are using stable SDKs to compile diff --git a/apex/apex_test.go b/apex/apex_test.go index 3c37ca304..f7e02e338 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -236,13 +236,15 @@ func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*andr ctx.PreArchMutators(android.RegisterComponentsMutator) ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators) - cc.RegisterRequiredBuildComponentsForTest(ctx) + android.RegisterPrebuiltMutators(ctx) - // Register this after the prebuilt mutators have been registered (in - // cc.RegisterRequiredBuildComponentsForTest) to match what happens at runtime. + // Register these after the prebuilt mutators have been registered to match what + // happens at runtime. ctx.PreArchMutators(android.RegisterVisibilityRuleGatherer) ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer) + cc.RegisterRequiredBuildComponentsForTest(ctx) + ctx.RegisterModuleType("cc_test", cc.TestFactory) ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory) ctx.RegisterModuleType("vndk_libraries_txt", cc.VndkLibrariesTxtFactory) @@ -412,7 +414,14 @@ func TestBasicApex(t *testing.T) { system_shared_libs: [], static_executable: true, stl: "none", - apex_available: [ "myapex" ], + apex_available: [ "myapex", "com.android.gki.*" ], + } + + apex { + name: "com.android.gki.fake", + binaries: ["foo"], + key: "myapex.key", + file_contexts: ":myapex-file_contexts", } cc_library_shared { @@ -519,13 +528,13 @@ func TestBasicApex(t *testing.T) { ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_apex10000") // Ensure that apex variant is created for the indirect dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") @@ -714,10 +723,10 @@ func TestBasicZipApex(t *testing.T) { ensureContains(t, zipApexRule.Output.String(), "myapex.zipapex.unsigned") // Ensure that APEX variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000") // Ensure that APEX variant is created for the indirect dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.zipapex/lib64/mylib.so") @@ -791,7 +800,7 @@ func TestApexWithStubs(t *testing.T) { // Ensure that direct stubs dep is included ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with the latest version of stubs for mylib2 ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_3/mylib2.so") @@ -799,9 +808,9 @@ func TestApexWithStubs(t *testing.T) { ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so") // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because mylib3 is in the same apex) - ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_myapex/mylib3.so") + ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_apex10000/mylib3.so") // .. and not linking to the stubs variant of mylib3 - ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12_myapex/mylib3.so") + ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12/mylib3.so") // Ensure that stubs libs are built without -include flags mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] @@ -881,7 +890,7 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { // Ensure that dependency of stubs is not included ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex2").Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with version 10 of libfoo ensureContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared_10/libfoo.so") @@ -1101,18 +1110,21 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { testcases := []struct { name string minSdkVersion string + apexVariant string shouldLink string shouldNotLink []string }{ { name: "should link to the latest", minSdkVersion: "", + apexVariant: "apex10000", shouldLink: "30", shouldNotLink: []string{"29"}, }, { name: "should link to llndk#29", minSdkVersion: "min_sdk_version: \"29\",", + apexVariant: "apex29", shouldLink: "29", shouldNotLink: []string{"30"}, }, @@ -1171,13 +1183,13 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"])) ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_"+tc.apexVariant).Rule("ld").Args["libFlags"] ensureContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so") for _, ver := range tc.shouldNotLink { ensureNotContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+ver+"/libbar.so") } - mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] + mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "__LIBBAR_API__="+tc.shouldLink) }) } @@ -1232,9 +1244,9 @@ func TestApexWithSystemLibsStubs(t *testing.T) { // Ensure that libc is not included (since it has stubs and not listed in native_shared_libs) ensureNotContains(t, copyCmds, "image.apex/lib64/bionic/libc.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] - mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] - mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_myapex").Rule("cc").Args["cFlags"] + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] + mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"] + mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_apex10000").Rule("cc").Args["cFlags"] // For dependency to libc // Ensure that mylib is linking with the latest version of stubs @@ -1247,7 +1259,7 @@ func TestApexWithSystemLibsStubs(t *testing.T) { // For dependency to libm // Ensure that mylib is linking with the non-stub (impl) variant - ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_myapex/libm.so") + ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_apex10000/libm.so") // ... and not linking to the stub variant ensureNotContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_29/libm.so") // ... and is not compiling with the stub @@ -1261,7 +1273,7 @@ func TestApexWithSystemLibsStubs(t *testing.T) { ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_28/libdl.so") ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_29/libdl.so") // ... and not linking to the non-stub (impl) variant - ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_myapex/libdl.so") + ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_apex10000/libdl.so") // ... Cflags from stub is correctly exported to mylib ensureContains(t, mylibCFlags, "__LIBDL_API__=27") ensureContains(t, mylibSharedCFlags, "__LIBDL_API__=27") @@ -1350,13 +1362,13 @@ func TestApexMinSdkVersion_NativeModulesShouldBeBuiltAgainstStubs(t *testing.T) // platform liba is linked to non-stub version expectLink("liba", "shared", "libz", "shared") // liba in myapex is linked to #28 - expectLink("liba", "shared_myapex", "libz", "shared_28") - expectNoLink("liba", "shared_myapex", "libz", "shared_30") - expectNoLink("liba", "shared_myapex", "libz", "shared") + expectLink("liba", "shared_apex29", "libz", "shared_28") + expectNoLink("liba", "shared_apex29", "libz", "shared_30") + expectNoLink("liba", "shared_apex29", "libz", "shared") // liba in otherapex is linked to #30 - expectLink("liba", "shared_otherapex", "libz", "shared_30") - expectNoLink("liba", "shared_otherapex", "libz", "shared_28") - expectNoLink("liba", "shared_otherapex", "libz", "shared") + expectLink("liba", "shared_apex30", "libz", "shared_30") + expectNoLink("liba", "shared_apex30", "libz", "shared_28") + expectNoLink("liba", "shared_apex30", "libz", "shared") } func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { @@ -1409,9 +1421,9 @@ func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { // to distinguish them from finalized and future_api(10000) // In this test, "R" is assumed not finalized yet( listed in Platform_version_active_codenames) and translated into 9000 // (refer android/api_levels.go) - expectLink("libx", "shared_myapex", "libz", "shared_9000") - expectNoLink("libx", "shared_myapex", "libz", "shared_29") - expectNoLink("libx", "shared_myapex", "libz", "shared") + expectLink("libx", "shared_apex10000", "libz", "shared_9000") + expectNoLink("libx", "shared_apex10000", "libz", "shared_29") + expectNoLink("libx", "shared_apex10000", "libz", "shared") } func TestApexMinSdkVersion_DefaultsToLatest(t *testing.T) { @@ -1454,9 +1466,9 @@ func TestApexMinSdkVersion_DefaultsToLatest(t *testing.T) { ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("libx", "shared_myapex", "libz", "shared_2") - expectNoLink("libx", "shared_myapex", "libz", "shared_1") - expectNoLink("libx", "shared_myapex", "libz", "shared") + expectLink("libx", "shared_apex10000", "libz", "shared_2") + expectNoLink("libx", "shared_apex10000", "libz", "shared_1") + expectNoLink("libx", "shared_apex10000", "libz", "shared") } func TestPlatformUsesLatestStubsFromApexes(t *testing.T) { @@ -1540,7 +1552,7 @@ func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) { libFlags := ld.Args["libFlags"] ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("libx", "shared_hwasan_myapex", "libbar", "shared_30") + expectLink("libx", "shared_hwasan_apex29", "libbar", "shared_30") } func TestQTargetApexUsesStaticUnwinder(t *testing.T) { @@ -1566,7 +1578,7 @@ func TestQTargetApexUsesStaticUnwinder(t *testing.T) { `) // ensure apex variant of c++ is linked with static unwinder - cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module) + cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_apex29").Module().(*cc.Module) ensureListContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped") // note that platform variant is not. cm = ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared").Module().(*cc.Module) @@ -1928,8 +1940,8 @@ func TestApexMinSdkVersion_OkayEvenWhenDepIsNewer_IfItSatisfiesApexMinSdkVersion libFlags := ld.Args["libFlags"] ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("mylib", "shared_myapex", "mylib2", "shared_29") - expectLink("mylib", "shared_otherapex", "mylib2", "shared_otherapex") + expectLink("mylib", "shared_apex29", "mylib2", "shared_29") + expectLink("mylib", "shared_apex30", "mylib2", "shared_apex30") } func TestFilesInSubDir(t *testing.T) { @@ -2098,12 +2110,12 @@ func TestUseVendor(t *testing.T) { inputsString := strings.Join(inputsList, " ") // ensure that the apex includes vendor variants of the direct and indirect deps - ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_myapex/mylib.so") - ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_myapex/mylib2.so") + ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_apex10000/mylib.so") + ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_apex10000/mylib2.so") // ensure that the apex does not include core variants - ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_myapex/mylib.so") - ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_myapex/mylib2.so") + ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_apex10000/mylib.so") + ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_apex10000/mylib2.so") } func TestUseVendorNotAllowedForSystemApexes(t *testing.T) { @@ -2201,6 +2213,63 @@ func TestVendorApex(t *testing.T) { data.Custom(&builder, name, prefix, "", data) androidMk := builder.String() ensureContains(t, androidMk, `LOCAL_MODULE_PATH := /tmp/target/product/test_device/vendor/apex`) + + apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") + requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"]) + ensureListNotContains(t, requireNativeLibs, ":vndk") +} + +func TestVendorApex_use_vndk_as_stable(t *testing.T) { + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + binaries: ["mybin"], + vendor: true, + use_vndk_as_stable: true, + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + cc_binary { + name: "mybin", + vendor: true, + shared_libs: ["libvndk", "libvendor"], + } + cc_library { + name: "libvndk", + vndk: { + enabled: true, + }, + vendor_available: true, + } + cc_library { + name: "libvendor", + vendor: true, + } + `) + + vendorVariant := "android_vendor.VER_arm64_armv8-a" + + ldRule := ctx.ModuleForTests("mybin", vendorVariant+"_apex10000").Rule("ld") + libs := names(ldRule.Args["libFlags"]) + // VNDK libs(libvndk/libc++) as they are + ensureListContains(t, libs, buildDir+"/.intermediates/libvndk/"+vendorVariant+"_shared/libvndk.so") + ensureListContains(t, libs, buildDir+"/.intermediates/libc++/"+vendorVariant+"_shared/libc++.so") + // non-stable Vendor libs as APEX variants + ensureListContains(t, libs, buildDir+"/.intermediates/libvendor/"+vendorVariant+"_shared_apex10000/libvendor.so") + + // VNDK libs are not included when use_vndk_as_stable: true + ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + "bin/mybin", + "lib64/libvendor.so", + }) + + apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") + requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"]) + ensureListContains(t, requireNativeLibs, ":vndk") } func TestAndroidMk_UseVendorRequired(t *testing.T) { @@ -2567,7 +2636,21 @@ func TestMacro(t *testing.T) { "myapex", "otherapex", ], + static_libs: ["mylib3"], + recovery_available: true, + min_sdk_version: "29", + } + cc_library { + name: "mylib3", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: [ + "myapex", + "otherapex", + ], use_apex_name_macro: true, + recovery_available: true, min_sdk_version: "29", } `) @@ -2578,19 +2661,43 @@ func TestMacro(t *testing.T) { ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__") // APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined - mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=10000") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") // APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined - mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex29").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=29") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") - // When cc_library sets use_apex_name_macro: true - // apex variants define additional macro to distinguish which apex variant it is built for + // When a cc_library sets use_apex_name_macro: true each apex gets a unique variant and + // each variant defines additional macros to distinguish which apex variant it is built for + + // non-APEX variant does not have __ANDROID_APEX__ defined + mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") + + // APEX variant has __ANDROID_APEX__ defined + mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") + + // APEX variant has __ANDROID_APEX__ defined + mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"] + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") + + // recovery variant does not set __ANDROID_SDK_VERSION__ + mylibCFlags = ctx.ModuleForTests("mylib3", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__") + + // When a dependency of a cc_library sets use_apex_name_macro: true each apex gets a unique + // variant. // non-APEX variant does not have __ANDROID_APEX__ defined mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] @@ -2599,17 +2706,17 @@ func TestMacro(t *testing.T) { // APEX variant has __ANDROID_APEX__ defined mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") - ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") // APEX variant has __ANDROID_APEX__ defined mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") - ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") // recovery variant does not set __ANDROID_SDK_VERSION__ - mylibCFlags = ctx.ModuleForTests("mylib", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests("mylib2", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__") } @@ -3389,7 +3496,7 @@ func TestNonTestApex(t *testing.T) { ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib_common.so") @@ -3445,7 +3552,7 @@ func TestTestApex(t *testing.T) { ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib_common_test.so") @@ -3529,9 +3636,9 @@ func TestApexWithTarget(t *testing.T) { ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_myapex") - ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_apex10000") + ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") @@ -3996,8 +4103,8 @@ func TestApexUsesOtherApex(t *testing.T) { apexRule2 := module2.Rule("apexRule") copyCmds2 := apexRule2.Args["copy_commands"] - ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("libcommon"), "android_arm64_armv8-a_shared_commonapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("libcommon"), "android_arm64_armv8-a_shared_apex10000") ensureContains(t, copyCmds1, "image.apex/lib64/mylib.so") ensureContains(t, copyCmds2, "image.apex/lib64/libcommon.so") ensureNotContains(t, copyCmds1, "image.apex/lib64/libcommon.so") @@ -4177,14 +4284,14 @@ func TestApexWithApps(t *testing.T) { ensureContains(t, copyCmds, "image.apex/app/AppFoo/AppFoo.apk") ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv/AppFooPriv.apk") - appZipRule := ctx.ModuleForTests("AppFoo", "android_common_myapex").Description("zip jni libs") + appZipRule := ctx.ModuleForTests("AppFoo", "android_common_apex10000").Description("zip jni libs") // JNI libraries are uncompressed if args := appZipRule.Args["jarArgs"]; !strings.Contains(args, "-L 0") { t.Errorf("jni libs are not uncompressed for AppFoo") } // JNI libraries including transitive deps are for _, jni := range []string{"libjni", "libfoo"} { - jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_myapex").Module().(*cc.Module).OutputFile() + jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_apex10000").Module().(*cc.Module).OutputFile() // ... embedded inside APK (jnilibs.zip) ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String()) // ... and not directly inside the APEX @@ -4384,11 +4491,11 @@ func TestApexAvailable_DirectDep(t *testing.T) { func TestApexAvailable_IndirectDep(t *testing.T) { // libbbaz is an indirect dep testApexError(t, `requires "libbaz" that is not available for the APEX. Dependency path: -.*via tag apex\.dependencyTag.*"sharedLib".* +.*via tag apex\.dependencyTag.*name:sharedLib.* .*-> libfoo.*link:shared.* -.*via tag cc\.DependencyTag.*"shared".* +.*via tag cc\.libraryDependencyTag.*Kind:sharedLibraryDependency.* .*-> libbar.*link:shared.* -.*via tag cc\.DependencyTag.*"shared".* +.*via tag cc\.libraryDependencyTag.*Kind:sharedLibraryDependency.* .*-> libbaz.*link:shared.*`, ` apex { name: "myapex", @@ -4698,7 +4805,7 @@ func TestLegacyAndroid10Support(t *testing.T) { // the dependency names directly here but for some reason the names are blank in // this test. for _, lib := range []string{"libc++", "mylib"} { - apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_myapex").Rule("ld").Implicits + apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_apex29").Rule("ld").Implicits nonApexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld").Implicits if len(apexImplicits) != len(nonApexImplicits)+1 { t.Errorf("%q missing unwinder dep", lib) @@ -5179,6 +5286,57 @@ func TestSymlinksFromApexToSystem(t *testing.T) { ensureRealfileExists(t, files, "lib64/myotherlib.so") // this is a real file } +func TestSymlinksFromApexToSystemRequiredModuleNames(t *testing.T) { + ctx, config := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library_shared { + name: "mylib", + srcs: ["mylib.cpp"], + shared_libs: ["myotherlib"], + system_shared_libs: [], + stl: "none", + apex_available: [ + "myapex", + "//apex_available:platform", + ], + } + + cc_prebuilt_library_shared { + name: "myotherlib", + srcs: ["prebuilt.so"], + system_shared_libs: [], + stl: "none", + apex_available: [ + "myapex", + "//apex_available:platform", + ], + } + `) + + apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + data := android.AndroidMkDataForTest(t, config, "", apexBundle) + var builder strings.Builder + data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data) + androidMk := builder.String() + // `myotherlib` is added to `myapex` as symlink + ensureContains(t, androidMk, "LOCAL_MODULE := mylib.myapex\n") + ensureNotContains(t, androidMk, "LOCAL_MODULE := prebuilt_myotherlib.myapex\n") + ensureNotContains(t, androidMk, "LOCAL_MODULE := myotherlib.myapex\n") + // `myapex` should have `myotherlib` in its required line, not `prebuilt_myotherlib` + ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += mylib.myapex myotherlib apex_manifest.pb.myapex apex_pubkey.myapex\n") +} + func TestApexWithJniLibs(t *testing.T) { ctx, _ := testApex(t, ` apex { @@ -5241,29 +5399,6 @@ func TestApexMutatorsDontRunIfDisabled(t *testing.T) { } } -func TestApexWithJniLibs_Errors(t *testing.T) { - testApexError(t, `jni_libs: "xxx" is not a cc_library`, ` - apex { - name: "myapex", - key: "myapex.key", - jni_libs: ["xxx"], - } - - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - - prebuilt_etc { - name: "xxx", - src: "xxx", - } - `, withFiles(map[string][]byte{ - "xxx": nil, - })) -} - func TestAppBundle(t *testing.T) { ctx, _ := testApex(t, ` apex { @@ -5434,6 +5569,7 @@ func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, transformDexpre ctx.RegisterModuleType("apex_key", ApexKeyFactory) ctx.RegisterModuleType("filegroup", android.FileGroupFactory) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) + android.RegisterPrebuiltMutators(ctx) cc.RegisterRequiredBuildComponentsForTest(ctx) java.RegisterJavaBuildComponents(ctx) java.RegisterSystemModulesBuildComponents(ctx) @@ -5484,52 +5620,54 @@ func TestUpdatable_should_set_min_sdk_version(t *testing.T) { } func TestNoUpdatableJarsInBootImage(t *testing.T) { - var err string var transform func(*dexpreopt.GlobalConfig) + config := android.TestArchConfig(buildDir, nil, "", nil) + ctx := android.PathContextForTesting(config) + t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) { transform = func(config *dexpreopt.GlobalConfig) { - config.ArtApexJars = []string{"com.android.art.something:some-art-lib"} + config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"com.android.art.something:some-art-lib"}) } testNoUpdatableJarsInBootImage(t, "", transform) }) t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) { - err = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image" + err = `module "some-art-lib" from updatable apexes \["com.android.art.something"\] is not allowed in the framework boot image` transform = func(config *dexpreopt.GlobalConfig) { - config.BootJars = []string{"com.android.art.something:some-art-lib"} + config.BootJars = android.CreateConfiguredJarList(ctx, []string{"com.android.art.something:some-art-lib"}) } testNoUpdatableJarsInBootImage(t, err, transform) }) t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) { - err = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image" + err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the ART boot image` transform = func(config *dexpreopt.GlobalConfig) { - config.ArtApexJars = []string{"some-updatable-apex:some-updatable-apex-lib"} + config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"some-updatable-apex:some-updatable-apex-lib"}) } testNoUpdatableJarsInBootImage(t, err, transform) }) t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) { - err = "module 'some-non-updatable-apex-lib' is not allowed in the ART boot image" + err = `module "some-non-updatable-apex-lib" is not allowed in the ART boot image` transform = func(config *dexpreopt.GlobalConfig) { - config.ArtApexJars = []string{"some-non-updatable-apex:some-non-updatable-apex-lib"} + config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"some-non-updatable-apex:some-non-updatable-apex-lib"}) } testNoUpdatableJarsInBootImage(t, err, transform) }) t.Run("updatable jar from some other apex in the framework boot image => error", func(t *testing.T) { - err = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image" + err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the framework boot image` transform = func(config *dexpreopt.GlobalConfig) { - config.BootJars = []string{"some-updatable-apex:some-updatable-apex-lib"} + config.BootJars = android.CreateConfiguredJarList(ctx, []string{"some-updatable-apex:some-updatable-apex-lib"}) } testNoUpdatableJarsInBootImage(t, err, transform) }) t.Run("non-updatable jar from some other apex in the framework boot image => ok", func(t *testing.T) { transform = func(config *dexpreopt.GlobalConfig) { - config.BootJars = []string{"some-non-updatable-apex:some-non-updatable-apex-lib"} + config.BootJars = android.CreateConfiguredJarList(ctx, []string{"some-non-updatable-apex:some-non-updatable-apex-lib"}) } testNoUpdatableJarsInBootImage(t, "", transform) }) @@ -5537,7 +5675,7 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) { err = "failed to find a dex jar path for module 'nonexistent'" transform = func(config *dexpreopt.GlobalConfig) { - config.ArtApexJars = []string{"platform:nonexistent"} + config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"platform:nonexistent"}) } testNoUpdatableJarsInBootImage(t, err, transform) }) @@ -5545,22 +5683,22 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { t.Run("nonexistent jar in the framework boot image => error", func(t *testing.T) { err = "failed to find a dex jar path for module 'nonexistent'" transform = func(config *dexpreopt.GlobalConfig) { - config.BootJars = []string{"platform:nonexistent"} + config.BootJars = android.CreateConfiguredJarList(ctx, []string{"platform:nonexistent"}) } testNoUpdatableJarsInBootImage(t, err, transform) }) t.Run("platform jar in the ART boot image => error", func(t *testing.T) { - err = "module 'some-platform-lib' is not allowed in the ART boot image" + err = `module "some-platform-lib" is not allowed in the ART boot image` transform = func(config *dexpreopt.GlobalConfig) { - config.ArtApexJars = []string{"platform:some-platform-lib"} + config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"platform:some-platform-lib"}) } testNoUpdatableJarsInBootImage(t, err, transform) }) t.Run("platform jar in the framework boot image => ok", func(t *testing.T) { transform = func(config *dexpreopt.GlobalConfig) { - config.BootJars = []string{"platform:some-platform-lib"} + config.BootJars = android.CreateConfiguredJarList(ctx, []string{"platform:some-platform-lib"}) } testNoUpdatableJarsInBootImage(t, "", transform) }) diff --git a/apex/builder.go b/apex/builder.go index a31429c86..307142097 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -63,6 +63,8 @@ func init() { pctx.HostBinToolVariable("jsonmodify", "jsonmodify") pctx.HostBinToolVariable("conv_apex_manifest", "conv_apex_manifest") pctx.HostBinToolVariable("extract_apks", "extract_apks") + pctx.HostBinToolVariable("make_f2fs", "make_f2fs") + pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs") } var ( @@ -116,12 +118,12 @@ var ( `--payload_type image ` + `--key ${key} ${opt_flags} ${image_dir} ${out} `, CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}", - "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", + "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}", "${sload_f2fs}", "${soong_zip}", "${zipalign}", "${aapt2}", "prebuilts/sdk/current/public/android.jar"}, Rspfile: "${out}.copy_commands", RspfileContent: "${copy_commands}", Description: "APEX ${image_dir} => ${out}", - }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest") + }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "payload_fs_type") zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{ Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` + @@ -193,7 +195,7 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, // collect jniLibs. Notice that a.filesInfo is already sorted var jniLibs []string for _, fi := range a.filesInfo { - if fi.isJniLib { + if fi.isJniLib && !android.InList(fi.Stem(), jniLibs) { jniLibs = append(jniLibs, fi.Stem()) } } @@ -403,16 +405,16 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { } for _, d := range fi.dataPaths { // TODO(eakammer): This is now the third repetition of ~this logic for test paths, refactoring should be possible - relPath := d.Rel() - dataPath := d.String() + relPath := d.SrcPath.Rel() + dataPath := d.SrcPath.String() if !strings.HasSuffix(dataPath, relPath) { panic(fmt.Errorf("path %q does not end with %q", dataPath, relPath)) } - dataDest := android.PathForModuleOut(ctx, "image"+suffix, fi.apexRelativePath(relPath)).String() + dataDest := android.PathForModuleOut(ctx, "image"+suffix, fi.apexRelativePath(relPath), d.RelativeInstallPath).String() - copyCommands = append(copyCommands, "cp -f "+d.String()+" "+dataDest) - implicitInputs = append(implicitInputs, d) + copyCommands = append(copyCommands, "cp -f "+d.SrcPath.String()+" "+dataDest) + implicitInputs = append(implicitInputs, d.SrcPath) } } @@ -473,7 +475,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") { executablePaths = append(executablePaths, pathInApex) for _, d := range f.dataPaths { - readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.Rel())) + readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.RelativeInstallPath, d.SrcPath.Rel())) } for _, s := range f.symlinks { executablePaths = append(executablePaths, filepath.Join(f.installDir, s)) @@ -582,6 +584,8 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String()) } + optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string()) + ctx.Build(pctx, android.BuildParams{ Rule: apexRule, Implicits: implicitInputs, @@ -815,3 +819,12 @@ func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) { }, }) } + +func (a *apexBundle) buildLintReports(ctx android.ModuleContext) { + depSetsBuilder := java.NewLintDepSetBuilder() + for _, fi := range a.filesInfo { + depSetsBuilder.Transitive(fi.lintDepSets) + } + + a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build()) +} diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 794799ee6..37457e921 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -40,9 +40,55 @@ var ( "abis", "allow-prereleased", "sdk-version") ) +type prebuilt interface { + isForceDisabled() bool + InstallFilename() string +} + +type prebuiltCommon struct { + prebuilt android.Prebuilt + properties prebuiltCommonProperties +} + +type prebuiltCommonProperties struct { + ForceDisable bool `blueprint:"mutated"` +} + +func (p *prebuiltCommon) Prebuilt() *android.Prebuilt { + return &p.prebuilt +} + +func (p *prebuiltCommon) isForceDisabled() bool { + return p.properties.ForceDisable +} + +func (p *prebuiltCommon) checkForceDisable(ctx android.ModuleContext) bool { + // If the device is configured to use flattened APEX, force disable the prebuilt because + // the prebuilt is a non-flattened one. + forceDisable := ctx.Config().FlattenApex() + + // Force disable the prebuilts when we are doing unbundled build. We do unbundled build + // to build the prebuilts themselves. + forceDisable = forceDisable || ctx.Config().UnbundledBuild() + + // Force disable the prebuilts when coverage is enabled. + forceDisable = forceDisable || ctx.DeviceConfig().NativeCoverageEnabled() + forceDisable = forceDisable || ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") + + // b/137216042 don't use prebuilts when address sanitizer is on + forceDisable = forceDisable || android.InList("address", ctx.Config().SanitizeDevice()) || + android.InList("hwaddress", ctx.Config().SanitizeDevice()) + + if forceDisable && p.prebuilt.SourceExists() { + p.properties.ForceDisable = true + return true + } + return false +} + type Prebuilt struct { android.ModuleBase - prebuilt android.Prebuilt + prebuiltCommon properties PrebuiltProperties @@ -58,8 +104,7 @@ type Prebuilt struct { type PrebuiltProperties struct { // the path to the prebuilt .apex file to import. - Source string `blueprint:"mutated"` - ForceDisable bool `blueprint:"mutated"` + Source string `blueprint:"mutated"` Src *string Arch struct { @@ -94,10 +139,6 @@ func (p *Prebuilt) installable() bool { return p.properties.Installable == nil || proptools.Bool(p.properties.Installable) } -func (p *Prebuilt) isForceDisabled() bool { - return p.properties.ForceDisable -} - func (p *Prebuilt) OutputFiles(tag string) (android.Paths, error) { switch tag { case "": @@ -111,12 +152,8 @@ func (p *Prebuilt) InstallFilename() string { return proptools.StringDefault(p.properties.Filename, p.BaseModuleName()+imageApexSuffix) } -func (p *Prebuilt) Prebuilt() *android.Prebuilt { - return &p.prebuilt -} - func (p *Prebuilt) Name() string { - return p.prebuilt.Name(p.ModuleBase.Name()) + return p.prebuiltCommon.prebuilt.Name(p.ModuleBase.Name()) } // prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex. @@ -129,27 +166,6 @@ func PrebuiltFactory() android.Module { } func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) { - // If the device is configured to use flattened APEX, force disable the prebuilt because - // the prebuilt is a non-flattened one. - forceDisable := ctx.Config().FlattenApex() - - // Force disable the prebuilts when we are doing unbundled build. We do unbundled build - // to build the prebuilts themselves. - forceDisable = forceDisable || ctx.Config().UnbundledBuild() - - // Force disable the prebuilts when coverage is enabled. - forceDisable = forceDisable || ctx.DeviceConfig().NativeCoverageEnabled() - forceDisable = forceDisable || ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") - - // b/137216042 don't use prebuilts when address sanitizer is on - forceDisable = forceDisable || android.InList("address", ctx.Config().SanitizeDevice()) || - android.InList("hwaddress", ctx.Config().SanitizeDevice()) - - if forceDisable && p.prebuilt.SourceExists() { - p.properties.ForceDisable = true - return - } - // This is called before prebuilt_select and prebuilt_postdeps mutators // The mutators requires that src to be set correctly for each arch so that // arch variants are disabled when src is not provided for the arch. @@ -178,10 +194,6 @@ func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) { } func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { - if p.properties.ForceDisable { - return - } - // TODO(jungjw): Check the key validity. p.inputApex = p.Prebuilt().SingleSourcePath(ctx) p.installDir = android.PathForModuleInstall(ctx, "apex") @@ -195,6 +207,12 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { Input: p.inputApex, Output: p.outputApex, }) + + if p.prebuiltCommon.checkForceDisable(ctx) { + p.SkipInstall() + return + } + if p.installable() { ctx.InstallFile(p.installDir, p.installFilename, p.inputApex) } @@ -228,7 +246,7 @@ func (p *Prebuilt) AndroidMkEntries() []android.AndroidMkEntries { type ApexSet struct { android.ModuleBase - prebuilt android.Prebuilt + prebuiltCommon properties ApexSetProperties @@ -274,12 +292,8 @@ func (a *ApexSet) InstallFilename() string { return proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+imageApexSuffix) } -func (a *ApexSet) Prebuilt() *android.Prebuilt { - return &a.prebuilt -} - func (a *ApexSet) Name() string { - return a.prebuilt.Name(a.ModuleBase.Name()) + return a.prebuiltCommon.prebuilt.Name(a.ModuleBase.Name()) } func (a *ApexSet) Overrides() []string { @@ -301,7 +315,7 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.ModuleErrorf("filename should end in %s for apex_set", imageApexSuffix) } - apexSet := a.prebuilt.SingleSourcePath(ctx) + apexSet := a.prebuiltCommon.prebuilt.SingleSourcePath(ctx) a.outputApex = android.PathForModuleOut(ctx, a.installFilename) ctx.Build(pctx, android.BuildParams{ @@ -315,6 +329,12 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { "sdk-version": ctx.Config().PlatformSdkVersion(), }, }) + + if a.prebuiltCommon.checkForceDisable(ctx) { + a.SkipInstall() + return + } + a.installDir = android.PathForModuleInstall(ctx, "apex") if a.installable() { ctx.InstallFile(a.installDir, a.installFilename, a.outputApex) diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go index 689cbd15b..faec473a4 100644 --- a/bpfix/bpfix/bpfix.go +++ b/bpfix/bpfix/bpfix.go @@ -128,6 +128,10 @@ var fixSteps = []FixStep{ Name: "removeSoongConfigBoolVariable", Fix: removeSoongConfigBoolVariable, }, + { + Name: "removePdkProperty", + Fix: runPatchListMod(removePdkProperty), + }, } func NewFixRequest() FixRequest { @@ -993,6 +997,25 @@ func removeTags(mod *parser.Module, buf []byte, patchlist *parser.PatchList) err return patchlist.Add(prop.Pos().Offset, prop.End().Offset+2, replaceStr) } +func removePdkProperty(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error { + prop, ok := mod.GetProperty("product_variables") + if !ok { + return nil + } + propMap, ok := prop.Value.(*parser.Map) + if !ok { + return nil + } + pdkProp, ok := propMap.GetProperty("pdk") + if !ok { + return nil + } + if len(propMap.Properties) > 1 { + return patchlist.Add(pdkProp.Pos().Offset, pdkProp.End().Offset+2, "") + } + return patchlist.Add(prop.Pos().Offset, prop.End().Offset+2, "") +} + func mergeMatchingModuleProperties(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error { return mergeMatchingProperties(&mod.Properties, buf, patchlist) } diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go index 8988177b1..ef9814fb8 100644 --- a/bpfix/bpfix/bpfix_test.go +++ b/bpfix/bpfix/bpfix_test.go @@ -998,3 +998,61 @@ func TestRemoveSoongConfigBoolVariable(t *testing.T) { }) } } + +func TestRemovePdkProperty(t *testing.T) { + tests := []struct { + name string + in string + out string + }{ + { + name: "remove property", + in: ` + cc_library_shared { + name: "foo", + product_variables: { + other: { + bar: true, + }, + pdk: { + enabled: false, + }, + }, + } + `, + out: ` + cc_library_shared { + name: "foo", + product_variables: { + other: { + bar: true, + }, + }, + } + `, + }, + { + name: "remove property and empty product_variables", + in: ` + cc_library_shared { + name: "foo", + product_variables: { + pdk: { + enabled: false, + }, + }, + } + `, + out: ` + cc_library_shared { + name: "foo", + } + `, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + runPass(t, test.in, test.out, runPatchListMod(removePdkProperty)) + }) + } +} diff --git a/cc/Android.bp b/cc/Android.bp index 9ece05f6c..831911e45 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -19,6 +19,7 @@ bootstrap_go_package { "check.go", "coverage.go", "gen.go", + "image.go", "linkable.go", "lto.go", "makevars.go", diff --git a/cc/androidmk.go b/cc/androidmk.go index 3f812c2c0..c899cdd72 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -149,21 +149,33 @@ func (c *Module) AndroidMkEntries() []android.AndroidMkEntries { return []android.AndroidMkEntries{entries} } -func AndroidMkDataPaths(data android.Paths) []string { +func AndroidMkDataPaths(data []android.DataPath) []string { var testFiles []string for _, d := range data { - rel := d.Rel() - path := d.String() + rel := d.SrcPath.Rel() + path := d.SrcPath.String() if !strings.HasSuffix(path, rel) { panic(fmt.Errorf("path %q does not end with %q", path, rel)) } path = strings.TrimSuffix(path, rel) - testFiles = append(testFiles, path+":"+rel) + testFileString := path + ":" + rel + if len(d.RelativeInstallPath) > 0 { + testFileString += ":" + d.RelativeInstallPath + } + testFiles = append(testFiles, testFileString) } return testFiles } -func androidMkWriteTestData(data android.Paths, ctx AndroidMkContext, entries *android.AndroidMkEntries) { +func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) { + if len(extraTestConfigs) > 0 { + entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { + entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...) + }) + } +} + +func androidMkWriteTestData(data []android.DataPath, ctx AndroidMkContext, entries *android.AndroidMkEntries) { testFiles := AndroidMkDataPaths(data) if len(testFiles) > 0 { entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { @@ -202,29 +214,15 @@ func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.An } func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkEntries) { - if library.sAbiOutputFile.Valid() { - entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", - "$(LOCAL_ADDITIONAL_DEPENDENCIES) "+library.sAbiOutputFile.String()) - if library.sAbiDiff.Valid() && !library.static() { - entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", - "$(LOCAL_ADDITIONAL_DEPENDENCIES) "+library.sAbiDiff.String()) - entries.SetString("HEADER_ABI_DIFFS", - "$(HEADER_ABI_DIFFS) "+library.sAbiDiff.String()) - } + if library.sAbiDiff.Valid() && !library.static() { + entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", library.sAbiDiff.String()) } } // TODO(ccross): remove this once apex/androidmk.go is converted to AndroidMkEntries func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) { - if library.sAbiOutputFile.Valid() { - fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_ADDITIONAL_DEPENDENCIES) ", - library.sAbiOutputFile.String()) - if library.sAbiDiff.Valid() && !library.static() { - fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_ADDITIONAL_DEPENDENCIES) ", - library.sAbiDiff.String()) - fmt.Fprintln(w, "HEADER_ABI_DIFFS := $(HEADER_ABI_DIFFS) ", - library.sAbiDiff.String()) - } + if library.sAbiDiff.Valid() && !library.static() { + fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiDiff.String()) } } @@ -282,10 +280,8 @@ func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries entries.SubName = "." + library.stubsVersion() } entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { - // Note library.skipInstall() has a special case to get here for static - // libraries that otherwise would have skipped installation and hence not - // have executed AndroidMkEntries at all. The reason is to ensure they get - // a NOTICE file make target which other libraries might depend on. + // library.makeUninstallable() depends on this to bypass SkipInstall() for + // static libraries. entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) if library.buildStubs() { entries.SetBool("LOCAL_NO_NOTICE_FILE", true) @@ -357,8 +353,11 @@ func (benchmark *benchmarkDecorator) AndroidMkEntries(ctx AndroidMkContext, entr entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true) } }) - - androidMkWriteTestData(benchmark.data, ctx, entries) + dataPaths := []android.DataPath{} + for _, srcPath := range benchmark.data { + dataPaths = append(dataPaths, android.DataPath{SrcPath: srcPath}) + } + androidMkWriteTestData(dataPaths, ctx, entries) } func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { @@ -381,6 +380,7 @@ func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android. }) androidMkWriteTestData(test.data, ctx, entries) + androidMkWriteExtraTestConfigs(test.extraTestConfigs, entries) } func (fuzz *fuzzBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { @@ -511,10 +511,14 @@ func (c *vendorSnapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries.Class = "HEADER_LIBRARIES" } + entries.SubName = "" + + if c.sanitizerProperties.CfiEnabled { + entries.SubName += ".cfi" + } + if c.androidMkVendorSuffix { - entries.SubName = vendorSuffix - } else { - entries.SubName = "" + entries.SubName += vendorSuffix } entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { diff --git a/cc/binary.go b/cc/binary.go index 565cb8ae7..b3ce5ff1c 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -83,7 +83,7 @@ func binaryHostFactory() android.Module { type binaryDecorator struct { *baseLinker *baseInstaller - stripper + stripper Stripper Properties BinaryLinkerProperties @@ -130,34 +130,12 @@ func (binary *binaryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { deps = binary.baseLinker.linkerDeps(ctx, deps) if ctx.toolchain().Bionic() { if !Bool(binary.baseLinker.Properties.Nocrt) { - if !ctx.useSdk() { - if binary.static() { - deps.CrtBegin = "crtbegin_static" - } else { - deps.CrtBegin = "crtbegin_dynamic" - } - deps.CrtEnd = "crtend_android" + if binary.static() { + deps.CrtBegin = "crtbegin_static" } else { - // TODO(danalbert): Add generation of crt objects. - // For `sdk_version: "current"`, we don't actually have a - // freshly generated set of CRT objects. Use the last stable - // version. - version := ctx.sdkVersion() - if version == "current" { - version = getCurrentNdkPrebuiltVersion(ctx) - } - - if binary.static() { - deps.CrtBegin = "ndk_crtbegin_static." + version - } else { - if binary.static() { - deps.CrtBegin = "ndk_crtbegin_static." + version - } else { - deps.CrtBegin = "ndk_crtbegin_dynamic." + version - } - deps.CrtEnd = "ndk_crtend_android." + version - } + deps.CrtBegin = "crtbegin_dynamic" } + deps.CrtEnd = "crtend_android" } if binary.static() { @@ -339,14 +317,14 @@ func (binary *binaryDecorator) link(ctx ModuleContext, } builderFlags := flagsToBuilderFlags(flags) - - if binary.stripper.needsStrip(ctx) { + stripFlags := flagsToStripFlags(flags) + if binary.stripper.NeedsStrip(ctx) { if ctx.Darwin() { - builderFlags.stripUseGnuStrip = true + stripFlags.StripUseGnuStrip = true } strippedOutputFile := outputFile outputFile = android.PathForModuleOut(ctx, "unstripped", fileName) - binary.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags) + binary.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, stripFlags) } binary.unstrippedOutputFile = outputFile @@ -355,7 +333,7 @@ func (binary *binaryDecorator) link(ctx ModuleContext, afterPrefixSymbols := outputFile outputFile = android.PathForModuleOut(ctx, "unprefixed", fileName) TransformBinaryPrefixSymbols(ctx, String(binary.Properties.Prefix_symbols), outputFile, - flagsToBuilderFlags(flags), afterPrefixSymbols) + builderFlags, afterPrefixSymbols) } outputFile = maybeInjectBoringSSLHash(ctx, outputFile, binary.Properties.Inject_bssl_hash, fileName) @@ -369,10 +347,10 @@ func (binary *binaryDecorator) link(ctx ModuleContext, versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName) binary.distFiles = android.MakeDefaultDistFiles(versionedOutputFile) - if binary.stripper.needsStrip(ctx) { + if binary.stripper.NeedsStrip(ctx) { out := android.PathForModuleOut(ctx, "versioned-stripped", fileName) binary.distFiles = android.MakeDefaultDistFiles(out) - binary.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags) + binary.stripper.StripExecutableOrSharedLib(ctx, versionedOutputFile, out, stripFlags) } binary.injectVersionSymbol(ctx, outputFile, versionedOutputFile) @@ -467,7 +445,7 @@ func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) { // The original path becomes a symlink to the corresponding file in the // runtime APEX. translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled - if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() { + if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() { if ctx.Device() && isBionic(ctx.baseModuleName()) { binary.installSymlinkToRuntimeApex(ctx, file) } diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go index 372a72e2c..337de55b3 100644 --- a/cc/binary_sdk_member.go +++ b/cc/binary_sdk_member.go @@ -29,7 +29,8 @@ func init() { var ccBinarySdkMemberType = &binarySdkMemberType{ SdkMemberTypeBase: android.SdkMemberTypeBase{ - PropertyName: "native_binaries", + PropertyName: "native_binaries", + HostOsDependent: true, }, } @@ -140,10 +141,6 @@ func (p *nativeBinaryInfoProperties) PopulateFromVariant(ctx android.SdkMemberCo } func (p *nativeBinaryInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { - if p.Compile_multilib != "" { - propertySet.AddProperty("compile_multilib", p.Compile_multilib) - } - builder := ctx.SnapshotBuilder() if p.outputFile != nil { propertySet.AddProperty("srcs", []string{nativeBinaryPathFor(*p)}) diff --git a/cc/builder.go b/cc/builder.go index b4f9947d7..8f2da34eb 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -174,12 +174,21 @@ var ( }, "crossCompile", "format") - clangTidy = pctx.AndroidStaticRule("clangTidy", + clangTidy, clangTidyRE = remoteexec.StaticRules(pctx, "clangTidy", blueprint.RuleParams{ - Command: "rm -f $out && ${config.ClangBin}/clang-tidy $tidyFlags $in -- $cFlags && touch $out", + Command: "rm -f $out && $reTemplate${config.ClangBin}/clang-tidy $tidyFlags $in -- $cFlags && touch $out", CommandDeps: []string{"${config.ClangBin}/clang-tidy"}, }, - "cFlags", "tidyFlags") + &remoteexec.REParams{ + Labels: map[string]string{"type": "lint", "tool": "clang-tidy", "lang": "cpp"}, + ExecStrategy: "${config.REClangTidyExecStrategy}", + Inputs: []string{"$in"}, + // OutputFile here is $in for remote-execution since its possible that + // clang-tidy modifies the given input file itself and $out refers to the + // ".tidy" file generated for ninja-dependency reasons. + OutputFiles: []string{"$in"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"}, + }, []string{"cFlags", "tidyFlags"}, []string{}) _ = pctx.SourcePathVariable("yasmCmd", "prebuilts/misc/${config.HostPrebuiltTag}/yasm/yasm") @@ -256,9 +265,9 @@ var ( zip = pctx.AndroidStaticRule("zip", blueprint.RuleParams{ - Command: "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp", + Command: "${SoongZipCmd} -o ${out} -C $$OUT_DIR -r ${out}.rsp", CommandDeps: []string{"${SoongZipCmd}"}, - Rspfile: "$out.rsp", + Rspfile: "${out}.rsp", RspfileContent: "$in", }) @@ -340,18 +349,22 @@ type builderFlags struct { groupStaticLibs bool - stripKeepSymbols bool - stripKeepSymbolsList string - stripKeepSymbolsAndDebugFrame bool - stripKeepMiniDebugInfo bool - stripAddGnuDebuglink bool - stripUseGnuStrip bool - proto android.ProtoFlags protoC bool protoOptionsFile bool yacc *YaccProperties + lex *LexProperties +} + +type StripFlags struct { + Toolchain config.Toolchain + StripKeepSymbols bool + StripKeepSymbolsList string + StripKeepSymbolsAndDebugFrame bool + StripKeepMiniDebugInfo bool + StripAddGnuDebuglink bool + StripUseGnuStrip bool } type Objects struct { @@ -569,8 +582,13 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and tidyFile := android.ObjPathWithExt(ctx, subdir, srcFile, "tidy") tidyFiles = append(tidyFiles, tidyFile) + rule := clangTidy + if ctx.Config().IsEnvTrue("RBE_CLANG_TIDY") { + rule = clangTidyRE + } + ctx.Build(pctx, android.BuildParams{ - Rule: clangTidy, + Rule: rule, Description: "clang-tidy " + srcFile.Rel(), Output: tidyFile, Input: srcFile, @@ -925,26 +943,26 @@ func TransformBinaryPrefixSymbols(ctx android.ModuleContext, prefix string, inpu } func TransformStrip(ctx android.ModuleContext, inputFile android.Path, - outputFile android.WritablePath, flags builderFlags) { + outputFile android.WritablePath, flags StripFlags) { - crossCompile := gccCmd(flags.toolchain, "") + crossCompile := gccCmd(flags.Toolchain, "") args := "" - if flags.stripAddGnuDebuglink { + if flags.StripAddGnuDebuglink { args += " --add-gnu-debuglink" } - if flags.stripKeepMiniDebugInfo { + if flags.StripKeepMiniDebugInfo { args += " --keep-mini-debug-info" } - if flags.stripKeepSymbols { + if flags.StripKeepSymbols { args += " --keep-symbols" } - if flags.stripKeepSymbolsList != "" { - args += " -k" + flags.stripKeepSymbolsList + if flags.StripKeepSymbolsList != "" { + args += " -k" + flags.StripKeepSymbolsList } - if flags.stripKeepSymbolsAndDebugFrame { + if flags.StripKeepSymbolsAndDebugFrame { args += " --keep-symbols-and-debug-frame" } - if flags.stripUseGnuStrip { + if flags.StripUseGnuStrip { args += " --use-gnu-strip" } @@ -210,6 +210,7 @@ type Flags struct { protoOptionsFile bool // Whether to look for a .options file next to the .proto Yacc *YaccProperties + Lex *LexProperties } // Properties used to compile all C or C++ modules @@ -344,7 +345,7 @@ type ModuleContextIntf interface { isNDKStubLibrary() bool useClangLld(actx ModuleContext) bool isForPlatform() bool - apexName() string + apexVariationName() string apexSdkVersion() int hasStubsVariants() bool isStubs() bool @@ -418,51 +419,137 @@ type installer interface { inSanitizerDir() bool hostToolPath() android.OptionalPath relativeInstallPath() string - skipInstall(mod *Module) + makeUninstallable(mod *Module) } type xref interface { XrefCcFiles() android.Paths } +type libraryDependencyKind int + +const ( + headerLibraryDependency = iota + sharedLibraryDependency + staticLibraryDependency +) + +func (k libraryDependencyKind) String() string { + switch k { + case headerLibraryDependency: + return "headerLibraryDependency" + case sharedLibraryDependency: + return "sharedLibraryDependency" + case staticLibraryDependency: + return "staticLibraryDependency" + default: + panic(fmt.Errorf("unknown libraryDependencyKind %d", k)) + } +} + +type libraryDependencyOrder int + +const ( + earlyLibraryDependency = -1 + normalLibraryDependency = 0 + lateLibraryDependency = 1 +) + +func (o libraryDependencyOrder) String() string { + switch o { + case earlyLibraryDependency: + return "earlyLibraryDependency" + case normalLibraryDependency: + return "normalLibraryDependency" + case lateLibraryDependency: + return "lateLibraryDependency" + default: + panic(fmt.Errorf("unknown libraryDependencyOrder %d", o)) + } +} + +// libraryDependencyTag is used to tag dependencies on libraries. Unlike many dependency +// tags that have a set of predefined tag objects that are reused for each dependency, a +// libraryDependencyTag is designed to contain extra metadata and is constructed as needed. +// That means that comparing a libraryDependencyTag for equality will only be equal if all +// of the metadata is equal. Most usages will want to type assert to libraryDependencyTag and +// then check individual metadata fields instead. +type libraryDependencyTag struct { + blueprint.BaseDependencyTag + + // These are exported so that fmt.Printf("%#v") can call their String methods. + Kind libraryDependencyKind + Order libraryDependencyOrder + + wholeStatic bool + + reexportFlags bool + explicitlyVersioned bool + dataLib bool + ndk bool + + staticUnwinder bool + + makeSuffix string +} + +// header returns true if the libraryDependencyTag is tagging a header lib dependency. +func (d libraryDependencyTag) header() bool { + return d.Kind == headerLibraryDependency +} + +// shared returns true if the libraryDependencyTag is tagging a shared lib dependency. +func (d libraryDependencyTag) shared() bool { + return d.Kind == sharedLibraryDependency +} + +// shared returns true if the libraryDependencyTag is tagging a static lib dependency. +func (d libraryDependencyTag) static() bool { + return d.Kind == staticLibraryDependency +} + +// dependencyTag is used for tagging miscellanous 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 +// variable and modifying it will not modify the original). Users can compare the tag +// returned by ctx.OtherModuleDependencyTag against the global original +type dependencyTag struct { + blueprint.BaseDependencyTag + name string +} + var ( - dataLibDepTag = DependencyTag{Name: "data_lib", Library: true, Shared: true} - sharedExportDepTag = DependencyTag{Name: "shared", Library: true, Shared: true, ReexportFlags: true} - earlySharedDepTag = DependencyTag{Name: "early_shared", Library: true, Shared: true} - lateSharedDepTag = DependencyTag{Name: "late shared", Library: true, Shared: true} - staticExportDepTag = DependencyTag{Name: "static", Library: true, ReexportFlags: true} - lateStaticDepTag = DependencyTag{Name: "late static", Library: true} - staticUnwinderDepTag = DependencyTag{Name: "static unwinder", Library: true} - wholeStaticDepTag = DependencyTag{Name: "whole static", Library: true, ReexportFlags: true} - headerDepTag = DependencyTag{Name: "header", Library: true} - headerExportDepTag = DependencyTag{Name: "header", Library: true, ReexportFlags: true} - genSourceDepTag = DependencyTag{Name: "gen source"} - genHeaderDepTag = DependencyTag{Name: "gen header"} - genHeaderExportDepTag = DependencyTag{Name: "gen header", ReexportFlags: true} - objDepTag = DependencyTag{Name: "obj"} - linkerFlagsDepTag = DependencyTag{Name: "linker flags file"} - dynamicLinkerDepTag = DependencyTag{Name: "dynamic linker"} - reuseObjTag = DependencyTag{Name: "reuse objects"} - staticVariantTag = DependencyTag{Name: "static variant"} - ndkStubDepTag = DependencyTag{Name: "ndk stub", Library: true} - ndkLateStubDepTag = DependencyTag{Name: "ndk late stub", Library: true} - vndkExtDepTag = DependencyTag{Name: "vndk extends", Library: true} - runtimeDepTag = DependencyTag{Name: "runtime lib"} - testPerSrcDepTag = DependencyTag{Name: "test_per_src"} + genSourceDepTag = dependencyTag{name: "gen source"} + genHeaderDepTag = dependencyTag{name: "gen header"} + genHeaderExportDepTag = dependencyTag{name: "gen header export"} + objDepTag = dependencyTag{name: "obj"} + linkerFlagsDepTag = dependencyTag{name: "linker flags file"} + dynamicLinkerDepTag = dependencyTag{name: "dynamic linker"} + reuseObjTag = dependencyTag{name: "reuse objects"} + staticVariantTag = dependencyTag{name: "static variant"} + vndkExtDepTag = dependencyTag{name: "vndk extends"} + dataLibDepTag = dependencyTag{name: "data lib"} + runtimeDepTag = dependencyTag{name: "runtime lib"} + testPerSrcDepTag = dependencyTag{name: "test_per_src"} ) func IsSharedDepTag(depTag blueprint.DependencyTag) bool { - ccDepTag, ok := depTag.(DependencyTag) - return ok && ccDepTag.Shared + ccLibDepTag, ok := depTag.(libraryDependencyTag) + return ok && ccLibDepTag.shared() +} + +func IsStaticDepTag(depTag blueprint.DependencyTag) bool { + ccLibDepTag, ok := depTag.(libraryDependencyTag) + return ok && ccLibDepTag.static() } func IsRuntimeDepTag(depTag blueprint.DependencyTag) bool { - ccDepTag, ok := depTag.(DependencyTag) + ccDepTag, ok := depTag.(dependencyTag) return ok && ccDepTag == runtimeDepTag } func IsTestPerSrcDepTag(depTag blueprint.DependencyTag) bool { - ccDepTag, ok := depTag.(DependencyTag) + ccDepTag, ok := depTag.(dependencyTag) return ok && ccDepTag == testPerSrcDepTag } @@ -595,6 +682,13 @@ func (c *Module) MinSdkVersion() string { return String(c.Properties.Min_sdk_version) } +func (c *Module) SplitPerApiLevel() bool { + if linker, ok := c.linker.(*objectLinker); ok { + return linker.isCrt() + } + return false +} + func (c *Module) AlwaysSdk() bool { return c.Properties.AlwaysSdk || Bool(c.Properties.Sdk_variant_only) } @@ -866,7 +960,7 @@ func (c *Module) canUseSdk() bool { func (c *Module) UseSdk() bool { if c.canUseSdk() { - return String(c.Properties.Sdk_version) != "" + return String(c.Properties.Sdk_version) != "" || c.SplitPerApiLevel() } return false } @@ -876,7 +970,7 @@ func (c *Module) isCoverageVariant() bool { } func (c *Module) IsNdk() bool { - return inList(c.Name(), ndkKnownLibs) + return inList(c.BaseModuleName(), ndkKnownLibs) } func (c *Module) isLlndk(config android.Config) bool { @@ -941,48 +1035,6 @@ func (c *Module) getVndkExtendsModuleName() string { return "" } -// Returns true only when this module is configured to have core, product and vendor -// variants. -func (c *Module) HasVendorVariant() bool { - return c.IsVndk() || Bool(c.VendorProperties.Vendor_available) -} - -const ( - // VendorVariationPrefix is the variant prefix used for /vendor code that compiles - // against the VNDK. - VendorVariationPrefix = "vendor." - - // ProductVariationPrefix is the variant prefix used for /product code that compiles - // against the VNDK. - ProductVariationPrefix = "product." -) - -// 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 -} - -// 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 -} - -func (c *Module) InRamdisk() bool { - return c.ModuleBase.InRamdisk() || c.ModuleBase.InstallInRamdisk() -} - -func (c *Module) InRecovery() bool { - return c.ModuleBase.InRecovery() || c.ModuleBase.InstallInRecovery() -} - -func (c *Module) OnlyInRamdisk() bool { - return c.ModuleBase.InstallInRamdisk() -} - -func (c *Module) OnlyInRecovery() bool { - return c.ModuleBase.InstallInRecovery() -} - func (c *Module) IsStubs() bool { if library, ok := c.linker.(*libraryDecorator); ok { return library.buildStubs() @@ -1090,16 +1142,6 @@ type moduleContext struct { moduleContextImpl } -func (ctx *moduleContext) ProductSpecific() bool { - return ctx.ModuleContext.ProductSpecific() || - (ctx.mod.HasVendorVariant() && ctx.mod.inProduct() && !ctx.mod.IsVndk()) -} - -func (ctx *moduleContext) SocSpecific() bool { - return ctx.ModuleContext.SocSpecific() || - (ctx.mod.HasVendorVariant() && ctx.mod.inVendor() && !ctx.mod.IsVndk()) -} - type moduleContextImpl struct { mod *Module ctx BaseModuleContext @@ -1195,22 +1237,6 @@ func (ctx *moduleContextImpl) mustUseVendorVariant() bool { return ctx.mod.MustUseVendorVariant() } -func (ctx *moduleContextImpl) inProduct() bool { - return ctx.mod.inProduct() -} - -func (ctx *moduleContextImpl) inVendor() bool { - return ctx.mod.inVendor() -} - -func (ctx *moduleContextImpl) inRamdisk() bool { - return ctx.mod.InRamdisk() -} - -func (ctx *moduleContextImpl) inRecovery() bool { - return ctx.mod.InRecovery() -} - // Check whether ABI dumps should be created for this module. func (ctx *moduleContextImpl) shouldCreateSourceAbiDump() bool { if ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") { @@ -1265,8 +1291,8 @@ func (ctx *moduleContextImpl) isForPlatform() bool { return ctx.mod.IsForPlatform() } -func (ctx *moduleContextImpl) apexName() string { - return ctx.mod.ApexName() +func (ctx *moduleContextImpl) apexVariationName() string { + return ctx.mod.ApexVariationName() } func (ctx *moduleContextImpl) apexSdkVersion() int { @@ -1401,9 +1427,9 @@ func (c *Module) IsTestPerSrcAllTestsVariation() bool { return ok && test.isAllTestsVariation() } -func (c *Module) DataPaths() android.Paths { +func (c *Module) DataPaths() []android.DataPath { if p, ok := c.installer.(interface { - dataPaths() android.Paths + dataPaths() []android.DataPath }); ok { return p.dataPaths() } @@ -1467,8 +1493,11 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { c.Properties.SubName += ramdiskSuffix } else if c.InRecovery() && !c.OnlyInRecovery() { c.Properties.SubName += recoverySuffix - } else if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake { + } else if c.IsSdkVariant() && (c.Properties.SdkAndPlatformVariantVisibleToMake || c.SplitPerApiLevel()) { c.Properties.SubName += sdkSuffix + if c.SplitPerApiLevel() { + c.Properties.SubName += "." + c.SdkVersion() + } } ctx := &moduleContext{ @@ -1641,7 +1670,7 @@ func (c *Module) begin(ctx BaseModuleContext) { for _, feature := range c.features { feature.begin(ctx) } - if ctx.useSdk() { + if ctx.useSdk() && c.IsSdkVariant() { version, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch()) if err != nil { ctx.PropertyErrorf("sdk_version", err.Error()) @@ -1744,6 +1773,22 @@ func StubsLibNameAndVersion(name string) (string, string) { return name, "" } +func GetCrtVariations(ctx android.BottomUpMutatorContext, + m LinkableInterface) []blueprint.Variation { + if ctx.Os() != android.Android { + return nil + } + if m.UseSdk() { + return []blueprint.Variation{ + {Mutator: "sdk", Variation: "sdk"}, + {Mutator: "ndk_api", Variation: m.SdkVersion()}, + } + } + return []blueprint.Variation{ + {Mutator: "sdk", Variation: ""}, + } +} + func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { if !c.Enabled() { return @@ -1859,9 +1904,9 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { vendorSnapshotHeaderLibs := vendorSnapshotHeaderLibs(actx.Config()) for _, lib := range deps.HeaderLibs { - depTag := headerDepTag + depTag := libraryDependencyTag{Kind: headerLibraryDependency} if inList(lib, deps.ReexportHeaderLibHeaders) { - depTag = headerExportDepTag + depTag.reexportFlags = true } lib = rewriteSnapshotLibs(lib, vendorSnapshotHeaderLibs) @@ -1884,7 +1929,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { vendorSnapshotStaticLibs := vendorSnapshotStaticLibs(actx.Config()) for _, lib := range deps.WholeStaticLibs { - depTag := wholeStaticDepTag + depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true, reexportFlags: true} if impl, ok := syspropImplLibraries[lib]; ok { lib = impl } @@ -1897,9 +1942,9 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { } for _, lib := range deps.StaticLibs { - depTag := StaticDepTag + depTag := libraryDependencyTag{Kind: staticLibraryDependency} if inList(lib, deps.ReexportStaticLibHeaders) { - depTag = staticExportDepTag + depTag.reexportFlags = true } if impl, ok := syspropImplLibraries[lib]; ok { @@ -1917,24 +1962,26 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { // so that native libraries/binaries are linked with static unwinder // because Q libc doesn't have unwinder APIs if deps.StaticUnwinderIfLegacy { + depTag := libraryDependencyTag{Kind: staticLibraryDependency, staticUnwinder: true} actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, - }, staticUnwinderDepTag, rewriteSnapshotLibs(staticUnwinder(actx), vendorSnapshotStaticLibs)) + }, depTag, rewriteSnapshotLibs(staticUnwinder(actx), vendorSnapshotStaticLibs)) } for _, lib := range deps.LateStaticLibs { + depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency} actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, - }, lateStaticDepTag, rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs)) + }, depTag, rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs)) } - addSharedLibDependencies := func(depTag DependencyTag, name string, version string) { + addSharedLibDependencies := func(depTag libraryDependencyTag, name string, version string) { var variations []blueprint.Variation variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"}) if version != "" && VersionVariantAvailable(c) { // Version is explicitly specified. i.e. libFoo#30 variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version}) - depTag.ExplicitlyVersioned = true + depTag.explicitlyVersioned = true } actx.AddVariationDependencies(variations, depTag, name) @@ -1956,12 +2003,9 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { var sharedLibNames []string for _, lib := range deps.SharedLibs { - depTag := SharedDepTag - if c.static() { - depTag = SharedFromStaticDepTag - } + depTag := libraryDependencyTag{Kind: sharedLibraryDependency} if inList(lib, deps.ReexportSharedLibHeaders) { - depTag = sharedExportDepTag + depTag.reexportFlags = true } if impl, ok := syspropImplLibraries[lib]; ok { @@ -1981,7 +2025,8 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { // linking against both the stubs lib and the non-stubs lib at the same time. continue } - addSharedLibDependencies(lateSharedDepTag, lib, "") + depTag := libraryDependencyTag{Kind: sharedLibraryDependency, Order: lateLibraryDependency} + addSharedLibDependencies(depTag, lib, "") } actx.AddVariationDependencies([]blueprint.Variation{ @@ -2006,11 +2051,14 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { vendorSnapshotObjects := vendorSnapshotObjects(actx.Config()) + crtVariations := GetCrtVariations(ctx, c) if deps.CrtBegin != "" { - actx.AddVariationDependencies(nil, CrtBeginDepTag, rewriteSnapshotLibs(deps.CrtBegin, vendorSnapshotObjects)) + actx.AddVariationDependencies(crtVariations, CrtBeginDepTag, + rewriteSnapshotLibs(deps.CrtBegin, vendorSnapshotObjects)) } if deps.CrtEnd != "" { - actx.AddVariationDependencies(nil, CrtEndDepTag, rewriteSnapshotLibs(deps.CrtEnd, vendorSnapshotObjects)) + actx.AddVariationDependencies(crtVariations, CrtEndDepTag, + rewriteSnapshotLibs(deps.CrtEnd, vendorSnapshotObjects)) } if deps.LinkerFlagsFile != "" { actx.AddDependency(c, linkerFlagsDepTag, deps.LinkerFlagsFile) @@ -2020,10 +2068,14 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { } version := ctx.sdkVersion() + + ndkStubDepTag := libraryDependencyTag{Kind: sharedLibraryDependency, ndk: true, makeSuffix: "." + version} actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "ndk_api", Variation: version}, {Mutator: "link", Variation: "shared"}, }, ndkStubDepTag, variantNdkLibs...) + + ndkLateStubDepTag := libraryDependencyTag{Kind: sharedLibraryDependency, Order: lateLibraryDependency, ndk: true, makeSuffix: "." + version} actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "ndk_api", Variation: version}, {Mutator: "link", Variation: "shared"}, @@ -2047,7 +2099,19 @@ func BeginMutator(ctx android.BottomUpMutatorContext) { // Whether a module can link to another module, taking into // account NDK linking. -func checkLinkType(ctx android.ModuleContext, from LinkableInterface, to LinkableInterface, tag DependencyTag) { +func checkLinkType(ctx android.ModuleContext, from LinkableInterface, to LinkableInterface, + tag blueprint.DependencyTag) { + + switch t := tag.(type) { + case dependencyTag: + if t != vndkExtDepTag { + return + } + case libraryDependencyTag: + default: + return + } + if from.Module().Target().Os != android.Android { // Host code is not restricted return @@ -2205,8 +2269,6 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { directStaticDeps := []LinkableInterface{} directSharedDeps := []LinkableInterface{} - vendorPublicLibraries := vendorPublicLibraries(ctx.Config()) - reexportExporter := func(exporter exportedFlagsProducer) { depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, exporter.exportedDirs()...) depPaths.ReexportedSystemDirs = append(depPaths.ReexportedSystemDirs, exporter.exportedSystemDirs()...) @@ -2215,6 +2277,19 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.ReexportedGeneratedHeaders = append(depPaths.ReexportedGeneratedHeaders, exporter.exportedGeneratedHeaders()...) } + // For the dependency from platform to apex, use the latest stubs + c.apexSdkVersion = android.FutureApiLevel + if !c.IsForPlatform() { + c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion + } + + if android.InList("hwaddress", ctx.Config().SanitizeDevice()) { + // In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000) + // so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)). + // (b/144430859) + c.apexSdkVersion = android.FutureApiLevel + } + ctx.VisitDirectDeps(func(dep android.Module) { depName := ctx.OtherModuleName(dep) depTag := ctx.OtherModuleDependencyTag(dep) @@ -2303,52 +2378,24 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } } - // For the dependency from platform to apex, use the latest stubs - c.apexSdkVersion = android.FutureApiLevel - if !c.IsForPlatform() { - c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion - } + checkLinkType(ctx, c, ccDep, depTag) - if android.InList("hwaddress", ctx.Config().SanitizeDevice()) { - // In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000) - // so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)). - // (b/144430859) - c.apexSdkVersion = android.FutureApiLevel - } + linkFile := ccDep.OutputFile() - if depTag == staticUnwinderDepTag { - // Use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859) - if c.apexSdkVersion <= android.SdkVersion_Android10 { - depTag = StaticDepTag - } else { + if libDepTag, ok := depTag.(libraryDependencyTag); ok { + // Only use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859) + if libDepTag.staticUnwinder && c.apexSdkVersion > android.SdkVersion_Android10 { return } - } - // Extract ExplicitlyVersioned field from the depTag and reset it inside the struct. - // Otherwise, SharedDepTag and lateSharedDepTag with ExplicitlyVersioned set to true - // won't be matched to SharedDepTag and lateSharedDepTag. - explicitlyVersioned := false - if t, ok := depTag.(DependencyTag); ok { - explicitlyVersioned = t.ExplicitlyVersioned - t.ExplicitlyVersioned = false - depTag = t - } - - if t, ok := depTag.(DependencyTag); ok && t.Library { - depIsStatic := false - switch depTag { - case StaticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag: - depIsStatic = true - } - if ccDep.CcLibrary() && !depIsStatic { + if ccDep.CcLibrary() && !libDepTag.static() { depIsStubs := ccDep.BuildStubs() depHasStubs := VersionVariantAvailable(c) && ccDep.HasStubsVariants() - depInSameApex := android.DirectlyInApex(c.ApexName(), depName) + depInSameApexes := android.DirectlyInAllApexes(c.InApexes(), depName) depInPlatform := !android.DirectlyInAnyApex(ctx, depName) var useThisDep bool - if depIsStubs && explicitlyVersioned { + if depIsStubs && libDepTag.explicitlyVersioned { // Always respect dependency to the versioned stubs (i.e. libX#10) useThisDep = true } else if !depHasStubs { @@ -2374,13 +2421,13 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } } } else { - // If building for APEX, use stubs only when it is not from - // the same APEX - useThisDep = (depInSameApex != depIsStubs) + // If building for APEX, use stubs when the parent is in any APEX that + // the child is not in. + useThisDep = (depInSameApexes != depIsStubs) } // when to use (unspecified) stubs, check min_sdk_version and choose the right one - if useThisDep && depIsStubs && !explicitlyVersioned { + if useThisDep && depIsStubs && !libDepTag.explicitlyVersioned { versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), c.apexSdkVersion) if err != nil { ctx.OtherModuleErrorf(dep, err.Error()) @@ -2400,7 +2447,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // by default, use current version of LLNDK versionToUse := "" versions := stubsVersionsFor(ctx.Config())[depName] - if c.ApexName() != "" && len(versions) > 0 { + if c.ApexVariationName() != "" && len(versions) > 0 { // if this is for use_vendor apex && dep has stubsVersions // apply the same rule of apex sdk enforcement to choose right version var err error @@ -2425,7 +2472,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.GeneratedDeps = append(depPaths.GeneratedDeps, i.exportedDeps()...) depPaths.Flags = append(depPaths.Flags, i.exportedFlags()...) - if t.ReexportFlags { + if libDepTag.reexportFlags { reexportExporter(i) // 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 @@ -2437,210 +2484,169 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } } } - checkLinkType(ctx, c, ccDep, t) - } - - var ptr *android.Paths - var depPtr *android.Paths - linkFile := ccDep.OutputFile() - depFile := android.OptionalPath{} - - switch depTag { - case ndkStubDepTag, SharedDepTag, SharedFromStaticDepTag, sharedExportDepTag: - ptr = &depPaths.SharedLibs - depPtr = &depPaths.SharedLibsDeps - depFile = ccDep.Toc() - directSharedDeps = append(directSharedDeps, ccDep) - - case earlySharedDepTag: - ptr = &depPaths.EarlySharedLibs - depPtr = &depPaths.EarlySharedLibsDeps - depFile = ccDep.Toc() - directSharedDeps = append(directSharedDeps, ccDep) - case lateSharedDepTag, ndkLateStubDepTag: - ptr = &depPaths.LateSharedLibs - depPtr = &depPaths.LateSharedLibsDeps - depFile = ccDep.Toc() - case StaticDepTag, staticExportDepTag: - ptr = nil - directStaticDeps = append(directStaticDeps, ccDep) - case lateStaticDepTag: - ptr = &depPaths.LateStaticLibs - case wholeStaticDepTag: - ptr = &depPaths.WholeStaticLibs - if !ccDep.CcLibraryInterface() || !ccDep.Static() { - ctx.ModuleErrorf("module %q not a static library", depName) - return - } + var ptr *android.Paths + var depPtr *android.Paths + + depFile := android.OptionalPath{} + + switch { + case libDepTag.header(): + // nothing + case libDepTag.shared(): + ptr = &depPaths.SharedLibs + switch libDepTag.Order { + case earlyLibraryDependency: + ptr = &depPaths.EarlySharedLibs + depPtr = &depPaths.EarlySharedLibsDeps + case normalLibraryDependency: + ptr = &depPaths.SharedLibs + depPtr = &depPaths.SharedLibsDeps + directSharedDeps = append(directSharedDeps, ccDep) + case lateLibraryDependency: + ptr = &depPaths.LateSharedLibs + depPtr = &depPaths.LateSharedLibsDeps + default: + panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order)) + } + depFile = ccDep.Toc() + case libDepTag.static(): + if libDepTag.wholeStatic { + ptr = &depPaths.WholeStaticLibs + if !ccDep.CcLibraryInterface() || !ccDep.Static() { + ctx.ModuleErrorf("module %q not a static library", depName) + return + } - // Because the static library objects are included, this only makes sense - // in the context of proper cc.Modules. - if ccWholeStaticLib, ok := ccDep.(*Module); ok { - staticLib := ccWholeStaticLib.linker.(libraryInterface) - if missingDeps := staticLib.getWholeStaticMissingDeps(); missingDeps != nil { - postfix := " (required by " + ctx.OtherModuleName(dep) + ")" - for i := range missingDeps { - missingDeps[i] += postfix + // Because the static library objects are included, this only makes sense + // in the context of proper cc.Modules. + if ccWholeStaticLib, ok := ccDep.(*Module); ok { + staticLib := ccWholeStaticLib.linker.(libraryInterface) + if missingDeps := staticLib.getWholeStaticMissingDeps(); missingDeps != nil { + postfix := " (required by " + ctx.OtherModuleName(dep) + ")" + for i := range missingDeps { + missingDeps[i] += postfix + } + ctx.AddMissingDependencies(missingDeps) + } + if _, ok := ccWholeStaticLib.linker.(prebuiltLinkerInterface); ok { + depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, linkFile.Path()) + } else { + depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs()) + } + } else { + ctx.ModuleErrorf( + "non-cc.Modules cannot be included as whole static libraries.", depName) + return } - ctx.AddMissingDependencies(missingDeps) - } - if _, ok := ccWholeStaticLib.linker.(prebuiltLinkerInterface); ok { - depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, linkFile.Path()) + } else { - depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs()) + 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, ccDep) + case lateLibraryDependency: + ptr = &depPaths.LateStaticLibs + default: + panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order)) + } } - } else { - ctx.ModuleErrorf( - "non-cc.Modules cannot be included as whole static libraries.", depName) - return - } - case headerDepTag: - // Nothing - case objDepTag: - depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path()) - case CrtBeginDepTag: - depPaths.CrtBegin = linkFile - case CrtEndDepTag: - depPaths.CrtEnd = linkFile - case dynamicLinkerDepTag: - depPaths.DynamicLinker = linkFile - } - - switch depTag { - case StaticDepTag, staticExportDepTag, lateStaticDepTag: - if !ccDep.CcLibraryInterface() || !ccDep.Static() { - ctx.ModuleErrorf("module %q not a static library", depName) - return - } - - // When combining coverage files for shared libraries and executables, coverage files - // in static libraries act as if they were whole static libraries. The same goes for - // source based Abi dump files. - if c, ok := ccDep.(*Module); ok { - staticLib := c.linker.(libraryInterface) - depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles, - staticLib.objs().coverageFiles...) - depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles, - staticLib.objs().sAbiDumpFiles...) - } else if c, ok := ccDep.(LinkableInterface); ok { - // Handle non-CC modules here - depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles, - c.CoverageFiles()...) } - } - if ptr != nil { - if !linkFile.Valid() { - if !ctx.Config().AllowMissingDependencies() { - ctx.ModuleErrorf("module %q missing output file", depName) - } else { - ctx.AddMissingDependencies([]string{depName}) + if libDepTag.static() && !libDepTag.wholeStatic { + if !ccDep.CcLibraryInterface() || !ccDep.Static() { + ctx.ModuleErrorf("module %q not a static library", depName) + return } - return - } - *ptr = append(*ptr, linkFile.Path()) - } - if depPtr != nil { - dep := depFile - if !dep.Valid() { - dep = linkFile + // When combining coverage files for shared libraries and executables, coverage files + // in static libraries act as if they were whole static libraries. The same goes for + // source based Abi dump files. + if c, ok := ccDep.(*Module); ok { + staticLib := c.linker.(libraryInterface) + depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles, + staticLib.objs().coverageFiles...) + depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles, + staticLib.objs().sAbiDumpFiles...) + } else if c, ok := ccDep.(LinkableInterface); ok { + // Handle non-CC modules here + depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles, + c.CoverageFiles()...) + } } - *depPtr = append(*depPtr, dep.Path()) - } - - vendorSuffixModules := vendorSuffixModules(ctx.Config()) - baseLibName := func(depName string) string { - libName := strings.TrimSuffix(depName, llndkLibrarySuffix) - libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix) - libName = strings.TrimPrefix(libName, "prebuilt_") - return libName - } - - makeLibName := func(depName string) string { - libName := baseLibName(depName) - isLLndk := isLlndkLibrary(libName, ctx.Config()) - isVendorPublicLib := inList(libName, *vendorPublicLibraries) - bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk - - if c, ok := ccDep.(*Module); ok { - // Use base module name for snapshots when exporting to Makefile. - if c.isSnapshotPrebuilt() { - baseName := c.BaseModuleName() - - if c.IsVndk() { - return baseName + ".vendor" - } - - if vendorSuffixModules[baseName] { - return baseName + ".vendor" + if ptr != nil { + if !linkFile.Valid() { + if !ctx.Config().AllowMissingDependencies() { + ctx.ModuleErrorf("module %q missing output file", depName) } else { - return baseName + ctx.AddMissingDependencies([]string{depName}) } + return } + *ptr = append(*ptr, linkFile.Path()) } - if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && !c.InRamdisk() && !c.InRecovery() { - // The vendor module is a no-vendor-variant VNDK library. Depend on the - // core module instead. - return libName - } else if c.UseVndk() && bothVendorAndCoreVariantsExist { - // The vendor module in Make will have been renamed to not conflict with the core - // module, so update the dependency name here accordingly. - return libName + c.getNameSuffixWithVndkVersion(ctx) - } else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib { - return libName + vendorPublicLibrarySuffix - } else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() { - return libName + ramdiskSuffix - } else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() { - return libName + recoverySuffix - } else if ccDep.Module().Target().NativeBridge == android.NativeBridgeEnabled { - return libName + nativeBridgeSuffix - } else { - return libName + if depPtr != nil { + dep := depFile + if !dep.Valid() { + dep = linkFile + } + *depPtr = append(*depPtr, dep.Path()) } - } - // Export the shared libs to Make. - switch depTag { - case SharedDepTag, sharedExportDepTag, lateSharedDepTag, earlySharedDepTag: - if ccDep.CcLibrary() { - if ccDep.BuildStubs() && android.InAnyApex(depName) { - // Add the dependency to the APEX(es) providing the library so that - // m <module> can trigger building the APEXes as well. - for _, an := range android.GetApexesForModule(depName) { - c.Properties.ApexesProvidingSharedLibs = append( - c.Properties.ApexesProvidingSharedLibs, an) + makeLibName := c.makeLibName(ctx, ccDep, depName) + libDepTag.makeSuffix + switch { + case libDepTag.header(): + c.Properties.AndroidMkHeaderLibs = append( + c.Properties.AndroidMkHeaderLibs, makeLibName) + case libDepTag.shared(): + if ccDep.CcLibrary() { + if ccDep.BuildStubs() && android.InAnyApex(depName) { + // Add the dependency to the APEX(es) providing the library so that + // m <module> can trigger building the APEXes as well. + for _, an := range android.GetApexesForModule(depName) { + c.Properties.ApexesProvidingSharedLibs = append( + c.Properties.ApexesProvidingSharedLibs, an) + } } } - } - // Note: the order of libs in this list is not important because - // they merely serve as Make dependencies and do not affect this lib itself. - c.Properties.AndroidMkSharedLibs = append( - c.Properties.AndroidMkSharedLibs, makeLibName(depName)) - // Record baseLibName for snapshots. - c.Properties.SnapshotSharedLibs = append(c.Properties.SnapshotSharedLibs, baseLibName(depName)) - case ndkStubDepTag, ndkLateStubDepTag: - c.Properties.AndroidMkSharedLibs = append( - c.Properties.AndroidMkSharedLibs, - depName+"."+ccDep.ApiLevel()) - case StaticDepTag, staticExportDepTag, lateStaticDepTag: - c.Properties.AndroidMkStaticLibs = append( - c.Properties.AndroidMkStaticLibs, makeLibName(depName)) - case runtimeDepTag: - c.Properties.AndroidMkRuntimeLibs = append( - c.Properties.AndroidMkRuntimeLibs, makeLibName(depName)) - // Record baseLibName for snapshots. - c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, baseLibName(depName)) - case wholeStaticDepTag: - c.Properties.AndroidMkWholeStaticLibs = append( - c.Properties.AndroidMkWholeStaticLibs, makeLibName(depName)) - case headerDepTag: - c.Properties.AndroidMkHeaderLibs = append( - c.Properties.AndroidMkHeaderLibs, makeLibName(depName)) + // Note: the order of libs in this list is not important because + // 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) + } + } + } else { + switch depTag { + case runtimeDepTag: + c.Properties.AndroidMkRuntimeLibs = append( + c.Properties.AndroidMkRuntimeLibs, c.makeLibName(ctx, ccDep, depName)+libDepTag.makeSuffix) + // Record baseLibName for snapshots. + c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, baseLibName(depName)) + case objDepTag: + depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path()) + case CrtBeginDepTag: + depPaths.CrtBegin = linkFile + case CrtEndDepTag: + depPaths.CrtEnd = linkFile + case dynamicLinkerDepTag: + depPaths.DynamicLinker = linkFile + } } }) @@ -2665,6 +2671,61 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return depPaths } +// baseLibName trims known prefixes and suffixes +func baseLibName(depName string) string { + libName := strings.TrimSuffix(depName, llndkLibrarySuffix) + libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix) + libName = strings.TrimPrefix(libName, "prebuilt_") + return libName +} + +func (c *Module) makeLibName(ctx android.ModuleContext, ccDep LinkableInterface, depName string) string { + vendorSuffixModules := vendorSuffixModules(ctx.Config()) + vendorPublicLibraries := vendorPublicLibraries(ctx.Config()) + + libName := baseLibName(depName) + isLLndk := isLlndkLibrary(libName, ctx.Config()) + isVendorPublicLib := inList(libName, *vendorPublicLibraries) + bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk + + if c, ok := ccDep.(*Module); ok { + // Use base module name for snapshots when exporting to Makefile. + if c.isSnapshotPrebuilt() { + baseName := c.BaseModuleName() + + if c.IsVndk() { + return baseName + ".vendor" + } + + if vendorSuffixModules[baseName] { + return baseName + ".vendor" + } else { + return baseName + } + } + } + + if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && !c.InRamdisk() && !c.InRecovery() { + // The vendor module is a no-vendor-variant VNDK library. Depend on the + // core module instead. + return libName + } else if c.UseVndk() && bothVendorAndCoreVariantsExist { + // The vendor module in Make will have been renamed to not conflict with the core + // module, so update the dependency name here accordingly. + return libName + c.getNameSuffixWithVndkVersion(ctx) + } else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib { + return libName + vendorPublicLibrarySuffix + } else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() { + return libName + ramdiskSuffix + } else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() { + return libName + recoverySuffix + } else if ccDep.Module().Target().NativeBridge == android.NativeBridgeEnabled { + return libName + nativeBridgeSuffix + } else { + return libName + } +} + func (c *Module) InstallInData() bool { if c.installer == nil { return false @@ -2690,12 +2751,12 @@ func (c *Module) InstallInRecovery() bool { return c.InRecovery() } -func (c *Module) SkipInstall() { +func (c *Module) MakeUninstallable() { if c.installer == nil { - c.ModuleBase.SkipInstall() + c.ModuleBase.MakeUninstallable() return } - c.installer.skipInstall(c) + c.installer.makeUninstallable(c) } func (c *Module) HostToolPath() android.OptionalPath { @@ -2835,6 +2896,16 @@ func (c *Module) TestFor() []string { } } +func (c *Module) UniqueApexVariations() bool { + if u, ok := c.compiler.(interface { + uniqueApexVariations() bool + }); ok { + return u.uniqueApexVariations() + } else { + return false + } +} + // Return true if the module is ever installable. func (c *Module) EverInstallable() bool { return c.installer != nil && @@ -2876,26 +2947,28 @@ func (c *Module) AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Write } func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { - if depTag, ok := ctx.OtherModuleDependencyTag(dep).(DependencyTag); ok { - if cc, ok := dep.(*Module); ok { - if cc.HasStubsVariants() { - if depTag.Shared && depTag.Library { - // dynamic dep to a stubs lib crosses APEX boundary - return false - } - if IsRuntimeDepTag(depTag) { - // runtime dep to a stubs lib also crosses APEX boundary - return false - } + depTag := ctx.OtherModuleDependencyTag(dep) + libDepTag, isLibDepTag := depTag.(libraryDependencyTag) + + if cc, ok := dep.(*Module); ok { + if cc.HasStubsVariants() { + if isLibDepTag && libDepTag.shared() { + // dynamic dep to a stubs lib crosses APEX boundary + return false } - if depTag.FromStatic { - // shared_lib dependency from a static lib is considered as crossing - // the APEX boundary because the dependency doesn't actually is - // linked; the dependency is used only during the compilation phase. + if IsRuntimeDepTag(depTag) { + // runtime dep to a stubs lib also crosses APEX boundary return false } } - } else if ctx.OtherModuleDependencyTag(dep) == llndkImplDep { + if isLibDepTag && c.static() && libDepTag.shared() { + // shared_lib dependency from a static lib is considered as crossing + // the APEX boundary because the dependency doesn't actually is + // linked; the dependency is used only during the compilation phase. + return false + } + } + if depTag == llndkImplDep { // We don't track beyond LLNDK return false } @@ -3031,238 +3104,8 @@ func squashRecoverySrcs(m *Module) { } } -var _ android.ImageInterface = (*Module)(nil) - -func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { - // Sanity check - vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific() - productSpecific := mctx.ProductSpecific() - - if m.VendorProperties.Vendor_available != nil && vendorSpecific { - mctx.PropertyErrorf("vendor_available", - "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`") - } - - 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 m.VendorProperties.Vendor_available != nil { - mctx.PropertyErrorf("vendor_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 m.VendorProperties.Vendor_available == nil { - mctx.PropertyErrorf("vndk", - "vendor_available must be set to either true or false when `vndk: {enabled: true}`") - } - } - } 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()) - } - } - } - - var coreVariantNeeded bool = false - var ramdiskVariantNeeded bool = false - var recoveryVariantNeeded bool = false - - var vendorVariants []string - var productVariants []string - - platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion() - boardVndkVersion := mctx.DeviceConfig().VndkVersion() - productVndkVersion := mctx.DeviceConfig().ProductVndkVersion() - if boardVndkVersion == "current" { - boardVndkVersion = platformVndkVersion - } - if productVndkVersion == "current" { - productVndkVersion = platformVndkVersion - } - - if boardVndkVersion == "" { - // If the device isn't compiling against the VNDK, we always - // use the core mode. - coreVariantNeeded = true - } else if _, ok := m.linker.(*llndkStubDecorator); ok { - // LL-NDK stubs only exist in the vendor and product variants, - // since the real libraries will be used in the core variant. - vendorVariants = append(vendorVariants, - platformVndkVersion, - boardVndkVersion, - ) - productVariants = append(productVariants, - platformVndkVersion, - productVndkVersion, - ) - } else if _, ok := m.linker.(*llndkHeadersDecorator); ok { - // ... and LL-NDK headers as well - vendorVariants = append(vendorVariants, - platformVndkVersion, - boardVndkVersion, - ) - productVariants = append(productVariants, - platformVndkVersion, - productVndkVersion, - ) - } else if m.isSnapshotPrebuilt() { - // Make vendor variants only for the versions in BOARD_VNDK_VERSION and - // PRODUCT_EXTRA_VNDK_VERSIONS. - if snapshot, ok := m.linker.(interface { - version() string - }); ok { - vendorVariants = append(vendorVariants, snapshot.version()) - } else { - mctx.ModuleErrorf("version is unknown for snapshot prebuilt") - } - } else if m.HasVendorVariant() && !m.isVndkExt() { - // This will be available in /system, /vendor and /product - // or a /system directory that is available to vendor and product. - coreVariantNeeded = true - - // We assume that modules under proprietary paths are compatible for - // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or - // PLATFORM_VNDK_VERSION. - if isVendorProprietaryPath(mctx.ModuleDir()) { - vendorVariants = append(vendorVariants, boardVndkVersion) - } else { - vendorVariants = append(vendorVariants, platformVndkVersion) - } - - // vendor_available modules are also available to /product. - productVariants = append(productVariants, platformVndkVersion) - // VNDK is always PLATFORM_VNDK_VERSION - if !m.IsVndk() { - productVariants = append(productVariants, productVndkVersion) - } - } else if vendorSpecific && String(m.Properties.Sdk_version) == "" { - // 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 _, ok := m.linker.(*kernelHeadersDecorator); ok { - vendorVariants = append(vendorVariants, - platformVndkVersion, - boardVndkVersion, - ) - } else if isVendorProprietaryPath(mctx.ModuleDir()) { - vendorVariants = append(vendorVariants, boardVndkVersion) - } else { - vendorVariants = append(vendorVariants, platformVndkVersion) - } - } else { - // This is either in /system (or similar: /data), or is a - // modules built with the NDK. Modules built with the NDK - // will be restricted using the existing link type checks. - coreVariantNeeded = true - } - - if boardVndkVersion != "" && productVndkVersion != "" { - if coreVariantNeeded && productSpecific && String(m.Properties.Sdk_version) == "" { - // 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 Bool(m.Properties.Ramdisk_available) { - ramdiskVariantNeeded = true - } - - if m.ModuleBase.InstallInRamdisk() { - ramdiskVariantNeeded = true - coreVariantNeeded = false - } - - if Bool(m.Properties.Recovery_available) { - recoveryVariantNeeded = true - } - - if m.ModuleBase.InstallInRecovery() { - recoveryVariantNeeded = true - coreVariantNeeded = false - } - - for _, variant := range android.FirstUniqueStrings(vendorVariants) { - m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, VendorVariationPrefix+variant) - } - - for _, variant := range android.FirstUniqueStrings(productVariants) { - m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, ProductVariationPrefix+variant) - } - - m.Properties.RamdiskVariantNeeded = ramdiskVariantNeeded - m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded - m.Properties.CoreVariantNeeded = coreVariantNeeded -} - -func (c *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool { - return c.Properties.CoreVariantNeeded -} - -func (c *Module) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { - return c.Properties.RamdiskVariantNeeded -} - -func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { - return c.Properties.RecoveryVariantNeeded -} - -func (c *Module) ExtraImageVariations(ctx android.BaseModuleContext) []string { - return c.Properties.ExtraVariants -} - -func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) { - m := module.(*Module) - if variant == android.RamdiskVariation { - m.MakeAsPlatform() - } 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.SkipInstall() - } - } else if strings.HasPrefix(variant, ProductVariationPrefix) { - m.Properties.ImageVariationPrefix = ProductVariationPrefix - m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix) - squashVendorSrcs(m) - } -} - func (c *Module) IsSdkVariant() bool { - return c.Properties.IsSdkVariant + return c.Properties.IsSdkVariant || c.AlwaysSdk() } func getCurrentNdkPrebuiltVersion(ctx DepsContext) string { diff --git a/cc/cc_test.go b/cc/cc_test.go index 8a1c8ed4c..77b5c527b 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -539,7 +539,7 @@ func TestDataLibs(t *testing.T) { data_libs: ["test_lib"], gtest: false, } - ` + ` config := TestConfig(buildDir, android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") @@ -564,7 +564,7 @@ func TestDataLibs(t *testing.T) { } outputPath := outputFiles[0].String() - testBinaryPath := testBinary.dataPaths()[0].String() + testBinaryPath := testBinary.dataPaths()[0].SrcPath.String() if !strings.HasSuffix(outputPath, "/main_test") { t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath) @@ -576,6 +576,53 @@ func TestDataLibs(t *testing.T) { } } +func TestDataLibsRelativeInstallPath(t *testing.T) { + bp := ` + cc_test_library { + name: "test_lib", + srcs: ["test_lib.cpp"], + relative_install_path: "foo/bar/baz", + gtest: false, + } + + cc_test { + name: "main_test", + data_libs: ["test_lib"], + gtest: false, + } + ` + + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + 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.Fatalf("Expected cc_test to produce output files, error: %s", err) + } + 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()) + } + + outputPath := outputFiles[0].String() + + if !strings.HasSuffix(outputPath, "/main_test") { + t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath) + } + entries := android.AndroidMkEntriesForTest(t, config, "", module)[0] + if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][0], ":test_lib.so:foo/bar/baz") { + t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+ + " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0]) + } +} + func TestVndkWhenVndkVersionIsNotSet(t *testing.T) { ctx := testCcNoVndk(t, ` cc_library { @@ -966,17 +1013,25 @@ func TestVendorSnapshot(t *testing.T) { filepath.Join(sharedDir, "libvendor_available.so.json")) // 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.VER_%s_%s_static", archType, archVariant) + staticCfiVariant := fmt.Sprintf("android_vendor.VER_%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_available.a.json")) + filepath.Join(staticDir, "libvendor.cfi.a.json"), + filepath.Join(staticDir, "libvendor_available.a.json"), + filepath.Join(staticDir, "libvendor_available.cfi.a.json")) // For binary executables, all vendor:true and vendor_available modules are captured. if archType == "arm64" { @@ -1008,6 +1063,39 @@ func TestVendorSnapshot(t *testing.T) { } } +func TestVendorSnapshotSanitizer(t *testing.T) { + bp := ` + vendor_snapshot_static { + name: "libsnapshot", + vendor: true, + target_arch: "arm64", + version: "BOARD", + arch: { + arm64: { + src: "libsnapshot.a", + cfi: { + src: "libsnapshot.cfi.a", + } + }, + }, + } +` + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := testCcWithConfig(t, config) + + // Check non-cfi and cfi variant. + staticVariant := "android_vendor.BOARD_arm64_armv8-a_static" + staticCfiVariant := "android_vendor.BOARD_arm64_armv8-a_static_cfi" + + staticModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticVariant).Module().(*Module) + assertString(t, staticModule.outputFile.Path().Base(), "libsnapshot.a") + + staticCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticCfiVariant).Module().(*Module) + assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a") +} + func TestDoubleLoadableDepError(t *testing.T) { // Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` @@ -2919,6 +3007,52 @@ func TestRecovery(t *testing.T) { } } +func TestDataLibsPrebuiltSharedTestLibrary(t *testing.T) { + bp := ` + cc_prebuilt_test_library_shared { + name: "test_lib", + relative_install_path: "foo/bar/baz", + srcs: ["srcpath/dontusethispath/baz.so"], + } + + cc_test { + name: "main_test", + data_libs: ["test_lib"], + gtest: false, + } + ` + + config := TestConfig(buildDir, android.Android, nil, bp, nil) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + 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.Fatalf("Expected cc_test to produce output files, error: %s", err) + } + 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()) + } + + outputPath := outputFiles[0].String() + + if !strings.HasSuffix(outputPath, "/main_test") { + t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath) + } + entries := android.AndroidMkEntriesForTest(t, config, "", module)[0] + if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][0], ":test_lib.so:foo/bar/baz") { + t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+ + " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0]) + } +} + func TestVersionedStubs(t *testing.T) { ctx := testCc(t, ` cc_library_shared { diff --git a/cc/compiler.go b/cc/compiler.go index d5ea2c3ae..f504c38a2 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -111,6 +111,7 @@ type BaseCompilerProperties struct { Gnu_extensions *bool Yacc *YaccProperties + Lex *LexProperties Aidl struct { // list of directories that will be added to the aidl include paths. @@ -189,8 +190,14 @@ type BaseCompilerProperties struct { // Build and link with OpenMP Openmp *bool `android:"arch_variant"` + // Deprecated. // Adds __ANDROID_APEX_<APEX_MODULE_NAME>__ macro defined for apex variants in addition to __ANDROID_APEX__ Use_apex_name_macro *bool + + // Adds two macros for apex variants in addition to __ANDROID_APEX__ + // * __ANDROID_APEX_COM_ANDROID_FOO__ + // * __ANDROID_APEX_NAME__="com.android.foo" + UseApexNameMacro bool `blueprint:"mutated"` } func NewBaseCompiler() *baseCompiler { @@ -254,6 +261,10 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { return deps } +func (compiler *baseCompiler) useApexNameMacro() bool { + return Bool(compiler.Properties.Use_apex_name_macro) || compiler.Properties.UseApexNameMacro +} + // Return true if the module is in the WarningAllowedProjects. func warningsAreAllowed(subdir string) bool { subdir += "/" @@ -289,6 +300,7 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Local.YasmFlags = append(flags.Local.YasmFlags, esc(compiler.Properties.Asflags)...) flags.Yacc = compiler.Properties.Yacc + flags.Lex = compiler.Properties.Lex // Include dir cflags localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs) @@ -335,10 +347,11 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_RECOVERY__") } - if ctx.apexName() != "" { + if ctx.apexVariationName() != "" { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX__") - if Bool(compiler.Properties.Use_apex_name_macro) { - flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexName())+"__") + if compiler.useApexNameMacro() { + flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexVariationName())+"__") + flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_NAME__='\""+ctx.apexVariationName()+"\"'") } if ctx.Device() { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_SDK_VERSION__="+strconv.Itoa(ctx.apexSdkVersion())) @@ -556,6 +569,10 @@ func (compiler *baseCompiler) hasSrcExt(ext string) bool { return false } +func (compiler *baseCompiler) uniqueApexVariations() bool { + return compiler.useApexNameMacro() +} + // makeDefineString transforms a name of an APEX module into a value to be used as value for C define // For example, com.android.foo => COM_ANDROID_FOO func makeDefineString(name string) string { @@ -565,7 +582,7 @@ func makeDefineString(name string) string { var gnuToCReplacer = strings.NewReplacer("gnu", "c") func ndkPathDeps(ctx ModuleContext) android.Paths { - if ctx.useSdk() { + if ctx.Module().(*Module).IsSdkVariant() { // The NDK sysroot timestamp file depends on all the NDK sysroot files // (headers and libraries). return android.Paths{getNdkBaseTimestampFile(ctx)} diff --git a/cc/config/clang.go b/cc/config/clang.go index 24dc6b932..7db405c2e 100644 --- a/cc/config/clang.go +++ b/cc/config/clang.go @@ -15,6 +15,7 @@ package config import ( + "android/soong/android" "sort" "strings" ) @@ -88,6 +89,12 @@ var ClangUnknownLldflags = sorted([]string{ var ClangLibToolingUnknownCflags = sorted([]string{}) +// List of tidy checks that should be disabled globally. When the compiler is +// updated, some checks enabled by this module may be disabled if they have +// become more strict, or if they are a new match for a wildcard group like +// `modernize-*`. +var ClangTidyDisableChecks = []string{} + func init() { pctx.StaticVariable("ClangExtraCflags", strings.Join([]string{ "-D__compiler_offsetof=__builtin_offsetof", @@ -202,25 +209,34 @@ func init() { } func ClangFilterUnknownCflags(cflags []string) []string { - ret := make([]string, 0, len(cflags)) - for _, f := range cflags { - if !inListSorted(f, ClangUnknownCflags) { - ret = append(ret, f) + result, _ := android.FilterList(cflags, ClangUnknownCflags) + return result +} + +func clangTidyNegateChecks(checks []string) []string { + ret := make([]string, 0, len(checks)) + for _, c := range checks { + if strings.HasPrefix(c, "-") { + ret = append(ret, c) + } else { + ret = append(ret, "-"+c) } } - return ret } -func ClangFilterUnknownLldflags(lldflags []string) []string { - ret := make([]string, 0, len(lldflags)) - for _, f := range lldflags { - if !inListSorted(f, ClangUnknownLldflags) { - ret = append(ret, f) - } - } +func ClangRewriteTidyChecks(checks []string) []string { + checks = append(checks, clangTidyNegateChecks(ClangTidyDisableChecks)...) + // clang-tidy does not allow later arguments to override earlier arguments, + // so if we just disabled an argument that was explicitly enabled we must + // remove the enabling argument from the list. + result, _ := android.FilterList(checks, ClangTidyDisableChecks) + return result +} - return ret +func ClangFilterUnknownLldflags(lldflags []string) []string { + result, _ := android.FilterList(lldflags, ClangUnknownLldflags) + return result } func inListSorted(s string, list []string) bool { diff --git a/cc/config/global.go b/cc/config/global.go index 373fc77f4..32f163d88 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -261,7 +261,9 @@ func init() { pctx.VariableFunc("RECXXPool", remoteexec.EnvOverrideFunc("RBE_CXX_POOL", remoteexec.DefaultPool)) pctx.VariableFunc("RECXXLinksPool", remoteexec.EnvOverrideFunc("RBE_CXX_LINKS_POOL", remoteexec.DefaultPool)) + pctx.VariableFunc("REClangTidyPool", remoteexec.EnvOverrideFunc("RBE_CLANG_TIDY_POOL", remoteexec.DefaultPool)) pctx.VariableFunc("RECXXLinksExecStrategy", remoteexec.EnvOverrideFunc("RBE_CXX_LINKS_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) + pctx.VariableFunc("REClangTidyExecStrategy", remoteexec.EnvOverrideFunc("RBE_CLANG_TIDY_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) pctx.VariableFunc("REAbiDumperExecStrategy", remoteexec.EnvOverrideFunc("RBE_ABI_DUMPER_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) pctx.VariableFunc("REAbiLinkerExecStrategy", remoteexec.EnvOverrideFunc("RBE_ABI_LINKER_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) } diff --git a/cc/config/integer_overflow_blacklist.txt b/cc/config/integer_overflow_blocklist.txt index 3480c3c08..3480c3c08 100644 --- a/cc/config/integer_overflow_blacklist.txt +++ b/cc/config/integer_overflow_blocklist.txt diff --git a/cc/coverage.go b/cc/coverage.go index c8233247f..aa1fdf6c5 100644 --- a/cc/coverage.go +++ b/cc/coverage.go @@ -22,6 +22,8 @@ import ( "android/soong/android" ) +const profileInstrFlag = "-fprofile-instr-generate=/data/misc/trace/clang-%p-%m.profraw" + type CoverageProperties struct { Native_coverage *bool @@ -92,7 +94,7 @@ 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, "-fprofile-instr-generate", "-fcoverage-mapping", "-Wno-pass-failed") + flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag, "-fcoverage-mapping", "-Wno-pass-failed") } } @@ -103,10 +105,14 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags // For static libraries, the only thing that changes our object files // are included whole static libraries, so check to see if any of // those have coverage enabled. - ctx.VisitDirectDepsWithTag(wholeStaticDepTag, func(m android.Module) { - if cc, ok := m.(*Module); ok && cc.coverage != nil { - if cc.coverage.linkCoverage { - cov.linkCoverage = true + 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 && cc.coverage != nil { + if cc.coverage.linkCoverage { + cov.linkCoverage = true + } + } } } }) @@ -139,7 +145,7 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv") } else if clangCoverage { - flags.Local.LdFlags = append(flags.Local.LdFlags, "-fprofile-instr-generate") + flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrFlag) coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module) deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path()) diff --git a/cc/fuzz.go b/cc/fuzz.go index 58c1888ad..529541859 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -402,7 +402,7 @@ func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { command := builder.Command().BuiltTool(ctx, "soong_zip"). Flag("-j"). FlagWithOutput("-o ", corpusZip) - command.FlagWithRspFileInputList("-l ", fuzzModule.corpus) + command.FlagWithRspFileInputList("-r ", fuzzModule.corpus) files = append(files, fileToZip{corpusZip, ""}) } @@ -34,9 +34,9 @@ func init() { var ( lex = pctx.AndroidStaticRule("lex", blueprint.RuleParams{ - Command: "M4=$m4Cmd $lexCmd -o$out $in", + Command: "M4=$m4Cmd $lexCmd $flags -o$out $in", CommandDeps: []string{"$lexCmd", "$m4Cmd"}, - }) + }, "flags") sysprop = pctx.AndroidStaticRule("sysprop", blueprint.RuleParams{ @@ -153,12 +153,23 @@ func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile andr } } -func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath) { +type LexProperties struct { + // list of module-specific flags that will be used for .l and .ll compiles + Flags []string +} + +func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath, props *LexProperties) { + var flags []string + if props != nil { + flags = props.Flags + } + flagsString := strings.Join(flags[:], " ") ctx.Build(pctx, android.BuildParams{ Rule: lex, Description: "lex " + lexFile.Rel(), Output: outFile, Input: lexFile, + Args: map[string]string{"flags": flagsString}, }) } @@ -235,11 +246,11 @@ func genSources(ctx android.ModuleContext, srcFiles android.Paths, case ".l": cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c") srcFiles[i] = cFile - genLex(ctx, srcFile, cFile) + genLex(ctx, srcFile, cFile, buildFlags.lex) case ".ll": cppFile := android.GenPathWithExt(ctx, "lex", srcFile, "cpp") srcFiles[i] = cppFile - genLex(ctx, srcFile, cppFile) + genLex(ctx, srcFile, cppFile, buildFlags.lex) case ".proto": ccFile, headerFile := genProto(ctx, srcFile, buildFlags) srcFiles[i] = ccFile diff --git a/cc/genrule_test.go b/cc/genrule_test.go index d38cf27f0..a366f765c 100644 --- a/cc/genrule_test.go +++ b/cc/genrule_test.go @@ -76,3 +76,42 @@ func TestArchGenruleCmd(t *testing.T) { t.Errorf(`want arm64 inputs %v, got %v`, expected, gen.Inputs.Strings()) } } + +func TestLibraryGenruleCmd(t *testing.T) { + bp := ` + cc_library { + name: "libboth", + } + + cc_library_shared { + name: "libshared", + } + + cc_library_static { + name: "libstatic", + } + + cc_genrule { + name: "gen", + tool_files: ["tool"], + srcs: [ + ":libboth", + ":libshared", + ":libstatic", + ], + cmd: "$(location tool) $(in) $(out)", + out: ["out"], + } + ` + ctx := testCc(t, bp) + + gen := ctx.ModuleForTests("gen", "android_arm_armv7-a-neon").Output("out") + expected := []string{"libboth.so", "libshared.so", "libstatic.a"} + var got []string + for _, input := range gen.Inputs { + got = append(got, input.Base()) + } + if !reflect.DeepEqual(expected, got) { + t.Errorf(`want inputs %v, got %v`, expected, got) + } +} diff --git a/cc/image.go b/cc/image.go new file mode 100644 index 000000000..4daed7c00 --- /dev/null +++ b/cc/image.go @@ -0,0 +1,348 @@ +// 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 image variant related things, including image mutator functions, utility +// functions to determine where a module is installed, etc. + +import ( + "strings" + + "android/soong/android" +) + +var _ android.ImageInterface = (*Module)(nil) + +type imageVariantType string + +const ( + coreImageVariant imageVariantType = "core" + vendorImageVariant imageVariantType = "vendor" + productImageVariant imageVariantType = "product" + ramdiskImageVariant imageVariantType = "ramdisk" + recoveryImageVariant imageVariantType = "recovery" + hostImageVariant imageVariantType = "host" +) + +func (c *Module) getImageVariantType() imageVariantType { + if c.Host() { + return hostImageVariant + } else if c.inVendor() { + return vendorImageVariant + } else if c.inProduct() { + return productImageVariant + } else if c.InRamdisk() { + return ramdiskImageVariant + } else if c.InRecovery() { + return recoveryImageVariant + } else { + return coreImageVariant + } +} + +const ( + // VendorVariationPrefix is the variant prefix used for /vendor code that compiles + // against the VNDK. + VendorVariationPrefix = "vendor." + + // ProductVariationPrefix is the variant prefix used for /product code that compiles + // against the VNDK. + ProductVariationPrefix = "product." +) + +func (ctx *moduleContext) ProductSpecific() bool { + return ctx.ModuleContext.ProductSpecific() || + (ctx.mod.HasVendorVariant() && ctx.mod.inProduct() && !ctx.mod.IsVndk()) +} + +func (ctx *moduleContext) SocSpecific() bool { + return ctx.ModuleContext.SocSpecific() || + (ctx.mod.HasVendorVariant() && ctx.mod.inVendor() && !ctx.mod.IsVndk()) +} + +func (ctx *moduleContextImpl) inProduct() bool { + return ctx.mod.inProduct() +} + +func (ctx *moduleContextImpl) inVendor() bool { + return ctx.mod.inVendor() +} + +func (ctx *moduleContextImpl) inRamdisk() bool { + return ctx.mod.InRamdisk() +} + +func (ctx *moduleContextImpl) inRecovery() bool { + return ctx.mod.InRecovery() +} + +// Returns true only when this module is configured to have core, product and vendor +// variants. +func (c *Module) HasVendorVariant() bool { + return c.IsVndk() || Bool(c.VendorProperties.Vendor_available) +} + +// 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 +} + +// 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 +} + +func (c *Module) InRamdisk() bool { + return c.ModuleBase.InRamdisk() || c.ModuleBase.InstallInRamdisk() +} + +func (c *Module) InRecovery() bool { + return c.ModuleBase.InRecovery() || c.ModuleBase.InstallInRecovery() +} + +func (c *Module) OnlyInRamdisk() bool { + return c.ModuleBase.InstallInRamdisk() +} + +func (c *Module) OnlyInRecovery() bool { + return c.ModuleBase.InstallInRecovery() +} + +func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { + // Validation check + vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific() + productSpecific := mctx.ProductSpecific() + + if m.VendorProperties.Vendor_available != nil && vendorSpecific { + mctx.PropertyErrorf("vendor_available", + "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`") + } + + 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 m.VendorProperties.Vendor_available != nil { + mctx.PropertyErrorf("vendor_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 m.VendorProperties.Vendor_available == nil { + mctx.PropertyErrorf("vndk", + "vendor_available must be set to either true or false when `vndk: {enabled: true}`") + } + } + } 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()) + } + } + } + + var coreVariantNeeded bool = false + var ramdiskVariantNeeded bool = false + var recoveryVariantNeeded bool = false + + var vendorVariants []string + var productVariants []string + + platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion() + boardVndkVersion := mctx.DeviceConfig().VndkVersion() + productVndkVersion := mctx.DeviceConfig().ProductVndkVersion() + if boardVndkVersion == "current" { + boardVndkVersion = platformVndkVersion + } + if productVndkVersion == "current" { + productVndkVersion = platformVndkVersion + } + + if boardVndkVersion == "" { + // If the device isn't compiling against the VNDK, we always + // use the core mode. + coreVariantNeeded = true + } else if _, ok := m.linker.(*llndkStubDecorator); ok { + // LL-NDK stubs only exist in the vendor and product variants, + // since the real libraries will be used in the core variant. + vendorVariants = append(vendorVariants, + platformVndkVersion, + boardVndkVersion, + ) + productVariants = append(productVariants, + platformVndkVersion, + productVndkVersion, + ) + } else if _, ok := m.linker.(*llndkHeadersDecorator); ok { + // ... and LL-NDK headers as well + vendorVariants = append(vendorVariants, + platformVndkVersion, + boardVndkVersion, + ) + productVariants = append(productVariants, + platformVndkVersion, + productVndkVersion, + ) + } else if m.isSnapshotPrebuilt() { + // Make vendor variants only for the versions in BOARD_VNDK_VERSION and + // PRODUCT_EXTRA_VNDK_VERSIONS. + if snapshot, ok := m.linker.(interface { + version() string + }); ok { + vendorVariants = append(vendorVariants, snapshot.version()) + } else { + mctx.ModuleErrorf("version is unknown for snapshot prebuilt") + } + } else if m.HasVendorVariant() && !m.isVndkExt() { + // This will be available in /system, /vendor and /product + // or a /system directory that is available to vendor and product. + coreVariantNeeded = true + + // We assume that modules under proprietary paths are compatible for + // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or + // PLATFORM_VNDK_VERSION. + if isVendorProprietaryPath(mctx.ModuleDir()) { + vendorVariants = append(vendorVariants, boardVndkVersion) + } else { + vendorVariants = append(vendorVariants, platformVndkVersion) + } + + // vendor_available modules are also available to /product. + productVariants = append(productVariants, platformVndkVersion) + // VNDK is always PLATFORM_VNDK_VERSION + if !m.IsVndk() { + productVariants = append(productVariants, productVndkVersion) + } + } else if vendorSpecific && String(m.Properties.Sdk_version) == "" { + // 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 _, ok := m.linker.(*kernelHeadersDecorator); ok { + vendorVariants = append(vendorVariants, + platformVndkVersion, + boardVndkVersion, + ) + } else if isVendorProprietaryPath(mctx.ModuleDir()) { + vendorVariants = append(vendorVariants, boardVndkVersion) + } else { + vendorVariants = append(vendorVariants, platformVndkVersion) + } + } else { + // This is either in /system (or similar: /data), or is a + // modules built with the NDK. Modules built with the NDK + // will be restricted using the existing link type checks. + coreVariantNeeded = true + } + + if boardVndkVersion != "" && productVndkVersion != "" { + if coreVariantNeeded && productSpecific && String(m.Properties.Sdk_version) == "" { + // 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 Bool(m.Properties.Ramdisk_available) { + ramdiskVariantNeeded = true + } + + if m.ModuleBase.InstallInRamdisk() { + ramdiskVariantNeeded = true + coreVariantNeeded = false + } + + if Bool(m.Properties.Recovery_available) { + recoveryVariantNeeded = true + } + + if m.ModuleBase.InstallInRecovery() { + recoveryVariantNeeded = true + coreVariantNeeded = false + } + + for _, variant := range android.FirstUniqueStrings(vendorVariants) { + m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, VendorVariationPrefix+variant) + } + + for _, variant := range android.FirstUniqueStrings(productVariants) { + m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, ProductVariationPrefix+variant) + } + + m.Properties.RamdiskVariantNeeded = ramdiskVariantNeeded + m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded + m.Properties.CoreVariantNeeded = coreVariantNeeded +} + +func (c *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool { + return c.Properties.CoreVariantNeeded +} + +func (c *Module) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { + return c.Properties.RamdiskVariantNeeded +} + +func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { + return c.Properties.RecoveryVariantNeeded +} + +func (c *Module) ExtraImageVariations(ctx android.BaseModuleContext) []string { + return c.Properties.ExtraVariants +} + +func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) { + m := module.(*Module) + if variant == android.RamdiskVariation { + m.MakeAsPlatform() + } 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.SkipInstall() + } + } else if strings.HasPrefix(variant, ProductVariationPrefix) { + m.Properties.ImageVariationPrefix = ProductVariationPrefix + m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix) + squashVendorSrcs(m) + } +} diff --git a/cc/installer.go b/cc/installer.go index 0b4a68cc8..e551c63e2 100644 --- a/cc/installer.go +++ b/cc/installer.go @@ -107,6 +107,6 @@ func (installer *baseInstaller) relativeInstallPath() string { return String(installer.Properties.Relative_install_path) } -func (installer *baseInstaller) skipInstall(mod *Module) { - mod.ModuleBase.SkipInstall() +func (installer *baseInstaller) makeUninstallable(mod *Module) { + mod.ModuleBase.MakeUninstallable() } diff --git a/cc/library.go b/cc/library.go index 98f4d48d6..92853b5d3 100644 --- a/cc/library.go +++ b/cc/library.go @@ -28,7 +28,6 @@ import ( "android/soong/android" "android/soong/cc/config" - "android/soong/genrule" ) type LibraryProperties struct { @@ -337,7 +336,7 @@ type libraryDecorator struct { tocFile android.OptionalPath flagExporter - stripper + stripper Stripper // If we're used as a whole_static_lib, our missing dependencies need // to be given @@ -801,21 +800,8 @@ func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.StaticProperties.Static.Export_static_lib_headers...) } else if library.shared() { if ctx.toolchain().Bionic() && !Bool(library.baseLinker.Properties.Nocrt) { - if !ctx.useSdk() { - deps.CrtBegin = "crtbegin_so" - deps.CrtEnd = "crtend_so" - } else { - // TODO(danalbert): Add generation of crt objects. - // For `sdk_version: "current"`, we don't actually have a - // freshly generated set of CRT objects. Use the last stable - // version. - version := ctx.sdkVersion() - if version == "current" { - version = getCurrentNdkPrebuiltVersion(ctx) - } - deps.CrtBegin = "ndk_crtbegin_so." + version - deps.CrtEnd = "ndk_crtend_so." + version - } + deps.CrtBegin = "crtbegin_so" + deps.CrtEnd = "crtend_so" } deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.SharedProperties.Shared.Whole_static_libs...) deps.StaticLibs = append(deps.StaticLibs, library.SharedProperties.Shared.Static_libs...) @@ -969,13 +955,14 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, library.tocFile = android.OptionalPathForPath(tocFile) TransformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags) - if library.stripper.needsStrip(ctx) { + stripFlags := flagsToStripFlags(flags) + if library.stripper.NeedsStrip(ctx) { if ctx.Darwin() { - builderFlags.stripUseGnuStrip = true + stripFlags.StripUseGnuStrip = true } strippedOutputFile := outputFile outputFile = android.PathForModuleOut(ctx, "unstripped", fileName) - library.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags) + library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, stripFlags) } library.unstrippedOutputFile = outputFile @@ -990,10 +977,10 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName) library.distFile = versionedOutputFile - if library.stripper.needsStrip(ctx) { + if library.stripper.NeedsStrip(ctx) { out := android.PathForModuleOut(ctx, "versioned-stripped", fileName) library.distFile = out - library.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags) + library.stripper.StripExecutableOrSharedLib(ctx, versionedOutputFile, out, stripFlags) } library.injectVersionSymbol(ctx, outputFile, versionedOutputFile) @@ -1041,6 +1028,10 @@ func (library *libraryDecorator) unstrippedOutputFilePath() android.Path { return library.unstrippedOutputFile } +func (library *libraryDecorator) disableStripping() { + library.stripper.StripProperties.Strip.None = BoolPtr(true) +} + func (library *libraryDecorator) nativeCoverage() bool { if library.header() || library.buildStubs() { return false @@ -1365,16 +1356,15 @@ func (library *libraryDecorator) availableFor(what string) bool { return android.CheckAvailableForApex(what, list) } -func (library *libraryDecorator) skipInstall(mod *Module) { +func (library *libraryDecorator) makeUninstallable(mod *Module) { if library.static() && library.buildStatic() && !library.buildStubs() { - // If we're asked to skip installation of a static library (in particular - // when it's not //apex_available:platform) we still want an AndroidMk entry - // for it to ensure we get the relevant NOTICE file targets (cf. - // notice_files.mk) that other libraries might depend on. AndroidMkEntries - // always sets LOCAL_UNINSTALLABLE_MODULE for these entries. + // If we're asked to make a static library uninstallable we don't do + // anything since AndroidMkEntries always sets LOCAL_UNINSTALLABLE_MODULE + // for these entries. This is done to still get the make targets for NOTICE + // files from notice_files.mk, which other libraries might depend on. return } - mod.ModuleBase.SkipInstall() + mod.ModuleBase.MakeUninstallable() } var versioningMacroNamesListKey = android.NewOnceKey("versioningMacroNamesList") @@ -1470,6 +1460,12 @@ func LinkageMutator(mctx android.BottomUpMutatorContext) { static.linker.(prebuiltLibraryInterface).setStatic() shared.linker.(prebuiltLibraryInterface).setShared() + if library.buildShared() { + mctx.AliasVariation("shared") + } else if library.buildStatic() { + mctx.AliasVariation("static") + } + if !library.buildStatic() { static.linker.(prebuiltLibraryInterface).disablePrebuilt() } @@ -1501,18 +1497,22 @@ func LinkageMutator(mctx android.BottomUpMutatorContext) { if _, ok := library.(*Module); ok { reuseStaticLibrary(mctx, static.(*Module), shared.(*Module)) } + mctx.AliasVariation("shared") } else if library.BuildStaticVariant() { variations := append([]string{"static"}, variations...) modules := mctx.CreateLocalVariations(variations...) modules[0].(LinkableInterface).SetStatic() + mctx.AliasVariation("static") } else if library.BuildSharedVariant() { variations := append([]string{"shared"}, variations...) modules := mctx.CreateLocalVariations(variations...) modules[0].(LinkableInterface).SetShared() + mctx.AliasVariation("shared") } else if len(variations) > 0 { mctx.CreateLocalVariations(variations...) + mctx.AliasVariation(variations[0]) } } } @@ -1559,13 +1559,14 @@ func createVersionVariations(mctx android.BottomUpMutatorContext, versions []str // "" is for the non-stubs variant versions = append([]string{""}, versions...) - modules := mctx.CreateVariations(versions...) + modules := mctx.CreateLocalVariations(versions...) for i, m := range modules { if versions[i] != "" { m.(LinkableInterface).SetBuildStubs() m.(LinkableInterface).SetStubsVersions(versions[i]) } } + mctx.AliasVariation("") } func VersionVariantAvailable(module interface { @@ -1600,7 +1601,7 @@ func VersionMutator(mctx android.BottomUpMutatorContext) { if c, ok := library.(*Module); ok && c.IsStubs() { stubsVersionsLock.Lock() defer stubsVersionsLock.Unlock() - // For LLNDK llndk_library, we borrow vstubs.ersions from its implementation library. + // For LLNDK llndk_library, we borrow stubs.versions from its implementation library. // Since llndk_library has dependency to its implementation library, // we can safely access stubsVersionsFor() with its baseModuleName. versions := stubsVersionsFor(mctx.Config())[c.BaseModuleName()] @@ -1611,17 +1612,10 @@ func VersionMutator(mctx android.BottomUpMutatorContext) { return } - mctx.CreateVariations("") + mctx.CreateLocalVariations("") + mctx.AliasVariation("") return } - if genrule, ok := mctx.Module().(*genrule.Module); ok { - if _, ok := genrule.Extra.(*GenruleExtraProperties); ok { - if VersionVariantAvailable(genrule) { - mctx.CreateVariations("") - return - } - } - } } // maybeInjectBoringSSLHash adds a rule to run bssl_inject_hash on the output file if the module has the @@ -1633,8 +1627,7 @@ func maybeInjectBoringSSLHash(ctx android.ModuleContext, outputFile android.Modu // TODO(b/137267623): Remove this in favor of a cc_genrule when they support operating on shared libraries. injectBoringSSLHash := Bool(inject) ctx.VisitDirectDeps(func(dep android.Module) { - tag := ctx.OtherModuleDependencyTag(dep) - if tag == StaticDepTag || tag == staticExportDepTag || tag == wholeStaticDepTag || tag == lateStaticDepTag { + if tag, ok := ctx.OtherModuleDependencyTag(dep).(libraryDependencyTag); ok && tag.static() { if cc, ok := dep.(*Module); ok { if library, ok := cc.linker.(*libraryDecorator); ok { if Bool(library.Properties.Inject_bssl_hash) { diff --git a/cc/library_headers.go b/cc/library_headers.go index b7ab3907c..8b3dbeb8b 100644 --- a/cc/library_headers.go +++ b/cc/library_headers.go @@ -25,8 +25,9 @@ func init() { var headersLibrarySdkMemberType = &librarySdkMemberType{ SdkMemberTypeBase: android.SdkMemberTypeBase{ - PropertyName: "native_header_libs", - SupportsSdk: true, + PropertyName: "native_header_libs", + SupportsSdk: true, + HostOsDependent: true, }, prebuiltModuleType: "cc_prebuilt_library_headers", noOutputFiles: true, diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go index 4b9eb302c..9328a2596 100644 --- a/cc/library_sdk_member.go +++ b/cc/library_sdk_member.go @@ -27,8 +27,9 @@ import ( var sharedLibrarySdkMemberType = &librarySdkMemberType{ SdkMemberTypeBase: android.SdkMemberTypeBase{ - PropertyName: "native_shared_libs", - SupportsSdk: true, + PropertyName: "native_shared_libs", + SupportsSdk: true, + HostOsDependent: true, }, prebuiltModuleType: "cc_prebuilt_library_shared", linkTypes: []string{"shared"}, @@ -36,8 +37,9 @@ var sharedLibrarySdkMemberType = &librarySdkMemberType{ var staticLibrarySdkMemberType = &librarySdkMemberType{ SdkMemberTypeBase: android.SdkMemberTypeBase{ - PropertyName: "native_static_libs", - SupportsSdk: true, + PropertyName: "native_static_libs", + SupportsSdk: true, + HostOsDependent: true, }, prebuiltModuleType: "cc_prebuilt_library_static", linkTypes: []string{"static"}, @@ -45,8 +47,9 @@ var staticLibrarySdkMemberType = &librarySdkMemberType{ var staticAndSharedLibrarySdkMemberType = &librarySdkMemberType{ SdkMemberTypeBase: android.SdkMemberTypeBase{ - PropertyName: "native_libs", - SupportsSdk: true, + PropertyName: "native_libs", + SupportsSdk: true, + HostOsDependent: true, }, prebuiltModuleType: "cc_prebuilt_library", linkTypes: []string{"static", "shared"}, @@ -209,6 +212,11 @@ var includeDirProperties = []includeDirsProperty{ // Add properties that may, or may not, be arch specific. func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) { + if libInfo.SanitizeNever { + sanitizeSet := outputProperties.AddPropertySet("sanitize") + sanitizeSet.AddProperty("never", true) + } + // Copy the generated library to the snapshot and add a reference to it in the .bp module. if libInfo.outputFile != nil { nativeLibraryPath := nativeLibraryPathFor(libInfo) @@ -356,6 +364,9 @@ type nativeLibInfoProperties struct { // not vary by arch so cannot be android specific. StubsVersion string `sdk:"ignored-on-host"` + // Value of SanitizeProperties.Sanitize.Never. Needs to be propagated for CRT objects. + SanitizeNever bool `android:"arch_variant"` + // outputFile is not exported as it is always arch specific. outputFile android.Path } @@ -402,6 +413,10 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte if ccModule.HasStubsVariants() { p.StubsVersion = ccModule.StubsVersion() } + + if ccModule.sanitize != nil && proptools.Bool(ccModule.sanitize.Properties.Sanitize.Never) { + p.SanitizeNever = true + } } func getRequiredMemberOutputFile(ctx android.SdkMemberContext, ccModule *Module) android.Path { diff --git a/cc/linkable.go b/cc/linkable.go index 66b1c3fea..4c8416347 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -1,9 +1,9 @@ package cc import ( - "github.com/google/blueprint" - "android/soong/android" + + "github.com/google/blueprint" ) type LinkableInterface interface { @@ -63,27 +63,16 @@ type LinkableInterface interface { StubDecorator() bool } -type DependencyTag struct { - blueprint.BaseDependencyTag - Name string - Library bool - Shared bool - - ReexportFlags bool - - ExplicitlyVersioned bool - - FromStatic bool -} - var ( - SharedDepTag = DependencyTag{Name: "shared", Library: true, Shared: true} - StaticDepTag = DependencyTag{Name: "static", Library: true} + CrtBeginDepTag = dependencyTag{name: "crtbegin"} + CrtEndDepTag = dependencyTag{name: "crtend"} + CoverageDepTag = dependencyTag{name: "coverage"} +) - // Same as SharedDepTag, but from a static lib - SharedFromStaticDepTag = DependencyTag{Name: "shared from static", Library: true, Shared: true, FromStatic: true} +func SharedDepTag() blueprint.DependencyTag { + return libraryDependencyTag{Kind: sharedLibraryDependency} +} - CrtBeginDepTag = DependencyTag{Name: "crtbegin"} - CrtEndDepTag = DependencyTag{Name: "crtend"} - CoverageDepTag = DependencyTag{Name: "coverage"} -) +func StaticDepTag() blueprint.DependencyTag { + return libraryDependencyTag{Kind: staticLibraryDependency} +} diff --git a/cc/llndk_library.go b/cc/llndk_library.go index 71c92042a..b3f9d6177 100644 --- a/cc/llndk_library.go +++ b/cc/llndk_library.go @@ -179,7 +179,7 @@ func NewLLndkStubLibrary() *Module { library.BuildOnlyShared() module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() stub := &llndkStubDecorator{ libraryDecorator: library, @@ -148,24 +148,31 @@ func ltoDepsMutator(mctx android.TopDownMutatorContext) { mctx.WalkDeps(func(dep android.Module, parent android.Module) bool { tag := mctx.OtherModuleDependencyTag(dep) - switch tag { - case StaticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag: - if dep, ok := dep.(*Module); ok && dep.lto != nil && - !dep.lto.Disabled() { - if full && !Bool(dep.lto.Properties.Lto.Full) { - dep.lto.Properties.FullDep = true - } - if thin && !Bool(dep.lto.Properties.Lto.Thin) { - dep.lto.Properties.ThinDep = true - } + 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 + } + } - // Recursively walk static dependencies - return true + if dep, ok := dep.(*Module); ok && dep.lto != nil && + !dep.lto.Disabled() { + if full && !Bool(dep.lto.Properties.Lto.Full) { + dep.lto.Properties.FullDep = true + } + if thin && !Bool(dep.lto.Properties.Lto.Thin) { + dep.lto.Properties.ThinDep = true + } } - // Do not recurse down non-static dependencies - return false + // Recursively walk static dependencies + return true }) } } diff --git a/cc/makevars.go b/cc/makevars.go index 968eeb5f4..dcfd6d8ef 100644 --- a/cc/makevars.go +++ b/cc/makevars.go @@ -148,8 +148,6 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("AIDL_CPP", "${aidlCmd}") ctx.Strict("ALLOWED_MANUAL_INTERFACE_PATHS", strings.Join(allowedManualInterfacePaths, " ")) - ctx.Strict("M4", "${m4Cmd}") - ctx.Strict("RS_GLOBAL_INCLUDES", "${config.RsGlobalIncludes}") ctx.Strict("SOONG_STRIP_PATH", "${stripPath}") diff --git a/cc/ndk_library.go b/cc/ndk_library.go index 4578fd329..fe3efc01e 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -110,6 +110,10 @@ func intMax(a int, b int) int { func normalizeNdkApiLevel(ctx android.BaseModuleContext, apiLevel string, arch android.Arch) (string, error) { + if apiLevel == "" { + panic("empty apiLevel not allowed") + } + if apiLevel == "current" { return apiLevel, nil } @@ -136,7 +140,8 @@ func normalizeNdkApiLevel(ctx android.BaseModuleContext, apiLevel string, // supported version here instead. version, err := strconv.Atoi(apiLevel) if err != nil { - return "", fmt.Errorf("API level must be an integer (is %q)", apiLevel) + // Non-integer API levels are codenames. + return apiLevel, nil } version = intMax(version, minVersion) @@ -182,40 +187,61 @@ func shouldUseVersionScript(ctx android.BaseModuleContext, stub *stubDecorator) return version >= unversionedUntil, nil } -func generateStubApiVariants(mctx android.BottomUpMutatorContext, c *stubDecorator) { - platformVersion := mctx.Config().PlatformSdkVersionInt() +func generatePerApiVariants(ctx android.BottomUpMutatorContext, m *Module, + propName string, propValue string, perSplit func(*Module, string)) { + platformVersion := ctx.Config().PlatformSdkVersionInt() - firstSupportedVersion, err := normalizeNdkApiLevel(mctx, String(c.properties.First_version), - mctx.Arch()) + firstSupportedVersion, err := normalizeNdkApiLevel(ctx, propValue, + ctx.Arch()) if err != nil { - mctx.PropertyErrorf("first_version", err.Error()) + ctx.PropertyErrorf(propName, err.Error()) } - firstGenVersion, err := getFirstGeneratedVersion(firstSupportedVersion, platformVersion) + firstGenVersion, err := getFirstGeneratedVersion(firstSupportedVersion, + platformVersion) if err != nil { // In theory this is impossible because we've already run this through // normalizeNdkApiLevel above. - mctx.PropertyErrorf("first_version", err.Error()) + ctx.PropertyErrorf(propName, err.Error()) } var versionStrs []string for version := firstGenVersion; version <= platformVersion; version++ { versionStrs = append(versionStrs, strconv.Itoa(version)) } - versionStrs = append(versionStrs, mctx.Config().PlatformVersionActiveCodenames()...) + versionStrs = append(versionStrs, ctx.Config().PlatformVersionActiveCodenames()...) versionStrs = append(versionStrs, "current") - modules := mctx.CreateVariations(versionStrs...) + modules := ctx.CreateVariations(versionStrs...) for i, module := range modules { - module.(*Module).compiler.(*stubDecorator).properties.ApiLevel = versionStrs[i] + perSplit(module.(*Module), versionStrs[i]) } } -func NdkApiMutator(mctx android.BottomUpMutatorContext) { - if m, ok := mctx.Module().(*Module); ok { +func NdkApiMutator(ctx android.BottomUpMutatorContext) { + if m, ok := ctx.Module().(*Module); ok { if m.Enabled() { if compiler, ok := m.compiler.(*stubDecorator); ok { - generateStubApiVariants(mctx, compiler) + if ctx.Os() != android.Android { + // These modules are always android.DeviceEnabled only, but + // those include Fuchsia devices, which we don't support. + ctx.Module().Disable() + return + } + generatePerApiVariants(ctx, m, "first_version", + String(compiler.properties.First_version), + func(m *Module, version string) { + m.compiler.(*stubDecorator).properties.ApiLevel = + version + }) + } else if m.SplitPerApiLevel() && m.IsSdkVariant() { + if ctx.Os() != android.Android { + return + } + generatePerApiVariants(ctx, m, "min_sdk_version", + m.MinSdkVersion(), func(m *Module, version string) { + m.Properties.Sdk_version = &version + }) } } } @@ -379,7 +405,7 @@ func newStubLibrary() *Module { library.BuildOnlyShared() module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() stub := &stubDecorator{ libraryDecorator: library, @@ -396,8 +422,8 @@ func newStubLibrary() *Module { return module } -// ndk_library creates a stub library that exposes dummy implementation -// of functions and variables for use at build time only. +// ndk_library creates a library that exposes a stub implementation of functions +// and variables for use at build time only. func NdkLibraryFactory() android.Module { module := newStubLibrary() android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth) diff --git a/cc/object.go b/cc/object.go index 15a529e85..778d131ba 100644 --- a/cc/object.go +++ b/cc/object.go @@ -55,6 +55,10 @@ type ObjectLinkerProperties struct { // if set, the path to a linker script to pass to ld -r when combining multiple object files. Linker_script *string `android:"path,arch_variant"` + + // Indicates that this module is a CRT object. CRT objects will be split + // into a variant per-API level between min_sdk_version and current. + Crt *bool } func newObject() *Module { @@ -162,3 +166,7 @@ func (object *objectLinker) coverageOutputFilePath() android.OptionalPath { func (object *objectLinker) object() bool { return true } + +func (object *objectLinker) isCrt() bool { + return Bool(object.Properties.Crt) +} @@ -199,8 +199,8 @@ func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool { return false } - // If at least one property exists, validate that all properties exist - if !profileKindPresent || !filePresent || !benchmarksPresent { + // profileKindPresent and filePresent are mandatory properties. + if !profileKindPresent || !filePresent { var missing []string if !profileKindPresent { missing = append(missing, "profile kind (either \"instrumentation\" or \"sampling\" property)") @@ -208,13 +208,15 @@ func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool { if !filePresent { missing = append(missing, "profile_file property") } - if !benchmarksPresent { - missing = append(missing, "non-empty benchmarks 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") + } + if isSampling && isInstrumentation { ctx.PropertyErrorf("pgo", "Exactly one of \"instrumentation\" and \"sampling\" properties must be set") } @@ -288,15 +290,17 @@ func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags { // Add flags to profile this module based on its profile_kind if props.ShouldProfileModule && props.isInstrumentation() { - return props.addInstrumentationProfileGatherFlags(ctx, flags) + props.addInstrumentationProfileGatherFlags(ctx, flags) + // Instrumentation PGO use and gather flags cannot coexist. + return flags } else if props.ShouldProfileModule && props.isSampling() { - return props.addSamplingProfileGatherFlags(ctx, flags) + props.addSamplingProfileGatherFlags(ctx, flags) } else if ctx.DeviceConfig().SamplingPGO() { - return props.addSamplingProfileGatherFlags(ctx, flags) + props.addSamplingProfileGatherFlags(ctx, flags) } if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") { - return props.addProfileUseFlags(ctx, flags) + props.addProfileUseFlags(ctx, flags) } return flags diff --git a/cc/prebuilt.go b/cc/prebuilt.go index 0751f1ca6..3af65d654 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -26,6 +26,7 @@ func RegisterPrebuiltBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("cc_prebuilt_library", PrebuiltLibraryFactory) ctx.RegisterModuleType("cc_prebuilt_library_shared", PrebuiltSharedLibraryFactory) ctx.RegisterModuleType("cc_prebuilt_library_static", PrebuiltStaticLibraryFactory) + ctx.RegisterModuleType("cc_prebuilt_test_library_shared", PrebuiltSharedTestLibraryFactory) ctx.RegisterModuleType("cc_prebuilt_object", prebuiltObjectFactory) ctx.RegisterModuleType("cc_prebuilt_binary", prebuiltBinaryFactory) } @@ -124,9 +125,10 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, outputFile := android.PathForModuleOut(ctx, libName) var implicits android.Paths - if p.needsStrip(ctx) { + if p.stripper.NeedsStrip(ctx) { + stripFlags := flagsToStripFlags(flags) stripped := android.PathForModuleOut(ctx, "stripped", libName) - p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags) in = stripped } @@ -198,10 +200,6 @@ func (p *prebuiltLibraryLinker) disablePrebuilt() { p.properties.Srcs = nil } -func (p *prebuiltLibraryLinker) skipInstall(mod *Module) { - mod.ModuleBase.SkipInstall() -} - func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) { module, library := NewLibrary(hod) module.compiler = nil @@ -210,7 +208,6 @@ func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDec libraryDecorator: library, } module.linker = prebuilt - module.installer = prebuilt module.AddProperties(&prebuilt.properties) @@ -243,6 +240,16 @@ func PrebuiltSharedLibraryFactory() android.Module { return module.Init() } +// cc_prebuilt_test_library_shared installs a precompiled shared library +// to be used as a data dependency of a test-related module (such as cc_test, or +// cc_test_library). +func PrebuiltSharedTestLibraryFactory() android.Module { + module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported) + library.BuildOnlyShared() + library.baseInstaller = NewTestInstaller() + return module.Init() +} + func NewPrebuiltSharedLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) { module, library := NewPrebuiltLibrary(hod) library.BuildOnlyShared() @@ -325,16 +332,16 @@ func (p *prebuiltBinaryLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { // TODO(ccross): verify shared library dependencies if len(p.properties.Srcs) > 0 { - builderFlags := flagsToBuilderFlags(flags) + stripFlags := flagsToStripFlags(flags) fileName := p.getStem(ctx) + flags.Toolchain.ExecutableSuffix() in := p.Prebuilt.SingleSourcePath(ctx) p.unstrippedOutputFile = in - if p.needsStrip(ctx) { + if p.stripper.NeedsStrip(ctx) { stripped := android.PathForModuleOut(ctx, "stripped", fileName) - p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags) in = stripped } @@ -25,8 +25,8 @@ import ( func init() { pctx.VariableFunc("rsCmd", func(ctx android.PackageVarContext) string { - if ctx.Config().UnbundledBuild() { - // Use RenderScript prebuilts for unbundled builds but not PDK builds + if ctx.Config().AlwaysUsePrebuiltSdks() { + // Use RenderScript prebuilts for unbundled builds return filepath.Join("prebuilts/sdk/tools", runtime.GOOS, "bin/llvm-rs-cc") } else { return ctx.Config().HostToolPath(ctx, "llvm-rs-cc").String() diff --git a/cc/sabi.go b/cc/sabi.go index 8cef1700c..ef6beada6 100644 --- a/cc/sabi.go +++ b/cc/sabi.go @@ -83,10 +83,7 @@ func sabiDepsMutator(mctx android.TopDownMutatorContext) { ((c.IsVndk() && c.UseVndk()) || c.isLlndk(mctx.Config()) || (c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) { mctx.VisitDirectDeps(func(m android.Module) { - tag := mctx.OtherModuleDependencyTag(m) - switch tag { - case StaticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag: - + if tag, ok := mctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok && tag.static() { cc, _ := m.(*Module) if cc == nil { return diff --git a/cc/sanitize.go b/cc/sanitize.go index 69563e09e..418671fcd 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -55,17 +55,15 @@ var ( } cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso", - "-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blacklist.txt"} + "-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blocklist.txt"} // -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", "-fsanitize-cfi-cross-dso", "-fsanitize=cfi", "-Wl,-plugin-opt,O1"} - cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map" - cfiStaticLibsMutex sync.Mutex - hwasanStaticLibsMutex sync.Mutex + cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map" - intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blacklist.txt"} + intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blocklist.txt"} minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined", "-fno-sanitize-recover=integer,undefined"} @@ -162,6 +160,9 @@ type SanitizeProperties struct { Scudo *bool `android:"arch_variant"` Scs *bool `android:"arch_variant"` + // A modifier for ASAN and HWASAN for write only instrumentation + Writeonly *bool `android:"arch_variant"` + // Sanitizers to run in the diagnostic mode (as opposed to the release mode). // Replaces abort() on error with a human-readable error message. // Address and Thread sanitizers always run in diagnostic mode. @@ -177,7 +178,7 @@ type SanitizeProperties struct { Recover []string // value to pass to -fsanitize-blacklist - Blacklist *string + Blocklist *string } `android:"arch_variant"` SanitizerEnabled bool `blueprint:"mutated"` @@ -283,6 +284,15 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s.Hwaddress = boolPtr(true) } + if found, globalSanitizers = removeFromList("writeonly", globalSanitizers); found && s.Writeonly == nil { + // Hwaddress and Address are set before, so we can check them here + // If they aren't explicitly set in the blueprint/SANITIZE_(HOST|TARGET), they would be nil instead of false + if s.Address == nil && s.Hwaddress == nil { + ctx.ModuleErrorf("writeonly modifier cannot be used without 'address' or 'hwaddress'") + } + s.Writeonly = boolPtr(true) + } + if len(globalSanitizers) > 0 { ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0]) } @@ -313,14 +323,14 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { // Is CFI actually enabled? if !ctx.Config().EnableCFI() { - s.Cfi = nil - s.Diag.Cfi = nil + s.Cfi = boolPtr(false) + s.Diag.Cfi = boolPtr(false) } // Also disable CFI for arm32 until b/35157333 is fixed. if ctx.Arch().ArchType == android.Arm { - s.Cfi = nil - s.Diag.Cfi = nil + s.Cfi = boolPtr(false) + s.Diag.Cfi = boolPtr(false) } // HWASan requires AArch64 hardware feature (top-byte-ignore). @@ -335,14 +345,14 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { // Also disable CFI if ASAN is enabled. if Bool(s.Address) || Bool(s.Hwaddress) { - s.Cfi = nil - s.Diag.Cfi = nil + s.Cfi = boolPtr(false) + s.Diag.Cfi = boolPtr(false) } // Disable sanitizers that depend on the UBSan runtime for windows/darwin builds. if !ctx.Os().Linux() { - s.Cfi = nil - s.Diag.Cfi = nil + s.Cfi = boolPtr(false) + s.Diag.Cfi = boolPtr(false) s.Misc_undefined = nil s.Undefined = nil s.All_undefined = nil @@ -351,14 +361,15 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { // Also disable CFI for VNDK variants of components if ctx.isVndk() && ctx.useVndk() { - s.Cfi = nil - s.Diag.Cfi = nil - } - - // Also disable CFI if building against snapshot. - vndkVersion := ctx.DeviceConfig().VndkVersion() - if ctx.useVndk() && vndkVersion != "current" && vndkVersion != "" { - s.Cfi = nil + if ctx.static() { + // Cfi variant for static vndk should be captured as vendor snapshot, + // so don't strictly disable Cfi. + s.Cfi = nil + s.Diag.Cfi = nil + } else { + s.Cfi = boolPtr(false) + s.Diag.Cfi = boolPtr(false) + } } // HWASan ramdisk (which is built from recovery) goes over some bootloader limit. @@ -403,7 +414,7 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { // TODO(b/131771163): CFI transiently depends on LTO, and thus Fuzzer is // mutually incompatible. if Bool(s.Fuzzer) { - s.Cfi = nil + s.Cfi = boolPtr(false) } } @@ -460,6 +471,10 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { flags.Local.CFlags = append(flags.Local.CFlags, asanCflags...) flags.Local.LdFlags = append(flags.Local.LdFlags, asanLdflags...) + if Bool(sanitize.Properties.Sanitize.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) @@ -479,6 +494,9 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { if Bool(sanitize.Properties.Sanitize.Hwaddress) { flags.Local.CFlags = append(flags.Local.CFlags, hwasanCflags...) + if Bool(sanitize.Properties.Sanitize.Writeonly) { + flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-hwasan-instrument-reads=0") + } } if Bool(sanitize.Properties.Sanitize.Fuzzer) { @@ -594,10 +612,10 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { strings.Join(sanitize.Properties.Sanitize.Diag.No_recover, ",")) } - blacklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blacklist) - if blacklist.Valid() { - flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-blacklist="+blacklist.String()) - flags.CFlagsDeps = append(flags.CFlagsDeps, blacklist.Path()) + blocklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blocklist) + if blocklist.Valid() { + flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-blacklist="+blocklist.String()) + flags.CFlagsDeps = append(flags.CFlagsDeps, blocklist.Path()) } return flags @@ -710,31 +728,74 @@ func (sanitize *sanitize) isSanitizerEnabled(t sanitizerType) bool { } func isSanitizableDependencyTag(tag blueprint.DependencyTag) bool { - t, ok := tag.(DependencyTag) - return ok && t.Library || t == reuseObjTag || t == objDepTag + switch t := tag.(type) { + case dependencyTag: + return t == reuseObjTag || t == objDepTag + case libraryDependencyTag: + return true + default: + return false + } +} + +// 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.TopDownMutatorContext) bool { + if isVendorProprietaryPath(mctx.ModuleDir()) { + return false + } + + c := mctx.Module().(*Module) + + if !c.inVendor() { + return false + } + + if !c.static() { + return false + } + + if c.Prebuilt() != nil { + return false + } + + return c.sanitize != nil && + !Bool(c.sanitize.Properties.Sanitize.Never) && + !c.sanitize.isSanitizerExplicitlyDisabled(cfi) } // Propagate sanitizer requirements down from binaries func sanitizerDepsMutator(t sanitizerType) func(android.TopDownMutatorContext) { return func(mctx android.TopDownMutatorContext) { - if c, ok := mctx.Module().(*Module); ok && c.sanitize.isSanitizerEnabled(t) { - mctx.WalkDeps(func(child, parent android.Module) bool { - if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) { - return false - } - if d, ok := child.(*Module); ok && d.sanitize != nil && - !Bool(d.sanitize.Properties.Sanitize.Never) && - !d.sanitize.isSanitizerExplicitlyDisabled(t) { - if t == cfi || t == hwasan || t == scs { - if d.static() { + if c, ok := mctx.Module().(*Module); ok { + enabled := c.sanitize.isSanitizerEnabled(t) + if t == cfi && needsCfiForVendorSnapshot(mctx) { + // We shouldn't change the result of isSanitizerEnabled(cfi) to correctly + // determine defaultVariation in sanitizerMutator below. + // Instead, just mark SanitizeDep to forcefully create cfi variant. + enabled = true + c.sanitize.Properties.SanitizeDep = true + } + if enabled { + mctx.WalkDeps(func(child, parent android.Module) bool { + if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) { + return false + } + if d, ok := child.(*Module); ok && d.sanitize != nil && + !Bool(d.sanitize.Properties.Sanitize.Never) && + !d.sanitize.isSanitizerExplicitlyDisabled(t) { + if t == cfi || t == hwasan || t == scs { + if d.static() { + d.sanitize.Properties.SanitizeDep = true + } + } else { d.sanitize.Properties.SanitizeDep = true } - } else { - d.sanitize.Properties.SanitizeDep = true } - } - return true - }) + return true + }) + } } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok { // If an APEX module includes a lib which is enabled for a sanitizer T, then // the APEX module is also enabled for the same sanitizer type. @@ -953,10 +1014,11 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { } // static executable gets static runtime libs + depTag := libraryDependencyTag{Kind: staticLibraryDependency} mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{ {Mutator: "link", Variation: "static"}, c.ImageVariation(), - }...), StaticDepTag, deps...) + }...), depTag, deps...) } else if !c.static() && !c.header() { // If we're using snapshots and in vendor, redirect to snapshot whenever possible if c.VndkVersion() == mctx.DeviceConfig().VndkVersion() { @@ -967,10 +1029,11 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { } // dynamic executable and shared libs get shared runtime libs + depTag := libraryDependencyTag{Kind: sharedLibraryDependency, Order: earlyLibraryDependency} mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{ {Mutator: "link", Variation: "shared"}, c.ImageVariation(), - }...), earlySharedDepTag, runtimeLibrary) + }...), depTag, runtimeLibrary) } // static lib does not have dependency to the runtime library. The // dependency will be added to the executables or shared libs using @@ -1038,15 +1101,9 @@ func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) { // Export the static lib name to make if c.static() && c.ExportedToMake() { if t == cfi { - appendStringSync(c.Name(), cfiStaticLibs(mctx.Config()), &cfiStaticLibsMutex) + cfiStaticLibs(mctx.Config()).add(c, c.Name()) } else if t == hwasan { - if c.UseVndk() { - appendStringSync(c.Name(), hwasanVendorStaticLibs(mctx.Config()), - &hwasanStaticLibsMutex) - } else { - appendStringSync(c.Name(), hwasanStaticLibs(mctx.Config()), - &hwasanStaticLibsMutex) - } + hwasanStaticLibs(mctx.Config()).add(c, c.Name()) } } } else { @@ -1072,38 +1129,96 @@ func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) { // APEX modules fall here sanitizeable.AddSanitizerDependencies(mctx, t.name()) mctx.CreateVariations(t.variationName()) + } else if c, ok := mctx.Module().(*Module); ok { + // Check if it's a snapshot module supporting sanitizer + if s, ok := c.linker.(snapshotSanitizer); ok && s.isSanitizerEnabled(t) { + // Set default variation as above. + defaultVariation := t.variationName() + mctx.SetDefaultDependencyVariation(&defaultVariation) + modules := mctx.CreateVariations("", t.variationName()) + modules[0].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, false) + modules[1].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, true) + + // Export the static lib name to make + if c.static() && c.ExportedToMake() { + if t == cfi { + // use BaseModuleName which is the name for Make. + cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName()) + } + } + } } } } -var cfiStaticLibsKey = android.NewOnceKey("cfiStaticLibs") +type sanitizerStaticLibsMap struct { + // libsMap contains one list of modules per each image and each arch. + // e.g. libs[vendor]["arm"] contains arm modules installed to vendor + libsMap map[imageVariantType]map[string][]string + libsMapLock sync.Mutex + sanitizerType sanitizerType +} -func cfiStaticLibs(config android.Config) *[]string { - return config.Once(cfiStaticLibsKey, func() interface{} { - return &[]string{} - }).(*[]string) +func newSanitizerStaticLibsMap(t sanitizerType) *sanitizerStaticLibsMap { + return &sanitizerStaticLibsMap{ + sanitizerType: t, + libsMap: make(map[imageVariantType]map[string][]string), + } } -var hwasanStaticLibsKey = android.NewOnceKey("hwasanStaticLibs") +// Add the current module to sanitizer static libs maps +// Each module should pass its exported name as names of Make and Soong can differ. +func (s *sanitizerStaticLibsMap) add(c *Module, name string) { + image := c.getImageVariantType() + arch := c.Arch().ArchType.String() -func hwasanStaticLibs(config android.Config) *[]string { - return config.Once(hwasanStaticLibsKey, func() interface{} { - return &[]string{} - }).(*[]string) + s.libsMapLock.Lock() + defer s.libsMapLock.Unlock() + + if _, ok := s.libsMap[image]; !ok { + s.libsMap[image] = make(map[string][]string) + } + + s.libsMap[image][arch] = append(s.libsMap[image][arch], name) } -var hwasanVendorStaticLibsKey = android.NewOnceKey("hwasanVendorStaticLibs") +// Exports makefile variables in the following format: +// SOONG_{sanitizer}_{image}_{arch}_STATIC_LIBRARIES +// e.g. SOONG_cfi_core_x86_STATIC_LIBRARIES +// These are to be used by use_soong_sanitized_static_libraries. +// See build/make/core/binary.mk for more details. +func (s *sanitizerStaticLibsMap) exportToMake(ctx android.MakeVarsContext) { + for _, image := range android.SortedStringKeys(s.libsMap) { + archMap := s.libsMap[imageVariantType(image)] + for _, arch := range android.SortedStringKeys(archMap) { + libs := archMap[arch] + sort.Strings(libs) + + key := fmt.Sprintf( + "SOONG_%s_%s_%s_STATIC_LIBRARIES", + s.sanitizerType.variationName(), + image, // already upper + arch) + + ctx.Strict(key, strings.Join(libs, " ")) + } + } +} -func hwasanVendorStaticLibs(config android.Config) *[]string { - return config.Once(hwasanVendorStaticLibsKey, func() interface{} { - return &[]string{} - }).(*[]string) +var cfiStaticLibsKey = android.NewOnceKey("cfiStaticLibs") + +func cfiStaticLibs(config android.Config) *sanitizerStaticLibsMap { + return config.Once(cfiStaticLibsKey, func() interface{} { + return newSanitizerStaticLibsMap(cfi) + }).(*sanitizerStaticLibsMap) } -func appendStringSync(item string, list *[]string, mutex *sync.Mutex) { - mutex.Lock() - *list = append(*list, item) - mutex.Unlock() +var hwasanStaticLibsKey = android.NewOnceKey("hwasanStaticLibs") + +func hwasanStaticLibs(config android.Config) *sanitizerStaticLibsMap { + return config.Once(hwasanStaticLibsKey, func() interface{} { + return newSanitizerStaticLibsMap(hwasan) + }).(*sanitizerStaticLibsMap) } func enableMinimalRuntime(sanitize *sanitize) bool { @@ -1133,17 +1248,9 @@ func enableUbsanRuntime(sanitize *sanitize) bool { } func cfiMakeVarsProvider(ctx android.MakeVarsContext) { - cfiStaticLibs := cfiStaticLibs(ctx.Config()) - sort.Strings(*cfiStaticLibs) - ctx.Strict("SOONG_CFI_STATIC_LIBRARIES", strings.Join(*cfiStaticLibs, " ")) + cfiStaticLibs(ctx.Config()).exportToMake(ctx) } func hwasanMakeVarsProvider(ctx android.MakeVarsContext) { - hwasanStaticLibs := hwasanStaticLibs(ctx.Config()) - sort.Strings(*hwasanStaticLibs) - ctx.Strict("SOONG_HWASAN_STATIC_LIBRARIES", strings.Join(*hwasanStaticLibs, " ")) - - hwasanVendorStaticLibs := hwasanVendorStaticLibs(ctx.Config()) - sort.Strings(*hwasanVendorStaticLibs) - ctx.Strict("SOONG_HWASAN_VENDOR_STATIC_LIBRARIES", strings.Join(*hwasanVendorStaticLibs, " ")) + hwasanStaticLibs(ctx.Config()).exportToMake(ctx) } diff --git a/cc/strip.go b/cc/strip.go index 7e560ec9c..18150dc8d 100644 --- a/cc/strip.go +++ b/cc/strip.go @@ -30,42 +30,42 @@ type StripProperties struct { } `android:"arch_variant"` } -type stripper struct { +type Stripper struct { StripProperties StripProperties } -func (stripper *stripper) needsStrip(ctx ModuleContext) bool { +func (stripper *Stripper) NeedsStrip(actx android.ModuleContext) bool { // TODO(ccross): enable host stripping when embedded in make? Make never had support for stripping host binaries. - return (!ctx.Config().EmbeddedInMake() || ctx.Device()) && !Bool(stripper.StripProperties.Strip.None) + return (!actx.Config().EmbeddedInMake() || actx.Device()) && !Bool(stripper.StripProperties.Strip.None) } -func (stripper *stripper) strip(ctx ModuleContext, in android.Path, out android.ModuleOutPath, - flags builderFlags, isStaticLib bool) { - if ctx.Darwin() { - TransformDarwinStrip(ctx, in, out) +func (stripper *Stripper) strip(actx android.ModuleContext, in android.Path, out android.ModuleOutPath, + flags StripFlags, isStaticLib bool) { + if actx.Darwin() { + TransformDarwinStrip(actx, in, out) } else { if Bool(stripper.StripProperties.Strip.Keep_symbols) { - flags.stripKeepSymbols = true + flags.StripKeepSymbols = true } else if Bool(stripper.StripProperties.Strip.Keep_symbols_and_debug_frame) { - flags.stripKeepSymbolsAndDebugFrame = true + flags.StripKeepSymbolsAndDebugFrame = true } else if len(stripper.StripProperties.Strip.Keep_symbols_list) > 0 { - flags.stripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",") + flags.StripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",") } else if !Bool(stripper.StripProperties.Strip.All) { - flags.stripKeepMiniDebugInfo = true + flags.StripKeepMiniDebugInfo = true } - if ctx.Config().Debuggable() && !flags.stripKeepMiniDebugInfo && !isStaticLib { - flags.stripAddGnuDebuglink = true + if actx.Config().Debuggable() && !flags.StripKeepMiniDebugInfo && !isStaticLib { + flags.StripAddGnuDebuglink = true } - TransformStrip(ctx, in, out, flags) + TransformStrip(actx, in, out, flags) } } -func (stripper *stripper) stripExecutableOrSharedLib(ctx ModuleContext, in android.Path, - out android.ModuleOutPath, flags builderFlags) { - stripper.strip(ctx, in, out, flags, false) +func (stripper *Stripper) StripExecutableOrSharedLib(actx android.ModuleContext, in android.Path, + out android.ModuleOutPath, flags StripFlags) { + stripper.strip(actx, in, out, flags, false) } -func (stripper *stripper) stripStaticLib(ctx ModuleContext, in android.Path, out android.ModuleOutPath, - flags builderFlags) { - stripper.strip(ctx, in, out, flags, true) +func (stripper *Stripper) StripStaticLib(actx android.ModuleContext, in android.Path, out android.ModuleOutPath, + flags StripFlags) { + stripper.strip(actx, in, out, flags, true) } diff --git a/cc/test.go b/cc/test.go index 37afb0ca4..a8056479f 100644 --- a/cc/test.go +++ b/cc/test.go @@ -40,8 +40,12 @@ type TestProperties struct { type TestOptions struct { // The UID that you want to run the test as on a device. Run_test_as *string + // A list of free-formed strings without spaces that categorize the test. Test_suite_tag []string + + // a list of extra test configuration files that should be installed with the module. + Extra_test_configs []string `android:"path,arch_variant"` } type TestBinaryProperties struct { @@ -165,7 +169,7 @@ func (test *testBinary) srcs() []string { return test.baseCompiler.Properties.Srcs } -func (test *testBinary) dataPaths() android.Paths { +func (test *testBinary) dataPaths() []android.DataPath { return test.data } @@ -309,9 +313,10 @@ type testBinary struct { testDecorator *binaryDecorator *baseCompiler - Properties TestBinaryProperties - data android.Paths - testConfig android.Path + Properties TestBinaryProperties + data []android.DataPath + testConfig android.Path + extraTestConfigs android.Paths } func (test *testBinary) linkerProps() []interface{} { @@ -339,7 +344,11 @@ func (test *testBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { } func (test *testBinary) install(ctx ModuleContext, file android.Path) { - test.data = android.PathsForModuleSrc(ctx, test.Properties.Data) + dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data) + + for _, dataSrcPath := range dataSrcPaths { + test.data = append(test.data, android.DataPath{SrcPath: dataSrcPath}) + } ctx.VisitDirectDepsWithTag(dataLibDepTag, func(dep android.Module) { depName := ctx.OtherModuleName(dep) @@ -348,10 +357,14 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { if !ok { ctx.ModuleErrorf("data_lib %q is not a linkable cc module", depName) } + ccModule, ok := dep.(*Module) + if !ok { + ctx.ModuleErrorf("data_lib %q is not a cc module", depName) + } if ccDep.OutputFile().Valid() { - test.data = append(test.data, ccDep.OutputFile().Path()) - } else { - ctx.ModuleErrorf("data_lib %q has no output file", depName) + test.data = append(test.data, + android.DataPath{SrcPath: ccDep.OutputFile().Path(), + RelativeInstallPath: ccModule.installer.relativeInstallPath()}) } }) @@ -400,6 +413,8 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config, test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config) + test.extraTestConfigs = android.PathsForModuleSrc(ctx, test.Properties.Test_options.Extra_test_configs) + test.binaryDecorator.baseInstaller.dir = "nativetest" test.binaryDecorator.baseInstaller.dir64 = "nativetest64" diff --git a/cc/testing.go b/cc/testing.go index 4d0b28b7f..06e5f832c 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -20,8 +20,6 @@ import ( func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { RegisterPrebuiltBuildComponents(ctx) - android.RegisterPrebuiltMutators(ctx) - RegisterCCBuildComponents(ctx) RegisterBinaryBuildComponents(ctx) RegisterLibraryBuildComponents(ctx) @@ -340,6 +338,8 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { vendor_available: true, native_bridge_supported: true, stl: "none", + min_sdk_version: "16", + crt: true, apex_available: [ "//apex_available:platform", "//apex_available:anyapex", @@ -349,48 +349,26 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { cc_object { name: "crtbegin_so", defaults: ["crt_defaults"], - recovery_available: true, - vendor_available: true, - native_bridge_supported: true, - min_sdk_version: "29", - stl: "none", } cc_object { name: "crtbegin_dynamic", defaults: ["crt_defaults"], - recovery_available: true, - vendor_available: true, - native_bridge_supported: true, - stl: "none", } cc_object { name: "crtbegin_static", defaults: ["crt_defaults"], - recovery_available: true, - vendor_available: true, - native_bridge_supported: true, - stl: "none", } cc_object { name: "crtend_so", defaults: ["crt_defaults"], - recovery_available: true, - vendor_available: true, - native_bridge_supported: true, - min_sdk_version: "29", - stl: "none", } cc_object { name: "crtend_android", defaults: ["crt_defaults"], - recovery_available: true, - vendor_available: true, - native_bridge_supported: true, - stl: "none", } cc_library { @@ -422,26 +400,6 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { symbol_file: "libdl.map.txt", } - ndk_prebuilt_object { - name: "ndk_crtbegin_so.27", - sdk_version: "27", - } - - ndk_prebuilt_object { - name: "ndk_crtend_so.27", - sdk_version: "27", - } - - ndk_prebuilt_object { - name: "ndk_crtbegin_dynamic.27", - sdk_version: "27", - } - - ndk_prebuilt_object { - name: "ndk_crtend_android.27", - sdk_version: "27", - } - ndk_prebuilt_shared_stl { name: "ndk_libc++_shared", } @@ -569,7 +527,9 @@ func CreateTestContext() *android.TestContext { ctx.RegisterModuleType("filegroup", android.FileGroupFactory) ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory) ctx.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory) + ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) + android.RegisterPrebuiltMutators(ctx) RegisterRequiredBuildComponentsForTest(ctx) ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton) ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton) diff --git a/cc/tidy.go b/cc/tidy.go index 364e56c5d..17471e674 100644 --- a/cc/tidy.go +++ b/cc/tidy.go @@ -109,7 +109,8 @@ func (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags { tidyChecks += config.TidyChecksForDir(ctx.ModuleDir()) } if len(tidy.Properties.Tidy_checks) > 0 { - tidyChecks = tidyChecks + "," + strings.Join(esc(tidy.Properties.Tidy_checks), ",") + tidyChecks = tidyChecks + "," + strings.Join(esc( + config.ClangRewriteTidyChecks(tidy.Properties.Tidy_checks)), ",") } if ctx.Windows() { // https://b.corp.google.com/issues/120614316 diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go index 042e012d9..19f5ea4f7 100644 --- a/cc/toolchain_library.go +++ b/cc/toolchain_library.go @@ -36,8 +36,7 @@ type toolchainLibraryProperties struct { type toolchainLibraryDecorator struct { *libraryDecorator - - stripper + stripper Stripper Properties toolchainLibraryProperties } @@ -89,8 +88,8 @@ func (library *toolchainLibraryDecorator) link(ctx ModuleContext, if library.stripper.StripProperties.Strip.Keep_symbols_list != nil { fileName := ctx.ModuleName() + staticLibraryExtension outputFile := android.PathForModuleOut(ctx, fileName) - buildFlags := flagsToBuilderFlags(flags) - library.stripper.stripStaticLib(ctx, srcPath, outputFile, buildFlags) + stripFlags := flagsToStripFlags(flags) + library.stripper.StripStaticLib(ctx, srcPath, outputFile, stripFlags) return outputFile } diff --git a/cc/util.go b/cc/util.go index af26268e2..40374bff7 100644 --- a/cc/util.go +++ b/cc/util.go @@ -97,9 +97,14 @@ func flagsToBuilderFlags(in Flags) builderFlags { protoOptionsFile: in.protoOptionsFile, yacc: in.Yacc, + lex: in.Lex, } } +func flagsToStripFlags(in Flags) StripFlags { + return StripFlags{Toolchain: in.Toolchain} +} + func addPrefix(list []string, prefix string) []string { for i := range list { list[i] = prefix + list[i] diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go index e9d1c7378..85f514c83 100644 --- a/cc/vendor_public_library.go +++ b/cc/vendor_public_library.go @@ -144,7 +144,7 @@ func vendorPublicLibraryFactory() android.Module { library.BuildOnlyShared() module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() stub := &vendorPublicLibraryStubDecorator{ libraryDecorator: library, diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index fec0c8bb6..93aece4fc 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -80,64 +80,98 @@ func vendorSnapshotObjects(config android.Config) *snapshotMap { }).(*snapshotMap) } -type vendorSnapshotLibraryProperties struct { +type vendorSnapshotBaseProperties struct { // snapshot version. Version string // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64') Target_arch string - - // Prebuilt file for each arch. - Src *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"` - - // Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined symbols, - // etc). - Check_elf_files *bool - - // 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 vendorSnapshotLibraryDecorator struct { - *libraryDecorator - properties vendorSnapshotLibraryProperties - androidMkVendorSuffix bool +// vendorSnapshotModuleBase provides common basic functions for all snapshot modules. +type vendorSnapshotModuleBase struct { + baseProperties vendorSnapshotBaseProperties + moduleSuffix string } -func (p *vendorSnapshotLibraryDecorator) Name(name string) string { +func (p *vendorSnapshotModuleBase) Name(name string) string { return name + p.NameSuffix() } -func (p *vendorSnapshotLibraryDecorator) NameSuffix() string { +func (p *vendorSnapshotModuleBase) NameSuffix() string { versionSuffix := p.version() if p.arch() != "" { versionSuffix += "." + p.arch() } - var linkageSuffix string - if p.buildShared() { - linkageSuffix = vendorSnapshotSharedSuffix - } else if p.buildStatic() { - linkageSuffix = vendorSnapshotStaticSuffix - } else { - linkageSuffix = vendorSnapshotHeaderSuffix + return p.moduleSuffix + versionSuffix +} + +func (p *vendorSnapshotModuleBase) version() string { + return p.baseProperties.Version +} + +func (p *vendorSnapshotModuleBase) arch() string { + return p.baseProperties.Target_arch +} + +func (p *vendorSnapshotModuleBase) isSnapshotPrebuilt() bool { + return true +} + +// Call this after creating a snapshot module with module suffix +// such as vendorSnapshotSharedSuffix +func (p *vendorSnapshotModuleBase) init(m *Module, suffix string) { + p.moduleSuffix = suffix + m.AddProperties(&p.baseProperties) + android.AddLoadHook(m, func(ctx android.LoadHookContext) { + vendorSnapshotLoadHook(ctx, p) + }) +} + +func vendorSnapshotLoadHook(ctx android.LoadHookContext, p *vendorSnapshotModuleBase) { + if p.version() != ctx.DeviceConfig().VndkVersion() { + ctx.Module().Disable() + return } +} + +type vendorSnapshotLibraryProperties 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"` - return linkageSuffix + versionSuffix + // Whether this prebuilt needs to depend on sanitize minimal runtime or not. + Sanitize_minimal_dep *bool `android:"arch_variant"` } -func (p *vendorSnapshotLibraryDecorator) version() string { - return p.properties.Version +type snapshotSanitizer interface { + isSanitizerEnabled(t sanitizerType) bool + setSanitizerVariation(t sanitizerType, enabled bool) } -func (p *vendorSnapshotLibraryDecorator) arch() string { - return p.properties.Target_arch +type vendorSnapshotLibraryDecorator struct { + vendorSnapshotModuleBase + *libraryDecorator + properties vendorSnapshotLibraryProperties + sanitizerProperties struct { + CfiEnabled bool `blueprint:"mutated"` + + // Library flags for cfi variant. + Cfi vendorSnapshotLibraryProperties `android:"arch_variant"` + } + androidMkVendorSuffix bool } func (p *vendorSnapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { @@ -165,11 +199,16 @@ func (p *vendorSnapshotLibraryDecorator) link(ctx ModuleContext, return p.libraryDecorator.link(ctx, flags, deps, objs) } + if p.sanitizerProperties.CfiEnabled { + p.properties = p.sanitizerProperties.Cfi + } + if !p.matchesWithDevice(ctx.DeviceConfig()) { return nil } - p.libraryDecorator.exportIncludes(ctx) + 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...) in := android.PathForModuleSrc(ctx, *p.properties.Src) @@ -189,37 +228,43 @@ func (p *vendorSnapshotLibraryDecorator) link(ctx ModuleContext, return in } -func (p *vendorSnapshotLibraryDecorator) nativeCoverage() bool { - return false -} - -func (p *vendorSnapshotLibraryDecorator) isSnapshotPrebuilt() bool { - return true -} - func (p *vendorSnapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) { if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) { p.baseInstaller.install(ctx, file) } } -type vendorSnapshotInterface interface { - version() string +func (p *vendorSnapshotLibraryDecorator) nativeCoverage() bool { + return false } -func vendorSnapshotLoadHook(ctx android.LoadHookContext, p vendorSnapshotInterface) { - if p.version() != ctx.DeviceConfig().VndkVersion() { - ctx.Module().Disable() +func (p *vendorSnapshotLibraryDecorator) isSanitizerEnabled(t sanitizerType) bool { + switch t { + case cfi: + return p.sanitizerProperties.Cfi.Src != nil + default: + return false + } +} + +func (p *vendorSnapshotLibraryDecorator) setSanitizerVariation(t sanitizerType, enabled bool) { + if !enabled { + return + } + switch t { + case cfi: + p.sanitizerProperties.CfiEnabled = true + default: return } } -func vendorSnapshotLibrary() (*Module, *vendorSnapshotLibraryDecorator) { +func vendorSnapshotLibrary(suffix string) (*Module, *vendorSnapshotLibraryDecorator) { module, library := NewLibrary(android.DeviceSupported) module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() prebuilt := &vendorSnapshotLibraryDecorator{ libraryDecorator: library, @@ -237,77 +282,47 @@ func vendorSnapshotLibrary() (*Module, *vendorSnapshotLibraryDecorator) { module.linker = prebuilt module.installer = prebuilt + prebuilt.init(module, suffix) module.AddProperties( &prebuilt.properties, + &prebuilt.sanitizerProperties, ) return module, prebuilt } func VendorSnapshotSharedFactory() android.Module { - module, prebuilt := vendorSnapshotLibrary() + module, prebuilt := vendorSnapshotLibrary(vendorSnapshotSharedSuffix) prebuilt.libraryDecorator.BuildOnlyShared() - android.AddLoadHook(module, func(ctx android.LoadHookContext) { - vendorSnapshotLoadHook(ctx, prebuilt) - }) return module.Init() } func VendorSnapshotStaticFactory() android.Module { - module, prebuilt := vendorSnapshotLibrary() + module, prebuilt := vendorSnapshotLibrary(vendorSnapshotStaticSuffix) prebuilt.libraryDecorator.BuildOnlyStatic() - android.AddLoadHook(module, func(ctx android.LoadHookContext) { - vendorSnapshotLoadHook(ctx, prebuilt) - }) return module.Init() } func VendorSnapshotHeaderFactory() android.Module { - module, prebuilt := vendorSnapshotLibrary() + module, prebuilt := vendorSnapshotLibrary(vendorSnapshotHeaderSuffix) prebuilt.libraryDecorator.HeaderOnly() - android.AddLoadHook(module, func(ctx android.LoadHookContext) { - vendorSnapshotLoadHook(ctx, prebuilt) - }) return module.Init() } -type vendorSnapshotBinaryProperties struct { - // snapshot version. - Version string - - // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab') - Target_arch string +var _ snapshotSanitizer = (*vendorSnapshotLibraryDecorator)(nil) +type vendorSnapshotBinaryProperties struct { // Prebuilt file for each arch. Src *string `android:"arch_variant"` } type vendorSnapshotBinaryDecorator struct { + vendorSnapshotModuleBase *binaryDecorator properties vendorSnapshotBinaryProperties androidMkVendorSuffix bool } -func (p *vendorSnapshotBinaryDecorator) Name(name string) string { - return name + p.NameSuffix() -} - -func (p *vendorSnapshotBinaryDecorator) NameSuffix() string { - versionSuffix := p.version() - if p.arch() != "" { - versionSuffix += "." + p.arch() - } - return vendorSnapshotBinarySuffix + versionSuffix -} - -func (p *vendorSnapshotBinaryDecorator) version() string { - return p.properties.Version -} - -func (p *vendorSnapshotBinaryDecorator) arch() string { - return p.properties.Target_arch -} - func (p *vendorSnapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool { if config.DeviceArch() != p.arch() { return false @@ -325,12 +340,12 @@ func (p *vendorSnapshotBinaryDecorator) link(ctx ModuleContext, } in := android.PathForModuleSrc(ctx, *p.properties.Src) - builderFlags := flagsToBuilderFlags(flags) + stripFlags := flagsToStripFlags(flags) p.unstrippedOutputFile = in binName := in.Base() - if p.needsStrip(ctx) { + if p.stripper.NeedsStrip(ctx) { stripped := android.PathForModuleOut(ctx, "stripped", binName) - p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags) in = stripped } @@ -349,8 +364,8 @@ func (p *vendorSnapshotBinaryDecorator) link(ctx ModuleContext, return outputFile } -func (p *vendorSnapshotBinaryDecorator) isSnapshotPrebuilt() bool { - return true +func (p *vendorSnapshotBinaryDecorator) nativeCoverage() bool { + return false } func VendorSnapshotBinaryFactory() android.Module { @@ -372,51 +387,23 @@ func VendorSnapshotBinaryFactory() android.Module { module.stl = nil module.linker = prebuilt - android.AddLoadHook(module, func(ctx android.LoadHookContext) { - vendorSnapshotLoadHook(ctx, prebuilt) - }) - + prebuilt.init(module, vendorSnapshotBinarySuffix) module.AddProperties(&prebuilt.properties) return module.Init() } type vendorSnapshotObjectProperties struct { - // snapshot version. - Version string - - // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab') - Target_arch string - // Prebuilt file for each arch. Src *string `android:"arch_variant"` } type vendorSnapshotObjectLinker struct { + vendorSnapshotModuleBase objectLinker properties vendorSnapshotObjectProperties androidMkVendorSuffix bool } -func (p *vendorSnapshotObjectLinker) Name(name string) string { - return name + p.NameSuffix() -} - -func (p *vendorSnapshotObjectLinker) NameSuffix() string { - versionSuffix := p.version() - if p.arch() != "" { - versionSuffix += "." + p.arch() - } - return vendorSnapshotObjectSuffix + versionSuffix -} - -func (p *vendorSnapshotObjectLinker) version() string { - return p.properties.Version -} - -func (p *vendorSnapshotObjectLinker) arch() string { - return p.properties.Target_arch -} - func (p *vendorSnapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool { if config.DeviceArch() != p.arch() { return false @@ -443,10 +430,6 @@ func (p *vendorSnapshotObjectLinker) nativeCoverage() bool { return false } -func (p *vendorSnapshotObjectLinker) isSnapshotPrebuilt() bool { - return true -} - func VendorSnapshotObjectFactory() android.Module { module := newObject() @@ -457,10 +440,7 @@ func VendorSnapshotObjectFactory() android.Module { } module.linker = prebuilt - android.AddLoadHook(module, func(ctx android.LoadHookContext) { - vendorSnapshotLoadHook(ctx, prebuilt) - }) - + prebuilt.init(module, vendorSnapshotObjectSuffix) module.AddProperties(&prebuilt.properties) return module.Init() } @@ -484,18 +464,22 @@ type vendorSnapshotSingleton struct { var ( // Modules under following directories are ignored. They are OEM's and vendor's - // proprietary modules(device/, vendor/, and hardware/). + // proprietary modules(device/, kernel/, vendor/, and hardware/). // TODO(b/65377115): Clean up these with more maintainable way vendorProprietaryDirs = []string{ "device", + "kernel", "vendor", "hardware", } // Modules under following directories are included as they are in AOSP, - // although hardware/ is normally for vendor's own. + // although hardware/ and kernel/ are normally for vendor's own. // TODO(b/65377115): Clean up these with more maintainable way aospDirsUnderProprietary = []string{ + "kernel/configs", + "kernel/prebuilts", + "kernel/tests", "hardware/interfaces", "hardware/libhardware", "hardware/libhardware_legacy", @@ -552,18 +536,29 @@ func isVendorSnapshotModule(m *Module, moduleDir string) bool { if _, ok := m.linker.(*kernelHeadersDecorator); ok { return false } + // skip llndk_library and llndk_headers which are backward compatible + if _, ok := m.linker.(*llndkStubDecorator); ok { + return false + } + if _, ok := m.linker.(*llndkHeadersDecorator); ok { + return false + } // Libraries if l, ok := m.linker.(snapshotLibraryInterface); ok { // TODO(b/65377115): add full support for sanitizer if m.sanitize != nil { - // cfi, scs and hwasan export both sanitized and unsanitized variants for static and header + // scs and hwasan export both sanitized and unsanitized variants for static and header // Always use unsanitized variants of them. - for _, t := range []sanitizerType{cfi, scs, hwasan} { + for _, t := range []sanitizerType{scs, hwasan} { if !l.shared() && m.sanitize.isSanitizerEnabled(t) { return false } } + // cfi also exports both variants. But for static, we capture both. + if !l.static() && !l.shared() && m.sanitize.isSanitizerEnabled(cfi) { + return false + } } if l.static() { return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true) @@ -657,6 +652,7 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont ExportedDirs []string `json:",omitempty"` ExportedSystemDirs []string `json:",omitempty"` ExportedFlags []string `json:",omitempty"` + Sanitize string `json:",omitempty"` SanitizeMinimalDep bool `json:",omitempty"` SanitizeUbsanDep bool `json:",omitempty"` @@ -706,6 +702,7 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont var propOut string if l, ok := m.linker.(snapshotLibraryInterface); ok { + // library flags prop.ExportedFlags = l.exportedFlags() for _, dir := range l.exportedDirs() { @@ -738,6 +735,15 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont if libType != "header" { libPath := m.outputFile.Path() stem = libPath.Base() + if l.static() && m.sanitize != nil && m.sanitize.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" + } snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem) ret = append(ret, copyFile(ctx, libPath, snapshotLibOut)) } else { diff --git a/cc/vndk.go b/cc/vndk.go index 4adf9d226..23bb095bc 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -26,6 +26,8 @@ import ( "android/soong/android" "android/soong/cc/config" "android/soong/etc" + + "github.com/google/blueprint" ) const ( @@ -127,7 +129,7 @@ func (vndk *vndkdep) typeName() string { return "native:vendor:vndkspext" } -func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module, tag DependencyTag) { +func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module, tag blueprint.DependencyTag) { if to.linker == nil { return } @@ -340,7 +342,7 @@ func processVndkLibrary(mctx android.BottomUpMutatorContext, m *Module) { } } -// Sanity check for modules that mustn't be VNDK +// Check for modules that mustn't be VNDK func shouldSkipVndkMutator(m *Module) bool { if !m.Enabled() { return true @@ -559,10 +561,6 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex return } - if ctx.DeviceConfig().BoardVndkRuntimeDisable() { - return - } - var snapshotOutputs android.Paths /* diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go index 5a44c4663..94847601e 100644 --- a/cc/vndk_prebuilt.go +++ b/cc/vndk_prebuilt.go @@ -142,9 +142,10 @@ func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, builderFlags := flagsToBuilderFlags(flags) p.unstrippedOutputFile = in libName := in.Base() - if p.needsStrip(ctx) { + if p.stripper.NeedsStrip(ctx) { + stripFlags := flagsToStripFlags(flags) stripped := android.PathForModuleOut(ctx, "stripped", libName) - p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags) in = stripped } @@ -213,7 +214,7 @@ func vndkPrebuiltSharedLibrary() *Module { library.BuildOnlyShared() module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() prebuilt := &vndkPrebuiltLibraryDecorator{ libraryDecorator: library, diff --git a/cmd/diff_target_files/Android.bp b/cmd/diff_target_files/Android.bp index 5397f4b74..bc6b068b9 100644 --- a/cmd/diff_target_files/Android.bp +++ b/cmd/diff_target_files/Android.bp @@ -5,12 +5,12 @@ blueprint_go_binary { "diff_target_files.go", "glob.go", "target_files.go", - "whitelist.go", + "allow_list.go", "zip_artifact.go", ], testSrcs: [ "compare_test.go", "glob_test.go", - "whitelist_test.go", + "allow_list_test.go", ], } diff --git a/cmd/diff_target_files/whitelist.go b/cmd/diff_target_files/allow_list.go index f00fc1ee2..ca55b43e1 100644 --- a/cmd/diff_target_files/whitelist.go +++ b/cmd/diff_target_files/allow_list.go @@ -25,18 +25,13 @@ import ( "unicode" ) -type jsonWhitelist struct { - Paths []string - IgnoreMatchingLines []string -} - -type whitelist struct { +type allowList struct { path string ignoreMatchingLines []string } -func parseWhitelists(whitelists []string, whitelistFiles []string) ([]whitelist, error) { - var ret []whitelist +func parseAllowLists(allowLists []string, allowListFiles []string) ([]allowList, error) { + var ret []allowList add := func(path string, ignoreMatchingLines []string) { for _, x := range ret { @@ -46,24 +41,24 @@ func parseWhitelists(whitelists []string, whitelistFiles []string) ([]whitelist, } } - ret = append(ret, whitelist{ + ret = append(ret, allowList{ path: path, ignoreMatchingLines: ignoreMatchingLines, }) } - for _, file := range whitelistFiles { - newWhitelists, err := parseWhitelistFile(file) + for _, file := range allowListFiles { + newAllowlists, err := parseAllowListFile(file) if err != nil { return nil, err } - for _, w := range newWhitelists { + for _, w := range newAllowlists { add(w.path, w.ignoreMatchingLines) } } - for _, s := range whitelists { + for _, s := range allowLists { colon := strings.IndexRune(s, ':') var ignoreMatchingLines []string if colon >= 0 { @@ -75,7 +70,7 @@ func parseWhitelists(whitelists []string, whitelistFiles []string) ([]whitelist, return ret, nil } -func parseWhitelistFile(file string) ([]whitelist, error) { +func parseAllowListFile(file string) ([]allowList, error) { r, err := os.Open(file) if err != nil { return nil, err @@ -84,27 +79,32 @@ func parseWhitelistFile(file string) ([]whitelist, error) { d := json.NewDecoder(newJSONCommentStripper(r)) - var jsonWhitelists []jsonWhitelist + var jsonAllowLists []struct { + Paths []string + IgnoreMatchingLines []string + } - err = d.Decode(&jsonWhitelists) + if err := d.Decode(&jsonAllowLists); err != nil { + return nil, err + } - var whitelists []whitelist - for _, w := range jsonWhitelists { + var allowLists []allowList + for _, w := range jsonAllowLists { for _, p := range w.Paths { - whitelists = append(whitelists, whitelist{ + allowLists = append(allowLists, allowList{ path: p, ignoreMatchingLines: w.IgnoreMatchingLines, }) } } - return whitelists, err + return allowLists, err } -func filterModifiedPaths(l [][2]*ZipArtifactFile, whitelists []whitelist) ([][2]*ZipArtifactFile, error) { +func filterModifiedPaths(l [][2]*ZipArtifactFile, allowLists []allowList) ([][2]*ZipArtifactFile, error) { outer: for i := 0; i < len(l); i++ { - for _, w := range whitelists { + for _, w := range allowLists { if match, err := Match(w.path, l[i][0].Name); err != nil { return l, err } else if match { @@ -126,10 +126,10 @@ outer: return l, nil } -func filterNewPaths(l []*ZipArtifactFile, whitelists []whitelist) ([]*ZipArtifactFile, error) { +func filterNewPaths(l []*ZipArtifactFile, allowLists []allowList) ([]*ZipArtifactFile, error) { outer: for i := 0; i < len(l); i++ { - for _, w := range whitelists { + for _, w := range allowLists { if match, err := Match(w.path, l[i].Name); err != nil { return l, err } else if match && len(w.ignoreMatchingLines) == 0 { @@ -192,18 +192,18 @@ func diffIgnoringMatchingLines(a *ZipArtifactFile, b *ZipArtifactFile, ignoreMat return bytes.Compare(bufA, bufB) == 0, nil } -func applyWhitelists(diff zipDiff, whitelists []whitelist) (zipDiff, error) { +func applyAllowLists(diff zipDiff, allowLists []allowList) (zipDiff, error) { var err error - diff.modified, err = filterModifiedPaths(diff.modified, whitelists) + diff.modified, err = filterModifiedPaths(diff.modified, allowLists) if err != nil { return diff, err } - diff.onlyInA, err = filterNewPaths(diff.onlyInA, whitelists) + diff.onlyInA, err = filterNewPaths(diff.onlyInA, allowLists) if err != nil { return diff, err } - diff.onlyInB, err = filterNewPaths(diff.onlyInB, whitelists) + diff.onlyInB, err = filterNewPaths(diff.onlyInB, allowLists) if err != nil { return diff, err } diff --git a/cmd/diff_target_files/whitelist_test.go b/cmd/diff_target_files/allow_list_test.go index 4b19fdd21..8410e5acc 100644 --- a/cmd/diff_target_files/whitelist_test.go +++ b/cmd/diff_target_files/allow_list_test.go @@ -57,10 +57,10 @@ c var f2 = bytesToZipArtifactFile("dir/f2", nil) -func Test_applyWhitelists(t *testing.T) { +func Test_applyAllowLists(t *testing.T) { type args struct { diff zipDiff - whitelists []whitelist + allowLists []allowList } tests := []struct { name string @@ -74,7 +74,7 @@ func Test_applyWhitelists(t *testing.T) { diff: zipDiff{ onlyInA: []*ZipArtifactFile{f1a, f2}, }, - whitelists: []whitelist{{path: "dir/f1"}}, + allowLists: []allowList{{path: "dir/f1"}}, }, want: zipDiff{ onlyInA: []*ZipArtifactFile{f2}, @@ -86,7 +86,7 @@ func Test_applyWhitelists(t *testing.T) { diff: zipDiff{ onlyInA: []*ZipArtifactFile{f1a, f2}, }, - whitelists: []whitelist{{path: "dir/*"}}, + allowLists: []allowList{{path: "dir/*"}}, }, want: zipDiff{}, }, @@ -96,7 +96,7 @@ func Test_applyWhitelists(t *testing.T) { diff: zipDiff{ modified: [][2]*ZipArtifactFile{{f1a, f1b}}, }, - whitelists: []whitelist{{path: "dir/*"}}, + allowLists: []allowList{{path: "dir/*"}}, }, want: zipDiff{}, }, @@ -106,20 +106,20 @@ func Test_applyWhitelists(t *testing.T) { diff: zipDiff{ modified: [][2]*ZipArtifactFile{{f1a, f1b}}, }, - whitelists: []whitelist{{path: "dir/*", ignoreMatchingLines: []string{"foo: .*"}}}, + allowLists: []allowList{{path: "dir/*", ignoreMatchingLines: []string{"foo: .*"}}}, }, want: zipDiff{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := applyWhitelists(tt.args.diff, tt.args.whitelists) + got, err := applyAllowLists(tt.args.diff, tt.args.allowLists) if (err != nil) != tt.wantErr { - t.Errorf("applyWhitelists() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Test_applyAllowLists() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("applyWhitelists() = %v, want %v", got, tt.want) + t.Errorf("Test_applyAllowLists() = %v, want %v", got, tt.want) } }) } diff --git a/cmd/diff_target_files/compare.go b/cmd/diff_target_files/compare.go index 00cd9ca10..45b6d6b1c 100644 --- a/cmd/diff_target_files/compare.go +++ b/cmd/diff_target_files/compare.go @@ -21,7 +21,7 @@ import ( // compareTargetFiles takes two ZipArtifacts and compares the files they contain by examining // the path, size, and CRC of each file. -func compareTargetFiles(priZip, refZip ZipArtifact, artifact string, whitelists []whitelist, filters []string) (zipDiff, error) { +func compareTargetFiles(priZip, refZip ZipArtifact, artifact string, allowLists []allowList, filters []string) (zipDiff, error) { priZipFiles, err := priZip.Files() if err != nil { return zipDiff{}, fmt.Errorf("error fetching target file lists from primary zip %v", err) @@ -45,7 +45,7 @@ func compareTargetFiles(priZip, refZip ZipArtifact, artifact string, whitelists // Compare the file lists from both builds diff := diffTargetFilesLists(refZipFiles, priZipFiles) - return applyWhitelists(diff, whitelists) + return applyAllowLists(diff, allowLists) } // zipDiff contains the list of files that differ between two zip files. diff --git a/cmd/diff_target_files/diff_target_files.go b/cmd/diff_target_files/diff_target_files.go index 75bc8ee4e..634565bca 100644 --- a/cmd/diff_target_files/diff_target_files.go +++ b/cmd/diff_target_files/diff_target_files.go @@ -22,8 +22,8 @@ import ( ) var ( - whitelists = newMultiString("whitelist", "whitelist patterns in the form <pattern>[:<regex of line to ignore>]") - whitelistFiles = newMultiString("whitelist_file", "files containing whitelist definitions") + allowLists = newMultiString("allowlist", "allowlist patterns in the form <pattern>[:<regex of line to ignore>]") + allowListFiles = newMultiString("allowlist_file", "files containing allowlist definitions") filters = newMultiString("filter", "filter patterns to apply to files in target-files.zip before comparing") ) @@ -47,9 +47,9 @@ func main() { os.Exit(1) } - whitelists, err := parseWhitelists(*whitelists, *whitelistFiles) + allowLists, err := parseAllowLists(*allowLists, *allowListFiles) if err != nil { - fmt.Fprintf(os.Stderr, "Error parsing whitelists: %v\n", err) + fmt.Fprintf(os.Stderr, "Error parsing allowlists: %v\n", err) os.Exit(1) } @@ -67,7 +67,7 @@ func main() { } defer refZip.Close() - diff, err := compareTargetFiles(priZip, refZip, targetFilesPattern, whitelists, *filters) + diff, err := compareTargetFiles(priZip, refZip, targetFilesPattern, allowLists, *filters) if err != nil { fmt.Fprintf(os.Stderr, "Error comparing zip files: %v\n", err) os.Exit(1) diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go index a95aca9f0..274c8eee5 100644 --- a/cmd/merge_zips/merge_zips.go +++ b/cmd/merge_zips/merge_zips.go @@ -429,7 +429,7 @@ func NewInputZipsManager(nInputZips, maxOpenZips int) *InputZipsManager { if maxOpenZips < 3 { panic(fmt.Errorf("open zips limit should be above 3")) } - // In the dummy element .older points to the most recently opened InputZip, and .newer points to the oldest. + // In the fake element .older points to the most recently opened InputZip, and .newer points to the oldest. head := new(ManagedInputZip) head.older = head head.newer = head diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp index b559bac86..4ebbe6895 100644 --- a/cmd/soong_build/Android.bp +++ b/cmd/soong_build/Android.bp @@ -26,6 +26,10 @@ bootstrap_go_binary { srcs: [ "main.go", "writedocs.go", + "bazel_overlay.go", + ], + testSrcs: [ + "bazel_overlay_test.go", ], primaryBuilder: true, } diff --git a/cmd/soong_build/bazel_overlay.go b/cmd/soong_build/bazel_overlay.go new file mode 100644 index 000000000..308076d52 --- /dev/null +++ b/cmd/soong_build/bazel_overlay.go @@ -0,0 +1,449 @@ +// Copyright 2020 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 main + +import ( + "android/soong/android" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "strings" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +const ( + soongModuleLoad = `package(default_visibility = ["//visibility:public"]) +load("//:soong_module.bzl", "soong_module") + +` + + // A BUILD file target snippet representing a Soong module + soongModuleTarget = `soong_module( + name = "%s", + module_name = "%s", + module_type = "%s", + module_variant = "%s", + module_deps = %s, +%s)` + + // The soong_module rule implementation in a .bzl file + soongModuleBzl = `SoongModuleInfo = provider( + fields = { + "name": "Name of module", + "type": "Type of module", + "variant": "Variant of module", + }, +) + +def _merge_dicts(*dicts): + """Adds a list of dictionaries into a single dictionary.""" + + # If keys are repeated in multiple dictionaries, the latter one "wins". + result = {} + for d in dicts: + result.update(d) + + return result + +def _generic_soong_module_impl(ctx): + return [ + SoongModuleInfo( + name = ctx.attr.module_name, + type = ctx.attr.module_type, + variant = ctx.attr.module_variant, + ), + ] + +_COMMON_ATTRS = { + "module_name": attr.string(mandatory = True), + "module_type": attr.string(mandatory = True), + "module_variant": attr.string(), + "module_deps": attr.label_list(providers = [SoongModuleInfo]), +} + + +generic_soong_module = rule( + implementation = _generic_soong_module_impl, + attrs = _COMMON_ATTRS, +) + +# TODO(jingwen): auto generate Soong module shims +def _soong_filegroup_impl(ctx): + return [SoongModuleInfo(),] + +soong_filegroup = rule( + implementation = _soong_filegroup_impl, + # Matches https://cs.android.com/android/platform/superproject/+/master:build/soong/android/filegroup.go;l=25-40;drc=6a6478d49e78703ba22a432c41d819c8df79ef6c + attrs = _merge_dicts(_COMMON_ATTRS, { + "srcs": attr.string_list(doc = "srcs lists files that will be included in this filegroup"), + "exclude_srcs": attr.string_list(), + "path": attr.string(doc = "The base path to the files. May be used by other modules to determine which portion of the path to use. For example, when a filegroup is used as data in a cc_test rule, the base path is stripped off the path and the remaining path is used as the installation directory."), + "export_to_make_var": attr.string(doc = "Create a make variable with the specified name that contains the list of files in the filegroup, relative to the root of the source tree."), + }) +) + +soong_module_rule_map = { + "filegroup": soong_filegroup, +} + +# soong_module is a macro that supports arbitrary kwargs, and uses module_type to +# expand to the right underlying shim. +def soong_module(name, module_type, **kwargs): + soong_module_rule = soong_module_rule_map.get(module_type) + + if soong_module_rule == None: + # This module type does not have an existing rule to map to, so use the + # generic_soong_module rule instead. + generic_soong_module( + name = name, + module_type = module_type, + module_name = kwargs.pop("module_name", ""), + module_variant = kwargs.pop("module_variant", ""), + module_deps = kwargs.pop("module_deps", []), + ) + else: + soong_module_rule( + name = name, + module_type = module_type, + **kwargs, + ) +` +) + +func targetNameWithVariant(c *blueprint.Context, logicModule blueprint.Module) string { + name := "" + if c.ModuleSubDir(logicModule) != "" { + // TODO(b/162720883): Figure out a way to drop the "--" variant suffixes. + name = c.ModuleName(logicModule) + "--" + c.ModuleSubDir(logicModule) + } else { + name = c.ModuleName(logicModule) + } + + return strings.Replace(name, "//", "", 1) +} + +func qualifiedTargetLabel(c *blueprint.Context, logicModule blueprint.Module) string { + return "//" + + packagePath(c, logicModule) + + ":" + + targetNameWithVariant(c, logicModule) +} + +func packagePath(c *blueprint.Context, logicModule blueprint.Module) string { + return filepath.Dir(c.BlueprintFile(logicModule)) +} + +func escapeString(s string) string { + s = strings.ReplaceAll(s, "\\", "\\\\") + return strings.ReplaceAll(s, "\"", "\\\"") +} + +func makeIndent(indent int) string { + if indent < 0 { + panic(fmt.Errorf("indent column cannot be less than 0, but got %d", indent)) + } + return strings.Repeat(" ", indent) +} + +// prettyPrint a property value into the equivalent Starlark representation +// recursively. +func prettyPrint(propertyValue reflect.Value, indent int) (string, error) { + if isZero(propertyValue) { + // A property value being set or unset actually matters -- Soong does set default + // values for unset properties, like system_shared_libs = ["libc", "libm", "libdl"] at + // https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=281-287;drc=f70926eef0b9b57faf04c17a1062ce50d209e480 + // + // In Bazel-parlance, we would use "attr.<type>(default = <default value>)" to set the default + // value of unset attributes. + return "", nil + } + + var ret string + switch propertyValue.Kind() { + case reflect.String: + ret = fmt.Sprintf("\"%v\"", escapeString(propertyValue.String())) + case reflect.Bool: + ret = strings.Title(fmt.Sprintf("%v", propertyValue.Interface())) + case reflect.Int, reflect.Uint, reflect.Int64: + ret = fmt.Sprintf("%v", propertyValue.Interface()) + case reflect.Ptr: + return prettyPrint(propertyValue.Elem(), indent) + case reflect.Slice: + ret = "[\n" + for i := 0; i < propertyValue.Len(); i++ { + indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1) + if err != nil { + return "", err + } + + if indexedValue != "" { + ret += makeIndent(indent + 1) + ret += indexedValue + ret += ",\n" + } + } + ret += makeIndent(indent) + ret += "]" + case reflect.Struct: + ret = "{\n" + // Sort and print the struct props by the key. + structProps := extractStructProperties(propertyValue, indent) + for _, k := range android.SortedStringKeys(structProps) { + ret += makeIndent(indent + 1) + ret += "\"" + k + "\": " + ret += structProps[k] + ret += ",\n" + } + ret += makeIndent(indent) + ret += "}" + case reflect.Interface: + // TODO(b/164227191): implement pretty print for interfaces. + // Interfaces are used for for arch, multilib and target properties. + return "", nil + default: + return "", fmt.Errorf( + "unexpected kind for property struct field: %s", propertyValue.Kind()) + } + return ret, nil +} + +func extractStructProperties(structValue reflect.Value, indent int) map[string]string { + if structValue.Kind() != reflect.Struct { + panic(fmt.Errorf("Expected a reflect.Struct type, but got %s", structValue.Kind())) + } + + ret := map[string]string{} + structType := structValue.Type() + for i := 0; i < structValue.NumField(); i++ { + field := structType.Field(i) + if field.PkgPath != "" { + // Skip unexported fields. Some properties are + // internal to Soong only, and these fields do not have PkgPath. + continue + } + if proptools.HasTag(field, "blueprint", "mutated") { + continue + } + + fieldValue := structValue.Field(i) + if isZero(fieldValue) { + // Ignore zero-valued fields + continue + } + + propertyName := proptools.PropertyNameForField(field.Name) + prettyPrintedValue, err := prettyPrint(fieldValue, indent+1) + if err != nil { + panic( + fmt.Errorf( + "Error while parsing property: %q. %s", + propertyName, + err)) + } + if prettyPrintedValue != "" { + ret[propertyName] = prettyPrintedValue + } + } + + return ret +} + +func isStructPtr(t reflect.Type) bool { + return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct +} + +// Generically extract module properties and types into a map, keyed by the module property name. +func extractModuleProperties(aModule android.Module) map[string]string { + ret := map[string]string{} + + // Iterate over this android.Module's property structs. + for _, properties := range aModule.GetProperties() { + propertiesValue := reflect.ValueOf(properties) + // Check that propertiesValue is a pointer to the Properties struct, like + // *cc.BaseLinkerProperties or *java.CompilerProperties. + // + // propertiesValue can also be type-asserted to the structs to + // manipulate internal props, if needed. + if isStructPtr(propertiesValue.Type()) { + structValue := propertiesValue.Elem() + for k, v := range extractStructProperties(structValue, 0) { + ret[k] = v + } + } else { + panic(fmt.Errorf( + "properties must be a pointer to a struct, got %T", + propertiesValue.Interface())) + } + + } + + return ret +} + +func createBazelOverlay(ctx *android.Context, bazelOverlayDir string) error { + blueprintCtx := ctx.Context + blueprintCtx.VisitAllModules(func(module blueprint.Module) { + buildFile, err := buildFileForModule(blueprintCtx, module) + if err != nil { + panic(err) + } + + buildFile.Write([]byte(generateSoongModuleTarget(blueprintCtx, module) + "\n\n")) + buildFile.Close() + }) + + if err := writeReadOnlyFile(bazelOverlayDir, "WORKSPACE", ""); err != nil { + return err + } + + if err := writeReadOnlyFile(bazelOverlayDir, "BUILD", ""); err != nil { + return err + } + + return writeReadOnlyFile(bazelOverlayDir, "soong_module.bzl", soongModuleBzl) +} + +var ignoredProps map[string]bool = map[string]bool{ + "name": true, // redundant, since this is explicitly generated for every target + "from": true, // reserved keyword + "in": true, // reserved keyword + "arch": true, // interface prop type is not supported yet. + "multilib": true, // interface prop type is not supported yet. + "target": true, // interface prop type is not supported yet. + "visibility": true, // Bazel has native visibility semantics. Handle later. +} + +func shouldGenerateAttribute(prop string) bool { + return !ignoredProps[prop] +} + +// props is an unsorted map. This function ensures that +// the generated attributes are sorted to ensure determinism. +func propsToAttributes(props map[string]string) string { + var attributes string + for _, propName := range android.SortedStringKeys(props) { + if shouldGenerateAttribute(propName) { + attributes += fmt.Sprintf(" %s = %s,\n", propName, props[propName]) + } + } + return attributes +} + +// Convert a module and its deps and props into a Bazel macro/rule +// representation in the BUILD file. +func generateSoongModuleTarget( + blueprintCtx *blueprint.Context, + module blueprint.Module) string { + + var props map[string]string + if aModule, ok := module.(android.Module); ok { + props = extractModuleProperties(aModule) + } + attributes := propsToAttributes(props) + + // TODO(b/163018919): DirectDeps can have duplicate (module, variant) + // items, if the modules are added using different DependencyTag. Figure + // out the implications of that. + depLabels := map[string]bool{} + blueprintCtx.VisitDirectDeps(module, func(depModule blueprint.Module) { + depLabels[qualifiedTargetLabel(blueprintCtx, depModule)] = true + }) + + depLabelList := "[\n" + for depLabel, _ := range depLabels { + depLabelList += " \"" + depLabelList += depLabel + depLabelList += "\",\n" + } + depLabelList += " ]" + + return fmt.Sprintf( + soongModuleTarget, + targetNameWithVariant(blueprintCtx, module), + blueprintCtx.ModuleName(module), + blueprintCtx.ModuleType(module), + blueprintCtx.ModuleSubDir(module), + depLabelList, + attributes) +} + +func buildFileForModule(ctx *blueprint.Context, module blueprint.Module) (*os.File, error) { + // Create nested directories for the BUILD file + dirPath := filepath.Join(bazelOverlayDir, packagePath(ctx, module)) + if _, err := os.Stat(dirPath); os.IsNotExist(err) { + os.MkdirAll(dirPath, os.ModePerm) + } + // Open the file for appending, and create it if it doesn't exist + f, err := os.OpenFile( + filepath.Join(dirPath, "BUILD.bazel"), + os.O_APPEND|os.O_CREATE|os.O_WRONLY, + 0644) + if err != nil { + return nil, err + } + + // If the file is empty, add the load statement for the `soong_module` rule + fi, err := f.Stat() + if err != nil { + return nil, err + } + if fi.Size() == 0 { + f.Write([]byte(soongModuleLoad + "\n")) + } + + return f, nil +} + +// The overlay directory should be read-only, sufficient for bazel query. +func writeReadOnlyFile(dir string, baseName string, content string) error { + workspaceFile := filepath.Join(bazelOverlayDir, baseName) + // 0444 is read-only + return ioutil.WriteFile(workspaceFile, []byte(content), 0444) +} + +func isZero(value reflect.Value) bool { + switch value.Kind() { + case reflect.Func, reflect.Map, reflect.Slice: + return value.IsNil() + case reflect.Array: + valueIsZero := true + for i := 0; i < value.Len(); i++ { + valueIsZero = valueIsZero && isZero(value.Index(i)) + } + return valueIsZero + case reflect.Struct: + valueIsZero := true + for i := 0; i < value.NumField(); i++ { + if value.Field(i).CanSet() { + valueIsZero = valueIsZero && isZero(value.Field(i)) + } + } + return valueIsZero + case reflect.Ptr: + if !value.IsNil() { + return isZero(reflect.Indirect(value)) + } else { + return true + } + default: + zeroValue := reflect.Zero(value.Type()) + result := value.Interface() == zeroValue.Interface() + return result + } +} diff --git a/cmd/soong_build/bazel_overlay_test.go b/cmd/soong_build/bazel_overlay_test.go new file mode 100644 index 000000000..8db784d6b --- /dev/null +++ b/cmd/soong_build/bazel_overlay_test.go @@ -0,0 +1,255 @@ +// Copyright 2020 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 main + +import ( + "android/soong/android" + "io/ioutil" + "os" + "testing" +) + +var buildDir string + +func setUp() { + var err error + buildDir, err = ioutil.TempDir("", "bazel_overlay_test") + if err != nil { + panic(err) + } +} + +func tearDown() { + os.RemoveAll(buildDir) +} + +func TestMain(m *testing.M) { + run := func() int { + setUp() + defer tearDown() + + return m.Run() + } + + os.Exit(run()) +} + +type customModule struct { + android.ModuleBase +} + +func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // nothing for now. +} + +func customModuleFactory() android.Module { + module := &customModule{} + android.InitAndroidModule(module) + return module +} + +func TestGenerateBazelOverlayFromBlueprint(t *testing.T) { + testCases := []struct { + bp string + expectedBazelTarget string + }{ + { + bp: `custom { + name: "foo", +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], +)`, + }, + { + bp: `custom { + name: "foo", + ramdisk: true, +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + ramdisk = True, +)`, + }, + { + bp: `custom { + name: "foo", + owner: "a_string_with\"quotes\"_and_\\backslashes\\\\", +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + owner = "a_string_with\"quotes\"_and_\\backslashes\\\\", +)`, + }, + { + bp: `custom { + name: "foo", + required: ["bar"], +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + required = [ + "bar", + ], +)`, + }, + { + bp: `custom { + name: "foo", + target_required: ["qux", "bazqux"], +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + target_required = [ + "qux", + "bazqux", + ], +)`, + }, + { + bp: `custom { + name: "foo", + dist: { + targets: ["goal_foo"], + tag: ".foo", + }, + dists: [ + { + targets: ["goal_bar"], + tag: ".bar", + }, + ], +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + dist = { + "tag": ".foo", + "targets": [ + "goal_foo", + ], + }, + dists = [ + { + "tag": ".bar", + "targets": [ + "goal_bar", + ], + }, + ], +)`, + }, + { + bp: `custom { + name: "foo", + required: ["bar"], + target_required: ["qux", "bazqux"], + ramdisk: true, + owner: "custom_owner", + dists: [ + { + tag: ".tag", + targets: ["my_goal"], + }, + ], +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + dists = [ + { + "tag": ".tag", + "targets": [ + "my_goal", + ], + }, + ], + owner = "custom_owner", + ramdisk = True, + required = [ + "bar", + ], + target_required = [ + "qux", + "bazqux", + ], +)`, + }, + } + + for _, testCase := range testCases { + config := android.TestConfig(buildDir, nil, testCase.bp, nil) + ctx := android.NewTestContext() + ctx.RegisterModuleType("custom", customModuleFactory) + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + module := ctx.ModuleForTests("foo", "").Module().(*customModule) + blueprintCtx := ctx.Context.Context + + actualBazelTarget := generateSoongModuleTarget(blueprintCtx, module) + if actualBazelTarget != testCase.expectedBazelTarget { + t.Errorf( + "Expected generated Bazel target to be '%s', got '%s'", + testCase.expectedBazelTarget, + actualBazelTarget, + ) + } + } +} diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index 532d9e486..01a39a216 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -26,11 +26,13 @@ import ( ) var ( - docFile string + docFile string + bazelOverlayDir string ) func init() { flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output") + flag.StringVar(&bazelOverlayDir, "bazel_overlay_dir", "", "path to the bazel overlay directory") } func newNameResolver(config android.Config) *android.NameResolver { @@ -65,7 +67,7 @@ func main() { os.Exit(1) } - if docFile != "" { + if !shouldPrepareBuildActions() { configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions) } @@ -85,6 +87,13 @@ func main() { bootstrap.Main(ctx.Context, configuration, extraNinjaDeps...) + if bazelOverlayDir != "" { + if err := createBazelOverlay(ctx, bazelOverlayDir); err != nil { + fmt.Fprintf(os.Stderr, "%s", err) + os.Exit(1) + } + } + if docFile != "" { if err := writeDocs(ctx, docFile); err != nil { fmt.Fprintf(os.Stderr, "%s", err) @@ -94,7 +103,7 @@ func main() { // TODO(ccross): make this a command line argument. Requires plumbing through blueprint // to affect the command line of the primary builder. - if docFile == "" { + if shouldPrepareBuildActions() { metricsFile := filepath.Join(bootstrap.BuildDir, "soong_build_metrics.pb") err = android.WriteMetrics(configuration, metricsFile) if err != nil { @@ -103,3 +112,9 @@ func main() { } } } + +func shouldPrepareBuildActions() bool { + // If we're writing soong_docs or bazel_overlay, don't write build.ninja or + // collect metrics. + return docFile == "" && bazelOverlayDir == "" +} diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go index e485c60e0..4aa62be3c 100644 --- a/cmd/soong_ui/main.go +++ b/cmd/soong_ui/main.go @@ -35,14 +35,14 @@ import ( // A command represents an operation to be executed in the soong build // system. type command struct { - // the flag name (must have double dashes) + // The flag name (must have double dashes). flag string - // description for the flag (to display when running help) + // Description for the flag (to display when running help). description string - // Forces the status output into dumb terminal mode. - forceDumbOutput bool + // Stream the build status output into the simple terminal mode. + simpleOutput bool // Sets a prefix string to use for filenames of log files. logsPrefix string @@ -70,21 +70,21 @@ var commands []command = []command{ stdio: stdio, run: make, }, { - flag: "--dumpvar-mode", - description: "print the value of the legacy make variable VAR to stdout", - forceDumbOutput: true, - logsPrefix: "dumpvars-", - config: dumpVarConfig, - stdio: customStdio, - run: dumpVar, + flag: "--dumpvar-mode", + description: "print the value of the legacy make variable VAR to stdout", + simpleOutput: true, + logsPrefix: "dumpvars-", + config: dumpVarConfig, + stdio: customStdio, + run: dumpVar, }, { - flag: "--dumpvars-mode", - description: "dump the values of one or more legacy make variables, in shell syntax", - forceDumbOutput: true, - logsPrefix: "dumpvars-", - config: dumpVarConfig, - stdio: customStdio, - run: dumpVars, + flag: "--dumpvars-mode", + description: "dump the values of one or more legacy make variables, in shell syntax", + simpleOutput: true, + logsPrefix: "dumpvars-", + config: dumpVarConfig, + stdio: customStdio, + run: dumpVars, }, { flag: "--build-mode", description: "build modules based on the specified build action", @@ -125,7 +125,7 @@ func main() { os.Exit(1) } - output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), c.forceDumbOutput, + output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), c.simpleOutput, build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")) log := logger.New(output) @@ -172,7 +172,8 @@ func main() { buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error") rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb") soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics") - defer build.UploadMetrics(buildCtx, config, c.forceDumbOutput, buildStarted, buildErrorFile, rbeMetricsFile, soongMetricsFile) + defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, buildErrorFile, rbeMetricsFile, soongMetricsFile) + defer build.PrintGomaDeprecation(buildCtx, config) os.MkdirAll(logsDir, 0777) log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log")) diff --git a/dexpreopt/config.go b/dexpreopt/config.go index 2cf65feca..f22ee4735 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -40,15 +40,15 @@ type GlobalConfig struct { DisableGenerateProfile bool // don't generate profiles ProfileDir string // directory to find profiles in - BootJars []string // modules for jars that form the boot class path - UpdatableBootJars []string // jars within apex that form the boot class path + BootJars android.ConfiguredJarList // modules for jars that form the boot class path + UpdatableBootJars android.ConfiguredJarList // jars within apex that form the boot class path - ArtApexJars []string // modules for jars that are in the ART APEX + ArtApexJars android.ConfiguredJarList // modules for jars that are in the ART APEX - SystemServerJars []string // jars that form the system server - SystemServerApps []string // apps that are loaded into system server - UpdatableSystemServerJars []string // jars within apex that are loaded into system server - SpeedApps []string // apps that should be speed optimized + SystemServerJars []string // jars that form the system server + SystemServerApps []string // apps that are loaded into system server + UpdatableSystemServerJars android.ConfiguredJarList // jars within apex that are loaded into system server + SpeedApps []string // apps that should be speed optimized BrokenSuboptimalOrderOfSystemServerJars bool // if true, sub-optimal order does not cause a build error @@ -100,6 +100,8 @@ type GlobalSoongConfig struct { ConstructContext android.Path } +const UnknownInstallLibraryPath = "error" + // LibraryPath contains paths to the library DEX jar on host and on device. type LibraryPath struct { Host android.Path @@ -109,6 +111,54 @@ type LibraryPath struct { // LibraryPaths is a map from library name to on-host and on-device paths to its DEX jar. type LibraryPaths map[string]*LibraryPath +// Add a new library path to the map, unless a path for this library already exists. +func (libPaths LibraryPaths) addLibraryPath(ctx android.PathContext, lib string, hostPath, installPath android.Path) { + if _, present := libPaths[lib]; !present { + var devicePath string + if installPath != nil { + devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath)) + } else { + // For some stub libraries the only known thing is the name of their implementation + // library, but the library itself is unavailable (missing or part of a prebuilt). In + // such cases we still need to add the library to <uses-library> tags in the manifest, + // but we cannot use if for dexpreopt. + devicePath = UnknownInstallLibraryPath + } + libPaths[lib] = &LibraryPath{hostPath, devicePath} + } +} + +// Add a new library path to the map. Ensure that the build path to the library exists. +func (libPaths LibraryPaths) AddLibraryPath(ctx android.PathContext, lib string, hostPath, installPath android.Path) { + if hostPath != nil { + // Add a library only if the build path to it is known. + libPaths.addLibraryPath(ctx, lib, hostPath, installPath) + } else if !ctx.Config().AllowMissingDependencies() { + // Error on libraries with unknown build paths, unless missing dependencies are allowed. + android.ReportPathErrorf(ctx, "unknown build path to <uses-library> '%s'", lib) + } else { + // Not adding a library to the map will likely result in disabling dexpreopt. + } +} + +// Add a new library path to the map, if the library exists (name is not nil). +func (libPaths LibraryPaths) MaybeAddLibraryPath(ctx android.PathContext, lib *string, hostPath, installPath android.Path) { + if lib != nil { + // Don't check the build paths, add in any case. Some libraries may be missing from the + // build, but their names still need to be added to <uses-library> tags in the manifest. + libPaths.addLibraryPath(ctx, *lib, hostPath, installPath) + } +} + +// Add library paths from the second map to the first map (do not override existing entries). +func (libPaths LibraryPaths) AddLibraryPaths(otherPaths LibraryPaths) { + for lib, path := range otherPaths { + if _, present := libPaths[lib]; !present { + libPaths[lib] = path + } + } +} + type ModuleConfig struct { Name string DexLocation string // dex location on device @@ -189,8 +239,12 @@ func ParseGlobalConfig(ctx android.PathContext, data []byte) (*GlobalConfig, err // Copies of entries in GlobalConfig that are not constructable without extra parameters. They will be // used to construct the real value manually below. - DirtyImageObjects string - BootImageProfiles []string + BootJars []string + UpdatableBootJars []string + ArtApexJars []string + UpdatableSystemServerJars []string + DirtyImageObjects string + BootImageProfiles []string } config := GlobalJSONConfig{} @@ -200,6 +254,10 @@ func ParseGlobalConfig(ctx android.PathContext, data []byte) (*GlobalConfig, err } // Construct paths that require a PathContext. + config.GlobalConfig.BootJars = android.CreateConfiguredJarList(ctx, config.BootJars) + config.GlobalConfig.UpdatableBootJars = android.CreateConfiguredJarList(ctx, config.UpdatableBootJars) + config.GlobalConfig.ArtApexJars = android.CreateConfiguredJarList(ctx, config.ArtApexJars) + config.GlobalConfig.UpdatableSystemServerJars = android.CreateConfiguredJarList(ctx, config.UpdatableSystemServerJars) config.GlobalConfig.DirtyImageObjects = android.OptionalPathForPath(constructPath(ctx, config.DirtyImageObjects)) config.GlobalConfig.BootImageProfiles = constructPaths(ctx, config.BootImageProfiles) @@ -352,7 +410,33 @@ func RegisterToolDeps(ctx android.BottomUpMutatorContext) { func dex2oatPathFromDep(ctx android.ModuleContext) android.Path { dex2oatBin := dex2oatModuleName(ctx.Config()) - dex2oatModule := ctx.GetDirectDepWithTag(dex2oatBin, dex2oatDepTag) + // Find the right dex2oat module, trying to follow PrebuiltDepTag from source + // to prebuilt if there is one. We wouldn't have to do this if the + // prebuilt_postdeps mutator that replaces source deps with prebuilt deps was + // run after RegisterToolDeps above, but changing that leads to ordering + // problems between mutators (RegisterToolDeps needs to run late to act on + // final variants, while prebuilt_postdeps needs to run before many of the + // PostDeps mutators, like the APEX mutators). Hence we need to dig out the + // prebuilt explicitly here instead. + var dex2oatModule android.Module + ctx.WalkDeps(func(child, parent android.Module) bool { + if parent == ctx.Module() && ctx.OtherModuleDependencyTag(child) == dex2oatDepTag { + // Found the source module, or prebuilt module that has replaced the source. + dex2oatModule = child + if p, ok := child.(android.PrebuiltInterface); ok && p.Prebuilt() != nil { + return false // If it's the prebuilt we're done. + } else { + return true // Recurse to check if the source has a prebuilt dependency. + } + } + if parent == dex2oatModule && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag { + if p, ok := child.(android.PrebuiltInterface); ok && p.Prebuilt() != nil && p.Prebuilt().UsePrebuilt() { + dex2oatModule = child // Found a prebuilt that should be used. + } + } + return false + }) + if dex2oatModule == nil { // If this happens there's probably a missing call to AddToolDeps in DepsMutator. panic(fmt.Sprintf("Failed to lookup %s dependency", dex2oatBin)) @@ -530,12 +614,12 @@ func GlobalConfigForTests(ctx android.PathContext) *GlobalConfig { PatternsOnSystemOther: nil, DisableGenerateProfile: false, ProfileDir: "", - BootJars: nil, - UpdatableBootJars: nil, - ArtApexJars: nil, + BootJars: android.EmptyConfiguredJarList(), + UpdatableBootJars: android.EmptyConfiguredJarList(), + ArtApexJars: android.EmptyConfiguredJarList(), SystemServerJars: nil, SystemServerApps: nil, - UpdatableSystemServerJars: nil, + UpdatableSystemServerJars: android.EmptyConfiguredJarList(), SpeedApps: nil, PreoptFlags: nil, DefaultCompilerFilter: "", diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index e49fa984e..4dbda49b3 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -37,7 +37,6 @@ import ( "fmt" "path/filepath" "runtime" - "sort" "strings" "android/soong/android" @@ -82,15 +81,14 @@ func GenerateDexpreoptRule(ctx android.PathContext, globalSoong *GlobalSoongConf } if !dexpreoptDisabled(ctx, global, module) { - // Don't preopt individual boot jars, they will be preopted together. - if !contains(android.GetJarsFromApexJarPairs(ctx, global.BootJars), module.Name) { + if clc := genClassLoaderContext(ctx, global, module); clc != nil { appImage := (generateProfile || module.ForceCreateAppImage || global.DefaultAppImages) && !module.NoCreateAppImage generateDM := shouldGenerateDM(module, global) for archIdx, _ := range module.Archs { - dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage, generateDM) + dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, *clc, profile, appImage, generateDM) } } } @@ -103,18 +101,21 @@ func dexpreoptDisabled(ctx android.PathContext, global *GlobalConfig, module *Mo return true } + // Don't preopt individual boot jars, they will be preopted together. + if global.BootJars.ContainsJar(module.Name) { + return true + } + // Don't preopt system server jars that are updatable. - for _, p := range global.UpdatableSystemServerJars { - if _, jar := android.SplitApexJarPair(ctx, p); jar == module.Name { - return true - } + if global.UpdatableSystemServerJars.ContainsJar(module.Name) { + return true } // If OnlyPreoptBootImageAndSystemServer=true and module is not in boot class path skip // Also preopt system server jars since selinux prevents system server from loading anything from // /data. If we don't do this they will need to be extracted which is not favorable for RAM usage // or performance. If PreoptExtractedApk is true, we ignore the only preopt boot image options. - if global.OnlyPreoptBootImageAndSystemServer && !contains(android.GetJarsFromApexJarPairs(ctx, global.BootJars), module.Name) && + if global.OnlyPreoptBootImageAndSystemServer && !global.BootJars.ContainsJar(module.Name) && !contains(global.SystemServerJars, module.Name) && !module.PreoptExtractedApk { return true } @@ -210,15 +211,6 @@ type classLoaderContextMap map[int]*classLoaderContext const anySdkVersion int = 9999 // should go last in class loader context -func (m classLoaderContextMap) getSortedKeys() []int { - keys := make([]int, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Ints(keys) - return keys -} - func (m classLoaderContextMap) getValue(sdkVer int) *classLoaderContext { if _, ok := m[sdkVer]; !ok { m[sdkVer] = &classLoaderContext{} @@ -226,13 +218,17 @@ func (m classLoaderContextMap) getValue(sdkVer int) *classLoaderContext { return m[sdkVer] } -func (m classLoaderContextMap) addLibs(sdkVer int, module *ModuleConfig, libs ...string) { +func (m classLoaderContextMap) addLibs(sdkVer int, module *ModuleConfig, libs ...string) bool { clc := m.getValue(sdkVer) for _, lib := range libs { - p := pathForLibrary(module, lib) - clc.Host = append(clc.Host, p.Host) - clc.Target = append(clc.Target, p.Device) + if p := pathForLibrary(module, lib); p != nil { + clc.Host = append(clc.Host, p.Host) + clc.Target = append(clc.Target, p.Device) + } else { + return false + } } + return true } func (m classLoaderContextMap) addSystemServerLibs(sdkVer int, ctx android.PathContext, module *ModuleConfig, libs ...string) { @@ -243,9 +239,79 @@ func (m classLoaderContextMap) addSystemServerLibs(sdkVer int, ctx android.PathC } } +// genClassLoaderContext generates host and target class loader context to be passed to the dex2oat +// command for the dexpreopted module. There are three possible cases: +// +// 1. System server jars. They have a special class loader context that includes other system +// server jars. +// +// 2. Library jars or APKs which have precise list of their <uses-library> libs. Their class loader +// context includes build and on-device paths to these libs. In some cases it may happen that +// the path to a <uses-library> is unknown (e.g. the dexpreopted module may depend on stubs +// library, whose implementation library is missing from the build altogether). In such case +// dexpreopting with the <uses-library> is impossible, and dexpreopting without it is pointless, +// as the runtime classpath won't match and the dexpreopted code will be discarded. Therefore in +// such cases the function returns nil, which disables dexpreopt. +// +// 2. All other library jars or APKs for which the exact <uses-library> list is unknown. They use +// the unsafe &-classpath workaround that means empty class loader context and absence of runtime +// check that the class loader context provided by the PackageManager agrees with the stored +// class loader context recorded in the .odex file. +// +func genClassLoaderContext(ctx android.PathContext, global *GlobalConfig, module *ModuleConfig) *classLoaderContextMap { + classLoaderContexts := make(classLoaderContextMap) + systemServerJars := NonUpdatableSystemServerJars(ctx, global) + + if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 { + // System server jars should be dexpreopted together: class loader context of each jar + // should include all preceding jars on the system server classpath. + classLoaderContexts.addSystemServerLibs(anySdkVersion, ctx, module, systemServerJars[:jarIndex]...) + + } else if module.EnforceUsesLibraries { + // Unconditional class loader context. + usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...) + if !classLoaderContexts.addLibs(anySdkVersion, module, usesLibs...) { + return nil + } + + // Conditional class loader context for API version < 28. + const httpLegacy = "org.apache.http.legacy" + if !contains(usesLibs, httpLegacy) { + if !classLoaderContexts.addLibs(28, module, httpLegacy) { + return nil + } + } + + // Conditional class loader context for API version < 29. + usesLibs29 := []string{ + "android.hidl.base-V1.0-java", + "android.hidl.manager-V1.0-java", + } + if !classLoaderContexts.addLibs(29, module, usesLibs29...) { + return nil + } + + // Conditional class loader context for API version < 30. + const testBase = "android.test.base" + if !contains(usesLibs, testBase) { + if !classLoaderContexts.addLibs(30, module, testBase) { + return nil + } + } + + } else { + // Pass special class loader context to skip the classpath and collision check. + // This will get removed once LOCAL_USES_LIBRARIES is enforced. + // Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default + // to the &. + } + + return &classLoaderContexts +} + func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig, - module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath, - appImage bool, generateDM bool) { + module *ModuleConfig, rule *android.RuleBuilder, archIdx int, classLoaderContexts classLoaderContextMap, + profile android.WritablePath, appImage bool, generateDM bool) { arch := module.Archs[archIdx] @@ -276,17 +342,12 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g invocationPath := odexPath.ReplaceExtension(ctx, "invocation") - classLoaderContexts := make(classLoaderContextMap) systemServerJars := NonUpdatableSystemServerJars(ctx, global) rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String())) rule.Command().FlagWithOutput("rm -f ", odexPath) if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 { - // System server jars should be dexpreopted together: class loader context of each jar - // should include all preceding jars on the system server classpath. - classLoaderContexts.addSystemServerLibs(anySdkVersion, ctx, module, systemServerJars[:jarIndex]...) - // Copy the system server jar to a predefined location where dex2oat will find it. dexPathHost := SystemServerDexJarHostPath(ctx, module.Name) rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String())) @@ -300,29 +361,6 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g Implicits(clc.Host). Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(clc.Target, ":") + "]") } else if module.EnforceUsesLibraries { - // Unconditional class loader context. - usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...) - classLoaderContexts.addLibs(anySdkVersion, module, usesLibs...) - - // Conditional class loader context for API version < 28. - const httpLegacy = "org.apache.http.legacy" - if !contains(usesLibs, httpLegacy) { - classLoaderContexts.addLibs(28, module, httpLegacy) - } - - // Conditional class loader context for API version < 29. - usesLibs29 := []string{ - "android.hidl.base-V1.0-java", - "android.hidl.manager-V1.0-java", - } - classLoaderContexts.addLibs(29, module, usesLibs29...) - - // Conditional class loader context for API version < 30. - const testBase = "android.test.base" - if !contains(usesLibs, testBase) { - classLoaderContexts.addLibs(30, module, testBase) - } - // Generate command that saves target SDK version in a shell variable. if module.ManifestPath != nil { rule.Command().Text(`target_sdk_version="$(`). @@ -344,7 +382,7 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g cmd := rule.Command(). Text(`eval "$(`).Tool(globalSoong.ConstructContext). Text(` --target-sdk-version ${target_sdk_version}`) - for _, ver := range classLoaderContexts.getSortedKeys() { + for _, ver := range android.SortedIntKeys(classLoaderContexts) { clc := classLoaderContexts.getValue(ver) verString := fmt.Sprintf("%d", ver) if ver == anySdkVersion { @@ -552,11 +590,11 @@ func PathToLocation(path android.Path, arch android.ArchType) string { } func pathForLibrary(module *ModuleConfig, lib string) *LibraryPath { - path, ok := module.LibraryPaths[lib] - if !ok { - panic(fmt.Errorf("unknown library path for %q", lib)) + if path, ok := module.LibraryPaths[lib]; ok && path.Host != nil && path.Device != "error" { + return path + } else { + return nil } - return path } func makefileMatch(pattern, s string) bool { @@ -571,20 +609,13 @@ func makefileMatch(pattern, s string) bool { } } -// Expected format for apexJarValue = <apex name>:<jar name> -func GetJarLocationFromApexJarPair(ctx android.PathContext, apexJarValue string) string { - apex, jar := android.SplitApexJarPair(ctx, apexJarValue) - return filepath.Join("/apex", apex, "javalib", jar+".jar") -} - var nonUpdatableSystemServerJarsKey = android.NewOnceKey("nonUpdatableSystemServerJars") // TODO: eliminate the superficial global config parameter by moving global config definition // from java subpackage to dexpreopt. func NonUpdatableSystemServerJars(ctx android.PathContext, global *GlobalConfig) []string { return ctx.Config().Once(nonUpdatableSystemServerJarsKey, func() interface{} { - return android.RemoveListFromList(global.SystemServerJars, - android.GetJarsFromApexJarPairs(ctx, global.UpdatableSystemServerJars)) + return android.RemoveListFromList(global.SystemServerJars, global.UpdatableSystemServerJars.CopyOfJars()) }).([]string) } diff --git a/genrule/genrule.go b/genrule/genrule.go index 00baa57cb..1cec2893a 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -259,9 +259,9 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) { // If AllowMissingDependencies is enabled, the build will not have stopped when // AddFarVariationDependencies was called on a missing tool, which will result in nonsensical - // "cmd: unknown location label ..." errors later. Add a dummy file to the local label. The - // command that uses this dummy file will never be executed because the rule will be replaced with - // an android.Error rule reporting the missing dependencies. + // "cmd: unknown location label ..." errors later. Add a placeholder file to the local label. + // The command that uses this placeholder file will never be executed because the rule will be + // replaced with an android.Error rule reporting the missing dependencies. if ctx.Config().AllowMissingDependencies() { for _, tool := range g.properties.Tools { if !seenTools[tool] { @@ -292,9 +292,9 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) { // If AllowMissingDependencies is enabled, the build will not have stopped when // the dependency was added on a missing SourceFileProducer module, which will result in nonsensical - // "cmd: label ":..." has no files" errors later. Add a dummy file to the local label. The - // command that uses this dummy file will never be executed because the rule will be replaced with - // an android.Error rule reporting the missing dependencies. + // "cmd: label ":..." has no files" errors later. Add a placeholder file to the local label. + // The command that uses this placeholder file will never be executed because the rule will be + // replaced with an android.Error rule reporting the missing dependencies. ctx.AddMissingDependencies(missingDeps) addLocationLabel(in, []string{"***missing srcs " + in + "***"}) } else { @@ -8,4 +8,4 @@ replace github.com/golang/protobuf v0.0.0 => ../../external/golang-protobuf replace github.com/google/blueprint v0.0.0 => ../blueprint -go 1.13 +go 1.15 diff --git a/java/Android.bp b/java/Android.bp index 1fda7f71d..e345014ce 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -10,6 +10,7 @@ bootstrap_go_package { "soong-dexpreopt", "soong-genrule", "soong-java-config", + "soong-python", "soong-remoteexec", "soong-tradefed", ], @@ -38,6 +39,7 @@ bootstrap_go_package { "java_resources.go", "kotlin.go", "lint.go", + "legacy_core_platform_api_usage.go", "platform_compat_config.go", "plugin.go", "prebuilt_apis.go", diff --git a/java/aar.go b/java/aar.go index ad9b5e7d2..0f5e30deb 100644 --- a/java/aar.go +++ b/java/aar.go @@ -20,6 +20,7 @@ import ( "strings" "android/soong/android" + "android/soong/dexpreopt" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -99,7 +100,7 @@ type aapt struct { useEmbeddedNativeLibs bool useEmbeddedDex bool usesNonSdkApis bool - sdkLibraries []string + sdkLibraries dexpreopt.LibraryPaths hasNoCode bool LoggingParent string resourceFiles android.Paths @@ -231,6 +232,8 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, ex transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags, sdkLibraries := aaptLibs(ctx, sdkContext) + a.sdkLibraries = sdkLibraries + // App manifest file manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile) @@ -357,7 +360,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, ex // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths, - staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries []string) { + staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries dexpreopt.LibraryPaths) { var sharedLibs android.Paths @@ -366,6 +369,8 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati sharedLibs = append(sharedLibs, sdkDep.jars...) } + sdkLibraries = make(dexpreopt.LibraryPaths) + ctx.VisitDirectDeps(func(module android.Module) { var exportPackage android.Path aarDep, _ := module.(AndroidLibraryDependency) @@ -385,7 +390,8 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati // (including the java_sdk_library) itself then append any implicit sdk library // names to the list of sdk libraries to be added to the manifest. if component, ok := module.(SdkLibraryComponentDependency); ok { - sdkLibraries = append(sdkLibraries, component.OptionalImplicitSdkLibrary()...) + sdkLibraries.MaybeAddLibraryPath(ctx, component.OptionalImplicitSdkLibrary(), + component.DexJarBuildPath(), component.DexJarInstallPath()) } case frameworkResTag: @@ -393,11 +399,14 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati sharedLibs = append(sharedLibs, exportPackage) } case staticLibTag: + if dep, ok := module.(Dependency); ok { + sdkLibraries.AddLibraryPaths(dep.ExportedSdkLibs()) + } if exportPackage != nil { transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...) transitiveStaticLibs = append(transitiveStaticLibs, exportPackage) transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...) - sdkLibraries = append(sdkLibraries, aarDep.ExportedSdkLibs()...) + sdkLibraries.AddLibraryPaths(aarDep.ExportedSdkLibs()) if aarDep.ExportedAssets().Valid() { assets = append(assets, aarDep.ExportedAssets().Path()) } @@ -428,7 +437,6 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs) transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests) - sdkLibraries = android.FirstUniqueStrings(sdkLibraries) return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags, sdkLibraries } @@ -465,8 +473,8 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.aapt.isLibrary = true - a.aapt.sdkLibraries = a.exportedSdkLibs a.aapt.buildActions(ctx, sdkContext(a)) + a.exportedSdkLibs = a.aapt.sdkLibraries ctx.CheckbuildFile(a.proguardOptionsFile) ctx.CheckbuildFile(a.exportPackage) @@ -625,7 +633,7 @@ func (a *AARImport) JacocoReportClassesFile() android.Path { } func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) { - if !ctx.Config().UnbundledBuildUsePrebuiltSdks() { + if !ctx.Config().AlwaysUsePrebuiltSdks() { sdkDep := decodeSdkDep(ctx, sdkContext(a)) if sdkDep.useModule && sdkDep.frameworkResModule != "" { ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule) @@ -641,9 +649,11 @@ func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) { var unzipAAR = pctx.AndroidStaticRule("unzipAAR", blueprint.RuleParams{ Command: `rm -rf $outDir && mkdir -p $outDir && ` + - `unzip -qoDD -d $outDir $in && rm -rf $outDir/res && touch $out`, + `unzip -qoDD -d $outDir $in && rm -rf $outDir/res && touch $out && ` + + `${config.MergeZipsCmd} $combinedClassesJar $$(ls $outDir/classes.jar 2> /dev/null) $$(ls $outDir/libs/*.jar 2> /dev/null)`, + CommandDeps: []string{"${config.MergeZipsCmd}"}, }, - "outDir") + "outDir", "combinedClassesJar") func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { if len(a.properties.Aars) != 1 { @@ -661,7 +671,7 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { } extractedAARDir := android.PathForModuleOut(ctx, "aar") - a.classpathFile = extractedAARDir.Join(ctx, "classes.jar") + a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar") a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt") a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml") @@ -671,7 +681,8 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest}, Description: "unzip AAR", Args: map[string]string{ - "outDir": extractedAARDir.String(), + "outDir": extractedAARDir.String(), + "combinedClassesJar": a.classpathFile.String(), }, }) @@ -746,7 +757,7 @@ func (a *AARImport) AidlIncludeDirs() android.Paths { return nil } -func (a *AARImport) ExportedSdkLibs() []string { +func (a *AARImport) ExportedSdkLibs() dexpreopt.LibraryPaths { return nil } diff --git a/java/android_manifest.go b/java/android_manifest.go index 8280cb1b1..f45ebe8d5 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -21,6 +21,7 @@ import ( "github.com/google/blueprint" "android/soong/android" + "android/soong/dexpreopt" ) var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer", @@ -52,7 +53,7 @@ var optionalUsesLibs = []string{ } // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml -func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string, +func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries dexpreopt.LibraryPaths, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path { var args []string @@ -79,7 +80,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext args = append(args, "--use-embedded-dex") } - for _, usesLib := range sdkLibraries { + for usesLib, _ := range sdkLibraries { if inList(usesLib, optionalUsesLibs) { args = append(args, "--optional-uses-library", usesLib) } else { @@ -130,7 +131,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext }, }) - return fixedManifest + return fixedManifest.WithoutRel() } func manifestMerger(ctx android.ModuleContext, manifest android.Path, staticLibManifests android.Paths, @@ -155,5 +156,5 @@ func manifestMerger(ctx android.ModuleContext, manifest android.Path, staticLibM }, }) - return mergedManifest + return mergedManifest.WithoutRel() } diff --git a/java/androidmk.go b/java/androidmk.go index 03994bfd6..2c02e5f38 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -121,20 +121,17 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile) } - entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs...) + entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", android.SortedStringKeys(library.exportedSdkLibs)...) if len(library.additionalCheckedModules) != 0 { entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...) } - if library.proguardDictionary != nil { - entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary) - } + entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", library.dexer.proguardDictionary) + entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", library.dexer.proguardUsageZip) entries.SetString("LOCAL_MODULE_STEM", library.Stem()) - entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", library.linter.outputs.transitiveHTMLZip) - entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", library.linter.outputs.transitiveTextZip) - entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", library.linter.outputs.transitiveXMLZip) + entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", library.linter.reports) }, }, } @@ -164,6 +161,7 @@ func (j *Test) AndroidMkEntries() []android.AndroidMkEntries { if j.testConfig != nil { entries.SetPath("LOCAL_FULL_TEST_CONFIG", j.testConfig) } + androidMkWriteExtraTestConfigs(j.extraTestConfigs, entries) androidMkWriteTestData(j.data, entries) if !BoolDefault(j.testProperties.Auto_gen_config, true) { entries.SetString("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", "true") @@ -173,6 +171,12 @@ func (j *Test) AndroidMkEntries() []android.AndroidMkEntries { return entriesList } +func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) { + if len(extraTestConfigs) > 0 { + entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...) + } +} + func (j *TestHelperLibrary) AndroidMkEntries() []android.AndroidMkEntries { entriesList := j.Library.AndroidMkEntries() entries := &entriesList[0] @@ -198,7 +202,7 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries { entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable)) entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile) - entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion().raw) + entries.SetString("LOCAL_SDK_VERSION", prebuilt.makeSdkVersion()) entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem()) }, }, @@ -334,9 +338,8 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { if app.jacocoReportClassesFile != nil { entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoReportClassesFile) } - if app.proguardDictionary != nil { - entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", app.proguardDictionary) - } + entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary) + entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", app.dexer.proguardUsageZip) if app.Name() == "framework-res" { entries.SetString("LOCAL_MODULE_PATH", "$(TARGET_OUT_JAVA_LIBRARIES)") @@ -394,9 +397,7 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { entries.AddStrings("LOCAL_SOONG_BUILT_INSTALLED", extra.String()+":"+install) } - entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", app.linter.outputs.transitiveHTMLZip) - entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", app.linter.outputs.transitiveTextZip) - entries.AddOptionalPath("LOCAL_SOONG_LINT_REPORTS", app.linter.outputs.transitiveXMLZip) + entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", app.linter.reports) }, }, ExtraFooters: []android.AndroidMkExtraFootersFunc{ @@ -437,6 +438,7 @@ func (a *AndroidTest) AndroidMkEntries() []android.AndroidMkEntries { if a.testConfig != nil { entries.SetPath("LOCAL_FULL_TEST_CONFIG", a.testConfig) } + androidMkWriteExtraTestConfigs(a.extraTestConfigs, entries) androidMkWriteTestData(a.data, entries) }) @@ -563,15 +565,21 @@ func (dstubs *Droidstubs) AndroidMkEntries() []android.AndroidMkEntries { // are created in make if only the api txt file is being generated. This is // needed because an invalid output file would prevent the make entries from // being written. + // + // Note that dstubs.apiFile can be also be nil if WITHOUT_CHECKS_API is true. // TODO(b/146727827): Revert when we do not need to generate stubs and API separately. - distFile := dstubs.apiFile + + var distFiles android.TaggedDistFiles + if dstubs.apiFile != nil { + distFiles = android.MakeDefaultDistFiles(dstubs.apiFile) + } outputFile := android.OptionalPathForPath(dstubs.stubsSrcJar) if !outputFile.Valid() { - outputFile = android.OptionalPathForPath(distFile) + outputFile = android.OptionalPathForPath(dstubs.apiFile) } return []android.AndroidMkEntries{android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", - DistFiles: android.MakeDefaultDistFiles(distFile), + DistFiles: distFiles, OutputFile: outputFile, Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ @@ -732,7 +740,7 @@ func (apkSet *AndroidAppSet) AndroidMkEntries() []android.AndroidMkEntries { ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(entries *android.AndroidMkEntries) { entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", apkSet.Privileged()) - entries.SetString("LOCAL_APK_SET_MASTER_FILE", apkSet.masterFile) + entries.SetString("LOCAL_APK_SET_INSTALL_FILE", apkSet.InstallFile()) entries.SetPath("LOCAL_APKCERTS_FILE", apkSet.apkcertsFile) entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...) }, diff --git a/java/app.go b/java/app.go index b4bc39e0f..900f6a6d7 100755 --- a/java/app.go +++ b/java/app.go @@ -78,7 +78,7 @@ type AndroidAppSet struct { properties AndroidAppSetProperties packedOutput android.WritablePath - masterFile string + installFile string apkcertsFile android.ModuleOutPath } @@ -102,8 +102,8 @@ func (as *AndroidAppSet) OutputFile() android.Path { return as.packedOutput } -func (as *AndroidAppSet) MasterFile() string { - return as.masterFile +func (as *AndroidAppSet) InstallFile() string { + return as.installFile } func (as *AndroidAppSet) APKCertsFile() android.Path { @@ -136,10 +136,10 @@ func SupportedAbis(ctx android.ModuleContext) []string { func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip") as.apkcertsFile = android.PathForModuleOut(ctx, "apkcerts.txt") - // We are assuming here that the master file in the APK + // We are assuming here that the install file in the APK // set has `.apk` suffix. If it doesn't the build will fail. // APK sets containing APEX files are handled elsewhere. - as.masterFile = as.BaseModuleName() + ".apk" + as.installFile = as.BaseModuleName() + ".apk" screenDensities := "all" if dpis := ctx.Config().ProductAAPTPrebuiltDPI(); len(dpis) > 0 { screenDensities = strings.ToUpper(strings.Join(dpis, ",")) @@ -167,7 +167,7 @@ func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) // android_app_set extracts a set of APKs based on the target device // configuration and installs this set as "split APKs". -// The extracted set always contains 'master' APK whose name is +// The extracted set always contains an APK whose name is // _module_name_.apk and every split APK matching target device. // The extraction of the density-specific splits depends on // PRODUCT_AAPT_PREBUILT_DPI variable. If present (its value should @@ -602,18 +602,20 @@ func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk") } -func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { +func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext, sdkLibs dexpreopt.LibraryPaths) android.Path { a.dexpreopter.installPath = a.installPath(ctx) - if a.deviceProperties.Uncompress_dex == nil { + if a.dexProperties.Uncompress_dex == nil { // If the value was not force-set by the user, use reasonable default based on the module. - a.deviceProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx)) + a.dexProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx)) } - a.dexpreopter.uncompressedDex = *a.deviceProperties.Uncompress_dex + a.dexpreopter.uncompressedDex = *a.dexProperties.Uncompress_dex a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries() a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx) a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx) + a.dexpreopter.libraryPaths.AddLibraryPaths(sdkLibs) a.dexpreopter.manifestFile = a.mergedManifestFile + a.exportedSdkLibs = make(dexpreopt.LibraryPaths) if ctx.ModuleName() != "framework-res" { a.Module.compile(ctx, a.aaptSrcJar) @@ -782,6 +784,15 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { // Process all building blocks, from AAPT to certificates. a.aaptBuildActions(ctx) + // The decision to enforce <uses-library> checks is made before adding implicit SDK libraries. + a.usesLibrary.freezeEnforceUsesLibraries() + + // Add implicit SDK libraries to <uses-library> list. + for _, usesLib := range android.SortedStringKeys(a.aapt.sdkLibraries) { + a.usesLibrary.addLib(usesLib, inList(usesLib, optionalUsesLibs)) + } + + // Check that the <uses-library> list is coherent with the manifest. if a.usesLibrary.enforceUsesLibraries() { manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(ctx, a.mergedManifestFile) apkDeps = append(apkDeps, manifestCheckFile) @@ -794,7 +805,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.linter.resources = a.aapt.resourceFiles a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps() - dexJarFile := a.dexBuildActions(ctx) + dexJarFile := a.dexBuildActions(ctx, a.aapt.sdkLibraries) jniLibs, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis)) jniJarFile := a.jniBuildActions(jniLibs, ctx) @@ -875,7 +886,7 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) - if IsJniDepTag(tag) || tag == cc.SharedDepTag { + if IsJniDepTag(tag) || cc.IsSharedDepTag(tag) { if dep, ok := module.(*cc.Module); ok { if dep.IsNdk() || dep.IsStubs() { return false @@ -993,6 +1004,8 @@ func (a *AndroidApp) OutputFiles(tag string) (android.Paths, error) { switch tag { case ".aapt.srcjar": return []android.Path{a.aaptSrcJar}, nil + case ".export-package.apk": + return []android.Path{a.exportPackage}, nil } return a.Library.OutputFiles(tag) } @@ -1025,8 +1038,8 @@ var _ cc.Coverage = (*AndroidApp)(nil) func AndroidAppFactory() android.Module { module := &AndroidApp{} - module.Module.deviceProperties.Optimize.EnabledByDefault = true - module.Module.deviceProperties.Optimize.Shrink = proptools.BoolPtr(true) + module.Module.dexProperties.Optimize.EnabledByDefault = true + module.Module.dexProperties.Optimize.Shrink = proptools.BoolPtr(true) module.Module.properties.Instrument = true module.Module.properties.Installable = proptools.BoolPtr(true) @@ -1061,8 +1074,9 @@ type AndroidTest struct { testProperties testProperties - testConfig android.Path - data android.Paths + testConfig android.Path + extraTestConfigs android.Paths + data android.Paths } func (a *AndroidTest) InstallInTestcases() bool { @@ -1090,6 +1104,7 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { testConfig := tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config, configs) a.testConfig = a.FixTestConfig(ctx, testConfig) + a.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs) a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data) } @@ -1140,7 +1155,7 @@ func (a *AndroidTest) OverridablePropertiesDepsMutator(ctx android.BottomUpMutat func AndroidTestFactory() android.Module { module := &AndroidTest{} - module.Module.deviceProperties.Optimize.EnabledByDefault = true + module.Module.dexProperties.Optimize.EnabledByDefault = true module.Module.properties.Instrument = true module.Module.properties.Installable = proptools.BoolPtr(true) @@ -1191,7 +1206,7 @@ func (a *AndroidTestHelperApp) InstallInTestcases() bool { func AndroidTestHelperAppFactory() android.Module { module := &AndroidTestHelperApp{} - module.Module.deviceProperties.Optimize.EnabledByDefault = true + module.Module.dexProperties.Optimize.EnabledByDefault = true module.Module.properties.Installable = proptools.BoolPtr(true) module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true) @@ -1913,6 +1928,16 @@ type usesLibrary struct { usesLibraryProperties UsesLibraryProperties } +func (u *usesLibrary) addLib(lib string, optional bool) { + if !android.InList(lib, u.usesLibraryProperties.Uses_libs) && !android.InList(lib, u.usesLibraryProperties.Optional_uses_libs) { + if optional { + u.usesLibraryProperties.Optional_uses_libs = append(u.usesLibraryProperties.Optional_uses_libs, lib) + } else { + u.usesLibraryProperties.Uses_libs = append(u.usesLibraryProperties.Uses_libs, lib) + } + } +} + func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs bool) { if !ctx.Config().UnbundledBuild() { ctx.AddVariationDependencies(nil, usesLibTag, u.usesLibraryProperties.Uses_libs...) @@ -1985,6 +2010,12 @@ func (u *usesLibrary) enforceUsesLibraries() bool { return BoolDefault(u.usesLibraryProperties.Enforce_uses_libs, defaultEnforceUsesLibs) } +// Freeze the value of `enforce_uses_libs` based on the current values of `uses_libs` and `optional_uses_libs`. +func (u *usesLibrary) freezeEnforceUsesLibraries() { + enforce := u.enforceUsesLibraries() + u.usesLibraryProperties.Enforce_uses_libs = &enforce +} + // verifyUsesLibrariesManifest checks the <uses-library> tags in an AndroidManifest.xml against the ones specified // in the uses_libs and optional_uses_libs properties. It returns the path to a copy of the manifest. func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path { diff --git a/java/app_test.go b/java/app_test.go index 6b83cd2e1..536797119 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -161,11 +161,11 @@ func TestAndroidAppSet(t *testing.T) { t.Errorf("wrong partition value: '%s', expected 'system'", s) } mkEntries := android.AndroidMkEntriesForTest(t, config, "", module.Module())[0] - actualMaster := mkEntries.EntryMap["LOCAL_APK_SET_MASTER_FILE"] - expectedMaster := []string{"foo.apk"} - if !reflect.DeepEqual(actualMaster, expectedMaster) { - t.Errorf("Unexpected LOCAL_APK_SET_MASTER_FILE value: '%s', expected: '%s',", - actualMaster, expectedMaster) + actualInstallFile := mkEntries.EntryMap["LOCAL_APK_SET_INSTALL_FILE"] + expectedInstallFile := []string{"foo.apk"} + if !reflect.DeepEqual(actualInstallFile, expectedInstallFile) { + t.Errorf("Unexpected LOCAL_APK_SET_INSTALL_FILE value: '%s', expected: '%s',", + actualInstallFile, expectedInstallFile) } } @@ -533,16 +533,6 @@ func TestUpdatableApps_JniLibShouldBeBuiltAgainstMinSdkVersion(t *testing.T) { system_shared_libs: [], sdk_version: "29", } - - ndk_prebuilt_object { - name: "ndk_crtbegin_so.29", - sdk_version: "29", - } - - ndk_prebuilt_object { - name: "ndk_crtend_so.29", - sdk_version: "29", - } ` fs := map[string][]byte{ "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtbegin_so.o": nil, @@ -555,16 +545,28 @@ func TestUpdatableApps_JniLibShouldBeBuiltAgainstMinSdkVersion(t *testing.T) { inputs := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").Description("link").Implicits var crtbeginFound, crtendFound bool + expectedCrtBegin := ctx.ModuleForTests("crtbegin_so", + "android_arm64_armv8-a_sdk_29").Rule("partialLd").Output + expectedCrtEnd := ctx.ModuleForTests("crtend_so", + "android_arm64_armv8-a_sdk_29").Rule("partialLd").Output + implicits := []string{} for _, input := range inputs { - switch input.String() { - case "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtbegin_so.o": + implicits = append(implicits, input.String()) + if strings.HasSuffix(input.String(), expectedCrtBegin.String()) { crtbeginFound = true - case "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtend_so.o": + } else if strings.HasSuffix(input.String(), expectedCrtEnd.String()) { crtendFound = true } } - if !crtbeginFound || !crtendFound { - t.Error("should link with ndk_crtbegin_so.29 and ndk_crtend_so.29") + if !crtbeginFound { + t.Error(fmt.Sprintf( + "expected implicit with suffix %q, have the following implicits:\n%s", + expectedCrtBegin, strings.Join(implicits, "\n"))) + } + if !crtendFound { + t.Error(fmt.Sprintf( + "expected implicit with suffix %q, have the following implicits:\n%s", + expectedCrtEnd, strings.Join(implicits, "\n"))) } } @@ -1038,6 +1040,35 @@ func TestAndroidResources(t *testing.T) { } } +func checkSdkVersion(t *testing.T, config android.Config, expectedSdkVersion string) { + ctx := testContext() + + run(t, ctx, config) + + foo := ctx.ModuleForTests("foo", "android_common") + link := foo.Output("package-res.apk") + linkFlags := strings.Split(link.Args["flags"], " ") + min := android.IndexList("--min-sdk-version", linkFlags) + target := android.IndexList("--target-sdk-version", linkFlags) + + if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 { + t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags) + } + + gotMinSdkVersion := linkFlags[min+1] + gotTargetSdkVersion := linkFlags[target+1] + + if gotMinSdkVersion != expectedSdkVersion { + t.Errorf("incorrect --min-sdk-version, expected %q got %q", + expectedSdkVersion, gotMinSdkVersion) + } + + if gotTargetSdkVersion != expectedSdkVersion { + t.Errorf("incorrect --target-sdk-version, expected %q got %q", + expectedSdkVersion, gotTargetSdkVersion) + } +} + func TestAppSdkVersion(t *testing.T) { testCases := []struct { name string @@ -1107,34 +1138,81 @@ func TestAppSdkVersion(t *testing.T) { config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal + checkSdkVersion(t, config, test.expectedMinSdkVersion) - ctx := testContext() - - run(t, ctx, config) - - foo := ctx.ModuleForTests("foo", "android_common") - link := foo.Output("package-res.apk") - linkFlags := strings.Split(link.Args["flags"], " ") - min := android.IndexList("--min-sdk-version", linkFlags) - target := android.IndexList("--target-sdk-version", linkFlags) - - if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 { - t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags) - } - - gotMinSdkVersion := linkFlags[min+1] - gotTargetSdkVersion := linkFlags[target+1] + }) + } + } +} - if gotMinSdkVersion != test.expectedMinSdkVersion { - t.Errorf("incorrect --min-sdk-version, expected %q got %q", - test.expectedMinSdkVersion, gotMinSdkVersion) - } +func TestVendorAppSdkVersion(t *testing.T) { + testCases := []struct { + name string + sdkVersion string + platformSdkInt int + platformSdkCodename string + platformSdkFinal bool + deviceCurrentApiLevelForVendorModules string + expectedMinSdkVersion string + }{ + { + name: "current final SDK", + sdkVersion: "current", + platformSdkInt: 29, + platformSdkCodename: "REL", + platformSdkFinal: true, + deviceCurrentApiLevelForVendorModules: "29", + expectedMinSdkVersion: "29", + }, + { + name: "current final SDK", + sdkVersion: "current", + platformSdkInt: 29, + platformSdkCodename: "REL", + platformSdkFinal: true, + deviceCurrentApiLevelForVendorModules: "28", + expectedMinSdkVersion: "28", + }, + { + name: "current final SDK", + sdkVersion: "current", + platformSdkInt: 29, + platformSdkCodename: "Q", + platformSdkFinal: false, + deviceCurrentApiLevelForVendorModules: "current", + expectedMinSdkVersion: "Q", + }, + { + name: "current final SDK", + sdkVersion: "current", + platformSdkInt: 29, + platformSdkCodename: "Q", + platformSdkFinal: false, + deviceCurrentApiLevelForVendorModules: "28", + expectedMinSdkVersion: "28", + }, + } - if gotTargetSdkVersion != test.expectedMinSdkVersion { - t.Errorf("incorrect --target-sdk-version, expected %q got %q", - test.expectedMinSdkVersion, gotTargetSdkVersion) - } - }) + for _, moduleType := range []string{"android_app", "android_library"} { + for _, sdkKind := range []string{"", "system_"} { + for _, test := range testCases { + t.Run(moduleType+" "+test.name, func(t *testing.T) { + bp := fmt.Sprintf(`%s { + name: "foo", + srcs: ["a.java"], + sdk_version: "%s%s", + vendor: true, + }`, moduleType, sdkKind, test.sdkVersion) + + config := testAppConfig(nil, bp, nil) + config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt + config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename + config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal + config.TestProductVariables.DeviceCurrentApiLevelForVendorModules = &test.deviceCurrentApiLevelForVendorModules + config.TestProductVariables.DeviceSystemSdkVersions = []string{"28", "29"} + checkSdkVersion(t, config, test.expectedMinSdkVersion) + }) + } } } } @@ -2663,10 +2741,37 @@ func TestUsesLibraries(t *testing.T) { sdk_version: "current", } + java_sdk_library { + name: "runtime-library", + srcs: ["a.java"], + sdk_version: "current", + } + + java_library { + name: "static-runtime-helper", + srcs: ["a.java"], + libs: ["runtime-library"], + sdk_version: "current", + } + android_app { name: "app", srcs: ["a.java"], + libs: ["qux", "quuz"], + static_libs: ["static-runtime-helper"], + uses_libs: ["foo"], + sdk_version: "current", + optional_uses_libs: [ + "bar", + "baz", + ], + } + + android_app { + name: "app_with_stub_deps", + srcs: ["a.java"], libs: ["qux", "quuz.stubs"], + static_libs: ["static-runtime-helper"], uses_libs: ["foo"], sdk_version: "current", optional_uses_libs: [ @@ -2695,15 +2800,15 @@ func TestUsesLibraries(t *testing.T) { run(t, ctx, config) app := ctx.ModuleForTests("app", "android_common") + appWithStubDeps := ctx.ModuleForTests("app_with_stub_deps", "android_common") prebuilt := ctx.ModuleForTests("prebuilt", "android_common") // Test that implicit dependencies on java_sdk_library instances are passed to the manifest. manifestFixerArgs := app.Output("manifest_fixer/AndroidManifest.xml").Args["args"] - if w := "--uses-library qux"; !strings.Contains(manifestFixerArgs, w) { - t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs) - } - if w := "--uses-library quuz"; !strings.Contains(manifestFixerArgs, w) { - t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs) + for _, w := range []string{"qux", "quuz", "runtime-library"} { + if !strings.Contains(manifestFixerArgs, "--uses-library "+w) { + t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs) + } } // Test that all libraries are verified @@ -2726,15 +2831,24 @@ func TestUsesLibraries(t *testing.T) { t.Errorf("wanted %q in %q", w, cmd) } - // Test that only present libraries are preopted + // Test that all present libraries are preopted, including implicit SDK dependencies cmd = app.Rule("dexpreopt").RuleParams.Command - - if w := `--target-classpath-for-sdk any /system/framework/foo.jar:/system/framework/bar.jar`; !strings.Contains(cmd, w) { + w := `--target-classpath-for-sdk any` + + ` /system/framework/foo.jar` + + `:/system/framework/quuz.jar` + + `:/system/framework/qux.jar` + + `:/system/framework/runtime-library.jar` + + `:/system/framework/bar.jar` + if !strings.Contains(cmd, w) { t.Errorf("wanted %q in %q", w, cmd) } - cmd = prebuilt.Rule("dexpreopt").RuleParams.Command + // TODO(skvadrik) fix dexpreopt for stub libraries for which the implementation is present + if appWithStubDeps.MaybeRule("dexpreopt").RuleParams.Command != "" { + t.Errorf("dexpreopt should be disabled for apps with dependencies on stub libraries") + } + cmd = prebuilt.Rule("dexpreopt").RuleParams.Command if w := `--target-classpath-for-sdk any /system/framework/foo.jar:/system/framework/bar.jar`; !strings.Contains(cmd, w) { t.Errorf("wanted %q in %q", w, cmd) } @@ -3005,6 +3119,7 @@ func TestUncompressDex(t *testing.T) { config := testAppConfig(nil, bp, nil) if unbundled { config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) + config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) } ctx := testContext() diff --git a/java/config/config.go b/java/config/config.go index 54a709c5e..31e2b0ffe 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -30,6 +30,8 @@ var ( LegacyCorePlatformBootclasspathLibraries = []string{"legacy.core.platform.api.stubs", "core-lambda-stubs"} LegacyCorePlatformSystemModules = "legacy-core-platform-api-stubs-system-modules" + StableCorePlatformBootclasspathLibraries = []string{"stable.core.platform.api.stubs", "core-lambda-stubs"} + StableCorePlatformSystemModules = "stable-core-platform-api-stubs-system-modules" FrameworkLibraries = []string{"ext", "framework"} DefaultLambdaStubsLibrary = "core-lambda-stubs" SdkLambdaStubsPath = "prebuilts/sdk/tools/core-lambda-stubs.jar" @@ -128,7 +130,7 @@ func init() { pctx.HostBinToolVariable("ExtractApksCmd", "extract_apks") pctx.VariableFunc("TurbineJar", func(ctx android.PackageVarContext) string { turbine := "turbine.jar" - if ctx.Config().UnbundledBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return "prebuilts/build-tools/common/framework/" + turbine } else { return ctx.Config().HostJavaToolPath(ctx, turbine).String() @@ -148,9 +150,9 @@ func init() { pctx.HostBinToolVariable("DexpreoptGen", "dexpreopt_gen") pctx.VariableFunc("REJavaPool", remoteexec.EnvOverrideFunc("RBE_JAVA_POOL", "java16")) - pctx.VariableFunc("REJavacExecStrategy", remoteexec.EnvOverrideFunc("RBE_JAVAC_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) - pctx.VariableFunc("RED8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_D8_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) - pctx.VariableFunc("RER8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_R8_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) + pctx.VariableFunc("REJavacExecStrategy", remoteexec.EnvOverrideFunc("RBE_JAVAC_EXEC_STRATEGY", remoteexec.RemoteLocalFallbackExecStrategy)) + pctx.VariableFunc("RED8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_D8_EXEC_STRATEGY", remoteexec.RemoteLocalFallbackExecStrategy)) + pctx.VariableFunc("RER8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_R8_EXEC_STRATEGY", remoteexec.RemoteLocalFallbackExecStrategy)) pctx.VariableFunc("RETurbineExecStrategy", remoteexec.EnvOverrideFunc("RBE_TURBINE_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) pctx.VariableFunc("RESignApkExecStrategy", remoteexec.EnvOverrideFunc("RBE_SIGNAPK_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) pctx.VariableFunc("REJarExecStrategy", remoteexec.EnvOverrideFunc("RBE_JAR_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) @@ -163,7 +165,7 @@ func init() { pctx.HostBinToolVariable("ManifestMergerCmd", "manifest-merger") - pctx.HostBinToolVariable("Class2Greylist", "class2greylist") + pctx.HostBinToolVariable("Class2NonSdkList", "class2nonsdklist") pctx.HostBinToolVariable("HiddenAPI", "hiddenapi") hostBinToolVariableWithSdkToolsPrebuilt("Aapt2Cmd", "aapt2") @@ -178,7 +180,7 @@ func init() { func hostBinToolVariableWithSdkToolsPrebuilt(name, tool string) { pctx.VariableFunc(name, func(ctx android.PackageVarContext) string { - if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return filepath.Join("prebuilts/sdk/tools", runtime.GOOS, "bin", tool) } else { return ctx.Config().HostToolPath(ctx, tool).String() @@ -188,7 +190,7 @@ func hostBinToolVariableWithSdkToolsPrebuilt(name, tool string) { func hostJavaToolVariableWithSdkToolsPrebuilt(name, tool string) { pctx.VariableFunc(name, func(ctx android.PackageVarContext) string { - if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return filepath.Join("prebuilts/sdk/tools/lib", tool+".jar") } else { return ctx.Config().HostJavaToolPath(ctx, tool+".jar").String() @@ -198,7 +200,7 @@ func hostJavaToolVariableWithSdkToolsPrebuilt(name, tool string) { func hostJNIToolVariableWithSdkToolsPrebuilt(name, tool string) { pctx.VariableFunc(name, func(ctx android.PackageVarContext) string { - if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { ext := ".so" if runtime.GOOS == "darwin" { ext = ".dylib" @@ -212,7 +214,7 @@ func hostJNIToolVariableWithSdkToolsPrebuilt(name, tool string) { func hostBinToolVariableWithBuildToolsPrebuilt(name, tool string) { pctx.VariableFunc(name, func(ctx android.PackageVarContext) string { - if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return filepath.Join("prebuilts/build-tools", ctx.Config().PrebuiltOS(), "bin", tool) } else { return ctx.Config().HostToolPath(ctx, tool).String() diff --git a/java/config/makevars.go b/java/config/makevars.go index 708a72aa4..df447a129 100644 --- a/java/config/makevars.go +++ b/java/config/makevars.go @@ -75,7 +75,7 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("ANDROID_MANIFEST_MERGER", "${ManifestMergerCmd}") - ctx.Strict("CLASS2GREYLIST", "${Class2Greylist}") + ctx.Strict("CLASS2NONSDKLIST", "${Class2NonSdkList}") ctx.Strict("HIDDENAPI", "${HiddenAPI}") ctx.Strict("DEX_FLAGS", "${DexFlags}") diff --git a/java/device_host_converter.go b/java/device_host_converter.go index 9191a8321..40a2280d9 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -19,6 +19,7 @@ import ( "io" "android/soong/android" + "android/soong/dexpreopt" ) type DeviceHostConverter struct { @@ -162,7 +163,7 @@ func (d *DeviceHostConverter) AidlIncludeDirs() android.Paths { return nil } -func (d *DeviceHostConverter) ExportedSdkLibs() []string { +func (d *DeviceHostConverter) ExportedSdkLibs() dexpreopt.LibraryPaths { return nil } diff --git a/java/dex.go b/java/dex.go index 9e61e95ad..c85914c41 100644 --- a/java/dex.go +++ b/java/dex.go @@ -24,6 +24,61 @@ import ( "android/soong/remoteexec" ) +type DexProperties struct { + // If set to true, compile dex regardless of installable. Defaults to false. + Compile_dex *bool + + // list of module-specific flags that will be used for dex compiles + Dxflags []string `android:"arch_variant"` + + Optimize struct { + // If false, disable all optimization. Defaults to true for android_app and android_test + // modules, false for java_library and java_test modules. + Enabled *bool + // True if the module containing this has it set by default. + EnabledByDefault bool `blueprint:"mutated"` + + // If true, optimize for size by removing unused code. Defaults to true for apps, + // false for libraries and tests. + Shrink *bool + + // If true, optimize bytecode. Defaults to false. + Optimize *bool + + // If true, obfuscate bytecode. Defaults to false. + Obfuscate *bool + + // If true, do not use the flag files generated by aapt that automatically keep + // classes referenced by the app manifest. Defaults to false. + No_aapt_flags *bool + + // Flags to pass to proguard. + Proguard_flags []string + + // Specifies the locations of files containing proguard flags. + Proguard_flags_files []string `android:"path"` + } + + // Keep the data uncompressed. We always need uncompressed dex for execution, + // so this might actually save space by avoiding storing the same data twice. + // This defaults to reasonable value based on module and should not be set. + // It exists only to support ART tests. + Uncompress_dex *bool +} + +type dexer struct { + dexProperties DexProperties + + // list of extra proguard flag files + extraProguardFlagFiles android.Paths + proguardDictionary android.OptionalPath + proguardUsageZip android.OptionalPath +} + +func (d *dexer) effectiveOptimizeEnabled() bool { + return BoolDefault(d.dexProperties.Optimize.Enabled, d.dexProperties.Optimize.EnabledByDefault) +} + var d8, d8RE = remoteexec.MultiCommandStaticRules(pctx, "d8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + @@ -55,13 +110,17 @@ var d8, d8RE = remoteexec.MultiCommandStaticRules(pctx, "d8", var r8, r8RE = remoteexec.MultiCommandStaticRules(pctx, "r8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + - `rm -f "$outDict" && ` + + `rm -f "$outDict" && rm -rf "${outUsageDir}" && ` + + `mkdir -p $$(dirname ${outUsage}) && ` + `$r8Template${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` + `--force-proguard-compatibility ` + `--no-data-resources ` + - `-printmapping $outDict ` + + `-printmapping ${outDict} ` + + `-printusage ${outUsage} ` + `$r8Flags && ` + - `touch "$outDict" && ` + + `touch "${outDict}" "${outUsage}" && ` + + `${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` + + `rm -rf ${outUsageDir} && ` + `$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + `${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`, CommandDeps: []string{ @@ -84,10 +143,18 @@ var r8, r8RE = remoteexec.MultiCommandStaticRules(pctx, "r8", ExecStrategy: "${config.RER8ExecStrategy}", Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, }, - }, []string{"outDir", "outDict", "r8Flags", "zipFlags"}, []string{"implicits"}) + "$zipUsageTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "${outUsage}"}, + OutputFiles: []string{"${outUsageZip}"}, + ExecStrategy: "${config.RER8ExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + }, []string{"outDir", "outDict", "outUsage", "outUsageZip", "outUsageDir", + "r8Flags", "zipFlags"}, []string{"implicits"}) -func (j *Module) dexCommonFlags(ctx android.ModuleContext) []string { - flags := j.deviceProperties.Dxflags +func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion sdkSpec) []string { + flags := d.dexProperties.Dxflags // Translate all the DX flags to D8 ones until all the build files have been migrated // to D8 flags. See: b/69377755 flags = android.RemoveListFromList(flags, @@ -103,30 +170,27 @@ func (j *Module) dexCommonFlags(ctx android.ModuleContext) []string { "--verbose") } - minSdkVersion, err := j.minSdkVersion().effectiveVersion(ctx) + effectiveVersion, err := minSdkVersion.effectiveVersion(ctx) if err != nil { ctx.PropertyErrorf("min_sdk_version", "%s", err) } - flags = append(flags, "--min-api "+minSdkVersion.asNumberString()) + flags = append(flags, "--min-api "+effectiveVersion.asNumberString()) return flags } -func (j *Module) d8Flags(ctx android.ModuleContext, flags javaBuilderFlags) ([]string, android.Paths) { - d8Flags := j.dexCommonFlags(ctx) - +func d8Flags(flags javaBuilderFlags) (d8Flags []string, d8Deps android.Paths) { d8Flags = append(d8Flags, flags.bootClasspath.FormRepeatedClassPath("--lib ")...) d8Flags = append(d8Flags, flags.classpath.FormRepeatedClassPath("--lib ")...) - var d8Deps android.Paths d8Deps = append(d8Deps, flags.bootClasspath...) d8Deps = append(d8Deps, flags.classpath...) return d8Flags, d8Deps } -func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Flags []string, r8Deps android.Paths) { - opt := j.deviceProperties.Optimize +func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Flags []string, r8Deps android.Paths) { + opt := d.dexProperties.Optimize // When an app contains references to APIs that are not in the SDK specified by // its LOCAL_SDK_VERSION for example added by support library or by runtime @@ -140,8 +204,6 @@ func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8F proguardRaiseDeps = append(proguardRaiseDeps, dep.(Dependency).HeaderJars()...) }) - r8Flags = append(r8Flags, j.dexCommonFlags(ctx)...) - r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars")) r8Flags = append(r8Flags, flags.bootClasspath.FormJavaClassPath("-libraryjars")) r8Flags = append(r8Flags, flags.classpath.FormJavaClassPath("-libraryjars")) @@ -154,15 +216,10 @@ func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8F android.PathForSource(ctx, "build/make/core/proguard.flags"), } - if j.shouldInstrumentStatic(ctx) { - flagFiles = append(flagFiles, - android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags")) - } - - flagFiles = append(flagFiles, j.extraProguardFlagFiles...) + flagFiles = append(flagFiles, d.extraProguardFlagFiles...) // TODO(ccross): static android library proguard files - flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, j.deviceProperties.Optimize.Proguard_flags_files)...) + flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, opt.Proguard_flags_files)...) r8Flags = append(r8Flags, android.JoinWithPrefix(flagFiles.Strings(), "-include ")) r8Deps = append(r8Deps, flagFiles...) @@ -171,7 +228,7 @@ func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8F r8Deps = append(r8Deps, android.PathForSource(ctx, "build/make/core/proguard_basic_keeps.flags")) - r8Flags = append(r8Flags, j.deviceProperties.Optimize.Proguard_flags...) + r8Flags = append(r8Flags, opt.Proguard_flags...) // TODO(ccross): Don't shrink app instrumentation tests by default. if !Bool(opt.Shrink) { @@ -197,46 +254,55 @@ func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8F return r8Flags, r8Deps } -func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, +func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, minSdkVersion sdkSpec, classesJar android.Path, jarName string) android.ModuleOutPath { - useR8 := j.deviceProperties.EffectiveOptimizeEnabled() - // Compile classes.jar into classes.dex and then javalib.jar javalibJar := android.PathForModuleOut(ctx, "dex", jarName) outDir := android.PathForModuleOut(ctx, "dex") zipFlags := "--ignore_missing_files" - if proptools.Bool(j.deviceProperties.Uncompress_dex) { + if proptools.Bool(d.dexProperties.Uncompress_dex) { zipFlags += " -L 0" } + commonFlags := d.dexCommonFlags(ctx, minSdkVersion) + + useR8 := d.effectiveOptimizeEnabled() if useR8 { proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary") - j.proguardDictionary = proguardDictionary - r8Flags, r8Deps := j.r8Flags(ctx, flags) + d.proguardDictionary = android.OptionalPathForPath(proguardDictionary) + proguardUsageDir := android.PathForModuleOut(ctx, "proguard_usage") + proguardUsage := proguardUsageDir.Join(ctx, ctx.Namespace().Path, + android.ModuleNameWithPossibleOverride(ctx), "unused.txt") + proguardUsageZip := android.PathForModuleOut(ctx, "proguard_usage.zip") + d.proguardUsageZip = android.OptionalPathForPath(proguardUsageZip) + r8Flags, r8Deps := d.r8Flags(ctx, flags) rule := r8 args := map[string]string{ - "r8Flags": strings.Join(r8Flags, " "), - "zipFlags": zipFlags, - "outDict": j.proguardDictionary.String(), - "outDir": outDir.String(), + "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "), + "zipFlags": zipFlags, + "outDict": proguardDictionary.String(), + "outUsageDir": proguardUsageDir.String(), + "outUsage": proguardUsage.String(), + "outUsageZip": proguardUsageZip.String(), + "outDir": outDir.String(), } if ctx.Config().IsEnvTrue("RBE_R8") { rule = r8RE args["implicits"] = strings.Join(r8Deps.Strings(), ",") } ctx.Build(pctx, android.BuildParams{ - Rule: rule, - Description: "r8", - Output: javalibJar, - ImplicitOutput: proguardDictionary, - Input: classesJar, - Implicits: r8Deps, - Args: args, + Rule: rule, + Description: "r8", + Output: javalibJar, + ImplicitOutputs: android.WritablePaths{proguardDictionary, proguardUsageZip}, + Input: classesJar, + Implicits: r8Deps, + Args: args, }) } else { - d8Flags, d8Deps := j.d8Flags(ctx, flags) + d8Flags, d8Deps := d8Flags(flags) rule := d8 if ctx.Config().IsEnvTrue("RBE_D8") { rule = d8RE @@ -248,13 +314,13 @@ func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, Input: classesJar, Implicits: d8Deps, Args: map[string]string{ - "d8Flags": strings.Join(d8Flags, " "), + "d8Flags": strings.Join(append(commonFlags, d8Flags...), " "), "zipFlags": zipFlags, "outDir": outDir.String(), }, }) } - if proptools.Bool(j.deviceProperties.Uncompress_dex) { + if proptools.Bool(d.dexProperties.Uncompress_dex) { alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", jarName) TransformZipAlign(ctx, alignedJavalibJar, javalibJar) javalibJar = alignedJavalibJar diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 41205598e..3addc1a74 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -49,8 +49,8 @@ type bootImageConfig struct { // Subdirectory where the image files are installed. installSubdir string - // The names of jars that constitute this image. - modules []string + // A list of (location, jar) pairs for the Java modules in this image. + modules android.ConfiguredJarList // File paths to jars. dexPaths android.WritablePaths // for this image @@ -113,16 +113,16 @@ func (image bootImageConfig) moduleName(ctx android.PathContext, idx int) string // Dexpreopt on the boot class path produces multiple files. The first dex file // is converted into 'name'.art (to match the legacy assumption that 'name'.art // exists), and the rest are converted to 'name'-<jar>.art. - _, m := android.SplitApexJarPair(ctx, image.modules[idx]) + m := image.modules.Jar(idx) name := image.stem if idx != 0 || image.extends != nil { - name += "-" + stemOf(m) + name += "-" + android.ModuleStem(m) } return name } func (image bootImageConfig) firstModuleNameOrStem(ctx android.PathContext) string { - if len(image.modules) > 0 { + if image.modules.Len() > 0 { return image.moduleName(ctx, 0) } else { return image.stem @@ -130,8 +130,8 @@ func (image bootImageConfig) firstModuleNameOrStem(ctx android.PathContext) stri } func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.OutputPath, exts ...string) android.OutputPaths { - ret := make(android.OutputPaths, 0, len(image.modules)*len(exts)) - for i := range image.modules { + ret := make(android.OutputPaths, 0, image.modules.Len()*len(exts)) + for i := 0; i < image.modules.Len(); i++ { name := image.moduleName(ctx, i) for _, ext := range exts { ret = append(ret, dir.Join(ctx, name+ext)) @@ -253,7 +253,7 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul } name := ctx.ModuleName(module) - index := android.IndexList(name, android.GetJarsFromApexJarPairs(ctx, image.modules)) + index := image.modules.IndexOfJar(name) if index == -1 { return -1, nil } @@ -262,7 +262,7 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul apex, isApexModule := module.(android.ApexModule) fromUpdatableApex := isApexModule && apex.Updatable() if image.name == artBootImageName { - if isApexModule && strings.HasPrefix(apex.ApexName(), "com.android.art.") { + if isApexModule && len(apex.InApexes()) > 0 && allHavePrefix(apex.InApexes(), "com.android.art.") { // ok: found the jar in the ART apex } else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) { // exception (skip and continue): special "hostdex" platform variant @@ -272,17 +272,17 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul return -1, nil } else if fromUpdatableApex { // error: this jar is part of an updatable apex other than ART - ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexName()) + ctx.Errorf("module %q from updatable apexes %q is not allowed in the ART boot image", name, apex.InApexes()) } else { // error: this jar is part of the platform or a non-updatable apex - ctx.Errorf("module '%s' is not allowed in the ART boot image", name) + ctx.Errorf("module %q is not allowed in the ART boot image", name) } } else if image.name == frameworkBootImageName { if !fromUpdatableApex { // ok: this jar is part of the platform or a non-updatable apex } else { // error: this jar is part of an updatable apex - ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the framework boot image", name, apex.ApexName()) + ctx.Errorf("module %q from updatable apexes %q is not allowed in the framework boot image", name, apex.InApexes()) } } else { panic("unknown boot image: " + image.name) @@ -291,11 +291,20 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul return index, jar.DexJarBuildPath() } +func allHavePrefix(list []string, prefix string) bool { + for _, s := range list { + if !strings.HasPrefix(s, prefix) { + return false + } + } + return true +} + // buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image. func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig { // Collect dex jar paths for the boot image modules. // This logic is tested in the apex package to avoid import cycle apex <-> java. - bootDexJars := make(android.Paths, len(image.modules)) + bootDexJars := make(android.Paths, image.modules.Len()) ctx.VisitAllModules(func(module android.Module) { if i, j := getBootImageJar(ctx, image, module); i != -1 { bootDexJars[i] = j @@ -306,7 +315,7 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI // Ensure all modules were converted to paths for i := range bootDexJars { if bootDexJars[i] == nil { - _, m := android.SplitApexJarPair(ctx, image.modules[i]) + m := image.modules.Jar(i) if ctx.Config().AllowMissingDependencies() { missingDeps = append(missingDeps, m) bootDexJars[i] = android.PathForOutput(ctx, "missing") @@ -505,7 +514,7 @@ func bootImageProfileRule(ctx android.SingletonContext, image *bootImageConfig, globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx) - if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() { + if global.DisableGenerateProfile || ctx.Config().UnbundledBuild() { return nil } profile := ctx.Config().Once(bootImageProfileRuleKey, func() interface{} { @@ -560,7 +569,7 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConf globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx) - if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() { + if global.DisableGenerateProfile || ctx.Config().UnbundledBuild() { return nil } return ctx.Config().Once(bootFrameworkProfileRuleKey, func() interface{} { @@ -602,13 +611,13 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConf var bootFrameworkProfileRuleKey = android.NewOnceKey("bootFrameworkProfileRule") func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath { - if ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() { + if ctx.Config().UnbundledBuild() { return nil } return ctx.Config().Once(updatableBcpPackagesRuleKey, func() interface{} { global := dexpreopt.GetGlobalConfig(ctx) - updatableModules := android.GetJarsFromApexJarPairs(ctx, global.UpdatableBootJars) + updatableModules := global.UpdatableBootJars.CopyOfJars() // Collect `permitted_packages` for updatable boot jars. var updatablePackages []string diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go index 9670c7f4b..4a8d3cd50 100644 --- a/java/dexpreopt_bootjars_test.go +++ b/java/dexpreopt_bootjars_test.go @@ -48,7 +48,7 @@ func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOu pathCtx := android.PathContextForTesting(config) dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx) - dexpreoptConfig.BootJars = []string{"platform:foo", "platform:bar", "platform:baz"} + dexpreoptConfig.BootJars = android.CreateConfiguredJarList(pathCtx, []string{"platform:foo", "platform:bar", "platform:baz"}) dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig) ctx := testContext() diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index f13d9f210..f0d82ff92 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -37,14 +37,12 @@ func systemServerClasspath(ctx android.MakeVarsContext) []string { filepath.Join("/system/framework", m+".jar")) } // 2) The jars that are from an updatable apex. - for _, m := range global.UpdatableSystemServerJars { - systemServerClasspathLocations = append(systemServerClasspathLocations, - dexpreopt.GetJarLocationFromApexJarPair(ctx, m)) - } - if len(systemServerClasspathLocations) != len(global.SystemServerJars)+len(global.UpdatableSystemServerJars) { + systemServerClasspathLocations = append(systemServerClasspathLocations, + global.UpdatableSystemServerJars.DevicePaths(ctx.Config(), android.Android)...) + if len(systemServerClasspathLocations) != len(global.SystemServerJars)+global.UpdatableSystemServerJars.Len() { panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d", len(systemServerClasspathLocations), - len(global.SystemServerJars)+len(global.UpdatableSystemServerJars))) + len(global.SystemServerJars)+global.UpdatableSystemServerJars.Len())) } return systemServerClasspathLocations }) @@ -69,39 +67,6 @@ func dexpreoptTargets(ctx android.PathContext) []android.Target { return targets } -func stemOf(moduleName string) string { - // b/139391334: the stem of framework-minus-apex is framework - // This is hard coded here until we find a good way to query the stem - // of a module before any other mutators are run - if moduleName == "framework-minus-apex" { - return "framework" - } - return moduleName -} - -func getDexLocation(ctx android.PathContext, target android.Target, module string) string { - apex, jar := android.SplitApexJarPair(ctx, module) - - name := stemOf(jar) + ".jar" - - var subdir string - if apex == "platform" { - // Special apex name "platform" denotes jars do not come from an apex, but are part - // of the platform. Such jars are installed on the /system partition on device. - subdir = "system/framework" - } else if apex == "system_ext" { - subdir = "system_ext/framework" - } else { - subdir = filepath.Join("apex", apex, "javalib") - } - - if target.Os.Class == android.Host { - return filepath.Join(ctx.Config().Getenv("OUT_DIR"), "host", ctx.Config().PrebuiltOS(), subdir, name) - } else { - return filepath.Join("/", subdir, name) - } -} - var ( bootImageConfigKey = android.NewOnceKey("bootImageConfig") artBootImageName = "art" @@ -116,12 +81,13 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig { targets := dexpreoptTargets(ctx) deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName()) - artModules := global.ArtApexJars + artModules := global.ArtApexJars.CopyOf() // With EMMA_INSTRUMENT_FRAMEWORK=true the Core libraries depend on jacoco. if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") { - artModules = append(artModules, "com.android.art:jacocoagent") + artModules.Append("com.android.art", "jacocoagent") } - frameworkModules := android.RemoveListFromList(global.BootJars, artModules) + frameworkModules := global.BootJars.CopyOf() + frameworkModules.RemoveList(artModules) artSubdir := "apex/com.android.art/javalib" frameworkSubdir := "system/framework" @@ -163,10 +129,7 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig { // Set up known paths for them, the singleton rules will copy them there. // TODO(b/143682396): use module dependencies instead inputDir := deviceDir.Join(ctx, "dex_"+c.name+"jars_input") - for _, m := range c.modules { - _, jar := android.SplitApexJarPair(ctx, m) - c.dexPaths = append(c.dexPaths, inputDir.Join(ctx, stemOf(jar)+".jar")) - } + c.dexPaths = c.modules.BuildPaths(ctx, inputDir) c.dexPathsDeps = c.dexPaths // Create target-specific variants. @@ -178,9 +141,7 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig { target: target, images: imageDir.Join(ctx, imageName), imagesDeps: c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex"), - } - for _, m := range c.modules { - variant.dexLocations = append(variant.dexLocations, getDexLocation(ctx, target, m)) + dexLocations: c.modules.DevicePaths(ctx.Config(), target.Os), } variant.dexLocationsDeps = variant.dexLocations c.variants = append(c.variants, variant) @@ -213,10 +174,7 @@ func defaultBootclasspath(ctx android.PathContext) []string { global := dexpreopt.GetGlobalConfig(ctx) image := defaultBootImageConfig(ctx) - updatableBootclasspath := make([]string, len(global.UpdatableBootJars)) - for i, p := range global.UpdatableBootJars { - updatableBootclasspath[i] = dexpreopt.GetJarLocationFromApexJarPair(ctx, p) - } + updatableBootclasspath := global.UpdatableBootJars.DevicePaths(ctx.Config(), android.Android) bootclasspath := append(copyOf(image.getAnyAndroidVariant().dexLocationsDeps), updatableBootclasspath...) return bootclasspath @@ -236,5 +194,5 @@ func dexpreoptConfigMakevars(ctx android.MakeVarsContext) { ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).getAnyAndroidVariant().dexLocationsDeps, ":")) ctx.Strict("PRODUCT_SYSTEM_SERVER_CLASSPATH", strings.Join(systemServerClasspath(ctx), ":")) - ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules, ":")) + ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules.CopyOfApexJarPairs(), ":")) } diff --git a/java/droiddoc.go b/java/droiddoc.go index fde18d5a5..3b192ba55 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -198,7 +198,7 @@ type DroiddocProperties struct { // the generated removed Dex API filename by Doclava. Removed_dex_api_filename *string - // if set to false, don't allow droiddoc to generate stubs source files. Defaults to true. + // if set to false, don't allow droiddoc to generate stubs source files. Defaults to false. Create_stubs *bool Check_api struct { @@ -294,6 +294,9 @@ type DroidstubsProperties struct { // the dirs which Metalava extracts API levels annotations from. Api_levels_annotations_dirs []string + // the filename which Metalava extracts API levels annotations from. Defaults to android.jar. + Api_levels_jar_filename *string + // if set to true, collect the values used by the Dev tools and // write them in files packaged with the SDK. Defaults to false. Write_sdk_values *bool @@ -870,6 +873,10 @@ func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.Rule } } +func (d *Droiddoc) createStubs() bool { + return BoolDefault(d.properties.Create_stubs, false) +} + func (d *Droiddoc) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) { if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || @@ -892,7 +899,7 @@ func (d *Droiddoc) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilde cmd.FlagWithOutput("-removedDexApi ", d.removedDexApiFile) } - if BoolDefault(d.properties.Create_stubs, true) { + if d.createStubs() { cmd.FlagWithArg("-stubs ", stubsDir.String()) } @@ -1074,9 +1081,7 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule.Build(pctx, ctx, "javadoc", desc) - if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") && - !ctx.Config().IsPdkBuild() { - + if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") { apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file)) removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file)) @@ -1143,9 +1148,7 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule.Build(pctx, ctx, "doclavaCurrentApiUpdate", "update current API") } - if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") && - !ctx.Config().IsPdkBuild() { - + if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") { apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file)) removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file)) @@ -1403,38 +1406,41 @@ func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *a } func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { - if Bool(d.properties.Api_levels_annotations_enabled) { - d.apiVersionsXml = android.PathForModuleOut(ctx, "api-versions.xml") + if !Bool(d.properties.Api_levels_annotations_enabled) { + return + } - if len(d.properties.Api_levels_annotations_dirs) == 0 { - ctx.PropertyErrorf("api_levels_annotations_dirs", - "has to be non-empty if api levels annotations was enabled!") - } + d.apiVersionsXml = android.PathForModuleOut(ctx, "api-versions.xml") + + if len(d.properties.Api_levels_annotations_dirs) == 0 { + ctx.PropertyErrorf("api_levels_annotations_dirs", + "has to be non-empty if api levels annotations was enabled!") + } - cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml) - cmd.FlagWithInput("--apply-api-levels ", d.apiVersionsXml) - cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion()) - cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename()) - - ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) { - if t, ok := m.(*ExportedDroiddocDir); ok { - for _, dep := range t.deps { - if strings.HasSuffix(dep.String(), "android.jar") { - cmd.Implicit(dep) - } + cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml) + cmd.FlagWithInput("--apply-api-levels ", d.apiVersionsXml) + cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion()) + cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename()) + + filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar") + + ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) { + if t, ok := m.(*ExportedDroiddocDir); ok { + for _, dep := range t.deps { + if strings.HasSuffix(dep.String(), filename) { + cmd.Implicit(dep) } - cmd.FlagWithArg("--android-jar-pattern ", t.dir.String()+"/%/public/android.jar") - } else { - ctx.PropertyErrorf("api_levels_annotations_dirs", - "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m)) } - }) - - } + cmd.FlagWithArg("--android-jar-pattern ", t.dir.String()+"/%/public/"+filename) + } else { + ctx.PropertyErrorf("api_levels_annotations_dirs", + "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m)) + } + }) } func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { - if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() && d.apiFile != nil { + if Bool(d.properties.Jdiff_enabled) && d.apiFile != nil { if d.apiFile.String() == "" { ctx.ModuleErrorf("API signature file has to be specified in Metalava when jdiff is enabled.") } @@ -1582,7 +1588,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Add API lint options. - if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) && !ctx.Config().IsPdkBuild() { + if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) { doApiLint = true newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since) @@ -1649,8 +1655,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Add "check released" options. (Detect incompatible API changes from the last public release) - if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") && - !ctx.Config().IsPdkBuild() { + if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") { doCheckReleased = true if len(d.Javadoc.properties.Out) > 0 { @@ -1683,7 +1688,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { impRule := android.NewRuleBuilder() impCmd := impRule.Command() - // A dummy action that copies the ninja generated rsp file to a new location. This allows us to + // An action that copies the ninja generated rsp file to a new location. This allows us to // add a large number of inputs to a file without exceeding bash command length limits (which // would happen if we use the WriteFile rule). The cp is needed because RuleBuilder sets the // rsp file to be ${output}.rsp. @@ -1727,8 +1732,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule.Build(pctx, ctx, "metalava", "metalava merged") - if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") && - !ctx.Config().IsPdkBuild() { + if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") { if len(d.Javadoc.properties.Out) > 0 { ctx.PropertyErrorf("out", "out property may not be combined with check_api") @@ -1842,7 +1846,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule.Build(pctx, ctx, "nullabilityWarningsCheck", "nullability warnings check") } - if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() { + if Bool(d.properties.Jdiff_enabled) { if len(d.Javadoc.properties.Out) > 0 { ctx.PropertyErrorf("out", "out property may not be combined with jdiff") } diff --git a/java/hiddenapi.go b/java/hiddenapi.go index b5a021785..63b801a5c 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -23,8 +23,8 @@ import ( ) var hiddenAPIGenerateCSVRule = pctx.AndroidStaticRule("hiddenAPIGenerateCSV", blueprint.RuleParams{ - Command: "${config.Class2Greylist} --stub-api-flags ${stubAPIFlags} $in $outFlag $out", - CommandDeps: []string{"${config.Class2Greylist}"}, + Command: "${config.Class2NonSdkList} --stub-api-flags ${stubAPIFlags} $in $outFlag $out", + CommandDeps: []string{"${config.Class2NonSdkList}"}, }, "outFlag", "stubAPIFlags") type hiddenAPI struct { diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index 857894958..29b6bcd7d 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -43,7 +43,7 @@ func hiddenAPISingletonPaths(ctx android.PathContext) hiddenAPISingletonPathsStr return hiddenAPISingletonPathsStruct{ flags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-flags.csv"), index: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-index.csv"), - metadata: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-greylist.csv"), + metadata: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-unsupported.csv"), stubFlags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-stub-flags.txt"), } }).(hiddenAPISingletonPathsStruct) @@ -100,7 +100,7 @@ func stubFlagsRule(ctx android.SingletonContext) { // Add the android.test.base to the set of stubs only if the android.test.base module is on // the boot jars list as the runtime will only enforce hiddenapi access against modules on // that list. - if inList("android.test.base", ctx.Config().BootJars()) && !ctx.Config().UnbundledBuildUsePrebuiltSdks() { + if inList("android.test.base", ctx.Config().BootJars()) && !ctx.Config().AlwaysUsePrebuiltSdks() { publicStubModules = append(publicStubModules, "android.test.base.stubs") } @@ -217,7 +217,7 @@ func moduleForGreyListRemovedApis(ctx android.SingletonContext, module android.M } // flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and -// the greylists. +// the unsupported API. func flagsRule(ctx android.SingletonContext) android.Path { var flagsCSV android.Paths var greylistRemovedApis android.Paths @@ -256,19 +256,19 @@ func flagsRule(ctx android.SingletonContext) android.Path { Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py")). FlagWithInput("--csv ", stubFlags). Inputs(flagsCSV). - FlagWithInput("--greylist ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist.txt")). - FlagWithInput("--greylist-ignore-conflicts ", combinedRemovedApis). - FlagWithInput("--greylist-max-q ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-q.txt")). - FlagWithInput("--greylist-max-p ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-p.txt")). - FlagWithInput("--greylist-max-o-ignore-conflicts ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-o.txt")). - FlagWithInput("--blacklist ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blacklist.txt")). - FlagWithInput("--greylist-packages ", - android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-packages.txt")). + FlagWithInput("--unsupported ", + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-unsupported.txt")). + FlagWithInput("--unsupported-ignore-conflicts ", combinedRemovedApis). + FlagWithInput("--max-target-q ", + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-max-target-q.txt")). + FlagWithInput("--max-target-p ", + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-max-target-p.txt")). + FlagWithInput("--max-target-o-ignore-conflicts ", + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-max-target-o.txt")). + FlagWithInput("--blocked ", + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blocked.txt")). + FlagWithInput("--unsupported-packages ", + android.PathForSource(ctx, "frameworks/base/config/hiddenapi-unsupported-packages.txt")). FlagWithOutput("--output ", tempPath) commitChangeForRestat(rule, tempPath, outputPath) @@ -293,7 +293,7 @@ func emptyFlagsRule(ctx android.SingletonContext) android.Path { return outputPath } -// metadataRule creates a rule to build hiddenapi-greylist.csv out of the metadata.csv files generated for boot image +// metadataRule creates a rule to build hiddenapi-unsupported.csv out of the metadata.csv files generated for boot image // modules. func metadataRule(ctx android.SingletonContext) android.Path { var metadataCSV android.Paths diff --git a/java/java.go b/java/java.go index ebff4e01b..79ad74a1f 100644 --- a/java/java.go +++ b/java/java.go @@ -29,6 +29,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/dexpreopt" "android/soong/java/config" "android/soong/tradefed" ) @@ -264,9 +265,6 @@ type CompilerProperties struct { } type CompilerDeviceProperties struct { - // list of module-specific flags that will be used for dex compiles - Dxflags []string `android:"arch_variant"` - // if not blank, set to the version of the sdk to compile against. // Defaults to compiling against the current platform. Sdk_version *string @@ -312,37 +310,6 @@ type CompilerDeviceProperties struct { } } - // If set to true, compile dex regardless of installable. Defaults to false. - Compile_dex *bool - - Optimize struct { - // If false, disable all optimization. Defaults to true for android_app and android_test - // modules, false for java_library and java_test modules. - Enabled *bool - // True if the module containing this has it set by default. - EnabledByDefault bool `blueprint:"mutated"` - - // If true, optimize for size by removing unused code. Defaults to true for apps, - // false for libraries and tests. - Shrink *bool - - // If true, optimize bytecode. Defaults to false. - Optimize *bool - - // If true, obfuscate bytecode. Defaults to false. - Obfuscate *bool - - // If true, do not use the flag files generated by aapt that automatically keep - // classes referenced by the app manifest. Defaults to false. - No_aapt_flags *bool - - // Flags to pass to proguard. - Proguard_flags []string - - // Specifies the locations of files containing proguard flags. - Proguard_flags_files []string `android:"path"` - } - // When targeting 1.9 and above, override the modules to use with --system, // otherwise provides defaults libraries to add to the bootclasspath. System_modules *string @@ -356,12 +323,6 @@ type CompilerDeviceProperties struct { // set the name of the output Stem *string - // Keep the data uncompressed. We always need uncompressed dex for execution, - // so this might actually save space by avoiding storing the same data twice. - // This defaults to reasonable value based on module and should not be set. - // It exists only to support ART tests. - Uncompress_dex *bool - IsSDKLibrary bool `blueprint:"mutated"` // If true, generate the signature file of APK Signing Scheme V4, along side the signed APK file. @@ -369,10 +330,6 @@ type CompilerDeviceProperties struct { V4_signature *bool } -func (me *CompilerDeviceProperties) EffectiveOptimizeEnabled() bool { - return BoolDefault(me.Optimize.Enabled, me.Optimize.EnabledByDefault) -} - // Functionality common to Module and Import // // It is embedded in Module so its functionality can be used by methods in Module @@ -441,9 +398,6 @@ type Module struct { // output file containing uninstrumented classes that will be instrumented by jacoco jacocoReportClassesFile android.Path - // output file containing mapping of obfuscated names - proguardDictionary android.Path - // output file of the module, which may be a classes jar or a dex jar outputFile android.Path extraOutputFiles android.Paths @@ -459,14 +413,11 @@ type Module struct { compiledJavaSrcs android.Paths compiledSrcJars android.Paths - // list of extra progurad flag files - extraProguardFlagFiles android.Paths - // manifest file to use instead of properties.Manifest overrideManifest android.OptionalPath - // list of SDK lib names that this java module is exporting - exportedSdkLibs []string + // map of SDK libs exported by this java module to their build and install paths + exportedSdkLibs dexpreopt.LibraryPaths // list of plugins that this java module is exporting exportedPluginJars android.Paths @@ -488,6 +439,7 @@ type Module struct { extraResources android.Paths hiddenAPI + dexer dexpreopter linter @@ -511,6 +463,7 @@ func (j *Module) addHostAndDeviceProperties() { j.addHostProperties() j.AddProperties( &j.deviceProperties, + &j.dexer.dexProperties, &j.dexpreoptProperties, &j.linter.properties, ) @@ -523,7 +476,10 @@ func (j *Module) OutputFiles(tag string) (android.Paths, error) { case ".jar": return android.Paths{j.implementationAndResourcesJar}, nil case ".proguard_map": - return android.Paths{j.proguardDictionary}, nil + if j.dexer.proguardDictionary.Valid() { + return android.Paths{j.dexer.proguardDictionary.Path()}, nil + } + return nil, fmt.Errorf("%q was requested, but no output file was found.", tag) default: return nil, fmt.Errorf("unsupported module reference tag %q", tag) } @@ -537,14 +493,19 @@ type ApexDependency interface { ImplementationAndResourcesJars() android.Paths } +// Provides build path and install path to DEX jars. +type UsesLibraryDependency interface { + DexJarBuildPath() android.Path + DexJarInstallPath() android.Path +} + type Dependency interface { ApexDependency + UsesLibraryDependency ImplementationJars() android.Paths ResourceJars() android.Paths - DexJarBuildPath() android.Path - DexJarInstallPath() android.Path AidlIncludeDirs() android.Paths - ExportedSdkLibs() []string + ExportedSdkLibs() dexpreopt.LibraryPaths ExportedPlugins() (android.Paths, []string) SrcJarArgs() ([]string, android.Paths) BaseModuleName() string @@ -560,7 +521,20 @@ func (j *Module) XrefJavaFiles() android.Paths { } func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) { - android.InitAndroidArchModule(module, hod, android.MultilibCommon) + initJavaModule(module, hod, false) +} + +func InitJavaModuleMultiTargets(module android.DefaultableModule, hod android.HostOrDeviceSupported) { + initJavaModule(module, hod, true) +} + +func initJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported, multiTargets bool) { + multilib := android.MultilibCommon + if multiTargets { + android.InitAndroidMultiTargetsArchModule(module, hod, multilib) + } else { + android.InitAndroidArchModule(module, hod, multilib) + } android.InitDefaultableModule(module) } @@ -579,6 +553,7 @@ func IsJniDepTag(depTag blueprint.DependencyTag) bool { } var ( + dataNativeBinsTag = dependencyTag{name: "dataNativeBins"} staticLibTag = dependencyTag{name: "staticlib"} libTag = dependencyTag{name: "javalib"} java9LibTag = dependencyTag{name: "java9lib"} @@ -587,7 +562,6 @@ var ( bootClasspathTag = dependencyTag{name: "bootclasspath"} systemModulesTag = dependencyTag{name: "system modules"} frameworkResTag = dependencyTag{name: "framework-res"} - frameworkApkTag = dependencyTag{name: "framework-apk"} kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib"} kotlinAnnotationsTag = dependencyTag{name: "kotlin-annotations"} proguardRaiseTag = dependencyTag{name: "proguard-raise"} @@ -718,22 +692,16 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...) ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...) - if j.deviceProperties.EffectiveOptimizeEnabled() && sdkDep.hasStandardLibs() { + if j.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() { ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...) } - if j.deviceProperties.EffectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() { + if j.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() { ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...) } } if sdkDep.systemModules != "" { ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules) } - - if ctx.ModuleName() == "android_stubs_current" || - ctx.ModuleName() == "android_system_stubs_current" || - ctx.ModuleName() == "android_test_stubs_current" { - ctx.AddVariationDependencies(nil, frameworkApkTag, "framework-res") - } } syspropPublicStubs := syspropPublicStubs(ctx.Config()) @@ -1008,12 +976,6 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } } - // If this is a component library (stubs, etc.) for a java_sdk_library then - // add the name of that java_sdk_library to the exported sdk libs to make sure - // that, if necessary, a <uses-library> element for that java_sdk_library is - // added to the Android manifest. - j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...) - ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -1033,7 +995,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case libTag: deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) // names of sdk libs that are directly depended are exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.OptionalImplicitSdkLibrary()...) + j.exportedSdkLibs.MaybeAddLibraryPath(ctx, dep.OptionalImplicitSdkLibrary(), dep.DexJarBuildPath(), dep.DexJarInstallPath()) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } @@ -1044,7 +1006,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case libTag, instrumentationForTag: deps.classpath = append(deps.classpath, dep.HeaderJars()...) // sdk lib names from dependencies are re-exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) + j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs()) deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) pluginJars, pluginClasses := dep.ExportedPlugins() addPlugins(&deps, pluginJars, pluginClasses...) @@ -1056,7 +1018,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...) deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...) // sdk lib names from dependencies are re-exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) + j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs()) deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) pluginJars, pluginClasses := dep.ExportedPlugins() addPlugins(&deps, pluginJars, pluginClasses...) @@ -1083,18 +1045,6 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } else { ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName) } - case frameworkApkTag: - if ctx.ModuleName() == "android_stubs_current" || - ctx.ModuleName() == "android_system_stubs_current" || - ctx.ModuleName() == "android_test_stubs_current" { - // framework stubs.jar need to depend on framework-res.apk, in order to pull the - // resource files out of there for aapt. - // - // Normally the package rule runs aapt, which includes the resource, - // but we're not running that in our package rule so just copy in the - // resource files here. - deps.staticResourceJars = append(deps.staticResourceJars, dep.(*AndroidApp).exportPackage) - } case kotlinStdlibTag: deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars()...) case kotlinAnnotationsTag: @@ -1131,8 +1081,6 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } }) - j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs) - return deps } @@ -1637,8 +1585,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // Enable dex compilation for the APEX variants, unless it is disabled explicitly if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !j.IsForPlatform() { - if j.deviceProperties.Compile_dex == nil { - j.deviceProperties.Compile_dex = proptools.BoolPtr(true) + if j.dexProperties.Compile_dex == nil { + j.dexProperties.Compile_dex = proptools.BoolPtr(true) } if j.deviceProperties.Hostdex == nil { j.deviceProperties.Hostdex = proptools.BoolPtr(true) @@ -1646,10 +1594,14 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } if ctx.Device() && j.hasCode(ctx) && - (Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) { + (Bool(j.properties.Installable) || Bool(j.dexProperties.Compile_dex)) { + if j.shouldInstrumentStatic(ctx) { + j.dexer.extraProguardFlagFiles = append(j.dexer.extraProguardFlagFiles, + android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags")) + } // Dex compilation var dexOutputFile android.ModuleOutPath - dexOutputFile = j.compileDex(ctx, flags, outputFile, jarName) + dexOutputFile = j.dexer.compileDex(ctx, flags, j.minSdkVersion(), outputFile, jarName) if ctx.Failed() { return } @@ -1659,7 +1611,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // Hidden API CSV generation and dex encoding dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile, - proptools.Bool(j.deviceProperties.Uncompress_dex)) + proptools.Bool(j.dexProperties.Uncompress_dex)) // merge dex jar with resources if necessary if j.resourceJar != nil { @@ -1667,7 +1619,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { combinedJar := android.PathForModuleOut(ctx, "dex-withres", jarName) TransformJarsToJar(ctx, combinedJar, "for dex resources", jars, android.OptionalPath{}, false, nil, nil) - if *j.deviceProperties.Uncompress_dex { + if *j.dexProperties.Uncompress_dex { combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName) TransformZipAlign(ctx, combinedAlignedJar, combinedJar) dexOutputFile = combinedAlignedJar @@ -1711,6 +1663,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.linter.compileSdkVersion = lintSDKVersionString(j.sdkVersion()) j.linter.javaLanguageLevel = flags.javaVersion.String() j.linter.kotlinLanguageLevel = "1.3" + if j.ApexVariationName() != "" && ctx.Config().UnbundledBuildApps() { + j.linter.buildModuleReportZip = true + } j.linter.lint(ctx) } @@ -1866,8 +1821,7 @@ func (j *Module) AidlIncludeDirs() android.Paths { return j.exportAidlIncludeDirs } -func (j *Module) ExportedSdkLibs() []string { - // exportedSdkLibs is type []string +func (j *Module) ExportedSdkLibs() dexpreopt.LibraryPaths { return j.exportedSdkLibs } @@ -1995,11 +1949,12 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.checkSdkVersions(ctx) j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar") j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary - if j.deviceProperties.Uncompress_dex == nil { + if j.dexProperties.Uncompress_dex == nil { // If the value was not force-set by the user, use reasonable default based on the module. - j.deviceProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter)) + j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter)) } - j.dexpreopter.uncompressedDex = *j.deviceProperties.Uncompress_dex + j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex + j.exportedSdkLibs = make(dexpreopt.LibraryPaths) j.compile(ctx, nil) // Collect the module directory for IDE info in java/jdeps.go. @@ -2015,6 +1970,12 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.Stem()+".jar", j.outputFile, extraInstallDeps...) } + // If this is a component library (stubs, etc.) for a java_sdk_library then + // add the name of that java_sdk_library to the exported sdk libs to make sure + // that, if necessary, a <uses-library> element for that java_sdk_library is + // added to the Android manifest. + j.exportedSdkLibs.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), j.DexJarBuildPath(), j.DexJarInstallPath()) + j.distFiles = j.GenerateTaggedDistFiles(ctx) } @@ -2167,6 +2128,12 @@ func LibraryHostFactory() android.Module { // Java Tests // +// Test option struct. +type TestOptions struct { + // a list of extra test configuration files that should be installed with the module. + Extra_test_configs []string `android:"path,arch_variant"` +} + type testProperties struct { // list of compatibility suites (for example "cts", "vts") that the module should be // installed into. @@ -2192,6 +2159,14 @@ type testProperties struct { // Add parameterized mainline modules to auto generated test config. The options will be // handled by TradeFed to do downloading and installing the specified modules on the device. Test_mainline_modules []string + + // Test options. + Test_options TestOptions +} + +type hostTestProperties struct { + // list of native binary modules that should be installed alongside the test + Data_native_bins []string `android:"arch_variant"` } type testHelperLibraryProperties struct { @@ -2215,8 +2190,15 @@ type Test struct { testProperties testProperties - testConfig android.Path - data android.Paths + testConfig android.Path + extraTestConfigs android.Paths + data android.Paths +} + +type TestHost struct { + Test + + testHostProperties hostTestProperties } type TestHelperLibrary struct { @@ -2233,11 +2215,28 @@ type JavaTestImport struct { testConfig android.Path } +func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) { + if len(j.testHostProperties.Data_native_bins) > 0 { + for _, target := range ctx.MultiTargets() { + ctx.AddVariationDependencies(target.Variations(), dataNativeBinsTag, j.testHostProperties.Data_native_bins...) + } + } + + j.deps(ctx) +} + func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template, j.testProperties.Test_suites, j.testProperties.Auto_gen_config) + j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data) + j.extraTestConfigs = android.PathsForModuleSrc(ctx, j.testProperties.Test_options.Extra_test_configs) + + ctx.VisitDirectDepsWithTag(dataNativeBinsTag, func(dep android.Module) { + j.data = append(j.data, android.OutputFileForModule(ctx, dep, "")) + }) + j.Library.GenerateAndroidBuildActions(ctx) } @@ -2378,14 +2377,15 @@ func JavaTestImportFactory() android.Module { // A java_test_host has a single variant that produces a `.jar` file containing `.class` files that were // compiled against the host bootclasspath. func TestHostFactory() android.Module { - module := &Test{} + module := &TestHost{} module.addHostProperties() module.AddProperties(&module.testProperties) + module.AddProperties(&module.testHostProperties) module.Module.properties.Installable = proptools.BoolPtr(true) - InitJavaModule(module, android.HostSupported) + InitJavaModuleMultiTargets(module, android.HostSupported) return module } @@ -2538,7 +2538,7 @@ type Import struct { properties ImportProperties combinedClasspathFile android.Path - exportedSdkLibs []string + exportedSdkLibs dexpreopt.LibraryPaths exportAidlIncludeDirs android.Paths } @@ -2546,6 +2546,10 @@ func (j *Import) sdkVersion() sdkSpec { return sdkSpecFrom(String(j.properties.Sdk_version)) } +func (j *Import) makeSdkVersion() string { + return j.sdkVersion().raw +} + func (j *Import) minSdkVersion() sdkSpec { return j.sdkVersion() } @@ -2591,12 +2595,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { TransformJetifier(ctx, outputFile, inputFile) } j.combinedClasspathFile = outputFile - - // If this is a component library (impl, stubs, etc.) for a java_sdk_library then - // add the name of that java_sdk_library to the exported sdk libs to make sure - // that, if necessary, a <uses-library> element for that java_sdk_library is - // added to the Android manifest. - j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...) + j.exportedSdkLibs = make(dexpreopt.LibraryPaths) ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) @@ -2607,23 +2606,29 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { switch tag { case libTag, staticLibTag: // sdk lib names from dependencies are re-exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) + j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs()) } case SdkLibraryDependency: switch tag { case libTag: // names of sdk libs that are directly depended are exported - j.exportedSdkLibs = append(j.exportedSdkLibs, otherName) + j.exportedSdkLibs.AddLibraryPath(ctx, otherName, dep.DexJarBuildPath(), dep.DexJarInstallPath()) } } }) - j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs) + var installFile android.Path if Bool(j.properties.Installable) { - ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), + installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), jarName, outputFile) } + // If this is a component library (impl, stubs, etc.) for a java_sdk_library then + // add the name of that java_sdk_library to the exported sdk libs to make sure + // that, if necessary, a <uses-library> element for that java_sdk_library is + // added to the Android manifest. + j.exportedSdkLibs.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), outputFile, installFile) + j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs) } @@ -2666,7 +2671,7 @@ func (j *Import) AidlIncludeDirs() android.Paths { return j.exportAidlIncludeDirs } -func (j *Import) ExportedSdkLibs() []string { +func (j *Import) ExportedSdkLibs() dexpreopt.LibraryPaths { return j.exportedSdkLibs } @@ -2793,6 +2798,10 @@ func (a *DexImport) JacocoReportClassesFile() android.Path { return nil } +func (a *DexImport) LintDepSets() LintDepSets { + return LintDepSets{} +} + func (j *DexImport) IsInstallable() bool { return true } @@ -2926,6 +2935,7 @@ func DefaultsFactory() android.Module { module.AddProperties( &CompilerProperties{}, &CompilerDeviceProperties{}, + &DexProperties{}, &DexpreoptProperties{}, &android.ProtoProperties{}, &aaptProperties{}, diff --git a/java/java_test.go b/java/java_test.go index db3f18740..0e936118c 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -20,7 +20,6 @@ import ( "path/filepath" "reflect" "regexp" - "sort" "strconv" "strings" "testing" @@ -31,6 +30,7 @@ import ( "android/soong/cc" "android/soong/dexpreopt" "android/soong/genrule" + "android/soong/python" ) var buildDir string @@ -81,6 +81,7 @@ func testContext() *android.TestContext { ctx.RegisterModuleType("java_plugin", PluginFactory) ctx.RegisterModuleType("filegroup", android.FileGroupFactory) ctx.RegisterModuleType("genrule", genrule.GenRuleFactory) + ctx.RegisterModuleType("python_binary_host", python.PythonBinaryHostFactory) RegisterDocsBuildComponents(ctx) RegisterStubsBuildComponents(ctx) RegisterSdkLibraryBuildComponents(ctx) @@ -89,10 +90,13 @@ func testContext() *android.TestContext { RegisterPrebuiltApisBuildComponents(ctx) + ctx.PreDepsMutators(python.RegisterPythonPreDepsMutators) ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators) ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory)) ctx.RegisterPreSingletonType("sdk_versions", android.SingletonFactoryAdaptor(sdkPreSingletonFactory)) + android.RegisterPrebuiltMutators(ctx) + // Register module types and mutators from cc needed for JNI testing cc.RegisterRequiredBuildComponentsForTest(ctx) @@ -486,7 +490,7 @@ func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) { ctx, _ := testJavaWithConfig(t, config) - // first, sanity check that the -g flag is added to target modules + // first, check that the -g flag is added to target modules targetLibrary := ctx.ModuleForTests("target_library", "android_common") targetJavaFlags := targetLibrary.Module().VariablesForTests()["javacFlags"] if !strings.Contains(targetJavaFlags, "-g:source,lines") { @@ -1104,8 +1108,13 @@ func TestDroiddoc(t *testing.T) { "bar-doc/a.java": nil, "bar-doc/b.java": nil, }) + barDocModule := ctx.ModuleForTests("bar-doc", "android_common") + barDoc := barDocModule.Rule("javadoc") + notExpected := " -stubs " + if strings.Contains(barDoc.RuleParams.Command, notExpected) { + t.Errorf("bar-doc command contains flag %q to create stubs, but should not", notExpected) + } - barDoc := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc") var javaSrcs []string for _, i := range barDoc.Inputs { javaSrcs = append(javaSrcs, i.Base()) @@ -1114,7 +1123,7 @@ func TestDroiddoc(t *testing.T) { t.Errorf("inputs of bar-doc must be []string{\"a.java\"}, but was %#v.", javaSrcs) } - aidl := ctx.ModuleForTests("bar-doc", "android_common").Rule("aidl") + aidl := barDocModule.Rule("aidl") if g, w := barDoc.Implicits.Strings(), aidl.Output.String(); !inList(w, g) { t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g) } @@ -1160,6 +1169,62 @@ func TestDroiddocArgsAndFlagsCausesError(t *testing.T) { `) } +func TestDroidstubs(t *testing.T) { + ctx, _ := testJavaWithFS(t, ` + droiddoc_exported_dir { + name: "droiddoc-templates-sdk", + path: ".", + } + + droidstubs { + name: "bar-stubs", + srcs: [ + "bar-doc/a.java", + ], + api_levels_annotations_dirs: [ + "droiddoc-templates-sdk", + ], + api_levels_annotations_enabled: true, + } + + droidstubs { + name: "bar-stubs-other", + srcs: [ + "bar-doc/a.java", + ], + api_levels_annotations_dirs: [ + "droiddoc-templates-sdk", + ], + api_levels_annotations_enabled: true, + api_levels_jar_filename: "android.other.jar", + } + `, + map[string][]byte{ + "bar-doc/a.java": nil, + }) + testcases := []struct { + moduleName string + expectedJarFilename string + }{ + { + moduleName: "bar-stubs", + expectedJarFilename: "android.jar", + }, + { + moduleName: "bar-stubs-other", + expectedJarFilename: "android.other.jar", + }, + } + for _, c := range testcases { + m := ctx.ModuleForTests(c.moduleName, "android_common") + metalava := m.Rule("metalava") + expected := "--android-jar-pattern ./%/public/" + c.expectedJarFilename + if actual := metalava.RuleParams.Command; !strings.Contains(actual, expected) { + t.Errorf("For %q, expected metalava argument %q, but was not found %q", c.moduleName, expected, actual) + } + } +} + func TestDroidstubsWithSystemModules(t *testing.T) { ctx, _ := testJava(t, ` droidstubs { @@ -1430,8 +1495,7 @@ func TestJavaSdkLibrary(t *testing.T) { // test if baz has exported SDK lib names foo and bar to qux qux := ctx.ModuleForTests("qux", "android_common") if quxLib, ok := qux.Module().(*Library); ok { - sdkLibs := quxLib.ExportedSdkLibs() - sort.Strings(sdkLibs) + sdkLibs := android.SortedStringKeys(quxLib.ExportedSdkLibs()) if w := []string{"bar", "foo", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) { t.Errorf("qux should export %q but exports %q", w, sdkLibs) } @@ -2008,3 +2072,28 @@ func TestAidlExportIncludeDirsFromImports(t *testing.T) { t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag) } } + +func TestDataNativeBinaries(t *testing.T) { + ctx, config := testJava(t, ` + java_test_host { + name: "foo", + srcs: ["a.java"], + data_native_bins: ["bin"] + } + + python_binary_host { + name: "bin", + srcs: ["bin.py"], + } + `) + + buildOS := android.BuildOs.String() + + test := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost) + entries := android.AndroidMkEntriesForTest(t, config, "", test)[0] + expected := []string{buildDir + "/.intermediates/bin/" + buildOS + "_x86_64_PY3/bin:bin"} + actual := entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"] + if !reflect.DeepEqual(expected, actual) { + t.Errorf("Unexpected test data - expected: %q, actual: %q", expected, actual) + } +} diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go new file mode 100644 index 000000000..021920af6 --- /dev/null +++ b/java/legacy_core_platform_api_usage.go @@ -0,0 +1,174 @@ +// Copyright 2020 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 java + +import ( + "android/soong/android" + "android/soong/java/config" +) + +// This variable is effectively unused in pre-master branches, and is +// included (with the same value as it has in AOSP) only to ease +// merges between branches (see the comment in the +// useLegacyCorePlatformApi() function): +var legacyCorePlatformApiModules = []string{ + "ahat-test-dump", + "android.car", + "android.test.mock", + "android.test.mock.impl", + "AoapTestDeviceApp", + "AoapTestHostApp", + "api-stubs-docs", + "art_cts_jvmti_test_library", + "art-gtest-jars-MyClassNatives", + "BackupFrameworksServicesRoboTests", + "BandwidthEnforcementTest", + "BlockedNumberProvider", + "BluetoothInstrumentationTests", + "BluetoothMidiService", + "car-apps-common", + "CertInstaller", + "ConnectivityManagerTest", + "ContactsProvider", + "core-tests-support", + "CtsContentTestCases", + "CtsIkeTestCases", + "CtsLibcoreWycheproofBCTestCases", + "CtsMediaTestCases", + "CtsNetTestCases", + "CtsNetTestCasesLatestSdk", + "CtsSecurityTestCases", + "CtsUsageStatsTestCases", + "DisplayCutoutEmulationEmu01Overlay", + "DocumentsUIPerfTests", + "DocumentsUITests", + "DownloadProvider", + "DownloadProviderTests", + "DownloadProviderUi", + "DynamicSystemInstallationService", + "EmergencyInfo-lib", + "ethernet-service", + "EthernetServiceTests", + "ExternalStorageProvider", + "ExtServices", + "ExtServices-core", + "framework-all", + "framework-minus-apex", + "FrameworksCoreTests", + "FrameworksIkeTests", + "FrameworksNetCommonTests", + "FrameworksNetTests", + "FrameworksServicesRoboTests", + "FrameworksServicesTests", + "FrameworksUtilTests", + "hid", + "hidl_test_java_java", + "hwbinder", + "ims", + "KeyChain", + "ksoap2", + "LocalTransport", + "lockagent", + "mediaframeworktest", + "MediaProvider", + "MmsService", + "MtpDocumentsProvider", + "MultiDisplayProvider", + "NetworkStackIntegrationTestsLib", + "NetworkStackNextIntegrationTests", + "NetworkStackNextTests", + "NetworkStackTests", + "NetworkStackTestsLib", + "NfcNci", + "platform_library-docs", + "PrintSpooler", + "RollbackTest", + "services", + "services.accessibility", + "services.backup", + "services.core.unboosted", + "services.devicepolicy", + "services.print", + "services.usage", + "services.usb", + "Settings-core", + "SettingsLib", + "SettingsProvider", + "SettingsProviderTest", + "SettingsRoboTests", + "Shell", + "ShellTests", + "sl4a.Common", + "StatementService", + "SystemUI-core", + "SystemUISharedLib", + "SystemUI-tests", + "Telecom", + "TelecomUnitTests", + "telephony-common", + "TelephonyProvider", + "TelephonyProviderTests", + "TeleService", + "testables", + "TetheringTests", + "TetheringTestsLib", + "time_zone_distro_installer", + "time_zone_distro_installer-tests", + "time_zone_distro-tests", + "time_zone_updater", + "TvProvider", + "uiautomator-stubs-docs", + "UsbHostExternalManagementTestApp", + "UserDictionaryProvider", + "WallpaperBackup", + "wifi-service", +} + +// This variable is effectively unused in pre-master branches, and is +// included (with the same value as it has in AOSP) only to ease +// merges between branches (see the comment in the +// useLegacyCorePlatformApi() function): +var legacyCorePlatformApiLookup = make(map[string]struct{}) + +func init() { + for _, module := range legacyCorePlatformApiModules { + legacyCorePlatformApiLookup[module] = struct{}{} + } +} + +func useLegacyCorePlatformApi(ctx android.EarlyModuleContext) bool { + // In pre-master branches, we don't attempt to force usage of the stable + // version of the core/platform API. Instead, we always use the legacy + // version --- except in tests, where we always use stable, so that we + // can make the test assertions the same as other branches. + // This should be false in tests and true otherwise: + return ctx.Config().TestProductVariables == nil +} + +func corePlatformSystemModules(ctx android.EarlyModuleContext) string { + if useLegacyCorePlatformApi(ctx) { + return config.LegacyCorePlatformSystemModules + } else { + return config.StableCorePlatformSystemModules + } +} + +func corePlatformBootclasspathLibraries(ctx android.EarlyModuleContext) []string { + if useLegacyCorePlatformApi(ctx) { + return config.LegacyCorePlatformBootclasspathLibraries + } else { + return config.StableCorePlatformBootclasspathLibraries + } +} diff --git a/java/lint.go b/java/lint.go index 20a7dc49f..3a210cc0b 100644 --- a/java/lint.go +++ b/java/lint.go @@ -17,6 +17,7 @@ package java import ( "fmt" "sort" + "strings" "android/soong/android" ) @@ -68,28 +69,78 @@ type linter struct { outputs lintOutputs properties LintProperties + reports android.Paths + buildModuleReportZip bool } type lintOutputs struct { - html android.ModuleOutPath - text android.ModuleOutPath - xml android.ModuleOutPath - - transitiveHTML *android.DepSet - transitiveText *android.DepSet - transitiveXML *android.DepSet + html android.Path + text android.Path + xml android.Path - transitiveHTMLZip android.OptionalPath - transitiveTextZip android.OptionalPath - transitiveXMLZip android.OptionalPath + depSets LintDepSets } -type lintOutputIntf interface { +type lintOutputsIntf interface { lintOutputs() *lintOutputs } -var _ lintOutputIntf = (*linter)(nil) +type lintDepSetsIntf interface { + LintDepSets() LintDepSets +} + +type LintDepSets struct { + HTML, Text, XML *android.DepSet +} + +type LintDepSetsBuilder struct { + HTML, Text, XML *android.DepSetBuilder +} + +func NewLintDepSetBuilder() LintDepSetsBuilder { + return LintDepSetsBuilder{ + HTML: android.NewDepSetBuilder(android.POSTORDER), + Text: android.NewDepSetBuilder(android.POSTORDER), + XML: android.NewDepSetBuilder(android.POSTORDER), + } +} + +func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder { + l.HTML.Direct(html) + l.Text.Direct(text) + l.XML.Direct(xml) + return l +} + +func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder { + if depSets.HTML != nil { + l.HTML.Transitive(depSets.HTML) + } + if depSets.Text != nil { + l.Text.Transitive(depSets.Text) + } + if depSets.XML != nil { + l.XML.Transitive(depSets.XML) + } + return l +} + +func (l LintDepSetsBuilder) Build() LintDepSets { + return LintDepSets{ + HTML: l.HTML.Build(), + Text: l.Text.Build(), + XML: l.XML.Build(), + } +} + +func (l *linter) LintDepSets() LintDepSets { + return l.outputs.depSets +} + +var _ lintDepSetsIntf = (*linter)(nil) + +var _ lintOutputsIntf = (*linter)(nil) func (l *linter) lintOutputs() *lintOutputs { return &l.outputs @@ -104,7 +155,16 @@ func (l *linter) deps(ctx android.BottomUpMutatorContext) { return } - ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), extraLintCheckTag, l.properties.Lint.Extra_check_modules...) + extraCheckModules := l.properties.Lint.Extra_check_modules + + if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" { + if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" { + extraCheckModules = strings.Split(checkOnlyModules, ",") + } + } + + ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), + extraLintCheckTag, extraCheckModules...) } func (l *linter) writeLintProjectXML(ctx android.ModuleContext, @@ -192,7 +252,7 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, return projectXMLPath, configXMLPath, cacheDir, homeDir, deps } -// generateManifest adds a command to the rule to write a dummy manifest cat contains the +// generateManifest adds a command to the rule to write a simple manifest that contains the // minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest. func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.Path { manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml") @@ -237,16 +297,11 @@ func (l *linter) lint(ctx android.ModuleContext) { text := android.PathForModuleOut(ctx, "lint-report.txt") xml := android.PathForModuleOut(ctx, "lint-report.xml") - htmlDeps := android.NewDepSetBuilder(android.POSTORDER).Direct(html) - textDeps := android.NewDepSetBuilder(android.POSTORDER).Direct(text) - xmlDeps := android.NewDepSetBuilder(android.POSTORDER).Direct(xml) + depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml) ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) { - if depLint, ok := dep.(lintOutputIntf); ok { - depLintOutputs := depLint.lintOutputs() - htmlDeps.Transitive(depLintOutputs.transitiveHTML) - textDeps.Transitive(depLintOutputs.transitiveText) - xmlDeps.Transitive(depLintOutputs.transitiveXML) + if depLint, ok := dep.(lintDepSetsIntf); ok { + depSetsBuilder.Transitive(depLint.LintDepSets()) } }) @@ -254,7 +309,7 @@ func (l *linter) lint(ctx android.ModuleContext) { rule.Command().Text("mkdir -p").Flag(cacheDir.String()).Flag(homeDir.String()) var annotationsZipPath, apiVersionsXMLPath android.Path - if ctx.Config().UnbundledBuildUsePrebuiltSdks() { + if ctx.Config().AlwaysUsePrebuiltSdks() { annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip") apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml") } else { @@ -262,9 +317,9 @@ func (l *linter) lint(ctx android.ModuleContext) { apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx) } - rule.Command(). + cmd := rule.Command(). Text("("). - Flag("JAVA_OPTS=-Xmx2048m"). + Flag("JAVA_OPTS=-Xmx3072m"). FlagWithArg("ANDROID_SDK_HOME=", homeDir.String()). FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath). FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath). @@ -282,9 +337,13 @@ func (l *linter) lint(ctx android.ModuleContext) { FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())). Flag("--exitcode"). Flags(l.properties.Lint.Flags). - Implicits(deps). - Text("|| (").Text("cat").Input(text).Text("; exit 7)"). - Text(")") + Implicits(deps) + + if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" { + cmd.FlagWithArg("--check ", checkOnly) + } + + cmd.Text("|| (").Text("cat").Input(text).Text("; exit 7)").Text(")") rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String()) @@ -295,24 +354,33 @@ func (l *linter) lint(ctx android.ModuleContext) { text: text, xml: xml, - transitiveHTML: htmlDeps.Build(), - transitiveText: textDeps.Build(), - transitiveXML: xmlDeps.Build(), + depSets: depSetsBuilder.Build(), } if l.buildModuleReportZip { - htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip") - l.outputs.transitiveHTMLZip = android.OptionalPathForPath(htmlZip) - lintZip(ctx, l.outputs.transitiveHTML.ToSortedList(), htmlZip) + l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets()) + } +} - textZip := android.PathForModuleOut(ctx, "lint-report-text.zip") - l.outputs.transitiveTextZip = android.OptionalPathForPath(textZip) - lintZip(ctx, l.outputs.transitiveText.ToSortedList(), textZip) +func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths { + htmlList := depSets.HTML.ToSortedList() + textList := depSets.Text.ToSortedList() + xmlList := depSets.XML.ToSortedList() - xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip") - l.outputs.transitiveXMLZip = android.OptionalPathForPath(xmlZip) - lintZip(ctx, l.outputs.transitiveXML.ToSortedList(), xmlZip) + if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 { + return nil } + + htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip") + lintZip(ctx, htmlList, htmlZip) + + textZip := android.PathForModuleOut(ctx, "lint-report-text.zip") + lintZip(ctx, textList, textZip) + + xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip") + lintZip(ctx, xmlList, xmlZip) + + return android.Paths{htmlZip, textZip, xmlZip} } type lintSingleton struct { @@ -327,7 +395,7 @@ func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) { } func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) { - if ctx.Config().UnbundledBuildUsePrebuiltSdks() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return } @@ -389,7 +457,7 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { return } - if l, ok := m.(lintOutputIntf); ok { + if l, ok := m.(lintOutputsIntf); ok { outputs = append(outputs, l.lintOutputs()) } }) @@ -400,7 +468,9 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { var paths android.Paths for _, output := range outputs { - paths = append(paths, get(output)) + if p := get(output); p != nil { + paths = append(paths, p) + } } lintZip(ctx, paths, outputPath) @@ -443,7 +513,7 @@ func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android rule.Command().BuiltTool(ctx, "soong_zip"). FlagWithOutput("-o ", outputPath). FlagWithArg("-C ", android.PathForIntermediates(ctx).String()). - FlagWithRspFileInputList("-l ", paths) + FlagWithRspFileInputList("-r ", paths) rule.Build(pctx, ctx, outputPath.Base(), outputPath.Base()) } diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index b10e6c7fe..ac8337dc5 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -34,6 +34,10 @@ func RegisterPrebuiltApisBuildComponents(ctx android.RegistrationContext) { type prebuiltApisProperties struct { // list of api version directories Api_dirs []string + + // The sdk_version of java_import modules generated based on jar files. + // Defaults to "current" + Imports_sdk_version *string } type prebuiltApis struct { @@ -74,7 +78,7 @@ func prebuiltApiModuleName(mctx android.LoadHookContext, module string, scope st return mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module } -func createImport(mctx android.LoadHookContext, module string, scope string, apiver string, path string) { +func createImport(mctx android.LoadHookContext, module, scope, apiver, path, sdk_version string) { props := struct { Name *string Jars []string @@ -83,7 +87,7 @@ func createImport(mctx android.LoadHookContext, module string, scope string, api }{} props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, apiver)) props.Jars = append(props.Jars, path) - props.Sdk_version = proptools.StringPtr(scope) + props.Sdk_version = proptools.StringPtr(sdk_version) props.Installable = proptools.BoolPtr(false) mctx.CreateModule(ImportFactory, &props) @@ -100,10 +104,10 @@ func createFilegroup(mctx android.LoadHookContext, module string, scope string, mctx.CreateModule(android.FileGroupFactory, &filegroupProps) } -func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string { +func getPrebuiltFiles(mctx android.LoadHookContext, p *prebuiltApis, name string) []string { mydir := mctx.ModuleDir() + "/" var files []string - for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs { + for _, apiver := range p.properties.Api_dirs { for _, scope := range []string{"public", "system", "test", "core", "module-lib", "system-server"} { vfiles, err := mctx.GlobWithDeps(mydir+apiver+"/"+scope+"/"+name, nil) if err != nil { @@ -115,16 +119,18 @@ func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string { return files } -func prebuiltSdkStubs(mctx android.LoadHookContext) { +func prebuiltSdkStubs(mctx android.LoadHookContext, p *prebuiltApis) { mydir := mctx.ModuleDir() + "/" // <apiver>/<scope>/<module>.jar - files := getPrebuiltFiles(mctx, "*.jar") + files := getPrebuiltFiles(mctx, p, "*.jar") + + sdk_version := proptools.StringDefault(p.properties.Imports_sdk_version, "current") for _, f := range files { // create a Import module for each jar file localPath := strings.TrimPrefix(f, mydir) module, apiver, scope := parseJarPath(localPath) - createImport(mctx, module, scope, apiver, localPath) + createImport(mctx, module, scope, apiver, localPath, sdk_version) } } @@ -139,8 +145,8 @@ func createSystemModules(mctx android.LoadHookContext, apiver string) { mctx.CreateModule(SystemModulesFactory, &props) } -func prebuiltSdkSystemModules(mctx android.LoadHookContext) { - for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs { +func prebuiltSdkSystemModules(mctx android.LoadHookContext, p *prebuiltApis) { + for _, apiver := range p.properties.Api_dirs { jar := android.ExistentPathForSource(mctx, mctx.ModuleDir(), apiver, "public", "core-for-system-modules.jar") if jar.Valid() { @@ -149,10 +155,10 @@ func prebuiltSdkSystemModules(mctx android.LoadHookContext) { } } -func prebuiltApiFiles(mctx android.LoadHookContext) { +func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { mydir := mctx.ModuleDir() + "/" // <apiver>/<scope>/api/<module>.txt - files := getPrebuiltFiles(mctx, "api/*.txt") + files := getPrebuiltFiles(mctx, p, "api/*.txt") if len(files) == 0 { mctx.ModuleErrorf("no api file found under %q", mydir) @@ -200,10 +206,10 @@ func prebuiltApiFiles(mctx android.LoadHookContext) { } func createPrebuiltApiModules(mctx android.LoadHookContext) { - if _, ok := mctx.Module().(*prebuiltApis); ok { - prebuiltApiFiles(mctx) - prebuiltSdkStubs(mctx) - prebuiltSdkSystemModules(mctx) + if p, ok := mctx.Module().(*prebuiltApis); ok { + prebuiltApiFiles(mctx, p) + prebuiltSdkStubs(mctx, p) + prebuiltSdkSystemModules(mctx, p) } } diff --git a/java/robolectric.go b/java/robolectric.go index c6b07a17e..3fe6626bb 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -21,10 +21,13 @@ import ( "strings" "android/soong/android" + "android/soong/java/config" + "android/soong/tradefed" ) func init() { android.RegisterModuleType("android_robolectric_test", RobolectricTestFactory) + android.RegisterModuleType("android_robolectric_runtimes", robolectricRuntimesFactory) } var robolectricDefaultLibs = []string{ @@ -32,10 +35,13 @@ var robolectricDefaultLibs = []string{ "Robolectric_all-target", "mockito-robolectric-prebuilt", "truth-prebuilt", + // TODO(ccross): this is not needed at link time + "junitxml", } var ( - roboCoverageLibsTag = dependencyTag{name: "roboSrcs"} + roboCoverageLibsTag = dependencyTag{name: "roboCoverageLibs"} + roboRuntimesTag = dependencyTag{name: "roboRuntimes"} ) type robolectricProperties struct { @@ -58,13 +64,28 @@ type robolectricTest struct { Library robolectricProperties robolectricProperties + testProperties testProperties libs []string tests []string + manifest android.Path + resourceApk android.Path + + combinedJar android.WritablePath + roboSrcJar android.Path + + testConfig android.Path + data android.Paths +} + +func (r *robolectricTest) TestSuites() []string { + return r.testProperties.Test_suites } +var _ android.TestSuiteModule = (*robolectricTest)(nil) + func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) { r.Library.DepsMutator(ctx) @@ -77,9 +98,16 @@ func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...) ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...) + + ctx.AddVariationDependencies(nil, roboRuntimesTag, "robolectric-android-all-prebuilts") } func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { + r.testConfig = tradefed.AutoGenRobolectricTestConfig(ctx, r.testProperties.Test_config, + r.testProperties.Test_config_template, r.testProperties.Test_suites, + r.testProperties.Auto_gen_config) + r.data = android.PathsForModuleSrc(ctx, r.testProperties.Data) + roboTestConfig := android.PathForModuleGen(ctx, "robolectric"). Join(ctx, "com/android/tools/test_config.properties") @@ -95,6 +123,9 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) ctx.PropertyErrorf("instrumentation_for", "dependency must be an android_app") } + r.manifest = instrumentedApp.mergedManifestFile + r.resourceApk = instrumentedApp.outputFile + generateRoboTestConfig(ctx, roboTestConfig, instrumentedApp) r.extraResources = android.Paths{roboTestConfig} @@ -104,10 +135,30 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) r.generateRoboSrcJar(ctx, roboSrcJar, instrumentedApp) r.roboSrcJar = roboSrcJar + roboTestConfigJar := android.PathForModuleOut(ctx, "robolectric_samedir", "samedir_config.jar") + generateSameDirRoboTestConfigJar(ctx, roboTestConfigJar) + + combinedJarJars := android.Paths{ + // roboTestConfigJar comes first so that its com/android/tools/test_config.properties + // overrides the one from r.extraResources. The r.extraResources one can be removed + // once the Make test runner is removed. + roboTestConfigJar, + r.outputFile, + instrumentedApp.implementationAndResourcesJar, + } + for _, dep := range ctx.GetDirectDepsWithTag(libTag) { - r.libs = append(r.libs, dep.(Dependency).BaseModuleName()) + m := dep.(Dependency) + r.libs = append(r.libs, m.BaseModuleName()) + if !android.InList(m.BaseModuleName(), config.FrameworkLibraries) { + combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars()...) + } } + r.combinedJar = android.PathForModuleOut(ctx, "robolectric_combined", r.outputFile.Base()) + TransformJarsToJar(ctx, r.combinedJar, "combine jars", combinedJarJars, android.OptionalPath{}, + false, nil, nil) + // TODO: this could all be removed if tradefed was used as the test runner, it will find everything // annotated as a test and run it. for _, src := range r.compiledJavaSrcs { @@ -121,14 +172,38 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) } r.tests = append(r.tests, s) } + + r.data = append(r.data, r.manifest, r.resourceApk) + + runtimes := ctx.GetDirectDepWithTag("robolectric-android-all-prebuilts", roboRuntimesTag) + + installPath := android.PathForModuleInstall(ctx, r.BaseModuleName()) + + installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", r.resourceApk) + installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", r.manifest) + installedConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig) + + var installDeps android.Paths + for _, runtime := range runtimes.(*robolectricRuntimes).runtimes { + installDeps = append(installDeps, runtime) + } + installDeps = append(installDeps, installedResourceApk, installedManifest, installedConfig) + + for _, data := range android.PathsForModuleSrc(ctx, r.testProperties.Data) { + installedData := ctx.InstallFile(installPath, data.Rel(), data) + installDeps = append(installDeps, installedData) + } + + ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...) } -func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath, instrumentedApp *AndroidApp) { +func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath, + instrumentedApp *AndroidApp) { + rule := android.NewRuleBuilder() + manifest := instrumentedApp.mergedManifestFile resourceApk := instrumentedApp.outputFile - rule := android.NewRuleBuilder() - rule.Command().Text("rm -f").Output(outputFile) rule.Command(). Textf(`echo "android_merged_manifest=%s" >>`, manifest.String()).Output(outputFile).Text("&&"). @@ -141,6 +216,28 @@ func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.Writab rule.Build(pctx, ctx, "generate_test_config", "generate test_config.properties") } +func generateSameDirRoboTestConfigJar(ctx android.ModuleContext, outputFile android.ModuleOutPath) { + rule := android.NewRuleBuilder() + + outputDir := outputFile.InSameDir(ctx) + configFile := outputDir.Join(ctx, "com/android/tools/test_config.properties") + rule.Temporary(configFile) + rule.Command().Text("rm -f").Output(outputFile).Output(configFile) + rule.Command().Textf("mkdir -p $(dirname %s)", configFile.String()) + rule.Command(). + Text("("). + Textf(`echo "android_merged_manifest=%s-AndroidManifest.xml" &&`, ctx.ModuleName()). + Textf(`echo "android_resource_apk=%s.apk"`, ctx.ModuleName()). + Text(") >>").Output(configFile) + rule.Command(). + BuiltTool(ctx, "soong_zip"). + FlagWithArg("-C ", outputDir.String()). + FlagWithInput("-f ", configFile). + FlagWithOutput("-o ", outputFile) + + rule.Build(pctx, ctx, "generate_test_config_samedir", "generate test_config.properties") +} + func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFile android.WritablePath, instrumentedApp *AndroidApp) { @@ -202,7 +299,6 @@ func (r *robolectricTest) writeTestRunner(w io.Writer, module, name string, test fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t) } fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk") - } // An android_robolectric_test module compiles tests against the Robolectric framework that can run on the local host @@ -218,11 +314,82 @@ func RobolectricTestFactory() android.Module { module.addHostProperties() module.AddProperties( &module.Module.deviceProperties, - &module.robolectricProperties) + &module.robolectricProperties, + &module.testProperties) module.Module.dexpreopter.isTest = true module.Module.linter.test = true + module.testProperties.Test_suites = []string{"robolectric-tests"} + InitJavaModule(module, android.DeviceSupported) return module } + +func (r *robolectricTest) InstallBypassMake() bool { return true } +func (r *robolectricTest) InstallInTestcases() bool { return true } +func (r *robolectricTest) InstallForceOS() *android.OsType { return &android.BuildOs } + +func robolectricRuntimesFactory() android.Module { + module := &robolectricRuntimes{} + module.AddProperties(&module.props) + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + return module +} + +type robolectricRuntimesProperties struct { + Jars []string `android:"path"` + Lib *string +} + +type robolectricRuntimes struct { + android.ModuleBase + + props robolectricRuntimesProperties + + runtimes []android.InstallPath +} + +func (r *robolectricRuntimes) TestSuites() []string { + return []string{"robolectric-tests"} +} + +var _ android.TestSuiteModule = (*robolectricRuntimes)(nil) + +func (r *robolectricRuntimes) DepsMutator(ctx android.BottomUpMutatorContext) { + if !ctx.Config().AlwaysUsePrebuiltSdks() && r.props.Lib != nil { + ctx.AddVariationDependencies(nil, libTag, String(r.props.Lib)) + } +} + +func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleContext) { + files := android.PathsForModuleSrc(ctx, r.props.Jars) + + androidAllDir := android.PathForModuleInstall(ctx, "android-all") + for _, from := range files { + installedRuntime := ctx.InstallFile(androidAllDir, from.Base(), from) + r.runtimes = append(r.runtimes, installedRuntime) + } + + if !ctx.Config().AlwaysUsePrebuiltSdks() && r.props.Lib != nil { + runtimeFromSourceModule := ctx.GetDirectDepWithTag(String(r.props.Lib), libTag) + if runtimeFromSourceModule == nil { + if ctx.Config().AllowMissingDependencies() { + ctx.AddMissingDependencies([]string{String(r.props.Lib)}) + } else { + ctx.PropertyErrorf("lib", "missing dependency %q", String(r.props.Lib)) + } + return + } + runtimeFromSourceJar := android.OutputFileForModule(ctx, runtimeFromSourceModule, "") + + runtimeName := fmt.Sprintf("android-all-%s-robolectric-r0.jar", + ctx.Config().PlatformSdkCodename()) + installedRuntime := ctx.InstallFile(androidAllDir, runtimeName, runtimeFromSourceJar) + r.runtimes = append(r.runtimes, installedRuntime) + } +} + +func (r *robolectricRuntimes) InstallBypassMake() bool { return true } +func (r *robolectricRuntimes) InstallInTestcases() bool { return true } +func (r *robolectricRuntimes) InstallForceOS() *android.OsType { return &android.BuildOs } diff --git a/java/sdk.go b/java/sdk.go index 6564f6d28..56fa12b3e 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -53,7 +53,7 @@ type sdkContext interface { func UseApiFingerprint(ctx android.BaseModuleContext) bool { if ctx.Config().UnbundledBuild() && - !ctx.Config().UnbundledBuildUsePrebuiltSdks() && + !ctx.Config().AlwaysUsePrebuiltSdks() && ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") { return true } @@ -191,19 +191,22 @@ func (s sdkSpec) prebuiltSdkAvailableForUnbundledBuild() bool { return s.kind != sdkPrivate && s.kind != sdkNone && s.kind != sdkCorePlatform } -// forPdkBuild converts this sdkSpec into another sdkSpec that is for the PDK builds. -func (s sdkSpec) forPdkBuild(ctx android.EarlyModuleContext) sdkSpec { - // For PDK builds, use the latest SDK version instead of "current" or "" - if s.kind == sdkPrivate || s.kind == sdkPublic { - kind := s.kind - if kind == sdkPrivate { - // We don't have prebuilt SDK for private APIs, so use the public SDK - // instead. This looks odd, but that's how it has been done. - // TODO(b/148271073): investigate the need for this. - kind = sdkPublic +func (s sdkSpec) forVendorPartition(ctx android.EarlyModuleContext) sdkSpec { + // If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value, + // use it instead of "current" for the vendor partition. + currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules() + if currentSdkVersion == "current" { + return s + } + + if s.kind == sdkPublic || s.kind == sdkSystem { + if s.version.isCurrent() { + if i, err := strconv.Atoi(currentSdkVersion); err == nil { + version := sdkVersion(i) + return sdkSpec{s.kind, version, s.raw} + } + panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion)) } - version := sdkVersion(LatestSdkVersionInt(ctx)) - return sdkSpec{kind, version, s.raw} } return s } @@ -212,9 +215,9 @@ func (s sdkSpec) forPdkBuild(ctx android.EarlyModuleContext) sdkSpec { func (s sdkSpec) usePrebuilt(ctx android.EarlyModuleContext) bool { if s.version.isCurrent() { // "current" can be built from source and be from prebuilt SDK - return ctx.Config().UnbundledBuildUsePrebuiltSdks() + return ctx.Config().AlwaysUsePrebuiltSdks() } else if s.version.isNumbered() { - // sanity check + // validation check if s.kind != sdkPublic && s.kind != sdkSystem && s.kind != sdkTest { panic(fmt.Errorf("prebuilt SDK is not not available for sdkKind=%q", s.kind)) return false @@ -233,8 +236,9 @@ func (s sdkSpec) effectiveVersion(ctx android.EarlyModuleContext) (sdkVersion, e if !s.valid() { return s.version, fmt.Errorf("invalid sdk version %q", s.raw) } - if ctx.Config().IsPdkBuild() { - s = s.forPdkBuild(ctx) + + if ctx.DeviceSpecific() || ctx.SocSpecific() { + s = s.forVendorPartition(ctx) } if s.version.isNumbered() { return s.version, nil @@ -350,9 +354,10 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep return sdkDep{} } - if ctx.Config().IsPdkBuild() { - sdkVersion = sdkVersion.forPdkBuild(ctx) + if ctx.DeviceSpecific() || ctx.SocSpecific() { + sdkVersion = sdkVersion.forVendorPartition(ctx) } + if !sdkVersion.validateSystemSdk(ctx) { return sdkDep{} } @@ -413,8 +418,8 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep case sdkPrivate: return sdkDep{ useModule: true, - systemModules: config.LegacyCorePlatformSystemModules, - bootclasspath: config.LegacyCorePlatformBootclasspathLibraries, + systemModules: corePlatformSystemModules(ctx), + bootclasspath: corePlatformBootclasspathLibraries(ctx), classpath: config.FrameworkLibraries, frameworkResModule: "framework-res", } @@ -438,8 +443,8 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep case sdkCorePlatform: return sdkDep{ useModule: true, - systemModules: config.LegacyCorePlatformSystemModules, - bootclasspath: config.LegacyCorePlatformBootclasspathLibraries, + systemModules: corePlatformSystemModules(ctx), + bootclasspath: corePlatformBootclasspathLibraries(ctx), noFrameworksLibs: true, } case sdkPublic: @@ -511,7 +516,7 @@ func sdkSingletonFactory() android.Singleton { type sdkSingleton struct{} func (sdkSingleton) GenerateBuildActions(ctx android.SingletonContext) { - if ctx.Config().UnbundledBuildUsePrebuiltSdks() || ctx.Config().IsPdkBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return } @@ -631,10 +636,7 @@ func createAPIFingerprint(ctx android.SingletonContext) { if ctx.Config().PlatformSdkCodename() == "REL" { cmd.Text("echo REL >").Output(out) - } else if ctx.Config().IsPdkBuild() { - // TODO: get this from the PDK artifacts? - cmd.Text("echo PDK >").Output(out) - } else if !ctx.Config().UnbundledBuildUsePrebuiltSdks() { + } else if !ctx.Config().AlwaysUsePrebuiltSdks() { in, err := ctx.GlobWithDeps("frameworks/base/api/*current.txt", nil) if err != nil { ctx.Errorf("error globbing API files: %s", err) @@ -663,7 +665,7 @@ func ApiFingerprintPath(ctx android.PathContext) android.OutputPath { } func sdkMakeVars(ctx android.MakeVarsContext) { - if ctx.Config().UnbundledBuildUsePrebuiltSdks() || ctx.Config().IsPdkBuild() { + if ctx.Config().AlwaysUsePrebuiltSdks() { return } diff --git a/java/sdk_library.go b/java/sdk_library.go index 68713df82..30478a1fb 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -126,25 +126,23 @@ type apiScope struct { // the prebuilt jar. sdkVersion string - // Extra arguments to pass to droidstubs for this scope. - droidstubsArgs []string + // The annotation that identifies this API level, empty for the public API scope. + annotation string - // The args that must be passed to droidstubs to generate the stubs source - // for this scope. + // Extra arguments to pass to droidstubs for this scope. // - // The stubs source must include the definitions of everything that is in this - // api scope and all the scopes that this one extends. - droidstubsArgsForGeneratingStubsSource []string + // This is not used directly but is used to construct the droidstubsArgs. + extraArgs []string - // The args that must be passed to droidstubs to generate the API for this scope. + // The args that must be passed to droidstubs to generate the API and stubs source + // for this scope, constructed dynamically by initApiScope(). // // The API only includes the additional members that this scope adds over the scope // that it extends. - droidstubsArgsForGeneratingApi []string - - // True if the stubs source and api can be created by the same metalava invocation. - // TODO(b/146727827) Now that metalava supports "API hierarchy", do we still need it? - createStubsSourceAndApiTogether bool + // + // The stubs source must include the definitions of everything that is in this + // api scope and all the scopes that this one extends. + droidstubsArgs []string // Whether the api scope can be treated as unstable, and should skip compat checks. unstable bool @@ -181,21 +179,23 @@ func initApiScope(scope *apiScope) *apiScope { // To get the args needed to generate the stubs source append all the args from // this scope and all the scopes it extends as each set of args adds additional // members to the stubs. - var stubsSourceArgs []string - for s := scope; s != nil; s = s.extends { - stubsSourceArgs = append(stubsSourceArgs, s.droidstubsArgs...) + var scopeSpecificArgs []string + if scope.annotation != "" { + scopeSpecificArgs = []string{"--show-annotation", scope.annotation} } - scope.droidstubsArgsForGeneratingStubsSource = stubsSourceArgs + for s := scope; s != nil; s = s.extends { + scopeSpecificArgs = append(scopeSpecificArgs, s.extraArgs...) - // Currently the args needed to generate the API are the same as the args - // needed to add additional members. - apiArgs := scope.droidstubsArgs - scope.droidstubsArgsForGeneratingApi = apiArgs + // Ensure that the generated stubs includes all the API elements from the API scope + // that this scope extends. + if s != scope && s.annotation != "" { + scopeSpecificArgs = append(scopeSpecificArgs, "--show-for-stub-purposes-annotation", s.annotation) + } + } - // If the args needed to generate the stubs and API are the same then they - // can be generated in a single invocation of metalava, otherwise they will - // need separate invocations. - scope.createStubsSourceAndApiTogether = reflect.DeepEqual(stubsSourceArgs, apiArgs) + // Escape any special characters in the arguments. This is needed because droidstubs + // passes these directly to the shell command. + scope.droidstubsArgs = proptools.ShellEscapeList(scopeSpecificArgs) return scope } @@ -250,10 +250,10 @@ var ( scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties { return &module.sdkLibraryProperties.System }, - apiFilePrefix: "system-", - moduleSuffix: ".system", - sdkVersion: "system_current", - droidstubsArgs: []string{"-showAnnotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)"}, + apiFilePrefix: "system-", + moduleSuffix: ".system", + sdkVersion: "system_current", + annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS)", }) apiScopeTest = initApiScope(&apiScope{ name: "test", @@ -262,11 +262,11 @@ var ( scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties { return &module.sdkLibraryProperties.Test }, - apiFilePrefix: "test-", - moduleSuffix: ".test", - sdkVersion: "test_current", - droidstubsArgs: []string{"-showAnnotation android.annotation.TestApi"}, - unstable: true, + apiFilePrefix: "test-", + moduleSuffix: ".test", + sdkVersion: "test_current", + annotation: "android.annotation.TestApi", + unstable: true, }) apiScopeModuleLib = initApiScope(&apiScope{ name: "module-lib", @@ -283,10 +283,7 @@ var ( apiFilePrefix: "module-lib-", moduleSuffix: ".module_lib", sdkVersion: "module_current", - droidstubsArgs: []string{ - "--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\)", - "--show-for-stub-purposes-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)", - }, + annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)", }) apiScopeSystemServer = initApiScope(&apiScope{ name: "system-server", @@ -303,11 +300,11 @@ var ( apiFilePrefix: "system-server-", moduleSuffix: ".system_server", sdkVersion: "system_server_current", - droidstubsArgs: []string{ - "--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\) ", - "--hide-annotation android.annotation.Hide", + annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.SYSTEM_SERVER)", + extraArgs: []string{ + "--hide-annotation", "android.annotation.Hide", // com.android.* classes are okay in this interface" - "--hide InternalClasses", + "--hide", "InternalClasses", }, }) allApiScopes = apiScopes{ @@ -855,22 +852,20 @@ func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(moduleBase *andr } // to satisfy SdkLibraryComponentDependency -func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() []string { - if e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack != nil { - return []string{*e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack} - } - return nil +func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() *string { + return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack } // Implemented by modules that are (or possibly could be) a component of a java_sdk_library // (including the java_sdk_library) itself. type SdkLibraryComponentDependency interface { + UsesLibraryDependency + // The optional name of the sdk library that should be implicitly added to the // AndroidManifest of an app that contains code which references the sdk library. // - // Returns an array containing 0 or 1 items rather than a *string to make it easier - // to append this to the list of exported sdk libraries. - OptionalImplicitSdkLibrary() []string + // Returns the name of the optional implicit SDK library or nil, if there isn't one. + OptionalImplicitSdkLibrary() *string } // Make sure that all the module types that are components of java_sdk_library/_import @@ -990,16 +985,8 @@ func (module *SdkLibrary) ComponentDepsMutator(ctx android.BottomUpMutatorContex // Add dependencies to the stubs library ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope)) - // If the stubs source and API cannot be generated together then add an additional dependency on - // the API module. - if apiScope.createStubsSourceAndApiTogether { - // Add a dependency on the stubs source in order to access both stubs source and api information. - ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope)) - } else { - // Add separate dependencies on the creators of the stubs source files and the API. - ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceModuleName(apiScope)) - ctx.AddVariationDependencies(nil, apiScope.apiFileTag, module.apiModuleName(apiScope)) - } + // Add a dependency on the stubs source in order to access both stubs source and api information. + ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope)) } if module.requiresRuntimeImplementationLibrary() { @@ -1126,6 +1113,7 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) &module.properties, &module.protoProperties, &module.deviceProperties, + &module.dexProperties, &module.dexpreoptProperties, &module.linter.properties, &props, @@ -1137,22 +1125,17 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) // Creates a static java library that has API stubs func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { props := struct { - Name *string - Visibility []string - Srcs []string - Installable *bool - Sdk_version *string - System_modules *string - Patch_module *string - Libs []string - Compile_dex *bool - Java_version *string - Product_variables struct { - Pdk struct { - Enabled *bool - } - } - Openjdk9 struct { + Name *string + Visibility []string + Srcs []string + Installable *bool + Sdk_version *string + System_modules *string + Patch_module *string + Libs []string + Compile_dex *bool + Java_version *string + Openjdk9 struct { Srcs []string Javacflags []string } @@ -1184,14 +1167,13 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) { props.Libs = append(props.Libs, "stub-annotations") } - props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false) props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags // We compile the stubs for 1.8 in line with the main android.jar stubs, and potential // interop with older developer tools that don't support 1.9. props.Java_version = proptools.StringPtr("1.8") - if module.deviceProperties.Compile_dex != nil { - props.Compile_dex = module.deviceProperties.Compile_dex + if module.dexProperties.Compile_dex != nil { + props.Compile_dex = module.dexProperties.Compile_dex } // Dist the class jar artifact for sdk builds. @@ -1207,7 +1189,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext // Creates a droidstubs module that creates stubs source files from the given full source // files and also updates and checks the API specification files. -func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, createStubSources, createApi bool, scopeSpecificDroidstubsArgs []string) { +func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) { props := struct { Name *string Visibility []string @@ -1296,64 +1278,57 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC } droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide ")) - if !createStubSources { - // Stubs are not required. - props.Generate_stubs = proptools.BoolPtr(false) - } - // Add in scope specific arguments. droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...) props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " ")) - if createApi { - // List of APIs identified from the provided source files are created. They are later - // compared against to the not-yet-released (a.k.a current) list of APIs and to the - // last-released (a.k.a numbered) list of API. - currentApiFileName := apiScope.apiFilePrefix + "current.txt" - removedApiFileName := apiScope.apiFilePrefix + "removed.txt" - apiDir := module.getApiDir() - currentApiFileName = path.Join(apiDir, currentApiFileName) - removedApiFileName = path.Join(apiDir, removedApiFileName) - - // check against the not-yet-release API - props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName) - props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName) - - if !apiScope.unstable { - // check against the latest released API - latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope)) - props.Check_api.Last_released.Api_file = latestApiFilegroupName - props.Check_api.Last_released.Removed_api_file = proptools.StringPtr( - module.latestRemovedApiFilegroupName(apiScope)) - props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true) - - if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) { - // Enable api lint. - props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true) - props.Check_api.Api_lint.New_since = latestApiFilegroupName - - // If it exists then pass a lint-baseline.txt through to droidstubs. - baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt") - baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath) - paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil) - if err != nil { - mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err) - } - if len(paths) == 1 { - props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath) - } else if len(paths) != 0 { - mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths) - } + // List of APIs identified from the provided source files are created. They are later + // compared against to the not-yet-released (a.k.a current) list of APIs and to the + // last-released (a.k.a numbered) list of API. + currentApiFileName := apiScope.apiFilePrefix + "current.txt" + removedApiFileName := apiScope.apiFilePrefix + "removed.txt" + apiDir := module.getApiDir() + currentApiFileName = path.Join(apiDir, currentApiFileName) + removedApiFileName = path.Join(apiDir, removedApiFileName) + + // check against the not-yet-release API + props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName) + props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName) + + if !apiScope.unstable { + // check against the latest released API + latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope)) + props.Check_api.Last_released.Api_file = latestApiFilegroupName + props.Check_api.Last_released.Removed_api_file = proptools.StringPtr( + module.latestRemovedApiFilegroupName(apiScope)) + props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true) + + if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) { + // Enable api lint. + props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true) + props.Check_api.Api_lint.New_since = latestApiFilegroupName + + // If it exists then pass a lint-baseline.txt through to droidstubs. + baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt") + baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath) + paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil) + if err != nil { + mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err) + } + if len(paths) == 1 { + props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath) + } else if len(paths) != 0 { + mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths) } } + } - // Dist the api txt artifact for sdk builds. - if !Bool(module.sdkLibraryProperties.No_dist) { - props.Dist.Targets = []string{"sdk", "win_sdk"} - props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName())) - props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api")) - } + // Dist the api txt artifact for sdk builds. + if !Bool(module.sdkLibraryProperties.No_dist) { + props.Dist.Targets = []string{"sdk", "win_sdk"} + props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName())) + props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api")) } mctx.CreateModule(DroidstubsFactory, &props) @@ -1409,22 +1384,22 @@ func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s sdkSpec) and return android.Paths{jarPath.Path()} } -// Get the apex name for module, "" if it is for platform. -func getApexNameForModule(module android.Module) string { +// Get the apex names for module, nil if it is for platform. +func getApexNamesForModule(module android.Module) []string { if apex, ok := module.(android.ApexModule); ok { - return apex.ApexName() + return apex.InApexes() } - return "" + return nil } -// Check to see if the other module is within the same named APEX as this module. +// Check to see if the other module is within the same set of named APEXes as this module. // // If either this or the other module are on the platform then this will return // false. -func withinSameApexAs(module android.ApexModule, other android.Module) bool { - name := module.ApexName() - return name != "" && getApexNameForModule(other) == name +func withinSameApexesAs(module android.ApexModule, other android.Module) bool { + names := module.InApexes() + return len(names) > 0 && reflect.DeepEqual(names, getApexNamesForModule(other)) } func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths { @@ -1443,7 +1418,7 @@ func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkS // Only allow access to the implementation library in the following condition: // * No sdk_version specified on the referencing module. // * The referencing module is in the same apex as this. - if sdkVersion.kind == sdkPrivate || withinSameApexAs(module, ctx.Module()) { + if sdkVersion.kind == sdkPrivate || withinSameApexesAs(module, ctx.Module()) { if headerJars { return module.HeaderJars() } else { @@ -1536,22 +1511,8 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont } for _, scope := range generatedScopes { - stubsSourceArgs := scope.droidstubsArgsForGeneratingStubsSource - stubsSourceModuleName := module.stubsSourceModuleName(scope) - - // If the args needed to generate the stubs and API are the same then they - // can be generated in a single invocation of metalava, otherwise they will - // need separate invocations. - if scope.createStubsSourceAndApiTogether { - // Use the stubs source name for legacy reasons. - module.createStubsSourcesAndApi(mctx, scope, stubsSourceModuleName, true, true, stubsSourceArgs) - } else { - module.createStubsSourcesAndApi(mctx, scope, stubsSourceModuleName, true, false, stubsSourceArgs) - - apiArgs := scope.droidstubsArgsForGeneratingApi - apiName := module.apiModuleName(scope) - module.createStubsSourcesAndApi(mctx, scope, apiName, false, true, apiArgs) - } + // Use the stubs source name for legacy reasons. + module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs) module.createStubsLibrary(mctx, scope) } @@ -1840,7 +1801,7 @@ func (module *SdkLibraryImport) Name() string { func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) { // If the build is configured to use prebuilts then force this to be preferred. - if mctx.Config().UnbundledBuildUsePrebuiltSdks() { + if mctx.Config().AlwaysUsePrebuiltSdks() { module.prebuilt.ForcePrefer() } @@ -1996,7 +1957,7 @@ func (module *SdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersio // For consistency with SdkLibrary make the implementation jar available to libraries that // are within the same APEX. implLibraryModule := module.implLibraryModule - if implLibraryModule != nil && withinSameApexAs(module, ctx.Module()) { + if implLibraryModule != nil && withinSameApexesAs(module, ctx.Module()) { if headerJars { return implLibraryModule.HeaderJars() } else { @@ -2019,7 +1980,7 @@ func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleCont return module.sdkJars(ctx, sdkVersion, false) } -// to satisfy apex.javaDependency interface +// to satisfy SdkLibraryDependency interface func (module *SdkLibraryImport) DexJarBuildPath() android.Path { if module.implLibraryModule == nil { return nil @@ -2028,6 +1989,15 @@ func (module *SdkLibraryImport) DexJarBuildPath() android.Path { } } +// to satisfy SdkLibraryDependency interface +func (module *SdkLibraryImport) DexJarInstallPath() android.Path { + if module.implLibraryModule == nil { + return nil + } else { + return module.implLibraryModule.DexJarInstallPath() + } +} + // to satisfy apex.javaDependency interface func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path { if module.implLibraryModule == nil { @@ -2038,6 +2008,15 @@ func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path { } // to satisfy apex.javaDependency interface +func (module *SdkLibraryImport) LintDepSets() LintDepSets { + if module.implLibraryModule == nil { + return LintDepSets{} + } else { + return module.implLibraryModule.LintDepSets() + } +} + +// to satisfy apex.javaDependency interface func (module *SdkLibraryImport) Stem() string { return module.BaseModuleName() } @@ -2094,6 +2073,12 @@ func sdkLibraryXmlFactory() android.Module { return module } +func (module *sdkLibraryXml) UniqueApexVariations() bool { + // sdkLibraryXml needs a unique variation per APEX because the generated XML file contains the path to the + // mounted APEX, which contains the name of the APEX. + return true +} + // from android.PrebuiltEtcModule func (module *sdkLibraryXml) SubDir() string { return "permissions" @@ -2121,8 +2106,8 @@ func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleConte // File path to the runtime implementation library func (module *sdkLibraryXml) implPath() string { implName := proptools.String(module.properties.Lib_name) - if apexName := module.ApexName(); apexName != "" { - // TODO(b/146468504): ApexName() is only a soong module name, not apex name. + if apexName := module.ApexVariationName(); apexName != "" { + // TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name. // In most cases, this works fine. But when apex_name is set or override_apex is used // this can be wrong. return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, implName) diff --git a/java/sdk_test.go b/java/sdk_test.go index 1f23b140c..776069dc9 100644 --- a/java/sdk_test.go +++ b/java/sdk_test.go @@ -30,7 +30,6 @@ func TestClasspath(t *testing.T) { var classpathTestcases = []struct { name string unbundled bool - pdk bool moduleType string host android.OsClass properties string @@ -49,8 +48,8 @@ func TestClasspath(t *testing.T) { }{ { name: "default", - bootclasspath: config.LegacyCorePlatformBootclasspathLibraries, - system: config.LegacyCorePlatformSystemModules, + bootclasspath: config.StableCorePlatformBootclasspathLibraries, + system: config.StableCorePlatformSystemModules, java8classpath: config.FrameworkLibraries, java9classpath: config.FrameworkLibraries, aidl: "-Iframework/aidl", @@ -58,16 +57,16 @@ func TestClasspath(t *testing.T) { { name: `sdk_version:"core_platform"`, properties: `sdk_version:"core_platform"`, - bootclasspath: config.LegacyCorePlatformBootclasspathLibraries, - system: config.LegacyCorePlatformSystemModules, + bootclasspath: config.StableCorePlatformBootclasspathLibraries, + system: config.StableCorePlatformSystemModules, java8classpath: []string{}, aidl: "", }, { name: "blank sdk version", properties: `sdk_version: "",`, - bootclasspath: config.LegacyCorePlatformBootclasspathLibraries, - system: config.LegacyCorePlatformSystemModules, + bootclasspath: config.StableCorePlatformBootclasspathLibraries, + system: config.StableCorePlatformSystemModules, java8classpath: config.FrameworkLibraries, java9classpath: config.FrameworkLibraries, aidl: "-Iframework/aidl", @@ -155,9 +154,9 @@ func TestClasspath(t *testing.T) { { name: "nostdlib system_modules", - properties: `sdk_version: "none", system_modules: "legacy-core-platform-api-stubs-system-modules"`, - system: "legacy-core-platform-api-stubs-system-modules", - bootclasspath: []string{"legacy-core-platform-api-stubs-system-modules-lib"}, + properties: `sdk_version: "none", system_modules: "stable-core-platform-api-stubs-system-modules"`, + system: "stable-core-platform-api-stubs-system-modules", + bootclasspath: []string{"stable-core-platform-api-stubs-system-modules-lib"}, java8classpath: []string{}, }, { @@ -217,35 +216,6 @@ func TestClasspath(t *testing.T) { }, { - name: "pdk default", - pdk: true, - bootclasspath: []string{`""`}, - system: "sdk_public_30_system_modules", - java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"}, - java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"}, - aidl: "-pprebuilts/sdk/30/public/framework.aidl", - }, - { - name: "pdk current", - pdk: true, - properties: `sdk_version: "current",`, - bootclasspath: []string{`""`}, - system: "sdk_public_30_system_modules", - java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"}, - java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"}, - aidl: "-pprebuilts/sdk/30/public/framework.aidl", - }, - { - name: "pdk 29", - pdk: true, - properties: `sdk_version: "29",`, - bootclasspath: []string{`""`}, - system: "sdk_public_30_system_modules", - java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"}, - java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"}, - aidl: "-pprebuilts/sdk/30/public/framework.aidl", - }, - { name: "module_current", properties: `sdk_version: "module_current",`, bootclasspath: []string{"android_module_lib_stubs_current", "core-lambda-stubs"}, @@ -384,9 +354,7 @@ func TestClasspath(t *testing.T) { config := testConfig(nil, bpJava8, nil) if testcase.unbundled { config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) - } - if testcase.pdk { - config.TestProductVariables.Pdk = proptools.BoolPtr(true) + config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) } ctx := testContext() run(t, ctx, config) @@ -407,9 +375,7 @@ func TestClasspath(t *testing.T) { config := testConfig(nil, bp, nil) if testcase.unbundled { config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) - } - if testcase.pdk { - config.TestProductVariables.Pdk = proptools.BoolPtr(true) + config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) } ctx := testContext() run(t, ctx, config) @@ -433,9 +399,7 @@ func TestClasspath(t *testing.T) { if testcase.unbundled { config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) - } - if testcase.pdk { - config.TestProductVariables.Pdk = proptools.BoolPtr(true) + config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) } ctx := testContext() run(t, ctx, config) @@ -451,9 +415,7 @@ func TestClasspath(t *testing.T) { if testcase.unbundled { config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) - } - if testcase.pdk { - config.TestProductVariables.Pdk = proptools.BoolPtr(true) + config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) } ctx := testContext() run(t, ctx, config) diff --git a/java/testing.go b/java/testing.go index 4f3f9f160..70c857f39 100644 --- a/java/testing.go +++ b/java/testing.go @@ -22,6 +22,8 @@ import ( "android/soong/android" "android/soong/cc" + "android/soong/python" + "github.com/google/blueprint" ) @@ -42,6 +44,9 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string "prebuilts/sdk/17/public/android.jar": nil, "prebuilts/sdk/17/public/framework.aidl": nil, "prebuilts/sdk/17/system/android.jar": nil, + "prebuilts/sdk/28/public/android.jar": nil, + "prebuilts/sdk/28/public/framework.aidl": nil, + "prebuilts/sdk/28/system/android.jar": nil, "prebuilts/sdk/29/public/android.jar": nil, "prebuilts/sdk/29/public/framework.aidl": nil, "prebuilts/sdk/29/system/android.jar": nil, @@ -85,6 +90,10 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string "prebuilts/sdk/tools/core-lambda-stubs.jar": nil, "prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"],}`), + "bin.py": nil, + python.StubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%' + MAIN_FILE = '%main%'`), + // For java_sdk_library "api/module-lib-current.txt": nil, "api/module-lib-removed.txt": nil, @@ -135,7 +144,7 @@ func GatherRequiredDepsForTest() string { name: "%s", srcs: ["a.java"], sdk_version: "none", - system_modules: "legacy-core-platform-api-stubs-system-modules", + system_modules: "stable-core-platform-api-stubs-system-modules", } `, extra) } @@ -145,7 +154,7 @@ func GatherRequiredDepsForTest() string { name: "framework", srcs: ["a.java"], sdk_version: "none", - system_modules: "legacy-core-platform-api-stubs-system-modules", + system_modules: "stable-core-platform-api-stubs-system-modules", aidl: { export_include_dirs: ["framework/aidl"], }, @@ -160,7 +169,7 @@ func GatherRequiredDepsForTest() string { name: "android.hidl.base-V1.0-java", srcs: ["a.java"], sdk_version: "none", - system_modules: "legacy-core-platform-api-stubs-system-modules", + system_modules: "stable-core-platform-api-stubs-system-modules", installable: true, } @@ -168,7 +177,7 @@ func GatherRequiredDepsForTest() string { name: "android.hidl.manager-V1.0-java", srcs: ["a.java"], sdk_version: "none", - system_modules: "legacy-core-platform-api-stubs-system-modules", + system_modules: "stable-core-platform-api-stubs-system-modules", installable: true, } @@ -176,7 +185,7 @@ func GatherRequiredDepsForTest() string { name: "org.apache.http.legacy", srcs: ["a.java"], sdk_version: "none", - system_modules: "legacy-core-platform-api-stubs-system-modules", + system_modules: "stable-core-platform-api-stubs-system-modules", installable: true, } @@ -184,7 +193,7 @@ func GatherRequiredDepsForTest() string { name: "android.test.base", srcs: ["a.java"], sdk_version: "none", - system_modules: "legacy-core-platform-api-stubs-system-modules", + system_modules: "stable-core-platform-api-stubs-system-modules", installable: true, } @@ -192,7 +201,7 @@ func GatherRequiredDepsForTest() string { name: "android.test.mock", srcs: ["a.java"], sdk_version: "none", - system_modules: "legacy-core-platform-api-stubs-system-modules", + system_modules: "stable-core-platform-api-stubs-system-modules", installable: true, } ` diff --git a/phony/phony.go b/phony/phony.go index 305a434f4..cb60b9f9e 100644 --- a/phony/phony.go +++ b/phony/phony.go @@ -44,11 +44,6 @@ func (p *phony) GenerateAndroidBuildActions(ctx android.ModuleContext) { p.requiredModuleNames = ctx.RequiredModuleNames() p.hostRequiredModuleNames = ctx.HostRequiredModuleNames() p.targetRequiredModuleNames = ctx.TargetRequiredModuleNames() - if len(p.requiredModuleNames) == 0 && - len(p.hostRequiredModuleNames) == 0 && len(p.targetRequiredModuleNames) == 0 { - ctx.PropertyErrorf("required", "phony must not have empty required dependencies "+ - "in order to be useful(and therefore permitted).") - } } func (p *phony) AndroidMk() android.AndroidMkData { diff --git a/python/binary.go b/python/binary.go index 695fa123b..5a7492648 100644 --- a/python/binary.go +++ b/python/binary.go @@ -65,7 +65,7 @@ type IntermPathProvider interface { } var ( - stubTemplateHost = "build/soong/python/scripts/stub_template_host.txt" + StubTemplateHost = "build/soong/python/scripts/stub_template_host.txt" ) func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { diff --git a/python/builder.go b/python/builder.go index 36baecdf1..dc2d1f127 100644 --- a/python/builder.go +++ b/python/builder.go @@ -91,7 +91,7 @@ func registerBuildActionForParFile(ctx android.ModuleContext, embeddedLauncher b if !embeddedLauncher { // the path of stub_template_host.txt from source tree. - template := android.PathForSource(ctx, stubTemplateHost) + template := android.PathForSource(ctx, StubTemplateHost) implicits = append(implicits, template) // intermediate output path for __main__.py diff --git a/python/python.go b/python/python.go index a6c9e2a07..479c7291d 100644 --- a/python/python.go +++ b/python/python.go @@ -30,9 +30,11 @@ import ( ) func init() { - android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("version_split", versionSplitMutator()).Parallel() - }) + android.PreDepsMutators(RegisterPythonPreDepsMutators) +} + +func RegisterPythonPreDepsMutators(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("version_split", versionSplitMutator()).Parallel() } // the version properties that apply to python libraries and binaries. @@ -226,15 +228,20 @@ func versionSplitMutator() func(android.BottomUpMutatorContext) { return func(mctx android.BottomUpMutatorContext) { if base, ok := mctx.Module().(*Module); ok { versionNames := []string{} - if base.properties.Version.Py2.Enabled != nil && - *(base.properties.Version.Py2.Enabled) == true { - versionNames = append(versionNames, pyVersion2) - } + // PY3 is first so that we alias the PY3 variant rather than PY2 if both + // are available if !(base.properties.Version.Py3.Enabled != nil && *(base.properties.Version.Py3.Enabled) == false) { versionNames = append(versionNames, pyVersion3) } + if base.properties.Version.Py2.Enabled != nil && + *(base.properties.Version.Py2.Enabled) == true { + versionNames = append(versionNames, pyVersion2) + } modules := mctx.CreateVariations(versionNames...) + if len(versionNames) > 0 { + mctx.AliasVariation(versionNames[0]) + } for i, v := range versionNames { // set the actual version for Python module. modules[i].(*Module).properties.Actual_version = v diff --git a/python/python_test.go b/python/python_test.go index 1245ca184..23db24e8f 100644 --- a/python/python_test.go +++ b/python/python_test.go @@ -301,7 +301,7 @@ var ( filepath.Join("dir", "file2.py"): nil, filepath.Join("dir", "bin.py"): nil, filepath.Join("dir", "file4.py"): nil, - stubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%' + StubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%' MAIN_FILE = '%main%'`), }, expectedBinaries: []pyModule{ @@ -330,9 +330,7 @@ func TestPythonModule(t *testing.T) { t.Run(d.desc, func(t *testing.T) { config := android.TestConfig(buildDir, nil, "", d.mockFiles) ctx := android.NewTestContext() - ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("version_split", versionSplitMutator()).Parallel() - }) + ctx.PreDepsMutators(RegisterPythonPreDepsMutators) ctx.RegisterModuleType("python_library_host", PythonLibraryHostFactory) ctx.RegisterModuleType("python_binary_host", PythonBinaryHostFactory) ctx.RegisterModuleType("python_defaults", defaultsFactory) diff --git a/rust/Android.bp b/rust/Android.bp index d56de870f..bbeb28d0b 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -10,6 +10,7 @@ bootstrap_go_package { srcs: [ "androidmk.go", "binary.go", + "bindgen.go", "builder.go", "clippy.go", "compiler.go", @@ -19,17 +20,21 @@ bootstrap_go_package { "proc_macro.go", "project_json.go", "rust.go", + "source_provider.go", "test.go", "testing.go", ], testSrcs: [ "binary_test.go", + "bindgen_test.go", + "builder_test.go", "clippy_test.go", "compiler_test.go", "coverage_test.go", "library_test.go", "project_json_test.go", "rust_test.go", + "source_provider_test.go", "test_test.go", ], pluginFor: ["soong_build"], diff --git a/rust/androidmk.go b/rust/androidmk.go index aea899baa..fda0a2579 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -26,18 +26,18 @@ import ( type AndroidMkContext interface { Name() string Target() android.Target - subAndroidMk(*android.AndroidMkData, interface{}) + SubAndroidMk(*android.AndroidMkData, interface{}) } -type subAndroidMkProvider interface { +type SubAndroidMkProvider interface { AndroidMk(AndroidMkContext, *android.AndroidMkData) } -func (mod *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) { +func (mod *Module) SubAndroidMk(data *android.AndroidMkData, obj interface{}) { if mod.subAndroidMkOnce == nil { - mod.subAndroidMkOnce = make(map[subAndroidMkProvider]bool) + mod.subAndroidMkOnce = make(map[SubAndroidMkProvider]bool) } - if androidmk, ok := obj.(subAndroidMkProvider); ok { + if androidmk, ok := obj.(SubAndroidMkProvider); ok { if !mod.subAndroidMkOnce[androidmk] { mod.subAndroidMkOnce[androidmk] = true androidmk.AndroidMk(mod, data) @@ -76,15 +76,19 @@ func (mod *Module) AndroidMk() android.AndroidMkData { }, } - mod.subAndroidMk(&ret, mod.compiler) - + if mod.compiler != nil && !mod.compiler.Disabled() { + mod.SubAndroidMk(&ret, mod.compiler) + } else if mod.sourceProvider != nil { + // If the compiler is disabled, this is a SourceProvider. + mod.SubAndroidMk(&ret, mod.sourceProvider) + } ret.SubName += mod.Properties.SubName return ret } func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { - ctx.subAndroidMk(ret, binary.baseCompiler) + ctx.SubAndroidMk(ret, binary.baseCompiler) if binary.distFile.Valid() { ret.DistFiles = android.MakeDefaultDistFiles(binary.distFile.Path()) @@ -118,7 +122,7 @@ func (test *testDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidM } func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { - ctx.subAndroidMk(ret, library.baseCompiler) + ctx.SubAndroidMk(ret, library.baseCompiler) if library.rlib() { ret.Class = "RLIB_LIBRARIES" @@ -146,7 +150,7 @@ func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.An } func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { - ctx.subAndroidMk(ret, procMacro.baseCompiler) + ctx.SubAndroidMk(ret, procMacro.baseCompiler) ret.Class = "PROC_MACRO_LIBRARIES" if procMacro.distFile.Valid() { @@ -155,6 +159,26 @@ func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *androi } +func (sourceProvider *BaseSourceProvider) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + outFile := sourceProvider.OutputFile + ret.Class = "ETC" + ret.OutputFile = android.OptionalPathForPath(outFile) + ret.SubName += sourceProvider.subName + ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { + _, file := filepath.Split(outFile.String()) + stem, suffix, _ := android.SplitFileExt(file) + fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix) + fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem) + }) +} + +func (bindgen *bindgenDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + ctx.SubAndroidMk(ret, bindgen.BaseSourceProvider) + ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { + fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true") + }) +} + func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { // Soong installation is only supported for host modules. Have Make // installation trigger Soong installation. diff --git a/rust/binary.go b/rust/binary.go index 9fc52cdb8..d287a06ef 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -24,9 +24,6 @@ func init() { } type BinaryCompilerProperties struct { - // passes -C prefer-dynamic to rustc, which tells it to dynamically link the stdlib - // (assuming it has no dylib dependencies already) - Prefer_dynamic *bool } type binaryDecorator struct { @@ -60,10 +57,6 @@ func NewRustBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator return module, binary } -func (binary *binaryDecorator) preferDynamic() bool { - return Bool(binary.Properties.Prefer_dynamic) -} - func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags = binary.baseCompiler.compilerFlags(ctx, flags) @@ -76,9 +69,6 @@ func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Fla "-Wl,--no-undefined-version") } - if binary.preferDynamic() { - flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic") - } return flags } @@ -86,7 +76,7 @@ func (binary *binaryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { deps = binary.baseCompiler.compilerDeps(ctx, deps) if ctx.toolchain().Bionic() { - deps = binary.baseCompiler.bionicDeps(ctx, deps) + deps = bionicDeps(deps) deps.CrtBegin = "crtbegin_dynamic" deps.CrtEnd = "crtend_android" } @@ -106,13 +96,13 @@ func (binary *binaryDecorator) nativeCoverage() bool { func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix() - srcPath, paths := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs) - deps.SrcDeps = paths + srcPath, _ := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs) outputFile := android.PathForModuleOut(ctx, fileName) binary.unstrippedOutputFile = outputFile flags.RustFlags = append(flags.RustFlags, deps.depFlags...) + flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...) outputs := TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) binary.coverageFile = outputs.coverageFile @@ -133,8 +123,9 @@ func (binary *binaryDecorator) coverageOutputZipPath() android.OptionalPath { return binary.coverageOutputZipFile } -func (binary *binaryDecorator) autoDep() autoDep { - if binary.preferDynamic() { +func (binary *binaryDecorator) autoDep(ctx BaseModuleContext) autoDep { + // Binaries default to dylib dependencies for device, rlib for host. + if ctx.Device() { return dylibAutoDep } else { return rlibAutoDep diff --git a/rust/binary_test.go b/rust/binary_test.go index ab2dae153..2fc38ed74 100644 --- a/rust/binary_test.go +++ b/rust/binary_test.go @@ -17,39 +17,82 @@ package rust import ( "strings" "testing" + + "android/soong/android" ) -// Test that the prefer_dynamic property is handled correctly. -func TestPreferDynamicBinary(t *testing.T) { +// Test that rustlibs default linkage is correct for binaries. +func TestBinaryLinkage(t *testing.T) { ctx := testRust(t, ` - rust_binary_host { - name: "fizz-buzz-dynamic", + rust_binary { + name: "fizz-buzz", srcs: ["foo.rs"], - prefer_dynamic: true, + rustlibs: ["libfoo"], + host_supported: true, } + rust_library { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + host_supported: true, + }`) + + fizzBuzzHost := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) + fizzBuzzDevice := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module) + + if !android.InList("libfoo", fizzBuzzHost.Properties.AndroidMkRlibs) { + t.Errorf("rustlibs dependency libfoo should be an rlib dep for host modules") + } + + if !android.InList("libfoo", fizzBuzzDevice.Properties.AndroidMkDylibs) { + t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules") + } +} + +// Test that the path returned by HostToolPath is correct +func TestHostToolPath(t *testing.T) { + ctx := testRust(t, ` + rust_binary_host { + name: "fizz-buzz", + srcs: ["foo.rs"], + }`) + + path := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath() + if g, w := path.String(), "/host/linux-x86/bin/fizz-buzz"; !strings.Contains(g, w) { + t.Errorf("wrong host tool path, expected %q got %q", w, g) + } +} +// Test that the flags being passed to rust_binary modules are as expected +func TestBinaryFlags(t *testing.T) { + ctx := testRust(t, ` rust_binary_host { name: "fizz-buzz", srcs: ["foo.rs"], }`) fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz") - fizzBuzzDynamic := ctx.ModuleForTests("fizz-buzz-dynamic", "linux_glibc_x86_64").Output("fizz-buzz-dynamic") - // Do not compile binary modules with the --test flag. - flags := fizzBuzzDynamic.Args["rustcFlags"] + flags := fizzBuzz.Args["rustcFlags"] if strings.Contains(flags, "--test") { t.Errorf("extra --test flag, rustcFlags: %#v", flags) } - if !strings.Contains(flags, "prefer-dynamic") { - t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", flags) - } +} - flags = fizzBuzz.Args["rustcFlags"] - if strings.Contains(flags, "--test") { - t.Errorf("extra --test flag, rustcFlags: %#v", flags) - } - if strings.Contains(flags, "prefer-dynamic") { - t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", flags) +func TestLinkObjects(t *testing.T) { + ctx := testRust(t, ` + rust_binary { + name: "fizz-buzz", + srcs: ["foo.rs"], + shared_libs: ["libfoo"], + } + cc_library { + name: "libfoo", + }`) + + fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Output("fizz-buzz") + linkFlags := fizzBuzz.Args["linkFlags"] + if !strings.Contains(linkFlags, "/libfoo.so") { + t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags) } } diff --git a/rust/bindgen.go b/rust/bindgen.go new file mode 100644 index 000000000..9b09e616e --- /dev/null +++ b/rust/bindgen.go @@ -0,0 +1,206 @@ +// 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 rust + +import ( + "strings" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" + + "android/soong/android" + ccConfig "android/soong/cc/config" +) + +var ( + defaultBindgenFlags = []string{""} + + // bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures. + bindgenClangVersion = "clang-r383902c" + bindgenLibClangSoGit = "11git" + + //TODO(b/160803703) Use a prebuilt bindgen instead of the built bindgen. + _ = pctx.SourcePathVariable("bindgenCmd", "out/host/${config.HostPrebuiltTag}/bin/bindgen") + _ = pctx.SourcePathVariable("bindgenClang", + "${ccConfig.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/bin/clang") + _ = pctx.SourcePathVariable("bindgenLibClang", + "${ccConfig.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/lib64/libclang.so."+bindgenLibClangSoGit) + + //TODO(ivanlozano) Switch this to RuleBuilder + bindgen = pctx.AndroidStaticRule("bindgen", + blueprint.RuleParams{ + Command: "CLANG_PATH=$bindgenClang LIBCLANG_PATH=$bindgenLibClang RUSTFMT=${config.RustBin}/rustfmt " + + "$cmd $flags $in -o $out -- -MD -MF $out.d $cflags", + CommandDeps: []string{"$cmd"}, + Deps: blueprint.DepsGCC, + Depfile: "$out.d", + }, + "cmd", "flags", "cflags") +) + +func init() { + android.RegisterModuleType("rust_bindgen", RustBindgenFactory) + android.RegisterModuleType("rust_bindgen_host", RustBindgenHostFactory) +} + +var _ SourceProvider = (*bindgenDecorator)(nil) + +type BindgenProperties struct { + // The wrapper header file + Wrapper_src *string `android:"path,arch_variant"` + + // list of bindgen-specific flags and options + Bindgen_flags []string `android:"arch_variant"` + + // list of clang flags required to correctly interpret the headers. + Cflags []string `android:"arch_variant"` + + // list of directories relative to the Blueprints file that will + // be added to the include path using -I + Local_include_dirs []string `android:"arch_variant,variant_prepend"` + + // list of static libraries that provide headers for this binding. + Static_libs []string `android:"arch_variant,variant_prepend"` + + // list of shared libraries that provide headers for this binding. + Shared_libs []string `android:"arch_variant"` + + // module name of a custom binary/script which should be used instead of the 'bindgen' binary. This custom + // binary must expect arguments in a similar fashion to bindgen, e.g. + // + // "my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]" + Custom_bindgen string `android:"path"` + + //TODO(b/161141999) Add support for headers from cc_library_header modules. +} + +type bindgenDecorator struct { + *BaseSourceProvider + + Properties BindgenProperties +} + +func (b *bindgenDecorator) GenerateSource(ctx android.ModuleContext, deps PathDeps) android.Path { + ccToolchain := ccConfig.FindToolchain(ctx.Os(), ctx.Arch()) + + var cflags []string + var implicits android.Paths + + implicits = append(implicits, deps.depIncludePaths...) + implicits = append(implicits, deps.depSystemIncludePaths...) + + // Default clang flags + cflags = append(cflags, "${ccConfig.CommonClangGlobalCflags}") + if ctx.Device() { + cflags = append(cflags, "${ccConfig.DeviceClangGlobalCflags}") + } + + // Toolchain clang flags + cflags = append(cflags, "-target "+ccToolchain.ClangTriple()) + cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainClangCflags(), "${config.", "${ccConfig.")) + + // Dependency clang flags and include paths + cflags = append(cflags, deps.depClangFlags...) + for _, include := range deps.depIncludePaths { + cflags = append(cflags, "-I"+include.String()) + } + for _, include := range deps.depSystemIncludePaths { + cflags = append(cflags, "-isystem "+include.String()) + } + + esc := proptools.NinjaAndShellEscapeList + + // Module defined clang flags and include paths + cflags = append(cflags, esc(b.Properties.Cflags)...) + for _, include := range b.Properties.Local_include_dirs { + cflags = append(cflags, "-I"+android.PathForModuleSrc(ctx, include).String()) + implicits = append(implicits, android.PathForModuleSrc(ctx, include)) + } + + bindgenFlags := defaultBindgenFlags + bindgenFlags = append(bindgenFlags, esc(b.Properties.Bindgen_flags)...) + + wrapperFile := android.OptionalPathForModuleSrc(ctx, b.Properties.Wrapper_src) + if !wrapperFile.Valid() { + ctx.PropertyErrorf("wrapper_src", "invalid path to wrapper source") + } + + outputFile := android.PathForModuleOut(ctx, b.BaseSourceProvider.getStem(ctx)+".rs") + + var cmd, cmdDesc string + if b.Properties.Custom_bindgen != "" { + cmd = ctx.GetDirectDepWithTag(b.Properties.Custom_bindgen, customBindgenDepTag).(*Module).HostToolPath().String() + cmdDesc = b.Properties.Custom_bindgen + } else { + cmd = "$bindgenCmd" + cmdDesc = "bindgen" + } + + ctx.Build(pctx, android.BuildParams{ + Rule: bindgen, + Description: strings.Join([]string{cmdDesc, wrapperFile.Path().Rel()}, " "), + Output: outputFile, + Input: wrapperFile.Path(), + Implicits: implicits, + Args: map[string]string{ + "cmd": cmd, + "flags": strings.Join(bindgenFlags, " "), + "cflags": strings.Join(cflags, " "), + }, + }) + + b.BaseSourceProvider.OutputFile = outputFile + return outputFile +} + +func (b *bindgenDecorator) SourceProviderProps() []interface{} { + return append(b.BaseSourceProvider.SourceProviderProps(), + &b.Properties) +} + +// rust_bindgen generates Rust FFI bindings to C libraries using bindgen given a wrapper header as the primary input. +// Bindgen has a number of flags to control the generated source, and additional flags can be passed to clang to ensure +// the header and generated source is appropriately handled. +func RustBindgenFactory() android.Module { + module, _ := NewRustBindgen(android.HostAndDeviceSupported) + return module.Init() +} + +func RustBindgenHostFactory() android.Module { + module, _ := NewRustBindgen(android.HostSupported) + return module.Init() +} + +func NewRustBindgen(hod android.HostOrDeviceSupported) (*Module, *bindgenDecorator) { + bindgen := &bindgenDecorator{ + BaseSourceProvider: NewSourceProvider(), + Properties: BindgenProperties{}, + } + + module := NewSourceProviderModule(hod, bindgen, false) + + return module, bindgen +} + +func (b *bindgenDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps { + deps = b.BaseSourceProvider.SourceProviderDeps(ctx, deps) + if ctx.toolchain().Bionic() { + deps = bionicDeps(deps) + } + + deps.SharedLibs = append(deps.SharedLibs, b.Properties.Shared_libs...) + deps.StaticLibs = append(deps.StaticLibs, b.Properties.Static_libs...) + return deps +} diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go new file mode 100644 index 000000000..191da9b11 --- /dev/null +++ b/rust/bindgen_test.go @@ -0,0 +1,84 @@ +// 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 rust + +import ( + "strings" + "testing" +) + +func TestRustBindgen(t *testing.T) { + ctx := testRust(t, ` + rust_bindgen { + name: "libbindgen", + wrapper_src: "src/any.h", + crate_name: "bindgen", + stem: "libbindgen", + source_stem: "bindings", + bindgen_flags: ["--bindgen-flag.*"], + cflags: ["--clang-flag()"], + shared_libs: ["libfoo_shared"], + static_libs: ["libfoo_static"], + } + cc_library_shared { + name: "libfoo_shared", + export_include_dirs: ["shared_include"], + } + cc_library_static { + name: "libfoo_static", + export_include_dirs: ["static_include"], + } + `) + libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a").Output("bindings.rs") + // Ensure that the flags are present and escaped + if !strings.Contains(libbindgen.Args["flags"], "'--bindgen-flag.*'") { + t.Errorf("missing bindgen flags in rust_bindgen rule: flags %#v", libbindgen.Args["flags"]) + } + if !strings.Contains(libbindgen.Args["cflags"], "'--clang-flag()'") { + t.Errorf("missing clang cflags in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"]) + } + if !strings.Contains(libbindgen.Args["cflags"], "-Ishared_include") { + t.Errorf("missing shared_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"]) + } + if !strings.Contains(libbindgen.Args["cflags"], "-Istatic_include") { + t.Errorf("missing static_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"]) + } +} + +func TestRustBindgenCustomBindgen(t *testing.T) { + ctx := testRust(t, ` + rust_bindgen { + name: "libbindgen", + wrapper_src: "src/any.h", + crate_name: "bindgen", + stem: "libbindgen", + source_stem: "bindings", + custom_bindgen: "my_bindgen" + } + rust_binary_host { + name: "my_bindgen", + srcs: ["foo.rs"], + } + `) + + libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a").Output("bindings.rs") + + // The rule description should contain the custom binary name rather than bindgen, so checking the description + // should be sufficient. + if !strings.Contains(libbindgen.Description, "my_bindgen") { + t.Errorf("Custom bindgen binary %s not used for libbindgen: rule description %#v", "my_bindgen", + libbindgen.Description) + } +} diff --git a/rust/builder.go b/rust/builder.go index 7f94bb514..45cd268e9 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -28,7 +28,7 @@ var ( _ = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc") rustc = pctx.AndroidStaticRule("rustc", blueprint.RuleParams{ - Command: "$rustcCmd " + + Command: "$envVars $rustcCmd " + "-C linker=${config.RustLinker} " + "-C link-args=\"${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}\" " + "--emit link -o $out --emit dep-info=$out.d $in ${libFlags} $rustcFlags", @@ -37,19 +37,19 @@ var ( Deps: blueprint.DepsGCC, Depfile: "$out.d", }, - "rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd") + "rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars") _ = pctx.SourcePathVariable("clippyCmd", "${config.RustBin}/clippy-driver") clippyDriver = pctx.AndroidStaticRule("clippy", blueprint.RuleParams{ - Command: "$clippyCmd " + + Command: "$envVars $clippyCmd " + // Because clippy-driver uses rustc as backend, we need to have some output even during the linting. // Use the metadata output as it has the smallest footprint. "--emit metadata -o $out $in ${libFlags} " + "$rustcFlags $clippyFlags", CommandDeps: []string{"$clippyCmd"}, }, - "rustcFlags", "libFlags", "clippyFlags") + "rustcFlags", "libFlags", "clippyFlags", "envVars") zip = pctx.AndroidStaticRule("zip", blueprint.RuleParams{ @@ -58,6 +58,14 @@ var ( Rspfile: "$out.rsp", RspfileContent: "$in", }) + + cp = pctx.AndroidStaticRule("cp", + blueprint.RuleParams{ + Command: "cp `cat $outDir.rsp` $outDir", + Rspfile: "${outDir}.rsp", + RspfileContent: "$in", + }, + "outDir") ) type buildOutput struct { @@ -116,6 +124,7 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl var inputs android.Paths var implicits android.Paths + var envVars []string var output buildOutput var libFlags, rustcFlags, linkFlags []string var implicitOutputs android.WritablePaths @@ -166,7 +175,7 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...) implicits = append(implicits, deps.StaticLibs...) implicits = append(implicits, deps.SharedLibs...) - implicits = append(implicits, deps.SrcDeps...) + if deps.CrtBegin.Valid() { implicits = append(implicits, deps.CrtBegin.Path(), deps.CrtEnd.Path()) } @@ -190,6 +199,32 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl output.coverageFile = gcnoFile } + if len(deps.SrcDeps) > 0 { + genSubDir := "out/" + moduleGenDir := android.PathForModuleOut(ctx, genSubDir) + var outputs android.WritablePaths + + for _, genSrc := range deps.SrcDeps { + if android.SuffixInList(outputs.Strings(), genSubDir+genSrc.Base()) { + ctx.PropertyErrorf("srcs", + "multiple source providers generate the same filename output: "+genSrc.Base()) + } + outputs = append(outputs, android.PathForModuleOut(ctx, genSubDir+genSrc.Base())) + } + + ctx.Build(pctx, android.BuildParams{ + Rule: cp, + Description: "cp " + moduleGenDir.Rel(), + Outputs: outputs, + Inputs: deps.SrcDeps, + Args: map[string]string{ + "outDir": moduleGenDir.String(), + }, + }) + implicits = append(implicits, outputs.Paths()...) + envVars = append(envVars, "OUT_DIR=$$PWD/"+moduleGenDir.String()) + } + if flags.Clippy { clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy") ctx.Build(pctx, android.BuildParams{ @@ -203,6 +238,7 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl "rustcFlags": strings.Join(rustcFlags, " "), "libFlags": strings.Join(libFlags, " "), "clippyFlags": strings.Join(flags.ClippyFlags, " "), + "envVars": strings.Join(envVars, " "), }, }) // Declare the clippy build as an implicit dependency of the original crate. @@ -222,6 +258,7 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl "libFlags": strings.Join(libFlags, " "), "crtBegin": deps.CrtBegin.String(), "crtEnd": deps.CrtEnd.String(), + "envVars": strings.Join(envVars, " "), }, }) diff --git a/rust/builder_test.go b/rust/builder_test.go new file mode 100644 index 000000000..5c11cb7b5 --- /dev/null +++ b/rust/builder_test.go @@ -0,0 +1,42 @@ +// 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 rust + +import "testing" + +func TestSourceProviderCollision(t *testing.T) { + testRustError(t, "multiple source providers generate the same filename output: bindings.rs", ` + rust_binary { + name: "source_collider", + srcs: [ + "foo.rs", + ":libbindings1", + ":libbindings2", + ], + } + rust_bindgen { + name: "libbindings1", + source_stem: "bindings", + crate_name: "bindings1", + wrapper_src: "src/any.h", + } + rust_bindgen { + name: "libbindings2", + source_stem: "bindings", + crate_name: "bindings2", + wrapper_src: "src/any.h", + } + `) +} diff --git a/rust/clippy.go b/rust/clippy.go index e1f567d99..6f0ed7ff1 100644 --- a/rust/clippy.go +++ b/rust/clippy.go @@ -19,8 +19,14 @@ import ( ) type ClippyProperties struct { - // whether to run clippy. - Clippy *bool + // name of the lint set that should be used to validate this module. + // + // Possible values are "default" (for using a sensible set of lints + // depending on the module's location), "android" (for the strictest + // lint set that applies to all Android platform code), "vendor" (for a + // relaxed set) and "none" (to disable the execution of clippy). The + // default value is "default". See also the `lints` property. + Clippy_lints *string } type clippy struct { @@ -32,10 +38,10 @@ func (c *clippy) props() []interface{} { } func (c *clippy) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) { - if c.Properties.Clippy != nil && !*c.Properties.Clippy { - return flags, deps + enabled, lints, err := config.ClippyLintsForDir(ctx.ModuleDir(), c.Properties.Clippy_lints) + if err != nil { + ctx.PropertyErrorf("clippy_lints", err.Error()) } - enabled, lints := config.ClippyLintsForDir(ctx.ModuleDir()) flags.Clippy = enabled flags.ClippyFlags = append(flags.ClippyFlags, lints) return flags, deps diff --git a/rust/clippy_test.go b/rust/clippy_test.go index 314417362..7815aab9d 100644 --- a/rust/clippy_test.go +++ b/rust/clippy_test.go @@ -16,31 +16,77 @@ package rust import ( "testing" + + "android/soong/android" ) func TestClippy(t *testing.T) { - ctx := testRust(t, ` + + bp := ` + // foo uses the default value of clippy_lints rust_library { name: "libfoo", srcs: ["foo.rs"], crate_name: "foo", } + // bar forces the use of the "android" lint set + rust_library { + name: "libbar", + srcs: ["foo.rs"], + crate_name: "bar", + clippy_lints: "android", + } + // foobar explicitly disable clippy rust_library { name: "libfoobar", srcs: ["foo.rs"], crate_name: "foobar", - clippy: false, - }`) + clippy_lints: "none", + }` + + bp = bp + GatherRequiredDepsForTest() - ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Output("libfoo.dylib.so") - fooClippy := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("clippy") - if fooClippy.Rule.String() != "android/soong/rust.clippy" { - t.Errorf("Clippy output (default) for libfoo was not generated: %+v", fooClippy) + fs := map[string][]byte{ + // Reuse the same blueprint file for subdirectories. + "external/Android.bp": []byte(bp), + "hardware/Android.bp": []byte(bp), } - ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").Output("libfoobar.dylib.so") - foobarClippy := ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("clippy") - if foobarClippy.Rule != nil { - t.Errorf("Clippy output for libfoobar is not empty") + var clippyLintTests = []struct { + modulePath string + fooFlags string + }{ + {"", "${config.ClippyDefaultLints}"}, + {"external/", ""}, + {"hardware/", "${config.ClippyVendorLints}"}, + } + + for _, tc := range clippyLintTests { + t.Run("path="+tc.modulePath, func(t *testing.T) { + + config := android.TestArchConfig(buildDir, nil, bp, fs) + ctx := CreateTestContext() + ctx.Register(config) + _, errs := ctx.ParseFileList(".", []string{tc.modulePath + "Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + r := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("clippy") + if r.Args["clippyFlags"] != tc.fooFlags { + t.Errorf("Incorrect flags for libfoo: %q, want %q", r.Args["clippyFlags"], tc.fooFlags) + } + + r = ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("clippy") + if r.Args["clippyFlags"] != "${config.ClippyDefaultLints}" { + t.Errorf("Incorrect flags for libbar: %q, want %q", r.Args["clippyFlags"], "${config.ClippyDefaultLints}") + } + + r = ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("clippy") + if r.Rule != nil { + t.Errorf("libfoobar is setup to use clippy when explicitly disabled: clippyFlags=%q", r.Args["clippyFlags"]) + } + + }) } } diff --git a/rust/compiler.go b/rust/compiler.go index c20179bd0..2600f4d0f 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -24,7 +24,7 @@ import ( "android/soong/rust/config" ) -func getEdition(compiler *baseCompiler) string { +func (compiler *baseCompiler) edition() string { return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition) } @@ -32,6 +32,10 @@ func (compiler *baseCompiler) setNoStdlibs() { compiler.Properties.No_stdlibs = proptools.BoolPtr(true) } +func (compiler *baseCompiler) disableLints() { + compiler.Properties.Lints = proptools.StringPtr("none") +} + func NewBaseCompiler(dir, dir64 string, location installLocation) *baseCompiler { return &baseCompiler{ Properties: BaseCompilerProperties{}, @@ -46,14 +50,22 @@ type installLocation int const ( InstallInSystem installLocation = 0 InstallInData = iota + + incorrectSourcesError = "srcs can only contain one path for a rust file and source providers prefixed by \":\"" ) type BaseCompilerProperties struct { // path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs) Srcs []string `android:"path,arch_variant"` - // whether to suppress the standard lint flags - default to false - No_lint *bool + // name of the lint set that should be used to validate this module. + // + // Possible values are "default" (for using a sensible set of lints + // depending on the module's location), "android" (for the strictest + // lint set that applies to all Android platform code), "vendor" (for + // a relaxed set) and "none" (for ignoring all lint warnings and + // errors). The default value is "default". + Lints *string // flags to pass to rustc Flags []string `android:"path,arch_variant"` @@ -79,7 +91,10 @@ type BaseCompilerProperties struct { // list of C static library dependencies Static_libs []string `android:"arch_variant"` - // crate name, required for libraries. This must be the expected extern crate name used in source + // crate name, required for modules which produce Rust libraries: rust_library, rust_ffi and SourceProvider + // modules which create library variants (rust_bindgen). This must be the expected extern crate name used in + // source, and is required to conform to an enforced format matching library output files (if the output file is + // lib<someName><suffix>, the crate_name property must be <someName>). Crate_name string `android:"arch_variant"` // list of features to enable for this crate @@ -118,10 +133,22 @@ type baseCompiler struct { distFile android.OptionalPath } +func (compiler *baseCompiler) Disabled() bool { + return false +} + +func (compiler *baseCompiler) SetDisabled() { + panic("baseCompiler does not implement SetDisabled()") +} + func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath { panic("baseCompiler does not implement coverageOutputZipPath()") } +func (compiler *baseCompiler) static() bool { + return false +} + var _ compiler = (*baseCompiler)(nil) func (compiler *baseCompiler) inData() bool { @@ -142,12 +169,14 @@ func (compiler *baseCompiler) featuresToFlags(features []string) []string { func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags { - if !Bool(compiler.Properties.No_lint) { - flags.RustFlags = append(flags.RustFlags, config.RustcLintsForDir(ctx.ModuleDir())) + lintFlags, err := config.RustcLintsForDir(ctx.ModuleDir(), compiler.Properties.Lints) + if err != nil { + ctx.PropertyErrorf("lints", err.Error()) } + flags.RustFlags = append(flags.RustFlags, lintFlags) flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...) flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...) - flags.RustFlags = append(flags.RustFlags, "--edition="+getEdition(compiler)) + flags.RustFlags = append(flags.RustFlags, "--edition="+compiler.edition()) flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...) flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...) flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags()) @@ -191,13 +220,21 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { stdlib = stdlib + "_" + ctx.toolchain().RustTriple() } - deps.Rustlibs = append(deps.Rustlibs, stdlib) + // For devices, we always link stdlibs in as dylibs except for ffi static libraries. + // (rustc does not support linking libstd as a dylib for ffi static libraries) + if ctx.Host() { + deps.Rustlibs = append(deps.Rustlibs, stdlib) + } else if ctx.RustModule().compiler.static() { + deps.Rlibs = append(deps.Rlibs, stdlib) + } else { + deps.Dylibs = append(deps.Dylibs, stdlib) + } } } return deps } -func (compiler *baseCompiler) bionicDeps(ctx DepsContext, deps Deps) Deps { +func bionicDeps(deps Deps) Deps { deps.SharedLibs = append(deps.SharedLibs, "liblog") deps.SharedLibs = append(deps.SharedLibs, "libc") deps.SharedLibs = append(deps.SharedLibs, "libm") @@ -253,6 +290,7 @@ func (compiler *baseCompiler) relativeInstallPath() string { return String(compiler.Properties.Relative_install_path) } +// Returns the Path for the main source file along with Paths for generated source files from modules listed in srcs. func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, android.Paths) { // The srcs can contain strings with prefix ":". // They are dependent modules of this module, with android.SourceDepTag. @@ -266,11 +304,11 @@ func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, andr } } if numSrcs != 1 { - ctx.PropertyErrorf("srcs", "srcs can only contain one path for a rust file") + ctx.PropertyErrorf("srcs", incorrectSourcesError) } if srcIndex != 0 { ctx.PropertyErrorf("srcs", "main source file must be the first in srcs") } paths := android.PathsForModuleSrc(ctx, srcs) - return paths[srcIndex], paths + return paths[srcIndex], paths[1:] } diff --git a/rust/compiler_test.go b/rust/compiler_test.go index 58ca52a0c..56a8ef8ac 100644 --- a/rust/compiler_test.go +++ b/rust/compiler_test.go @@ -17,6 +17,8 @@ package rust import ( "strings" "testing" + + "android/soong/android" ) // Test that feature flags are being correctly generated. @@ -43,7 +45,7 @@ func TestFeaturesToFlags(t *testing.T) { // Test that we reject multiple source files. func TestEnforceSingleSourceFile(t *testing.T) { - singleSrcError := "srcs can only contain one path for a rust file" + singleSrcError := "srcs can only contain one path for a rust file and source providers prefixed by \":\"" // Test libraries testRustError(t, singleSrcError, ` @@ -104,3 +106,101 @@ func TestInstallDir(t *testing.T) { t.Fatalf("unexpected install path for binary: %#v", install_path_bin) } } + +func TestLints(t *testing.T) { + + bp := ` + // foo uses the default value of lints + rust_library { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + } + // bar forces the use of the "android" lint set + rust_library { + name: "libbar", + srcs: ["foo.rs"], + crate_name: "bar", + lints: "android", + } + // foobar explicitly disable all lints + rust_library { + name: "libfoobar", + srcs: ["foo.rs"], + crate_name: "foobar", + lints: "none", + }` + + bp = bp + GatherRequiredDepsForTest() + + fs := map[string][]byte{ + // Reuse the same blueprint file for subdirectories. + "external/Android.bp": []byte(bp), + "hardware/Android.bp": []byte(bp), + } + + var lintTests = []struct { + modulePath string + fooFlags string + }{ + {"", "${config.RustDefaultLints}"}, + {"external/", "${config.RustAllowAllLints}"}, + {"hardware/", "${config.RustVendorLints}"}, + } + + for _, tc := range lintTests { + t.Run("path="+tc.modulePath, func(t *testing.T) { + + config := android.TestArchConfig(buildDir, nil, bp, fs) + ctx := CreateTestContext() + ctx.Register(config) + _, errs := ctx.ParseFileList(".", []string{tc.modulePath + "Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + r := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("rustc") + if !strings.Contains(r.Args["rustcFlags"], tc.fooFlags) { + t.Errorf("Incorrect flags for libfoo: %q, want %q", r.Args["rustcFlags"], tc.fooFlags) + } + + r = ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") + if !strings.Contains(r.Args["rustcFlags"], "${config.RustDefaultLints}") { + t.Errorf("Incorrect flags for libbar: %q, want %q", r.Args["rustcFlags"], "${config.RustDefaultLints}") + } + + r = ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") + if !strings.Contains(r.Args["rustcFlags"], "${config.RustAllowAllLints}") { + t.Errorf("Incorrect flags for libfoobar: %q, want %q", r.Args["rustcFlags"], "${config.RustAllowAllLints}") + } + + }) + } +} + +// Test that devices are linking the stdlib dynamically +func TestStdDeviceLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_binary { + name: "fizz", + srcs: ["foo.rs"], + } + rust_library { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + }`) + fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module) + fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Module().(*Module) + fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) + + if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) { + t.Errorf("libstd is not linked dynamically for device binaries") + } + if !android.InList("libstd", fooRlib.Properties.AndroidMkDylibs) { + t.Errorf("libstd is not linked dynamically for rlibs") + } + if !android.InList("libstd", fooDylib.Properties.AndroidMkDylibs) { + t.Errorf("libstd is not linked dynamically for dylibs") + } +} diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go index 0204cd2e7..62d469e4f 100644 --- a/rust/config/allowed_list.go +++ b/rust/config/allowed_list.go @@ -6,7 +6,11 @@ var ( "external/rust", "external/crosvm", "external/adhd", + "frameworks/native/libs/binder/rust", "prebuilts/rust", + "system/extras/profcollectd", + "system/security", + "system/tools/aidl", } RustModuleTypes = []string{ diff --git a/rust/config/global.go b/rust/config/global.go index 2020f461d..97de6761b 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -24,7 +24,7 @@ import ( var pctx = android.NewPackageContext("android/soong/rust/config") var ( - RustDefaultVersion = "1.44.0" + RustDefaultVersion = "1.45.2" RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2018" Stdlibs = []string{ diff --git a/rust/config/lints.go b/rust/config/lints.go index 529d0942f..06bb668d1 100644 --- a/rust/config/lints.go +++ b/rust/config/lints.go @@ -15,6 +15,7 @@ package config import ( + "fmt" "strings" "android/soong/android" @@ -24,18 +25,21 @@ import ( // The Android build system tries to avoid reporting warnings during the build. // Therefore, by default, we upgrade warnings to denials. For some of these // lints, an allow exception is setup, using the variables below. -// There are different default lints depending on the repository location (see -// DefaultLocalClippyChecks). +// // The lints are split into two categories. The first one contains the built-in // lints (https://doc.rust-lang.org/rustc/lints/index.html). The second is // specific to Clippy lints (https://rust-lang.github.io/rust-clippy/master/). // -// When developing a module, it is possible to use the `no_lint` property to -// disable the built-in lints configuration. It is also possible to set -// `clippy` to false to disable the clippy verification. Expect some -// questioning during review if you enable one of these options. For external/ -// code, if you need to use them, it is likely a bug. Otherwise, it may be -// useful to add an exception (that is, move a lint from deny to allow). +// For both categories, there are 3 levels of linting possible: +// - "android", for the strictest lints that applies to all Android platform code. +// - "vendor", for relaxed rules. +// - "none", to disable the linting. +// There is a fourth option ("default") which automatically selects the linting level +// based on the module's location. See defaultLintSetForPath. +// +// When developing a module, you may set `lints = "none"` and `clippy_lints = +// "none"` to disable all the linting. Expect some questioning during code review +// if you enable one of these options. var ( // Default Rust lints that applies to Google-authored modules. defaultRustcLints = []string{ @@ -102,13 +106,6 @@ func init() { pctx.StaticVariable("RustAllowAllLints", strings.Join(allowAllLints, " ")) } -type PathBasedClippyConfig struct { - PathPrefix string - RustcConfig string - ClippyEnabled bool - ClippyConfig string -} - const noLint = "" const rustcDefault = "${config.RustDefaultLints}" const rustcVendor = "${config.RustVendorLints}" @@ -116,35 +113,78 @@ const rustcAllowAll = "${config.RustAllowAllLints}" const clippyDefault = "${config.ClippyDefaultLints}" const clippyVendor = "${config.ClippyVendorLints}" -// This is a map of local path prefixes to a set of parameters for the linting: -// - a string for the lints to apply to rustc. -// - a boolean to indicate if clippy should be executed. -// - a string for the lints to apply to clippy. -// The first entry matching will be used. -var DefaultLocalClippyChecks = []PathBasedClippyConfig{ - {"external/", rustcAllowAll, false, noLint}, - {"hardware/", rustcVendor, true, clippyVendor}, - {"prebuilts/", rustcAllowAll, false, noLint}, - {"vendor/google", rustcDefault, true, clippyDefault}, - {"vendor/", rustcVendor, true, clippyVendor}, +// lintConfig defines a set of lints and clippy configuration. +type lintConfig struct { + rustcConfig string // for the lints to apply to rustc. + clippyEnabled bool // to indicate if clippy should be executed. + clippyConfig string // for the lints to apply to clippy. +} + +const ( + androidLints = "android" + vendorLints = "vendor" + noneLints = "none" +) + +// lintSets defines the categories of linting for Android and their mapping to lintConfigs. +var lintSets = map[string]lintConfig{ + androidLints: {rustcDefault, true, clippyDefault}, + vendorLints: {rustcVendor, true, clippyVendor}, + noneLints: {rustcAllowAll, false, noLint}, +} + +type pathLintSet struct { + prefix string + set string +} + +// This is a map of local path prefixes to a lint set. The first entry +// matching will be used. If no entry matches, androidLints ("android") will be +// used. +var defaultLintSetForPath = []pathLintSet{ + {"external", noneLints}, + {"hardware", vendorLints}, + {"prebuilts", noneLints}, + {"vendor/google", androidLints}, + {"vendor", vendorLints}, } // ClippyLintsForDir returns a boolean if Clippy should be executed and if so, the lints to be used. -func ClippyLintsForDir(dir string) (bool, string) { - for _, pathCheck := range DefaultLocalClippyChecks { - if strings.HasPrefix(dir, pathCheck.PathPrefix) { - return pathCheck.ClippyEnabled, pathCheck.ClippyConfig +func ClippyLintsForDir(dir string, clippyLintsProperty *string) (bool, string, error) { + if clippyLintsProperty != nil { + set, ok := lintSets[*clippyLintsProperty] + if ok { + return set.clippyEnabled, set.clippyConfig, nil + } + if *clippyLintsProperty != "default" { + return false, "", fmt.Errorf("unknown value for `clippy_lints`: %v, valid options are: default, android, vendor or none", *clippyLintsProperty) + } + } + for _, p := range defaultLintSetForPath { + if strings.HasPrefix(dir, p.prefix) { + setConfig := lintSets[p.set] + return setConfig.clippyEnabled, setConfig.clippyConfig, nil } } - return true, clippyDefault + return true, clippyDefault, nil } // RustcLintsForDir returns the standard lints to be used for a repository. -func RustcLintsForDir(dir string) string { - for _, pathCheck := range DefaultLocalClippyChecks { - if strings.HasPrefix(dir, pathCheck.PathPrefix) { - return pathCheck.RustcConfig +func RustcLintsForDir(dir string, lintProperty *string) (string, error) { + if lintProperty != nil { + set, ok := lintSets[*lintProperty] + if ok { + return set.rustcConfig, nil + } + if *lintProperty != "default" { + return "", fmt.Errorf("unknown value for `lints`: %v, valid options are: default, android, vendor or none", *lintProperty) + } + + } + for _, p := range defaultLintSetForPath { + if strings.HasPrefix(dir, p.prefix) { + return lintSets[p.set].rustcConfig, nil } } - return rustcDefault + return rustcDefault, nil } diff --git a/rust/coverage.go b/rust/coverage.go index 223ba4f19..26375f507 100644 --- a/rust/coverage.go +++ b/rust/coverage.go @@ -53,7 +53,7 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags flags.Coverage = true coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface) flags.RustFlags = append(flags.RustFlags, - "-Z profile", "-g", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads") + "-Z profile", "-g", "-C opt-level=0", "-C link-dead-code") flags.LinkFlags = append(flags.LinkFlags, "--coverage", "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,getenv") deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path()) diff --git a/rust/coverage_test.go b/rust/coverage_test.go index 357c2e8b1..73673d035 100644 --- a/rust/coverage_test.go +++ b/rust/coverage_test.go @@ -56,7 +56,7 @@ func TestCoverageFlags(t *testing.T) { fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc") buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc") - rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads"} + rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code"} for _, flag := range rustcCoverageFlags { missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v" containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v" diff --git a/rust/library.go b/rust/library.go index d718eb897..450c9d429 100644 --- a/rust/library.go +++ b/rust/library.go @@ -69,6 +69,10 @@ type LibraryMutatedProperties struct { VariantIsShared bool `blueprint:"mutated"` // This variant is a static library VariantIsStatic bool `blueprint:"mutated"` + + // This variant is disabled and should not be compiled + // (used for SourceProvider variants that produce only source) + VariantIsDisabled bool `blueprint:"mutated"` } type libraryDecorator struct { @@ -78,6 +82,7 @@ type libraryDecorator struct { Properties LibraryCompilerProperties MutatedProperties LibraryMutatedProperties includeDirs android.Paths + sourceProvider SourceProvider } type libraryInterface interface { @@ -171,13 +176,13 @@ func (library *libraryDecorator) setStatic() { library.MutatedProperties.VariantIsDylib = false } -func (library *libraryDecorator) autoDep() autoDep { +func (library *libraryDecorator) autoDep(ctx BaseModuleContext) autoDep { if library.rlib() || library.static() { return rlibAutoDep } else if library.dylib() || library.shared() { return dylibAutoDep } else { - return rlibAutoDep + panic("autoDep called on library" + ctx.ModuleName() + "that has no enabled variants.") } } @@ -340,7 +345,7 @@ func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { deps = library.baseCompiler.compilerDeps(ctx, deps) if ctx.toolchain().Bionic() && (library.dylib() || library.shared()) { - deps = library.baseCompiler.bionicDeps(ctx, deps) + deps = bionicDeps(deps) deps.CrtBegin = "crtbegin_so" deps.CrtEnd = "crtend_so" } @@ -367,11 +372,16 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) F func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { var outputFile android.WritablePath + var srcPath android.Path - srcPath, paths := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs) - deps.SrcDeps = paths + if library.sourceProvider != nil { + srcPath = library.sourceProvider.Srcs()[0] + } else { + srcPath, _ = srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs) + } flags.RustFlags = append(flags.RustFlags, deps.depFlags...) + flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...) if library.dylib() { // We need prefer-dynamic for now to avoid linking in the static stdlib. See: @@ -418,6 +428,7 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa if library.rlib() || library.dylib() { library.exportLinkDirs(deps.linkDirs...) library.exportDepFlags(deps.depFlags...) + library.exportLinkObjects(deps.linkObjects...) } library.unstrippedOutputFile = outputFile @@ -431,6 +442,14 @@ func (library *libraryDecorator) getStem(ctx ModuleContext) string { return stem + String(library.baseCompiler.Properties.Suffix) } +func (library *libraryDecorator) Disabled() bool { + return library.MutatedProperties.VariantIsDisabled +} + +func (library *libraryDecorator) SetDisabled() { + library.MutatedProperties.VariantIsDisabled = true +} + var validCrateName = regexp.MustCompile("[^a-zA-Z0-9_]+") func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) { @@ -455,25 +474,35 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) { if m, ok := mctx.Module().(*Module); ok && m.compiler != nil { switch library := m.compiler.(type) { case libraryInterface: - - // We only build the rust library variants here. This assumes that - // LinkageMutator runs first and there's an empty variant - // if rust variants are required. - if !library.static() && !library.shared() { - if library.buildRlib() && library.buildDylib() { - modules := mctx.CreateLocalVariations("rlib", "dylib") - rlib := modules[0].(*Module) - dylib := modules[1].(*Module) - - rlib.compiler.(libraryInterface).setRlib() - dylib.compiler.(libraryInterface).setDylib() - } else if library.buildRlib() { - modules := mctx.CreateLocalVariations("rlib") - modules[0].(*Module).compiler.(libraryInterface).setRlib() - } else if library.buildDylib() { - modules := mctx.CreateLocalVariations("dylib") - modules[0].(*Module).compiler.(libraryInterface).setDylib() + if library.buildRlib() && library.buildDylib() { + variants := []string{"rlib", "dylib"} + if m.sourceProvider != nil { + variants = append(variants, "") } + modules := mctx.CreateLocalVariations(variants...) + + rlib := modules[0].(*Module) + dylib := modules[1].(*Module) + rlib.compiler.(libraryInterface).setRlib() + dylib.compiler.(libraryInterface).setDylib() + + if m.sourceProvider != nil { + // This library is SourceProvider generated, so the non-library-producing + // variant needs to disable it's compiler and skip installation. + sourceProvider := modules[2].(*Module) + sourceProvider.compiler.SetDisabled() + } + } else if library.buildRlib() { + modules := mctx.CreateLocalVariations("rlib") + modules[0].(*Module).compiler.(libraryInterface).setRlib() + } else if library.buildDylib() { + modules := mctx.CreateLocalVariations("dylib") + modules[0].(*Module).compiler.(libraryInterface).setDylib() + } + + if m.sourceProvider != nil { + // Alias the non-library variant to the empty-string variant. + mctx.AliasVariation("") } } } diff --git a/rust/library_test.go b/rust/library_test.go index 8a91cf10f..0fd9e32f9 100644 --- a/rust/library_test.go +++ b/rust/library_test.go @@ -144,6 +144,22 @@ func TestSharedLibrary(t *testing.T) { } } +func TestStaticLibraryLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_ffi_static { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + }`) + + libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static") + + if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) { + t.Errorf("Static libstd rlib expected to be a dependency of Rust static libraries. Rlib deps are: %#v", + libfoo.Module().(*Module).Properties.AndroidMkDylibs) + } +} + // Test that variants pull in the right type of rustlib autodep func TestAutoDeps(t *testing.T) { diff --git a/rust/prebuilt.go b/rust/prebuilt.go index 3b4f40a55..3d081c113 100644 --- a/rust/prebuilt.go +++ b/rust/prebuilt.go @@ -96,7 +96,9 @@ func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags prebuilt.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...) srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs()) - deps.SrcDeps = paths + if len(paths) > 0 { + ctx.PropertyErrorf("srcs", "prebuilt libraries can only have one entry in srcs (the prebuilt path)") + } prebuilt.unstrippedOutputFile = srcPath diff --git a/rust/proc_macro.go b/rust/proc_macro.go index 49dbd8dc2..748879cc8 100644 --- a/rust/proc_macro.go +++ b/rust/proc_macro.go @@ -65,8 +65,7 @@ func (procMacro *procMacroDecorator) compile(ctx ModuleContext, flags Flags, dep fileName := procMacro.getStem(ctx) + ctx.toolchain().ProcMacroSuffix() outputFile := android.PathForModuleOut(ctx, fileName) - srcPath, paths := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs) - deps.SrcDeps = paths + srcPath, _ := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs) procMacro.unstrippedOutputFile = outputFile @@ -81,6 +80,6 @@ func (procMacro *procMacroDecorator) getStem(ctx ModuleContext) string { return stem + String(procMacro.baseCompiler.Properties.Suffix) } -func (procMacro *procMacroDecorator) autoDep() autoDep { +func (procMacro *procMacroDecorator) autoDep(ctx BaseModuleContext) autoDep { return rlibAutoDep } diff --git a/rust/project_json.go b/rust/project_json.go index a50e73a95..831047938 100644 --- a/rust/project_json.go +++ b/rust/project_json.go @@ -75,24 +75,23 @@ func mergeDependencies(ctx android.SingletonContext, project *rustProjectJson, knownCrates map[string]crateInfo, module android.Module, crate *rustProjectCrate, deps map[string]int) { - //TODO(tweek): The stdlib dependencies do not appear here. We need to manually add them. ctx.VisitDirectDeps(module, func(child android.Module) { - childId, childName, ok := appendLibraryAndDeps(ctx, project, knownCrates, child) + childId, childCrateName, ok := appendLibraryAndDeps(ctx, project, knownCrates, child) if !ok { return } - if _, ok = deps[childName]; ok { + if _, ok = deps[ctx.ModuleName(child)]; ok { return } - crate.Deps = append(crate.Deps, rustProjectDep{Crate: childId, Name: childName}) - deps[childName] = childId + crate.Deps = append(crate.Deps, rustProjectDep{Crate: childId, Name: childCrateName}) + deps[ctx.ModuleName(child)] = childId }) } // appendLibraryAndDeps creates a rustProjectCrate for the module argument and // appends it to the rustProjectJson struct. It visits the dependencies of the // module depth-first. If the current module is already in knownCrates, its -// its dependencies are merged. Returns a tuple (id, crate_name, ok). +// dependencies are merged. Returns a tuple (id, crate_name, ok). func appendLibraryAndDeps(ctx android.SingletonContext, project *rustProjectJson, knownCrates map[string]crateInfo, module android.Module) (int, string, bool) { rModule, ok := module.(*Module) @@ -106,23 +105,28 @@ func appendLibraryAndDeps(ctx android.SingletonContext, project *rustProjectJson if !ok { return 0, "", false } + moduleName := ctx.ModuleName(module) crateName := rModule.CrateName() - if cInfo, ok := knownCrates[crateName]; ok { + if cInfo, ok := knownCrates[moduleName]; ok { // We have seen this crate already; merge any new dependencies. crate := project.Crates[cInfo.ID] mergeDependencies(ctx, project, knownCrates, module, &crate, cInfo.Deps) + project.Crates[cInfo.ID] = crate return cInfo.ID, crateName, true } crate := rustProjectCrate{Deps: make([]rustProjectDep, 0), Cfgs: make([]string, 0)} - src := rustLib.baseCompiler.Properties.Srcs[0] - crate.RootModule = path.Join(ctx.ModuleDir(rModule), src) - crate.Edition = getEdition(rustLib.baseCompiler) + srcs := rustLib.baseCompiler.Properties.Srcs + if len(srcs) == 0 { + return 0, "", false + } + crate.RootModule = path.Join(ctx.ModuleDir(rModule), srcs[0]) + crate.Edition = rustLib.baseCompiler.edition() deps := make(map[string]int) mergeDependencies(ctx, project, knownCrates, module, &crate, deps) id := len(project.Crates) - knownCrates[crateName] = crateInfo{ID: id, Deps: deps} + knownCrates[moduleName] = crateInfo{ID: id, Deps: deps} project.Crates = append(project.Crates, crate) // rust-analyzer requires that all crates belong to at least one root: // https://github.com/rust-analyzer/rust-analyzer/issues/4735. diff --git a/rust/project_json_test.go b/rust/project_json_test.go index 6786e72c7..85219404a 100644 --- a/rust/project_json_test.go +++ b/rust/project_json_test.go @@ -15,6 +15,7 @@ package rust import ( + "encoding/json" "io/ioutil" "path/filepath" "testing" @@ -23,20 +24,12 @@ import ( "android/soong/cc" ) -func TestProjectJson(t *testing.T) { - bp := `rust_library { - name: "liba", - srcs: ["src/lib.rs"], - crate_name: "a" - }` + GatherRequiredDepsForTest() - env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"} - fs := map[string][]byte{ - "foo.rs": nil, - "src/lib.rs": nil, - } - +// testProjectJson run the generation of rust-project.json. It returns the raw +// content of the generated file. +func testProjectJson(t *testing.T, bp string, fs map[string][]byte) []byte { cc.GatherRequiredFilesForTest(fs) + env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"} config := android.TestArchConfig(buildDir, env, bp, fs) ctx := CreateTestContext() ctx.Register(config) @@ -48,8 +41,131 @@ func TestProjectJson(t *testing.T) { // The JSON file is generated via WriteFileToOutputDir. Therefore, it // won't appear in the Output of the TestingSingleton. Manually verify // it exists. - _, err := ioutil.ReadFile(filepath.Join(buildDir, "rust-project.json")) + content, err := ioutil.ReadFile(filepath.Join(buildDir, rustProjectJsonFileName)) if err != nil { t.Errorf("rust-project.json has not been generated") } + return content +} + +// validateJsonCrates validates that content follows the basic structure of +// rust-project.json. It returns the crates attribute if the validation +// succeeded. +// It uses an empty interface instead of relying on a defined structure to +// avoid a strong dependency on our implementation. +func validateJsonCrates(t *testing.T, rawContent []byte) []interface{} { + var content interface{} + err := json.Unmarshal(rawContent, &content) + if err != nil { + t.Errorf("Unable to parse the rust-project.json as JSON: %v", err) + } + root, ok := content.(map[string]interface{}) + if !ok { + t.Errorf("Unexpected JSON format: %v", content) + } + if _, ok = root["crates"]; !ok { + t.Errorf("No crates attribute in rust-project.json: %v", root) + } + crates, ok := root["crates"].([]interface{}) + if !ok { + t.Errorf("Unexpected crates format: %v", root["crates"]) + } + return crates +} + +func TestProjectJsonDep(t *testing.T) { + bp := ` + rust_library { + name: "liba", + srcs: ["a/src/lib.rs"], + crate_name: "a" + } + rust_library { + name: "libb", + srcs: ["b/src/lib.rs"], + crate_name: "b", + rlibs: ["liba"], + } + ` + GatherRequiredDepsForTest() + fs := map[string][]byte{ + "a/src/lib.rs": nil, + "b/src/lib.rs": nil, + } + jsonContent := testProjectJson(t, bp, fs) + validateJsonCrates(t, jsonContent) +} + +func TestProjectJsonBindGen(t *testing.T) { + bp := ` + rust_library { + name: "liba", + srcs: ["src/lib.rs"], + rlibs: ["libbindings"], + crate_name: "a" + } + rust_bindgen { + name: "libbindings", + crate_name: "bindings", + source_stem: "bindings", + host_supported: true, + wrapper_src: "src/any.h", + } + ` + GatherRequiredDepsForTest() + fs := map[string][]byte{ + "src/lib.rs": nil, + } + jsonContent := testProjectJson(t, bp, fs) + validateJsonCrates(t, jsonContent) +} + +func TestProjectJsonMultiVersion(t *testing.T) { + bp := ` + rust_library { + name: "liba1", + srcs: ["a1/src/lib.rs"], + crate_name: "a" + } + rust_library { + name: "liba2", + srcs: ["a2/src/lib.rs"], + crate_name: "a", + } + rust_library { + name: "libb", + srcs: ["b/src/lib.rs"], + crate_name: "b", + rustlibs: ["liba1", "liba2"], + } + ` + GatherRequiredDepsForTest() + fs := map[string][]byte{ + "a1/src/lib.rs": nil, + "a2/src/lib.rs": nil, + "b/src/lib.rs": nil, + } + jsonContent := testProjectJson(t, bp, fs) + crates := validateJsonCrates(t, jsonContent) + for _, crate := range crates { + c := crate.(map[string]interface{}) + if c["root_module"] == "b/src/lib.rs" { + deps, ok := c["deps"].([]interface{}) + if !ok { + t.Errorf("Unexpected format for deps: %v", c["deps"]) + } + aCount := 0 + for _, dep := range deps { + d, ok := dep.(map[string]interface{}) + if !ok { + t.Errorf("Unexpected format for dep: %v", dep) + } + if d["name"] == "a" { + aCount++ + } + } + if aCount != 2 { + t.Errorf("Unexpected number of liba dependencies want %v, got %v: %v", 2, aCount, deps) + } + return + } + } + t.Errorf("libb crate has not been found: %v", crates) } diff --git a/rust/rust.go b/rust/rust.go index 7a98c6468..68dc5a08b 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -42,6 +42,7 @@ func init() { ctx.BottomUp("rust_begin", BeginMutator).Parallel() }) pctx.Import("android/soong/rust/config") + pctx.ImportAs("ccConfig", "android/soong/cc/config") } type Flags struct { @@ -61,9 +62,11 @@ type BaseProperties struct { AndroidMkProcMacroLibs []string AndroidMkSharedLibs []string AndroidMkStaticLibs []string - SubName string `blueprint:"mutated"` - PreventInstall bool - HideFromMake bool + + SubName string `blueprint:"mutated"` + + PreventInstall bool + HideFromMake bool } type Module struct { @@ -79,8 +82,27 @@ type Module struct { coverage *coverage clippy *clippy cachedToolchain config.Toolchain - subAndroidMkOnce map[subAndroidMkProvider]bool - outputFile android.OptionalPath + sourceProvider SourceProvider + subAndroidMkOnce map[SubAndroidMkProvider]bool + + outputFile android.OptionalPath + generatedFile android.OptionalPath +} + +func (mod *Module) OutputFiles(tag string) (android.Paths, error) { + switch tag { + case "": + if mod.sourceProvider != nil && (mod.compiler == nil || mod.compiler.Disabled()) { + return mod.sourceProvider.Srcs(), nil + } else { + if mod.outputFile.Valid() { + return android.Paths{mod.outputFile.Path()}, nil + } + return android.Paths{}, nil + } + default: + return nil, fmt.Errorf("unsupported module reference tag %q", tag) + } } var _ android.ImageInterface = (*Module)(nil) @@ -120,12 +142,8 @@ func (mod *Module) SelectedStl() string { func (mod *Module) NonCcVariants() bool { if mod.compiler != nil { - if library, ok := mod.compiler.(libraryInterface); ok { - if library.buildRlib() || library.buildDylib() { - return true - } else { - return false - } + if _, ok := mod.compiler.(libraryInterface); ok { + return false } } panic(fmt.Errorf("NonCcVariants called on non-library module: %q", mod.BaseModuleName())) @@ -141,16 +159,16 @@ func (mod *Module) Static() bool { return library.static() } } - panic(fmt.Errorf("Static called on non-library module: %q", mod.BaseModuleName())) + return false } func (mod *Module) Shared() bool { if mod.compiler != nil { if library, ok := mod.compiler.(libraryInterface); ok { - return library.static() + return library.shared() } } - panic(fmt.Errorf("Shared called on non-library module: %q", mod.BaseModuleName())) + return false } func (mod *Module) Toc() android.OptionalPath { @@ -226,15 +244,21 @@ type Deps struct { } type PathDeps struct { - DyLibs RustLibraries - RLibs RustLibraries - SharedLibs android.Paths - StaticLibs android.Paths - ProcMacros RustLibraries - linkDirs []string - depFlags []string + DyLibs RustLibraries + RLibs RustLibraries + SharedLibs android.Paths + StaticLibs android.Paths + ProcMacros RustLibraries + linkDirs []string + depFlags []string + linkObjects []string //ReexportedDeps android.Paths + // Used by bindgen modules which call clang + depClangFlags []string + depIncludePaths android.Paths + depSystemIncludePaths android.Paths + coverageFiles android.Paths CrtBegin android.OptionalPath @@ -263,18 +287,26 @@ type compiler interface { relativeInstallPath() string nativeCoverage() bool + + Disabled() bool + SetDisabled() + + static() bool } type exportedFlagsProducer interface { exportedLinkDirs() []string exportedDepFlags() []string + exportedLinkObjects() []string exportLinkDirs(...string) exportDepFlags(...string) + exportLinkObjects(...string) } type flagExporter struct { - depFlags []string - linkDirs []string + depFlags []string + linkDirs []string + linkObjects []string } func (flagExporter *flagExporter) exportedLinkDirs() []string { @@ -285,6 +317,10 @@ func (flagExporter *flagExporter) exportedDepFlags() []string { return flagExporter.depFlags } +func (flagExporter *flagExporter) exportedLinkObjects() []string { + return flagExporter.linkObjects +} + func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) { flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...)) } @@ -293,12 +329,17 @@ func (flagExporter *flagExporter) exportDepFlags(flags ...string) { flagExporter.depFlags = android.FirstUniqueStrings(append(flagExporter.depFlags, flags...)) } +func (flagExporter *flagExporter) exportLinkObjects(flags ...string) { + flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...)) +} + var _ exportedFlagsProducer = (*flagExporter)(nil) func NewFlagExporter() *flagExporter { return &flagExporter{ - depFlags: []string{}, - linkDirs: []string{}, + depFlags: []string{}, + linkDirs: []string{}, + linkObjects: []string{}, } } @@ -348,6 +389,7 @@ func DefaultsFactory(props ...interface{}) android.Module { &LibraryCompilerProperties{}, &ProcMacroCompilerProperties{}, &PrebuiltProperties{}, + &SourceProviderProperties{}, &TestProperties{}, &cc.CoverageProperties{}, &ClippyProperties{}, @@ -372,7 +414,9 @@ func (mod *Module) CcLibrary() bool { func (mod *Module) CcLibraryInterface() bool { if mod.compiler != nil { - if _, ok := mod.compiler.(libraryInterface); ok { + // use build{Static,Shared}() instead of {static,shared}() here because this might be called before + // VariantIs{Static,Shared} is set. + if lib, ok := mod.compiler.(libraryInterface); ok && (lib.buildShared() || lib.buildStatic()) { return true } } @@ -507,6 +551,9 @@ func (mod *Module) Init() android.Module { if mod.clippy != nil { mod.AddProperties(mod.clippy.props()...) } + if mod.sourceProvider != nil { + mod.AddProperties(mod.sourceProvider.SourceProviderProps()...) + } android.InitAndroidArchModule(mod, mod.hod, mod.multilib) @@ -639,10 +686,19 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { flags, deps = mod.clippy.flags(ctx, flags, deps) } - if mod.compiler != nil { + // SourceProvider needs to call GenerateSource() before compiler calls compile() so it can provide the source. + // TODO(b/162588681) This shouldn't have to run for every variant. + if mod.sourceProvider != nil { + generatedFile := mod.sourceProvider.GenerateSource(ctx, deps) + mod.generatedFile = android.OptionalPathForPath(generatedFile) + mod.sourceProvider.setSubName(ctx.ModuleSubDir()) + } + + if mod.compiler != nil && !mod.compiler.Disabled() { outputFile := mod.compiler.compile(ctx, flags, deps) + mod.outputFile = android.OptionalPathForPath(outputFile) - if !mod.Properties.PreventInstall { + if mod.outputFile.Valid() && !mod.Properties.PreventInstall { mod.compiler.install(ctx, mod.outputFile.Path()) } } @@ -654,6 +710,9 @@ func (mod *Module) deps(ctx DepsContext) Deps { if mod.compiler != nil { deps = mod.compiler.compilerDeps(ctx, deps) } + if mod.sourceProvider != nil { + deps = mod.sourceProvider.SourceProviderDeps(ctx, deps) + } if mod.coverage != nil { deps = mod.coverage.deps(ctx, deps) @@ -678,10 +737,11 @@ type dependencyTag struct { } var ( - rlibDepTag = dependencyTag{name: "rlibTag", library: true} - dylibDepTag = dependencyTag{name: "dylib", library: true} - procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true} - testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"} + customBindgenDepTag = dependencyTag{name: "customBindgenTag"} + rlibDepTag = dependencyTag{name: "rlibTag", library: true} + dylibDepTag = dependencyTag{name: "dylib", library: true} + procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true} + testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"} ) type autoDep struct { @@ -695,7 +755,7 @@ var ( ) type autoDeppable interface { - autoDep() autoDep + autoDep(ctx BaseModuleContext) autoDep } func (mod *Module) begin(ctx BaseModuleContext) { @@ -712,18 +772,15 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { directProcMacroDeps := []*Module{} directSharedLibDeps := [](cc.LinkableInterface){} directStaticLibDeps := [](cc.LinkableInterface){} + directSrcProvidersDeps := []*Module{} + directSrcDeps := [](android.SourceFileProducer){} ctx.VisitDirectDeps(func(dep android.Module) { depName := ctx.OtherModuleName(dep) depTag := ctx.OtherModuleDependencyTag(dep) - if rustDep, ok := dep.(*Module); ok { + if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() { //Handle Rust Modules - linkFile := rustDep.outputFile - if !linkFile.Valid() { - ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName()) - } - switch depTag { case dylibDepTag: dylib, ok := rustDep.compiler.(libraryInterface) @@ -745,24 +802,47 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { case procMacroDepTag: directProcMacroDeps = append(directProcMacroDeps, rustDep) mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, depName) + case android.SourceDepTag: + // Since these deps are added in path_properties.go via AddDependencies, we need to ensure the correct + // OS/Arch variant is used. + var helper string + if ctx.Host() { + helper = "missing 'host_supported'?" + } else { + helper = "device module defined?" + } + + if dep.Target().Os != ctx.Os() { + ctx.ModuleErrorf("OS mismatch on dependency %q (%s)", dep.Name(), helper) + return + } else if dep.Target().Arch.ArchType != ctx.Arch().ArchType { + ctx.ModuleErrorf("Arch mismatch on dependency %q (%s)", dep.Name(), helper) + return + } + directSrcProvidersDeps = append(directSrcProvidersDeps, rustDep) } - //Append the dependencies exportedDirs - if lib, ok := rustDep.compiler.(exportedFlagsProducer); ok { + //Append the dependencies exportedDirs, except for proc-macros which target a different arch/OS + if lib, ok := rustDep.compiler.(exportedFlagsProducer); ok && depTag != procMacroDepTag { depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedLinkDirs()...) depPaths.depFlags = append(depPaths.depFlags, lib.exportedDepFlags()...) + depPaths.linkObjects = append(depPaths.linkObjects, lib.exportedLinkObjects()...) } if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag { + linkFile := rustDep.outputFile + if !linkFile.Valid() { + ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", + depName, ctx.ModuleName()) + return + } linkDir := linkPathFromFilePath(linkFile.Path()) if lib, ok := mod.compiler.(exportedFlagsProducer); ok { lib.exportLinkDirs(linkDir) } } - } - - if ccDep, ok := dep.(cc.LinkableInterface); ok { + } else if ccDep, ok := dep.(cc.LinkableInterface); ok { //Handle C dependencies if _, ok := ccDep.(*Module); !ok { if ccDep.Module().Target().Os != ctx.Os() { @@ -774,42 +854,55 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } } + linkObject := ccDep.OutputFile() + linkPath := linkPathFromFilePath(linkObject.Path()) - linkFile := ccDep.OutputFile() - linkPath := linkPathFromFilePath(linkFile.Path()) - libName := libNameFromFilePath(linkFile.Path()) - depFlag := "-l" + libName - - if !linkFile.Valid() { + if !linkObject.Valid() { ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName()) } exportDep := false - switch depTag { - case cc.StaticDepTag: - depFlag = "-lstatic=" + libName + switch { + case cc.IsStaticDepTag(depTag): depPaths.linkDirs = append(depPaths.linkDirs, linkPath) - depPaths.depFlags = append(depPaths.depFlags, depFlag) + depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String()) + depPaths.depIncludePaths = append(depPaths.depIncludePaths, ccDep.IncludeDirs()...) + if mod, ok := ccDep.(*cc.Module); ok { + depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, mod.ExportedSystemIncludeDirs()...) + depPaths.depClangFlags = append(depPaths.depClangFlags, mod.ExportedFlags()...) + } depPaths.coverageFiles = append(depPaths.coverageFiles, ccDep.CoverageFiles()...) directStaticLibDeps = append(directStaticLibDeps, ccDep) mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName) - case cc.SharedDepTag: - depFlag = "-ldylib=" + libName + case cc.IsSharedDepTag(depTag): depPaths.linkDirs = append(depPaths.linkDirs, linkPath) - depPaths.depFlags = append(depPaths.depFlags, depFlag) + depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String()) + depPaths.depIncludePaths = append(depPaths.depIncludePaths, ccDep.IncludeDirs()...) + if mod, ok := ccDep.(*cc.Module); ok { + depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, mod.ExportedSystemIncludeDirs()...) + depPaths.depClangFlags = append(depPaths.depClangFlags, mod.ExportedFlags()...) + } directSharedLibDeps = append(directSharedLibDeps, ccDep) mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName) exportDep = true - case cc.CrtBeginDepTag: - depPaths.CrtBegin = linkFile - case cc.CrtEndDepTag: - depPaths.CrtEnd = linkFile + case depTag == cc.CrtBeginDepTag: + depPaths.CrtBegin = linkObject + case depTag == cc.CrtEndDepTag: + depPaths.CrtEnd = linkObject } // Make sure these dependencies are propagated if lib, ok := mod.compiler.(exportedFlagsProducer); ok && exportDep { lib.exportLinkDirs(linkPath) - lib.exportDepFlags(depFlag) + lib.exportLinkObjects(linkObject.String()) + } + } + + if srcDep, ok := dep.(android.SourceFileProducer); ok { + switch depTag { + case android.SourceDepTag: + // These are usually genrules which don't have per-target variants. + directSrcDeps = append(directSrcDeps, srcDep) } } }) @@ -837,16 +930,29 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { sharedLibDepFiles = append(sharedLibDepFiles, dep.OutputFile().Path()) } + var srcProviderDepFiles android.Paths + for _, dep := range directSrcProvidersDeps { + srcs, _ := dep.OutputFiles("") + srcProviderDepFiles = append(srcProviderDepFiles, srcs...) + } + for _, dep := range directSrcDeps { + srcs := dep.Srcs() + srcProviderDepFiles = append(srcProviderDepFiles, srcs...) + } + depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...) depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...) depPaths.SharedLibs = append(depPaths.SharedLibs, sharedLibDepFiles...) depPaths.StaticLibs = append(depPaths.StaticLibs, staticLibDepFiles...) depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...) + depPaths.SrcDeps = append(depPaths.SrcDeps, srcProviderDepFiles...) // Dedup exported flags from dependencies depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs) depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags) - depPaths.SrcDeps = android.FirstUniquePaths(depPaths.SrcDeps) + depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags) + depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths) + depPaths.depSystemIncludePaths = android.FirstUniquePaths(depPaths.depSystemIncludePaths) return depPaths } @@ -862,14 +968,6 @@ func linkPathFromFilePath(filepath android.Path) string { return strings.Split(filepath.String(), filepath.Base())[0] } -func libNameFromFilePath(filepath android.Path) string { - libName := strings.TrimSuffix(filepath.Base(), filepath.Ext()) - if strings.HasPrefix(libName, "lib") { - libName = libName[3:] - } - return libName -} - func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { ctx := &depsContext{ BottomUpMutatorContext: actx, @@ -887,38 +985,43 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { } actx.AddVariationDependencies( append(commonDepVariations, []blueprint.Variation{ - {Mutator: "rust_libraries", Variation: "rlib"}, - {Mutator: "link", Variation: ""}}...), + {Mutator: "rust_libraries", Variation: "rlib"}}...), rlibDepTag, deps.Rlibs...) actx.AddVariationDependencies( append(commonDepVariations, []blueprint.Variation{ - {Mutator: "rust_libraries", Variation: "dylib"}, - {Mutator: "link", Variation: ""}}...), + {Mutator: "rust_libraries", Variation: "dylib"}}...), dylibDepTag, deps.Dylibs...) - if deps.Rustlibs != nil { - autoDep := mod.compiler.(autoDeppable).autoDep() + if deps.Rustlibs != nil && !mod.compiler.Disabled() { + autoDep := mod.compiler.(autoDeppable).autoDep(ctx) actx.AddVariationDependencies( append(commonDepVariations, []blueprint.Variation{ - {Mutator: "rust_libraries", Variation: autoDep.variation}, - {Mutator: "link", Variation: ""}}...), + {Mutator: "rust_libraries", Variation: autoDep.variation}}...), autoDep.depTag, deps.Rustlibs...) } actx.AddVariationDependencies(append(commonDepVariations, blueprint.Variation{Mutator: "link", Variation: "shared"}), - cc.SharedDepTag, deps.SharedLibs...) + cc.SharedDepTag(), deps.SharedLibs...) actx.AddVariationDependencies(append(commonDepVariations, blueprint.Variation{Mutator: "link", Variation: "static"}), - cc.StaticDepTag, deps.StaticLibs...) + cc.StaticDepTag(), deps.StaticLibs...) + crtVariations := append(cc.GetCrtVariations(ctx, mod), commonDepVariations...) if deps.CrtBegin != "" { - actx.AddVariationDependencies(commonDepVariations, cc.CrtBeginDepTag, deps.CrtBegin) + actx.AddVariationDependencies(crtVariations, cc.CrtBeginDepTag, deps.CrtBegin) } if deps.CrtEnd != "" { - actx.AddVariationDependencies(commonDepVariations, cc.CrtEndDepTag, deps.CrtEnd) + actx.AddVariationDependencies(crtVariations, cc.CrtEndDepTag, deps.CrtEnd) } + if mod.sourceProvider != nil { + if bindgen, ok := mod.sourceProvider.(*bindgenDecorator); ok && + bindgen.Properties.Custom_bindgen != "" { + actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), customBindgenDepTag, + bindgen.Properties.Custom_bindgen) + } + } // proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy. actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...) } @@ -947,14 +1050,20 @@ func (mod *Module) Name() string { return name } +func (mod *Module) disableClippy() { + if mod.clippy != nil { + mod.clippy.Properties.Clippy_lints = proptools.StringPtr("none") + } +} + var _ android.HostToolProvider = (*Module)(nil) func (mod *Module) HostToolPath() android.OptionalPath { if !mod.Host() { return android.OptionalPath{} } - if _, ok := mod.compiler.(*binaryDecorator); ok { - return mod.outputFile + if binary, ok := mod.compiler.(*binaryDecorator); ok { + return android.OptionalPathForPath(binary.baseCompiler.path) } return android.OptionalPath{} } @@ -963,3 +1072,5 @@ var Bool = proptools.Bool var BoolDefault = proptools.BoolDefault var String = proptools.String var StringPtr = proptools.StringPtr + +var _ android.OutputFileProducer = (*Module)(nil) diff --git a/rust/rust_test.go b/rust/rust_test.go index e80392589..f1a08a805 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -132,25 +132,6 @@ func testRustError(t *testing.T, pattern string, bp string) { t.Fatalf("missing expected error %q (0 errors are returned)", pattern) } -// Test that we can extract the lib name from a lib path. -func TestLibNameFromFilePath(t *testing.T) { - libBarPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so.so") - libLibPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/liblib.dylib.so") - - libBarName := libNameFromFilePath(libBarPath) - libLibName := libNameFromFilePath(libLibPath) - - expectedResult := "bar.so" - if libBarName != expectedResult { - t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libBarName) - } - - expectedResult = "lib.dylib" - if libLibName != expectedResult { - t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libLibPath) - } -} - // Test that we can extract the link path from a lib path. func TestLinkPathFromFilePath(t *testing.T) { barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so") @@ -182,7 +163,7 @@ func TestDepsTracking(t *testing.T) { } rust_library_host_rlib { name: "librlib", - srcs: ["foo.rs", ":my_generator"], + srcs: ["foo.rs"], crate_name: "rlib", } rust_proc_macro { @@ -190,38 +171,17 @@ func TestDepsTracking(t *testing.T) { srcs: ["foo.rs"], crate_name: "pm", } - genrule { - name: "my_generator", - tools: ["any_rust_binary"], - cmd: "$(location) -o $(out) $(in)", - srcs: ["src/any.h"], - out: ["src/any.rs"], - } rust_binary_host { - name: "fizz-buzz-dep", + name: "fizz-buzz", dylibs: ["libdylib"], rlibs: ["librlib"], proc_macros: ["libpm"], static_libs: ["libstatic"], shared_libs: ["libshared"], - srcs: [ - "foo.rs", - ":my_generator", - ], + srcs: ["foo.rs"], } `) - module := ctx.ModuleForTests("fizz-buzz-dep", "linux_glibc_x86_64").Module().(*Module) - rlibmodule := ctx.ModuleForTests("librlib", "linux_glibc_x86_64_rlib").Module().(*Module) - - srcs := module.compiler.(*binaryDecorator).baseCompiler.Properties.Srcs - if len(srcs) != 2 || !android.InList(":my_generator", srcs) { - t.Errorf("missing module dependency in fizz-buzz)") - } - - srcs = rlibmodule.compiler.(*libraryDecorator).baseCompiler.Properties.Srcs - if len(srcs) != 2 || !android.InList(":my_generator", srcs) { - t.Errorf("missing module dependency in rlib") - } + module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) // Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up. if !android.InList("libdylib", module.Properties.AndroidMkDylibs) { @@ -245,6 +205,114 @@ func TestDepsTracking(t *testing.T) { } } +func TestSourceProviderDeps(t *testing.T) { + ctx := testRust(t, ` + rust_binary { + name: "fizz-buzz-dep", + srcs: [ + "foo.rs", + ":my_generator", + ":libbindings", + ], + rlibs: ["libbindings"], + } + rust_proc_macro { + name: "libprocmacro", + srcs: [ + "foo.rs", + ":my_generator", + ":libbindings", + ], + rlibs: ["libbindings"], + crate_name: "procmacro", + } + rust_library { + name: "libfoo", + srcs: [ + "foo.rs", + ":my_generator", + ":libbindings", + ], + rlibs: ["libbindings"], + crate_name: "foo", + } + genrule { + name: "my_generator", + tools: ["any_rust_binary"], + cmd: "$(location) -o $(out) $(in)", + srcs: ["src/any.h"], + out: ["src/any.rs"], + } + rust_bindgen { + name: "libbindings", + crate_name: "bindings", + source_stem: "bindings", + host_supported: true, + wrapper_src: "src/any.h", + } + `) + + libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Rule("rustc") + if !android.SuffixInList(libfoo.Implicits.Strings(), "/out/bindings.rs") { + t.Errorf("rust_bindgen generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings()) + } + if !android.SuffixInList(libfoo.Implicits.Strings(), "/out/any.rs") { + t.Errorf("genrule generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings()) + } + + fizzBuzz := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Rule("rustc") + if !android.SuffixInList(fizzBuzz.Implicits.Strings(), "/out/bindings.rs") { + t.Errorf("rust_bindgen generated source not included as implicit input for fizz-buzz-dep; Implicits %#v", libfoo.Implicits.Strings()) + } + if !android.SuffixInList(fizzBuzz.Implicits.Strings(), "/out/any.rs") { + t.Errorf("genrule generated source not included as implicit input for fizz-buzz-dep; Implicits %#v", libfoo.Implicits.Strings()) + } + + libprocmacro := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Rule("rustc") + if !android.SuffixInList(libprocmacro.Implicits.Strings(), "/out/bindings.rs") { + t.Errorf("rust_bindgen generated source not included as implicit input for libprocmacro; Implicits %#v", libfoo.Implicits.Strings()) + } + if !android.SuffixInList(libprocmacro.Implicits.Strings(), "/out/any.rs") { + t.Errorf("genrule generated source not included as implicit input for libprocmacro; Implicits %#v", libfoo.Implicits.Strings()) + } + + // Check that our bindings are picked up as crate dependencies as well + libfooMod := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) + if !android.InList("libbindings", libfooMod.Properties.AndroidMkRlibs) { + t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)") + } + fizzBuzzMod := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Module().(*Module) + if !android.InList("libbindings", fizzBuzzMod.Properties.AndroidMkRlibs) { + t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)") + } + libprocmacroMod := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Module().(*Module) + if !android.InList("libbindings", libprocmacroMod.Properties.AndroidMkRlibs) { + t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)") + } + +} + +func TestSourceProviderTargetMismatch(t *testing.T) { + // This might error while building the dependency tree or when calling depsToPaths() depending on the lunched + // target, which results in two different errors. So don't check the error, just confirm there is one. + testRustError(t, ".*", ` + rust_proc_macro { + name: "libprocmacro", + srcs: [ + "foo.rs", + ":libbindings", + ], + crate_name: "procmacro", + } + rust_bindgen { + name: "libbindings", + crate_name: "bindings", + source_stem: "bindings", + wrapper_src: "src/any.h", + } + `) +} + // Test to make sure proc_macros use host variants when building device modules. func TestProcMacroDeviceDeps(t *testing.T) { ctx := testRust(t, ` diff --git a/rust/source_provider.go b/rust/source_provider.go new file mode 100644 index 000000000..e168718e4 --- /dev/null +++ b/rust/source_provider.go @@ -0,0 +1,97 @@ +// 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 rust + +import ( + "android/soong/android" +) + +type SourceProviderProperties struct { + // filename for the generated source file (<source_stem>.rs). This field is required. + // The inherited "stem" property sets the output filename for the generated library variants only. + Source_stem *string `android:"arch_variant"` + + // crate name, used for the library variant of this source provider. See additional details in rust_library. + Crate_name string `android:"arch_variant"` +} + +type BaseSourceProvider struct { + Properties SourceProviderProperties + + OutputFile android.Path + subAndroidMkOnce map[SubAndroidMkProvider]bool + subName string +} + +var _ SourceProvider = (*BaseSourceProvider)(nil) + +type SourceProvider interface { + GenerateSource(ctx android.ModuleContext, deps PathDeps) android.Path + Srcs() android.Paths + SourceProviderProps() []interface{} + SourceProviderDeps(ctx DepsContext, deps Deps) Deps + setSubName(subName string) +} + +func (sp *BaseSourceProvider) Srcs() android.Paths { + return android.Paths{sp.OutputFile} +} + +func (sp *BaseSourceProvider) GenerateSource(ctx android.ModuleContext, deps PathDeps) android.Path { + panic("BaseSourceProviderModule does not implement GenerateSource()") +} + +func (sp *BaseSourceProvider) SourceProviderProps() []interface{} { + return []interface{}{&sp.Properties} +} + +func NewSourceProvider() *BaseSourceProvider { + return &BaseSourceProvider{ + Properties: SourceProviderProperties{}, + } +} + +func NewSourceProviderModule(hod android.HostOrDeviceSupported, sourceProvider SourceProvider, enableLints bool) *Module { + _, library := NewRustLibrary(hod) + library.BuildOnlyRust() + library.sourceProvider = sourceProvider + + module := newModule(hod, android.MultilibBoth) + module.sourceProvider = sourceProvider + module.compiler = library + + if !enableLints { + library.disableLints() + module.disableClippy() + } + + return module +} + +func (sp *BaseSourceProvider) getStem(ctx android.ModuleContext) string { + if String(sp.Properties.Source_stem) == "" { + ctx.PropertyErrorf("source_stem", + "source_stem property is undefined but required for rust_bindgen modules") + } + return String(sp.Properties.Source_stem) +} + +func (sp *BaseSourceProvider) SourceProviderDeps(ctx DepsContext, deps Deps) Deps { + return deps +} + +func (sp *BaseSourceProvider) setSubName(subName string) { + sp.subName = subName +} diff --git a/rust/source_provider_test.go b/rust/source_provider_test.go new file mode 100644 index 000000000..6e68ae62c --- /dev/null +++ b/rust/source_provider_test.go @@ -0,0 +1,31 @@ +// 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 rust + +import ( + "testing" +) + +var stemRequiredError = "source_stem property is undefined but required for rust_bindgen modules" + +func TestSourceProviderRequiredFields(t *testing.T) { + testRustError(t, stemRequiredError, ` + rust_bindgen { + name: "libbindgen", + wrapper_src: "src/any.h", + crate_name: "bindgen", + } + `) +} diff --git a/rust/test.go b/rust/test.go index e27a70cac..19802e392 100644 --- a/rust/test.go +++ b/rust/test.go @@ -41,6 +41,9 @@ type TestProperties struct { // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true // explicitly. Auto_gen_config *bool + + // if set, build with the standard Rust test harness. Defaults to true. + Test_harness *bool } // A test module is a binary module with extra --test compiler flag @@ -56,6 +59,10 @@ func (test *testDecorator) nativeCoverage() bool { return true } +func (test *testDecorator) testHarness() bool { + return BoolDefault(test.Properties.Test_harness, true) +} + func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testDecorator) { // Build both 32 and 64 targets for device tests. // Cannot build both for host tests yet if the test depends on @@ -101,11 +108,13 @@ func (test *testDecorator) install(ctx ModuleContext, file android.Path) { func (test *testDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags = test.binaryDecorator.compilerFlags(ctx, flags) - flags.RustFlags = append(flags.RustFlags, "--test") + if test.testHarness() { + flags.RustFlags = append(flags.RustFlags, "--test") + } return flags } -func (test *testDecorator) autoDep() autoDep { +func (test *testDecorator) autoDep(ctx BaseModuleContext) autoDep { return rlibAutoDep } diff --git a/rust/testing.go b/rust/testing.go index 430b40bfd..80e414871 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -44,7 +44,28 @@ func GatherRequiredDepsForTest() string { }, host_supported: true, } - + rust_prebuilt_library { + name: "libstd_x86_64-apple-darwin", + crate_name: "std", + rlib: { + srcs: ["libstd.rlib"], + }, + dylib: { + srcs: ["libstd.so"], + }, + host_supported: true, + } + rust_prebuilt_library { + name: "libtest_x86_64-apple-darwin", + crate_name: "test", + rlib: { + srcs: ["libtest.rlib"], + }, + dylib: { + srcs: ["libtest.so"], + }, + host_supported: true, + } ////////////////////////////// // Device module requirements @@ -77,10 +98,13 @@ func GatherRequiredDepsForTest() string { func CreateTestContext() *android.TestContext { ctx := android.NewTestArchContext() + android.RegisterPrebuiltMutators(ctx) + ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) cc.RegisterRequiredBuildComponentsForTest(ctx) ctx.RegisterModuleType("genrule", genrule.GenRuleFactory) ctx.RegisterModuleType("rust_binary", RustBinaryFactory) ctx.RegisterModuleType("rust_binary_host", RustBinaryHostFactory) + ctx.RegisterModuleType("rust_bindgen", RustBindgenFactory) ctx.RegisterModuleType("rust_test", RustTestFactory) ctx.RegisterModuleType("rust_test_host", RustTestHostFactory) ctx.RegisterModuleType("rust_library", RustLibraryFactory) diff --git a/scripts/build-aml-prebuilts.sh b/scripts/build-aml-prebuilts.sh index c60eaa1f6..ef5565de3 100755 --- a/scripts/build-aml-prebuilts.sh +++ b/scripts/build-aml-prebuilts.sh @@ -84,6 +84,8 @@ cat > ${SOONG_VARS}.new << EOF "CrossHostArch": "x86_64", "Aml_abis": true, + "Allow_missing_dependencies": ${SOONG_ALLOW_MISSING_DEPENDENCIES:-false}, + "Unbundled_build": ${TARGET_BUILD_UNBUNDLED:-false}, "UseGoma": ${USE_GOMA} } EOF diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh index 1bc78e6ba..c5ec8d19c 100755 --- a/scripts/build-mainline-modules.sh +++ b/scripts/build-mainline-modules.sh @@ -24,7 +24,7 @@ MODULES_SDK_AND_EXPORTS=( i18n-module-test-exports i18n-module-sdk platform-mainline-sdk - platform-mainline-host-exports + platform-mainline-test-exports ) # List of libraries installed on the platform that are needed for ART chroot @@ -52,6 +52,13 @@ echo_and_run() { "$@" } +lib_dir() { + case $1 in + (aosp_arm|aosp_x86) echo "lib";; + (aosp_arm64|aosp_x86_64) echo "lib64";; + esac +} + OUT_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var OUT_DIR) DIST_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var DIST_DIR) @@ -69,7 +76,8 @@ for product in "${PRODUCTS[@]}"; do echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/apex/${module}.apex ${DIST_DIR}/${TARGET_ARCH}/ done for library in "${PLATFORM_LIBRARIES[@]}"; do - echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/lib/${library}.so ${DIST_DIR}/${TARGET_ARCH}/ + libdir=$(lib_dir $product) + echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/${libdir}/${library}.so ${DIST_DIR}/${TARGET_ARCH}/ done done diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go index 935d348ae..84b905c9d 100644 --- a/sdk/cc_sdk_test.go +++ b/sdk/cc_sdk_test.go @@ -39,6 +39,20 @@ func testSdkWithCc(t *testing.T, bp string) *testSdkResult { // Contains tests for SDK members provided by the cc package. +func TestSingleDeviceOsAssumption(t *testing.T) { + // Mock a module with DeviceSupported() == true. + s := &sdk{} + android.InitAndroidArchModule(s, android.DeviceSupported, android.MultilibCommon) + + osTypes := s.getPossibleOsTypes() + if len(osTypes) != 1 { + // The snapshot generation assumes there is a single device OS. If more are + // added it might need to disable them by default, like it does for host + // OS'es. + t.Errorf("expected a single device OS, got %v", osTypes) + } +} + func TestSdkIsCompileMultilibBoth(t *testing.T) { result := testSdkWithCc(t, ` sdk { @@ -73,12 +87,14 @@ func TestSdkCompileMultilibOverride(t *testing.T) { result := testSdkWithCc(t, ` sdk { name: "mysdk", + host_supported: true, native_shared_libs: ["sdkmember"], compile_multilib: "64", } cc_library_shared { name: "sdkmember", + host_supported: true, srcs: ["Test.cpp"], stl: "none", compile_multilib: "64", @@ -86,8 +102,72 @@ func TestSdkCompileMultilibOverride(t *testing.T) { `) result.CheckSnapshot("mysdk", "", + checkAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +cc_prebuilt_library_shared { + name: "mysdk_sdkmember@current", + sdk_member_name: "sdkmember", + host_supported: true, + installable: false, + stl: "none", + compile_multilib: "64", + target: { + host: { + enabled: false, + }, + android_arm64: { + srcs: ["android/arm64/lib/sdkmember.so"], + }, + linux_glibc: { + enabled: true, + }, + linux_glibc_x86_64: { + srcs: ["linux_glibc/x86_64/lib/sdkmember.so"], + }, + }, +} + +cc_prebuilt_library_shared { + name: "sdkmember", + prefer: false, + host_supported: true, + stl: "none", + compile_multilib: "64", + target: { + host: { + enabled: false, + }, + android_arm64: { + srcs: ["android/arm64/lib/sdkmember.so"], + }, + linux_glibc: { + enabled: true, + }, + linux_glibc_x86_64: { + srcs: ["linux_glibc/x86_64/lib/sdkmember.so"], + }, + }, +} + +sdk_snapshot { + name: "mysdk@current", + host_supported: true, + native_shared_libs: ["mysdk_sdkmember@current"], + compile_multilib: "64", + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + }, +} +`), checkAllCopyRules(` -.intermediates/sdkmember/android_arm64_armv8-a_shared/sdkmember.so -> arm64/lib/sdkmember.so +.intermediates/sdkmember/android_arm64_armv8-a_shared/sdkmember.so -> android/arm64/lib/sdkmember.so +.intermediates/sdkmember/linux_glibc_x86_64_shared/sdkmember.so -> linux_glibc/x86_64/lib/sdkmember.so `)) } @@ -185,11 +265,11 @@ func TestBasicSdkWithCc(t *testing.T) { } `) - sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_shared_myapex").Rule("toc").Output - sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_shared_myapex2").Rule("toc").Output + sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_shared_apex10000_mysdk_1").Rule("toc").Output + sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_shared_apex10000_mysdk_2").Rule("toc").Output - cpplibForMyApex := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_myapex") - cpplibForMyApex2 := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_myapex2") + cpplibForMyApex := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_apex10000_mysdk_1") + cpplibForMyApex2 := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_apex10000_mysdk_2") // Depending on the uses_sdks value, different libs are linked ensureListContains(t, pathsToStrings(cpplibForMyApex.Rule("ld").Implicits), sdkMemberV1.String()) @@ -260,6 +340,9 @@ func TestSnapshotWithObject(t *testing.T) { cc_object { name: "crtobj", stl: "none", + sanitize: { + never: true, + }, } `) @@ -271,6 +354,10 @@ cc_prebuilt_object { name: "mysdk_crtobj@current", sdk_member_name: "crtobj", stl: "none", + compile_multilib: "both", + sanitize: { + never: true, + }, arch: { arm64: { srcs: ["arm64/lib/crtobj.o"], @@ -285,6 +372,10 @@ cc_prebuilt_object { name: "crtobj", prefer: false, stl: "none", + compile_multilib: "both", + sanitize: { + never: true, + }, arch: { arm64: { srcs: ["arm64/lib/crtobj.o"], @@ -378,6 +469,7 @@ cc_prebuilt_library_shared { sdk_member_name: "mynativelib", installable: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -394,6 +486,7 @@ cc_prebuilt_library_shared { name: "mynativelib", prefer: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -523,7 +616,11 @@ cc_prebuilt_binary { installable: false, stl: "none", target: { + host: { + enabled: false, + }, linux_glibc: { + enabled: true, compile_multilib: "both", }, linux_glibc_x86_64: { @@ -533,6 +630,7 @@ cc_prebuilt_binary { srcs: ["linux_glibc/x86/bin/mynativebinary"], }, windows: { + enabled: true, compile_multilib: "64", }, windows_x86_64: { @@ -548,7 +646,11 @@ cc_prebuilt_binary { host_supported: true, stl: "none", target: { + host: { + enabled: false, + }, linux_glibc: { + enabled: true, compile_multilib: "both", }, linux_glibc_x86_64: { @@ -558,6 +660,7 @@ cc_prebuilt_binary { srcs: ["linux_glibc/x86/bin/mynativebinary"], }, windows: { + enabled: true, compile_multilib: "64", }, windows_x86_64: { @@ -572,7 +675,14 @@ module_exports_snapshot { host_supported: true, native_binaries: ["myexports_mynativebinary@current"], target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, windows: { + enabled: true, compile_multilib: "64", }, }, @@ -586,6 +696,162 @@ module_exports_snapshot { ) } +func TestSnapshotWithSingleHostOsType(t *testing.T) { + ctx, config := testSdkContext(` + cc_defaults { + name: "mydefaults", + device_supported: false, + host_supported: true, + compile_multilib: "64", + target: { + host: { + enabled: false, + }, + linux_bionic: { + enabled: true, + }, + }, + } + + module_exports { + name: "myexports", + defaults: ["mydefaults"], + native_shared_libs: ["mynativelib"], + native_binaries: ["mynativebinary"], + compile_multilib: "64", // The built-in default in sdk.go overrides mydefaults. + } + + cc_library { + name: "mynativelib", + defaults: ["mydefaults"], + srcs: [ + "Test.cpp", + ], + stl: "none", + } + + cc_binary { + name: "mynativebinary", + defaults: ["mydefaults"], + srcs: [ + "Test.cpp", + ], + stl: "none", + } + `, ccTestFs, []android.OsType{android.LinuxBionic}) + + result := runTests(t, ctx, config) + + result.CheckSnapshot("myexports", "", + checkAndroidBpContents(` +// This is auto-generated. DO NOT EDIT. + +cc_prebuilt_binary { + name: "myexports_mynativebinary@current", + sdk_member_name: "mynativebinary", + device_supported: false, + host_supported: true, + installable: false, + stl: "none", + compile_multilib: "64", + target: { + host: { + enabled: false, + }, + linux_bionic: { + enabled: true, + }, + linux_bionic_x86_64: { + srcs: ["x86_64/bin/mynativebinary"], + }, + }, +} + +cc_prebuilt_binary { + name: "mynativebinary", + prefer: false, + device_supported: false, + host_supported: true, + stl: "none", + compile_multilib: "64", + target: { + host: { + enabled: false, + }, + linux_bionic: { + enabled: true, + }, + linux_bionic_x86_64: { + srcs: ["x86_64/bin/mynativebinary"], + }, + }, +} + +cc_prebuilt_library_shared { + name: "myexports_mynativelib@current", + sdk_member_name: "mynativelib", + device_supported: false, + host_supported: true, + installable: false, + stl: "none", + compile_multilib: "64", + target: { + host: { + enabled: false, + }, + linux_bionic: { + enabled: true, + }, + linux_bionic_x86_64: { + srcs: ["x86_64/lib/mynativelib.so"], + }, + }, +} + +cc_prebuilt_library_shared { + name: "mynativelib", + prefer: false, + device_supported: false, + host_supported: true, + stl: "none", + compile_multilib: "64", + target: { + host: { + enabled: false, + }, + linux_bionic: { + enabled: true, + }, + linux_bionic_x86_64: { + srcs: ["x86_64/lib/mynativelib.so"], + }, + }, +} + +module_exports_snapshot { + name: "myexports@current", + device_supported: false, + host_supported: true, + native_binaries: ["myexports_mynativebinary@current"], + native_shared_libs: ["myexports_mynativelib@current"], + compile_multilib: "64", + target: { + host: { + enabled: false, + }, + linux_bionic: { + enabled: true, + }, + }, +} +`), + checkAllCopyRules(` +.intermediates/mynativebinary/linux_bionic_x86_64/mynativebinary -> x86_64/bin/mynativebinary +.intermediates/mynativelib/linux_bionic_x86_64_shared/mynativelib.so -> x86_64/lib/mynativelib.so +`), + ) +} + // Test that we support the necessary flags for the linker binary, which is // special in several ways. func TestSnapshotWithCcStaticNocrtBinary(t *testing.T) { @@ -621,14 +887,20 @@ cc_prebuilt_binary { host_supported: true, installable: false, stl: "none", + compile_multilib: "both", static_executable: true, nocrt: true, - compile_multilib: "both", - arch: { - x86_64: { + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + linux_glibc_x86_64: { srcs: ["x86_64/bin/linker"], }, - x86: { + linux_glibc_x86: { srcs: ["x86/bin/linker"], }, }, @@ -640,14 +912,20 @@ cc_prebuilt_binary { device_supported: false, host_supported: true, stl: "none", + compile_multilib: "both", static_executable: true, nocrt: true, - compile_multilib: "both", - arch: { - x86_64: { + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + linux_glibc_x86_64: { srcs: ["x86_64/bin/linker"], }, - x86: { + linux_glibc_x86: { srcs: ["x86/bin/linker"], }, }, @@ -658,6 +936,14 @@ module_exports_snapshot { device_supported: false, host_supported: true, native_binaries: ["mymodule_exports_linker@current"], + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + }, } `), checkAllCopyRules(` @@ -702,6 +988,7 @@ cc_prebuilt_library_shared { ], installable: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -723,6 +1010,7 @@ cc_prebuilt_library_shared { "apex2", ], stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -824,6 +1112,7 @@ cc_prebuilt_library_shared { sdk_member_name: "mynativelib", installable: false, stl: "none", + compile_multilib: "both", shared_libs: [ "mysdk_myothernativelib@current", "libc", @@ -842,6 +1131,7 @@ cc_prebuilt_library_shared { name: "mynativelib", prefer: false, stl: "none", + compile_multilib: "both", shared_libs: [ "myothernativelib", "libc", @@ -861,6 +1151,7 @@ cc_prebuilt_library_shared { sdk_member_name: "myothernativelib", installable: false, stl: "none", + compile_multilib: "both", system_shared_libs: ["libm"], arch: { arm64: { @@ -876,6 +1167,7 @@ cc_prebuilt_library_shared { name: "myothernativelib", prefer: false, stl: "none", + compile_multilib: "both", system_shared_libs: ["libm"], arch: { arm64: { @@ -892,6 +1184,7 @@ cc_prebuilt_library_shared { sdk_member_name: "mysystemnativelib", installable: false, stl: "none", + compile_multilib: "both", arch: { arm64: { srcs: ["arm64/lib/mysystemnativelib.so"], @@ -906,6 +1199,7 @@ cc_prebuilt_library_shared { name: "mysystemnativelib", prefer: false, stl: "none", + compile_multilib: "both", arch: { arm64: { srcs: ["arm64/lib/mysystemnativelib.so"], @@ -974,13 +1268,20 @@ cc_prebuilt_library_shared { installable: false, sdk_version: "minimum", stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], - arch: { - x86_64: { + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + linux_glibc_x86_64: { srcs: ["x86_64/lib/mynativelib.so"], export_include_dirs: ["x86_64/include_gen/mynativelib"], }, - x86: { + linux_glibc_x86: { srcs: ["x86/lib/mynativelib.so"], export_include_dirs: ["x86/include_gen/mynativelib"], }, @@ -994,13 +1295,20 @@ cc_prebuilt_library_shared { host_supported: true, sdk_version: "minimum", stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], - arch: { - x86_64: { + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + linux_glibc_x86_64: { srcs: ["x86_64/lib/mynativelib.so"], export_include_dirs: ["x86_64/include_gen/mynativelib"], }, - x86: { + linux_glibc_x86: { srcs: ["x86/lib/mynativelib.so"], export_include_dirs: ["x86/include_gen/mynativelib"], }, @@ -1012,6 +1320,14 @@ sdk_snapshot { device_supported: false, host_supported: true, native_shared_libs: ["mysdk_mynativelib@current"], + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + }, } `), checkAllCopyRules(` @@ -1070,12 +1386,23 @@ cc_prebuilt_library_shared { installable: false, stl: "none", target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + compile_multilib: "both", + }, linux_glibc_x86_64: { srcs: ["linux_glibc/x86_64/lib/mynativelib.so"], }, linux_glibc_x86: { srcs: ["linux_glibc/x86/lib/mynativelib.so"], }, + windows: { + enabled: true, + compile_multilib: "64", + }, windows_x86_64: { srcs: ["windows/x86_64/lib/mynativelib.dll"], }, @@ -1089,12 +1416,23 @@ cc_prebuilt_library_shared { host_supported: true, stl: "none", target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + compile_multilib: "both", + }, linux_glibc_x86_64: { srcs: ["linux_glibc/x86_64/lib/mynativelib.so"], }, linux_glibc_x86: { srcs: ["linux_glibc/x86/lib/mynativelib.so"], }, + windows: { + enabled: true, + compile_multilib: "64", + }, windows_x86_64: { srcs: ["windows/x86_64/lib/mynativelib.dll"], }, @@ -1107,7 +1445,14 @@ sdk_snapshot { host_supported: true, native_shared_libs: ["mysdk_mynativelib@current"], target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, windows: { + enabled: true, compile_multilib: "64", }, }, @@ -1151,6 +1496,7 @@ cc_prebuilt_library_static { sdk_member_name: "mynativelib", installable: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -1168,6 +1514,7 @@ cc_prebuilt_library_static { name: "mynativelib", prefer: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -1236,13 +1583,20 @@ cc_prebuilt_library_static { host_supported: true, installable: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], - arch: { - x86_64: { + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + linux_glibc_x86_64: { srcs: ["x86_64/lib/mynativelib.a"], export_include_dirs: ["x86_64/include_gen/mynativelib"], }, - x86: { + linux_glibc_x86: { srcs: ["x86/lib/mynativelib.a"], export_include_dirs: ["x86/include_gen/mynativelib"], }, @@ -1255,13 +1609,20 @@ cc_prebuilt_library_static { device_supported: false, host_supported: true, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], - arch: { - x86_64: { + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + linux_glibc_x86_64: { srcs: ["x86_64/lib/mynativelib.a"], export_include_dirs: ["x86_64/include_gen/mynativelib"], }, - x86: { + linux_glibc_x86: { srcs: ["x86/lib/mynativelib.a"], export_include_dirs: ["x86/include_gen/mynativelib"], }, @@ -1273,6 +1634,14 @@ module_exports_snapshot { device_supported: false, host_supported: true, native_static_libs: ["myexports_mynativelib@current"], + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + }, } `), checkAllCopyRules(` @@ -1315,6 +1684,7 @@ cc_prebuilt_library { sdk_member_name: "mynativelib", installable: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -1340,6 +1710,7 @@ cc_prebuilt_library { name: "mynativelib", prefer: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -1416,9 +1787,16 @@ cc_prebuilt_library_static { host_supported: true, installable: false, stl: "none", + compile_multilib: "64", export_include_dirs: ["include/include"], - arch: { - x86_64: { + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + linux_glibc_x86_64: { srcs: ["x86_64/lib/mynativelib.a"], export_include_dirs: ["x86_64/include_gen/mynativelib"], }, @@ -1431,9 +1809,16 @@ cc_prebuilt_library_static { device_supported: false, host_supported: true, stl: "none", + compile_multilib: "64", export_include_dirs: ["include/include"], - arch: { - x86_64: { + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + linux_glibc_x86_64: { srcs: ["x86_64/lib/mynativelib.a"], export_include_dirs: ["x86_64/include_gen/mynativelib"], }, @@ -1445,9 +1830,13 @@ module_exports_snapshot { device_supported: false, host_supported: true, native_static_libs: ["myexports_mynativelib@current"], + compile_multilib: "64", target: { + host: { + enabled: false, + }, linux_glibc: { - compile_multilib: "64", + enabled: true, }, }, }`), @@ -1483,6 +1872,7 @@ cc_prebuilt_library_headers { name: "mysdk_mynativeheaders@current", sdk_member_name: "mynativeheaders", stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], } @@ -1490,6 +1880,7 @@ cc_prebuilt_library_headers { name: "mynativeheaders", prefer: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], } @@ -1532,7 +1923,16 @@ cc_prebuilt_library_headers { device_supported: false, host_supported: true, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + }, } cc_prebuilt_library_headers { @@ -1541,7 +1941,16 @@ cc_prebuilt_library_headers { device_supported: false, host_supported: true, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + }, } sdk_snapshot { @@ -1549,6 +1958,14 @@ sdk_snapshot { device_supported: false, host_supported: true, native_header_libs: ["mysdk_mynativeheaders@current"], + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + }, } `), checkAllCopyRules(` @@ -1590,12 +2007,17 @@ cc_prebuilt_library_headers { sdk_member_name: "mynativeheaders", host_supported: true, stl: "none", + compile_multilib: "both", export_system_include_dirs: ["common_os/include/include"], target: { + host: { + enabled: false, + }, android: { export_include_dirs: ["android/include/include-android"], }, linux_glibc: { + enabled: true, export_include_dirs: ["linux_glibc/include/include-host"], }, }, @@ -1606,12 +2028,17 @@ cc_prebuilt_library_headers { prefer: false, host_supported: true, stl: "none", + compile_multilib: "both", export_system_include_dirs: ["common_os/include/include"], target: { + host: { + enabled: false, + }, android: { export_include_dirs: ["android/include/include-android"], }, linux_glibc: { + enabled: true, export_include_dirs: ["linux_glibc/include/include-host"], }, }, @@ -1621,6 +2048,14 @@ sdk_snapshot { name: "mysdk@current", host_supported: true, native_header_libs: ["mysdk_mynativeheaders@current"], + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + }, } `), checkAllCopyRules(` @@ -1662,6 +2097,7 @@ cc_prebuilt_library_shared { name: "mysdk_sslnil@current", sdk_member_name: "sslnil", installable: false, + compile_multilib: "both", arch: { arm64: { srcs: ["arm64/lib/sslnil.so"], @@ -1675,6 +2111,7 @@ cc_prebuilt_library_shared { cc_prebuilt_library_shared { name: "sslnil", prefer: false, + compile_multilib: "both", arch: { arm64: { srcs: ["arm64/lib/sslnil.so"], @@ -1689,6 +2126,7 @@ cc_prebuilt_library_shared { name: "mysdk_sslempty@current", sdk_member_name: "sslempty", installable: false, + compile_multilib: "both", system_shared_libs: [], arch: { arm64: { @@ -1703,6 +2141,7 @@ cc_prebuilt_library_shared { cc_prebuilt_library_shared { name: "sslempty", prefer: false, + compile_multilib: "both", system_shared_libs: [], arch: { arm64: { @@ -1718,6 +2157,7 @@ cc_prebuilt_library_shared { name: "mysdk_sslnonempty@current", sdk_member_name: "sslnonempty", installable: false, + compile_multilib: "both", system_shared_libs: ["mysdk_sslnil@current"], arch: { arm64: { @@ -1732,6 +2172,7 @@ cc_prebuilt_library_shared { cc_prebuilt_library_shared { name: "sslnonempty", prefer: false, + compile_multilib: "both", system_shared_libs: ["sslnil"], arch: { arm64: { @@ -1780,7 +2221,11 @@ cc_prebuilt_library_shared { sdk_member_name: "sslvariants", host_supported: true, installable: false, + compile_multilib: "both", target: { + host: { + enabled: false, + }, android: { system_shared_libs: [], }, @@ -1790,6 +2235,9 @@ cc_prebuilt_library_shared { android_arm: { srcs: ["android/arm/lib/sslvariants.so"], }, + linux_glibc: { + enabled: true, + }, linux_glibc_x86_64: { srcs: ["linux_glibc/x86_64/lib/sslvariants.so"], }, @@ -1803,7 +2251,11 @@ cc_prebuilt_library_shared { name: "sslvariants", prefer: false, host_supported: true, + compile_multilib: "both", target: { + host: { + enabled: false, + }, android: { system_shared_libs: [], }, @@ -1813,6 +2265,9 @@ cc_prebuilt_library_shared { android_arm: { srcs: ["android/arm/lib/sslvariants.so"], }, + linux_glibc: { + enabled: true, + }, linux_glibc_x86_64: { srcs: ["linux_glibc/x86_64/lib/sslvariants.so"], }, @@ -1826,6 +2281,14 @@ sdk_snapshot { name: "mysdk@current", host_supported: true, native_shared_libs: ["mysdk_sslvariants@current"], + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + }, } `)) } @@ -1859,6 +2322,7 @@ cc_prebuilt_library_shared { name: "mysdk_stubslib@current", sdk_member_name: "stubslib", installable: false, + compile_multilib: "both", stubs: { versions: ["3"], }, @@ -1875,6 +2339,7 @@ cc_prebuilt_library_shared { cc_prebuilt_library_shared { name: "stubslib", prefer: false, + compile_multilib: "both", stubs: { versions: ["3"], }, @@ -1928,16 +2393,23 @@ cc_prebuilt_library_shared { sdk_member_name: "stubslib", host_supported: true, installable: false, + compile_multilib: "both", stubs: { versions: ["3"], }, target: { + host: { + enabled: false, + }, android_arm64: { srcs: ["android/arm64/lib/stubslib.so"], }, android_arm: { srcs: ["android/arm/lib/stubslib.so"], }, + linux_glibc: { + enabled: true, + }, linux_glibc_x86_64: { srcs: ["linux_glibc/x86_64/lib/stubslib.so"], }, @@ -1951,16 +2423,23 @@ cc_prebuilt_library_shared { name: "stubslib", prefer: false, host_supported: true, + compile_multilib: "both", stubs: { versions: ["3"], }, target: { + host: { + enabled: false, + }, android_arm64: { srcs: ["android/arm64/lib/stubslib.so"], }, android_arm: { srcs: ["android/arm/lib/stubslib.so"], }, + linux_glibc: { + enabled: true, + }, linux_glibc_x86_64: { srcs: ["linux_glibc/x86_64/lib/stubslib.so"], }, @@ -1974,6 +2453,14 @@ sdk_snapshot { name: "mysdk@current", host_supported: true, native_shared_libs: ["mysdk_stubslib@current"], + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + }, } `)) } @@ -2003,13 +2490,20 @@ cc_prebuilt_library_shared { host_supported: true, installable: false, unique_host_soname: true, + compile_multilib: "both", target: { + host: { + enabled: false, + }, android_arm64: { srcs: ["android/arm64/lib/mylib.so"], }, android_arm: { srcs: ["android/arm/lib/mylib.so"], }, + linux_glibc: { + enabled: true, + }, linux_glibc_x86_64: { srcs: ["linux_glibc/x86_64/lib/mylib-host.so"], }, @@ -2024,13 +2518,20 @@ cc_prebuilt_library_shared { prefer: false, host_supported: true, unique_host_soname: true, + compile_multilib: "both", target: { + host: { + enabled: false, + }, android_arm64: { srcs: ["android/arm64/lib/mylib.so"], }, android_arm: { srcs: ["android/arm/lib/mylib.so"], }, + linux_glibc: { + enabled: true, + }, linux_glibc_x86_64: { srcs: ["linux_glibc/x86_64/lib/mylib-host.so"], }, @@ -2044,6 +2545,14 @@ sdk_snapshot { name: "mysdk@current", host_supported: true, native_shared_libs: ["mysdk_mylib@current"], + target: { + host: { + enabled: false, + }, + linux_glibc: { + enabled: true, + }, + }, } `), checkAllCopyRules(` diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index aee04a163..5911c718d 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -51,10 +51,10 @@ java_system_modules_import { name: "core-current-stubs-system-modules", } java_system_modules_import { - name: "legacy-core-platform-api-stubs-system-modules", + name: "stable-core-platform-api-stubs-system-modules", } java_import { - name: "legacy.core.platform.api.stubs", + name: "stable.core.platform.api.stubs", } java_import { name: "android_stubs_current", @@ -204,11 +204,11 @@ func TestBasicSdkWithJavaLibrary(t *testing.T) { } `) - sdkMemberV1 := result.ctx.ModuleForTests("sdkmember_mysdk_1", "android_common_myapex").Rule("combineJar").Output - sdkMemberV2 := result.ctx.ModuleForTests("sdkmember_mysdk_2", "android_common_myapex2").Rule("combineJar").Output + sdkMemberV1 := result.ctx.ModuleForTests("sdkmember_mysdk_1", "android_common").Rule("combineJar").Output + sdkMemberV2 := result.ctx.ModuleForTests("sdkmember_mysdk_2", "android_common").Rule("combineJar").Output - javalibForMyApex := result.ctx.ModuleForTests("myjavalib", "android_common_myapex") - javalibForMyApex2 := result.ctx.ModuleForTests("myjavalib", "android_common_myapex2") + javalibForMyApex := result.ctx.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_1") + javalibForMyApex2 := result.ctx.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_2") // Depending on the uses_sdks value, different libs are linked ensureListContains(t, pathsToStrings(javalibForMyApex.Rule("javac").Implicits), sdkMemberV1.String()) @@ -1424,8 +1424,8 @@ sdk_snapshot { .intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt .intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt .intermediates/myjavalib.stubs.module_lib/android_common/javac/myjavalib.stubs.module_lib.jar -> sdk_library/module-lib/myjavalib-stubs.jar -.intermediates/myjavalib.api.module_lib/android_common/myjavalib.api.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt -.intermediates/myjavalib.api.module_lib/android_common/myjavalib.api.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt +.intermediates/myjavalib.stubs.source.module_lib/android_common/myjavalib.stubs.source.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt +.intermediates/myjavalib.stubs.source.module_lib/android_common/myjavalib.stubs.source.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt `), checkMergeZips( ".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip", diff --git a/sdk/sdk.go b/sdk/sdk.go index 3e760080e..759102028 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -406,13 +406,17 @@ func memberInterVersionMutator(mctx android.BottomUpMutatorContext) { // Step 4: transitively ripple down the SDK requirements from the root modules like APEX to its // descendants func sdkDepsMutator(mctx android.TopDownMutatorContext) { - if m, ok := mctx.Module().(android.SdkAware); ok { + if parent, ok := mctx.Module().(interface { + android.DepIsInSameApex + android.RequiredSdks + }); ok { // Module types for Mainline modules (e.g. APEX) are expected to implement RequiredSdks() // by reading its own properties like `uses_sdks`. - requiredSdks := m.RequiredSdks() + requiredSdks := parent.RequiredSdks() if len(requiredSdks) > 0 { mctx.VisitDirectDeps(func(m android.Module) { - if dep, ok := m.(android.SdkAware); ok { + // Only propagate required sdks from the apex onto its contents. + if dep, ok := m.(android.SdkAware); ok && parent.DepIsInSameApex(mctx, dep) { dep.BuildWithSdks(requiredSdks) } }) @@ -423,15 +427,28 @@ func sdkDepsMutator(mctx android.TopDownMutatorContext) { // Step 5: if libfoo.mysdk.11 is in the context where version 11 of mysdk is requested, the // versioned module is used instead of the un-versioned (in-development) module libfoo func sdkDepsReplaceMutator(mctx android.BottomUpMutatorContext) { - if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() { - if sdk := m.ContainingSdk(); !sdk.Unversioned() { - if m.RequiredSdks().Contains(sdk) { - // Note that this replacement is done only for the modules that have the same - // variations as the current module. Since current module is already mutated for - // apex references in other APEXes are not affected by this replacement. - memberName := m.MemberName() - mctx.ReplaceDependencies(memberName) - } + if versionedSdkMember, ok := mctx.Module().(android.SdkAware); ok && versionedSdkMember.IsInAnySdk() { + if sdk := versionedSdkMember.ContainingSdk(); !sdk.Unversioned() { + // Only replace dependencies to <sdkmember> with <sdkmember@required-version> + // if the depending module requires it. e.g. + // foo -> sdkmember + // will be transformed to: + // foo -> sdkmember@1 + // if and only if foo is a member of an APEX that requires version 1 of the + // sdk containing sdkmember. + memberName := versionedSdkMember.MemberName() + + // Replace dependencies on sdkmember with a dependency on the current module which + // is a versioned prebuilt of the sdkmember if required. + mctx.ReplaceDependenciesIf(memberName, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool { + // from - foo + // to - sdkmember + replace := false + if parent, ok := from.(android.RequiredSdks); ok { + replace = parent.RequiredSdks().Contains(sdk) + } + return replace + }) } } } diff --git a/sdk/testing.go b/sdk/testing.go index 34ea8f0cc..b53558d9f 100644 --- a/sdk/testing.go +++ b/sdk/testing.go @@ -97,6 +97,11 @@ func testSdkContext(bp string, fs map[string][]byte, extraOsTypes []android.OsTy ctx.PreArchMutators(android.RegisterVisibilityRuleChecker) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) ctx.PreArchMutators(android.RegisterComponentsMutator) + + android.RegisterPrebuiltMutators(ctx) + + // Register these after the prebuilt mutators have been registered to match what + // happens at runtime. ctx.PreArchMutators(android.RegisterVisibilityRuleGatherer) ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer) diff --git a/sdk/update.go b/sdk/update.go index cf2500826..537ab13cb 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -43,7 +43,7 @@ var ( zipFiles = pctx.AndroidStaticRule("SnapshotZipFiles", blueprint.RuleParams{ - Command: `${config.SoongZipCmd} -C $basedir -l $out.rsp -o $out`, + Command: `${config.SoongZipCmd} -C $basedir -r $out.rsp -o $out`, CommandDeps: []string{ "${config.SoongZipCmd}", }, @@ -262,7 +262,7 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) andro memberCtx := &memberContext{ctx, builder, memberType, member.name} prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member) - s.createMemberSnapshot(memberCtx, member, prebuiltModule) + s.createMemberSnapshot(memberCtx, member, prebuiltModule.(*bpModule)) } // Create a transformer that will transform an unversioned module into a versioned module. @@ -323,19 +323,62 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) andro // Add properties common to all os types. s.addMemberPropertiesToPropertySet(builder, snapshotModule, commonDynamicMemberProperties) - // Iterate over the os types in a fixed order. + // Optimize other per-variant properties, besides the dynamic member lists. + type variantProperties struct { + Compile_multilib string `android:"arch_variant"` + } + var variantPropertiesContainers []propertiesContainer + variantToProperties := make(map[*sdk]*variantProperties) + for _, sdkVariant := range sdkVariants { + props := &variantProperties{ + Compile_multilib: sdkVariant.multilibUsages.String(), + } + variantPropertiesContainers = append(variantPropertiesContainers, &dynamicMemberPropertiesContainer{sdkVariant, props}) + variantToProperties[sdkVariant] = props + } + commonVariantProperties := variantProperties{} + extractor = newCommonValueExtractor(commonVariantProperties) + extractCommonProperties(ctx, extractor, &commonVariantProperties, variantPropertiesContainers) + if commonVariantProperties.Compile_multilib != "" && commonVariantProperties.Compile_multilib != "both" { + // Compile_multilib defaults to both so only needs to be set when it's + // specified and not both. + snapshotModule.AddProperty("compile_multilib", commonVariantProperties.Compile_multilib) + } + targetPropertySet := snapshotModule.AddPropertySet("target") + + // If host is supported and any member is host OS dependent then disable host + // by default, so that we can enable each host OS variant explicitly. This + // avoids problems with implicitly enabled OS variants when the snapshot is + // used, which might be different from this run (e.g. different build OS). + hasHostOsDependentMember := false + if s.HostSupported() { + for _, memberRef := range memberRefs { + if memberRef.memberType.IsHostOsDependent() { + hasHostOsDependentMember = true + break + } + } + if hasHostOsDependentMember { + hostPropertySet := targetPropertySet.AddPropertySet("host") + hostPropertySet.AddProperty("enabled", false) + } + } + + // Iterate over the os types in a fixed order. for _, osType := range s.getPossibleOsTypes() { if sdkVariant, ok := osTypeToMemberProperties[osType]; ok { osPropertySet := targetPropertySet.AddPropertySet(sdkVariant.Target().Os.Name) - // Compile_multilib defaults to both and must always be set to both on the - // device and so only needs to be set when targeted at the host and is neither - // unspecified or both. - multilib := sdkVariant.multilibUsages - if (osType.Class == android.Host || osType.Class == android.HostCross) && - multilib != multilibNone && multilib != multilibBoth { - osPropertySet.AddProperty("compile_multilib", multilib.String()) + // Enable the variant explicitly when we've disabled it by default on host. + if hasHostOsDependentMember && + (osType.Class == android.Host || osType.Class == android.HostCross) { + osPropertySet.AddProperty("enabled", true) + } + + variantProps := variantToProperties[sdkVariant] + if variantProps.Compile_multilib != "" && variantProps.Compile_multilib != "both" { + osPropertySet.AddProperty("compile_multilib", variantProps.Compile_multilib) } s.addMemberPropertiesToPropertySet(builder, osPropertySet, sdkVariant.dynamicMemberTypeListProperties) @@ -794,6 +837,17 @@ func (s *snapshotBuilder) isInternalMember(memberName string) bool { return !ok } +// Add the properties from the given SdkMemberProperties to the blueprint +// property set. This handles common properties in SdkMemberPropertiesBase and +// calls the member-specific AddToPropertySet for the rest. +func addSdkMemberPropertiesToSet(ctx *memberContext, memberProperties android.SdkMemberProperties, targetPropertySet android.BpPropertySet) { + if memberProperties.Base().Compile_multilib != "" { + targetPropertySet.AddProperty("compile_multilib", memberProperties.Base().Compile_multilib) + } + + memberProperties.AddToPropertySet(ctx, targetPropertySet) +} + type sdkMemberRef struct { memberType android.SdkMemberType variant android.SdkAware @@ -964,9 +1018,12 @@ func (osInfo *osTypeSpecificInfo) addToPropertySet(ctx *memberContext, bpModule var osPropertySet android.BpPropertySet var archPropertySet android.BpPropertySet var archOsPrefix string - if osInfo.Properties.Base().Os_count == 1 { - // There is only one os type present in the variants so don't bother - // with adding target specific properties. + if osInfo.Properties.Base().Os_count == 1 && + (osInfo.osType.Class == android.Device || !ctx.memberType.IsHostOsDependent()) { + // There is only one OS type present in the variants and it shouldn't have a + // variant-specific target. The latter is the case if it's either for device + // where there is only one OS (android), or for host and the member type + // isn't host OS dependent. // Create a structure that looks like: // module_type { @@ -1003,13 +1060,19 @@ func (osInfo *osTypeSpecificInfo) addToPropertySet(ctx *memberContext, bpModule osPropertySet = targetPropertySet.AddPropertySet(osType.Name) archPropertySet = targetPropertySet + // Enable the variant explicitly when we've disabled it by default on host. + if ctx.memberType.IsHostOsDependent() && + (osType.Class == android.Host || osType.Class == android.HostCross) { + osPropertySet.AddProperty("enabled", true) + } + // Arch specific properties need to be added to an os and arch specific // section prefixed with <os>_. archOsPrefix = osType.Name + "_" } // Add the os specific but arch independent properties to the module. - osInfo.Properties.AddToPropertySet(ctx, osPropertySet) + addSdkMemberPropertiesToSet(ctx, osInfo.Properties, osPropertySet) // Add arch (and possibly os) specific sections for each set of arch (and possibly // os) specific properties. @@ -1111,11 +1174,11 @@ func (archInfo *archTypeSpecificInfo) optimizeProperties(ctx *memberContext, com func (archInfo *archTypeSpecificInfo) addToPropertySet(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) { archTypeName := archInfo.archType.Name archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName) - archInfo.Properties.AddToPropertySet(ctx, archTypePropertySet) + addSdkMemberPropertiesToSet(ctx, archInfo.Properties, archTypePropertySet) for _, linkInfo := range archInfo.linkInfos { linkPropertySet := archTypePropertySet.AddPropertySet(linkInfo.linkType) - linkInfo.Properties.AddToPropertySet(ctx, linkPropertySet) + addSdkMemberPropertiesToSet(ctx, linkInfo.Properties, linkPropertySet) } } @@ -1173,7 +1236,7 @@ func (m *memberContext) Name() string { return m.name } -func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule android.BpModule) { +func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) { memberType := member.memberType @@ -1221,12 +1284,24 @@ func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModu extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, commonProperties, osSpecificPropertiesContainers) // Add the common properties to the module. - commonProperties.AddToPropertySet(ctx, bpModule) + addSdkMemberPropertiesToSet(ctx, commonProperties, bpModule) // Create a target property set into which target specific properties can be // added. targetPropertySet := bpModule.AddPropertySet("target") + // If the member is host OS dependent and has host_supported then disable by + // default and enable each host OS variant explicitly. This avoids problems + // with implicitly enabled OS variants when the snapshot is used, which might + // be different from this run (e.g. different build OS). + if ctx.memberType.IsHostOsDependent() { + hostSupported := bpModule.getValue("host_supported") == true // Missing means false. + if hostSupported { + hostPropertySet := targetPropertySet.AddPropertySet("host") + hostPropertySet.AddProperty("enabled", false) + } + } + // Iterate over the os types in a fixed order. for _, osType := range s.getPossibleOsTypes() { osInfo := osTypeToInfo[osType] diff --git a/sh/Android.bp b/sh/Android.bp index 0f40c5f68..e5ffeefb4 100644 --- a/sh/Android.bp +++ b/sh/Android.bp @@ -5,6 +5,7 @@ bootstrap_go_package { "blueprint", "soong", "soong-android", + "soong-cc", "soong-tradefed", ], srcs: [ diff --git a/sh/sh_binary.go b/sh/sh_binary.go index f28b2b685..f3f4a4aa7 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -17,11 +17,14 @@ package sh import ( "fmt" "path/filepath" + "sort" "strings" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/cc" "android/soong/tradefed" ) @@ -61,6 +64,12 @@ type shBinaryProperties struct { // install symlinks to the binary Symlinks []string `android:"arch_variant"` + + // Make this module available when building for ramdisk. + Ramdisk_available *bool + + // Make this module available when building for recovery. + Recovery_available *bool } type TestProperties struct { @@ -88,6 +97,20 @@ type TestProperties struct { // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true // explicitly. Auto_gen_config *bool + + // list of binary modules that should be installed alongside the test + Data_bins []string `android:"path,arch_variant"` + + // list of library modules that should be installed alongside the test + Data_libs []string `android:"path,arch_variant"` + + // list of device binary modules that should be installed alongside the test. + // Only available for host sh_test modules. + Data_device_bins []string `android:"path,arch_variant"` + + // list of device library modules that should be installed alongside the test. + // Only available for host sh_test modules. + Data_device_libs []string `android:"path,arch_variant"` } type ShBinary struct { @@ -111,6 +134,8 @@ type ShTest struct { data android.Paths testConfig android.Path + + dataModules map[string]android.Path } func (s *ShBinary) HostToolPath() android.OptionalPath { @@ -139,6 +164,29 @@ func (s *ShBinary) Symlinks() []string { return s.properties.Symlinks } +var _ android.ImageInterface = (*ShBinary)(nil) + +func (s *ShBinary) ImageMutatorBegin(ctx android.BaseModuleContext) {} + +func (s *ShBinary) CoreVariantNeeded(ctx android.BaseModuleContext) bool { + return !s.ModuleBase.InstallInRecovery() && !s.ModuleBase.InstallInRamdisk() +} + +func (s *ShBinary) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { + return proptools.Bool(s.properties.Ramdisk_available) || s.ModuleBase.InstallInRamdisk() +} + +func (s *ShBinary) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { + return proptools.Bool(s.properties.Recovery_available) || s.ModuleBase.InstallInRecovery() +} + +func (s *ShBinary) ExtraImageVariations(ctx android.BaseModuleContext) []string { + return nil +} + +func (s *ShBinary) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) { +} + func (s *ShBinary) generateAndroidBuildActions(ctx android.ModuleContext) { s.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(s.properties.Src)) filename := proptools.String(s.properties.Filename) @@ -192,6 +240,50 @@ func (s *ShBinary) customAndroidMkEntries(entries *android.AndroidMkEntries) { } } +type dependencyTag struct { + blueprint.BaseDependencyTag + name string +} + +var ( + shTestDataBinsTag = dependencyTag{name: "dataBins"} + shTestDataLibsTag = dependencyTag{name: "dataLibs"} + shTestDataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"} + shTestDataDeviceLibsTag = dependencyTag{name: "dataDeviceLibs"} +) + +var sharedLibVariations = []blueprint.Variation{{Mutator: "link", Variation: "shared"}} + +func (s *ShTest) DepsMutator(ctx android.BottomUpMutatorContext) { + s.ShBinary.DepsMutator(ctx) + + ctx.AddFarVariationDependencies(ctx.Target().Variations(), shTestDataBinsTag, s.testProperties.Data_bins...) + ctx.AddFarVariationDependencies(append(ctx.Target().Variations(), sharedLibVariations...), + shTestDataLibsTag, s.testProperties.Data_libs...) + if ctx.Target().Os.Class == android.Host && len(ctx.Config().Targets[android.Android]) > 0 { + deviceVariations := ctx.Config().Targets[android.Android][0].Variations() + ctx.AddFarVariationDependencies(deviceVariations, shTestDataDeviceBinsTag, s.testProperties.Data_device_bins...) + ctx.AddFarVariationDependencies(append(deviceVariations, sharedLibVariations...), + shTestDataDeviceLibsTag, s.testProperties.Data_device_libs...) + } else if ctx.Target().Os.Class != android.Host { + if len(s.testProperties.Data_device_bins) > 0 { + ctx.PropertyErrorf("data_device_bins", "only available for host modules") + } + if len(s.testProperties.Data_device_libs) > 0 { + ctx.PropertyErrorf("data_device_libs", "only available for host modules") + } + } +} + +func (s *ShTest) addToDataModules(ctx android.ModuleContext, relPath string, path android.Path) { + if _, exists := s.dataModules[relPath]; exists { + ctx.ModuleErrorf("data modules have a conflicting installation path, %v - %s, %s", + relPath, s.dataModules[relPath].String(), path.String()) + return + } + s.dataModules[relPath] = path +} + func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { s.ShBinary.generateAndroidBuildActions(ctx) testDir := "nativetest" @@ -223,6 +315,50 @@ func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { } s.testConfig = tradefed.AutoGenShellTestConfig(ctx, s.testProperties.Test_config, s.testProperties.Test_config_template, s.testProperties.Test_suites, configs, s.testProperties.Auto_gen_config, s.outputFilePath.Base()) + + s.dataModules = make(map[string]android.Path) + ctx.VisitDirectDeps(func(dep android.Module) { + depTag := ctx.OtherModuleDependencyTag(dep) + switch depTag { + case shTestDataBinsTag, shTestDataDeviceBinsTag: + if cc, isCc := dep.(*cc.Module); isCc { + s.addToDataModules(ctx, cc.OutputFile().Path().Base(), cc.OutputFile().Path()) + return + } + property := "data_bins" + if depTag == shTestDataDeviceBinsTag { + property = "data_device_bins" + } + ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep)) + case shTestDataLibsTag, shTestDataDeviceLibsTag: + if cc, isCc := dep.(*cc.Module); isCc { + // Copy to an intermediate output directory to append "lib[64]" to the path, + // so that it's compatible with the default rpath values. + var relPath string + if cc.Arch().ArchType.Multilib == "lib64" { + relPath = filepath.Join("lib64", cc.OutputFile().Path().Base()) + } else { + relPath = filepath.Join("lib", cc.OutputFile().Path().Base()) + } + if _, exist := s.dataModules[relPath]; exist { + return + } + relocatedLib := android.PathForModuleOut(ctx, "relocated", relPath) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: cc.OutputFile().Path(), + Output: relocatedLib, + }) + s.addToDataModules(ctx, relPath, relocatedLib) + return + } + property := "data_libs" + if depTag == shTestDataDeviceBinsTag { + property = "data_device_libs" + } + ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep)) + } + }) } func (s *ShTest) InstallInData() bool { @@ -251,6 +387,15 @@ func (s *ShTest) AndroidMkEntries() []android.AndroidMkEntries { path = strings.TrimSuffix(path, rel) entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel) } + relPaths := make([]string, 0) + for relPath, _ := range s.dataModules { + relPaths = append(relPaths, relPath) + } + sort.Strings(relPaths) + for _, relPath := range relPaths { + dir := strings.TrimSuffix(s.dataModules[relPath].String(), relPath) + entries.AddStrings("LOCAL_TEST_DATA", dir+":"+relPath) + } }, }, }} diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go index 3bfe6110a..0aa607b6f 100644 --- a/sh/sh_binary_test.go +++ b/sh/sh_binary_test.go @@ -3,10 +3,12 @@ package sh import ( "io/ioutil" "os" + "path/filepath" "reflect" "testing" "android/soong/android" + "android/soong/cc" ) var buildDir string @@ -46,6 +48,9 @@ func testShBinary(t *testing.T, bp string) (*android.TestContext, android.Config ctx := android.NewTestArchContext() ctx.RegisterModuleType("sh_test", ShTestFactory) ctx.RegisterModuleType("sh_test_host", ShTestHostFactory) + + cc.RegisterRequiredBuildComponentsForTest(ctx) + ctx.Register(config) _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) android.FailIfErrored(t, errs) @@ -105,6 +110,65 @@ func TestShTest(t *testing.T) { } } +func TestShTest_dataModules(t *testing.T) { + ctx, config := testShBinary(t, ` + sh_test { + name: "foo", + src: "test.sh", + host_supported: true, + data_bins: ["bar"], + data_libs: ["libbar"], + } + + cc_binary { + name: "bar", + host_supported: true, + shared_libs: ["libbar"], + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } + + cc_library { + name: "libbar", + host_supported: true, + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } + `) + + buildOS := android.BuildOs.String() + arches := []string{"android_arm64_armv8-a", buildOS + "_x86_64"} + for _, arch := range arches { + variant := ctx.ModuleForTests("foo", arch) + + libExt := ".so" + if arch == "darwin_x86_64" { + libExt = ".dylib" + } + relocated := variant.Output("relocated/lib64/libbar" + libExt) + expectedInput := filepath.Join(buildDir, ".intermediates/libbar/"+arch+"_shared/libbar"+libExt) + if relocated.Input.String() != expectedInput { + t.Errorf("Unexpected relocation input, expected: %q, actual: %q", + expectedInput, relocated.Input.String()) + } + + mod := variant.Module().(*ShTest) + entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0] + expectedData := []string{ + filepath.Join(buildDir, ".intermediates/bar", arch, ":bar"), + filepath.Join(buildDir, ".intermediates/foo", arch, "relocated/:lib64/libbar"+libExt), + } + actualData := entries.EntryMap["LOCAL_TEST_DATA"] + if !reflect.DeepEqual(expectedData, actualData) { + t.Errorf("Unexpected test data, expected: %q, actual: %q", expectedData, actualData) + } + } +} + func TestShTestHost(t *testing.T) { ctx, _ := testShBinary(t, ` sh_test_host { @@ -124,3 +188,53 @@ func TestShTestHost(t *testing.T) { t.Errorf("host bit is not set for a sh_test_host module.") } } + +func TestShTestHost_dataDeviceModules(t *testing.T) { + ctx, config := testShBinary(t, ` + sh_test_host { + name: "foo", + src: "test.sh", + data_device_bins: ["bar"], + data_device_libs: ["libbar"], + } + + cc_binary { + name: "bar", + shared_libs: ["libbar"], + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } + + cc_library { + name: "libbar", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } + `) + + buildOS := android.BuildOs.String() + variant := ctx.ModuleForTests("foo", buildOS+"_x86_64") + + relocated := variant.Output("relocated/lib64/libbar.so") + expectedInput := filepath.Join(buildDir, ".intermediates/libbar/android_arm64_armv8-a_shared/libbar.so") + if relocated.Input.String() != expectedInput { + t.Errorf("Unexpected relocation input, expected: %q, actual: %q", + expectedInput, relocated.Input.String()) + } + + mod := variant.Module().(*ShTest) + entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0] + expectedData := []string{ + filepath.Join(buildDir, ".intermediates/bar/android_arm64_armv8-a/:bar"), + // libbar has been relocated, and so has a variant that matches the host arch. + filepath.Join(buildDir, ".intermediates/foo/"+buildOS+"_x86_64/relocated/:lib64/libbar.so"), + } + actualData := entries.EntryMap["LOCAL_TEST_DATA"] + if !reflect.DeepEqual(expectedData, actualData) { + t.Errorf("Unexpected test data, expected: %q, actual: %q", expectedData, actualData) + } +} diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go index 850338675..711129c84 100644 --- a/sysprop/sysprop_test.go +++ b/sysprop/sysprop_test.go @@ -67,6 +67,8 @@ func testContext(config android.Config) *android.TestContext { ctx.BottomUp("sysprop_deps", syspropDepsMutator).Parallel() }) + android.RegisterPrebuiltMutators(ctx) + cc.RegisterRequiredBuildComponentsForTest(ctx) ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("sysprop_java", java.SyspropMutator).Parallel() diff --git a/third_party/zip/android.go b/third_party/zip/android.go index 8d387ccb1..f8e45c56d 100644 --- a/third_party/zip/android.go +++ b/third_party/zip/android.go @@ -43,6 +43,15 @@ func (w *Writer) CopyFrom(orig *File, newName string) error { offset: uint64(w.cw.count), } w.dir = append(w.dir, h) + if !fh.isZip64() { + // Some writers will generate 64 bit sizes and set 32 bit fields to + // uint32max even if the actual size fits in 32 bit. So we should + // make sure CompressedSize contains the correct value in such + // cases. With out the two lines below we would be writing invalid(-1) + // sizes in such case. + fh.CompressedSize = uint32(fh.CompressedSize64) + fh.UncompressedSize = uint32(fh.UncompressedSize64) + } if err := writeHeader(w.cw, fh); err != nil { return err diff --git a/third_party/zip/zip_test.go b/third_party/zip/zip_test.go index 73736606e..559c91402 100644 --- a/third_party/zip/zip_test.go +++ b/third_party/zip/zip_test.go @@ -219,7 +219,7 @@ func TestRLEBuffer(t *testing.T) { } } -// fakeHash32 is a dummy Hash32 that always returns 0. +// fakeHash32 is a fake Hash32 that always returns 0. type fakeHash32 struct { hash.Hash32 } diff --git a/tradefed/autogen.go b/tradefed/autogen.go index 1cb874d7f..798fc40fc 100644 --- a/tradefed/autogen.go +++ b/tradefed/autogen.go @@ -239,6 +239,21 @@ func AutoGenRustTestConfig(ctx android.ModuleContext, testConfigProp *string, return path } +func AutoGenRobolectricTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string, + testSuites []string, autoGenConfig *bool) android.Path { + path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp) + if autogenPath != nil { + templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) + if templatePath.Valid() { + autogenTemplate(ctx, autogenPath, templatePath.String(), nil) + } else { + autogenTemplate(ctx, autogenPath, "${RobolectricTestConfigTemplate}", nil) + } + return autogenPath + } + return path +} + var autogenInstrumentationTest = pctx.StaticRule("autogenInstrumentationTest", blueprint.RuleParams{ Command: "${AutoGenTestConfigScript} $out $in ${EmptyTestConfig} $template ${extraConfigs}", CommandDeps: []string{ diff --git a/tradefed/config.go b/tradefed/config.go index 34195c364..f7e834988 100644 --- a/tradefed/config.go +++ b/tradefed/config.go @@ -33,6 +33,7 @@ func init() { pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml") pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml") pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml") + pctx.SourcePathVariable("RobolectricTestConfigTemplate", "build/make/core/robolectric_test_config_template.xml") pctx.SourcePathVariable("ShellTestConfigTemplate", "build/make/core/shell_test_config_template.xml") pctx.SourcePathVariable("EmptyTestConfig", "build/make/core/empty_test_config.xml") diff --git a/ui/build/config.go b/ui/build/config.go index ba477e61a..e9a8fc910 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -15,6 +15,7 @@ package build import ( + "fmt" "os" "path/filepath" "runtime" @@ -23,6 +24,9 @@ import ( "time" "android/soong/shared" + "github.com/golang/protobuf/proto" + + smpb "android/soong/ui/metrics/metrics_proto" ) type Config struct{ *configImpl } @@ -53,8 +57,6 @@ type configImpl struct { // Autodetected totalRAM uint64 - pdkBuild bool - brokenDupRules bool brokenUsesNetwork bool brokenNinjaEnvVars []string @@ -96,7 +98,7 @@ func NewConfig(ctx Context, args ...string) Config { environ: OsEnvironment(), } - // Sane default matching ninja + // Default matching ninja ret.parallel = runtime.NumCPU() + 2 ret.keepGoing = 1 @@ -260,12 +262,14 @@ func NewConfig(ctx Context, args ...string) Config { ret.environ.Set("BUILD_DATETIME_FILE", buildDateTimeFile) if ret.UseRBE() { - for k, v := range getRBEVars(ctx, tmpDir) { + for k, v := range getRBEVars(ctx, Config{ret}) { ret.environ.Set(k, v) } } - return Config{ret} + c := Config{ret} + storeConfigMetrics(ctx, c) + return c } // NewBuildActionConfig returns a build configuration based on the build action. The arguments are @@ -274,6 +278,20 @@ func NewBuildActionConfig(action BuildAction, dir string, ctx Context, args ...s return NewConfig(ctx, getConfigArgs(action, dir, ctx, args)...) } +// storeConfigMetrics selects a set of configuration information and store in +// the metrics system for further analysis. +func storeConfigMetrics(ctx Context, config Config) { + if ctx.Metrics == nil { + return + } + + b := &smpb.BuildConfig{ + UseGoma: proto.Bool(config.UseGoma()), + UseRbe: proto.Bool(config.UseRBE()), + } + ctx.Metrics.BuildConfig(b) +} + // getConfigArgs processes the command arguments based on the build action and creates a set of new // arguments to be accepted by Config. func getConfigArgs(action BuildAction, dir string, ctx Context, args []string) []string { @@ -808,13 +826,73 @@ func (c *configImpl) StartRBE() bool { return true } -func (c *configImpl) RBEStatsOutputDir() string { +func (c *configImpl) logDir() string { + if c.Dist() { + return filepath.Join(c.DistDir(), "logs") + } + return c.OutDir() +} + +func (c *configImpl) rbeStatsOutputDir() string { for _, f := range []string{"RBE_output_dir", "FLAG_output_dir"} { if v, ok := c.environ.Get(f); ok { return v } } - return "" + return c.logDir() +} + +func (c *configImpl) rbeLogPath() string { + for _, f := range []string{"RBE_log_path", "FLAG_log_path"} { + if v, ok := c.environ.Get(f); ok { + return v + } + } + return fmt.Sprintf("text://%v/reproxy_log.txt", c.logDir()) +} + +func (c *configImpl) rbeExecRoot() string { + for _, f := range []string{"RBE_exec_root", "FLAG_exec_root"} { + if v, ok := c.environ.Get(f); ok { + return v + } + } + wd, err := os.Getwd() + if err != nil { + return "" + } + return wd +} + +func (c *configImpl) rbeDir() string { + if v, ok := c.environ.Get("RBE_DIR"); ok { + return v + } + return "prebuilts/remoteexecution-client/live/" +} + +func (c *configImpl) rbeReproxy() string { + for _, f := range []string{"RBE_re_proxy", "FLAG_re_proxy"} { + if v, ok := c.environ.Get(f); ok { + return v + } + } + return filepath.Join(c.rbeDir(), "reproxy") +} + +func (c *configImpl) rbeAuth() (string, string) { + credFlags := []string{"use_application_default_credentials", "use_gce_credentials", "credential_file"} + for _, cf := range credFlags { + for _, f := range []string{"RBE_" + cf, "FLAG_" + cf} { + if v, ok := c.environ.Get(f); ok { + v = strings.TrimSpace(v) + if v != "" && v != "false" && v != "0" { + return "RBE_" + cf, v + } + } + } + } + return "RBE_use_application_default_credentials", "true" } func (c *configImpl) UseRemoteBuild() bool { @@ -968,14 +1046,6 @@ func (c *configImpl) TargetDeviceDir() string { return c.targetDeviceDir } -func (c *configImpl) SetPdkBuild(pdk bool) { - c.pdkBuild = pdk -} - -func (c *configImpl) IsPdkBuild() bool { - return c.pdkBuild -} - func (c *configImpl) BuildDateTime() string { return c.buildDateTime } diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go index e22985675..999af0796 100644 --- a/ui/build/dumpvars.go +++ b/ui/build/dumpvars.go @@ -161,8 +161,6 @@ var BannerVars = []string{ "BUILD_ID", "OUT_DIR", "AUX_OS_VARIANT_LIST", - "TARGET_BUILD_PDK", - "PDK_FUSION_PLATFORM_ZIP", "PRODUCT_SOONG_NAMESPACES", } @@ -281,7 +279,6 @@ func runMakeProductConfig(ctx Context, config Config) { config.SetTargetDevice(make_vars["TARGET_DEVICE"]) config.SetTargetDeviceDir(make_vars["TARGET_DEVICE_DIR"]) - config.SetPdkBuild(make_vars["TARGET_BUILD_PDK"] == "true") config.SetBuildBrokenDupRules(make_vars["BUILD_BROKEN_DUP_RULES"] == "true") config.SetBuildBrokenUsesNetwork(make_vars["BUILD_BROKEN_USES_NETWORK"] == "true") config.SetBuildBrokenNinjaUsesEnvVars(strings.Fields(make_vars["BUILD_BROKEN_NINJA_USES_ENV_VARS"])) diff --git a/ui/build/kati.go b/ui/build/kati.go index 1cd5fea32..f6d3a5741 100644 --- a/ui/build/kati.go +++ b/ui/build/kati.go @@ -134,14 +134,10 @@ func runKatiBuild(ctx Context, config Config) { args := []string{ "--writable", config.OutDir() + "/", + "--werror_implicit_rules", "-f", "build/make/core/main.mk", } - // PDK builds still uses a few implicit rules - if !config.IsPdkBuild() { - args = append(args, "--werror_implicit_rules") - } - if !config.BuildBrokenDupRules() { args = append(args, "--werror_overriding_commands") } diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go index 571740133..81c500d2b 100644 --- a/ui/build/paths/config.go +++ b/ui/build/paths/config.go @@ -88,7 +88,6 @@ var Configuration = map[string]PathConfig{ "javap": Allowed, "lsof": Allowed, "openssl": Allowed, - "patch": Allowed, "pstree": Allowed, "rsync": Allowed, "sh": Allowed, diff --git a/ui/build/rbe.go b/ui/build/rbe.go index fd3b7abb5..67bcebb75 100644 --- a/ui/build/rbe.go +++ b/ui/build/rbe.go @@ -37,10 +37,8 @@ const ( func rbeCommand(ctx Context, config Config, rbeCmd string) string { var cmdPath string - if rbeDir, ok := config.Environment().Get("RBE_DIR"); ok { + if rbeDir := config.rbeDir(); rbeDir != "" { cmdPath = filepath.Join(rbeDir, rbeCmd) - } else if home, ok := config.Environment().Get("HOME"); ok { - cmdPath = filepath.Join(home, "rbe", rbeCmd) } else { ctx.Fatalf("rbe command path not found") } @@ -52,9 +50,21 @@ func rbeCommand(ctx Context, config Config, rbeCmd string) string { return cmdPath } -func getRBEVars(ctx Context, tmpDir string) map[string]string { +func getRBEVars(ctx Context, config Config) map[string]string { rand.Seed(time.Now().UnixNano()) - return map[string]string{"RBE_server_address": fmt.Sprintf("unix://%v/reproxy_%v.sock", tmpDir, rand.Intn(1000))} + vars := map[string]string{ + "RBE_log_path": config.rbeLogPath(), + "RBE_log_dir": config.logDir(), + "RBE_re_proxy": config.rbeReproxy(), + "RBE_exec_root": config.rbeExecRoot(), + "RBE_output_dir": config.rbeStatsOutputDir(), + } + if config.StartRBE() { + vars["RBE_server_address"] = fmt.Sprintf("unix://%v/reproxy_%v.sock", absPath(ctx, config.TempDir()), rand.Intn(1000)) + } + k, v := config.rbeAuth() + vars[k] = v + return vars } func startRBE(ctx Context, config Config) { @@ -102,7 +112,7 @@ func DumpRBEMetrics(ctx Context, config Config, filename string) { return } - outputDir := config.RBEStatsOutputDir() + outputDir := config.rbeStatsOutputDir() if outputDir == "" { ctx.Fatal("RBE output dir variable not defined. Aborting metrics dumping.") } @@ -111,7 +121,20 @@ func DumpRBEMetrics(ctx Context, config Config, filename string) { // Stop the proxy first in order to generate the RBE metrics protobuf file. stopRBE(ctx, config) + if metricsFile == filename { + return + } if _, err := copyFile(metricsFile, filename); err != nil { ctx.Fatalf("failed to copy %q to %q: %v\n", metricsFile, filename, err) } } + +// PrintGomaDeprecation prints a PSA on the deprecation of Goma if it is set for the build. +func PrintGomaDeprecation(ctx Context, config Config) { + if config.UseGoma() { + fmt.Fprintln(ctx.Writer, "") + fmt.Fprintln(ctx.Writer, "Goma for Android is being deprecated and replaced with RBE.") + fmt.Fprintln(ctx.Writer, "See go/goma_android_deprecation for more details.") + fmt.Fprintln(ctx.Writer, "") + } +} diff --git a/ui/build/rbe_test.go b/ui/build/rbe_test.go index 2c4995b1d..8ff96bcbb 100644 --- a/ui/build/rbe_test.go +++ b/ui/build/rbe_test.go @@ -83,24 +83,13 @@ func TestDumpRBEMetrics(t *testing.T) { func TestDumpRBEMetricsErrors(t *testing.T) { ctx := testContext() tests := []struct { - description string - rbeOutputDirDefined bool - bootstrapProgram string - expectedErr string + description string + bootstrapProgram string + expectedErr string }{{ - description: "output_dir not defined", - bootstrapProgram: rbeBootstrapProgram, - expectedErr: "RBE output dir variable not defined", - }, { - description: "stopRBE failed", - rbeOutputDirDefined: true, - bootstrapProgram: "#!/bin/bash\nexit 1", - expectedErr: "shutdown failed", - }, { - description: "failed to copy metrics file", - rbeOutputDirDefined: true, - bootstrapProgram: "#!/bin/bash", - expectedErr: "failed to copy", + description: "stopRBE failed", + bootstrapProgram: "#!/bin/bash\nexit 1\n", + expectedErr: "shutdown failed", }} for _, tt := range tests { @@ -124,10 +113,6 @@ func TestDumpRBEMetricsErrors(t *testing.T) { env.Set("OUT_DIR", tmpDir) env.Set("RBE_DIR", tmpDir) - if tt.rbeOutputDirDefined { - env.Set("RBE_output_dir", t.TempDir()) - } - config := Config{&configImpl{ environ: env, }} @@ -139,4 +124,4 @@ func TestDumpRBEMetricsErrors(t *testing.T) { } } -var rbeBootstrapProgram = fmt.Sprintf("#!/bin/bash\necho 1 > $RBE_output_dir/%s", rbeMetricsPBFilename) +var rbeBootstrapProgram = fmt.Sprintf("#!/bin/bash\necho 1 > $RBE_output_dir/%s\n", rbeMetricsPBFilename) diff --git a/ui/build/upload.go b/ui/build/upload.go index 1cc2e940c..a9346e0c5 100644 --- a/ui/build/upload.go +++ b/ui/build/upload.go @@ -44,7 +44,7 @@ var ( // environment variable. The metrics files are copied to a temporary directory // and the uploader is then executed in the background to allow the user to continue // working. -func UploadMetrics(ctx Context, config Config, forceDumbOutput bool, buildStarted time.Time, files ...string) { +func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, files ...string) { ctx.BeginTrace(metrics.RunSetupTool, "upload_metrics") defer ctx.EndTrace() @@ -105,7 +105,7 @@ func UploadMetrics(ctx Context, config Config, forceDumbOutput bool, buildStarte // Start the uploader in the background as it takes several milliseconds to start the uploader // and prepare the metrics for upload. This affects small commands like "lunch". cmd := Command(ctx, config, "upload metrics", uploader, "--upload-metrics", pbFile) - if forceDumbOutput { + if simpleOutput { cmd.RunOrFatal() } else { cmd.RunAndStreamOrFatal() diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go index 2b5c4c3f6..f5552a3af 100644 --- a/ui/metrics/metrics.go +++ b/ui/metrics/metrics.go @@ -17,6 +17,7 @@ package metrics import ( "io/ioutil" "os" + "runtime" "time" "github.com/golang/protobuf/proto" @@ -65,6 +66,10 @@ func (m *Metrics) SetTimeMetrics(perf soong_metrics_proto.PerfInfo) { } } +func (m *Metrics) BuildConfig(b *soong_metrics_proto.BuildConfig) { + m.metrics.BuildConfig = b +} + func (m *Metrics) SetMetadataMetrics(metadata map[string]string) { for k, v := range metadata { switch k { @@ -98,8 +103,6 @@ func (m *Metrics) SetMetadataMetrics(metadata map[string]string) { m.metrics.HostArch = m.getArch(v) case "HOST_2ND_ARCH": m.metrics.Host_2NdArch = m.getArch(v) - case "HOST_OS": - m.metrics.HostOs = proto.String(v) case "HOST_OS_EXTRA": m.metrics.HostOsExtra = proto.String(v) case "HOST_CROSS_OS": @@ -137,6 +140,7 @@ func (m *Metrics) SetBuildDateTime(buildTimestamp time.Time) { // exports the output to the file at outputPath func (m *Metrics) Dump(outputPath string) (err error) { + m.metrics.HostOs = proto.String(runtime.GOOS) return writeMessageToFile(&m.metrics, outputPath) } diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go index a39d1a83a..d7c53ec2b 100644 --- a/ui/metrics/metrics_proto/metrics.pb.go +++ b/ui/metrics/metrics_proto/metrics.pb.go @@ -152,7 +152,7 @@ func (x *ModuleTypeInfo_BuildSystem) UnmarshalJSON(data []byte) error { } func (ModuleTypeInfo_BuildSystem) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{2, 0} + return fileDescriptor_6039342a2ba47b72, []int{3, 0} } type MetricsBase struct { @@ -199,6 +199,7 @@ type MetricsBase struct { // The metrics for the whole build Total *PerfInfo `protobuf:"bytes,21,opt,name=total" json:"total,omitempty"` SoongBuildMetrics *SoongBuildMetrics `protobuf:"bytes,22,opt,name=soong_build_metrics,json=soongBuildMetrics" json:"soong_build_metrics,omitempty"` + BuildConfig *BuildConfig `protobuf:"bytes,23,opt,name=build_config,json=buildConfig" json:"build_config,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -388,6 +389,60 @@ func (m *MetricsBase) GetSoongBuildMetrics() *SoongBuildMetrics { return nil } +func (m *MetricsBase) GetBuildConfig() *BuildConfig { + if m != nil { + return m.BuildConfig + } + return nil +} + +type BuildConfig struct { + UseGoma *bool `protobuf:"varint,1,opt,name=use_goma,json=useGoma" json:"use_goma,omitempty"` + UseRbe *bool `protobuf:"varint,2,opt,name=use_rbe,json=useRbe" json:"use_rbe,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BuildConfig) Reset() { *m = BuildConfig{} } +func (m *BuildConfig) String() string { return proto.CompactTextString(m) } +func (*BuildConfig) ProtoMessage() {} +func (*BuildConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_6039342a2ba47b72, []int{1} +} + +func (m *BuildConfig) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BuildConfig.Unmarshal(m, b) +} +func (m *BuildConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BuildConfig.Marshal(b, m, deterministic) +} +func (m *BuildConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_BuildConfig.Merge(m, src) +} +func (m *BuildConfig) XXX_Size() int { + return xxx_messageInfo_BuildConfig.Size(m) +} +func (m *BuildConfig) XXX_DiscardUnknown() { + xxx_messageInfo_BuildConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_BuildConfig proto.InternalMessageInfo + +func (m *BuildConfig) GetUseGoma() bool { + if m != nil && m.UseGoma != nil { + return *m.UseGoma + } + return false +} + +func (m *BuildConfig) GetUseRbe() bool { + if m != nil && m.UseRbe != nil { + return *m.UseRbe + } + return false +} + type PerfInfo struct { // The description for the phase/action/part while the tool running. Desc *string `protobuf:"bytes,1,opt,name=desc" json:"desc,omitempty"` @@ -410,7 +465,7 @@ func (m *PerfInfo) Reset() { *m = PerfInfo{} } func (m *PerfInfo) String() string { return proto.CompactTextString(m) } func (*PerfInfo) ProtoMessage() {} func (*PerfInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{1} + return fileDescriptor_6039342a2ba47b72, []int{2} } func (m *PerfInfo) XXX_Unmarshal(b []byte) error { @@ -482,7 +537,7 @@ func (m *ModuleTypeInfo) Reset() { *m = ModuleTypeInfo{} } func (m *ModuleTypeInfo) String() string { return proto.CompactTextString(m) } func (*ModuleTypeInfo) ProtoMessage() {} func (*ModuleTypeInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{2} + return fileDescriptor_6039342a2ba47b72, []int{3} } func (m *ModuleTypeInfo) XXX_Unmarshal(b []byte) error { @@ -540,7 +595,7 @@ func (m *CriticalUserJourneyMetrics) Reset() { *m = CriticalUserJourneyM func (m *CriticalUserJourneyMetrics) String() string { return proto.CompactTextString(m) } func (*CriticalUserJourneyMetrics) ProtoMessage() {} func (*CriticalUserJourneyMetrics) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{3} + return fileDescriptor_6039342a2ba47b72, []int{4} } func (m *CriticalUserJourneyMetrics) XXX_Unmarshal(b []byte) error { @@ -587,7 +642,7 @@ func (m *CriticalUserJourneysMetrics) Reset() { *m = CriticalUserJourney func (m *CriticalUserJourneysMetrics) String() string { return proto.CompactTextString(m) } func (*CriticalUserJourneysMetrics) ProtoMessage() {} func (*CriticalUserJourneysMetrics) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{4} + return fileDescriptor_6039342a2ba47b72, []int{5} } func (m *CriticalUserJourneysMetrics) XXX_Unmarshal(b []byte) error { @@ -635,7 +690,7 @@ func (m *SoongBuildMetrics) Reset() { *m = SoongBuildMetrics{} } func (m *SoongBuildMetrics) String() string { return proto.CompactTextString(m) } func (*SoongBuildMetrics) ProtoMessage() {} func (*SoongBuildMetrics) Descriptor() ([]byte, []int) { - return fileDescriptor_6039342a2ba47b72, []int{5} + return fileDescriptor_6039342a2ba47b72, []int{6} } func (m *SoongBuildMetrics) XXX_Unmarshal(b []byte) error { @@ -696,6 +751,7 @@ func init() { proto.RegisterEnum("soong_build_metrics.MetricsBase_Arch", MetricsBase_Arch_name, MetricsBase_Arch_value) proto.RegisterEnum("soong_build_metrics.ModuleTypeInfo_BuildSystem", ModuleTypeInfo_BuildSystem_name, ModuleTypeInfo_BuildSystem_value) proto.RegisterType((*MetricsBase)(nil), "soong_build_metrics.MetricsBase") + proto.RegisterType((*BuildConfig)(nil), "soong_build_metrics.BuildConfig") proto.RegisterType((*PerfInfo)(nil), "soong_build_metrics.PerfInfo") proto.RegisterType((*ModuleTypeInfo)(nil), "soong_build_metrics.ModuleTypeInfo") proto.RegisterType((*CriticalUserJourneyMetrics)(nil), "soong_build_metrics.CriticalUserJourneyMetrics") @@ -703,69 +759,74 @@ func init() { proto.RegisterType((*SoongBuildMetrics)(nil), "soong_build_metrics.SoongBuildMetrics") } -func init() { proto.RegisterFile("metrics.proto", fileDescriptor_6039342a2ba47b72) } +func init() { + proto.RegisterFile("metrics.proto", fileDescriptor_6039342a2ba47b72) +} var fileDescriptor_6039342a2ba47b72 = []byte{ - // 962 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xef, 0x4e, 0xdc, 0x46, - 0x10, 0x8f, 0xe1, 0xe0, 0xce, 0x63, 0xee, 0x30, 0x0b, 0x69, 0x9c, 0x44, 0xa8, 0x27, 0xab, 0x89, - 0x50, 0xd5, 0x90, 0x88, 0x46, 0x28, 0x42, 0x51, 0x25, 0x38, 0x50, 0x9a, 0x22, 0xb8, 0xc8, 0xfc, - 0x69, 0xd4, 0x7e, 0x58, 0x2d, 0xf6, 0x12, 0x9c, 0xda, 0x5e, 0x6b, 0x77, 0x1d, 0x41, 0xde, 0xa1, - 0x0f, 0xd4, 0xcf, 0x7d, 0x96, 0xbe, 0x47, 0xb5, 0xb3, 0xf6, 0x61, 0xda, 0x8b, 0x40, 0xf9, 0x66, - 0xcf, 0xef, 0xcf, 0xce, 0xac, 0x67, 0xe6, 0x0e, 0xfa, 0x39, 0xd7, 0x32, 0x8d, 0xd5, 0x7a, 0x29, - 0x85, 0x16, 0x64, 0x59, 0x09, 0x51, 0x7c, 0xa0, 0x67, 0x55, 0x9a, 0x25, 0xb4, 0x86, 0xc2, 0xbf, - 0x00, 0xbc, 0x03, 0xfb, 0xbc, 0xc3, 0x14, 0x27, 0x2f, 0x60, 0xc5, 0x12, 0x12, 0xa6, 0x39, 0xd5, - 0x69, 0xce, 0x95, 0x66, 0x79, 0x19, 0x38, 0x43, 0x67, 0x6d, 0x36, 0x22, 0x88, 0xed, 0x32, 0xcd, - 0x8f, 0x1b, 0x84, 0x3c, 0x84, 0x9e, 0x55, 0xa4, 0x49, 0x30, 0x33, 0x74, 0xd6, 0xdc, 0xa8, 0x8b, - 0xef, 0x6f, 0x13, 0xb2, 0x05, 0x0f, 0xcb, 0x8c, 0xe9, 0x73, 0x21, 0x73, 0xfa, 0x89, 0x4b, 0x95, - 0x8a, 0x82, 0xc6, 0x22, 0xe1, 0x05, 0xcb, 0x79, 0x30, 0x8b, 0xdc, 0x07, 0x0d, 0xe1, 0xd4, 0xe2, - 0xa3, 0x1a, 0x26, 0x4f, 0x60, 0xa0, 0x99, 0xfc, 0xc0, 0x35, 0x2d, 0xa5, 0x48, 0xaa, 0x58, 0x07, - 0x1d, 0x14, 0xf4, 0x6d, 0xf4, 0x9d, 0x0d, 0x92, 0x04, 0x56, 0x6a, 0x9a, 0x4d, 0xe2, 0x13, 0x93, - 0x29, 0x2b, 0x74, 0x30, 0x37, 0x74, 0xd6, 0x06, 0x1b, 0xcf, 0xd6, 0xa7, 0xd4, 0xbc, 0xde, 0xaa, - 0x77, 0x7d, 0xc7, 0x20, 0xa7, 0x56, 0xb4, 0x35, 0xbb, 0x77, 0xf8, 0x26, 0x22, 0xd6, 0xaf, 0x0d, - 0x90, 0x31, 0x78, 0xf5, 0x29, 0x4c, 0xc6, 0x17, 0xc1, 0x3c, 0x9a, 0x3f, 0xb9, 0xd5, 0x7c, 0x5b, - 0xc6, 0x17, 0x5b, 0xdd, 0x93, 0xc3, 0xfd, 0xc3, 0xf1, 0xaf, 0x87, 0x11, 0x58, 0x0b, 0x13, 0x24, - 0xeb, 0xb0, 0xdc, 0x32, 0x9c, 0x64, 0xdd, 0xc5, 0x12, 0x97, 0xae, 0x89, 0x4d, 0x02, 0x3f, 0x40, - 0x9d, 0x16, 0x8d, 0xcb, 0x6a, 0x42, 0xef, 0x21, 0xdd, 0xb7, 0xc8, 0xa8, 0xac, 0x1a, 0xf6, 0x3e, - 0xb8, 0x17, 0x42, 0xd5, 0xc9, 0xba, 0x5f, 0x95, 0x6c, 0xcf, 0x18, 0x60, 0xaa, 0x11, 0xf4, 0xd1, - 0x6c, 0xa3, 0x48, 0xac, 0x21, 0x7c, 0x95, 0xa1, 0x67, 0x4c, 0x36, 0x8a, 0x04, 0x3d, 0x1f, 0x40, - 0x17, 0x3d, 0x85, 0x0a, 0x3c, 0xac, 0x61, 0xde, 0xbc, 0x8e, 0x15, 0x09, 0xeb, 0xc3, 0x84, 0xa2, - 0xfc, 0x52, 0x4b, 0x16, 0x2c, 0x20, 0xec, 0x59, 0x78, 0xcf, 0x84, 0x26, 0x9c, 0x58, 0x0a, 0xa5, - 0x8c, 0x45, 0xff, 0x9a, 0x33, 0x32, 0xb1, 0xb1, 0x22, 0x4f, 0x61, 0xb1, 0xc5, 0xc1, 0xb4, 0x07, - 0xb6, 0x7d, 0x26, 0x2c, 0x4c, 0xe4, 0x19, 0x2c, 0xb7, 0x78, 0x93, 0x12, 0x17, 0xed, 0xc5, 0x4e, - 0xb8, 0xad, 0xbc, 0x45, 0xa5, 0x69, 0x92, 0xca, 0xc0, 0xb7, 0x79, 0x8b, 0x4a, 0xef, 0xa6, 0x92, - 0xfc, 0x04, 0x9e, 0xe2, 0xba, 0x2a, 0xa9, 0x16, 0x22, 0x53, 0xc1, 0xd2, 0x70, 0x76, 0xcd, 0xdb, - 0x58, 0x9d, 0x7a, 0x45, 0xef, 0xb8, 0x3c, 0x7f, 0x5b, 0x9c, 0x8b, 0x08, 0x50, 0x71, 0x6c, 0x04, - 0x64, 0x0b, 0xdc, 0x3f, 0x98, 0x4e, 0xa9, 0xac, 0x0a, 0x15, 0x90, 0xbb, 0xa8, 0x7b, 0x86, 0x1f, - 0x55, 0x85, 0x22, 0xaf, 0x01, 0x2c, 0x13, 0xc5, 0xcb, 0x77, 0x11, 0xbb, 0x88, 0x36, 0xea, 0x22, - 0x2d, 0x3e, 0x32, 0xab, 0x5e, 0xb9, 0x93, 0x1a, 0x05, 0xa8, 0xfe, 0x11, 0xe6, 0xb4, 0xd0, 0x2c, - 0x0b, 0xee, 0x0f, 0x9d, 0xdb, 0x85, 0x96, 0x4b, 0x4e, 0x61, 0xda, 0x2a, 0x0a, 0xbe, 0x41, 0x8b, - 0xa7, 0x53, 0x2d, 0x8e, 0x4c, 0x0c, 0x47, 0xb2, 0xee, 0xb0, 0x68, 0x49, 0xfd, 0x37, 0x14, 0xbe, - 0x80, 0x85, 0x1b, 0x53, 0xdb, 0x83, 0xce, 0xc9, 0xd1, 0x5e, 0xe4, 0xdf, 0x23, 0x7d, 0x70, 0xcd, - 0xd3, 0xee, 0xde, 0xce, 0xc9, 0x1b, 0xdf, 0x21, 0x5d, 0x30, 0x93, 0xee, 0xcf, 0x84, 0xaf, 0xa1, - 0x83, 0xdf, 0xd5, 0x83, 0xa6, 0x4f, 0xfd, 0x7b, 0x06, 0xdd, 0x8e, 0x0e, 0x7c, 0x87, 0xb8, 0x30, - 0xb7, 0x1d, 0x1d, 0x6c, 0xbe, 0xf4, 0x67, 0x4c, 0xec, 0xfd, 0xab, 0x4d, 0x7f, 0x96, 0x00, 0xcc, - 0xbf, 0x7f, 0xb5, 0x49, 0x37, 0x5f, 0xfa, 0x9d, 0xf0, 0x4f, 0x07, 0x7a, 0x4d, 0x6d, 0x84, 0x40, - 0x27, 0xe1, 0x2a, 0xc6, 0x45, 0xe9, 0x46, 0xf8, 0x6c, 0x62, 0xb8, 0xea, 0xec, 0x5a, 0xc4, 0x67, - 0xb2, 0x0a, 0xa0, 0x34, 0x93, 0x1a, 0x77, 0x2b, 0x2e, 0xc1, 0x4e, 0xe4, 0x62, 0xc4, 0xac, 0x54, - 0xf2, 0x18, 0x5c, 0xc9, 0x59, 0x66, 0xd1, 0x0e, 0xa2, 0x3d, 0x13, 0x40, 0x70, 0x15, 0x20, 0xe7, - 0xb9, 0x90, 0x57, 0xb4, 0x52, 0x1c, 0x57, 0x5c, 0x27, 0x72, 0x6d, 0xe4, 0x44, 0xf1, 0xf0, 0x1f, - 0x07, 0x06, 0x07, 0x22, 0xa9, 0x32, 0x7e, 0x7c, 0x55, 0x72, 0xcc, 0xea, 0x77, 0x58, 0xb0, 0x17, - 0xa9, 0xae, 0x94, 0xe6, 0x39, 0x66, 0x37, 0xd8, 0x78, 0x3e, 0x7d, 0x76, 0x6f, 0x48, 0xed, 0x66, - 0x3c, 0x42, 0x59, 0x6b, 0x8a, 0xcf, 0xae, 0xa3, 0xe4, 0x5b, 0xf0, 0x72, 0xd4, 0x50, 0x7d, 0x55, - 0x36, 0x55, 0x42, 0x3e, 0xb1, 0x21, 0xdf, 0xc1, 0xa0, 0xa8, 0x72, 0x2a, 0xce, 0xa9, 0x0d, 0x2a, - 0xac, 0xb7, 0x1f, 0x2d, 0x14, 0x55, 0x3e, 0x3e, 0xb7, 0xe7, 0xa9, 0xf0, 0x39, 0x78, 0xad, 0xb3, - 0x6e, 0x7e, 0x0b, 0x17, 0xe6, 0x8e, 0xc6, 0xe3, 0x43, 0xf3, 0xd1, 0x7a, 0xd0, 0x39, 0xd8, 0xde, - 0xdf, 0xf3, 0x67, 0xc2, 0x0c, 0x1e, 0x8d, 0x64, 0xaa, 0xd3, 0x98, 0x65, 0x27, 0x8a, 0xcb, 0x5f, - 0x44, 0x25, 0x0b, 0x7e, 0x55, 0x77, 0xc1, 0xe4, 0xd2, 0x9d, 0xd6, 0xa5, 0x6f, 0x41, 0xb7, 0xe9, - 0xb2, 0x19, 0xec, 0xb2, 0xe1, 0x6d, 0xdb, 0x2b, 0x6a, 0x04, 0xe1, 0x19, 0x3c, 0x9e, 0x72, 0x9a, - 0x6a, 0x8e, 0x1b, 0x41, 0x27, 0xae, 0x3e, 0xaa, 0xc0, 0xc1, 0xc9, 0x99, 0x7e, 0xb3, 0x5f, 0xce, - 0x36, 0x42, 0x71, 0xf8, 0xb7, 0x03, 0x4b, 0xff, 0x6b, 0x71, 0x12, 0x40, 0xb7, 0xb9, 0x37, 0x07, - 0xef, 0xad, 0x79, 0x25, 0x8f, 0xa0, 0x57, 0xff, 0x06, 0xd8, 0x82, 0xfa, 0xd1, 0xe4, 0x9d, 0x7c, - 0x0f, 0x4b, 0x38, 0x66, 0x94, 0x65, 0x99, 0x88, 0x69, 0x2c, 0xaa, 0x42, 0xd7, 0x7d, 0xb6, 0x88, - 0xc0, 0xb6, 0x89, 0x8f, 0x4c, 0x98, 0xac, 0x81, 0xdf, 0xe6, 0xaa, 0xf4, 0x73, 0xd3, 0x74, 0x83, - 0x6b, 0xea, 0x51, 0xfa, 0x99, 0x9b, 0xa5, 0x9b, 0xb3, 0x4b, 0x7a, 0xc1, 0x59, 0x69, 0x69, 0xb6, - 0xfb, 0xbc, 0x9c, 0x5d, 0xfe, 0xcc, 0x59, 0x69, 0x38, 0x3b, 0xf7, 0x7f, 0xab, 0xe7, 0xba, 0xae, - 0x9b, 0xe2, 0xff, 0x8e, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x4d, 0x2a, 0x36, 0xe3, 0x87, 0x08, - 0x00, 0x00, + // 1021 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xef, 0x6e, 0xdb, 0x36, + 0x10, 0xaf, 0x12, 0x27, 0xb6, 0x4e, 0xb1, 0xab, 0x30, 0xed, 0xa2, 0xb6, 0x08, 0x66, 0x18, 0x6b, + 0x11, 0x0c, 0x6b, 0x5a, 0x64, 0x45, 0x50, 0x04, 0xc5, 0x00, 0xc7, 0x09, 0xb2, 0x2e, 0x48, 0x5c, + 0x30, 0x7f, 0x56, 0x6c, 0x1f, 0x04, 0x5a, 0xa2, 0x13, 0x75, 0x96, 0x28, 0x90, 0x54, 0x91, 0xf4, + 0x1d, 0xf6, 0x54, 0x7b, 0x96, 0xbd, 0xc6, 0x30, 0xf0, 0x28, 0xd9, 0xca, 0xe6, 0xad, 0x41, 0xbf, + 0x89, 0xf7, 0xfb, 0xc3, 0x3b, 0xf2, 0x78, 0x36, 0xb4, 0x53, 0xae, 0x65, 0x12, 0xa9, 0xad, 0x5c, + 0x0a, 0x2d, 0xc8, 0x9a, 0x12, 0x22, 0xbb, 0x0c, 0x47, 0x45, 0x32, 0x89, 0xc3, 0x12, 0xea, 0xfd, + 0x05, 0xe0, 0x1d, 0xdb, 0xef, 0x3d, 0xa6, 0x38, 0x79, 0x09, 0x0f, 0x2c, 0x21, 0x66, 0x9a, 0x87, + 0x3a, 0x49, 0xb9, 0xd2, 0x2c, 0xcd, 0x03, 0xa7, 0xeb, 0x6c, 0x2e, 0x52, 0x82, 0xd8, 0x3e, 0xd3, + 0xfc, 0xac, 0x42, 0xc8, 0x23, 0x68, 0x59, 0x45, 0x12, 0x07, 0x0b, 0x5d, 0x67, 0xd3, 0xa5, 0x4d, + 0x5c, 0xbf, 0x8d, 0xc9, 0x2e, 0x3c, 0xca, 0x27, 0x4c, 0x8f, 0x85, 0x4c, 0xc3, 0x8f, 0x5c, 0xaa, + 0x44, 0x64, 0x61, 0x24, 0x62, 0x9e, 0xb1, 0x94, 0x07, 0x8b, 0xc8, 0x5d, 0xaf, 0x08, 0x17, 0x16, + 0x1f, 0x94, 0x30, 0x79, 0x0a, 0x1d, 0xcd, 0xe4, 0x25, 0xd7, 0x61, 0x2e, 0x45, 0x5c, 0x44, 0x3a, + 0x68, 0xa0, 0xa0, 0x6d, 0xa3, 0xef, 0x6c, 0x90, 0xc4, 0xf0, 0xa0, 0xa4, 0xd9, 0x24, 0x3e, 0x32, + 0x99, 0xb0, 0x4c, 0x07, 0x4b, 0x5d, 0x67, 0xb3, 0xb3, 0xfd, 0x7c, 0x6b, 0x4e, 0xcd, 0x5b, 0xb5, + 0x7a, 0xb7, 0xf6, 0x0c, 0x72, 0x61, 0x45, 0xbb, 0x8b, 0x07, 0x27, 0x87, 0x94, 0x58, 0xbf, 0x3a, + 0x40, 0x86, 0xe0, 0x95, 0xbb, 0x30, 0x19, 0x5d, 0x05, 0xcb, 0x68, 0xfe, 0xf4, 0xb3, 0xe6, 0x7d, + 0x19, 0x5d, 0xed, 0x36, 0xcf, 0x4f, 0x8e, 0x4e, 0x86, 0x3f, 0x9f, 0x50, 0xb0, 0x16, 0x26, 0x48, + 0xb6, 0x60, 0xad, 0x66, 0x38, 0xcd, 0xba, 0x89, 0x25, 0xae, 0xce, 0x88, 0x55, 0x02, 0xdf, 0x41, + 0x99, 0x56, 0x18, 0xe5, 0xc5, 0x94, 0xde, 0x42, 0xba, 0x6f, 0x91, 0x41, 0x5e, 0x54, 0xec, 0x23, + 0x70, 0xaf, 0x84, 0x2a, 0x93, 0x75, 0xbf, 0x28, 0xd9, 0x96, 0x31, 0xc0, 0x54, 0x29, 0xb4, 0xd1, + 0x6c, 0x3b, 0x8b, 0xad, 0x21, 0x7c, 0x91, 0xa1, 0x67, 0x4c, 0xb6, 0xb3, 0x18, 0x3d, 0xd7, 0xa1, + 0x89, 0x9e, 0x42, 0x05, 0x1e, 0xd6, 0xb0, 0x6c, 0x96, 0x43, 0x45, 0x7a, 0xe5, 0x66, 0x42, 0x85, + 0xfc, 0x5a, 0x4b, 0x16, 0xac, 0x20, 0xec, 0x59, 0xf8, 0xc0, 0x84, 0xa6, 0x9c, 0x48, 0x0a, 0xa5, + 0x8c, 0x45, 0x7b, 0xc6, 0x19, 0x98, 0xd8, 0x50, 0x91, 0x67, 0x70, 0xbf, 0xc6, 0xc1, 0xb4, 0x3b, + 0xb6, 0x7d, 0xa6, 0x2c, 0x4c, 0xe4, 0x39, 0xac, 0xd5, 0x78, 0xd3, 0x12, 0xef, 0xdb, 0x83, 0x9d, + 0x72, 0x6b, 0x79, 0x8b, 0x42, 0x87, 0x71, 0x22, 0x03, 0xdf, 0xe6, 0x2d, 0x0a, 0xbd, 0x9f, 0x48, + 0xf2, 0x03, 0x78, 0x8a, 0xeb, 0x22, 0x0f, 0xb5, 0x10, 0x13, 0x15, 0xac, 0x76, 0x17, 0x37, 0xbd, + 0xed, 0x8d, 0xb9, 0x47, 0xf4, 0x8e, 0xcb, 0xf1, 0xdb, 0x6c, 0x2c, 0x28, 0xa0, 0xe2, 0xcc, 0x08, + 0xc8, 0x2e, 0xb8, 0xbf, 0x31, 0x9d, 0x84, 0xb2, 0xc8, 0x54, 0x40, 0xee, 0xa2, 0x6e, 0x19, 0x3e, + 0x2d, 0x32, 0x45, 0xde, 0x00, 0x58, 0x26, 0x8a, 0xd7, 0xee, 0x22, 0x76, 0x11, 0xad, 0xd4, 0x59, + 0x92, 0x7d, 0x60, 0x56, 0xfd, 0xe0, 0x4e, 0x6a, 0x14, 0xa0, 0xfa, 0x7b, 0x58, 0xd2, 0x42, 0xb3, + 0x49, 0xf0, 0xb0, 0xeb, 0x7c, 0x5e, 0x68, 0xb9, 0xe4, 0x02, 0xe6, 0x8d, 0xa2, 0xe0, 0x2b, 0xb4, + 0x78, 0x36, 0xd7, 0xe2, 0xd4, 0xc4, 0xf0, 0x49, 0x96, 0x1d, 0x46, 0x57, 0xd5, 0x3f, 0x43, 0x64, + 0x00, 0x2b, 0x56, 0x15, 0x89, 0x6c, 0x9c, 0x5c, 0x06, 0xeb, 0x68, 0xd8, 0x9d, 0x6b, 0x88, 0xc2, + 0x01, 0xf2, 0xa8, 0x37, 0x9a, 0x2d, 0x7a, 0x2f, 0x61, 0xe5, 0xd6, 0xd3, 0x6f, 0x41, 0xe3, 0xfc, + 0xf4, 0x80, 0xfa, 0xf7, 0x48, 0x1b, 0x5c, 0xf3, 0xb5, 0x7f, 0xb0, 0x77, 0x7e, 0xe8, 0x3b, 0xa4, + 0x09, 0x66, 0x5c, 0xf8, 0x0b, 0xbd, 0x37, 0xd0, 0xc0, 0xe6, 0xf0, 0xa0, 0x6a, 0x76, 0xff, 0x9e, + 0x41, 0xfb, 0xf4, 0xd8, 0x77, 0x88, 0x0b, 0x4b, 0x7d, 0x7a, 0xbc, 0xf3, 0xca, 0x5f, 0x30, 0xb1, + 0xf7, 0xaf, 0x77, 0xfc, 0x45, 0x02, 0xb0, 0xfc, 0xfe, 0xf5, 0x4e, 0xb8, 0xf3, 0xca, 0x6f, 0xf4, + 0xfa, 0xe0, 0xd5, 0x72, 0x31, 0xd3, 0xb4, 0x50, 0x3c, 0xbc, 0x14, 0x29, 0xc3, 0x99, 0xdb, 0xa2, + 0xcd, 0x42, 0xf1, 0x43, 0x91, 0x32, 0xd3, 0x7c, 0x06, 0x92, 0x23, 0x8e, 0x73, 0xb6, 0x45, 0x97, + 0x0b, 0xc5, 0xe9, 0x88, 0xf7, 0x7e, 0x77, 0xa0, 0x55, 0x9d, 0x31, 0x21, 0xd0, 0x88, 0xb9, 0x8a, + 0x50, 0xec, 0x52, 0xfc, 0x36, 0x31, 0x1c, 0xb9, 0x76, 0x3c, 0xe3, 0x37, 0xd9, 0x00, 0x50, 0x9a, + 0x49, 0x8d, 0x33, 0x1e, 0x87, 0x71, 0x83, 0xba, 0x18, 0x31, 0xa3, 0x9d, 0x3c, 0x01, 0x57, 0x72, + 0x36, 0xb1, 0x68, 0x03, 0xd1, 0x96, 0x09, 0x20, 0xb8, 0x01, 0x90, 0xf2, 0x54, 0xc8, 0x9b, 0xb0, + 0x50, 0x1c, 0x47, 0x6d, 0x83, 0xba, 0x36, 0x72, 0xae, 0x78, 0xef, 0x4f, 0x07, 0x3a, 0xc7, 0x22, + 0x2e, 0x26, 0xfc, 0xec, 0x26, 0xe7, 0x98, 0xd5, 0xaf, 0xd5, 0xd5, 0xa8, 0x1b, 0xa5, 0x79, 0x8a, + 0xd9, 0x75, 0xb6, 0x5f, 0xcc, 0x9f, 0x21, 0xb7, 0xa4, 0xf6, 0xa6, 0x4e, 0x51, 0x56, 0x9b, 0x26, + 0xa3, 0x59, 0x94, 0x7c, 0x0d, 0x5e, 0x8a, 0x9a, 0x50, 0xdf, 0xe4, 0x55, 0x95, 0x90, 0x4e, 0x6d, + 0xc8, 0x37, 0xd0, 0xc9, 0x8a, 0x34, 0x14, 0xe3, 0xd0, 0x06, 0x15, 0xd6, 0xdb, 0xa6, 0x2b, 0x59, + 0x91, 0x0e, 0xc7, 0x76, 0x3f, 0xd5, 0x7b, 0x51, 0xde, 0x44, 0xe9, 0x7a, 0xeb, 0x3a, 0x5d, 0x58, + 0x3a, 0x1d, 0x0e, 0x4f, 0xcc, 0xbd, 0xb7, 0xa0, 0x71, 0xdc, 0x3f, 0x3a, 0xf0, 0x17, 0x7a, 0x13, + 0x78, 0x3c, 0x90, 0x89, 0x4e, 0x22, 0x36, 0x39, 0x57, 0x5c, 0xfe, 0x24, 0x0a, 0x99, 0xf1, 0x9b, + 0xaa, 0x1b, 0xab, 0x43, 0x77, 0x6a, 0x87, 0xbe, 0x0b, 0xcd, 0xaa, 0xdb, 0x17, 0xfe, 0xa7, 0x39, + 0x6b, 0x53, 0x94, 0x56, 0x82, 0xde, 0x08, 0x9e, 0xcc, 0xd9, 0x4d, 0xcd, 0x9a, 0xbf, 0x11, 0x15, + 0x1f, 0x54, 0xe0, 0xe0, 0x0b, 0x9e, 0x7f, 0xb2, 0xff, 0x9d, 0x2d, 0x45, 0x71, 0xef, 0x0f, 0x07, + 0x56, 0xff, 0xf5, 0xd4, 0x48, 0x00, 0xcd, 0xea, 0xdc, 0x1c, 0x3c, 0xb7, 0x6a, 0x49, 0x1e, 0x43, + 0xab, 0xfc, 0x2d, 0xb2, 0x05, 0xb5, 0xe9, 0x74, 0x4d, 0xbe, 0x85, 0x55, 0x7c, 0xee, 0x21, 0x9b, + 0x4c, 0x44, 0x14, 0x46, 0xa2, 0xc8, 0x74, 0xd9, 0x67, 0xf7, 0x11, 0xe8, 0x9b, 0xf8, 0xc0, 0x84, + 0xc9, 0x26, 0xf8, 0x75, 0xae, 0x4a, 0x3e, 0x55, 0x4d, 0xd7, 0x99, 0x51, 0x4f, 0x93, 0x4f, 0xdc, + 0x0c, 0xff, 0x94, 0x5d, 0x87, 0x57, 0x9c, 0xe5, 0x96, 0x66, 0xbb, 0xcf, 0x4b, 0xd9, 0xf5, 0x8f, + 0x9c, 0xe5, 0x86, 0xb3, 0xf7, 0xf0, 0x97, 0x72, 0xbe, 0x94, 0x75, 0x87, 0xf8, 0xff, 0xe7, 0xef, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x0a, 0x03, 0x26, 0x59, 0x0f, 0x09, 0x00, 0x00, } diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto index 50810ebdf..6559ba334 100644 --- a/ui/metrics/metrics_proto/metrics.proto +++ b/ui/metrics/metrics_proto/metrics.proto @@ -94,6 +94,14 @@ message MetricsBase { optional PerfInfo total = 21; optional SoongBuildMetrics soong_build_metrics = 22; + + optional BuildConfig build_config = 23; +} + +message BuildConfig { + optional bool use_goma = 1; + + optional bool use_rbe = 2; } message PerfInfo { @@ -159,4 +167,4 @@ message SoongBuildMetrics { // The approximate maximum size of the heap in soong_build in bytes. optional uint64 max_heap_size = 5; -}
\ No newline at end of file +} diff --git a/ui/terminal/Android.bp b/ui/terminal/Android.bp index b533b0d30..aa6e35d2b 100644 --- a/ui/terminal/Android.bp +++ b/ui/terminal/Android.bp @@ -17,7 +17,7 @@ bootstrap_go_package { pkgPath: "android/soong/ui/terminal", deps: ["soong-ui-status"], srcs: [ - "dumb_status.go", + "simple_status.go", "format.go", "smart_status.go", "status.go", diff --git a/ui/terminal/dumb_status.go b/ui/terminal/simple_status.go index 201770fac..4e8c56804 100644 --- a/ui/terminal/dumb_status.go +++ b/ui/terminal/simple_status.go @@ -21,31 +21,31 @@ import ( "android/soong/ui/status" ) -type dumbStatusOutput struct { +type simpleStatusOutput struct { writer io.Writer formatter formatter } -// NewDumbStatusOutput returns a StatusOutput that represents the +// NewSimpleStatusOutput returns a StatusOutput that represents the // current build status similarly to Ninja's built-in terminal // output. -func NewDumbStatusOutput(w io.Writer, formatter formatter) status.StatusOutput { - return &dumbStatusOutput{ +func NewSimpleStatusOutput(w io.Writer, formatter formatter) status.StatusOutput { + return &simpleStatusOutput{ writer: w, formatter: formatter, } } -func (s *dumbStatusOutput) Message(level status.MsgLevel, message string) { +func (s *simpleStatusOutput) Message(level status.MsgLevel, message string) { if level >= status.StatusLvl { fmt.Fprintln(s.writer, s.formatter.message(level, message)) } } -func (s *dumbStatusOutput) StartAction(action *status.Action, counts status.Counts) { +func (s *simpleStatusOutput) StartAction(action *status.Action, counts status.Counts) { } -func (s *dumbStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) { +func (s *simpleStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) { str := result.Description if str == "" { str = result.Command @@ -63,9 +63,9 @@ func (s *dumbStatusOutput) FinishAction(result status.ActionResult, counts statu } } -func (s *dumbStatusOutput) Flush() {} +func (s *simpleStatusOutput) Flush() {} -func (s *dumbStatusOutput) Write(p []byte) (int, error) { +func (s *simpleStatusOutput) Write(p []byte) (int, error) { fmt.Fprint(s.writer, string(p)) return len(p), nil } diff --git a/ui/terminal/status.go b/ui/terminal/status.go index 60dfc7025..d8e739211 100644 --- a/ui/terminal/status.go +++ b/ui/terminal/status.go @@ -26,12 +26,12 @@ import ( // // statusFormat takes nearly all the same options as NINJA_STATUS. // %c is currently unsupported. -func NewStatusOutput(w io.Writer, statusFormat string, forceDumbOutput, quietBuild bool) status.StatusOutput { +func NewStatusOutput(w io.Writer, statusFormat string, forceSimpleOutput, quietBuild bool) status.StatusOutput { formatter := newFormatter(statusFormat, quietBuild) - if !forceDumbOutput && isSmartTerminal(w) { + if !forceSimpleOutput && isSmartTerminal(w) { return NewSmartStatusOutput(w, formatter) } else { - return NewDumbStatusOutput(w, formatter) + return NewSimpleStatusOutput(w, formatter) } } diff --git a/ui/terminal/status_test.go b/ui/terminal/status_test.go index 9f6082988..aa69dff53 100644 --- a/ui/terminal/status_test.go +++ b/ui/terminal/status_test.go @@ -26,64 +26,64 @@ import ( func TestStatusOutput(t *testing.T) { tests := []struct { - name string - calls func(stat status.StatusOutput) - smart string - dumb string + name string + calls func(stat status.StatusOutput) + smart string + simple string }{ { - name: "two actions", - calls: twoActions, - smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n", - dumb: "[ 50% 1/2] action1\n[100% 2/2] action2\n", + name: "two actions", + calls: twoActions, + smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n", + simple: "[ 50% 1/2] action1\n[100% 2/2] action2\n", }, { - name: "two parallel actions", - calls: twoParallelActions, - smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n", - dumb: "[ 50% 1/2] action1\n[100% 2/2] action2\n", + name: "two parallel actions", + calls: twoParallelActions, + smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n", + simple: "[ 50% 1/2] action1\n[100% 2/2] action2\n", }, { - name: "action with output", - calls: actionsWithOutput, - smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n", - dumb: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n", + name: "action with output", + calls: actionsWithOutput, + smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n", + simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n", }, { - name: "action with output without newline", - calls: actionsWithOutputWithoutNewline, - smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n", - dumb: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n", + name: "action with output without newline", + calls: actionsWithOutputWithoutNewline, + smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n", + simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n", }, { - name: "action with error", - calls: actionsWithError, - smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n", - dumb: "[ 33% 1/3] action1\n[ 66% 2/3] action2\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n[100% 3/3] action3\n", + name: "action with error", + calls: actionsWithError, + smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n", + simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n[100% 3/3] action3\n", }, { - name: "action with empty description", - calls: actionWithEmptyDescription, - smart: "\r\x1b[1m[ 0% 0/1] command1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] command1\x1b[0m\x1b[K\n", - dumb: "[100% 1/1] command1\n", + name: "action with empty description", + calls: actionWithEmptyDescription, + smart: "\r\x1b[1m[ 0% 0/1] command1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] command1\x1b[0m\x1b[K\n", + simple: "[100% 1/1] command1\n", }, { - name: "messages", - calls: actionsWithMessages, - smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\nFAILED: error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n", - dumb: "[ 50% 1/2] action1\nstatus\nprint\nFAILED: error\n[100% 2/2] action2\n", + name: "messages", + calls: actionsWithMessages, + smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\nFAILED: error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n", + simple: "[ 50% 1/2] action1\nstatus\nprint\nFAILED: error\n[100% 2/2] action2\n", }, { - name: "action with long description", - calls: actionWithLongDescription, - smart: "\r\x1b[1m[ 0% 0/2] action with very long descrip\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action with very long descrip\x1b[0m\x1b[K\n", - dumb: "[ 50% 1/2] action with very long description to test eliding\n", + name: "action with long description", + calls: actionWithLongDescription, + smart: "\r\x1b[1m[ 0% 0/2] action with very long descrip\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action with very long descrip\x1b[0m\x1b[K\n", + simple: "[ 50% 1/2] action with very long description to test eliding\n", }, { - name: "action with output with ansi codes", - calls: actionWithOuptutWithAnsiCodes, - smart: "\r\x1b[1m[ 0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n", - dumb: "[100% 1/1] action1\ncolor\n", + name: "action with output with ansi codes", + calls: actionWithOuptutWithAnsiCodes, + smart: "\r\x1b[1m[ 0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n", + simple: "[100% 1/1] action1\ncolor\n", }, } @@ -103,24 +103,24 @@ func TestStatusOutput(t *testing.T) { } }) - t.Run("dumb", func(t *testing.T) { - dumb := &bytes.Buffer{} - stat := NewStatusOutput(dumb, "", false, false) + t.Run("simple", func(t *testing.T) { + simple := &bytes.Buffer{} + stat := NewStatusOutput(simple, "", false, false) tt.calls(stat) stat.Flush() - if g, w := dumb.String(), tt.dumb; g != w { + if g, w := simple.String(), tt.simple; g != w { t.Errorf("want:\n%q\ngot:\n%q", w, g) } }) - t.Run("force dumb", func(t *testing.T) { + t.Run("force simple", func(t *testing.T) { smart := &fakeSmartTerminal{termWidth: 40} stat := NewStatusOutput(smart, "", true, false) tt.calls(stat) stat.Flush() - if g, w := smart.String(), tt.dumb; g != w { + if g, w := smart.String(), tt.simple; g != w { t.Errorf("want:\n%q\ngot:\n%q", w, g) } }) diff --git a/zip/cmd/main.go b/zip/cmd/main.go index fba2e4b1e..d603586e6 100644 --- a/zip/cmd/main.go +++ b/zip/cmd/main.go @@ -62,6 +62,15 @@ func (listFiles) Set(s string) error { return nil } +type rspFiles struct{} + +func (rspFiles) String() string { return `""` } + +func (rspFiles) Set(s string) error { + fileArgsBuilder.RspFile(s) + return nil +} + type dir struct{} func (dir) String() string { return `""` } @@ -143,7 +152,8 @@ func main() { traceFile := flags.String("trace", "", "write trace to file") flags.Var(&rootPrefix{}, "P", "path prefix within the zip at which to place files") - flags.Var(&listFiles{}, "l", "file containing list of .class files") + flags.Var(&listFiles{}, "l", "file containing list of files to zip") + flags.Var(&rspFiles{}, "r", "file containing list of files to zip with Ninja rsp file escaping") flags.Var(&dir{}, "D", "directory to include in zip") flags.Var(&file{}, "f", "file to include in zip") flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression") diff --git a/zip/zip.go b/zip/zip.go index 3c710a782..e27432cbb 100644 --- a/zip/zip.go +++ b/zip/zip.go @@ -150,6 +150,30 @@ func (b *FileArgsBuilder) List(name string) *FileArgsBuilder { return b } +func (b *FileArgsBuilder) RspFile(name string) *FileArgsBuilder { + if b.err != nil { + return b + } + + f, err := b.fs.Open(name) + if err != nil { + b.err = err + return b + } + defer f.Close() + + list, err := ioutil.ReadAll(f) + if err != nil { + b.err = err + return b + } + + arg := b.state + arg.SourceFiles = ReadRespFile(list) + b.fileArgs = append(b.fileArgs, arg) + return b +} + func (b *FileArgsBuilder) Error() error { if b == nil { return nil diff --git a/zip/zip_test.go b/zip/zip_test.go index 9705d6c49..302a749a3 100644 --- a/zip/zip_test.go +++ b/zip/zip_test.go @@ -49,6 +49,9 @@ var mockFs = pathtools.MockFs(map[string][]byte{ "l_nl": []byte("a/a/a\na/a/b\nc\n"), "l_sp": []byte("a/a/a a/a/b c"), "l2": []byte("missing\n"), + "rsp": []byte("'a/a/a'\na/a/b\n'@'\n'foo'\\''bar'"), + "@ -> c": nil, + "foo'bar -> c": nil, "manifest.txt": fileCustomManifest, }) @@ -247,6 +250,19 @@ func TestZip(t *testing.T) { }, }, { + name: "rsp", + args: fileArgsBuilder(). + RspFile("rsp"), + compressionLevel: 9, + + files: []zip.FileHeader{ + fh("a/a/a", fileA, zip.Deflate), + fh("a/a/b", fileB, zip.Deflate), + fh("@", fileC, zip.Deflate), + fh("foo'bar", fileC, zip.Deflate), + }, + }, + { name: "prefix in zip", args: fileArgsBuilder(). PathPrefixInZip("foo"). @@ -568,6 +584,11 @@ func TestReadRespFile(t *testing.T) { in: `./cmd "\""-C`, out: []string{"./cmd", `"-C`}, }, + { + name: "ninja rsp file", + in: "'a'\nb\n'@'\n'foo'\\''bar'\n'foo\"bar'", + out: []string{"a", "b", "@", "foo'bar", `foo"bar`}, + }, } for _, testCase := range testCases { |