diff options
54 files changed, 1882 insertions, 382 deletions
diff --git a/android/Android.bp b/android/Android.bp index 977345b6b..96f0983e3 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -39,6 +39,7 @@ bootstrap_go_package { "paths.go", "phony.go", "prebuilt.go", + "prebuilt_build_tool.go", "proto.go", "register.go", "rule_builder.go", @@ -46,6 +47,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..7e8614031 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 { @@ -165,7 +185,7 @@ func (a *AndroidMkEntries) GetDistForGoals(mod blueprint.Module) []string { var ret []string 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()) 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..a7570dc54 100644 --- a/android/apex.go +++ b/android/apex.go @@ -65,9 +65,9 @@ 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) + BuildForApex(apex ApexInfo) // Returns the APEXes that this module will be built for ApexVariations() []ApexInfo @@ -96,7 +96,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" @@ -178,18 +178,15 @@ func (m *ApexModuleBase) TestFor() []string { return nil } -func (m *ApexModuleBase) BuildForApexes(apexes []ApexInfo) { +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.ApexName == apex.ApexName { + return } - m.apexVariations = append(m.apexVariations, apex) } + m.apexVariations = append(m.apexVariations, apex) } func (m *ApexModuleBase) ApexVariations() []ApexInfo { @@ -327,17 +324,15 @@ 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.ApexName] = apexesForModule[apex.ApexName] || directDep } // TODO(b/146393795): remove this when b/146393795 is fixed 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/paths.go b/android/paths.go index 20ff55e85..65f129ce8 100644 --- a/android/paths.go +++ b/android/paths.go @@ -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..d457da462 --- /dev/null +++ b/android/prebuilt_build_tool.go @@ -0,0 +1,100 @@ +// 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 ( + "path" + "path/filepath" +) + +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"` +} + +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) + + var relPath string + if filepath.IsAbs(installedPath.String()) { + relPath = filepath.Join(absSrcDir, sourcePath.String()) + } else { + var err error + relPath, err = filepath.Rel(path.Dir(installedPath.String()), sourcePath.String()) + if err != nil { + ctx.ModuleErrorf("Unable to generate symlink between %q and %q: %s", installedPath.String(), sourcePath.String(), err) + } + } + + ctx.Build(pctx, BuildParams{ + Rule: Symlink, + Output: installedPath, + Input: sourcePath, + Implicits: deps, + Args: map[string]string{ + "fromPath": relPath, + }, + }) + + t.toolPath = OptionalPathForPath(installedPath) +} + +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..28f5cd585 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 @@ -466,8 +471,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 +493,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..7b2d7dcd1 --- /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("-l ", installedPaths.Paths()) + rule.Build(pctx, ctx, "robolectric_tests_zip", "robolectric-tests.zip") + + return outputFile +} diff --git a/apex/androidmk.go b/apex/androidmk.go index b9bcc3acf..e739e2ba5 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -116,9 +116,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 @@ -353,6 +353,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 045ae828f..fa986cd65 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -669,7 +669,7 @@ func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { } func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { - ctx.TopDown("apex_deps", apexDepsMutator) + ctx.TopDown("apex_deps", apexDepsMutator).Parallel() ctx.BottomUp("apex", apexMutator).Parallel() ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel() ctx.BottomUp("apex_uses", apexUsesMutator).Parallel() @@ -682,33 +682,30 @@ 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{ + ApexName: mctx.ModuleName(), + MinSdkVersion: a.minSdkVersion(mctx), + Updatable: a.Updatable(), + } + 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) && !inAnySdk(child) { + return false + } - cur := mctx.Module().(android.DepIsInSameApex) - - 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) - } + // If the parent is apexBundle, this child is directly depended. + _, directDep := parent.(*apexBundle) + android.UpdateApexDependency(apexInfo, depName, directDep) + am.BuildForApex(apexInfo) + return true }) } @@ -1145,7 +1142,7 @@ type apexFile struct { 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 @@ -1154,6 +1151,7 @@ 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 @@ -1278,6 +1276,9 @@ 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 } func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, @@ -1666,9 +1667,16 @@ func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFil type javaDependency interface { DexJarBuildPath() android.Path JacocoReportClassesFile() android.Path + LintDepSets() java.LintDepSets + Stem() string } +var _ javaDependency = (*java.Library)(nil) +var _ javaDependency = (*java.SdkLibrary)(nil) +var _ javaDependency = (*java.DexImport)(nil) +var _ javaDependency = (*java.SdkLibraryImport)(nil) + func apexFileForJavaLibrary(ctx android.BaseModuleContext, lib javaDependency, module android.Module) apexFile { dirInApex := "javalib" fileToCopy := lib.DexJarBuildPath() @@ -1676,6 +1684,7 @@ func apexFileForJavaLibrary(ctx android.BaseModuleContext, lib javaDependency, m name := strings.TrimPrefix(module.Name(), "prebuilt_") af := newApexFile(ctx, fileToCopy, name, dirInApex, javaSharedLib, module) af.jacocoReportClassesFile = lib.JacocoReportClassesFile() + af.lintDepSets = lib.LintDepSets() af.stem = lib.Stem() + ".jar" return af } @@ -2275,6 +2284,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/builder.go b/apex/builder.go index 49e4642bf..0a1ec3eb3 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -403,16 +403,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 +473,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)) @@ -815,3 +815,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/cc/androidmk.go b/cc/androidmk.go index 3f812c2c0..e91b40ad8 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -149,21 +149,25 @@ 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 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) { @@ -357,8 +361,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) { diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go index 372a72e2c..51d8b4e97 100644 --- a/cc/binary_sdk_member.go +++ b/cc/binary_sdk_member.go @@ -140,10 +140,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)}) @@ -116,6 +116,8 @@ type Deps struct { // Used for host bionic LinkerFlagsFile string DynamicLinker string + + Tools []string } type PathDeps struct { @@ -158,6 +160,8 @@ type PathDeps struct { // Path to the dynamic linker binary DynamicLinker android.OptionalPath + + Tools map[string]android.Path } // LocalOrGlobalFlags contains flags that need to have values set globally by the build system or locally by the module @@ -425,6 +429,12 @@ type xref interface { XrefCcFiles() android.Paths } +type ToolDependencyTag 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} @@ -1401,9 +1411,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() } @@ -1694,6 +1704,7 @@ func (c *Module) deps(ctx DepsContext) Deps { deps.LateSharedLibs = android.LastUniqueStrings(deps.LateSharedLibs) deps.HeaderLibs = android.LastUniqueStrings(deps.HeaderLibs) deps.RuntimeLibs = android.LastUniqueStrings(deps.RuntimeLibs) + deps.Tools = android.LastUniqueStrings(deps.Tools) for _, lib := range deps.ReexportSharedLibHeaders { if !inList(lib, deps.SharedLibs) { @@ -2037,6 +2048,11 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { }, vndkExtDepTag, vndkdep.getVndkExtendsModuleName()) } } + + for _, tool := range deps.Tools { + actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), + ToolDependencyTag{Name: tool}, tool) + } } func BeginMutator(ctx android.BottomUpMutatorContext) { @@ -2215,10 +2231,38 @@ 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) + if toolDep, ok := depTag.(ToolDependencyTag); ok { + if toolMod, ok := dep.(android.HostToolProvider); ok { + if depPaths.Tools == nil { + depPaths.Tools = make(map[string]android.Path) + } + toolPath := toolMod.HostToolPath() + if !toolPath.Valid() { + ctx.ModuleErrorf("Failed to find path for host tool %q", toolDep.Name) + } + depPaths.Tools[toolDep.Name] = toolPath.Path() + } else { + ctx.ModuleErrorf("Found module, but not host tool for %q", toolDep.Name) + } + } + ccDep, ok := dep.(LinkableInterface) if !ok { @@ -2303,19 +2347,6 @@ 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 - } - - 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 - } - if depTag == staticUnwinderDepTag { // Use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859) if c.apexSdkVersion <= android.SdkVersion_Android10 { diff --git a/cc/cc_test.go b/cc/cc_test.go index 8a1c8ed4c..38a5c2d6d 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 { @@ -2919,6 +2966,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..ba14dd5d7 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -251,6 +251,14 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { deps.StaticLibs = append(deps.StaticLibs, "libomp") } + if compiler.hasSrcExt(".y") || compiler.hasSrcExt(".yy") { + deps.Tools = append(deps.Tools, "bison", "m4") + } + + if compiler.hasSrcExt(".l") || compiler.hasSrcExt(".ll") { + deps.Tools = append(deps.Tools, "flex", "m4") + } + return deps } @@ -581,7 +589,7 @@ func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathD srcs := append(android.Paths(nil), compiler.srcsBeforeGen...) - srcs, genDeps := genSources(ctx, srcs, buildFlags) + srcs, genDeps := genSources(ctx, srcs, buildFlags, deps.Tools) pathDeps = append(pathDeps, genDeps...) compiler.pathDeps = pathDeps @@ -24,7 +24,6 @@ import ( ) func init() { - pctx.SourcePathVariable("lexCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/flex") pctx.SourcePathVariable("m4Cmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/m4") pctx.HostBinToolVariable("aidlCmd", "aidl-cpp") @@ -32,12 +31,6 @@ func init() { } var ( - lex = pctx.AndroidStaticRule("lex", - blueprint.RuleParams{ - Command: "M4=$m4Cmd $lexCmd -o$out $in", - CommandDeps: []string{"$lexCmd", "$m4Cmd"}, - }) - sysprop = pctx.AndroidStaticRule("sysprop", blueprint.RuleParams{ Command: "$syspropCmd --header-dir=$headerOutDir --public-header-dir=$publicOutDir " + @@ -66,7 +59,8 @@ type YaccProperties struct { } func genYacc(ctx android.ModuleContext, rule *android.RuleBuilder, yaccFile android.Path, - outFile android.ModuleGenPath, props *YaccProperties) (headerFiles android.Paths) { + outFile android.ModuleGenPath, props *YaccProperties, + tools map[string]android.Path) (headerFiles android.Paths) { outDir := android.PathForModuleGen(ctx, "yacc") headerFile := android.GenPathWithExt(ctx, "yacc", yaccFile, "h") @@ -97,9 +91,17 @@ func genYacc(ctx android.ModuleContext, rule *android.RuleBuilder, yaccFile andr } } - cmd.Text("BISON_PKGDATADIR=prebuilts/build-tools/common/bison"). - FlagWithInput("M4=", ctx.Config().PrebuiltBuildTool(ctx, "m4")). - PrebuiltBuildTool(ctx, "bison"). + bison, ok := tools["bison"] + if !ok { + ctx.ModuleErrorf("Unable to find bison") + } + m4, ok := tools["m4"] + if !ok { + ctx.ModuleErrorf("Unable to find m4") + } + + cmd.FlagWithInput("M4=", m4). + Tool(bison). Flag("-d"). Flags(flags). FlagWithOutput("--defines=", headerFile). @@ -153,13 +155,23 @@ func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile andr } } -func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath) { - ctx.Build(pctx, android.BuildParams{ - Rule: lex, - Description: "lex " + lexFile.Rel(), - Output: outFile, - Input: lexFile, - }) +func genLex(ctx android.ModuleContext, rule *android.RuleBuilder, lexFile android.Path, + outFile android.ModuleGenPath, tools map[string]android.Path) { + + flex, ok := tools["flex"] + if !ok { + ctx.ModuleErrorf("Unable to find flex") + } + m4, ok := tools["m4"] + if !ok { + ctx.ModuleErrorf("Unable to find m4") + } + + rule.Command(). + FlagWithInput("M4=", m4). + Tool(flex). + FlagWithOutput("-o", outFile). + Input(lexFile) } func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Paths) { @@ -206,14 +218,22 @@ func genWinMsg(ctx android.ModuleContext, srcFile android.Path, flags builderFla return rcFile, headerFile } -func genSources(ctx android.ModuleContext, srcFiles android.Paths, - buildFlags builderFlags) (android.Paths, android.Paths) { +func genSources(ctx android.ModuleContext, srcFiles android.Paths, buildFlags builderFlags, + tools map[string]android.Path) (android.Paths, android.Paths) { var deps android.Paths var rsFiles android.Paths var aidlRule *android.RuleBuilder + var lexRule_ *android.RuleBuilder + lexRule := func() *android.RuleBuilder { + if lexRule_ == nil { + lexRule_ = android.NewRuleBuilder().Sbox(android.PathForModuleGen(ctx, "lex")) + } + return lexRule_ + } + var yaccRule_ *android.RuleBuilder yaccRule := func() *android.RuleBuilder { if yaccRule_ == nil { @@ -227,19 +247,19 @@ func genSources(ctx android.ModuleContext, srcFiles android.Paths, case ".y": cFile := android.GenPathWithExt(ctx, "yacc", srcFile, "c") srcFiles[i] = cFile - deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cFile, buildFlags.yacc)...) + deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cFile, buildFlags.yacc, tools)...) case ".yy": cppFile := android.GenPathWithExt(ctx, "yacc", srcFile, "cpp") srcFiles[i] = cppFile - deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cppFile, buildFlags.yacc)...) + deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cppFile, buildFlags.yacc, tools)...) case ".l": cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c") srcFiles[i] = cFile - genLex(ctx, srcFile, cFile) + genLex(ctx, lexRule(), srcFile, cFile, tools) case ".ll": cppFile := android.GenPathWithExt(ctx, "lex", srcFile, "cpp") srcFiles[i] = cppFile - genLex(ctx, srcFile, cppFile) + genLex(ctx, lexRule(), srcFile, cppFile, tools) case ".proto": ccFile, headerFile := genProto(ctx, srcFile, buildFlags) srcFiles[i] = ccFile @@ -271,6 +291,10 @@ func genSources(ctx android.ModuleContext, srcFiles android.Paths, aidlRule.Build(pctx, ctx, "aidl", "gen aidl") } + if lexRule_ != nil { + lexRule_.Build(pctx, ctx, "lex", "gen lex") + } + if yaccRule_ != nil { yaccRule_.Build(pctx, ctx, "yacc", "gen yacc") } @@ -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..653b43ef0 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) } @@ -243,6 +244,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() diff --git a/cc/test.go b/cc/test.go index 37afb0ca4..9b6864a4e 100644 --- a/cc/test.go +++ b/cc/test.go @@ -165,7 +165,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 } @@ -310,7 +310,7 @@ type testBinary struct { *binaryDecorator *baseCompiler Properties TestBinaryProperties - data android.Paths + data []android.DataPath testConfig android.Path } @@ -339,7 +339,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 +352,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()}) } }) diff --git a/java/Android.bp b/java/Android.bp index 1fda7f71d..fd06c46fa 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -38,6 +38,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/android_manifest.go b/java/android_manifest.go index 8280cb1b1..84dee16c5 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -130,7 +130,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 +155,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..25dd32931 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -132,9 +132,7 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { } 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) }, }, } @@ -394,9 +392,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{ diff --git a/java/config/config.go b/java/config/config.go index 0fe74c87d..d2f451302 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" diff --git a/java/java.go b/java/java.go index 367b09cbb..ef9613df0 100644 --- a/java/java.go +++ b/java/java.go @@ -1707,6 +1707,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.ApexName() != "" && ctx.Config().UnbundledBuildApps() { + j.linter.buildModuleReportZip = true + } j.linter.lint(ctx) } @@ -2789,6 +2792,10 @@ func (a *DexImport) JacocoReportClassesFile() android.Path { return nil } +func (a *DexImport) LintDepSets() LintDepSets { + return LintDepSets{} +} + func (j *DexImport) IsInstallable() bool { return true } diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go new file mode 100644 index 000000000..8af66d098 --- /dev/null +++ b/java/legacy_core_platform_api_usage.go @@ -0,0 +1,162 @@ +// 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" +) + +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", +} + +var legacyCorePlatformApiLookup = make(map[string]struct{}) + +func init() { + for _, module := range legacyCorePlatformApiModules { + legacyCorePlatformApiLookup[module] = struct{}{} + } +} + +func useLegacyCorePlatformApi(ctx android.EarlyModuleContext) bool { + _, found := legacyCorePlatformApiLookup[ctx.ModuleName()] + return found +} + +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..639106793 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, @@ -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()) } }) @@ -262,7 +317,7 @@ func (l *linter) lint(ctx android.ModuleContext) { apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx) } - rule.Command(). + cmd := rule.Command(). Text("("). Flag("JAVA_OPTS=-Xmx2048m"). FlagWithArg("ANDROID_SDK_HOME=", homeDir.String()). @@ -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 { @@ -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) diff --git a/java/robolectric.go b/java/robolectric.go index c6b07a17e..4d68fd9c8 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,74 @@ 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().UnbundledBuildUsePrebuiltSdks() && 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().UnbundledBuildUsePrebuiltSdks() && r.props.Lib != nil { + runtimeFromSourceModule := ctx.GetDirectDepWithTag(String(r.props.Lib), libTag) + 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..6e67a13cd 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -413,8 +413,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 +438,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: diff --git a/java/sdk_library.go b/java/sdk_library.go index 58e05e519..8a8d0c959 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{ @@ -987,16 +984,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() { @@ -1199,7 +1188,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 @@ -1286,64 +1275,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) @@ -1526,22 +1508,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) } @@ -2028,6 +1996,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() } diff --git a/java/sdk_test.go b/java/sdk_test.go index 1f23b140c..395da79df 100644 --- a/java/sdk_test.go +++ b/java/sdk_test.go @@ -49,8 +49,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 +58,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 +155,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{}, }, { diff --git a/java/testing.go b/java/testing.go index 94f054e67..e761743ff 100644 --- a/java/testing.go +++ b/java/testing.go @@ -136,7 +136,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) } @@ -146,7 +146,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"], }, @@ -161,7 +161,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, } @@ -169,7 +169,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, } @@ -177,7 +177,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, } @@ -185,7 +185,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, } @@ -193,7 +193,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/rust/Android.bp b/rust/Android.bp index d56de870f..e03bf4f6c 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,11 +20,14 @@ 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", diff --git a/rust/androidmk.go b/rust/androidmk.go index aea899baa..babbf9123 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -55,6 +55,7 @@ func (mod *Module) AndroidMk() android.AndroidMkData { ret := android.AndroidMkData{ OutputFile: mod.outputFile, Include: "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk", + SubName: mod.subName, Extra: []android.AndroidMkExtraFunc{ func(w io.Writer, outputFile android.Path) { if len(mod.Properties.AndroidMkRlibs) > 0 { @@ -75,9 +76,11 @@ func (mod *Module) AndroidMk() android.AndroidMkData { }, }, } - - mod.subAndroidMk(&ret, mod.compiler) - + if mod.compiler != nil { + mod.subAndroidMk(&ret, mod.compiler) + } else if mod.sourceProvider != nil { + mod.subAndroidMk(&ret, mod.sourceProvider) + } ret.SubName += mod.Properties.SubName return ret @@ -155,6 +158,25 @@ 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.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..1e9e11990 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -106,8 +106,7 @@ 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 diff --git a/rust/bindgen.go b/rust/bindgen.go new file mode 100644 index 000000000..83ad56013 --- /dev/null +++ b/rust/bindgen.go @@ -0,0 +1,182 @@ +// 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 ( + "github.com/google/blueprint" + "strings" + + "android/soong/android" + "android/soong/cc" + 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 " + + "$bindgenCmd $flags $in -o $out -- $cflags", + CommandDeps: []string{"$bindgenCmd"}, + }, + "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 + 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"` + + //TODO(b/161141999) Add support for headers from cc_library_header modules. +} + +type bindgenDecorator struct { + *baseSourceProvider + + Properties BindgenProperties +} + +func (b *bindgenDecorator) libraryExports(ctx android.ModuleContext) (android.Paths, []string) { + var libraryPaths android.Paths + var libraryFlags []string + + for _, static_lib := range b.Properties.Static_libs { + if dep, ok := ctx.GetDirectDepWithTag(static_lib, cc.StaticDepTag).(*cc.Module); ok { + libraryPaths = append(libraryPaths, dep.ExportedIncludeDirs()...) + libraryFlags = append(libraryFlags, dep.ExportedFlags()...) + } + } + for _, shared_lib := range b.Properties.Shared_libs { + if dep, ok := ctx.GetDirectDepWithTag(shared_lib, cc.SharedDepTag).(*cc.Module); ok { + libraryPaths = append(libraryPaths, dep.ExportedIncludeDirs()...) + libraryFlags = append(libraryFlags, dep.ExportedFlags()...) + } + } + + return libraryPaths, libraryFlags +} + +func (b *bindgenDecorator) generateSource(ctx android.ModuleContext) android.Path { + ccToolchain := ccConfig.FindToolchain(ctx.Os(), ctx.Arch()) + includes, exportedFlags := b.libraryExports(ctx) + + var cflags []string + cflags = append(cflags, b.Properties.Cflags...) + cflags = append(cflags, "-target "+ccToolchain.ClangTriple()) + cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainClangCflags(), "${config.", "${ccConfig.")) + cflags = append(cflags, exportedFlags...) + for _, include := range includes { + cflags = append(cflags, "-I"+include.String()) + } + for _, include := range b.Properties.Local_include_dirs { + cflags = append(cflags, "-I"+android.PathForModuleSrc(ctx, include).String()) + } + + bindgenFlags := defaultBindgenFlags + bindgenFlags = append(bindgenFlags, strings.Join(b.Properties.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") + + ctx.Build(pctx, android.BuildParams{ + Rule: bindgen, + Description: "bindgen " + wrapperFile.Path().Rel(), + Output: outputFile, + Input: wrapperFile.Path(), + Implicits: includes, + Args: map[string]string{ + "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) { + module := newModule(hod, android.MultilibBoth) + + bindgen := &bindgenDecorator{ + baseSourceProvider: NewSourceProvider(), + Properties: BindgenProperties{}, + } + module.sourceProvider = bindgen + + return module, bindgen +} + +func (b *bindgenDecorator) sourceProviderDeps(ctx DepsContext, deps Deps) Deps { + deps = b.baseSourceProvider.sourceProviderDeps(ctx, 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..18e188f22 --- /dev/null +++ b/rust/bindgen_test.go @@ -0,0 +1,56 @@ +// 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", + stem: "bindings", + 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") + 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 clang cflags in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"]) + } + if !strings.Contains(libbindgen.Args["cflags"], "-Istatic_include") { + t.Errorf("missing clang cflags in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"]) + } +} 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..04b67d9bd --- /dev/null +++ b/rust/builder_test.go @@ -0,0 +1,40 @@ +// 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", + stem: "bindings", + wrapper_src: "src/any.h", + } + rust_bindgen { + name: "libbindings2", + stem: "bindings", + wrapper_src: "src/any.h", + } + `) +} diff --git a/rust/compiler.go b/rust/compiler.go index c20179bd0..ab3d2f44a 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -46,6 +46,8 @@ 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 { @@ -253,6 +255,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 +269,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..b85319643 100644 --- a/rust/compiler_test.go +++ b/rust/compiler_test.go @@ -43,7 +43,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, ` diff --git a/rust/library.go b/rust/library.go index d718eb897..ac725d7da 100644 --- a/rust/library.go +++ b/rust/library.go @@ -368,8 +368,7 @@ 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 - srcPath, paths := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs) - deps.SrcDeps = paths + srcPath, _ := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs) flags.RustFlags = append(flags.RustFlags, deps.depFlags...) 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..3dd2521a3 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 diff --git a/rust/rust.go b/rust/rust.go index 7a98c6468..89b89e20c 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,10 @@ 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 +81,27 @@ type Module struct { coverage *coverage clippy *clippy cachedToolchain config.Toolchain + sourceProvider SourceProvider subAndroidMkOnce map[subAndroidMkProvider]bool outputFile android.OptionalPath + + subName string +} + +func (mod *Module) OutputFiles(tag string) (android.Paths, error) { + switch tag { + case "": + if mod.sourceProvider != nil { + 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) @@ -348,6 +369,7 @@ func DefaultsFactory(props ...interface{}) android.Module { &LibraryCompilerProperties{}, &ProcMacroCompilerProperties{}, &PrebuiltProperties{}, + &SourceProviderProperties{}, &TestProperties{}, &cc.CoverageProperties{}, &ClippyProperties{}, @@ -507,6 +529,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) @@ -645,6 +670,10 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { if !mod.Properties.PreventInstall { mod.compiler.install(ctx, mod.outputFile.Path()) } + } else if mod.sourceProvider != nil { + outputFile := mod.sourceProvider.generateSource(ctx) + mod.outputFile = android.OptionalPathForPath(outputFile) + mod.subName = ctx.ModuleSubDir() } } @@ -653,6 +682,8 @@ func (mod *Module) deps(ctx DepsContext) Deps { if mod.compiler != nil { deps = mod.compiler.compilerDeps(ctx, deps) + } else if mod.sourceProvider != nil { + deps = mod.sourceProvider.sourceProviderDeps(ctx, deps) } if mod.coverage != nil { @@ -712,6 +743,8 @@ 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) @@ -745,6 +778,24 @@ 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 @@ -762,6 +813,14 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } + 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) + } + } + if ccDep, ok := dep.(cc.LinkableInterface); ok { //Handle C dependencies if _, ok := ccDep.(*Module); !ok { @@ -837,16 +896,26 @@ 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) return depPaths } @@ -963,3 +1032,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..b3bbddbc6 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -182,7 +182,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 +190,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 +224,93 @@ 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", + ], + } + rust_proc_macro { + name: "libprocmacro", + srcs: [ + "foo.rs", + ":my_generator", + ":libbindings", + ], + crate_name: "procmacro", + } + rust_library { + name: "libfoo", + srcs: [ + "foo.rs", + ":my_generator", + ":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", + 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()) + } +} + +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", + 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..e034d2c28 --- /dev/null +++ b/rust/source_provider.go @@ -0,0 +1,70 @@ +// 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 { + // sets name of the output + Stem *string `android:"arch_variant"` +} + +type baseSourceProvider struct { + Properties SourceProviderProperties + + outputFile android.Path + subAndroidMkOnce map[subAndroidMkProvider]bool +} + +var _ SourceProvider = (*baseSourceProvider)(nil) + +type SourceProvider interface { + generateSource(ctx android.ModuleContext) android.Path + Srcs() android.Paths + sourceProviderProps() []interface{} + sourceProviderDeps(ctx DepsContext, deps Deps) Deps +} + +func (sp *baseSourceProvider) Srcs() android.Paths { + return android.Paths{sp.outputFile} +} + +func (sp *baseSourceProvider) generateSource(ctx android.ModuleContext) 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 (sp *baseSourceProvider) getStem(ctx android.ModuleContext) string { + stem := ctx.ModuleName() + if String(sp.Properties.Stem) != "" { + stem = String(sp.Properties.Stem) + } + return stem +} + +func (sp *baseSourceProvider) sourceProviderDeps(ctx DepsContext, deps Deps) Deps { + return deps +} diff --git a/rust/testing.go b/rust/testing.go index 430b40bfd..f2d4c5eba 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -81,6 +81,7 @@ func CreateTestContext() *android.TestContext { 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/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go index 935d348ae..497f14bde 100644 --- a/sdk/cc_sdk_test.go +++ b/sdk/cc_sdk_test.go @@ -73,12 +73,16 @@ func TestSdkCompileMultilibOverride(t *testing.T) { result := testSdkWithCc(t, ` sdk { name: "mysdk", + device_supported: false, + host_supported: true, native_shared_libs: ["sdkmember"], compile_multilib: "64", } cc_library_shared { name: "sdkmember", + device_supported: false, + host_supported: true, srcs: ["Test.cpp"], stl: "none", compile_multilib: "64", @@ -86,8 +90,52 @@ 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", + device_supported: false, + host_supported: true, + installable: false, + stl: "none", + compile_multilib: "64", + arch: { + x86_64: { + srcs: ["x86_64/lib/sdkmember.so"], + }, + }, +} + +cc_prebuilt_library_shared { + name: "sdkmember", + prefer: false, + device_supported: false, + host_supported: true, + stl: "none", + compile_multilib: "64", + arch: { + x86_64: { + srcs: ["x86_64/lib/sdkmember.so"], + }, + }, +} + +sdk_snapshot { + name: "mysdk@current", + device_supported: false, + host_supported: true, + native_shared_libs: ["mysdk_sdkmember@current"], + target: { + linux_glibc: { + compile_multilib: "64", + }, + }, +} +`), checkAllCopyRules(` -.intermediates/sdkmember/android_arm64_armv8-a_shared/sdkmember.so -> arm64/lib/sdkmember.so +.intermediates/sdkmember/linux_glibc_x86_64_shared/sdkmember.so -> x86_64/lib/sdkmember.so `)) } @@ -271,6 +319,7 @@ cc_prebuilt_object { name: "mysdk_crtobj@current", sdk_member_name: "crtobj", stl: "none", + compile_multilib: "both", arch: { arm64: { srcs: ["arm64/lib/crtobj.o"], @@ -285,6 +334,7 @@ cc_prebuilt_object { name: "crtobj", prefer: false, stl: "none", + compile_multilib: "both", arch: { arm64: { srcs: ["arm64/lib/crtobj.o"], @@ -378,6 +428,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 +445,7 @@ cc_prebuilt_library_shared { name: "mynativelib", prefer: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -621,9 +673,9 @@ cc_prebuilt_binary { host_supported: true, installable: false, stl: "none", + compile_multilib: "both", static_executable: true, nocrt: true, - compile_multilib: "both", arch: { x86_64: { srcs: ["x86_64/bin/linker"], @@ -640,9 +692,9 @@ 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: { srcs: ["x86_64/bin/linker"], @@ -702,6 +754,7 @@ cc_prebuilt_library_shared { ], installable: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -723,6 +776,7 @@ cc_prebuilt_library_shared { "apex2", ], stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -824,6 +878,7 @@ cc_prebuilt_library_shared { sdk_member_name: "mynativelib", installable: false, stl: "none", + compile_multilib: "both", shared_libs: [ "mysdk_myothernativelib@current", "libc", @@ -842,6 +897,7 @@ cc_prebuilt_library_shared { name: "mynativelib", prefer: false, stl: "none", + compile_multilib: "both", shared_libs: [ "myothernativelib", "libc", @@ -861,6 +917,7 @@ cc_prebuilt_library_shared { sdk_member_name: "myothernativelib", installable: false, stl: "none", + compile_multilib: "both", system_shared_libs: ["libm"], arch: { arm64: { @@ -876,6 +933,7 @@ cc_prebuilt_library_shared { name: "myothernativelib", prefer: false, stl: "none", + compile_multilib: "both", system_shared_libs: ["libm"], arch: { arm64: { @@ -892,6 +950,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 +965,7 @@ cc_prebuilt_library_shared { name: "mysystemnativelib", prefer: false, stl: "none", + compile_multilib: "both", arch: { arm64: { srcs: ["arm64/lib/mysystemnativelib.so"], @@ -974,6 +1034,7 @@ cc_prebuilt_library_shared { installable: false, sdk_version: "minimum", stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { x86_64: { @@ -994,6 +1055,7 @@ cc_prebuilt_library_shared { host_supported: true, sdk_version: "minimum", stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { x86_64: { @@ -1070,12 +1132,18 @@ cc_prebuilt_library_shared { installable: false, stl: "none", target: { + linux_glibc: { + 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: { + compile_multilib: "64", + }, windows_x86_64: { srcs: ["windows/x86_64/lib/mynativelib.dll"], }, @@ -1089,12 +1157,18 @@ cc_prebuilt_library_shared { host_supported: true, stl: "none", target: { + linux_glibc: { + 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: { + compile_multilib: "64", + }, windows_x86_64: { srcs: ["windows/x86_64/lib/mynativelib.dll"], }, @@ -1151,6 +1225,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 +1243,7 @@ cc_prebuilt_library_static { name: "mynativelib", prefer: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -1236,6 +1312,7 @@ cc_prebuilt_library_static { host_supported: true, installable: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { x86_64: { @@ -1255,6 +1332,7 @@ cc_prebuilt_library_static { device_supported: false, host_supported: true, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { x86_64: { @@ -1315,6 +1393,7 @@ cc_prebuilt_library { sdk_member_name: "mynativelib", installable: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -1340,6 +1419,7 @@ cc_prebuilt_library { name: "mynativelib", prefer: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], arch: { arm64: { @@ -1416,6 +1496,7 @@ cc_prebuilt_library_static { host_supported: true, installable: false, stl: "none", + compile_multilib: "64", export_include_dirs: ["include/include"], arch: { x86_64: { @@ -1431,6 +1512,7 @@ cc_prebuilt_library_static { device_supported: false, host_supported: true, stl: "none", + compile_multilib: "64", export_include_dirs: ["include/include"], arch: { x86_64: { @@ -1483,6 +1565,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 +1573,7 @@ cc_prebuilt_library_headers { name: "mynativeheaders", prefer: false, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], } @@ -1532,6 +1616,7 @@ cc_prebuilt_library_headers { device_supported: false, host_supported: true, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], } @@ -1541,6 +1626,7 @@ cc_prebuilt_library_headers { device_supported: false, host_supported: true, stl: "none", + compile_multilib: "both", export_include_dirs: ["include/include"], } @@ -1590,6 +1676,7 @@ 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: { android: { @@ -1606,6 +1693,7 @@ cc_prebuilt_library_headers { prefer: false, host_supported: true, stl: "none", + compile_multilib: "both", export_system_include_dirs: ["common_os/include/include"], target: { android: { @@ -1662,6 +1750,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 +1764,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 +1779,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 +1794,7 @@ cc_prebuilt_library_shared { cc_prebuilt_library_shared { name: "sslempty", prefer: false, + compile_multilib: "both", system_shared_libs: [], arch: { arm64: { @@ -1718,6 +1810,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 +1825,7 @@ cc_prebuilt_library_shared { cc_prebuilt_library_shared { name: "sslnonempty", prefer: false, + compile_multilib: "both", system_shared_libs: ["sslnil"], arch: { arm64: { @@ -1780,6 +1874,7 @@ cc_prebuilt_library_shared { sdk_member_name: "sslvariants", host_supported: true, installable: false, + compile_multilib: "both", target: { android: { system_shared_libs: [], @@ -1803,6 +1898,7 @@ cc_prebuilt_library_shared { name: "sslvariants", prefer: false, host_supported: true, + compile_multilib: "both", target: { android: { system_shared_libs: [], @@ -1859,6 +1955,7 @@ cc_prebuilt_library_shared { name: "mysdk_stubslib@current", sdk_member_name: "stubslib", installable: false, + compile_multilib: "both", stubs: { versions: ["3"], }, @@ -1875,6 +1972,7 @@ cc_prebuilt_library_shared { cc_prebuilt_library_shared { name: "stubslib", prefer: false, + compile_multilib: "both", stubs: { versions: ["3"], }, @@ -1928,6 +2026,7 @@ cc_prebuilt_library_shared { sdk_member_name: "stubslib", host_supported: true, installable: false, + compile_multilib: "both", stubs: { versions: ["3"], }, @@ -1951,6 +2050,7 @@ cc_prebuilt_library_shared { name: "stubslib", prefer: false, host_supported: true, + compile_multilib: "both", stubs: { versions: ["3"], }, @@ -2003,6 +2103,7 @@ cc_prebuilt_library_shared { host_supported: true, installable: false, unique_host_soname: true, + compile_multilib: "both", target: { android_arm64: { srcs: ["android/arm64/lib/mylib.so"], @@ -2024,6 +2125,7 @@ cc_prebuilt_library_shared { prefer: false, host_supported: true, unique_host_soname: true, + compile_multilib: "both", target: { android_arm64: { srcs: ["android/arm64/lib/mylib.so"], diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index aee04a163..a2198e97b 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", @@ -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/update.go b/sdk/update.go index cf2500826..b8d73c63f 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -794,6 +794,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 @@ -1009,7 +1020,7 @@ func (osInfo *osTypeSpecificInfo) addToPropertySet(ctx *memberContext, bpModule } // 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 +1122,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) } } @@ -1221,7 +1232,7 @@ 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. 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") |