Merge "Refactor build_release and test code"
diff --git a/README.md b/README.md
index 127c52c..18c6604 100644
--- a/README.md
+++ b/README.md
@@ -188,7 +188,7 @@
#### Namespaces
-A presense of the `soong_namespace {..}` in an Android.bp file defines a
+The presence of the `soong_namespace {..}` in an Android.bp file defines a
**namespace**. For instance, having
```
diff --git a/android/bazel.go b/android/bazel.go
index 0940205..8e2e350 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -291,7 +291,7 @@
"external/bouncycastle": Bp2BuildDefaultTrue,
"external/brotli": Bp2BuildDefaultTrue,
"external/conscrypt": Bp2BuildDefaultTrue,
- "external/error_prone": Bp2BuildDefaultTrue,
+ "external/error_prone": Bp2BuildDefaultTrueRecursively,
"external/fmtlib": Bp2BuildDefaultTrueRecursively,
"external/google-benchmark": Bp2BuildDefaultTrueRecursively,
"external/googletest": Bp2BuildDefaultTrueRecursively,
@@ -431,8 +431,19 @@
"libprotobuf-internal-protos", // b/210751803, we don't handle path property for filegroups
"libprotobuf-internal-python-srcs", // b/210751803, we don't handle path property for filegroups
"libprotobuf-java-full", // b/210751803, we don't handle path property for filegroups
+ "host-libprotobuf-java-full", // b/210751803, we don't handle path property for filegroups
"libprotobuf-java-util-full", // b/210751803, we don't handle path property for filegroups
- "conscrypt", // b/210751803, we don't handle path property for filegroups
+
+ "conscrypt", // b/210751803, we don't handle path property for filegroups
+ "conscrypt-for-host", // b/210751803, we don't handle path property for filegroups
+
+ "host-libprotobuf-java-lite", // b/217236083, java_library cannot have deps without srcs
+ "host-libprotobuf-java-micro", // b/217236083, java_library cannot have deps without srcs
+ "host-libprotobuf-java-nano", // b/217236083, java_library cannot have deps without srcs
+ "error_prone_core", // b/217236083, java_library cannot have deps without srcs
+ "bouncycastle-host", // b/217236083, java_library cannot have deps without srcs
+
+ "apex_manifest_proto_java", // b/215230097, we don't handle .proto files in java_library srcs attribute
// python protos
"libprotobuf-python", // contains .proto sources
diff --git a/android/license_metadata.go b/android/license_metadata.go
index 3bc53d6..6a5b0da 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -34,7 +34,7 @@
}, "args")
)
-func buildLicenseMetadata(ctx ModuleContext) {
+func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) {
base := ctx.Module().base()
if !base.Enabled() {
@@ -45,9 +45,18 @@
return
}
+ var outputFiles Paths
+ if outputFileProducer, ok := ctx.Module().(OutputFileProducer); ok {
+ outputFiles, _ = outputFileProducer.OutputFiles("")
+ outputFiles = PathsIfNonNil(outputFiles...)
+ }
+
+ isContainer := isContainerFromFileExtensions(base.installFiles, outputFiles)
+
var allDepMetadataFiles Paths
var allDepMetadataArgs []string
var allDepOutputFiles Paths
+ var allDepMetadataDepSets []*PathsDepSet
ctx.VisitDirectDepsBlueprint(func(bpdep blueprint.Module) {
dep, _ := bpdep.(Module)
@@ -61,6 +70,9 @@
if ctx.OtherModuleHasProvider(dep, LicenseMetadataProvider) {
info := ctx.OtherModuleProvider(dep, LicenseMetadataProvider).(*LicenseMetadataInfo)
allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath)
+ if isContainer || IsInstallDepNeeded(ctx.OtherModuleDependencyTag(dep)) {
+ allDepMetadataDepSets = append(allDepMetadataDepSets, info.LicenseMetadataDepSet)
+ }
depAnnotations := licenseAnnotationsFromTag(ctx.OtherModuleDependencyTag(dep))
@@ -105,9 +117,16 @@
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_text.Strings()), "-n "))
- args = append(args,
- JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepMetadataArgs), "-d "))
- orderOnlyDeps = append(orderOnlyDeps, allDepMetadataFiles...)
+ if isContainer {
+ transitiveDeps := newPathsDepSet(nil, allDepMetadataDepSets).ToList()
+ args = append(args,
+ JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(transitiveDeps.Strings()), "-d "))
+ orderOnlyDeps = append(orderOnlyDeps, transitiveDeps...)
+ } else {
+ args = append(args,
+ JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepMetadataArgs), "-d "))
+ orderOnlyDeps = append(orderOnlyDeps, allDepMetadataFiles...)
+ }
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepOutputFiles.Strings()), "-s "))
@@ -117,12 +136,6 @@
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.licenseInstallMap), "-m "))
// Built files
- var outputFiles Paths
- if outputFileProducer, ok := ctx.Module().(OutputFileProducer); ok {
- outputFiles, _ = outputFileProducer.OutputFiles("")
- outputFiles = PathsIfNonNil(outputFiles...)
- }
-
if len(outputFiles) > 0 {
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(outputFiles.Strings()), "-t "))
@@ -134,13 +147,10 @@
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.installFiles.Strings()), "-i "))
- isContainer := isContainerFromFileExtensions(base.installFiles, outputFiles)
if isContainer {
args = append(args, "--is_container")
}
- licenseMetadataFile := PathForModuleOut(ctx, "meta_lic")
-
ctx.Build(pctx, BuildParams{
Rule: licenseMetadataRule,
Output: licenseMetadataFile,
@@ -152,7 +162,8 @@
})
ctx.SetProvider(LicenseMetadataProvider, &LicenseMetadataInfo{
- LicenseMetadataPath: licenseMetadataFile,
+ LicenseMetadataPath: licenseMetadataFile,
+ LicenseMetadataDepSet: newPathsDepSet(Paths{licenseMetadataFile}, allDepMetadataDepSets),
})
}
@@ -179,7 +190,8 @@
// LicenseMetadataInfo stores the license metadata path for a module.
type LicenseMetadataInfo struct {
- LicenseMetadataPath Path
+ LicenseMetadataPath Path
+ LicenseMetadataDepSet *PathsDepSet
}
// licenseAnnotationsFromTag returns the LicenseAnnotations for a tag (if any) converted into
@@ -212,6 +224,9 @@
// LicenseAnnotationSharedDependency should be returned by LicenseAnnotations implementations
// of dependency tags when the usage of the dependency is dynamic, for example a shared library
// linkage for native modules or as a classpath library for java modules.
+ //
+ // Dependency tags that need to always return LicenseAnnotationSharedDependency
+ // can embed LicenseAnnotationSharedDependencyTag to implement LicenseAnnotations.
LicenseAnnotationSharedDependency LicenseAnnotation = "dynamic"
// LicenseAnnotationToolchain should be returned by LicenseAnnotations implementations of
@@ -222,6 +237,14 @@
LicenseAnnotationToolchain LicenseAnnotation = "toolchain"
)
+// LicenseAnnotationSharedDependencyTag can be embedded in a dependency tag to implement
+// LicenseAnnotations that always returns LicenseAnnotationSharedDependency.
+type LicenseAnnotationSharedDependencyTag struct{}
+
+func (LicenseAnnotationSharedDependencyTag) LicenseAnnotations() []LicenseAnnotation {
+ return []LicenseAnnotation{LicenseAnnotationSharedDependency}
+}
+
// LicenseAnnotationToolchainDependencyTag can be embedded in a dependency tag to implement
// LicenseAnnotations that always returns LicenseAnnotationToolchain.
type LicenseAnnotationToolchainDependencyTag struct{}
diff --git a/android/module.go b/android/module.go
index 666732f..00aed95 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1321,6 +1321,9 @@
// set of dependency module:location mappings used to populate the license metadata for
// apex containers.
licenseInstallMap []string
+
+ // The path to the generated license metadata file for the module.
+ licenseMetadataFile WritablePath
}
// A struct containing all relevant information about a Bazel target converted via bp2build.
@@ -2076,6 +2079,8 @@
variables: make(map[string]string),
}
+ m.licenseMetadataFile = PathForModuleOut(ctx, "meta_lic")
+
dependencyInstallFiles, dependencyPackagingSpecs := m.computeInstallDeps(ctx)
// set m.installFilesDepSet to only the transitive dependencies to be used as the dependencies
// of installed files of this module. It will be replaced by a depset including the installed
@@ -2207,7 +2212,7 @@
m.installFilesDepSet = newInstallPathsDepSet(m.installFiles, dependencyInstallFiles)
m.packagingSpecsDepSet = newPackagingSpecsDepSet(m.packagingSpecs, dependencyPackagingSpecs)
- buildLicenseMetadata(ctx)
+ buildLicenseMetadata(ctx, m.licenseMetadataFile)
m.buildParams = ctx.buildParams
m.ruleParams = ctx.ruleParams
diff --git a/android/mutator.go b/android/mutator.go
index fa6f2be8..739e4ee 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -323,13 +323,13 @@
// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations
// argument to select which variant of the dependency to use. It returns a slice of modules for
// each dependency (some entries may be nil). A variant of the dependency must exist that matches
- // the all of the non-local variations of the current module, plus the variations argument.
+ // all the non-local variations of the current module, plus the variations argument.
//
// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
// new dependencies have had the current mutator called on them. If the mutator is not
// parallel this method does not affect the ordering of the current mutator pass, but will
// be ordered correctly for all future mutator passes.
- AddVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string) []blueprint.Module
+ AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag, names ...string) []blueprint.Module
// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the
// variations argument to select which variant of the dependency to use. It returns a slice of
diff --git a/android/namespace.go b/android/namespace.go
index 4f727e1..fc7bc29 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -74,7 +74,7 @@
// A NameResolver implements blueprint.NameInterface, and implements the logic to
// find a module from namespaces based on a query string.
-// A query string can be a module name or can be be "//namespace_path:module_path"
+// A query string can be a module name or can be "//namespace_path:module_path"
type NameResolver struct {
rootNamespace *Namespace
diff --git a/android/notices.go b/android/notices.go
index d8cfaf2..194a734 100644
--- a/android/notices.go
+++ b/android/notices.go
@@ -16,6 +16,7 @@
import (
"path/filepath"
+ "strings"
"github.com/google/blueprint"
)
@@ -101,55 +102,15 @@
}
}
-// BuildNotices merges the supplied NOTICE files into a single file that lists notices
-// for every key in noticeMap (which would normally be installed files).
-func BuildNotices(ctx ModuleContext, noticeMap map[string]Paths) NoticeOutputs {
- // TODO(jungjw): We should just produce a well-formatted NOTICE.html file in a single pass.
- //
- // generate-notice-files.py, which processes the merged NOTICE file, has somewhat strict rules
- // about input NOTICE file paths.
- // 1. Their relative paths to the src root become their NOTICE index titles. We want to use
- // on-device paths as titles, and so output the merged NOTICE file the corresponding location.
- // 2. They must end with .txt extension. Otherwise, they're ignored.
-
- mergeTool := PathForSource(ctx, "build/soong/scripts/mergenotice.py")
- generateNoticeTool := PathForSource(ctx, "build/soong/scripts/generate-notice-files.py")
-
- outputDir := PathForModuleOut(ctx, "notices")
- builder := NewRuleBuilder(pctx, ctx).
- Sbox(outputDir, PathForModuleOut(ctx, "notices.sbox.textproto"))
- for _, installPath := range SortedStringKeys(noticeMap) {
- noticePath := outputDir.Join(ctx, installPath+".txt")
- // It would be nice if sbox created directories for temporaries, but until then
- // this is simple enough.
- builder.Command().
- Text("(cd").OutputDir().Text("&&").
- Text("mkdir -p").Text(filepath.Dir(installPath)).Text(")")
- builder.Temporary(noticePath)
- builder.Command().
- Tool(mergeTool).
- Flag("--output").Output(noticePath).
- Inputs(noticeMap[installPath])
- }
-
- // Transform the merged NOTICE file into a gzipped HTML file.
- txtOutput := outputDir.Join(ctx, "NOTICE.txt")
- htmlOutput := outputDir.Join(ctx, "NOTICE.html")
- htmlGzOutput := outputDir.Join(ctx, "NOTICE.html.gz")
- title := "\"Notices for " + ctx.ModuleName() + "\""
- builder.Command().Tool(generateNoticeTool).
- FlagWithOutput("--text-output ", txtOutput).
- FlagWithOutput("--html-output ", htmlOutput).
- FlagWithArg("-t ", title).
- Flag("-s").OutputDir()
- builder.Command().BuiltTool("minigzip").
- FlagWithInput("-c ", htmlOutput).
- FlagWithOutput("> ", htmlGzOutput)
- builder.Build("build_notices", "generate notice output")
-
- return NoticeOutputs{
- TxtOutput: OptionalPathForPath(txtOutput),
- HtmlOutput: OptionalPathForPath(htmlOutput),
- HtmlGzOutput: OptionalPathForPath(htmlGzOutput),
- }
+// BuildNoticeTextOutputFromLicenseMetadata writes out a notice text file based on the module's
+// generated license metadata file.
+func BuildNoticeTextOutputFromLicenseMetadata(ctx ModuleContext, outputFile WritablePath) {
+ depsFile := outputFile.ReplaceExtension(ctx, strings.TrimPrefix(outputFile.Ext()+".d", "."))
+ rule := NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("textnotice").
+ FlagWithOutput("-o ", outputFile).
+ FlagWithDepFile("-d ", depsFile).
+ Input(ctx.Module().base().licenseMetadataFile)
+ rule.Build("container_notice", "container notice file")
}
diff --git a/android/paths.go b/android/paths.go
index 70e427b..4c69de7 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -2149,3 +2149,23 @@
}
return false
}
+
+// PathsDepSet is a thin type-safe wrapper around the generic depSet. It always uses
+// topological order.
+type PathsDepSet struct {
+ depSet
+}
+
+// newPathsDepSet returns an immutable PathsDepSet with the given direct and
+// transitive contents.
+func newPathsDepSet(direct Paths, transitive []*PathsDepSet) *PathsDepSet {
+ return &PathsDepSet{*newDepSet(TOPOLOGICAL, direct, transitive)}
+}
+
+// ToList returns the PathsDepSet flattened to a list in topological order.
+func (d *PathsDepSet) ToList() Paths {
+ if d == nil {
+ return nil
+ }
+ return d.depSet.ToList().(Paths)
+}
diff --git a/android/register.go b/android/register.go
index 1ac4440..10e14e0 100644
--- a/android/register.go
+++ b/android/register.go
@@ -31,7 +31,7 @@
type sortableComponent interface {
// componentName returns the name of the component.
//
- // Uniquely identifies the components within the set of components used at runtimr and during
+ // Uniquely identifies the components within the set of components used at runtime and during
// tests.
componentName() string
diff --git a/android/variable.go b/android/variable.go
index 40dd2d8..ff77fef 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -129,7 +129,7 @@
Exclude_srcs []string
}
- // eng is true for -eng builds, and can be used to turn on additionaly heavyweight debugging
+ // eng is true for -eng builds, and can be used to turn on additional heavyweight debugging
// features.
Eng struct {
Cflags []string
diff --git a/android_sdk/sdk_repo_host.go b/android_sdk/sdk_repo_host.go
index d64eb7a..f050a2e 100644
--- a/android_sdk/sdk_repo_host.go
+++ b/android_sdk/sdk_repo_host.go
@@ -122,17 +122,10 @@
s.CopySpecsToDir(ctx, builder, packageSpecs, dir)
- // Collect licenses to write into NOTICE.txt
- noticeMap := map[string]android.Paths{}
- for path, pkgSpec := range packageSpecs {
- licenseFiles := pkgSpec.EffectiveLicenseFiles()
- if len(licenseFiles) > 0 {
- noticeMap[path] = pkgSpec.EffectiveLicenseFiles()
- }
- }
- notices := android.BuildNotices(ctx, noticeMap)
+ noticeFile := android.PathForModuleOut(ctx, "NOTICES.txt")
+ android.BuildNoticeTextOutputFromLicenseMetadata(ctx, noticeFile)
builder.Command().Text("cp").
- Input(notices.TxtOutput.Path()).
+ Input(noticeFile).
Text(filepath.Join(dir.String(), "NOTICE.txt"))
// Handle `merge_zips` by extracting their contents into our tmpdir
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index ae52688..6fac79d 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -191,6 +191,7 @@
// will be removed later by byfix
// TODO: does this property matter in the license module?
"LOCAL_LICENSE_CONDITIONS": "android_license_conditions",
+ "LOCAL_GENERATED_SOURCES": "generated_sources",
})
addStandardProperties(bpparser.BoolType,
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index abdbf53..81b5c30 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1620,6 +1620,31 @@
}
`,
},
+ {
+ desc: "LOCAL_GENERATED_SOURCES",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_SRC_FILES := src1, src2, src3
+LOCAL_GENERATED_SOURCES := gen_src1, gen_src2, gen_src3
+include $(BUILD_PACKAGE)
+ `,
+ expected: `
+android_app {
+ name: "foo",
+ srcs: [
+ "src1,",
+ "src2,",
+ "src3",
+ ],
+ generated_sources: [
+ "gen_src1,",
+ "gen_src2,",
+ "gen_src3",
+ ],
+}
+`,
+ },
}
func TestEndToEnd(t *testing.T) {
diff --git a/apex/builder.go b/apex/builder.go
index a66e1e0..1a1f22b 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -397,6 +397,22 @@
return output.OutputPath
}
+func markManifestTestOnly(ctx android.ModuleContext, androidManifestFile android.Path) android.Path {
+ return java.ManifestFixer(java.ManifestFixerParams{
+ Ctx: ctx,
+ Manifest: androidManifestFile,
+ SdkContext: nil,
+ ClassLoaderContexts: nil,
+ IsLibrary: false,
+ UseEmbeddedNativeLibs: false,
+ UsesNonSdkApis: false,
+ UseEmbeddedDex: false,
+ HasNoCode: false,
+ TestOnly: true,
+ LoggingParent: "",
+ })
+}
+
// buildUnflattendApex creates build rules to build an APEX using apexer.
func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
apexType := a.properties.ApexType
@@ -595,6 +611,11 @@
if a.properties.AndroidManifest != nil {
androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
+
+ if a.testApex {
+ androidManifestFile = markManifestTestOnly(ctx, androidManifestFile)
+ }
+
implicitInputs = append(implicitInputs, androidManifestFile)
optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
}
diff --git a/bp2build/java_plugin_conversion_test.go b/bp2build/java_plugin_conversion_test.go
new file mode 100644
index 0000000..ff13bb0
--- /dev/null
+++ b/bp2build/java_plugin_conversion_test.go
@@ -0,0 +1,72 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/java"
+)
+
+func runJavaPluginTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ (&tc).moduleTypeUnderTest = "java_plugin"
+ (&tc).moduleTypeUnderTestFactory = java.PluginFactory
+ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("java_library", java.LibraryFactory)
+ }, tc)
+}
+
+func TestJavaPlugin(t *testing.T) {
+ runJavaPluginTestCase(t, bp2buildTestCase{
+ description: "java_plugin with srcs, libs, static_libs",
+ blueprint: `java_plugin {
+ name: "java-plug-1",
+ srcs: ["a.java", "b.java"],
+ libs: ["java-lib-1"],
+ static_libs: ["java-lib-2"],
+ bazel_module: { bp2build_available: true },
+}
+
+java_library {
+ name: "java-lib-1",
+ srcs: ["b.java"],
+ bazel_module: { bp2build_available: false },
+}
+
+java_library {
+ name: "java-lib-2",
+ srcs: ["c.java"],
+ bazel_module: { bp2build_available: false },
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("java_plugin", "java-plug-1", attrNameToString{
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`,
+ "deps": `[
+ ":java-lib-1",
+ ":java-lib-2",
+ ]`,
+ "srcs": `[
+ "a.java",
+ "b.java",
+ ]`,
+ }),
+ },
+ })
+}
diff --git a/cc/binary.go b/cc/binary.go
index ee3de3f..bf77d3d 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -76,7 +76,6 @@
// cc_binary_host produces a binary that is runnable on a host.
func BinaryHostFactory() android.Module {
module, _ := newBinary(android.HostSupported, true)
- module.bazelable = true
return module.Init()
}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 1f99a96..153b025 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -408,6 +408,7 @@
type dex2oatDependencyTag struct {
blueprint.BaseDependencyTag
+ android.LicenseAnnotationToolchainDependencyTag
}
func (d dex2oatDependencyTag) ExcludeFromVisibilityEnforcement() {
diff --git a/java/OWNERS b/java/OWNERS
index 5242712..5b71b1e 100644
--- a/java/OWNERS
+++ b/java/OWNERS
@@ -1 +1,4 @@
per-file dexpreopt*.go = ngeoffray@google.com,calin@google.com,skvadrik@google.com
+
+# For metalava team to disable lint checks in platform
+per-file droidstubs.go = aurimas@google.com,emberrose@google.com,sjgilbert@google.com
\ No newline at end of file
diff --git a/java/aar.go b/java/aar.go
index aabbec6..4687424 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -276,9 +276,19 @@
manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
- manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, classLoaderContexts,
- a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode,
- a.LoggingParent)
+ manifestPath := ManifestFixer(ManifestFixerParams{
+ Ctx: ctx,
+ Manifest: manifestSrcPath,
+ SdkContext: sdkContext,
+ ClassLoaderContexts: classLoaderContexts,
+ IsLibrary: a.isLibrary,
+ UseEmbeddedNativeLibs: a.useEmbeddedNativeLibs,
+ UsesNonSdkApis: a.usesNonSdkApis,
+ UseEmbeddedDex: a.useEmbeddedDex,
+ HasNoCode: a.hasNoCode,
+ TestOnly: false,
+ LoggingParent: a.LoggingParent,
+ })
// Add additional manifest files to transitive manifests.
additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests)
diff --git a/java/android_manifest.go b/java/android_manifest.go
index f29d8ad..a5d5b97 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -28,13 +28,10 @@
var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer",
blueprint.RuleParams{
Command: `${config.ManifestFixerCmd} ` +
- `--minSdkVersion ${minSdkVersion} ` +
- `--targetSdkVersion ${targetSdkVersion} ` +
- `--raise-min-sdk-version ` +
`$args $in $out`,
CommandDeps: []string{"${config.ManifestFixerCmd}"},
},
- "minSdkVersion", "targetSdkVersion", "args")
+ "args")
var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger",
blueprint.RuleParams{
@@ -58,84 +55,110 @@
return targetSdkVersion
}
-// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
-func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext android.SdkContext,
- classLoaderContexts dexpreopt.ClassLoaderContextMap, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis,
- useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
+type ManifestFixerParams struct {
+ Ctx android.ModuleContext
+ Manifest android.Path
+ SdkContext android.SdkContext
+ ClassLoaderContexts dexpreopt.ClassLoaderContextMap
+ IsLibrary bool
+ UseEmbeddedNativeLibs bool
+ UsesNonSdkApis bool
+ UseEmbeddedDex bool
+ HasNoCode bool
+ TestOnly bool
+ LoggingParent string
+}
+// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
+func ManifestFixer(params ManifestFixerParams) android.Path {
var args []string
- if isLibrary {
+
+ if params.IsLibrary {
args = append(args, "--library")
- } else {
- minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersion(ctx)
+ } else if params.SdkContext != nil {
+ minSdkVersion, err := params.SdkContext.MinSdkVersion(params.Ctx).EffectiveVersion(params.Ctx)
if err != nil {
- ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+ params.Ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
if minSdkVersion.FinalOrFutureInt() >= 23 {
- args = append(args, fmt.Sprintf("--extract-native-libs=%v", !useEmbeddedNativeLibs))
- } else if useEmbeddedNativeLibs {
- ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
+ args = append(args, fmt.Sprintf("--extract-native-libs=%v", !params.UseEmbeddedNativeLibs))
+ } else if params.UseEmbeddedNativeLibs {
+ params.Ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
minSdkVersion)
}
}
- if usesNonSdkApis {
+ if params.UsesNonSdkApis {
args = append(args, "--uses-non-sdk-api")
}
- if useEmbeddedDex {
+ if params.UseEmbeddedDex {
args = append(args, "--use-embedded-dex")
}
- // manifest_fixer should add only the implicit SDK libraries inferred by Soong, not those added
- // explicitly via `uses_libs`/`optional_uses_libs`.
- requiredUsesLibs, optionalUsesLibs := classLoaderContexts.ImplicitUsesLibs()
- for _, usesLib := range requiredUsesLibs {
- args = append(args, "--uses-library", usesLib)
- }
- for _, usesLib := range optionalUsesLibs {
- args = append(args, "--optional-uses-library", usesLib)
+ if params.ClassLoaderContexts != nil {
+ // manifest_fixer should add only the implicit SDK libraries inferred by Soong, not those added
+ // explicitly via `uses_libs`/`optional_uses_libs`.
+ requiredUsesLibs, optionalUsesLibs := params.ClassLoaderContexts.ImplicitUsesLibs()
+
+ for _, usesLib := range requiredUsesLibs {
+ args = append(args, "--uses-library", usesLib)
+ }
+ for _, usesLib := range optionalUsesLibs {
+ args = append(args, "--optional-uses-library", usesLib)
+ }
}
- if hasNoCode {
+ if params.HasNoCode {
args = append(args, "--has-no-code")
}
- if loggingParent != "" {
- args = append(args, "--logging-parent", loggingParent)
+ if params.TestOnly {
+ args = append(args, "--test-only")
+ }
+
+ if params.LoggingParent != "" {
+ args = append(args, "--logging-parent", params.LoggingParent)
}
var deps android.Paths
- targetSdkVersion := targetSdkVersionForManifestFixer(ctx, sdkContext)
+ var argsMapper = make(map[string]string)
- if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
- targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
- deps = append(deps, ApiFingerprintPath(ctx))
+ if params.SdkContext != nil {
+ targetSdkVersion := targetSdkVersionForManifestFixer(params.Ctx, params.SdkContext)
+ args = append(args, "--targetSdkVersion ", targetSdkVersion)
+
+ if UseApiFingerprint(params.Ctx) && params.Ctx.ModuleName() != "framework-res" {
+ targetSdkVersion = params.Ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(params.Ctx).String())
+ deps = append(deps, ApiFingerprintPath(params.Ctx))
+ }
+
+ minSdkVersion, err := params.SdkContext.MinSdkVersion(params.Ctx).EffectiveVersionString(params.Ctx)
+ if err != nil {
+ params.Ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+ }
+
+ if UseApiFingerprint(params.Ctx) && params.Ctx.ModuleName() != "framework-res" {
+ minSdkVersion = params.Ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(params.Ctx).String())
+ deps = append(deps, ApiFingerprintPath(params.Ctx))
+ }
+
+ if err != nil {
+ params.Ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+ }
+ args = append(args, "--minSdkVersion ", minSdkVersion)
+ args = append(args, "--raise-min-sdk-version")
}
- minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx)
- if err != nil {
- ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
- }
- if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
- minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
- deps = append(deps, ApiFingerprintPath(ctx))
- }
+ fixedManifest := android.PathForModuleOut(params.Ctx, "manifest_fixer", "AndroidManifest.xml")
+ argsMapper["args"] = strings.Join(args, " ")
- fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
- if err != nil {
- ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
- }
- ctx.Build(pctx, android.BuildParams{
+ params.Ctx.Build(pctx, android.BuildParams{
Rule: manifestFixerRule,
Description: "fix manifest",
- Input: manifest,
+ Input: params.Manifest,
Implicits: deps,
Output: fixedManifest,
- Args: map[string]string{
- "minSdkVersion": minSdkVersion,
- "targetSdkVersion": targetSdkVersion,
- "args": strings.Join(args, " "),
- },
+ Args: argsMapper,
})
return fixedManifest.WithoutRel()
diff --git a/java/app_test.go b/java/app_test.go
index 2322ef4..16bbec1 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2512,7 +2512,7 @@
`--uses-library qux ` +
`--uses-library quuz ` +
`--uses-library runtime-library`
- android.AssertStringEquals(t, "manifest_fixer args", expectManifestFixerArgs, actualManifestFixerArgs)
+ android.AssertStringDoesContain(t, "manifest_fixer args", actualManifestFixerArgs, expectManifestFixerArgs)
// Test that all libraries are verified (library order matters).
verifyCmd := app.Rule("verify_uses_libraries").RuleParams.Command
@@ -3055,7 +3055,7 @@
result := fixture.RunTestWithBp(t, bp)
foo := result.ModuleForTests("foo", "android_common")
- manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args
- android.AssertStringEquals(t, testCase.name, testCase.targetSdkVersionExpected, manifestFixerArgs["targetSdkVersion"])
+ manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+ android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected)
}
}
diff --git a/java/base.go b/java/base.go
index a3eb8de..42d7733 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1969,7 +1969,7 @@
func (j *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
switch ctx.ModuleType() {
- case "java_library", "java_library_host":
+ case "java_library", "java_library_host", "java_library_static":
if lib, ok := ctx.Module().(*Library); ok {
javaLibraryBp2Build(ctx, lib)
}
@@ -1978,5 +1978,4 @@
javaBinaryHostBp2Build(ctx, binary)
}
}
-
}
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 7c8be1e..3af5f1c 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -297,6 +297,7 @@
type hiddenApiAnnotationsDependencyTag struct {
blueprint.BaseDependencyTag
+ android.LicenseAnnotationSharedDependencyTag
}
// Tag used to mark dependencies on java_library instances that contains Java source files whose
diff --git a/java/java.go b/java/java.go
index ca4b3cf..7a2a991 100644
--- a/java/java.go
+++ b/java/java.go
@@ -274,6 +274,9 @@
// True if the dependency is relinked at runtime.
runtimeLinked bool
+
+ // True if the dependency is a toolchain, for example an annotation processor.
+ toolchain bool
}
// installDependencyTag is a dependency tag that is annotated to cause the installed files of the
@@ -287,6 +290,8 @@
func (d dependencyTag) LicenseAnnotations() []android.LicenseAnnotation {
if d.runtimeLinked {
return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency}
+ } else if d.toolchain {
+ return []android.LicenseAnnotation{android.LicenseAnnotationToolchain}
}
return nil
}
@@ -329,19 +334,19 @@
staticLibTag = dependencyTag{name: "staticlib"}
libTag = dependencyTag{name: "javalib", runtimeLinked: true}
java9LibTag = dependencyTag{name: "java9lib", runtimeLinked: true}
- pluginTag = dependencyTag{name: "plugin"}
- errorpronePluginTag = dependencyTag{name: "errorprone-plugin"}
- exportedPluginTag = dependencyTag{name: "exported-plugin"}
+ pluginTag = dependencyTag{name: "plugin", toolchain: true}
+ errorpronePluginTag = dependencyTag{name: "errorprone-plugin", toolchain: true}
+ exportedPluginTag = dependencyTag{name: "exported-plugin", toolchain: true}
bootClasspathTag = dependencyTag{name: "bootclasspath", runtimeLinked: true}
systemModulesTag = dependencyTag{name: "system modules", runtimeLinked: true}
frameworkResTag = dependencyTag{name: "framework-res"}
kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib", runtimeLinked: true}
kotlinAnnotationsTag = dependencyTag{name: "kotlin-annotations", runtimeLinked: true}
- kotlinPluginTag = dependencyTag{name: "kotlin-plugin"}
+ kotlinPluginTag = dependencyTag{name: "kotlin-plugin", toolchain: true}
proguardRaiseTag = dependencyTag{name: "proguard-raise"}
certificateTag = dependencyTag{name: "certificate"}
instrumentationForTag = dependencyTag{name: "instrumentation_for"}
- extraLintCheckTag = dependencyTag{name: "extra-lint-check"}
+ extraLintCheckTag = dependencyTag{name: "extra-lint-check", toolchain: true}
jniLibTag = dependencyTag{name: "jnilib", runtimeLinked: true}
syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"}
jniInstallTag = installDependencyTag{name: "jni install"}
@@ -2005,7 +2010,7 @@
Javacopts bazel.StringListAttribute
}
-func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) {
+func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) *javaLibraryAttributes {
srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs))
attrs := &javaLibraryAttributes{
Srcs: srcs,
@@ -2015,9 +2020,21 @@
attrs.Javacopts = bazel.MakeStringListAttribute(m.properties.Javacflags)
}
+ var deps bazel.LabelList
if m.properties.Libs != nil {
- attrs.Deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, m.properties.Libs))
+ deps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Libs))
}
+ if m.properties.Static_libs != nil {
+ //TODO(b/217236083) handle static libs similarly to Soong
+ deps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Static_libs))
+ }
+ attrs.Deps = bazel.MakeLabelListAttribute(deps)
+
+ return attrs
+}
+
+func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) {
+ attrs := m.convertLibraryAttrsBp2Build(ctx)
props := bazel.BazelTargetModuleProperties{
Rule_class: "java_library",
diff --git a/java/plugin.go b/java/plugin.go
index 297ac2c..f1a5ec4 100644
--- a/java/plugin.go
+++ b/java/plugin.go
@@ -14,7 +14,12 @@
package java
-import "android/soong/android"
+import (
+ "android/soong/android"
+ "android/soong/bazel"
+
+ "github.com/google/blueprint/proptools"
+)
func init() {
registerJavaPluginBuildComponents(android.InitRegistrationContext)
@@ -24,7 +29,6 @@
ctx.RegisterModuleType("java_plugin", PluginFactory)
}
-// A java_plugin module describes a host java library that will be used by javac as an annotation processor.
func PluginFactory() android.Module {
module := &Plugin{}
@@ -32,9 +36,13 @@
module.AddProperties(&module.pluginProperties)
InitJavaModule(module, android.HostSupported)
+
+ android.InitBazelModule(module)
+
return module
}
+// Plugin describes a java_plugin module, a host java library that will be used by javac as an annotation processor.
type Plugin struct {
Library
@@ -50,3 +58,32 @@
// parallelism and cause more recompilation for modules that depend on modules that use this plugin.
Generates_api *bool
}
+
+type pluginAttributes struct {
+ *javaLibraryAttributes
+ Processor_class *string
+ Target_compatible_with bazel.LabelListAttribute
+}
+
+// ConvertWithBp2build is used to convert android_app to Bazel.
+func (p *Plugin) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ libAttrs := p.convertLibraryAttrsBp2Build(ctx)
+ attrs := &pluginAttributes{
+ libAttrs,
+ nil,
+ bazel.LabelListAttribute{},
+ }
+
+ if p.pluginProperties.Processor_class != nil {
+ attrs.Processor_class = p.pluginProperties.Processor_class
+ }
+
+ var enabledProperty bazel.BoolAttribute
+ enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, android.Android.Name, proptools.BoolPtr(false))
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "java_plugin",
+ }
+
+ ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: p.Name()}, attrs, enabledProperty)
+}
diff --git a/mk2rbc/expr.go b/mk2rbc/expr.go
index 3f355ac..07f7ca1 100644
--- a/mk2rbc/expr.go
+++ b/mk2rbc/expr.go
@@ -378,32 +378,6 @@
}
}
-// variableDefinedExpr corresponds to Make's ifdef VAR
-type variableDefinedExpr struct {
- v variable
-}
-
-func (v *variableDefinedExpr) emit(gctx *generationContext) {
- if v.v != nil {
- v.v.emitDefined(gctx)
- return
- }
- gctx.writef("%s(%q)", cfnWarning, "TODO(VAR)")
-}
-
-func (_ *variableDefinedExpr) typ() starlarkType {
- return starlarkTypeBool
-}
-
-func (v *variableDefinedExpr) emitListVarCopy(gctx *generationContext) {
- v.emit(gctx)
-}
-
-func (v *variableDefinedExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
- // TODO: VariableDefinedExpr isn't really an expression?
- return v
-}
-
type listExpr struct {
items []starlarkExpr
}
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index e317cad..90dc46b 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -829,11 +829,7 @@
pathPattern = append(pathPattern, chunk)
}
}
- if pathPattern[0] == "" {
- if len(ctx.includeTops) == 0 {
- ctx.errorf(v, "inherit-product/include statements must not be prefixed with a variable, or must include a #RBC# include_top comment beforehand giving a root directory to search.")
- return
- }
+ if pathPattern[0] == "" && len(ctx.includeTops) > 0 {
// If pattern starts from the top. restrict it to the directories where
// we know inherit-product uses dynamically calculated path.
for _, p := range ctx.includeTops {
@@ -849,14 +845,20 @@
ctx.errorf(v, "there are >%d files matching the pattern, please rewrite it", maxMatchingFiles)
return
}
- res := inheritedDynamicModule{*varPath, []*moduleInfo{}, loadAlways}
- for _, p := range matchingPaths {
- // A product configuration files discovered dynamically may attempt to inherit
- // from another one which does not exist in this source tree. Prevent load errors
- // by always loading the dynamic files as optional.
- res.candidateModules = append(res.candidateModules, ctx.newDependentModule(p, true))
+ if len(matchingPaths) == 1 {
+ res := inheritedStaticModule{ctx.newDependentModule(matchingPaths[0], loadAlways && ctx.ifNestLevel == 0), loadAlways}
+ processModule(res)
+ } else {
+ needsWarning := pathPattern[0] == "" && len(ctx.includeTops) == 0
+ res := inheritedDynamicModule{*varPath, []*moduleInfo{}, loadAlways, ctx.errorLocation(v), needsWarning}
+ for _, p := range matchingPaths {
+ // A product configuration files discovered dynamically may attempt to inherit
+ // from another one which does not exist in this source tree. Prevent load errors
+ // by always loading the dynamic files as optional.
+ res.candidateModules = append(res.candidateModules, ctx.newDependentModule(p, true))
+ }
+ processModule(res)
}
- processModule(res)
}
func (ctx *parseContext) findMatchingPaths(pattern []string) []string {
@@ -1003,19 +1005,14 @@
ctx.popReceiver()
}
-func (ctx *parseContext) newIfDefinedNode(check *mkparser.Directive) (starlarkExpr, bool) {
- if !check.Args.Const() {
- return ctx.newBadExpr(check, "ifdef variable ref too complex: %s", check.Args.Dump()), false
- }
- v := ctx.addVariable(check.Args.Strings[0])
- return &variableDefinedExpr{v}, true
-}
-
func (ctx *parseContext) parseCondition(check *mkparser.Directive) starlarkNode {
switch check.Name {
case "ifdef", "ifndef", "elifdef", "elifndef":
- v, ok := ctx.newIfDefinedNode(check)
- if ok && strings.HasSuffix(check.Name, "ndef") {
+ if !check.Args.Const() {
+ return &exprNode{expr: ctx.newBadExpr(check, "ifdef variable ref too complex: %s", check.Args.Dump())}
+ }
+ v := NewVariableRefExpr(ctx.addVariable(check.Args.Strings[0]), false)
+ if strings.HasSuffix(check.Name, "ndef") {
v = ¬Expr{v}
}
return &ifNode{
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index c4f7da3..376ee5e 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -131,7 +131,7 @@
def init(g, handle):
cfg = rblf.cfg(handle)
rblf.inherit(handle, "part", _part_init)
- if g.get("PRODUCT_NAME") != None:
+ if cfg.get("PRODUCT_NAME", ""):
if not _part1_init:
rblf.mkerror("product.mk", "Cannot find %s" % (":part1.star"))
rblf.inherit(handle, "part1", _part1_init)
@@ -174,7 +174,7 @@
def init(g, handle):
cfg = rblf.cfg(handle)
_part_init(g, handle)
- if g.get("PRODUCT_NAME") != None:
+ if cfg.get("PRODUCT_NAME", ""):
if not _part1_init:
rblf.mkerror("product.mk", "Cannot find %s" % (":part1.star"))
_part1_init(g, handle)
@@ -231,7 +231,7 @@
def init(g, handle):
cfg = rblf.cfg(handle)
- if g.get("PRODUCT_NAME") != None:
+ if cfg.get("PRODUCT_NAME", ""):
cfg["PRODUCT_NAME"] = "gizmo"
else:
pass
@@ -275,7 +275,7 @@
def init(g, handle):
cfg = rblf.cfg(handle)
- if g.get("PRODUCT_NAME") != None:
+ if cfg.get("PRODUCT_NAME", ""):
# Comment
pass
else:
@@ -296,7 +296,7 @@
def init(g, handle):
cfg = rblf.cfg(handle)
- if not g.get("PRODUCT_NAME") != None:
+ if not cfg.get("PRODUCT_NAME", ""):
cfg["PRODUCT_NAME"] = "gizmo1"
else:
cfg["PRODUCT_NAME"] = "gizmo2"
@@ -315,9 +315,9 @@
def init(g, handle):
cfg = rblf.cfg(handle)
- if g.get("PRODUCT_NAME") != None:
+ if cfg.get("PRODUCT_NAME", ""):
cfg["PRODUCT_NAME"] = "gizmo"
- elif not g.get("PRODUCT_PACKAGES") != None:
+ elif not cfg.get("PRODUCT_PACKAGES", []):
# Comment
pass
`,
@@ -509,11 +509,11 @@
def init(g, handle):
cfg = rblf.cfg(handle)
- if g.get("PRODUCT_NAME") != None:
+ if cfg.get("PRODUCT_NAME", ""):
cfg["PRODUCT_PACKAGES"] = ["pack-if0"]
- if g.get("PRODUCT_MODEL") != None:
+ if cfg.get("PRODUCT_MODEL", ""):
cfg["PRODUCT_PACKAGES"] = ["pack-if-if"]
- elif g.get("PRODUCT_NAME") != None:
+ elif cfg.get("PRODUCT_NAME", ""):
cfg["PRODUCT_PACKAGES"] = ["pack-if-elif"]
else:
cfg["PRODUCT_PACKAGES"] = ["pack-if-else"]
@@ -1072,13 +1072,7 @@
cfg = rblf.cfg(handle)
g["MY_PATH"] = "foo"
#RBC# include_top vendor/foo1
- _entry = {
- "vendor/foo1/cfg.mk": ("vendor/foo1/cfg", _cfg_init),
- }.get("%s/cfg.mk" % g["MY_PATH"])
- (_varmod, _varmod_init) = _entry if _entry else (None, None)
- if not _varmod_init:
- rblf.mkerror("product.mk", "Cannot find %s" % ("%s/cfg.mk" % g["MY_PATH"]))
- rblf.inherit(handle, _varmod, _varmod_init)
+ rblf.inherit(handle, "vendor/foo1/cfg", _cfg_init)
`,
},
{
@@ -1098,25 +1092,13 @@
cfg = rblf.cfg(handle)
g["MY_PATH"] = "foo"
#RBC# include_top vendor/foo1
- _entry = {
- "vendor/foo1/cfg.mk": ("vendor/foo1/cfg", _cfg_init),
- }.get("%s/cfg.mk" % g["MY_PATH"])
- (_varmod, _varmod_init) = _entry if _entry else (None, None)
- if not _varmod_init:
- rblf.mkerror("product.mk", "Cannot find %s" % ("%s/cfg.mk" % g["MY_PATH"]))
- rblf.inherit(handle, _varmod, _varmod_init)
+ rblf.inherit(handle, "vendor/foo1/cfg", _cfg_init)
#RBC# include_top vendor/foo1
- _entry = {
- "vendor/foo1/cfg.mk": ("vendor/foo1/cfg", _cfg_init),
- }.get("%s/cfg.mk" % g["MY_PATH"])
- (_varmod, _varmod_init) = _entry if _entry else (None, None)
- if not _varmod_init:
- rblf.mkerror("product.mk", "Cannot find %s" % ("%s/cfg.mk" % g["MY_PATH"]))
- rblf.inherit(handle, _varmod, _varmod_init)
+ rblf.inherit(handle, "vendor/foo1/cfg", _cfg_init)
`,
},
{
- desc: "Dynamic inherit path that lacks necessary hint",
+ desc: "Dynamic inherit path that lacks hint",
mkname: "product.mk",
in: `
#RBC# include_top foo
@@ -1133,26 +1115,23 @@
expected: `#RBC# include_top foo
load("//build/make/core:product_config.rbc", "rblf")
load("//foo:font.star|init", _font_init = "init")
+load("//bar:font.star|init", _font1_init = "init")
def init(g, handle):
cfg = rblf.cfg(handle)
- _entry = {
- "foo/font.mk": ("foo/font", _font_init),
- }.get("%s/font.mk" % g.get("MY_VAR", ""))
- (_varmod, _varmod_init) = _entry if _entry else (None, None)
- if not _varmod_init:
- rblf.mkerror("product.mk", "Cannot find %s" % ("%s/font.mk" % g.get("MY_VAR", "")))
- rblf.inherit(handle, _varmod, _varmod_init)
+ rblf.inherit(handle, "foo/font", _font_init)
#RBC# include_top foo
# There's some space and even this comment between the include_top and the inherit-product
+ rblf.inherit(handle, "foo/font", _font_init)
+ rblf.mkwarning("product.mk:11", "Including a path with a non-constant prefix, please convert this to a simple literal to generate cleaner starlark.")
_entry = {
"foo/font.mk": ("foo/font", _font_init),
+ "bar/font.mk": ("bar/font", _font1_init),
}.get("%s/font.mk" % g.get("MY_VAR", ""))
(_varmod, _varmod_init) = _entry if _entry else (None, None)
if not _varmod_init:
rblf.mkerror("product.mk", "Cannot find %s" % ("%s/font.mk" % g.get("MY_VAR", "")))
rblf.inherit(handle, _varmod, _varmod_init)
- rblf.mk2rbc_error("product.mk:11", "inherit-product/include statements must not be prefixed with a variable, or must include a #RBC# include_top comment beforehand giving a root directory to search.")
`,
},
{
diff --git a/mk2rbc/node.go b/mk2rbc/node.go
index 4f7c4f0..dea4dc8 100644
--- a/mk2rbc/node.go
+++ b/mk2rbc/node.go
@@ -86,6 +86,8 @@
path interpolateExpr
candidateModules []*moduleInfo
loadAlways bool
+ location ErrorLocation
+ needsWarning bool
}
func (i inheritedDynamicModule) name() string {
@@ -97,6 +99,10 @@
}
func (i inheritedDynamicModule) emitSelect(gctx *generationContext) {
+ if i.needsWarning {
+ gctx.newLine()
+ gctx.writef("%s.mkwarning(%q, %q)", baseName, i.location, "Including a path with a non-constant prefix, please convert this to a simple literal to generate cleaner starlark.")
+ }
gctx.newLine()
gctx.writef("_entry = {")
gctx.indentLevel++
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index d80a617..2d3103b 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -65,6 +65,9 @@
parser.add_argument('--has-no-code', dest='has_no_code', action='store_true',
help=('adds hasCode="false" attribute to application. Ignored if application elem '
'already has a hasCode attribute.'))
+ parser.add_argument('--test-only', dest='test_only', action='store_true',
+ help=('adds testOnly="true" attribute to application. Assign true value if application elem '
+ 'already has a testOnly attribute.'))
parser.add_argument('input', help='input AndroidManifest.xml file')
parser.add_argument('output', help='output AndroidManifest.xml file')
return parser.parse_args()
@@ -318,6 +321,26 @@
attr.value = 'false'
application.setAttributeNode(attr)
+def set_test_only_flag_to_true(doc):
+ manifest = parse_manifest(doc)
+ elems = get_children_with_tag(manifest, 'application')
+ application = elems[0] if len(elems) == 1 else None
+ if len(elems) > 1:
+ raise RuntimeError('found multiple <application> tags')
+ elif not elems:
+ application = doc.createElement('application')
+ indent = get_indent(manifest.firstChild, 1)
+ first = manifest.firstChild
+ manifest.insertBefore(doc.createTextNode(indent), first)
+ manifest.insertBefore(application, first)
+
+ attr = application.getAttributeNodeNS(android_ns, 'testOnly')
+ if attr is not None:
+ # Do nothing If the application already has a testOnly attribute.
+ return
+ attr = doc.createAttributeNS(android_ns, 'android:testOnly')
+ attr.value = 'true'
+ application.setAttributeNode(attr)
def main():
"""Program entry point."""
@@ -349,6 +372,9 @@
if args.has_no_code:
set_has_code_to_false(doc)
+ if args.test_only:
+ set_test_only_flag_to_true(doc)
+
if args.extract_native_libs is not None:
add_extract_native_libs(doc, args.extract_native_libs)
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index f6fcaaf..199b279 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -521,12 +521,55 @@
self.assert_xml_equal(output, manifest_input)
def test_has_application_has_code_true(self):
- """ Do nothing if there's already an application elemeent even if its
+ """ Do nothing if there's already an application element even if its
hasCode attribute is true. """
manifest_input = self.manifest_tmpl % ' <application android:hasCode="true"/>\n'
output = self.run_test(manifest_input)
self.assert_xml_equal(output, manifest_input)
+class AddTestOnlyApplicationTest(unittest.TestCase):
+ """Unit tests for set_test_only_flag_to_true function."""
+
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
+ def run_test(self, input_manifest):
+ doc = minidom.parseString(input_manifest)
+ manifest_fixer.set_test_only_flag_to_true(doc)
+ output = io.StringIO()
+ manifest_fixer.write_xml(output, doc)
+ return output.getvalue()
+
+ manifest_tmpl = (
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+ '%s'
+ '</manifest>\n')
+
+ def test_no_application(self):
+ manifest_input = self.manifest_tmpl % ''
+ expected = self.manifest_tmpl % ' <application android:testOnly="true"/>\n'
+ output = self.run_test(manifest_input)
+ self.assert_xml_equal(output, expected)
+
+ def test_has_application_no_test_only(self):
+ manifest_input = self.manifest_tmpl % ' <application/>\n'
+ expected = self.manifest_tmpl % ' <application android:testOnly="true"/>\n'
+ output = self.run_test(manifest_input)
+ self.assert_xml_equal(output, expected)
+
+ def test_has_application_test_only_true(self):
+ """ If there's already an application element."""
+ manifest_input = self.manifest_tmpl % ' <application android:testOnly="true"/>\n'
+ output = self.run_test(manifest_input)
+ self.assert_xml_equal(output, manifest_input)
+
+ def test_has_application_test_only_false(self):
+ """ If there's already an application element with the testOnly attribute as false."""
+ manifest_input = self.manifest_tmpl % ' <application android:testOnly="false"/>\n'
+ output = self.run_test(manifest_input)
+ self.assert_xml_equal(output, manifest_input)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/snapshot/host_snapshot.go b/snapshot/host_snapshot.go
index 252cef8..09a382e 100644
--- a/snapshot/host_snapshot.go
+++ b/snapshot/host_snapshot.go
@@ -58,7 +58,7 @@
android.ModuleBase
android.PackagingBase
- zipFile android.OptionalPath
+ outputFile android.OutputPath
installDir android.InstallPath
}
@@ -141,7 +141,7 @@
// Create a zip file for the binaries, and a zip of the meta data, then merge zips
depsZipFile := android.PathForModuleOut(ctx, f.Name()+"_deps.zip").OutputPath
modsZipFile := android.PathForModuleOut(ctx, f.Name()+"_mods.zip").OutputPath
- outputFile := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
+ f.outputFile = android.PathForModuleOut(ctx, f.installFileName()).OutputPath
f.installDir = android.PathForModuleInstall(ctx)
@@ -158,26 +158,21 @@
builder.Command().
BuiltTool("merge_zips").
- Output(outputFile).
+ Output(f.outputFile).
Input(metaZipFile).
Input(modsZipFile)
builder.Build("manifest", fmt.Sprintf("Adding manifest %s", f.installFileName()))
- zip := ctx.InstallFile(f.installDir, f.installFileName(), outputFile)
- f.zipFile = android.OptionalPathForPath(zip)
+ ctx.InstallFile(f.installDir, f.installFileName(), f.outputFile)
}
// Implements android.AndroidMkEntriesProvider
func (f *hostSnapshot) AndroidMkEntries() []android.AndroidMkEntries {
- if !f.zipFile.Valid() {
- return []android.AndroidMkEntries{}
- }
-
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "ETC",
- OutputFile: f.zipFile,
- DistFiles: android.MakeDefaultDistFiles(f.zipFile.Path()),
+ OutputFile: android.OptionalPathForPath(f.outputFile),
+ DistFiles: android.MakeDefaultDistFiles(f.outputFile),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_MODULE_PATH", f.installDir.String())
diff --git a/ui/build/config.go b/ui/build/config.go
index d1714a4..1dd948c 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -15,10 +15,12 @@
package build
import (
+ "context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
+ "os/exec"
"path/filepath"
"runtime"
"strconv"
@@ -35,6 +37,9 @@
const (
envConfigDir = "vendor/google/tools/soong_config"
jsonSuffix = "json"
+
+ configFetcher = "vendor/google/tools/soong/expconfigfetcher"
+ envConfigFetchTimeout = 10 * time.Second
)
type Config struct{ *configImpl }
@@ -135,40 +140,82 @@
}
}
-func loadEnvConfig(config *configImpl) error {
+// fetchEnvConfig optionally fetches environment config from an
+// experiments system to control Soong features dynamically.
+func fetchEnvConfig(ctx Context, config *configImpl, envConfigName string) error {
+ s, err := os.Stat(configFetcher)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil
+ }
+ return err
+ }
+ if s.Mode()&0111 == 0 {
+ return fmt.Errorf("configuration fetcher binary %v is not executable: %v", configFetcher, s.Mode())
+ }
+
+ configExists := false
+ outConfigFilePath := filepath.Join(config.OutDir(), envConfigName + jsonSuffix)
+ if _, err := os.Stat(outConfigFilePath); err == nil {
+ configExists = true
+ }
+
+ tCtx, cancel := context.WithTimeout(ctx, envConfigFetchTimeout)
+ defer cancel()
+ cmd := exec.CommandContext(tCtx, configFetcher, "-output_config_dir", config.OutDir())
+ if err := cmd.Start(); err != nil {
+ return err
+ }
+
+ // If a config file already exists, return immediately and run the config file
+ // fetch in the background. Otherwise, wait for the config file to be fetched.
+ if configExists {
+ go cmd.Wait()
+ return nil
+ }
+ if err := cmd.Wait(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func loadEnvConfig(ctx Context, config *configImpl) error {
bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
if bc == "" {
return nil
}
+
+ if err := fetchEnvConfig(ctx, config, bc); err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to fetch config file: %v", err)
+ }
+
configDirs := []string{
- os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG_DIR"),
config.OutDir(),
+ os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG_DIR"),
envConfigDir,
}
- var cfgFile string
for _, dir := range configDirs {
- cfgFile = filepath.Join(os.Getenv("TOP"), dir, fmt.Sprintf("%s.%s", bc, jsonSuffix))
- if _, err := os.Stat(cfgFile); err == nil {
- break
- }
- }
-
- envVarsJSON, err := ioutil.ReadFile(cfgFile)
- if err != nil {
- fmt.Fprintf(os.Stderr, "\033[33mWARNING:\033[0m failed to open config file %s: %s\n", cfgFile, err.Error())
- return nil
- }
-
- var envVars map[string]map[string]string
- if err := json.Unmarshal(envVarsJSON, &envVars); err != nil {
- return fmt.Errorf("env vars config file: %s did not parse correctly: %s", cfgFile, err.Error())
- }
- for k, v := range envVars["env"] {
- if os.Getenv(k) != "" {
+ cfgFile := filepath.Join(os.Getenv("TOP"), dir, fmt.Sprintf("%s.%s", bc, jsonSuffix))
+ envVarsJSON, err := ioutil.ReadFile(cfgFile)
+ if err != nil {
continue
}
- config.Environment().Set(k, v)
+ ctx.Verbosef("Loading config file %v\n", cfgFile)
+ var envVars map[string]map[string]string
+ if err := json.Unmarshal(envVarsJSON, &envVars); err != nil {
+ fmt.Fprintf(os.Stderr, "Env vars config file %s did not parse correctly: %s", cfgFile, err.Error())
+ continue
+ }
+ for k, v := range envVars["env"] {
+ if os.Getenv(k) != "" {
+ continue
+ }
+ config.environ.Set(k, v)
+ }
+ ctx.Verbosef("Finished loading config file %v\n", cfgFile)
+ break
}
+
return nil
}
@@ -203,7 +250,7 @@
// loadEnvConfig needs to know what the OUT_DIR is, so it should
// be called after we determine the appropriate out directory.
- if err := loadEnvConfig(ret); err != nil {
+ if err := loadEnvConfig(ctx, ret); err != nil {
ctx.Fatalln("Failed to parse env config files: %v", err)
}