Merge "Allow PRODUCT_CFI_INCLUDE_PATHS to work with blueprints also"
diff --git a/android/bazel.go b/android/bazel.go
index 7123ed2..fa19e52 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -148,11 +148,12 @@
// external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails
// e.g. ERROR: Analysis of target '@soong_injection//mixed_builds:buildroot' failed
"external/bazelbuild-rules_android":/* recursive = */ true,
+ "external/bazel-skylib":/* recursive = */ true,
"prebuilts/sdk":/* recursive = */ false,
"prebuilts/sdk/tools":/* recursive = */ false,
"prebuilts/r8":/* recursive = */ false,
- "packages/apps/Music":/* recursive = */ false,
+ "packages/apps/Music":/* recursive = */ true,
}
// Configure modules in these directories to enable bp2build_available: true or false by default.
@@ -166,9 +167,10 @@
"system/logging/liblog": Bp2BuildDefaultTrueRecursively,
"system/timezone/apex": Bp2BuildDefaultTrueRecursively,
"system/timezone/output_data": Bp2BuildDefaultTrueRecursively,
- "external/jemalloc_new": Bp2BuildDefaultTrueRecursively,
- "external/fmtlib": Bp2BuildDefaultTrueRecursively,
"external/arm-optimized-routines": Bp2BuildDefaultTrueRecursively,
+ "external/fmtlib": Bp2BuildDefaultTrueRecursively,
+ "external/jemalloc_new": Bp2BuildDefaultTrueRecursively,
+ "external/libcxxabi": Bp2BuildDefaultTrueRecursively,
"external/scudo": Bp2BuildDefaultTrueRecursively,
"prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively,
}
@@ -204,16 +206,11 @@
"libBionicBenchmarksUtils", // cc_library_static, fatal error: 'map' file not found, from libcxx
"fmtlib", // cc_library_static, fatal error: 'cassert' file not found, from libcxx
"fmtlib_ndk", // cc_library_static, fatal error: 'cassert' file not found
+ "liblog", // http://b/186822772: cc_library, 'sys/cdefs.h' file not found
"libbase", // Requires liblog. http://b/186826479, cc_library, fatal error: 'memory' file not found, from libcxx.
+ // Also depends on fmtlib.
- // http://b/186024507: Includes errors because of the system_shared_libs default value.
- // Missing -isystem bionic/libc/include through the libc/libm/libdl
- // default dependencies if system_shared_libs is unset.
- "liblog", // http://b/186822772: cc_library, 'sys/cdefs.h' file not found
- "libjemalloc5_jet", // cc_library, 'sys/cdefs.h' file not found
- "libseccomp_policy", // http://b/186476753: cc_library, 'linux/filter.h' not found
- "note_memtag_heap_async", // http://b/185127353: cc_library_static, error: feature.h not found
- "note_memtag_heap_sync", // http://b/185127353: cc_library_static, error: feature.h not found
+ "libseccomp_policy", // depends on libbase
"gwp_asan_crash_handler", // cc_library, ld.lld: error: undefined symbol: memset
@@ -236,7 +233,10 @@
// Per-module denylist to opt modules out of mixed builds. Such modules will
// still be generated via bp2build.
- mixedBuildsDisabledList = []string{}
+ mixedBuildsDisabledList = []string{
+ "libc++abi", // http://b/195970501, cc_library_static, duplicate symbols because it propagates libc objects.
+ "libc++demangle", // http://b/195970501, cc_library_static, duplicate symbols because it propagates libc objects.
+ }
// Used for quicker lookups
bp2buildModuleDoNotConvert = map[string]bool{}
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 341d500..312f009 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -28,8 +28,6 @@
"android/soong/bazel/cquery"
- "github.com/google/blueprint/bootstrap"
-
"android/soong/bazel"
"android/soong/shared"
)
@@ -57,6 +55,17 @@
archType ArchType
}
+// bazelHandler is the interface for a helper object related to deferring to Bazel for
+// processing a module (during Bazel mixed builds). Individual module types should define
+// their own bazel handler if they support deferring to Bazel.
+type BazelHandler interface {
+ // Issue query to Bazel to retrieve information about Bazel's view of the current module.
+ // If Bazel returns this information, set module properties on the current module to reflect
+ // the returned information.
+ // Returns true if information was available from Bazel, false if bazel invocation still needs to occur.
+ GenerateBazelBuildActions(ctx ModuleContext, label string) bool
+}
+
type BazelContext interface {
// The below methods involve queuing cquery requests to be later invoked
// by bazel. If any of these methods return (_, false), then the request
@@ -69,6 +78,9 @@
// Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error)
+ // Returns the executable binary resultant from building together the python sources
+ GetPythonBinary(label string, archType ArchType) (string, bool)
+
// ** End cquery methods
// Issues commands to Bazel to receive results for all cquery requests
@@ -123,8 +135,9 @@
type MockBazelContext struct {
OutputBaseDir string
- LabelToOutputFiles map[string][]string
- LabelToCcInfo map[string]cquery.CcInfo
+ LabelToOutputFiles map[string][]string
+ LabelToCcInfo map[string]cquery.CcInfo
+ LabelToPythonBinary map[string]string
}
func (m MockBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
@@ -137,6 +150,11 @@
return result, ok, nil
}
+func (m MockBazelContext) GetPythonBinary(label string, archType ArchType) (string, bool) {
+ result, ok := m.LabelToPythonBinary[label]
+ return result, ok
+}
+
func (m MockBazelContext) InvokeBazel() error {
panic("unimplemented")
}
@@ -174,6 +192,16 @@
return ret, ok, err
}
+func (bazelCtx *bazelContext) GetPythonBinary(label string, archType ArchType) (string, bool) {
+ rawString, ok := bazelCtx.cquery(label, cquery.GetPythonBinary, archType)
+ var ret string
+ if ok {
+ bazelOutput := strings.TrimSpace(rawString)
+ ret = cquery.GetPythonBinary.ParseResult(bazelOutput)
+ }
+ return ret, ok
+}
+
func (n noopBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
panic("unimplemented")
}
@@ -182,6 +210,10 @@
panic("unimplemented")
}
+func (n noopBazelContext) GetPythonBinary(label string, archType ArchType) (string, bool) {
+ panic("unimplemented")
+}
+
func (n noopBazelContext) GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool) {
panic("unimplemented")
}
@@ -726,7 +758,7 @@
// Add ninja file dependencies for files which all bazel invocations require.
bazelBuildList := absolutePath(filepath.Join(
- filepath.Dir(bootstrap.CmdlineArgs.ModuleListFile), "bazel.list"))
+ filepath.Dir(ctx.Config().moduleListFile), "bazel.list"))
ctx.AddNinjaFileDeps(bazelBuildList)
data, err := ioutil.ReadFile(bazelBuildList)
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index b050774..c09d218 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -115,6 +115,11 @@
func bazelLabelForModuleDeps(ctx BazelConversionPathContext, modules []string, isWholeLibs bool) bazel.LabelList {
var labels bazel.LabelList
+ // In some cases, a nil string list is different than an explicitly empty list.
+ if len(modules) == 0 && modules != nil {
+ labels.Includes = []bazel.Label{}
+ return labels
+ }
for _, module := range modules {
bpText := module
if m := SrcIsModule(module); m == "" {
diff --git a/android/config.go b/android/config.go
index b3b8f3c..35403b8 100644
--- a/android/config.go
+++ b/android/config.go
@@ -79,10 +79,6 @@
return false // Never compile Go code in the main build for debugging
}
-func (c Config) SrcDir() string {
- return c.srcDir
-}
-
// A DeviceConfig object represents the configuration for a particular device
// being built. For now there will only be one of these, but in the future there
// may be multiple devices being built.
@@ -126,7 +122,6 @@
deviceConfig *deviceConfig
- srcDir string // the path of the root source directory
buildDir string // the path of the build output directory
moduleListFile string // the path to the file which lists blueprint files to parse.
@@ -209,6 +204,20 @@
Bool(configurable.GcovCoverage) ||
Bool(configurable.ClangCoverage))
+ // when Platform_sdk_final is true (or PLATFORM_VERSION_CODENAME is REL), use Platform_sdk_version;
+ // if false (pre-released version, for example), use Platform_sdk_codename.
+ if Bool(configurable.Platform_sdk_final) {
+ if configurable.Platform_sdk_version != nil {
+ configurable.Platform_sdk_version_or_codename =
+ proptools.StringPtr(strconv.Itoa(*(configurable.Platform_sdk_version)))
+ } else {
+ return fmt.Errorf("Platform_sdk_version cannot be pointed by a NULL pointer")
+ }
+ } else {
+ configurable.Platform_sdk_version_or_codename =
+ proptools.StringPtr(String(configurable.Platform_sdk_codename))
+ }
+
return saveToBazelConfigFile(configurable, filepath.Dir(filename))
}
@@ -388,7 +397,7 @@
// multiple runs in the same program execution is carried over (such as Bazel
// context or environment deps).
func ConfigForAdditionalRun(c Config) (Config, error) {
- newConfig, err := NewConfig(c.srcDir, c.buildDir, c.moduleListFile, c.env)
+ newConfig, err := NewConfig(c.buildDir, c.moduleListFile, c.env)
if err != nil {
return Config{}, err
}
@@ -399,14 +408,13 @@
// NewConfig creates a new Config object. The srcDir argument specifies the path
// to the root source directory. It also loads the config file, if found.
-func NewConfig(srcDir, buildDir string, moduleListFile string, availableEnv map[string]string) (Config, error) {
+func NewConfig(buildDir string, moduleListFile string, availableEnv map[string]string) (Config, error) {
// Make a config with default options.
config := &config{
ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
env: availableEnv,
- srcDir: srcDir,
buildDir: buildDir,
multilibConflicts: make(map[ArchType]bool),
@@ -425,7 +433,7 @@
return Config{}, err
}
- absSrcDir, err := filepath.Abs(srcDir)
+ absSrcDir, err := filepath.Abs(".")
if err != nil {
return Config{}, err
}
@@ -583,7 +591,7 @@
// GoRoot returns the path to the root directory of the Go toolchain.
func (c *config) GoRoot() string {
- return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS())
+ return fmt.Sprintf("prebuilts/go/%s", c.PrebuiltOS())
}
// PrebuiltBuildTool returns the path to a tool in the prebuilts directory containing
diff --git a/android/filegroup.go b/android/filegroup.go
index e207412..97dd136 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -15,8 +15,9 @@
package android
import (
- "android/soong/bazel"
"strings"
+
+ "android/soong/bazel"
)
func init() {
@@ -108,7 +109,7 @@
return module
}
-func (fg *fileGroup) generateBazelBuildActions(ctx ModuleContext) bool {
+func (fg *fileGroup) GenerateBazelBuildActions(ctx ModuleContext) bool {
if !fg.MixedBuildsEnabled(ctx) {
return false
}
@@ -131,7 +132,7 @@
}
func (fg *fileGroup) GenerateAndroidBuildActions(ctx ModuleContext) {
- if fg.generateBazelBuildActions(ctx) {
+ if fg.GenerateBazelBuildActions(ctx) {
return
}
diff --git a/android/module.go b/android/module.go
index 5e2e06a..7451e09 100644
--- a/android/module.go
+++ b/android/module.go
@@ -235,8 +235,8 @@
// VisitDirectDeps calls visit for each direct dependency. If there are multiple
// direct dependencies on the same module visit will be called multiple times on that module
- // and OtherModuleDependencyTag will return a different tag for each. It skips any
- // dependencies that are not an android.Module.
+ // and OtherModuleDependencyTag will return a different tag for each. It raises an error if any of the
+ // dependencies are not an android.Module.
//
// The Module passed to the visit function should not be retained outside of the visit
// function, it may be invalidated by future mutators.
diff --git a/android/paths.go b/android/paths.go
index 9c9914e..71caaab 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -622,7 +622,7 @@
// It intended for use in globs that only list files that exist, so it allows '$' in
// filenames.
func pathsForModuleSrcFromFullPath(ctx EarlyModulePathContext, paths []string, incDirs bool) Paths {
- prefix := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir()) + "/"
+ prefix := ctx.ModuleDir() + "/"
if prefix == "./" {
prefix = ""
}
@@ -658,7 +658,7 @@
}
// Use Glob so that if the default doesn't exist, a dependency is added so that when it
// is created, we're run again.
- path := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir(), def)
+ path := filepath.Join(ctx.ModuleDir(), def)
return Glob(ctx, path, nil)
}
@@ -986,7 +986,7 @@
// code that is embedding ninja variables in paths
func safePathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
p, err := validateSafePath(pathComponents...)
- ret := SourcePath{basePath{p, ""}, ctx.Config().srcDir}
+ ret := SourcePath{basePath{p, ""}, "."}
if err != nil {
return ret, err
}
@@ -1002,7 +1002,7 @@
// pathForSource creates a SourcePath from pathComponents, but does not check that it exists.
func pathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
p, err := validatePath(pathComponents...)
- ret := SourcePath{basePath{p, ""}, ctx.Config().srcDir}
+ ret := SourcePath{basePath{p, ""}, "."}
if err != nil {
return ret, err
}
diff --git a/android/variable.go b/android/variable.go
index 0fb9078..5cf9aa8 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -42,6 +42,10 @@
Cflags []string
}
+ Platform_sdk_version_or_codename struct {
+ Java_resource_dirs []string
+ }
+
// unbundled_build is a catch-all property to annotate modules that don't build in one or
// more unbundled branches, usually due to dependencies missing from the manifest.
Unbundled_build struct {
@@ -164,6 +168,7 @@
Platform_version_name *string `json:",omitempty"`
Platform_sdk_version *int `json:",omitempty"`
Platform_sdk_codename *string `json:",omitempty"`
+ Platform_sdk_version_or_codename *string `json:",omitempty"`
Platform_sdk_final *bool `json:",omitempty"`
Platform_version_active_codenames []string `json:",omitempty"`
Platform_vndk_version *string `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index e525aff..b47f36b 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1100,13 +1100,6 @@
mctx.ModuleErrorf("base property is not set")
return
}
- // Workaround the issue reported in b/191269918 by using the unprefixed module name of this
- // module as the default variation to use if dependencies of this module do not have the correct
- // apex variant name. This name matches the name used to create the variations of modules for
- // which apexModuleTypeRequiresVariant return true.
- // TODO(b/191269918): Remove this workaround.
- unprefixedModuleName := android.RemoveOptionalPrebuiltPrefix(mctx.ModuleName())
- mctx.SetDefaultDependencyVariation(&unprefixedModuleName)
mctx.CreateVariations(apexBundleName)
if strings.HasPrefix(apexBundleName, "com.android.art") {
// TODO(b/183882457): See note for CreateAliasVariation above.
@@ -1587,6 +1580,7 @@
JacocoReportClassesFile() android.Path
Certificate() java.Certificate
BaseModuleName() string
+ LintDepSets() java.LintDepSets
}
var _ androidApp = (*java.AndroidApp)(nil)
@@ -1601,6 +1595,7 @@
fileToCopy := aapp.OutputFile()
af := newApexFile(ctx, fileToCopy, aapp.BaseModuleName(), dirInApex, app, aapp)
af.jacocoReportClassesFile = aapp.JacocoReportClassesFile()
+ af.lintDepSets = aapp.LintDepSets()
af.certificate = aapp.Certificate()
if app, ok := aapp.(interface {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 41bfcea..f07bf63 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -4663,6 +4663,7 @@
prebuilt_bootclasspath_fragment {
name: "art-bootclasspath-fragment",
+ image_name: "art",
contents: ["core-oj"],
hidden_api: {
annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
@@ -4871,7 +4872,7 @@
func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
preparer := android.GroupFixturePreparers(
- java.FixtureConfigureBootJars("myapex:libfoo", "myapex:libbar"),
+ java.FixtureConfigureApexBootJars("myapex:libfoo", "myapex:libbar"),
// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
// is disabled.
android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
@@ -4949,6 +4950,7 @@
name: "libfoo",
jars: ["libfoo.jar"],
apex_available: ["myapex"],
+ permitted_packages: ["foo"],
}
java_sdk_library_import {
@@ -4958,6 +4960,7 @@
},
apex_available: ["myapex"],
shared_library: false,
+ permitted_packages: ["bar"],
}
`
@@ -4998,6 +5001,7 @@
name: "libfoo",
jars: ["libfoo.jar"],
apex_available: ["myapex"],
+ permitted_packages: ["foo"],
}
java_sdk_library_import {
@@ -5007,6 +5011,7 @@
},
apex_available: ["myapex"],
shared_library: false,
+ permitted_packages: ["bar"],
}
`
@@ -5120,6 +5125,7 @@
prefer: true,
jars: ["libfoo.jar"],
apex_available: ["myapex"],
+ permitted_packages: ["foo"],
}
java_library {
@@ -5136,6 +5142,7 @@
},
apex_available: ["myapex"],
shared_library: false,
+ permitted_packages: ["bar"],
}
java_sdk_library {
@@ -5209,6 +5216,7 @@
name: "libfoo",
srcs: ["foo/bar/MyClass.java"],
apex_available: ["myapex"],
+ permitted_packages: ["foo"],
}
java_sdk_library_import {
@@ -5225,6 +5233,7 @@
srcs: ["foo/bar/MyClass.java"],
unsafe_ignore_missing_latest_api: true,
apex_available: ["myapex"],
+ permitted_packages: ["bar"],
}
`
@@ -5286,6 +5295,7 @@
prefer: true,
jars: ["libfoo.jar"],
apex_available: ["myapex"],
+ permitted_packages: ["foo"],
}
java_library {
@@ -5302,6 +5312,7 @@
},
apex_available: ["myapex"],
shared_library: false,
+ permitted_packages: ["bar"],
}
java_sdk_library {
@@ -6899,6 +6910,7 @@
apex_available: [
"some-updatable-apex",
],
+ permitted_packages: ["some.updatable.apex.lib"],
}
java_library {
@@ -6908,6 +6920,7 @@
"some-non-updatable-apex",
],
compile_dex: true,
+ permitted_packages: ["some.non.updatable.apex.lib"],
}
bootclasspath_fragment {
@@ -7118,7 +7131,9 @@
"myapex",
],
}
- `)
+ `,
+ dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
+ )
}
func TestNoUpdatableJarsInBootImage(t *testing.T) {
@@ -7148,18 +7163,30 @@
}
t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) {
- preparer := java.FixtureConfigureBootJars("com.android.art.debug:some-art-lib")
- fragment := java.ApexVariantReference{
- Apex: proptools.StringPtr("com.android.art.debug"),
- Module: proptools.StringPtr("art-bootclasspath-fragment"),
+ preparer := android.GroupFixturePreparers(
+ java.FixtureConfigureBootJars("com.android.art.debug:some-art-lib"),
+ java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
+ )
+ fragments := []java.ApexVariantReference{
+ {
+ Apex: proptools.StringPtr("com.android.art.debug"),
+ Module: proptools.StringPtr("art-bootclasspath-fragment"),
+ },
+ {
+ Apex: proptools.StringPtr("some-non-updatable-apex"),
+ Module: proptools.StringPtr("some-non-updatable-fragment"),
+ },
}
- testNoUpdatableJarsInBootImage(t, "", preparer, fragment)
+ testNoUpdatableJarsInBootImage(t, "", preparer, fragments...)
})
t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) {
err := `module "some-art-lib" from updatable apexes \["com.android.art.debug"\] is not allowed in the framework boot image`
// Update the dexpreopt BootJars directly.
- preparer := prepareSetBootJars("com.android.art.debug:some-art-lib")
+ preparer := android.GroupFixturePreparers(
+ prepareSetBootJars("com.android.art.debug:some-art-lib"),
+ java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
+ )
testNoUpdatableJarsInBootImage(t, err, preparer)
})
@@ -7179,12 +7206,15 @@
t.Run("updatable jar from some other apex in the framework boot image => error", func(t *testing.T) {
err := `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the framework boot image`
- preparer := java.FixtureConfigureBootJars("some-updatable-apex:some-updatable-apex-lib")
+ preparer := android.GroupFixturePreparers(
+ java.FixtureConfigureBootJars("some-updatable-apex:some-updatable-apex-lib"),
+ java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
+ )
testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("non-updatable jar from some other apex in the framework boot image => ok", func(t *testing.T) {
- preparer := java.FixtureConfigureBootJars("some-non-updatable-apex:some-non-updatable-apex-lib")
+ preparer := java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib")
fragment := java.ApexVariantReference{
Apex: proptools.StringPtr("some-non-updatable-apex"),
Module: proptools.StringPtr("some-non-updatable-fragment"),
@@ -7212,13 +7242,22 @@
})
t.Run("platform jar in the framework boot image => ok", func(t *testing.T) {
- preparer := java.FixtureConfigureBootJars("platform:some-platform-lib")
- testNoUpdatableJarsInBootImage(t, "", preparer)
+ preparer := android.GroupFixturePreparers(
+ java.FixtureConfigureBootJars("platform:some-platform-lib"),
+ java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
+ )
+ fragments := []java.ApexVariantReference{
+ {
+ Apex: proptools.StringPtr("some-non-updatable-apex"),
+ Module: proptools.StringPtr("some-non-updatable-fragment"),
+ },
+ }
+ testNoUpdatableJarsInBootImage(t, "", preparer, fragments...)
})
}
func TestDexpreoptAccessDexFilesFromPrebuiltApex(t *testing.T) {
- preparer := java.FixtureConfigureBootJars("myapex:libfoo")
+ preparer := java.FixtureConfigureApexBootJars("myapex:libfoo")
t.Run("prebuilt no source", func(t *testing.T) {
fragment := java.ApexVariantReference{
Apex: proptools.StringPtr("myapex"),
@@ -7256,6 +7295,7 @@
name: "libfoo",
jars: ["libfoo.jar"],
apex_available: ["myapex"],
+ permitted_packages: ["libfoo"],
}
`, "", preparer, fragment)
})
@@ -8168,6 +8208,8 @@
java.PrepareForTestWithJavaDefaultModules,
android.PrepareForTestWithAndroidBuildComponents,
android.FixtureWithRootAndroidBp(bp),
+ dexpreopt.FixtureSetApexBootJars("myapex:mybootclasspathlib"),
+ dexpreopt.FixtureSetApexSystemServerJars("myapex:mysystemserverclasspathlib"),
android.FixtureMergeEnv(map[string]string{
"EMMA_INSTRUMENT": "true",
}),
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 6098989..3e19014 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -130,7 +130,8 @@
result := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
// Configure some libraries in the art bootclasspath_fragment and platform_bootclasspath.
- java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo", "platform:bar"),
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz"),
+ java.FixtureConfigureApexBootJars("someapex:foo", "someapex:bar"),
prepareForTestWithArtApex,
java.PrepareForTestWithJavaSdkLibraryFiles,
@@ -642,7 +643,7 @@
prepareForTestWithBootclasspathFragment,
prepareForTestWithMyapex,
// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
- java.FixtureConfigureBootJars("myapex:foo", "myapex:bar"),
+ java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"),
// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
// is disabled.
android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
@@ -893,7 +894,8 @@
prepareForTestWithArtApex,
prepareForTestWithMyapex,
// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
- java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "myapex:foo", "myapex:bar"),
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz"),
+ java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"),
// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
// is disabled.
android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
@@ -1062,7 +1064,8 @@
prepareForTestWithArtApex,
prepareForTestWithMyapex,
// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
- java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "myapex:foo", "myapex:bar"),
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz"),
+ java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"),
// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
// is disabled.
android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
diff --git a/apex/builder.go b/apex/builder.go
index 148f42f..5baa5c0 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -75,7 +75,7 @@
// by default set to (uid/gid/mode) = (1000/1000/0644)
// TODO(b/113082813) make this configurable using config.fs syntax
generateFsConfig = pctx.StaticRule("generateFsConfig", blueprint.RuleParams{
- Command: `( echo '/ 1000 1000 0755' ` +
+ Command: `( set -e; echo '/ 1000 1000 0755' ` +
`&& for i in ${ro_paths}; do echo "/$$i 1000 1000 0644"; done ` +
`&& for i in ${exec_paths}; do echo "/$$i 0 2000 0755"; done ` +
`&& ( tr ' ' '\n' <${out}.apklist | for i in ${apk_paths}; do read apk; echo "/$$i 0 2000 0755"; zipinfo -1 $$apk | sed "s:\(.*\):/$$i/\1 1000 1000 0644:"; done ) ) > ${out}`,
diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go
index 0193127..e2d8465 100644
--- a/apex/classpath_element_test.go
+++ b/apex/classpath_element_test.go
@@ -58,6 +58,7 @@
}),
java.PrepareForTestWithJavaSdkLibraryFiles,
java.FixtureWithLastReleaseApis("foo", "othersdklibrary"),
+ java.FixtureConfigureApexBootJars("myapex:bar"),
android.FixtureWithRootAndroidBp(`
apex {
name: "com.android.art",
@@ -79,6 +80,7 @@
bootclasspath_fragment {
name: "art-bootclasspath-fragment",
+ image_name: "art",
apex_available: [
"com.android.art",
],
@@ -193,6 +195,10 @@
apex: "com.android.art",
module: "art-bootclasspath-fragment",
},
+ {
+ apex: "myapex",
+ module: "mybootclasspath-fragment",
+ },
],
}
`),
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index eaee20d..e0421f6 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -39,7 +39,7 @@
prepareForTestWithMyapex,
java.PrepareForTestWithJavaSdkLibraryFiles,
java.FixtureWithLastReleaseApis("foo"),
- java.FixtureConfigureBootJars("myapex:bar"),
+ java.FixtureConfigureApexBootJars("myapex:bar"),
android.FixtureWithRootAndroidBp(`
platform_bootclasspath {
name: "platform-bootclasspath",
@@ -159,11 +159,12 @@
android.AssertPathsRelativeToTopEquals(t, message, expected, info.FlagsFilesByCategory[category])
}
- android.AssertPathsRelativeToTopEquals(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/stub-flags.csv"}, info.StubFlagsPaths)
android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths)
android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/metadata.csv"}, info.MetadataPaths)
android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/index.csv"}, info.IndexPaths)
- android.AssertPathsRelativeToTopEquals(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/all-flags.csv"}, info.AllFlagsPaths)
+
+ android.AssertArrayString(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/filtered-stub-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop())
+ android.AssertArrayString(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/filtered-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop())
}
func TestPlatformBootclasspathDependencies(t *testing.T) {
@@ -194,6 +195,7 @@
bootclasspath_fragment {
name: "art-bootclasspath-fragment",
+ image_name: "art",
apex_available: [
"com.android.art",
],
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index 537f51d..a64c6f4 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -15,6 +15,7 @@
package apex
import (
+ "android/soong/dexpreopt"
"testing"
"android/soong/android"
@@ -30,6 +31,7 @@
result := android.GroupFixturePreparers(
prepareForTestWithSystemserverclasspathFragment,
prepareForTestWithMyapex,
+ dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
).RunTestWithBp(t, `
apex {
name: "myapex",
@@ -81,6 +83,7 @@
result := android.GroupFixturePreparers(
prepareForTestWithSystemserverclasspathFragment,
prepareForTestWithMyapex,
+ dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
).RunTestWithBp(t, `
apex {
name: "myapex",
diff --git a/bazel/configurability.go b/bazel/configurability.go
index f5f0913..7aaff9a 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -56,7 +56,7 @@
// This is consistently named "conditions_default" to mirror the Soong
// config variable default key in an Android.bp file, although there's no
// integration with Soong config variables (yet).
- conditionsDefault = "conditions_default"
+ ConditionsDefaultConfigKey = "conditions_default"
ConditionsDefaultSelectKey = "//conditions:default"
@@ -72,45 +72,45 @@
// A map of architectures to the Bazel label of the constraint_value
// for the @platforms//cpu:cpu constraint_setting
platformArchMap = map[string]string{
- archArm: "//build/bazel/platforms/arch:arm",
- archArm64: "//build/bazel/platforms/arch:arm64",
- archX86: "//build/bazel/platforms/arch:x86",
- archX86_64: "//build/bazel/platforms/arch:x86_64",
- conditionsDefault: ConditionsDefaultSelectKey, // The default condition of as arch select map.
+ archArm: "//build/bazel/platforms/arch:arm",
+ archArm64: "//build/bazel/platforms/arch:arm64",
+ archX86: "//build/bazel/platforms/arch:x86",
+ archX86_64: "//build/bazel/platforms/arch:x86_64",
+ ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of as arch select map.
}
// A map of target operating systems to the Bazel label of the
// constraint_value for the @platforms//os:os constraint_setting
platformOsMap = map[string]string{
- osAndroid: "//build/bazel/platforms/os:android",
- osDarwin: "//build/bazel/platforms/os:darwin",
- osLinux: "//build/bazel/platforms/os:linux",
- osLinuxMusl: "//build/bazel/platforms/os:linux_musl",
- osLinuxBionic: "//build/bazel/platforms/os:linux_bionic",
- osWindows: "//build/bazel/platforms/os:windows",
- conditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map.
+ osAndroid: "//build/bazel/platforms/os:android",
+ osDarwin: "//build/bazel/platforms/os:darwin",
+ osLinux: "//build/bazel/platforms/os:linux",
+ osLinuxMusl: "//build/bazel/platforms/os:linux_musl",
+ osLinuxBionic: "//build/bazel/platforms/os:linux_bionic",
+ osWindows: "//build/bazel/platforms/os:windows",
+ ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
}
platformBionicMap = map[string]string{
- "bionic": "//build/bazel/platforms/os:bionic",
- conditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map.
+ "bionic": "//build/bazel/platforms/os:bionic",
+ ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
}
platformOsArchMap = map[string]string{
- osArchAndroidArm: "//build/bazel/platforms/os_arch:android_arm",
- osArchAndroidArm64: "//build/bazel/platforms/os_arch:android_arm64",
- osArchAndroidX86: "//build/bazel/platforms/os_arch:android_x86",
- osArchAndroidX86_64: "//build/bazel/platforms/os_arch:android_x86_64",
- osArchDarwinX86_64: "//build/bazel/platforms/os_arch:darwin_x86_64",
- osArchLinuxX86: "//build/bazel/platforms/os_arch:linux_glibc_x86",
- osArchLinuxX86_64: "//build/bazel/platforms/os_arch:linux_glibc_x86_64",
- osArchLinuxMuslX86: "//build/bazel/platforms/os_arch:linux_musl_x86",
- osArchLinuxMuslX86_64: "//build/bazel/platforms/os_arch:linux_musl_x86_64",
- osArchLinuxBionicArm64: "//build/bazel/platforms/os_arch:linux_bionic_arm64",
- osArchLinuxBionicX86_64: "//build/bazel/platforms/os_arch:linux_bionic_x86_64",
- osArchWindowsX86: "//build/bazel/platforms/os_arch:windows_x86",
- osArchWindowsX86_64: "//build/bazel/platforms/os_arch:windows_x86_64",
- conditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map.
+ osArchAndroidArm: "//build/bazel/platforms/os_arch:android_arm",
+ osArchAndroidArm64: "//build/bazel/platforms/os_arch:android_arm64",
+ osArchAndroidX86: "//build/bazel/platforms/os_arch:android_x86",
+ osArchAndroidX86_64: "//build/bazel/platforms/os_arch:android_x86_64",
+ osArchDarwinX86_64: "//build/bazel/platforms/os_arch:darwin_x86_64",
+ osArchLinuxX86: "//build/bazel/platforms/os_arch:linux_glibc_x86",
+ osArchLinuxX86_64: "//build/bazel/platforms/os_arch:linux_glibc_x86_64",
+ osArchLinuxMuslX86: "//build/bazel/platforms/os_arch:linux_musl_x86",
+ osArchLinuxMuslX86_64: "//build/bazel/platforms/os_arch:linux_musl_x86_64",
+ osArchLinuxBionicArm64: "//build/bazel/platforms/os_arch:linux_bionic_arm64",
+ osArchLinuxBionicX86_64: "//build/bazel/platforms/os_arch:linux_bionic_x86_64",
+ osArchWindowsX86: "//build/bazel/platforms/os_arch:windows_x86",
+ osArchWindowsX86_64: "//build/bazel/platforms/os_arch:windows_x86_64",
+ ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
}
)
@@ -181,7 +181,7 @@
case bionic:
return platformBionicMap[config]
case productVariables:
- if config == conditionsDefault {
+ if config == ConditionsDefaultConfigKey {
return ConditionsDefaultSelectKey
}
return fmt.Sprintf("%s:%s", productVariableBazelPackage, strings.ToLower(config))
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index 52c6c2f..131f0ec 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -6,8 +6,9 @@
)
var (
- GetOutputFiles = &getOutputFilesRequestType{}
- GetCcInfo = &getCcInfoType{}
+ GetOutputFiles = &getOutputFilesRequestType{}
+ GetPythonBinary = &getPythonBinaryRequestType{}
+ GetCcInfo = &getCcInfoType{}
)
type CcInfo struct {
@@ -28,6 +29,8 @@
type getOutputFilesRequestType struct{}
+type getPythonBinaryRequestType struct{}
+
// Name returns a string name for this request type. Such request type names must be unique,
// and must only consist of alphanumeric characters.
func (g getOutputFilesRequestType) Name() string {
@@ -53,6 +56,31 @@
return splitOrEmpty(rawString, ", ")
}
+// Name returns a string name for this request type. Such request type names must be unique,
+// and must only consist of alphanumeric characters.
+func (g getPythonBinaryRequestType) Name() string {
+ return "getPythonBinary"
+}
+
+// StarlarkFunctionBody returns a starlark function body to process this request type.
+// The returned string is the body of a Starlark function which obtains
+// all request-relevant information about a target and returns a string containing
+// this information.
+// The function should have the following properties:
+// - `target` is the only parameter to this function (a configured target).
+// - The return value must be a string.
+// - The function body should not be indented outside of its own scope.
+func (g getPythonBinaryRequestType) StarlarkFunctionBody() string {
+ return "return providers(target)['FilesToRunProvider'].executable.path"
+}
+
+// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
+// The given rawString must correspond to the string output which was created by evaluating the
+// Starlark given in StarlarkFunctionBody.
+func (g getPythonBinaryRequestType) ParseResult(rawString string) string {
+ return rawString
+}
+
type getCcInfoType struct{}
// Name returns a string name for this request type. Such request type names must be unique,
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 035544e..49019ab 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -37,6 +37,31 @@
}
}
+func TestGetPythonBinaryParseResults(t *testing.T) {
+ testCases := []struct {
+ description string
+ input string
+ expectedOutput string
+ }{
+ {
+ description: "no result",
+ input: "",
+ expectedOutput: "",
+ },
+ {
+ description: "one result",
+ input: "test",
+ expectedOutput: "test",
+ },
+ }
+ for _, tc := range testCases {
+ actualOutput := GetPythonBinary.ParseResult(tc.input)
+ if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+ t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
+ }
+ }
+}
+
func TestGetCcInfoParseResults(t *testing.T) {
testCases := []struct {
description string
diff --git a/bazel/properties.go b/bazel/properties.go
index 2656bad..1a846ba 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -69,6 +69,23 @@
Excludes []Label
}
+func (ll *LabelList) Equals(other LabelList) bool {
+ if len(ll.Includes) != len(other.Includes) || len(ll.Excludes) != len(other.Excludes) {
+ return false
+ }
+ for i, _ := range ll.Includes {
+ if ll.Includes[i] != other.Includes[i] {
+ return false
+ }
+ }
+ for i, _ := range ll.Excludes {
+ if ll.Excludes[i] != other.Excludes[i] {
+ return false
+ }
+ }
+ return true
+}
+
func (ll *LabelList) IsNil() bool {
return ll.Includes == nil && ll.Excludes == nil
}
@@ -446,7 +463,7 @@
// HasConfigurableValues returns whether there are configurable values within this set of selects.
func (ll labelListSelectValues) HasConfigurableValues() bool {
for _, v := range ll {
- if len(v.Includes) > 0 {
+ if v.Includes != nil {
return true
}
}
@@ -462,6 +479,13 @@
// The configured attribute label list Values. Optional
// a map of independent configurability axes
ConfigurableValues configurableLabelLists
+
+ // If true, differentiate between "nil" and "empty" list. nil means that
+ // this attribute should not be specified at all, and "empty" means that
+ // the attribute should be explicitly specified as an empty list.
+ // This mode facilitates use of attribute defaults: an empty list should
+ // override the default.
+ ForceSpecifyEmptyList bool
}
type configurableLabelLists map[ConfigurationAxis]labelListSelectValues
@@ -546,6 +570,9 @@
// Append all values, including os and arch specific ones, from another
// LabelListAttribute to this LabelListAttribute.
func (lla *LabelListAttribute) Append(other LabelListAttribute) {
+ if lla.ForceSpecifyEmptyList && !other.Value.IsNil() {
+ lla.Value.Includes = []Label{}
+ }
lla.Value.Append(other.Value)
if lla.ConfigurableValues == nil {
lla.ConfigurableValues = make(configurableLabelLists)
@@ -595,7 +622,7 @@
// Now that the Value list is finalized for this axis, compare it with the original
// list, and put the difference into the default condition for the axis.
- lla.ConfigurableValues[axis][conditionsDefault] = SubtractBazelLabelList(baseLabels, lla.Value)
+ lla.ConfigurableValues[axis][ConditionsDefaultConfigKey] = SubtractBazelLabelList(baseLabels, lla.Value)
// if everything ends up without includes, just delete the axis
if !lla.ConfigurableValues[axis].HasConfigurableValues() {
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 9ec637a..78e3a74 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -39,6 +39,7 @@
"cc_library_static_conversion_test.go",
"cc_object_conversion_test.go",
"conversion_test.go",
+ "performance_test.go",
"prebuilt_etc_conversion_test.go",
"python_binary_conversion_test.go",
"sh_conversion_test.go",
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index e5dbda6..eb3a73f 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -334,9 +334,7 @@
config := android.TestConfig(buildDir, nil, testCase.bp, nil)
ctx := android.NewTestContext(config)
- ctx.RegisterModuleType("custom", customModuleFactory)
- ctx.RegisterBp2BuildMutator("custom", customBp2BuildMutator)
- ctx.RegisterForBazelConversion()
+ registerCustomModuleForBp2buildConversion(ctx)
_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
if errored(t, "", errs) {
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 204c519..9e0c0a1 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -85,6 +85,7 @@
"soong_module_variant": attr.string(),
"soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
"arch_paths": attr.string_list(),
+ "arch_paths_exclude": attr.string_list(),
# bazel_module start
# "label": attr.string(),
# "bp2build_available": attr.bool(),
@@ -114,6 +115,7 @@
"soong_module_variant": attr.string(),
"soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
"arch_paths": attr.string_list(),
+ "arch_paths_exclude": attr.string_list(),
"bool_prop": attr.bool(),
"bool_ptr_prop": attr.bool(),
"int64_ptr_prop": attr.int(),
@@ -139,6 +141,7 @@
"soong_module_variant": attr.string(),
"soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
"arch_paths": attr.string_list(),
+ "arch_paths_exclude": attr.string_list(),
"bool_prop": attr.bool(),
"bool_ptr_prop": attr.bool(),
"int64_ptr_prop": attr.int(),
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 8dcba55..bff192f 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -1454,3 +1454,213 @@
)`},
})
}
+
+func TestCcLibrary_SystemSharedLibsRootEmpty(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library system_shared_libs empty at root",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ blueprint: soongCcLibraryPreamble + `
+cc_library {
+ name: "root_empty",
+ system_shared_libs: [],
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "root_empty",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ system_dynamic_deps = [],
+)`},
+ })
+}
+
+func TestCcLibrary_SystemSharedLibsStaticEmpty(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library system_shared_libs empty for static variant",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ blueprint: soongCcLibraryPreamble + `
+cc_library {
+ name: "static_empty",
+ static: {
+ system_shared_libs: [],
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "static_empty",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ static = {
+ "system_dynamic_deps": [],
+ },
+)`},
+ })
+}
+
+func TestCcLibrary_SystemSharedLibsSharedEmpty(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library system_shared_libs empty for shared variant",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ blueprint: soongCcLibraryPreamble + `
+cc_library {
+ name: "shared_empty",
+ shared: {
+ system_shared_libs: [],
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "shared_empty",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ shared = {
+ "system_dynamic_deps": [],
+ },
+)`},
+ })
+}
+
+func TestCcLibrary_SystemSharedLibsSharedBionicEmpty(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library system_shared_libs empty for shared, bionic variant",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ blueprint: soongCcLibraryPreamble + `
+cc_library {
+ name: "shared_empty",
+ target: {
+ bionic: {
+ shared: {
+ system_shared_libs: [],
+ }
+ }
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "shared_empty",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ shared = {
+ "system_dynamic_deps": [],
+ },
+)`},
+ })
+}
+
+func TestCcLibrary_SystemSharedLibsLinuxBionicEmpty(t *testing.T) {
+ // Note that this behavior is technically incorrect (it's a simplification).
+ // The correct behavior would be if bp2build wrote `system_dynamic_deps = []`
+ // only for linux_bionic, but `android` had `["libc", "libdl", "libm"].
+ // b/195791252 tracks the fix.
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library system_shared_libs empty for linux_bionic variant",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ blueprint: soongCcLibraryPreamble + `
+cc_library {
+ name: "target_linux_bionic_empty",
+ target: {
+ linux_bionic: {
+ system_shared_libs: [],
+ },
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "target_linux_bionic_empty",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ system_dynamic_deps = [],
+)`},
+ })
+}
+
+func TestCcLibrary_SystemSharedLibsBionicEmpty(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library system_shared_libs empty for bionic variant",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ blueprint: soongCcLibraryPreamble + `
+cc_library {
+ name: "target_bionic_empty",
+ target: {
+ bionic: {
+ system_shared_libs: [],
+ },
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "target_bionic_empty",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ system_dynamic_deps = [],
+)`},
+ })
+}
+
+func TestCcLibrary_SystemSharedLibsSharedAndRoot(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library system_shared_libs set for shared and root",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ blueprint: soongCcLibraryPreamble + `
+cc_library {name: "libc"}
+cc_library {name: "libm"}
+
+cc_library {
+ name: "foo",
+ system_shared_libs: ["libc"],
+ shared: {
+ system_shared_libs: ["libm"],
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "foo",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ shared = {
+ "system_dynamic_deps": [":libm"],
+ },
+ system_dynamic_deps = [":libc"],
+)`, `cc_library(
+ name = "libc",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+)`, `cc_library(
+ name = "libm",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+)`},
+ })
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 1dc6713..d9145f6 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -73,6 +73,8 @@
ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
+ // Required for system_shared_libs dependencies.
+ ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
}
func runCcLibraryStaticTestCase(t *testing.T, tc bp2buildTestCase) {
@@ -1427,3 +1429,185 @@
)`},
})
}
+
+func TestStaticLibrary_SystemSharedLibsRootEmpty(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static system_shared_lib empty root",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_library_static {
+ name: "root_empty",
+ system_shared_libs: [],
+}
+`,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "root_empty",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ linkstatic = True,
+ system_dynamic_deps = [],
+)`},
+ })
+}
+
+func TestStaticLibrary_SystemSharedLibsStaticEmpty(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static system_shared_lib empty static default",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_defaults {
+ name: "static_empty_defaults",
+ static: {
+ system_shared_libs: [],
+ },
+}
+cc_library_static {
+ name: "static_empty",
+ defaults: ["static_empty_defaults"],
+}
+`,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "static_empty",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ linkstatic = True,
+ system_dynamic_deps = [],
+)`},
+ })
+}
+
+func TestStaticLibrary_SystemSharedLibsBionicEmpty(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static system_shared_lib empty for bionic variant",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_library_static {
+ name: "target_bionic_empty",
+ target: {
+ bionic: {
+ system_shared_libs: [],
+ },
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "target_bionic_empty",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ linkstatic = True,
+ system_dynamic_deps = [],
+)`},
+ })
+}
+
+func TestStaticLibrary_SystemSharedLibsLinuxBionicEmpty(t *testing.T) {
+ // Note that this behavior is technically incorrect (it's a simplification).
+ // The correct behavior would be if bp2build wrote `system_dynamic_deps = []`
+ // only for linux_bionic, but `android` had `["libc", "libdl", "libm"].
+ // b/195791252 tracks the fix.
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static system_shared_lib empty for linux_bionic variant",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_library_static {
+ name: "target_linux_bionic_empty",
+ target: {
+ linux_bionic: {
+ system_shared_libs: [],
+ },
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "target_linux_bionic_empty",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ linkstatic = True,
+ system_dynamic_deps = [],
+)`},
+ })
+}
+
+func TestStaticLibrary_SystemSharedLibsBionic(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static system_shared_libs set for bionic variant",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_library{name: "libc"}
+
+cc_library_static {
+ name: "target_bionic",
+ target: {
+ bionic: {
+ system_shared_libs: ["libc"],
+ },
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "target_bionic",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ linkstatic = True,
+ system_dynamic_deps = select({
+ "//build/bazel/platforms/os:bionic": [":libc"],
+ "//conditions:default": [],
+ }),
+)`},
+ })
+}
+
+func TestStaticLibrary_SystemSharedLibsLinuxRootAndLinuxBionic(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static system_shared_libs set for root and linux_bionic variant",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_library{name: "libc"}
+cc_library{name: "libm"}
+
+cc_library_static {
+ name: "target_linux_bionic",
+ system_shared_libs: ["libc"],
+ target: {
+ linux_bionic: {
+ system_shared_libs: ["libm"],
+ },
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "target_linux_bionic",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ linkstatic = True,
+ system_dynamic_deps = [":libc"] + select({
+ "//build/bazel/platforms/os:linux_bionic": [":libm"],
+ "//conditions:default": [],
+ }),
+)`},
+ })
+}
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index c8105eb..005f13d 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -82,7 +82,12 @@
continue
}
archSelects := map[string]reflect.Value{}
+ defaultVal := configToLabels[bazel.ConditionsDefaultConfigKey]
for config, labels := range configToLabels {
+ // Omit any entries in the map which match the default value, for brevity.
+ if config != bazel.ConditionsDefaultConfigKey && labels.Equals(defaultVal) {
+ continue
+ }
selectKey := axis.SelectKey(config)
if use, value := labelListSelectValue(selectKey, labels); use {
archSelects[selectKey] = value
@@ -118,6 +123,8 @@
var value reflect.Value
var configurableAttrs []selects
var defaultSelectValue *string
+ // If true, print the default attribute value, even if the attribute is zero.
+ shouldPrintDefault := false
switch list := v.(type) {
case bazel.StringListAttribute:
value, configurableAttrs = getStringListValues(list)
@@ -125,6 +132,9 @@
case bazel.LabelListAttribute:
value, configurableAttrs = getLabelListValues(list)
defaultSelectValue = &emptyBazelList
+ if list.ForceSpecifyEmptyList && (!value.IsNil() || list.HasConfigurableValues()) {
+ shouldPrintDefault = true
+ }
case bazel.LabelAttribute:
value, configurableAttrs = getLabelValue(list)
defaultSelectValue = &bazelNone
@@ -166,6 +176,9 @@
}
}
+ if ret == "" && shouldPrintDefault {
+ return *defaultSelectValue, nil
+ }
return ret, nil
}
diff --git a/bp2build/performance_test.go b/bp2build/performance_test.go
new file mode 100644
index 0000000..3283952
--- /dev/null
+++ b/bp2build/performance_test.go
@@ -0,0 +1,175 @@
+// 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
+
+// to run the benchmarks in this file, you must run go test with the -bench.
+// The benchmarked portion will run for the specified time (can be set via -benchtime)
+// This can mean if you are benchmarking a faster portion of a larger operation, it will take
+// longer.
+// If you are seeing a small number of iterations for a specific run, the data is less reliable, to
+// run for longer, set -benchtime to a larger value.
+
+import (
+ "android/soong/android"
+ "fmt"
+ "math"
+ "strings"
+ "testing"
+)
+
+func genCustomModule(i int, convert bool) string {
+ var conversionString string
+ if convert {
+ conversionString = `bazel_module: { bp2build_available: true },`
+ }
+ return fmt.Sprintf(`
+custom {
+ name: "arch_paths_%[1]d",
+ string_list_prop: ["\t", "\n"],
+ string_prop: "a\t\n\r",
+ arch_paths: ["outer", ":outer_dep_%[1]d"],
+ arch: {
+ x86: {
+ arch_paths: ["abc", ":x86_dep_%[1]d"],
+ },
+ x86_64: {
+ arch_paths: ["64bit"],
+ arch_paths_exclude: ["outer"],
+ },
+ },
+ %[2]s
+}
+
+custom {
+ name: "outer_dep_%[1]d",
+ %[2]s
+}
+
+custom {
+ name: "x86_dep_%[1]d",
+ %[2]s
+}
+`, i, conversionString)
+}
+
+func genCustomModuleBp(pctConverted float64) string {
+ modules := 100
+
+ bp := make([]string, 0, modules)
+ toConvert := int(math.Round(float64(modules) * pctConverted))
+
+ for i := 0; i < modules; i++ {
+ bp = append(bp, genCustomModule(i, i < toConvert))
+ }
+ return strings.Join(bp, "\n\n")
+}
+
+var pctToConvert = []float64{0.0, 0.01, 0.05, 0.10, 0.25, 0.5, 0.75, 1.0}
+
+func BenchmarkManyModulesFull(b *testing.B) {
+ dir := "."
+ for _, tcSize := range pctToConvert {
+
+ b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ b.StopTimer()
+ // setup we don't want to measure
+ config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil)
+ ctx := android.NewTestContext(config)
+
+ registerCustomModuleForBp2buildConversion(ctx)
+ codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+
+ b.StartTimer()
+ _, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+ if len(errs) > 0 {
+ b.Fatalf("Unexpected errors: %s", errs)
+ }
+
+ _, errs = ctx.ResolveDependencies(config)
+ if len(errs) > 0 {
+ b.Fatalf("Unexpected errors: %s", errs)
+ }
+
+ generateBazelTargetsForDir(codegenCtx, dir)
+ b.StopTimer()
+ }
+ })
+ }
+}
+
+func BenchmarkManyModulesResolveDependencies(b *testing.B) {
+ dir := "."
+ for _, tcSize := range pctToConvert {
+
+ b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ b.StopTimer()
+ // setup we don't want to measure
+ config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil)
+ ctx := android.NewTestContext(config)
+
+ registerCustomModuleForBp2buildConversion(ctx)
+ codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+
+ _, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+ if len(errs) > 0 {
+ b.Fatalf("Unexpected errors: %s", errs)
+ }
+
+ b.StartTimer()
+ _, errs = ctx.ResolveDependencies(config)
+ b.StopTimer()
+ if len(errs) > 0 {
+ b.Fatalf("Unexpected errors: %s", errs)
+ }
+
+ generateBazelTargetsForDir(codegenCtx, dir)
+ }
+ })
+ }
+}
+
+func BenchmarkManyModulesGenerateBazelTargetsForDir(b *testing.B) {
+ dir := "."
+ for _, tcSize := range pctToConvert {
+
+ b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) {
+ for n := 0; n < b.N; n++ {
+ b.StopTimer()
+ // setup we don't want to measure
+ config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil)
+ ctx := android.NewTestContext(config)
+
+ registerCustomModuleForBp2buildConversion(ctx)
+ codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+
+ _, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+ if len(errs) > 0 {
+ b.Fatalf("Unexpected errors: %s", errs)
+ }
+
+ _, errs = ctx.ResolveDependencies(config)
+ if len(errs) > 0 {
+ b.Fatalf("Unexpected errors: %s", errs)
+ }
+
+ b.StartTimer()
+ generateBazelTargetsForDir(codegenCtx, dir)
+ b.StopTimer()
+ }
+ })
+ }
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index f3cd7f0..faf1a44 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -33,7 +33,8 @@
Nested_props nestedProps
Nested_props_ptr *nestedProps
- Arch_paths []string `android:"path,arch_variant"`
+ Arch_paths []string `android:"path,arch_variant"`
+ Arch_paths_exclude []string `android:"path,arch_variant"`
}
type customModule struct {
@@ -155,16 +156,18 @@
return
}
- paths := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.props.Arch_paths))
+ paths := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, m.props.Arch_paths, m.props.Arch_paths_exclude))
for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
for config, props := range configToProps {
if archProps, ok := props.(*customProps); ok && archProps.Arch_paths != nil {
- paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, archProps.Arch_paths))
+ paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, archProps.Arch_paths, archProps.Arch_paths_exclude))
}
}
}
+ paths.ResolveExcludes()
+
attrs := &customBazelModuleAttributes{
String_prop: m.props.String_prop,
String_list_prop: m.props.String_list_prop,
@@ -216,3 +219,9 @@
buildFileToTargets, _, _ := GenerateBazelTargets(codegenCtx, false)
return buildFileToTargets[dir]
}
+
+func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) {
+ ctx.RegisterModuleType("custom", customModuleFactory)
+ ctx.RegisterBp2BuildMutator("custom", customBp2BuildMutator)
+ ctx.RegisterForBazelConversion()
+}
diff --git a/cc/Android.bp b/cc/Android.bp
index 164d32b..bff2761 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -13,6 +13,7 @@
"soong-bazel",
"soong-cc-config",
"soong-etc",
+ "soong-fuzz",
"soong-genrule",
"soong-snapshot",
"soong-tradefed",
@@ -59,7 +60,6 @@
"binary.go",
"binary_sdk_member.go",
"fuzz.go",
- "fuzz_common.go",
"library.go",
"library_headers.go",
"library_sdk_member.go",
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 68afd0d..1706d72 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -35,6 +35,8 @@
Static_deps bazel.LabelListAttribute
Dynamic_deps bazel.LabelListAttribute
Whole_archive_deps bazel.LabelListAttribute
+
+ System_dynamic_deps bazel.LabelListAttribute
}
func groupSrcsByExtension(ctx android.TopDownMutatorContext, srcs bazel.LabelListAttribute) (cppSrcs, cSrcs, asSrcs bazel.LabelListAttribute) {
@@ -137,12 +139,19 @@
props = lib.SharedProperties.Shared
}
+ system_dynamic_deps := bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, props.System_shared_libs))
+ system_dynamic_deps.ForceSpecifyEmptyList = true
+ if system_dynamic_deps.IsEmpty() && props.System_shared_libs != nil {
+ system_dynamic_deps.Value.Includes = []bazel.Label{}
+ }
+
attrs := staticOrSharedAttributes{
- Copts: bazel.StringListAttribute{Value: props.Cflags},
- Srcs: bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, props.Srcs)),
- Static_deps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, props.Static_libs)),
- Dynamic_deps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, append(props.Shared_libs, props.System_shared_libs...))),
- Whole_archive_deps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleWholeDeps(ctx, props.Whole_static_libs)),
+ Copts: bazel.StringListAttribute{Value: props.Cflags},
+ Srcs: bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, props.Srcs)),
+ Static_deps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, props.Static_libs)),
+ Dynamic_deps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, props.Shared_libs)),
+ Whole_archive_deps: bazel.MakeLabelListAttribute(android.BazelLabelForModuleWholeDeps(ctx, props.Whole_static_libs)),
+ System_dynamic_deps: system_dynamic_deps,
}
setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
@@ -151,6 +160,7 @@
attrs.Static_deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, props.Static_libs))
attrs.Dynamic_deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, props.Shared_libs))
attrs.Whole_archive_deps.SetSelectValue(axis, config, android.BazelLabelForModuleWholeDeps(ctx, props.Whole_static_libs))
+ attrs.System_dynamic_deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, props.System_shared_libs))
}
if isStatic {
@@ -230,6 +240,8 @@
// C++ options and sources
cppFlags bazel.StringListAttribute
srcs bazel.LabelListAttribute
+
+ rtti bazel.BoolAttribute
}
// bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes.
@@ -239,6 +251,7 @@
var asFlags bazel.StringListAttribute
var conlyFlags bazel.StringListAttribute
var cppFlags bazel.StringListAttribute
+ var rtti bazel.BoolAttribute
// Creates the -I flags for a directory, while making the directory relative
// to the exec root for Bazel to work.
@@ -292,6 +305,7 @@
asFlags.Value = parseCommandLineFlags(baseCompilerProps.Asflags)
conlyFlags.Value = parseCommandLineFlags(baseCompilerProps.Conlyflags)
cppFlags.Value = parseCommandLineFlags(baseCompilerProps.Cppflags)
+ rtti.Value = baseCompilerProps.Rtti
for _, dir := range parseLocalIncludeDirs(baseCompilerProps) {
copts.Value = append(copts.Value, includeFlags(dir)...)
@@ -335,6 +349,7 @@
asFlags.SetSelectValue(axis, config, archVariantAsflags)
conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(baseCompilerProps.Conlyflags))
cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(baseCompilerProps.Cppflags))
+ rtti.SetSelectValue(axis, config, baseCompilerProps.Rtti)
}
}
}
@@ -370,6 +385,7 @@
cSrcs: cSrcs,
conlyFlags: conlyFlags,
cppFlags: cppFlags,
+ rtti: rtti,
}
}
@@ -377,6 +393,7 @@
type linkerAttributes struct {
deps bazel.LabelListAttribute
dynamicDeps bazel.LabelListAttribute
+ systemDynamicDeps bazel.LabelListAttribute
wholeArchiveDeps bazel.LabelListAttribute
exportedDeps bazel.LabelListAttribute
useLibcrt bazel.BoolAttribute
@@ -406,6 +423,7 @@
var exportedDeps bazel.LabelListAttribute
var dynamicDeps bazel.LabelListAttribute
var wholeArchiveDeps bazel.LabelListAttribute
+ var systemSharedDeps bazel.LabelListAttribute
var linkopts bazel.StringListAttribute
var versionScript bazel.LabelAttribute
var useLibcrt bazel.BoolAttribute
@@ -445,9 +463,16 @@
staticDeps.Value = android.BazelLabelForModuleDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs)
wholeArchiveLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs)
wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleWholeDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs))
- // TODO(b/186024507): Handle system_shared_libs as its own attribute, so that the appropriate default
- // may be supported.
- sharedLibs := android.FirstUniqueStrings(append(baseLinkerProps.Shared_libs, baseLinkerProps.System_shared_libs...))
+
+ systemSharedLibs := android.FirstUniqueStrings(baseLinkerProps.System_shared_libs)
+ systemSharedDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, systemSharedLibs))
+ systemSharedDeps.ForceSpecifyEmptyList = true
+ if systemSharedDeps.Value.IsNil() && baseLinkerProps.System_shared_libs != nil {
+ systemSharedDeps.Value.Includes = []bazel.Label{}
+ }
+
+ sharedLibs := android.FirstUniqueStrings(baseLinkerProps.Shared_libs)
+
dynamicDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs))
headerLibs := android.FirstUniqueStrings(baseLinkerProps.Header_libs)
@@ -474,7 +499,14 @@
staticDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs))
wholeArchiveLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs)
wholeArchiveDeps.SetSelectValue(axis, config, android.BazelLabelForModuleWholeDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs))
- sharedLibs := android.FirstUniqueStrings(append(baseLinkerProps.Shared_libs, baseLinkerProps.System_shared_libs...))
+
+ systemSharedLibs := android.FirstUniqueStrings(baseLinkerProps.System_shared_libs)
+ if len(systemSharedLibs) == 0 && baseLinkerProps.System_shared_libs != nil {
+ systemSharedLibs = baseLinkerProps.System_shared_libs
+ }
+ systemSharedDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, systemSharedLibs))
+
+ sharedLibs := android.FirstUniqueStrings(baseLinkerProps.Shared_libs)
dynamicDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs))
headerLibs := android.FirstUniqueStrings(baseLinkerProps.Header_libs)
@@ -550,13 +582,14 @@
headerDeps.Append(staticDeps)
return linkerAttributes{
- deps: headerDeps,
- exportedDeps: exportedDeps,
- dynamicDeps: dynamicDeps,
- wholeArchiveDeps: wholeArchiveDeps,
- linkopts: linkopts,
- useLibcrt: useLibcrt,
- versionScript: versionScript,
+ deps: headerDeps,
+ exportedDeps: exportedDeps,
+ dynamicDeps: dynamicDeps,
+ systemDynamicDeps: systemSharedDeps,
+ wholeArchiveDeps: wholeArchiveDeps,
+ linkopts: linkopts,
+ useLibcrt: useLibcrt,
+ versionScript: versionScript,
// Strip properties
stripKeepSymbols: stripKeepSymbols,
diff --git a/cc/cc.go b/cc/cc.go
index 39d89e5..f65af30 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -29,6 +29,7 @@
"android/soong/android"
"android/soong/cc/config"
+ "android/soong/fuzz"
"android/soong/genrule"
)
@@ -589,17 +590,6 @@
installInRoot() bool
}
-// bazelHandler is the interface for a helper object related to deferring to Bazel for
-// processing a module (during Bazel mixed builds). Individual module types should define
-// their own bazel handler if they support deferring to Bazel.
-type bazelHandler interface {
- // Issue query to Bazel to retrieve information about Bazel's view of the current module.
- // If Bazel returns this information, set module properties on the current module to reflect
- // the returned information.
- // Returns true if information was available from Bazel, false if bazel invocation still needs to occur.
- generateBazelBuildActions(ctx android.ModuleContext, label string) bool
-}
-
type xref interface {
XrefCcFiles() android.Paths
}
@@ -773,7 +763,7 @@
// members of the cc.Module to this decorator. Thus, a cc_binary module has custom linker and
// installer logic.
type Module struct {
- FuzzModule
+ fuzz.FuzzModule
android.SdkBase
android.BazelModuleBase
@@ -796,7 +786,7 @@
compiler compiler
linker linker
installer installer
- bazelHandler bazelHandler
+ bazelHandler android.BazelHandler
features []feature
stl *stl
@@ -1696,7 +1686,7 @@
bazelModuleLabel := c.GetBazelLabel(actx, c)
bazelActionsUsed := false
if c.MixedBuildsEnabled(actx) && c.bazelHandler != nil {
- bazelActionsUsed = c.bazelHandler.generateBazelBuildActions(actx, bazelModuleLabel)
+ bazelActionsUsed = c.bazelHandler.GenerateBazelBuildActions(actx, bazelModuleLabel)
}
return bazelActionsUsed
}
@@ -3426,7 +3416,7 @@
&TestProperties{},
&TestBinaryProperties{},
&BenchmarkProperties{},
- &FuzzProperties{},
+ &fuzz.FuzzProperties{},
&StlProperties{},
&SanitizeProperties{},
&StripProperties{},
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 812a245..2d6bcb8 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -96,31 +96,25 @@
pctx.SourcePathVariable("Arm64GccRoot",
"prebuilts/gcc/${HostPrebuiltTag}/aarch64/aarch64-linux-android-${arm64GccVersion}")
- pctx.StaticVariable("Arm64Ldflags", strings.Join(arm64Ldflags, " "))
- pctx.StaticVariable("Arm64Lldflags", strings.Join(arm64Lldflags, " "))
+ exportStringListStaticVariable("Arm64Ldflags", arm64Ldflags)
+ exportStringListStaticVariable("Arm64Lldflags", arm64Lldflags)
- pctx.StaticVariable("Arm64Cflags", strings.Join(arm64Cflags, " "))
- pctx.StaticVariable("Arm64Cppflags", strings.Join(arm64Cppflags, " "))
+ exportStringListStaticVariable("Arm64Cflags", arm64Cflags)
+ exportStringListStaticVariable("Arm64Cppflags", arm64Cppflags)
+
+ exportedStringListDictVars.Set("Arm64ArchVariantCflags", arm64ArchVariantCflags)
+ exportedStringListDictVars.Set("Arm64CpuVariantCflags", arm64CpuVariantCflags)
pctx.StaticVariable("Arm64Armv8ACflags", strings.Join(arm64ArchVariantCflags["armv8-a"], " "))
pctx.StaticVariable("Arm64Armv8ABranchProtCflags", strings.Join(arm64ArchVariantCflags["armv8-a-branchprot"], " "))
pctx.StaticVariable("Arm64Armv82ACflags", strings.Join(arm64ArchVariantCflags["armv8-2a"], " "))
pctx.StaticVariable("Arm64Armv82ADotprodCflags", strings.Join(arm64ArchVariantCflags["armv8-2a-dotprod"], " "))
- pctx.StaticVariable("Arm64CortexA53Cflags",
- strings.Join(arm64CpuVariantCflags["cortex-a53"], " "))
-
- pctx.StaticVariable("Arm64CortexA55Cflags",
- strings.Join(arm64CpuVariantCflags["cortex-a55"], " "))
-
- pctx.StaticVariable("Arm64KryoCflags",
- strings.Join(arm64CpuVariantCflags["kryo"], " "))
-
- pctx.StaticVariable("Arm64ExynosM1Cflags",
- strings.Join(arm64CpuVariantCflags["exynos-m1"], " "))
-
- pctx.StaticVariable("Arm64ExynosM2Cflags",
- strings.Join(arm64CpuVariantCflags["exynos-m2"], " "))
+ pctx.StaticVariable("Arm64CortexA53Cflags", strings.Join(arm64CpuVariantCflags["cortex-a53"], " "))
+ pctx.StaticVariable("Arm64CortexA55Cflags", strings.Join(arm64CpuVariantCflags["cortex-a55"], " "))
+ pctx.StaticVariable("Arm64KryoCflags", strings.Join(arm64CpuVariantCflags["kryo"], " "))
+ pctx.StaticVariable("Arm64ExynosM1Cflags", strings.Join(arm64CpuVariantCflags["exynos-m1"], " "))
+ pctx.StaticVariable("Arm64ExynosM2Cflags", strings.Join(arm64CpuVariantCflags["exynos-m2"], " "))
}
var (
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index b5afe40..0fe5e68 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -188,6 +188,9 @@
exportStringListStaticVariable("ArmArmCflags", armArmCflags)
exportStringListStaticVariable("ArmThumbCflags", armThumbCflags)
+ exportedStringListDictVars.Set("ArmArchVariantCflags", armArchVariantCflags)
+ exportedStringListDictVars.Set("ArmCpuVariantCflags", armCpuVariantCflags)
+
// Clang arch variant cflags
exportStringListStaticVariable("ArmArmv7ACflags", armArchVariantCflags["armv7-a"])
exportStringListStaticVariable("ArmArmv7ANeonCflags", armArchVariantCflags["armv7-a-neon"])
diff --git a/cc/config/bp2build.go b/cc/config/bp2build.go
index e7e94a8..d19f5ac 100644
--- a/cc/config/bp2build.go
+++ b/cc/config/bp2build.go
@@ -15,98 +15,182 @@
package config
import (
- "android/soong/android"
"fmt"
"regexp"
+ "sort"
"strings"
)
+const (
+ bazelIndent = 4
+)
+
+type bazelVarExporter interface {
+ asBazel(exportedStringVariables, exportedStringListVariables) []bazelConstant
+}
+
// Helpers for exporting cc configuration information to Bazel.
var (
// Map containing toolchain variables that are independent of the
// environment variables of the build.
- exportedStringListVars = exportedStringListVariables{}
- exportedStringVars = exportedStringVariables{}
+ exportedStringListVars = exportedStringListVariables{}
+ exportedStringVars = exportedStringVariables{}
+ exportedStringListDictVars = exportedStringListDictVariables{}
)
+// Ensure that string s has no invalid characters to be generated into the bzl file.
+func validateCharacters(s string) string {
+ for _, c := range []string{`\n`, `"`, `\`} {
+ if strings.Contains(s, c) {
+ panic(fmt.Errorf("%s contains illegal character %s", s, c))
+ }
+ }
+ return s
+}
+
+type bazelConstant struct {
+ variableName string
+ internalDefinition string
+}
+
type exportedStringVariables map[string]string
-type exportedStringListVariables map[string][]string
func (m exportedStringVariables) Set(k string, v string) {
m[k] = v
}
+func bazelIndention(level int) string {
+ return strings.Repeat(" ", level*bazelIndent)
+}
+
+func printBazelList(items []string, indentLevel int) string {
+ list := make([]string, 0, len(items)+2)
+ list = append(list, "[")
+ innerIndent := bazelIndention(indentLevel + 1)
+ for _, item := range items {
+ list = append(list, fmt.Sprintf(`%s"%s",`, innerIndent, item))
+ }
+ list = append(list, bazelIndention(indentLevel)+"]")
+ return strings.Join(list, "\n")
+}
+
+func (m exportedStringVariables) asBazel(stringScope exportedStringVariables, stringListScope exportedStringListVariables) []bazelConstant {
+ ret := make([]bazelConstant, 0, len(m))
+ for k, variableValue := range m {
+ expandedVar := expandVar(variableValue, exportedStringVars, exportedStringListVars)
+ if len(expandedVar) > 1 {
+ panic(fmt.Errorf("%s expands to more than one string value: %s", variableValue, expandedVar))
+ }
+ ret = append(ret, bazelConstant{
+ variableName: k,
+ internalDefinition: fmt.Sprintf(`"%s"`, validateCharacters(expandedVar[0])),
+ })
+ }
+ return ret
+}
+
// Convenience function to declare a static variable and export it to Bazel's cc_toolchain.
func exportStringStaticVariable(name string, value string) {
pctx.StaticVariable(name, value)
exportedStringVars.Set(name, value)
}
+type exportedStringListVariables map[string][]string
+
func (m exportedStringListVariables) Set(k string, v []string) {
m[k] = v
}
+func (m exportedStringListVariables) asBazel(stringScope exportedStringVariables, stringListScope exportedStringListVariables) []bazelConstant {
+ ret := make([]bazelConstant, 0, len(m))
+ // For each exported variable, recursively expand elements in the variableValue
+ // list to ensure that interpolated variables are expanded according to their values
+ // in the variable scope.
+ for k, variableValue := range m {
+ var expandedVars []string
+ for _, v := range variableValue {
+ expandedVars = append(expandedVars, expandVar(v, stringScope, stringListScope)...)
+ }
+ // Assign the list as a bzl-private variable; this variable will be exported
+ // out through a constants struct later.
+ ret = append(ret, bazelConstant{
+ variableName: k,
+ internalDefinition: printBazelList(expandedVars, 0),
+ })
+ }
+ return ret
+}
+
// Convenience function to declare a static variable and export it to Bazel's cc_toolchain.
func exportStringListStaticVariable(name string, value []string) {
pctx.StaticVariable(name, strings.Join(value, " "))
exportedStringListVars.Set(name, value)
}
+type exportedStringListDictVariables map[string]map[string][]string
+
+func (m exportedStringListDictVariables) Set(k string, v map[string][]string) {
+ m[k] = v
+}
+
+func printBazelStringListDict(dict map[string][]string) string {
+ bazelDict := make([]string, 0, len(dict)+2)
+ bazelDict = append(bazelDict, "{")
+ for k, v := range dict {
+ bazelDict = append(bazelDict,
+ fmt.Sprintf(`%s"%s": %s,`, bazelIndention(1), k, printBazelList(v, 1)))
+ }
+ bazelDict = append(bazelDict, "}")
+ return strings.Join(bazelDict, "\n")
+}
+
+// Since dictionaries are not supported in Ninja, we do not expand variables for dictionaries
+func (m exportedStringListDictVariables) asBazel(_ exportedStringVariables, _ exportedStringListVariables) []bazelConstant {
+ ret := make([]bazelConstant, 0, len(m))
+ for k, dict := range m {
+ ret = append(ret, bazelConstant{
+ variableName: k,
+ internalDefinition: printBazelStringListDict(dict),
+ })
+ }
+ return ret
+}
+
// BazelCcToolchainVars generates bzl file content containing variables for
// Bazel's cc_toolchain configuration.
func BazelCcToolchainVars() string {
+ return bazelToolchainVars(
+ exportedStringListDictVars,
+ exportedStringListVars,
+ exportedStringVars)
+}
+
+func bazelToolchainVars(vars ...bazelVarExporter) string {
ret := "# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT.\n\n"
- // Ensure that string s has no invalid characters to be generated into the bzl file.
- validateCharacters := func(s string) string {
- for _, c := range []string{`\n`, `"`, `\`} {
- if strings.Contains(s, c) {
- panic(fmt.Errorf("%s contains illegal character %s", s, c))
- }
- }
- return s
+ results := []bazelConstant{}
+ for _, v := range vars {
+ results = append(results, v.asBazel(exportedStringVars, exportedStringListVars)...)
}
- // For each exported variable, recursively expand elements in the variableValue
- // list to ensure that interpolated variables are expanded according to their values
- // in the variable scope.
- for _, k := range android.SortedStringKeys(exportedStringListVars) {
- variableValue := exportedStringListVars[k]
- var expandedVars []string
- for _, v := range variableValue {
- expandedVars = append(expandedVars, expandVar(v, exportedStringVars, exportedStringListVars)...)
- }
- // Build the list for this variable.
- list := "["
- for _, flag := range expandedVars {
- list += fmt.Sprintf("\n \"%s\",", validateCharacters(flag))
- }
- list += "\n]"
- // Assign the list as a bzl-private variable; this variable will be exported
- // out through a constants struct later.
- ret += fmt.Sprintf("_%s = %s\n", k, list)
- ret += "\n"
- }
+ sort.Slice(results, func(i, j int) bool { return results[i].variableName < results[j].variableName })
- for _, k := range android.SortedStringKeys(exportedStringVars) {
- variableValue := exportedStringVars[k]
- expandedVar := expandVar(variableValue, exportedStringVars, exportedStringListVars)
- if len(expandedVar) > 1 {
- panic(fmt.Errorf("%s expands to more than one string value: %s", variableValue, expandedVar))
- }
- ret += fmt.Sprintf("_%s = \"%s\"\n", k, validateCharacters(expandedVar[0]))
- ret += "\n"
+ definitions := make([]string, 0, len(results))
+ constants := make([]string, 0, len(results))
+ for _, b := range results {
+ definitions = append(definitions,
+ fmt.Sprintf("_%s = %s", b.variableName, b.internalDefinition))
+ constants = append(constants,
+ fmt.Sprintf("%[1]s%[2]s = _%[2]s,", bazelIndention(1), b.variableName))
}
// Build the exported constants struct.
+ ret += strings.Join(definitions, "\n\n")
+ ret += "\n\n"
ret += "constants = struct(\n"
- for _, k := range android.SortedStringKeys(exportedStringVars) {
- ret += fmt.Sprintf(" %s = _%s,\n", k, k)
- }
- for _, k := range android.SortedStringKeys(exportedStringListVars) {
- ret += fmt.Sprintf(" %s = _%s,\n", k, k)
- }
- ret += ")"
+ ret += strings.Join(constants, "\n")
+ ret += "\n)"
+
return ret
}
diff --git a/cc/config/bp2build_test.go b/cc/config/bp2build_test.go
index a4745e6..883597a 100644
--- a/cc/config/bp2build_test.go
+++ b/cc/config/bp2build_test.go
@@ -115,3 +115,143 @@
})
}
}
+
+func TestBazelToolchainVars(t *testing.T) {
+ testCases := []struct {
+ name string
+ vars []bazelVarExporter
+ expectedOut string
+ }{
+ {
+ name: "exports strings",
+ vars: []bazelVarExporter{
+ exportedStringVariables{
+ "a": "b",
+ "c": "d",
+ },
+ },
+ expectedOut: `# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT.
+
+_a = "b"
+
+_c = "d"
+
+constants = struct(
+ a = _a,
+ c = _c,
+)`,
+ },
+ {
+ name: "exports string lists",
+ vars: []bazelVarExporter{
+ exportedStringListVariables{
+ "a": []string{"b1", "b2"},
+ "c": []string{"d1", "d2"},
+ },
+ },
+ expectedOut: `# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT.
+
+_a = [
+ "b1",
+ "b2",
+]
+
+_c = [
+ "d1",
+ "d2",
+]
+
+constants = struct(
+ a = _a,
+ c = _c,
+)`,
+ },
+ {
+ name: "exports string lists dicts",
+ vars: []bazelVarExporter{
+ exportedStringListDictVariables{
+ "a": map[string][]string{"b1": []string{"b2"}},
+ "c": map[string][]string{"d1": []string{"d2"}},
+ },
+ },
+ expectedOut: `# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT.
+
+_a = {
+ "b1": [
+ "b2",
+ ],
+}
+
+_c = {
+ "d1": [
+ "d2",
+ ],
+}
+
+constants = struct(
+ a = _a,
+ c = _c,
+)`,
+ },
+ {
+ name: "sorts across types",
+ vars: []bazelVarExporter{
+ exportedStringVariables{
+ "b": "b-val",
+ "d": "d-val",
+ },
+ exportedStringListVariables{
+ "c": []string{"c-val"},
+ "e": []string{"e-val"},
+ },
+ exportedStringListDictVariables{
+ "a": map[string][]string{"a1": []string{"a2"}},
+ "f": map[string][]string{"f1": []string{"f2"}},
+ },
+ },
+ expectedOut: `# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT.
+
+_a = {
+ "a1": [
+ "a2",
+ ],
+}
+
+_b = "b-val"
+
+_c = [
+ "c-val",
+]
+
+_d = "d-val"
+
+_e = [
+ "e-val",
+]
+
+_f = {
+ "f1": [
+ "f2",
+ ],
+}
+
+constants = struct(
+ a = _a,
+ b = _b,
+ c = _c,
+ d = _d,
+ e = _e,
+ f = _f,
+)`,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ out := bazelToolchainVars(tc.vars...)
+ if out != tc.expectedOut {
+ t.Errorf("Expected \n%s, got \n%s", tc.expectedOut, out)
+ }
+ })
+ }
+}
diff --git a/cc/config/global.go b/cc/config/global.go
index 55e0d79..9773345 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -46,7 +46,6 @@
"-O2",
"-g",
- "-fdebug-default-version=5",
"-fdebug-info-for-profiling",
"-fno-strict-aliasing",
@@ -229,6 +228,8 @@
"-Wno-non-c-typedef-for-linkage", // http://b/161304145
// New warnings to be fixed after clang-r407598
"-Wno-string-concatenation", // http://b/175068488
+ // New warnings to be fixed after clang-r428724
+ "-Wno-align-mismatch", // http://b/193679946
}
// Extra cflags for external third-party projects to disable warnings that
@@ -267,8 +268,8 @@
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r416183b1"
- ClangDefaultShortVersion = "12.0.7"
+ ClangDefaultVersion = "clang-r428724"
+ ClangDefaultShortVersion = "13.0.1"
// Directories with warnings from Android.bp files.
WarningAllowedProjects = []string{
@@ -354,6 +355,9 @@
exportedStringListVars.Set("CommonGlobalIncludes", commonGlobalIncludes)
pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I", commonGlobalIncludes)
+ exportStringStaticVariable("CLANG_DEFAULT_VERSION", ClangDefaultVersion)
+ exportStringStaticVariable("CLANG_DEFAULT_SHORT_VERSION", ClangDefaultShortVersion)
+
pctx.SourcePathVariable("ClangDefaultBase", ClangDefaultBase)
pctx.VariableFunc("ClangBase", func(ctx android.PackageVarContext) string {
if override := ctx.Config().Getenv("LLVM_PREBUILTS_BASE"); override != "" {
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index c4f47a7..00f07ff 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -77,6 +77,14 @@
"popcnt": []string{"-mpopcnt"},
"aes_ni": []string{"-maes"},
}
+
+ x86_64DefaultArchVariantFeatures = []string{
+ "ssse3",
+ "sse4",
+ "sse4_1",
+ "sse4_2",
+ "popcnt",
+ }
)
const (
@@ -84,37 +92,38 @@
)
func init() {
- android.RegisterDefaultArchVariantFeatures(android.Android, android.X86_64,
- "ssse3",
- "sse4",
- "sse4_1",
- "sse4_2",
- "popcnt")
+ android.RegisterDefaultArchVariantFeatures(android.Android, android.X86_64, x86_64DefaultArchVariantFeatures...)
+ exportedStringListVars.Set("X86_64DefaultArchVariantFeatures", x86_64DefaultArchVariantFeatures)
pctx.StaticVariable("x86_64GccVersion", x86_64GccVersion)
pctx.SourcePathVariable("X86_64GccRoot",
"prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${x86_64GccVersion}")
- pctx.StaticVariable("X86_64ToolchainCflags", "-m64")
- pctx.StaticVariable("X86_64ToolchainLdflags", "-m64")
+ exportStringListStaticVariable("X86_64ToolchainCflags", []string{"-m64"})
+ exportStringListStaticVariable("X86_64ToolchainLdflags", []string{"-m64"})
- pctx.StaticVariable("X86_64Ldflags", strings.Join(x86_64Ldflags, " "))
- pctx.StaticVariable("X86_64Lldflags", strings.Join(x86_64Ldflags, " "))
+ exportStringListStaticVariable("X86_64Ldflags", x86_64Ldflags)
+ exportStringListStaticVariable("X86_64Lldflags", x86_64Ldflags)
// Clang cflags
- pctx.StaticVariable("X86_64Cflags", strings.Join(x86_64Cflags, " "))
- pctx.StaticVariable("X86_64Cppflags", strings.Join(x86_64Cppflags, " "))
+ exportStringListStaticVariable("X86_64Cflags", x86_64Cflags)
+ exportStringListStaticVariable("X86_64Cppflags", x86_64Cppflags)
// Yasm flags
- pctx.StaticVariable("X86_64YasmFlags", "-f elf64 -m amd64")
+ exportStringListStaticVariable("X86_64YasmFlags", []string{
+ "-f elf64",
+ "-m amd64",
+ })
// Extended cflags
+ exportedStringListDictVars.Set("X86_64ArchVariantCflags", x86_64ArchVariantCflags)
+ exportedStringListDictVars.Set("X86_64ArchFeatureCflags", x86_64ArchFeatureCflags)
+
// Architecture variant cflags
for variant, cflags := range x86_64ArchVariantCflags {
- pctx.StaticVariable("X86_64"+variant+"VariantCflags",
- strings.Join(cflags, " "))
+ pctx.StaticVariable("X86_64"+variant+"VariantCflags", strings.Join(cflags, " "))
}
}
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index 5e510a4..29f0593 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -97,25 +97,29 @@
pctx.SourcePathVariable("X86GccRoot",
"prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${x86GccVersion}")
- pctx.StaticVariable("X86ToolchainCflags", "-m32")
- pctx.StaticVariable("X86ToolchainLdflags", "-m32")
+ exportStringListStaticVariable("X86ToolchainCflags", []string{"-m32"})
+ exportStringListStaticVariable("X86ToolchainLdflags", []string{"-m32"})
- pctx.StaticVariable("X86Ldflags", strings.Join(x86Ldflags, " "))
- pctx.StaticVariable("X86Lldflags", strings.Join(x86Ldflags, " "))
+ exportStringListStaticVariable("X86Ldflags", x86Ldflags)
+ exportStringListStaticVariable("X86Lldflags", x86Ldflags)
// Clang cflags
- pctx.StaticVariable("X86Cflags", strings.Join(x86Cflags, " "))
- pctx.StaticVariable("X86Cppflags", strings.Join(x86Cppflags, " "))
+ exportStringListStaticVariable("X86Cflags", x86Cflags)
+ exportStringListStaticVariable("X86Cppflags", x86Cppflags)
// Yasm flags
- pctx.StaticVariable("X86YasmFlags", "-f elf32 -m x86")
+ exportStringListStaticVariable("X86YasmFlags", []string{
+ "-f elf32",
+ "-m x86",
+ })
// Extended cflags
+ exportedStringListDictVars.Set("X86ArchVariantCflags", x86ArchVariantCflags)
+ exportedStringListDictVars.Set("X86ArchFeatureCflags", x86ArchFeatureCflags)
// Architecture variant cflags
for variant, cflags := range x86ArchVariantCflags {
- pctx.StaticVariable("X86"+variant+"VariantCflags",
- strings.Join(cflags, " "))
+ pctx.StaticVariable("X86"+variant+"VariantCflags", strings.Join(cflags, " "))
}
}
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index 1d66cb7..e7fcfed 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -110,7 +110,7 @@
muslCrtBeginSharedBinary, muslCrtEndSharedBinary = []string{"libc_musl_crtbegin_dynamic", "musl_linker_script"}, []string{"libc_musl_crtend"}
muslCrtBeginSharedLibrary, muslCrtEndSharedLibrary = []string{"libc_musl_crtbegin_so"}, []string{"libc_musl_crtend_so"}
- muslDefaultSharedLibraries = []string{"libjemalloc5", "libc_musl"}
+ muslDefaultSharedLibraries = []string{"libc_musl"}
)
const (
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 8b0f93e..fbef12b 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -15,7 +15,6 @@
package cc
import (
- "encoding/json"
"path/filepath"
"sort"
"strings"
@@ -24,55 +23,9 @@
"android/soong/android"
"android/soong/cc/config"
+ "android/soong/fuzz"
)
-type FuzzConfig struct {
- // Email address of people to CC on bugs or contact about this fuzz target.
- Cc []string `json:"cc,omitempty"`
- // Specify whether to enable continuous fuzzing on devices. Defaults to true.
- Fuzz_on_haiku_device *bool `json:"fuzz_on_haiku_device,omitempty"`
- // Specify whether to enable continuous fuzzing on host. Defaults to true.
- Fuzz_on_haiku_host *bool `json:"fuzz_on_haiku_host,omitempty"`
- // Component in Google's bug tracking system that bugs should be filed to.
- Componentid *int64 `json:"componentid,omitempty"`
- // Hotlists in Google's bug tracking system that bugs should be marked with.
- Hotlists []string `json:"hotlists,omitempty"`
- // Specify whether this fuzz target was submitted by a researcher. Defaults
- // to false.
- Researcher_submitted *bool `json:"researcher_submitted,omitempty"`
- // Specify who should be acknowledged for CVEs in the Android Security
- // Bulletin.
- Acknowledgement []string `json:"acknowledgement,omitempty"`
- // Additional options to be passed to libfuzzer when run in Haiku.
- Libfuzzer_options []string `json:"libfuzzer_options,omitempty"`
- // Additional options to be passed to HWASAN when running on-device in Haiku.
- Hwasan_options []string `json:"hwasan_options,omitempty"`
- // Additional options to be passed to HWASAN when running on host in Haiku.
- Asan_options []string `json:"asan_options,omitempty"`
-}
-
-func (f *FuzzConfig) String() string {
- b, err := json.Marshal(f)
- if err != nil {
- panic(err)
- }
-
- return string(b)
-}
-
-type FuzzProperties struct {
- // Optional list of seed files to be installed to the fuzz target's output
- // directory.
- Corpus []string `android:"path"`
- // Optional list of data files to be installed to the fuzz target's output
- // directory. Directory structure relative to the module is preserved.
- Data []string `android:"path"`
- // Optional dictionary to be installed to the fuzz target's output directory.
- Dictionary *string `android:"path"`
- // Config for running the target on fuzzing infrastructure.
- Fuzz_config *FuzzConfig
-}
-
func init() {
android.RegisterModuleType("cc_fuzz", FuzzFactory)
android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
@@ -94,7 +47,7 @@
*binaryDecorator
*baseCompiler
- fuzzPackagedModule FuzzPackagedModule
+ fuzzPackagedModule fuzz.FuzzPackagedModule
installedSharedDeps []string
}
@@ -355,7 +308,7 @@
// Responsible for generating GNU Make rules that package fuzz targets into
// their architecture & target/host specific zip file.
type ccFuzzPackager struct {
- FuzzPackager
+ fuzz.FuzzPackager
sharedLibInstallStrings []string
}
@@ -367,7 +320,7 @@
// Map between each architecture + host/device combination, and the files that
// need to be packaged (in the tuple of {source file, destination folder in
// archive}).
- archDirs := make(map[ArchOs][]FileToZip)
+ archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip)
// Map tracking whether each shared library has an install rule to avoid duplicate install rules from
// multiple fuzzers that depend on the same shared library.
@@ -384,7 +337,7 @@
}
// Discard non-fuzz targets.
- if ok := IsValid(ccModule.FuzzModule); !ok {
+ if ok := fuzz.IsValid(ccModule.FuzzModule); !ok {
return
}
@@ -400,12 +353,12 @@
archString := ccModule.Arch().ArchType.String()
archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
- archOs := ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
+ archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
// Grab the list of required shared libraries.
sharedLibraries := collectAllSharedDependencies(ctx, module)
- var files []FileToZip
+ var files []fuzz.FileToZip
builder := android.NewRuleBuilder(pctx, ctx)
// Package the corpus, data, dict and config into a zipfile.
@@ -414,7 +367,7 @@
// Find and mark all the transiently-dependent shared libraries for
// packaging.
for _, library := range sharedLibraries {
- files = append(files, FileToZip{library, "lib"})
+ files = append(files, fuzz.FileToZip{library, "lib"})
// For each architecture-specific shared library dependency, we need to
// install it to the output directory. Setup the install destination here,
@@ -446,7 +399,7 @@
}
// The executable.
- files = append(files, FileToZip{ccModule.UnstrippedOutputFile(), ""})
+ files = append(files, fuzz.FileToZip{ccModule.UnstrippedOutputFile(), ""})
archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
if !ok {
@@ -454,7 +407,7 @@
}
})
- s.CreateFuzzPackage(ctx, archDirs, Cc)
+ s.CreateFuzzPackage(ctx, archDirs, fuzz.Cc, pctx)
}
diff --git a/cc/library.go b/cc/library.go
index 6c7102e..84cd0d7 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -23,13 +23,12 @@
"strings"
"sync"
- "github.com/google/blueprint"
- "github.com/google/blueprint/pathtools"
-
"android/soong/android"
"android/soong/bazel"
"android/soong/bazel/cquery"
"android/soong/cc/config"
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/pathtools"
)
// LibraryProperties is a collection of properties shared by cc library rules.
@@ -233,9 +232,11 @@
Implementation_deps bazel.LabelListAttribute
Dynamic_deps bazel.LabelListAttribute
Whole_archive_deps bazel.LabelListAttribute
+ System_dynamic_deps bazel.LabelListAttribute
Includes bazel.StringListAttribute
Linkopts bazel.StringListAttribute
Use_libcrt bazel.BoolAttribute
+ Rtti bazel.BoolAttribute
// This is shared only.
Version_script bazel.LabelAttribute
@@ -319,9 +320,11 @@
Deps: linkerAttrs.exportedDeps,
Dynamic_deps: linkerAttrs.dynamicDeps,
Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
+ System_dynamic_deps: linkerAttrs.systemDynamicDeps,
Includes: exportedIncludes,
Linkopts: linkerAttrs.linkopts,
Use_libcrt: linkerAttrs.useLibcrt,
+ Rtti: compilerAttrs.rtti,
Version_script: linkerAttrs.versionScript,
@@ -553,7 +556,7 @@
}
type ccLibraryBazelHandler struct {
- bazelHandler
+ android.BazelHandler
module *Module
}
@@ -639,7 +642,7 @@
return android.OptionalPathForPath(android.PathForBazelOut(ctx, tocFile))
}
-func (handler *ccLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+func (handler *ccLibraryBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
if err != nil {
@@ -2329,9 +2332,12 @@
Implementation_deps bazel.LabelListAttribute
Deps bazel.LabelListAttribute
Whole_archive_deps bazel.LabelListAttribute
+ Dynamic_deps bazel.LabelListAttribute
+ System_dynamic_deps bazel.LabelListAttribute
Linkopts bazel.StringListAttribute
Linkstatic bool
Use_libcrt bazel.BoolAttribute
+ Rtti bazel.BoolAttribute
Includes bazel.StringListAttribute
Hdrs bazel.LabelListAttribute
@@ -2340,6 +2346,8 @@
Conlyflags bazel.StringListAttribute
Srcs_as bazel.LabelListAttribute
Asflags bazel.StringListAttribute
+
+ Static staticOrSharedAttributes
}
type bazelCcLibraryStatic struct {
@@ -2365,16 +2373,33 @@
asFlags = bazel.MakeStringListAttribute(nil)
}
+ // Append static{} stanza properties. These won't be specified on
+ // cc_library_static itself, but may be specified in cc_defaults that this module
+ // depends on.
+ staticAttrs := bp2BuildParseStaticProps(ctx, module)
+
+ compilerAttrs.srcs.Append(staticAttrs.Srcs)
+ compilerAttrs.cSrcs.Append(staticAttrs.Srcs_c)
+ compilerAttrs.asSrcs.Append(staticAttrs.Srcs_as)
+ compilerAttrs.copts.Append(staticAttrs.Copts)
+ linkerAttrs.exportedDeps.Append(staticAttrs.Static_deps)
+ linkerAttrs.dynamicDeps.Append(staticAttrs.Dynamic_deps)
+ linkerAttrs.wholeArchiveDeps.Append(staticAttrs.Whole_archive_deps)
+ linkerAttrs.systemDynamicDeps.Append(staticAttrs.System_dynamic_deps)
+
attrs := &bazelCcLibraryStaticAttributes{
Copts: compilerAttrs.copts,
Srcs: compilerAttrs.srcs,
Implementation_deps: linkerAttrs.deps,
Deps: linkerAttrs.exportedDeps,
Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
+ Dynamic_deps: linkerAttrs.dynamicDeps,
+ System_dynamic_deps: linkerAttrs.systemDynamicDeps,
Linkopts: linkerAttrs.linkopts,
Linkstatic: true,
Use_libcrt: linkerAttrs.useLibcrt,
+ Rtti: compilerAttrs.rtti,
Includes: exportedIncludes,
Cppflags: compilerAttrs.cppFlags,
diff --git a/cc/library_headers.go b/cc/library_headers.go
index d6b4529..1a276f4 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -44,13 +44,13 @@
}
type libraryHeaderBazelHander struct {
- bazelHandler
+ android.BazelHandler
module *Module
library *libraryDecorator
}
-func (h *libraryHeaderBazelHander) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+func (h *libraryHeaderBazelHander) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
if err != nil {
@@ -108,6 +108,7 @@
Includes bazel.StringListAttribute
Deps bazel.LabelListAttribute
Implementation_deps bazel.LabelListAttribute
+ System_dynamic_deps bazel.LabelListAttribute
}
type bazelCcLibraryHeaders struct {
@@ -146,6 +147,7 @@
Includes: exportedIncludes,
Implementation_deps: linkerAttrs.deps,
Deps: linkerAttrs.exportedDeps,
+ System_dynamic_deps: linkerAttrs.systemDynamicDeps,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/cc/object.go b/cc/object.go
index bd9f228..5952f1e 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -47,12 +47,12 @@
}
type objectBazelHandler struct {
- bazelHandler
+ android.BazelHandler
module *Module
}
-func (handler *objectBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+func (handler *objectBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
objPaths, ok := bazelCtx.GetOutputFiles(label, ctx.Arch().ArchType)
if ok {
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index f7154ec..d324241 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -15,9 +15,10 @@
package cc
import (
- "android/soong/android"
"path/filepath"
"strings"
+
+ "android/soong/android"
)
func init() {
@@ -321,13 +322,13 @@
}
type prebuiltStaticLibraryBazelHandler struct {
- bazelHandler
+ android.BazelHandler
module *Module
library *libraryDecorator
}
-func (h *prebuiltStaticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+func (h *prebuiltStaticLibraryBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
if err != nil {
diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py
index 31c4443..f8d1841 100644
--- a/cc/symbolfile/__init__.py
+++ b/cc/symbolfile/__init__.py
@@ -329,7 +329,7 @@
def parse(self) -> List[Version]:
"""Parses the symbol file and returns a list of Version objects."""
versions = []
- while self.next_line() != '':
+ while self.next_line():
assert self.current_line is not None
if '{' in self.current_line:
versions.append(self.parse_version())
@@ -376,7 +376,7 @@
symbols: List[Symbol] = []
global_scope = True
cpp_symbols = False
- while self.next_line() != '':
+ while self.next_line():
if '}' in self.current_line:
# Line is something like '} BASE; # tags'. Both base and tags
# are optional here.
@@ -428,11 +428,11 @@
A return value of '' indicates EOF.
"""
line = self.input_file.readline()
- while line.strip() == '' or line.strip().startswith('#'):
+ while not line.strip() or line.strip().startswith('#'):
line = self.input_file.readline()
# We want to skip empty lines, but '' indicates EOF.
- if line == '':
+ if not line:
break
self.current_line = line
return self.current_line
diff --git a/cc/testing.go b/cc/testing.go
index e8f3481..071f1ec 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -451,16 +451,6 @@
name: "note_memtag_heap_sync",
}
-
- cc_library {
- name: "libjemalloc5",
- host_supported: true,
- no_libcrt: true,
- nocrt: true,
- system_shared_libs: [],
- stl: "none",
- }
-
cc_library {
name: "libc_musl",
host_supported: true,
diff --git a/cc/tidy.go b/cc/tidy.go
index b2382e8..fefa7f0 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -146,6 +146,8 @@
tidyChecks = tidyChecks + ",-bugprone-signed-char-misuse"
// http://b/155034972
tidyChecks = tidyChecks + ",-bugprone-branch-clone"
+ // http://b/193716442
+ tidyChecks = tidyChecks + ",-bugprone-implicit-widening-of-multiplication-result"
flags.TidyFlags = append(flags.TidyFlags, tidyChecks)
if ctx.Config().IsEnvTrue("WITH_TIDY") {
diff --git a/cmd/extract_linker/main.go b/cmd/extract_linker/main.go
index f1f7bc7..1280553 100644
--- a/cmd/extract_linker/main.go
+++ b/cmd/extract_linker/main.go
@@ -26,7 +26,7 @@
"io/ioutil"
"log"
"os"
- "strings"
+ "strconv"
)
func main() {
@@ -59,20 +59,16 @@
fmt.Fprintln(script, "ENTRY(__dlwrap__start)")
fmt.Fprintln(script, "SECTIONS {")
+ progsWithFlagsCount := make(map[string]int)
+
for _, prog := range ef.Progs {
if prog.Type != elf.PT_LOAD {
continue
}
- var progName string
- progSection := progToFirstSection(prog, ef.Sections)
- if progSection != nil {
- progName = progSection.Name
- } else {
- progName = fmt.Sprintf(".sect%d", load)
- }
- sectionName := ".linker" + progName
- symName := "__dlwrap_linker" + strings.ReplaceAll(progName, ".", "_")
+ progName := progNameFromFlags(prog.Flags, progsWithFlagsCount)
+ sectionName := ".linker_" + progName
+ symName := "__dlwrap_linker_" + progName
flags := ""
if prog.Flags&elf.PF_W != 0 {
@@ -83,6 +79,12 @@
}
fmt.Fprintf(asm, ".section %s, \"a%s\"\n", sectionName, flags)
+ if load == 0 {
+ fmt.Fprintln(asm, ".globl __dlwrap_linker")
+ fmt.Fprintln(asm, "__dlwrap_linker:")
+ fmt.Fprintln(asm)
+ }
+
fmt.Fprintf(asm, ".globl %s\n%s:\n\n", symName, symName)
fmt.Fprintf(script, " %s 0x%x : {\n", sectionName, baseLoadAddr+prog.Vaddr)
@@ -106,6 +108,10 @@
load += 1
}
+ fmt.Fprintln(asm, ".globl __dlwrap_linker_end")
+ fmt.Fprintln(asm, "__dlwrap_linker_end:")
+ fmt.Fprintln(asm)
+
fmt.Fprintln(asm, `.section .note.android.embedded_linker,"a",%note`)
fmt.Fprintln(script, "}")
@@ -139,11 +145,25 @@
fmt.Fprintln(asm)
}
-func progToFirstSection(prog *elf.Prog, sections []*elf.Section) *elf.Section {
- for _, section := range sections {
- if section.Addr == prog.Vaddr {
- return section
- }
+func progNameFromFlags(flags elf.ProgFlag, progsWithFlagsCount map[string]int) string {
+ s := ""
+ if flags&elf.PF_R != 0 {
+ s += "r"
}
- return nil
+ if flags&elf.PF_W != 0 {
+ s += "w"
+ }
+ if flags&elf.PF_X != 0 {
+ s += "x"
+ }
+
+ count := progsWithFlagsCount[s]
+ count++
+ progsWithFlagsCount[s] = count
+
+ if count > 1 {
+ s += strconv.Itoa(count)
+ }
+
+ return s
}
diff --git a/cmd/multiproduct_kati/Android.bp b/cmd/multiproduct_kati/Android.bp
index 21d8e21..e5be6c0 100644
--- a/cmd/multiproduct_kati/Android.bp
+++ b/cmd/multiproduct_kati/Android.bp
@@ -19,8 +19,8 @@
blueprint_go_binary {
name: "multiproduct_kati",
deps: [
- "soong-ui-build",
"soong-ui-logger",
+ "soong-ui-signal",
"soong-ui-terminal",
"soong-ui-tracer",
"soong-zip",
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 55a5470..2846387 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -15,22 +15,24 @@
package main
import (
+ "bufio"
"context"
"flag"
"fmt"
"io"
- "io/ioutil"
+ "log"
"os"
+ "os/exec"
"path/filepath"
+ "regexp"
"runtime"
"strings"
"sync"
"syscall"
"time"
- "android/soong/finder"
- "android/soong/ui/build"
"android/soong/ui/logger"
+ "android/soong/ui/signal"
"android/soong/ui/status"
"android/soong/ui/terminal"
"android/soong/ui/tracer"
@@ -74,36 +76,6 @@
return nil
}
-const errorLeadingLines = 20
-const errorTrailingLines = 20
-
-func errMsgFromLog(filename string) string {
- if filename == "" {
- return ""
- }
-
- data, err := ioutil.ReadFile(filename)
- if err != nil {
- return ""
- }
-
- lines := strings.Split(strings.TrimSpace(string(data)), "\n")
- if len(lines) > errorLeadingLines+errorTrailingLines+1 {
- lines[errorLeadingLines] = fmt.Sprintf("... skipping %d lines ...",
- len(lines)-errorLeadingLines-errorTrailingLines)
-
- lines = append(lines[:errorLeadingLines+1],
- lines[len(lines)-errorTrailingLines:]...)
- }
- var buf strings.Builder
- for _, line := range lines {
- buf.WriteString("> ")
- buf.WriteString(line)
- buf.WriteString("\n")
- }
- return buf.String()
-}
-
// TODO(b/70370883): This tool uses a lot of open files -- over the default
// soft limit of 1024 on some systems. So bump up to the hard limit until I fix
// the algorithm.
@@ -155,28 +127,59 @@
}
type mpContext struct {
- Context context.Context
- Logger logger.Logger
- Status status.ToolStatus
- Tracer tracer.Tracer
- Finder *finder.Finder
- Config build.Config
+ Logger logger.Logger
+ Status status.ToolStatus
- LogsDir string
+ SoongUi string
+ MainOutDir string
+ MainLogsDir string
+}
+
+func detectTotalRAM() uint64 {
+ var info syscall.Sysinfo_t
+ err := syscall.Sysinfo(&info)
+ if err != nil {
+ panic(err)
+ }
+ return info.Totalram * uint64(info.Unit)
+}
+
+func findNamedProducts(soongUi string, log logger.Logger) []string {
+ cmd := exec.Command(soongUi, "--dumpvars-mode", "--vars=all_named_products")
+ output, err := cmd.Output()
+ if err != nil {
+ log.Fatalf("Cannot determine named products: %v", err)
+ }
+
+ rx := regexp.MustCompile(`^all_named_products='(.*)'$`)
+ match := rx.FindStringSubmatch(strings.TrimSpace(string(output)))
+ return strings.Fields(match[1])
+}
+
+// ensureEmptyFileExists ensures that the containing directory exists, and the
+// specified file exists. If it doesn't exist, it will write an empty file.
+func ensureEmptyFileExists(file string, log logger.Logger) {
+ if _, err := os.Stat(file); os.IsNotExist(err) {
+ f, err := os.Create(file)
+ if err != nil {
+ log.Fatalf("Error creating %s: %q\n", file, err)
+ }
+ f.Close()
+ } else if err != nil {
+ log.Fatalf("Error checking %s: %q\n", file, err)
+ }
}
func main() {
stdio := terminal.StdioImpl{}
- output := terminal.NewStatusOutput(stdio.Stdout(), "", false,
- build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"))
-
+ output := terminal.NewStatusOutput(stdio.Stdout(), "", false, false)
log := logger.New(output)
defer log.Cleanup()
flag.Parse()
- ctx, cancel := context.WithCancel(context.Background())
+ _, cancel := context.WithCancel(context.Background())
defer cancel()
trace := tracer.New(log)
@@ -189,61 +192,59 @@
var failures failureCount
stat.AddOutput(&failures)
- build.SetupSignals(log, cancel, func() {
+ signal.SetupSignals(log, cancel, func() {
trace.Close()
log.Cleanup()
stat.Finish()
})
- buildCtx := build.Context{ContextImpl: &build.ContextImpl{
- Context: ctx,
- Logger: log,
- Tracer: trace,
- Writer: output,
- Status: stat,
- }}
+ soongUi := "build/soong/soong_ui.bash"
- args := ""
- if *alternateResultDir {
- args = "dist"
- }
- config := build.NewConfig(buildCtx, args)
- if *outDir == "" {
+ var outputDir string
+ if *outDir != "" {
+ outputDir = *outDir
+ } else {
name := "multiproduct"
if !*incremental {
name += "-" + time.Now().Format("20060102150405")
}
- *outDir = filepath.Join(config.OutDir(), name)
-
- // Ensure the empty files exist in the output directory
- // containing our output directory too. This is mostly for
- // safety, but also triggers the ninja_build file so that our
- // build servers know that they can parse the output as if it
- // was ninja output.
- build.SetupOutDir(buildCtx, config)
-
- if err := os.MkdirAll(*outDir, 0777); err != nil {
- log.Fatalf("Failed to create tempdir: %v", err)
+ outDirBase := os.Getenv("OUT_DIR")
+ if outDirBase == "" {
+ outDirBase = "out"
}
- }
- config.Environment().Set("OUT_DIR", *outDir)
- log.Println("Output directory:", *outDir)
- logsDir := filepath.Join(config.OutDir(), "logs")
+ outputDir = filepath.Join(outDirBase, name)
+ }
+
+ log.Println("Output directory:", outputDir)
+
+ // The ninja_build file is used by our buildbots to understand that the output
+ // can be parsed as ninja output.
+ if err := os.MkdirAll(outputDir, 0777); err != nil {
+ log.Fatalf("Failed to create output directory: %v", err)
+ }
+ ensureEmptyFileExists(filepath.Join(outputDir, "ninja_build"), log)
+
+ logsDir := filepath.Join(outputDir, "logs")
os.MkdirAll(logsDir, 0777)
- build.SetupOutDir(buildCtx, config)
+ var configLogsDir string
+ if *alternateResultDir {
+ configLogsDir = filepath.Join(outputDir, "dist/logs")
+ } else {
+ configLogsDir = outputDir
+ }
- os.MkdirAll(config.LogsDir(), 0777)
- log.SetOutput(filepath.Join(config.LogsDir(), "soong.log"))
- trace.SetOutput(filepath.Join(config.LogsDir(), "build.trace"))
+ os.MkdirAll(configLogsDir, 0777)
+ log.SetOutput(filepath.Join(configLogsDir, "soong.log"))
+ trace.SetOutput(filepath.Join(configLogsDir, "build.trace"))
var jobs = *numJobs
if jobs < 1 {
jobs = runtime.NumCPU() / 4
- ramGb := int(config.TotalRAM() / 1024 / 1024 / 1024)
+ ramGb := int(detectTotalRAM() / (1024 * 1024 * 1024))
if ramJobs := ramGb / 25; ramGb > 0 && jobs > ramJobs {
jobs = ramJobs
}
@@ -256,17 +257,8 @@
setMaxFiles(log)
- finder := build.NewSourceFinder(buildCtx, config)
- defer finder.Shutdown()
-
- build.FindSources(buildCtx, config, finder)
-
- vars, err := build.DumpMakeVars(buildCtx, config, nil, []string{"all_named_products"})
- if err != nil {
- log.Fatal(err)
- }
+ allProducts := findNamedProducts(soongUi, log)
var productsList []string
- allProducts := strings.Fields(vars["all_named_products"])
if len(includeProducts) > 0 {
var missingProducts []string
@@ -314,19 +306,15 @@
log.Verbose("Got product list: ", finalProductsList)
- s := buildCtx.Status.StartTool()
+ s := stat.StartTool()
s.SetTotalActions(len(finalProductsList))
mpCtx := &mpContext{
- Context: ctx,
- Logger: log,
- Status: s,
- Tracer: trace,
-
- Finder: finder,
- Config: config,
-
- LogsDir: logsDir,
+ Logger: log,
+ Status: s,
+ SoongUi: soongUi,
+ MainOutDir: outputDir,
+ MainLogsDir: logsDir,
}
products := make(chan string, len(productsList))
@@ -348,7 +336,7 @@
if product == "" {
return
}
- buildProduct(mpCtx, product)
+ runSoongUiForProduct(mpCtx, product)
}
}
}()
@@ -360,7 +348,7 @@
FileArgs: []zip.FileArg{
{GlobDir: logsDir, SourcePrefixToStrip: logsDir},
},
- OutputFilePath: filepath.Join(config.RealDistDir(), "logs.zip"),
+ OutputFilePath: filepath.Join(outputDir, "dist/logs.zip"),
NumParallelJobs: runtime.NumCPU(),
CompressionLevel: 5,
}
@@ -380,11 +368,33 @@
}
}
-func buildProduct(mpctx *mpContext, product string) {
- var stdLog string
+func cleanupAfterProduct(outDir, productZip string) {
+ if *keepArtifacts {
+ args := zip.ZipArgs{
+ FileArgs: []zip.FileArg{
+ {
+ GlobDir: outDir,
+ SourcePrefixToStrip: outDir,
+ },
+ },
+ OutputFilePath: productZip,
+ NumParallelJobs: runtime.NumCPU(),
+ CompressionLevel: 5,
+ }
+ if err := zip.Zip(args); err != nil {
+ log.Fatalf("Error zipping artifacts: %v", err)
+ }
+ }
+ if !*incremental {
+ os.RemoveAll(outDir)
+ }
+}
- outDir := filepath.Join(mpctx.Config.OutDir(), product)
- logsDir := filepath.Join(mpctx.LogsDir, product)
+func runSoongUiForProduct(mpctx *mpContext, product string) {
+ outDir := filepath.Join(mpctx.MainOutDir, product)
+ logsDir := filepath.Join(mpctx.MainLogsDir, product)
+ productZip := filepath.Join(mpctx.MainOutDir, product+".zip")
+ consoleLogPath := filepath.Join(logsDir, "std.log")
if err := os.MkdirAll(outDir, 0777); err != nil {
mpctx.Logger.Fatalf("Error creating out directory: %v", err)
@@ -393,98 +403,65 @@
mpctx.Logger.Fatalf("Error creating log directory: %v", err)
}
- stdLog = filepath.Join(logsDir, "std.log")
- f, err := os.Create(stdLog)
+ consoleLogFile, err := os.Create(consoleLogPath)
if err != nil {
- mpctx.Logger.Fatalf("Error creating std.log: %v", err)
+ mpctx.Logger.Fatalf("Error creating console log file: %v", err)
}
- defer f.Close()
+ defer consoleLogFile.Close()
- log := logger.New(f)
- defer log.Cleanup()
- log.SetOutput(filepath.Join(logsDir, "soong.log"))
+ consoleLogWriter := bufio.NewWriter(consoleLogFile)
+ defer consoleLogWriter.Flush()
+
+ args := []string{"--make-mode", "--skip-soong-tests", "--skip-ninja"}
+
+ if !*keepArtifacts {
+ args = append(args, "--empty-ninja-file")
+ }
+
+ if *onlyConfig {
+ args = append(args, "--config-only")
+ } else if *onlySoong {
+ args = append(args, "--soong-only")
+ }
+
+ if *alternateResultDir {
+ args = append(args, "dist")
+ }
+
+ cmd := exec.Command(mpctx.SoongUi, args...)
+ cmd.Stdout = consoleLogWriter
+ cmd.Stderr = consoleLogWriter
+ cmd.Env = append(os.Environ(),
+ "OUT_DIR="+outDir,
+ "TARGET_PRODUCT="+product,
+ "TARGET_BUILD_VARIANT="+*buildVariant,
+ "TARGET_BUILD_TYPE=release",
+ "TARGET_BUILD_APPS=",
+ "TARGET_BUILD_UNBUNDLED=")
action := &status.Action{
Description: product,
Outputs: []string{product},
}
+
mpctx.Status.StartAction(action)
- defer logger.Recover(func(err error) {
- mpctx.Status.FinishAction(status.ActionResult{
- Action: action,
- Error: err,
- Output: errMsgFromLog(stdLog),
- })
- })
-
- ctx := build.Context{ContextImpl: &build.ContextImpl{
- Context: mpctx.Context,
- Logger: log,
- Tracer: mpctx.Tracer,
- Writer: f,
- Thread: mpctx.Tracer.NewThread(product),
- Status: &status.Status{},
- }}
- ctx.Status.AddOutput(terminal.NewStatusOutput(ctx.Writer, "", false,
- build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
-
- args := append([]string(nil), flag.Args()...)
- args = append(args, "--skip-soong-tests")
- config := build.NewConfig(ctx, args...)
- config.Environment().Set("OUT_DIR", outDir)
- if !*keepArtifacts {
- config.SetEmptyNinjaFile(true)
- }
- build.FindSources(ctx, config, mpctx.Finder)
- config.Lunch(ctx, product, *buildVariant)
-
- defer func() {
- if *keepArtifacts {
- args := zip.ZipArgs{
- FileArgs: []zip.FileArg{
- {
- GlobDir: outDir,
- SourcePrefixToStrip: outDir,
- },
- },
- OutputFilePath: filepath.Join(mpctx.Config.OutDir(), product+".zip"),
- NumParallelJobs: runtime.NumCPU(),
- CompressionLevel: 5,
- }
- if err := zip.Zip(args); err != nil {
- log.Fatalf("Error zipping artifacts: %v", err)
- }
- }
- if !*incremental {
- os.RemoveAll(outDir)
- }
- }()
-
- config.SetSkipNinja(true)
-
- buildWhat := build.RunProductConfig
- if !*onlyConfig {
- buildWhat |= build.RunSoong
- if !*onlySoong {
- buildWhat |= build.RunKati
- }
- }
+ defer cleanupAfterProduct(outDir, productZip)
before := time.Now()
- build.Build(ctx, config)
+ err = cmd.Run()
- // Save std_full.log if Kati re-read the makefiles
- if buildWhat&build.RunKati != 0 {
- if after, err := os.Stat(config.KatiBuildNinjaFile()); err == nil && after.ModTime().After(before) {
- err := copyFile(stdLog, filepath.Join(filepath.Dir(stdLog), "std_full.log"))
+ if !*onlyConfig && !*onlySoong {
+ katiBuildNinjaFile := filepath.Join(outDir, "build-"+product+".ninja")
+ if after, err := os.Stat(katiBuildNinjaFile); err == nil && after.ModTime().After(before) {
+ err := copyFile(consoleLogPath, filepath.Join(filepath.Dir(consoleLogPath), "std_full.log"))
if err != nil {
log.Fatalf("Error copying log file: %s", err)
}
}
}
-
mpctx.Status.FinishAction(status.ActionResult{
Action: action,
+ Error: err,
})
}
diff --git a/cmd/run_with_timeout/run_with_timeout.go b/cmd/run_with_timeout/run_with_timeout.go
index f2caaab..deaa842 100644
--- a/cmd/run_with_timeout/run_with_timeout.go
+++ b/cmd/run_with_timeout/run_with_timeout.go
@@ -47,7 +47,7 @@
flag.Parse()
if flag.NArg() < 1 {
- fmt.Fprintln(os.Stderr, "command is required")
+ fmt.Fprintf(os.Stderr, "%s: error: command is required\n", os.Args[0])
usage()
}
@@ -55,9 +55,9 @@
os.Stdin, os.Stdout, os.Stderr)
if err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
- fmt.Fprintln(os.Stderr, "process exited with error:", exitErr.Error())
+ fmt.Fprintf(os.Stderr, "%s: process exited with error: %s\n", os.Args[0], exitErr.Error())
} else {
- fmt.Fprintln(os.Stderr, "error:", err.Error())
+ fmt.Fprintf(os.Stderr, "%s: error: %s\n", os.Args[0], err.Error())
}
os.Exit(1)
}
@@ -115,6 +115,7 @@
if timeout > 0 {
timeoutCh = time.After(timeout)
}
+ startTime := time.Now()
select {
case err := <-waitCh:
@@ -126,10 +127,12 @@
// Continue below.
}
+ fmt.Fprintf(concurrentStderr, "%s: process timed out after %s\n", os.Args[0], time.Since(startTime))
// Process timed out before exiting.
defer cmd.Process.Signal(syscall.SIGKILL)
if onTimeoutCmdStr != "" {
+ fmt.Fprintf(concurrentStderr, "%s: running on_timeout command `%s`\n", os.Args[0], onTimeoutCmdStr)
onTimeoutCmd := exec.Command("sh", "-c", onTimeoutCmdStr)
onTimeoutCmd.Stdin, onTimeoutCmd.Stdout, onTimeoutCmd.Stderr = stdin, concurrentStdout, concurrentStderr
onTimeoutCmd.Env = append(os.Environ(), fmt.Sprintf("PID=%d", cmd.Process.Pid))
diff --git a/cmd/run_with_timeout/run_with_timeout_test.go b/cmd/run_with_timeout/run_with_timeout_test.go
index aebd336..ed6ec11 100644
--- a/cmd/run_with_timeout/run_with_timeout_test.go
+++ b/cmd/run_with_timeout/run_with_timeout_test.go
@@ -17,6 +17,7 @@
import (
"bytes"
"io"
+ "regexp"
"testing"
"time"
)
@@ -60,7 +61,8 @@
args: []string{"-c", "sleep 1 && echo foo"},
timeout: 1 * time.Millisecond,
},
- wantErr: true,
+ wantStderr: ".*: process timed out after .*\n",
+ wantErr: true,
},
{
name: "on_timeout command",
@@ -71,6 +73,7 @@
onTimeoutCmd: "echo bar",
},
wantStdout: "bar\n",
+ wantStderr: ".*: process timed out after .*\n.*: running on_timeout command `echo bar`\n",
wantErr: true,
},
}
@@ -86,7 +89,7 @@
if gotStdout := stdout.String(); gotStdout != tt.wantStdout {
t.Errorf("runWithTimeout() gotStdout = %v, want %v", gotStdout, tt.wantStdout)
}
- if gotStderr := stderr.String(); gotStderr != tt.wantStderr {
+ if gotStderr := stderr.String(); !regexp.MustCompile(tt.wantStderr).MatchString(gotStderr) {
t.Errorf("runWithTimeout() gotStderr = %v, want %v", gotStderr, tt.wantStderr)
}
})
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 0336fb6..af935db 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -44,6 +44,8 @@
docFile string
bazelQueryViewDir string
bp2buildMarker string
+
+ cmdlineArgs bootstrap.Args
)
func init() {
@@ -61,6 +63,21 @@
flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output")
flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top")
flag.StringVar(&bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
+
+ flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
+ flag.StringVar(&cmdlineArgs.GlobFile, "globFile", "build-globs.ninja", "the Ninja file of globs to output")
+ flag.StringVar(&cmdlineArgs.GlobListDir, "globListDir", "", "the directory containing the glob list files")
+ flag.StringVar(&cmdlineArgs.BuildDir, "b", ".", "the build output directory")
+ flag.StringVar(&cmdlineArgs.NinjaBuildDir, "n", "", "the ninja builddir directory")
+ flag.StringVar(&cmdlineArgs.DepFile, "d", "", "the dependency file to output")
+ flag.StringVar(&cmdlineArgs.Cpuprofile, "cpuprofile", "", "write cpu profile to file")
+ flag.StringVar(&cmdlineArgs.TraceFile, "trace", "", "write trace to file")
+ flag.StringVar(&cmdlineArgs.Memprofile, "memprofile", "", "write memory profile to file")
+ flag.BoolVar(&cmdlineArgs.NoGC, "nogc", false, "turn off GC for debugging")
+ flag.BoolVar(&cmdlineArgs.RunGoTests, "t", false, "build and run go tests during bootstrap")
+ flag.BoolVar(&cmdlineArgs.UseValidations, "use-validations", false, "use validations to depend on go tests")
+ flag.StringVar(&cmdlineArgs.ModuleListFile, "l", "", "file that lists filepaths to parse")
+ flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
}
func newNameResolver(config android.Config) *android.NameResolver {
@@ -90,8 +107,8 @@
return ctx
}
-func newConfig(srcDir, outDir string, availableEnv map[string]string) android.Config {
- configuration, err := android.NewConfig(srcDir, outDir, bootstrap.CmdlineArgs.ModuleListFile, availableEnv)
+func newConfig(outDir string, availableEnv map[string]string) android.Config {
+ configuration, err := android.NewConfig(outDir, cmdlineArgs.ModuleListFile, availableEnv)
if err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
@@ -107,7 +124,7 @@
func runMixedModeBuild(configuration android.Config, firstCtx *android.Context, extraNinjaDeps []string) {
var firstArgs, secondArgs bootstrap.Args
- firstArgs = bootstrap.CmdlineArgs
+ firstArgs = cmdlineArgs
configuration.SetStopBefore(bootstrap.StopBeforeWriteNinja)
bootstrap.RunBlueprint(firstArgs, firstCtx.Context, configuration)
@@ -123,7 +140,7 @@
os.Exit(1)
}
secondCtx := newContext(secondConfig, true)
- secondArgs = bootstrap.CmdlineArgs
+ secondArgs = cmdlineArgs
ninjaDeps := bootstrap.RunBlueprint(secondArgs, secondCtx.Context, secondConfig)
ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
err = deptools.WriteDepFile(shared.JoinPath(topDir, secondArgs.DepFile), secondArgs.OutFile, ninjaDeps)
@@ -145,7 +162,7 @@
func runSoongDocs(configuration android.Config) {
ctx := newContext(configuration, false)
- soongDocsArgs := bootstrap.CmdlineArgs
+ soongDocsArgs := cmdlineArgs
bootstrap.RunBlueprint(soongDocsArgs, ctx.Context, configuration)
if err := writeDocs(ctx, configuration, docFile); err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
@@ -183,7 +200,7 @@
generateQueryView := bazelQueryViewDir != ""
jsonModuleFile := configuration.Getenv("SOONG_DUMP_JSON_MODULE_GRAPH")
- blueprintArgs := bootstrap.CmdlineArgs
+ blueprintArgs := cmdlineArgs
prepareBuildActions := !generateQueryView && jsonModuleFile == ""
if bazelConversionRequested {
// Run the alternate pipeline of bp2build mutators and singleton to convert
@@ -208,16 +225,16 @@
// Convert the Soong module graph into Bazel BUILD files.
if generateQueryView {
runQueryView(configuration, ctx)
- return bootstrap.CmdlineArgs.OutFile // TODO: This is a lie
+ return cmdlineArgs.OutFile // TODO: This is a lie
}
if jsonModuleFile != "" {
writeJsonModuleGraph(configuration, ctx, jsonModuleFile, extraNinjaDeps)
- return bootstrap.CmdlineArgs.OutFile // TODO: This is a lie
+ return cmdlineArgs.OutFile // TODO: This is a lie
}
writeMetrics(configuration)
- return bootstrap.CmdlineArgs.OutFile
+ return cmdlineArgs.OutFile
}
// soong_ui dumps the available environment variables to
@@ -256,9 +273,7 @@
availableEnv := parseAvailableEnv()
- // The top-level Blueprints file is passed as the first argument.
- srcDir := filepath.Dir(flag.Arg(0))
- configuration := newConfig(srcDir, outDir, availableEnv)
+ configuration := newConfig(outDir, availableEnv)
extraNinjaDeps := []string{
configuration.ProductVariablesFileName,
usedEnvFile,
@@ -420,7 +435,7 @@
// Read the bazel.list file that the Soong Finder already dumped earlier (hopefully)
// It contains the locations of BUILD files, BUILD.bazel files, etc. in the source dir
func getExistingBazelRelatedFiles(topDir string) ([]string, error) {
- bazelFinderFile := filepath.Join(filepath.Dir(bootstrap.CmdlineArgs.ModuleListFile), "bazel.list")
+ bazelFinderFile := filepath.Join(filepath.Dir(cmdlineArgs.ModuleListFile), "bazel.list")
if !filepath.IsAbs(bazelFinderFile) {
// Assume this was a relative path under topDir
bazelFinderFile = filepath.Join(topDir, bazelFinderFile)
@@ -451,8 +466,8 @@
// Android.bp files. It must not depend on the values of per-build product
// configurations or variables, since those will generate different BUILD
// files based on how the user has configured their tree.
- bp2buildCtx.SetModuleListFile(bootstrap.CmdlineArgs.ModuleListFile)
- modulePaths, err := bp2buildCtx.ListModulePaths(configuration.SrcDir())
+ bp2buildCtx.SetModuleListFile(cmdlineArgs.ModuleListFile)
+ modulePaths, err := bp2buildCtx.ListModulePaths(".")
if err != nil {
panic(err)
}
@@ -465,11 +480,17 @@
// Run the loading and analysis pipeline to prepare the graph of regular
// Modules parsed from Android.bp files, and the BazelTargetModules mapped
// from the regular Modules.
- blueprintArgs := bootstrap.CmdlineArgs
+ blueprintArgs := cmdlineArgs
ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, bp2buildCtx.Context, configuration)
ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
- ninjaDeps = append(ninjaDeps, bootstrap.GlobFileListFiles(configuration)...)
+ // Generate out/soong/.bootstrap/build-globs.ninja with the actions to generate flattened globfiles
+ // containing the globs seen during bp2build conversion
+ if blueprintArgs.GlobFile != "" {
+ bootstrap.WriteBuildGlobsNinjaFile(blueprintArgs.GlobListDir, bp2buildCtx.Context, blueprintArgs, configuration)
+ }
+ // Add the depfile on the expanded globs in out/soong/.primary/globs
+ ninjaDeps = append(ninjaDeps, bootstrap.GlobFileListFiles(configuration, blueprintArgs.GlobListDir)...)
// Run the code-generation phase to convert BazelTargetModules to BUILD files
// and print conversion metrics to the user.
@@ -487,8 +508,8 @@
"bazel-" + filepath.Base(topDir),
}
- if bootstrap.CmdlineArgs.NinjaBuildDir[0] != '/' {
- excludes = append(excludes, bootstrap.CmdlineArgs.NinjaBuildDir)
+ if cmdlineArgs.NinjaBuildDir[0] != '/' {
+ excludes = append(excludes, cmdlineArgs.NinjaBuildDir)
}
existingBazelRelatedFiles, err := getExistingBazelRelatedFiles(topDir)
@@ -503,7 +524,7 @@
excludes = append(excludes, getTemporaryExcludes()...)
symlinkForestDeps := bp2build.PlantSymlinkForest(
- topDir, workspaceRoot, generatedRoot, configuration.SrcDir(), excludes)
+ topDir, workspaceRoot, generatedRoot, ".", excludes)
// Only report metrics when in bp2build mode. The metrics aren't relevant
// for queryview, since that's a total repo-wide conversion and there's a
@@ -522,12 +543,4 @@
// Create an empty bp2build marker file.
touch(shared.JoinPath(topDir, bp2buildMarker))
-
- // bp2build *always* writes a fake Ninja file containing just the nothing
- // phony target if it ever re-runs. This allows bp2build to exit early with
- // GENERATE_BAZEL_FILES=1 m nothing.
- //
- // If bp2build is invoked as part of an integrated mixed build, the fake
- // build.ninja file will be rewritten later into the real file anyway.
- writeFakeNinjaFile(extraNinjaDeps, codegenContext.Config().BuildDir())
}
diff --git a/cmd/soong_ui/Android.bp b/cmd/soong_ui/Android.bp
index 4f5eea9..9f10b82 100644
--- a/cmd/soong_ui/Android.bp
+++ b/cmd/soong_ui/Android.bp
@@ -20,6 +20,7 @@
name: "soong_ui",
deps: [
"soong-ui-build",
+ "soong-ui-signal",
"soong-ui-logger",
"soong-ui-terminal",
"soong-ui-tracer",
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 02c5229..d709787 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -30,6 +30,7 @@
"android/soong/ui/build"
"android/soong/ui/logger"
"android/soong/ui/metrics"
+ "android/soong/ui/signal"
"android/soong/ui/status"
"android/soong/ui/terminal"
"android/soong/ui/tracer"
@@ -190,7 +191,7 @@
stat.AddOutput(trace.StatusTracer())
// Set up a cleanup procedure in case the normal termination process doesn't work.
- build.SetupSignals(log, cancel, func() {
+ signal.SetupSignals(log, cancel, func() {
trace.Close()
log.Cleanup()
stat.Finish()
diff --git a/cuj/Android.bp b/cuj/Android.bp
index a2da6e6..f9cfdc1 100644
--- a/cuj/Android.bp
+++ b/cuj/Android.bp
@@ -7,6 +7,7 @@
deps: [
"soong-ui-build",
"soong-ui-logger",
+ "soong-ui-signal",
"soong-ui-terminal",
"soong-ui-tracer",
],
diff --git a/cuj/cuj.go b/cuj/cuj.go
index b4ae9a2..413f423 100644
--- a/cuj/cuj.go
+++ b/cuj/cuj.go
@@ -27,6 +27,7 @@
"android/soong/ui/build"
"android/soong/ui/logger"
"android/soong/ui/metrics"
+ "android/soong/ui/signal"
"android/soong/ui/status"
"android/soong/ui/terminal"
"android/soong/ui/tracer"
@@ -65,7 +66,7 @@
stat.AddOutput(output)
stat.AddOutput(trace.StatusTracer())
- build.SetupSignals(log, cancel, func() {
+ signal.SetupSignals(log, cancel, func() {
trace.Close()
log.Cleanup()
stat.Finish()
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index 245af2c..ebb8959 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -193,6 +193,9 @@
// The name of the library.
Name string
+ // If the library is optional or required.
+ Optional bool
+
// On-host build path to the library dex file (used in dex2oat argument --class-loader-context).
Host android.Path
@@ -256,7 +259,7 @@
// Add class loader context for the given library to the map entry for the given SDK version.
func (clcMap ClassLoaderContextMap) addContext(ctx android.ModuleInstallPathContext, sdkVer int, lib string,
- hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) error {
+ optional bool, hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) error {
// For prebuilts, library should have the same name as the source module.
lib = android.RemoveOptionalPrebuiltPrefix(lib)
@@ -304,6 +307,7 @@
clcMap[sdkVer] = append(clcMap[sdkVer], &ClassLoaderContext{
Name: lib,
+ Optional: optional,
Host: hostPath,
Device: devicePath,
Subcontexts: subcontexts,
@@ -316,9 +320,9 @@
// about paths). For the subset of libraries that are used in dexpreopt, their build/install paths
// are validated later before CLC is used (in validateClassLoaderContext).
func (clcMap ClassLoaderContextMap) AddContext(ctx android.ModuleInstallPathContext, sdkVer int,
- lib string, hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) {
+ lib string, optional bool, hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) {
- err := clcMap.addContext(ctx, sdkVer, lib, hostPath, installPath, nestedClcMap)
+ err := clcMap.addContext(ctx, sdkVer, lib, optional, hostPath, installPath, nestedClcMap)
if err != nil {
ctx.ModuleErrorf(err.Error())
}
@@ -361,15 +365,21 @@
// Returns top-level libraries in the CLC (conditional CLC, i.e. compatibility libraries are not
// included). This is the list of libraries that should be in the <uses-library> tags in the
// manifest. Some of them may be present in the source manifest, others are added by manifest_fixer.
-func (clcMap ClassLoaderContextMap) UsesLibs() (ulibs []string) {
+// Required and optional libraries are in separate lists.
+func (clcMap ClassLoaderContextMap) UsesLibs() (required []string, optional []string) {
if clcMap != nil {
clcs := clcMap[AnySdkVersion]
- ulibs = make([]string, 0, len(clcs))
+ required = make([]string, 0, len(clcs))
+ optional = make([]string, 0, len(clcs))
for _, clc := range clcs {
- ulibs = append(ulibs, clc.Name)
+ if clc.Optional {
+ optional = append(optional, clc.Name)
+ } else {
+ required = append(required, clc.Name)
+ }
}
}
- return ulibs
+ return required, optional
}
func (clcMap ClassLoaderContextMap) Dump() string {
@@ -388,7 +398,8 @@
// TODO(b/132357300): remove "android.hidl.manager" and "android.hidl.base" for non-system apps.
//
func fixClassLoaderContext(clcMap ClassLoaderContextMap) {
- usesLibs := clcMap.UsesLibs()
+ required, optional := clcMap.UsesLibs()
+ usesLibs := append(required, optional...)
for sdkVer, clcs := range clcMap {
if sdkVer == AnySdkVersion {
diff --git a/dexpreopt/class_loader_context_test.go b/dexpreopt/class_loader_context_test.go
index 610a4c9..0b7b546 100644
--- a/dexpreopt/class_loader_context_test.go
+++ b/dexpreopt/class_loader_context_test.go
@@ -49,32 +49,34 @@
//
ctx := testContext()
+ optional := false
+
m := make(ClassLoaderContextMap)
- m.AddContext(ctx, AnySdkVersion, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
- m.AddContext(ctx, AnySdkVersion, "b", buildPath(ctx, "b"), installPath(ctx, "b"), nil)
- m.AddContext(ctx, AnySdkVersion, "c", buildPath(ctx, "c"), installPath(ctx, "c"), nil)
+ m.AddContext(ctx, AnySdkVersion, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+ m.AddContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
+ m.AddContext(ctx, AnySdkVersion, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
// Add some libraries with nested subcontexts.
m1 := make(ClassLoaderContextMap)
- m1.AddContext(ctx, AnySdkVersion, "a1", buildPath(ctx, "a1"), installPath(ctx, "a1"), nil)
- m1.AddContext(ctx, AnySdkVersion, "b1", buildPath(ctx, "b1"), installPath(ctx, "b1"), nil)
+ m1.AddContext(ctx, AnySdkVersion, "a1", optional, buildPath(ctx, "a1"), installPath(ctx, "a1"), nil)
+ m1.AddContext(ctx, AnySdkVersion, "b1", optional, buildPath(ctx, "b1"), installPath(ctx, "b1"), nil)
m2 := make(ClassLoaderContextMap)
- m2.AddContext(ctx, AnySdkVersion, "a2", buildPath(ctx, "a2"), installPath(ctx, "a2"), nil)
- m2.AddContext(ctx, AnySdkVersion, "b2", buildPath(ctx, "b2"), installPath(ctx, "b2"), nil)
- m2.AddContext(ctx, AnySdkVersion, "c2", buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
+ m2.AddContext(ctx, AnySdkVersion, "a2", optional, buildPath(ctx, "a2"), installPath(ctx, "a2"), nil)
+ m2.AddContext(ctx, AnySdkVersion, "b2", optional, buildPath(ctx, "b2"), installPath(ctx, "b2"), nil)
+ m2.AddContext(ctx, AnySdkVersion, "c2", optional, buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
m3 := make(ClassLoaderContextMap)
- m3.AddContext(ctx, AnySdkVersion, "a3", buildPath(ctx, "a3"), installPath(ctx, "a3"), nil)
- m3.AddContext(ctx, AnySdkVersion, "b3", buildPath(ctx, "b3"), installPath(ctx, "b3"), nil)
+ m3.AddContext(ctx, AnySdkVersion, "a3", optional, buildPath(ctx, "a3"), installPath(ctx, "a3"), nil)
+ m3.AddContext(ctx, AnySdkVersion, "b3", optional, buildPath(ctx, "b3"), installPath(ctx, "b3"), nil)
- m.AddContext(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), m2)
+ m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), m2)
// When the same library is both in conditional and unconditional context, it should be removed
// from conditional context.
- m.AddContext(ctx, 42, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
- m.AddContext(ctx, AnySdkVersion, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
+ m.AddContext(ctx, 42, "f", optional, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
+ m.AddContext(ctx, AnySdkVersion, "f", optional, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
// Merge map with implicit root library that is among toplevel contexts => does nothing.
m.AddContextMap(m1, "c")
@@ -83,12 +85,12 @@
m.AddContextMap(m3, "m_g")
// Compatibility libraries with unknown install paths get default paths.
- m.AddContext(ctx, 29, AndroidHidlManager, buildPath(ctx, AndroidHidlManager), nil, nil)
- m.AddContext(ctx, 29, AndroidHidlBase, buildPath(ctx, AndroidHidlBase), nil, nil)
+ m.AddContext(ctx, 29, AndroidHidlManager, optional, buildPath(ctx, AndroidHidlManager), nil, nil)
+ m.AddContext(ctx, 29, AndroidHidlBase, optional, buildPath(ctx, AndroidHidlBase), nil, nil)
// Add "android.test.mock" to conditional CLC, observe that is gets removed because it is only
// needed as a compatibility library if "android.test.runner" is in CLC as well.
- m.AddContext(ctx, 30, AndroidTestMock, buildPath(ctx, AndroidTestMock), nil, nil)
+ m.AddContext(ctx, 30, AndroidTestMock, optional, buildPath(ctx, AndroidTestMock), nil, nil)
valid, validationError := validateClassLoaderContext(m)
@@ -96,10 +98,10 @@
var haveStr string
var havePaths android.Paths
- var haveUsesLibs []string
+ var haveUsesLibsReq, haveUsesLibsOpt []string
if valid && validationError == nil {
haveStr, havePaths = ComputeClassLoaderContext(m)
- haveUsesLibs = m.UsesLibs()
+ haveUsesLibsReq, haveUsesLibsOpt = m.UsesLibs()
}
// Test that validation is successful (all paths are known).
@@ -148,20 +150,25 @@
// Test for libraries that are added by the manifest_fixer.
t.Run("uses libs", func(t *testing.T) {
- wantUsesLibs := []string{"a", "b", "c", "d", "f", "a3", "b3"}
- if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
- t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
+ wantUsesLibsReq := []string{"a", "b", "c", "d", "f", "a3", "b3"}
+ wantUsesLibsOpt := []string{}
+ if !reflect.DeepEqual(wantUsesLibsReq, haveUsesLibsReq) {
+ t.Errorf("\nwant required uses libs: %s\nhave required uses libs: %s", wantUsesLibsReq, haveUsesLibsReq)
+ }
+ if !reflect.DeepEqual(wantUsesLibsOpt, haveUsesLibsOpt) {
+ t.Errorf("\nwant optional uses libs: %s\nhave optional uses libs: %s", wantUsesLibsOpt, haveUsesLibsOpt)
}
})
}
func TestCLCJson(t *testing.T) {
ctx := testContext()
+ optional := false
m := make(ClassLoaderContextMap)
- m.AddContext(ctx, 28, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
- m.AddContext(ctx, 29, "b", buildPath(ctx, "b"), installPath(ctx, "b"), nil)
- m.AddContext(ctx, 30, "c", buildPath(ctx, "c"), installPath(ctx, "c"), nil)
- m.AddContext(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), nil)
+ m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+ m.AddContext(ctx, 29, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
+ m.AddContext(ctx, 30, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
+ m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), nil)
jsonCLC := toJsonClassLoaderContext(m)
restored := fromJsonClassLoaderContext(ctx, jsonCLC)
android.AssertIntEquals(t, "The size of the maps should be the same.", len(m), len(restored))
@@ -181,20 +188,25 @@
// Test that unknown library paths cause a validation error.
func testCLCUnknownPath(t *testing.T, whichPath string) {
ctx := testContext()
+ optional := false
m := make(ClassLoaderContextMap)
if whichPath == "build" {
- m.AddContext(ctx, AnySdkVersion, "a", nil, nil, nil)
+ m.AddContext(ctx, AnySdkVersion, "a", optional, nil, nil, nil)
} else {
- m.AddContext(ctx, AnySdkVersion, "a", buildPath(ctx, "a"), nil, nil)
+ m.AddContext(ctx, AnySdkVersion, "a", optional, buildPath(ctx, "a"), nil, nil)
}
// The library should be added to <uses-library> tags by the manifest_fixer.
t.Run("uses libs", func(t *testing.T) {
- haveUsesLibs := m.UsesLibs()
- wantUsesLibs := []string{"a"}
- if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
- t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
+ haveUsesLibsReq, haveUsesLibsOpt := m.UsesLibs()
+ wantUsesLibsReq := []string{"a"}
+ wantUsesLibsOpt := []string{}
+ if !reflect.DeepEqual(wantUsesLibsReq, haveUsesLibsReq) {
+ t.Errorf("\nwant required uses libs: %s\nhave required uses libs: %s", wantUsesLibsReq, haveUsesLibsReq)
+ }
+ if !reflect.DeepEqual(wantUsesLibsOpt, haveUsesLibsOpt) {
+ t.Errorf("\nwant optional uses libs: %s\nhave optional uses libs: %s", wantUsesLibsOpt, haveUsesLibsOpt)
}
})
@@ -216,10 +228,11 @@
// An attempt to add conditional nested subcontext should fail.
func TestCLCNestedConditional(t *testing.T) {
ctx := testContext()
+ optional := false
m1 := make(ClassLoaderContextMap)
- m1.AddContext(ctx, 42, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+ m1.AddContext(ctx, 42, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
m := make(ClassLoaderContextMap)
- err := m.addContext(ctx, AnySdkVersion, "b", buildPath(ctx, "b"), installPath(ctx, "b"), m1)
+ err := m.addContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), m1)
checkError(t, err, "nested class loader context shouldn't have conditional part")
}
@@ -227,11 +240,12 @@
// they end up in the order that agrees with PackageManager.
func TestCLCSdkVersionOrder(t *testing.T) {
ctx := testContext()
+ optional := false
m := make(ClassLoaderContextMap)
- m.AddContext(ctx, 28, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
- m.AddContext(ctx, 29, "b", buildPath(ctx, "b"), installPath(ctx, "b"), nil)
- m.AddContext(ctx, 30, "c", buildPath(ctx, "c"), installPath(ctx, "c"), nil)
- m.AddContext(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), nil)
+ m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+ m.AddContext(ctx, 29, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
+ m.AddContext(ctx, 30, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
+ m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), nil)
valid, validationError := validateClassLoaderContext(m)
diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go
index 2f99655..8f5c315 100644
--- a/dexpreopt/testing.go
+++ b/dexpreopt/testing.go
@@ -125,6 +125,20 @@
})
}
+// FixtureSetSystemServerJars sets the SystemServerJars property.
+func FixtureSetSystemServerJars(jars ...string) android.FixturePreparer {
+ return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
+ dexpreoptConfig.SystemServerJars = android.CreateTestConfiguredJarList(jars)
+ })
+}
+
+// FixtureSetApexSystemServerJars sets the ApexSystemServerJars property in the global config.
+func FixtureSetApexSystemServerJars(jars ...string) android.FixturePreparer {
+ return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
+ dexpreoptConfig.ApexSystemServerJars = android.CreateTestConfiguredJarList(jars)
+ })
+}
+
// FixtureSetPreoptWithUpdatableBcp sets the PreoptWithUpdatableBcp property in the global config.
func FixtureSetPreoptWithUpdatableBcp(value bool) android.FixturePreparer {
return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
diff --git a/fuzz/Android.bp b/fuzz/Android.bp
new file mode 100644
index 0000000..9d96e48
--- /dev/null
+++ b/fuzz/Android.bp
@@ -0,0 +1,15 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-fuzz",
+ pkgPath: "android/soong/fuzz",
+ deps: [
+ "soong-android",
+ ],
+ srcs: [
+ "fuzz_common.go",
+ ],
+ pluginFor: ["soong_build"],
+}
diff --git a/cc/fuzz_common.go b/fuzz/fuzz_common.go
similarity index 73%
rename from cc/fuzz_common.go
rename to fuzz/fuzz_common.go
index 98ed7f4..ccadc0f 100644
--- a/cc/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -12,14 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package cc
+package fuzz
// This file contains the common code for compiling C/C++ and Rust fuzzers for Android.
import (
+ "encoding/json"
"sort"
"strings"
+ "github.com/google/blueprint/proptools"
+
"android/soong/android"
)
@@ -30,6 +33,8 @@
Rust Lang = "rust"
)
+var BoolDefault = proptools.BoolDefault
+
type FuzzModule struct {
android.ModuleBase
android.DefaultableModuleBase
@@ -52,6 +57,44 @@
Dir string
}
+type FuzzConfig struct {
+ // Email address of people to CC on bugs or contact about this fuzz target.
+ Cc []string `json:"cc,omitempty"`
+ // Specify whether to enable continuous fuzzing on devices. Defaults to true.
+ Fuzz_on_haiku_device *bool `json:"fuzz_on_haiku_device,omitempty"`
+ // Specify whether to enable continuous fuzzing on host. Defaults to true.
+ Fuzz_on_haiku_host *bool `json:"fuzz_on_haiku_host,omitempty"`
+ // Component in Google's bug tracking system that bugs should be filed to.
+ Componentid *int64 `json:"componentid,omitempty"`
+ // Hotlists in Google's bug tracking system that bugs should be marked with.
+ Hotlists []string `json:"hotlists,omitempty"`
+ // Specify whether this fuzz target was submitted by a researcher. Defaults
+ // to false.
+ Researcher_submitted *bool `json:"researcher_submitted,omitempty"`
+ // Specify who should be acknowledged for CVEs in the Android Security
+ // Bulletin.
+ Acknowledgement []string `json:"acknowledgement,omitempty"`
+ // Additional options to be passed to libfuzzer when run in Haiku.
+ Libfuzzer_options []string `json:"libfuzzer_options,omitempty"`
+ // Additional options to be passed to HWASAN when running on-device in Haiku.
+ Hwasan_options []string `json:"hwasan_options,omitempty"`
+ // Additional options to be passed to HWASAN when running on host in Haiku.
+ Asan_options []string `json:"asan_options,omitempty"`
+}
+
+type FuzzProperties struct {
+ // Optional list of seed files to be installed to the fuzz target's output
+ // directory.
+ Corpus []string `android:"path"`
+ // Optional list of data files to be installed to the fuzz target's output
+ // directory. Directory structure relative to the module is preserved.
+ Data []string `android:"path"`
+ // Optional dictionary to be installed to the fuzz target's output directory.
+ Dictionary *string `android:"path"`
+ // Config for running the target on fuzzing infrastructure.
+ Fuzz_config *FuzzConfig
+}
+
type FuzzPackagedModule struct {
FuzzProperties FuzzProperties
Dictionary android.Path
@@ -151,7 +194,16 @@
return archDirs[archOs], true
}
-func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, lang Lang) {
+func (f *FuzzConfig) String() string {
+ b, err := json.Marshal(f)
+ if err != nil {
+ panic(err)
+ }
+
+ return string(b)
+}
+
+func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, lang Lang, pctx android.PackageContext) {
var archOsList []ArchOs
for archOs := range archDirs {
archOsList = append(archOsList, archOs)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 71a8780..fdb3618 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -240,7 +240,7 @@
}
// Returns true if information was available from Bazel, false if bazel invocation still needs to occur.
-func (c *Module) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+func (c *Module) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
filePaths, ok := bazelCtx.GetOutputFiles(label, ctx.Arch().ArchType)
if ok {
@@ -560,7 +560,7 @@
bazelModuleLabel := g.GetBazelLabel(ctx, g)
bazelActionsUsed := false
if g.MixedBuildsEnabled(ctx) {
- bazelActionsUsed = g.generateBazelBuildActions(ctx, bazelModuleLabel)
+ bazelActionsUsed = g.GenerateBazelBuildActions(ctx, bazelModuleLabel)
}
if !bazelActionsUsed {
// For <= 6 outputs, just embed those directly in the users. Right now, that covers >90% of
diff --git a/java/aar.go b/java/aar.go
index 04727e4..afbaea2 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -502,11 +502,12 @@
if sdkDep.hasFrameworkLibs() {
a.aapt.deps(ctx, sdkDep)
}
+ a.usesLibrary.deps(ctx, sdkDep.hasFrameworkLibs())
}
func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.aapt.isLibrary = true
- a.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
+ a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts)
a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 331f941..1f7234d 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -71,12 +71,12 @@
args = append(args, "--use-embedded-dex")
}
- for _, usesLib := range classLoaderContexts.UsesLibs() {
- if inList(usesLib, dexpreopt.OptionalCompatUsesLibs) {
- args = append(args, "--optional-uses-library", usesLib)
- } else {
- args = append(args, "--uses-library", usesLib)
- }
+ requiredUsesLibs, optionalUsesLibs := classLoaderContexts.UsesLibs()
+ for _, usesLib := range requiredUsesLibs {
+ args = append(args, "--uses-library", usesLib)
+ }
+ for _, usesLib := range optionalUsesLibs {
+ args = append(args, "--optional-uses-library", usesLib)
}
if hasNoCode {
diff --git a/java/androidmk.go b/java/androidmk.go
index 04357e0..68ccd82 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -114,7 +114,8 @@
entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile)
}
- entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.classLoaderContexts.UsesLibs()...)
+ requiredUsesLibs, optionalUsesLibs := library.classLoaderContexts.UsesLibs()
+ entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", append(requiredUsesLibs, optionalUsesLibs...)...)
if len(library.additionalCheckedModules) != 0 {
entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...)
diff --git a/java/app.go b/java/app.go
index 35ed27f..99e2ab6 100755
--- a/java/app.go
+++ b/java/app.go
@@ -649,8 +649,12 @@
a.usesLibrary.freezeEnforceUsesLibraries()
// Add implicit SDK libraries to <uses-library> list.
- for _, usesLib := range a.classLoaderContexts.UsesLibs() {
- a.usesLibrary.addLib(usesLib, inList(usesLib, dexpreopt.OptionalCompatUsesLibs))
+ requiredUsesLibs, optionalUsesLibs := a.classLoaderContexts.UsesLibs()
+ for _, usesLib := range requiredUsesLibs {
+ a.usesLibrary.addLib(usesLib, false)
+ }
+ for _, usesLib := range optionalUsesLibs {
+ a.usesLibrary.addLib(usesLib, true)
}
// Check that the <uses-library> list is coherent with the manifest.
@@ -1220,17 +1224,17 @@
func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs bool) {
if !ctx.Config().UnbundledBuild() || ctx.Config().UnbundledBuildImage() {
- ctx.AddVariationDependencies(nil, usesLibTag, u.usesLibraryProperties.Uses_libs...)
- ctx.AddVariationDependencies(nil, usesLibTag, u.presentOptionalUsesLibs(ctx)...)
+ ctx.AddVariationDependencies(nil, usesLibReqTag, u.usesLibraryProperties.Uses_libs...)
+ ctx.AddVariationDependencies(nil, usesLibOptTag, u.presentOptionalUsesLibs(ctx)...)
// Only add these extra dependencies if the module depends on framework libs. This avoids
// creating a cyclic dependency:
// e.g. framework-res -> org.apache.http.legacy -> ... -> framework-res.
if hasFrameworkLibs {
// Dexpreopt needs paths to the dex jars of these libraries in order to construct
// class loader context for dex2oat. Add them as a dependency with a special tag.
- ctx.AddVariationDependencies(nil, usesLibCompat29Tag, dexpreopt.CompatUsesLibs29...)
- ctx.AddVariationDependencies(nil, usesLibCompat28Tag, dexpreopt.OptionalCompatUsesLibs28...)
- ctx.AddVariationDependencies(nil, usesLibCompat30Tag, dexpreopt.OptionalCompatUsesLibs30...)
+ ctx.AddVariationDependencies(nil, usesLibCompat29ReqTag, dexpreopt.CompatUsesLibs29...)
+ ctx.AddVariationDependencies(nil, usesLibCompat28OptTag, dexpreopt.OptionalCompatUsesLibs28...)
+ ctx.AddVariationDependencies(nil, usesLibCompat30OptTag, dexpreopt.OptionalCompatUsesLibs30...)
}
}
}
@@ -1289,7 +1293,7 @@
replaceInList(u.usesLibraryProperties.Uses_libs, dep, libName)
replaceInList(u.usesLibraryProperties.Optional_uses_libs, dep, libName)
}
- clcMap.AddContext(ctx, tag.sdkVersion, libName,
+ clcMap.AddContext(ctx, tag.sdkVersion, libName, tag.optional,
lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ClassLoaderContexts())
} else if ctx.Config().AllowMissingDependencies() {
ctx.AddMissingDependencies([]string{dep})
diff --git a/java/app_import.go b/java/app_import.go
index 5a87b07..b5a6084 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -410,6 +410,10 @@
return android.SdkSpecPrivate
}
+func (a *AndroidAppImport) LintDepSets() LintDepSets {
+ return LintDepSets{}
+}
+
var _ android.ApexModule = (*AndroidAppImport)(nil)
// Implements android.ApexModule
diff --git a/java/app_test.go b/java/app_test.go
index 7997f7a..8de6691 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2355,8 +2355,8 @@
`--uses-library quuz ` +
`--uses-library foo ` + // TODO(b/132357300): "foo" should not be passed to manifest_fixer
`--uses-library com.non.sdk.lib ` + // TODO(b/132357300): "com.non.sdk.lib" should not be passed to manifest_fixer
- `--uses-library bar ` + // TODO(b/132357300): "bar" should not be passed to manifest_fixer
- `--uses-library runtime-library`
+ `--uses-library runtime-library ` +
+ `--optional-uses-library bar` // TODO(b/132357300): "bar" should not be passed to manifest_fixer
android.AssertStringEquals(t, "manifest_fixer args", expectManifestFixerArgs, actualManifestFixerArgs)
// Test that all libraries are verified (library order matters).
diff --git a/java/base.go b/java/base.go
index 6b81196..ea5b137 100644
--- a/java/base.go
+++ b/java/base.go
@@ -605,7 +605,12 @@
if dep != nil {
if component, ok := dep.(SdkLibraryComponentDependency); ok {
if lib := component.OptionalSdkLibraryImplementation(); lib != nil {
- ctx.AddVariationDependencies(nil, usesLibTag, *lib)
+ // Add library as optional if it's one of the optional compatibility libs.
+ tag := usesLibReqTag
+ if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) {
+ tag = usesLibOptTag
+ }
+ ctx.AddVariationDependencies(nil, tag, *lib)
}
}
}
@@ -1230,7 +1235,7 @@
}
// Dex compilation
var dexOutputFile android.OutputPath
- dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), outputFile, jarName)
+ dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), implementationAndResourcesJar, jarName)
if ctx.Failed() {
return
}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 107d34a..bb542c4 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -579,6 +579,14 @@
common := ctx.Module().(commonBootclasspathFragment)
output := common.produceHiddenAPIOutput(ctx, contents, input)
+ // If the source or prebuilts module does not provide a signature patterns file then generate one
+ // from the flags.
+ // TODO(b/192868581): Remove once the source and prebuilts provide a signature patterns file of
+ // their own.
+ if output.SignaturePatternsPath == nil {
+ output.SignaturePatternsPath = buildRuleSignaturePatternsFile(ctx, output.AllFlagsPath)
+ }
+
// Initialize a HiddenAPIInfo structure.
hiddenAPIInfo := HiddenAPIInfo{
// The monolithic hidden API processing needs access to the flag files that override the default
@@ -744,9 +752,6 @@
// Flag files by *hiddenAPIFlagFileCategory
Flag_files_by_category FlagFilesByCategory
- // The path to the generated stub-flags.csv file.
- Stub_flags_path android.OptionalPath
-
// The path to the generated annotation-flags.csv file.
Annotation_flags_path android.OptionalPath
@@ -756,6 +761,12 @@
// The path to the generated index.csv file.
Index_path android.OptionalPath
+ // The path to the generated signature-patterns.csv file.
+ Signature_patterns_path android.OptionalPath
+
+ // The path to the generated stub-flags.csv file.
+ Stub_flags_path android.OptionalPath
+
// The path to the generated all-flags.csv file.
All_flags_path android.OptionalPath
}
@@ -772,10 +783,12 @@
b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory
// Copy all the generated file paths.
- b.Stub_flags_path = android.OptionalPathForPath(hiddenAPIInfo.StubFlagsPath)
b.Annotation_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AnnotationFlagsPath)
b.Metadata_path = android.OptionalPathForPath(hiddenAPIInfo.MetadataPath)
b.Index_path = android.OptionalPathForPath(hiddenAPIInfo.IndexPath)
+
+ b.Signature_patterns_path = android.OptionalPathForPath(hiddenAPIInfo.SignaturePatternsPath)
+ b.Stub_flags_path = android.OptionalPathForPath(hiddenAPIInfo.StubFlagsPath)
b.All_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AllFlagsPath)
// Copy stub_libs properties.
@@ -839,10 +852,11 @@
}
// Copy all the generated files, if available.
- copyOptionalPath(b.Stub_flags_path, "stub_flags")
copyOptionalPath(b.Annotation_flags_path, "annotation_flags")
copyOptionalPath(b.Metadata_path, "metadata")
copyOptionalPath(b.Index_path, "index")
+ copyOptionalPath(b.Signature_patterns_path, "signature_patterns")
+ copyOptionalPath(b.Stub_flags_path, "stub_flags")
copyOptionalPath(b.All_flags_path, "all_flags")
}
@@ -852,9 +866,6 @@
// specific properties.
type prebuiltBootclasspathFragmentProperties struct {
Hidden_api struct {
- // The path to the stub-flags.csv file created by the bootclasspath_fragment.
- Stub_flags *string `android:"path"`
-
// The path to the annotation-flags.csv file created by the bootclasspath_fragment.
Annotation_flags *string `android:"path"`
@@ -864,6 +875,12 @@
// The path to the index.csv file created by the bootclasspath_fragment.
Index *string `android:"path"`
+ // The path to the signature-patterns.csv file created by the bootclasspath_fragment.
+ Signature_patterns *string `android:"path"`
+
+ // The path to the stub-flags.csv file created by the bootclasspath_fragment.
+ Stub_flags *string `android:"path"`
+
// The path to the all-flags.csv file created by the bootclasspath_fragment.
All_flags *string `android:"path"`
}
@@ -892,6 +909,12 @@
// produceHiddenAPIOutput returns a path to the prebuilt all-flags.csv or nil if none is specified.
func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
+ pathForOptionalSrc := func(src *string) android.Path {
+ if src == nil {
+ return nil
+ }
+ return android.PathForModuleSrc(ctx, *src)
+ }
pathForSrc := func(property string, src *string) android.Path {
if src == nil {
ctx.PropertyErrorf(property, "is required but was not specified")
@@ -906,11 +929,12 @@
output := HiddenAPIOutput{
HiddenAPIFlagOutput: HiddenAPIFlagOutput{
- AnnotationFlagsPath: pathForSrc("hidden_api.annotation_flags", module.prebuiltProperties.Hidden_api.Annotation_flags),
- MetadataPath: pathForSrc("hidden_api.metadata", module.prebuiltProperties.Hidden_api.Metadata),
- IndexPath: pathForSrc("hidden_api.index", module.prebuiltProperties.Hidden_api.Index),
- StubFlagsPath: pathForSrc("hidden_api.stub_flags", module.prebuiltProperties.Hidden_api.Stub_flags),
- AllFlagsPath: pathForSrc("hidden_api.all_flags", module.prebuiltProperties.Hidden_api.All_flags),
+ AnnotationFlagsPath: pathForSrc("hidden_api.annotation_flags", module.prebuiltProperties.Hidden_api.Annotation_flags),
+ MetadataPath: pathForSrc("hidden_api.metadata", module.prebuiltProperties.Hidden_api.Metadata),
+ IndexPath: pathForSrc("hidden_api.index", module.prebuiltProperties.Hidden_api.Index),
+ SignaturePatternsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Signature_patterns),
+ StubFlagsPath: pathForSrc("hidden_api.stub_flags", module.prebuiltProperties.Hidden_api.Stub_flags),
+ AllFlagsPath: pathForSrc("hidden_api.all_flags", module.prebuiltProperties.Hidden_api.All_flags),
},
EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
}
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 3d0e155..d3de675 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -164,6 +164,7 @@
prepareForTestWithBootclasspathFragment,
PrepareForTestWithJavaSdkLibraryFiles,
FixtureWithLastReleaseApis("mysdklibrary", "mycoveragestubs"),
+ FixtureConfigureApexBootJars("someapex:mybootlib"),
prepareWithBp,
)
@@ -186,6 +187,7 @@
prepareForTestWithBootclasspathFragment,
PrepareForTestWithJavaSdkLibraryFiles,
FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary", "mycoreplatform"),
+ FixtureConfigureApexBootJars("someapex:mysdklibrary"),
).RunTestWithBp(t, `
bootclasspath_fragment {
name: "myfragment",
diff --git a/java/config/config.go b/java/config/config.go
index 273084c..30c6f91 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -69,8 +69,6 @@
pctx.StaticVariable("JavacHeapSize", "2048M")
pctx.StaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}")
pctx.StaticVariable("DexFlags", "-JXX:OnError='cat hs_err_pid%p.log' -JXX:CICompilerCount=6 -JXX:+UseDynamicNumberOfGCThreads")
- // TODO(b/181095653): remove duplicated flags.
- pctx.StaticVariable("DexJavaFlags", "-XX:OnError='cat hs_err_pid%p.log' -XX:CICompilerCount=6 -XX:+UseDynamicNumberOfGCThreads -Xmx2G")
pctx.StaticVariable("CommonJdkFlags", strings.Join([]string{
`-Xmaxerrs 9999999`,
diff --git a/java/dex.go b/java/dex.go
index 6bf0143..667800f 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -84,19 +84,17 @@
return BoolDefault(d.dexProperties.Optimize.Enabled, d.dexProperties.Optimize.EnabledByDefault)
}
-func init() {
- pctx.HostBinToolVariable("runWithTimeoutCmd", "run_with_timeout")
- pctx.SourcePathVariable("jstackCmd", "${config.JavaToolchain}/jstack")
-}
-
var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8",
blueprint.RuleParams{
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
- `$d8Template${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $in && ` +
+ `mkdir -p $$(dirname $tmpJar) && ` +
+ `${config.Zip2ZipCmd} -i $in -o $tmpJar -x '**/*.dex' && ` +
+ `$d8Template${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $tmpJar && ` +
`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
`${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
CommandDeps: []string{
"${config.D8Cmd}",
+ "${config.Zip2ZipCmd}",
"${config.SoongZipCmd}",
"${config.MergeZipsCmd}",
},
@@ -115,17 +113,16 @@
ExecStrategy: "${config.RED8ExecStrategy}",
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
},
- }, []string{"outDir", "d8Flags", "zipFlags"}, nil)
+ }, []string{"outDir", "d8Flags", "zipFlags", "tmpJar"}, nil)
var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8",
blueprint.RuleParams{
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
`rm -f "$outDict" && rm -rf "${outUsageDir}" && ` +
`mkdir -p $$(dirname ${outUsage}) && ` +
- // TODO(b/181095653): remove R8 timeout and go back to config.R8Cmd.
- `${runWithTimeoutCmd} -timeout 30m -on_timeout '${jstackCmd} $$PID' -- ` +
- `$r8Template${config.JavaCmd} ${config.DexJavaFlags} -cp ${config.R8Jar} ` +
- `com.android.tools.r8.compatproguard.CompatProguard -injars $in --output $outDir ` +
+ `mkdir -p $$(dirname $tmpJar) && ` +
+ `${config.Zip2ZipCmd} -i $in -o $tmpJar -x '**/*.dex' && ` +
+ `$r8Template${config.R8Cmd} ${config.DexFlags} -injars $tmpJar --output $outDir ` +
`--no-data-resources ` +
`-printmapping ${outDict} ` +
`-printusage ${outUsage} ` +
@@ -136,10 +133,10 @@
`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
`${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
CommandDeps: []string{
- "${config.R8Jar}",
+ "${config.R8Cmd}",
+ "${config.Zip2ZipCmd}",
"${config.SoongZipCmd}",
"${config.MergeZipsCmd}",
- "${runWithTimeoutCmd}",
},
}, map[string]*remoteexec.REParams{
"$r8Template": &remoteexec.REParams{
@@ -165,7 +162,7 @@
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
},
}, []string{"outDir", "outDict", "outUsage", "outUsageZip", "outUsageDir",
- "r8Flags", "zipFlags"}, []string{"implicits"})
+ "r8Flags", "zipFlags", "tmpJar"}, []string{"implicits"})
func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion android.SdkSpec) []string {
flags := d.dexProperties.Dxflags
@@ -282,6 +279,7 @@
// Compile classes.jar into classes.dex and then javalib.jar
javalibJar := android.PathForModuleOut(ctx, "dex", jarName).OutputPath
outDir := android.PathForModuleOut(ctx, "dex")
+ tmpJar := android.PathForModuleOut(ctx, "withres-withoutdex", jarName)
zipFlags := "--ignore_missing_files"
if proptools.Bool(d.dexProperties.Uncompress_dex) {
@@ -309,6 +307,7 @@
"outUsage": proguardUsage.String(),
"outUsageZip": proguardUsageZip.String(),
"outDir": outDir.String(),
+ "tmpJar": tmpJar.String(),
}
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") {
rule = r8RE
@@ -339,6 +338,7 @@
"d8Flags": strings.Join(append(commonFlags, d8Flags...), " "),
"zipFlags": zipFlags,
"outDir": outDir.String(),
+ "tmpJar": tmpJar.String(),
},
})
}
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 86ab825..8e39f40 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -297,7 +297,7 @@
//
// The rule is initialized but not built so that the caller can modify it and select an appropriate
// name.
-func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput, moduleStubFlagsPaths android.Paths) {
+func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput, stubFlagSubsets SignatureCsvSubsets) {
// Singleton rule which applies hiddenapi on all boot class path dex files.
rule := android.NewRuleBuilder(pctx, ctx)
@@ -317,7 +317,7 @@
// If no module stub flags paths are provided then this must be being called for a
// bootclasspath_fragment and not the whole platform_bootclasspath.
- if moduleStubFlagsPaths == nil {
+ if stubFlagSubsets == nil {
// This is being run on a fragment of the bootclasspath.
command.Flag("--fragment")
}
@@ -342,8 +342,8 @@
// If there are stub flag files that have been generated by fragments on which this depends then
// use them to validate the stub flag file generated by the rules created by this method.
- if len(moduleStubFlagsPaths) > 0 {
- validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, moduleStubFlagsPaths)
+ if len(stubFlagSubsets) > 0 {
+ validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, stubFlagSubsets)
// Add the file that indicates that the file generated by this is valid.
//
@@ -546,6 +546,20 @@
}
}
+// StubFlagSubset returns a SignatureCsvSubset that contains a path to a stub-flags.csv file and a
+// path to a signature-patterns.csv file that defines a subset of the monolithic stub flags file,
+// i.e. out/soong/hiddenapi/hiddenapi-stub-flags.txt, against which it will be compared.
+func (i *HiddenAPIInfo) StubFlagSubset() SignatureCsvSubset {
+ return SignatureCsvSubset{i.StubFlagsPath, i.SignaturePatternsPath}
+}
+
+// FlagSubset returns a SignatureCsvSubset that contains a path to an all-flags.csv file and a
+// path to a signature-patterns.csv file that defines a subset of the monolithic flags file, i.e.
+// out/soong/hiddenapi/hiddenapi-flags.csv, against which it will be compared.
+func (i *HiddenAPIInfo) FlagSubset() SignatureCsvSubset {
+ return SignatureCsvSubset{i.AllFlagsPath, i.SignaturePatternsPath}
+}
+
var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
// ModuleStubDexJars contains the stub dex jars provided by a single module.
@@ -782,6 +796,10 @@
// The path to the generated all-flags.csv file.
AllFlagsPath android.Path
+
+ // The path to the generated signature-patterns.txt file which defines the subset of the
+ // monolithic hidden API files provided in this.
+ SignaturePatternsPath android.Path
}
// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex
@@ -848,7 +866,7 @@
// the annotationFlags.
func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string,
outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlagPaths android.Paths,
- flagFilesByCategory FlagFilesByCategory, allFlagsPaths android.Paths, generatedRemovedDexSignatures android.OptionalPath) {
+ flagFilesByCategory FlagFilesByCategory, flagSubsets SignatureCsvSubsets, generatedRemovedDexSignatures android.OptionalPath) {
// Create the rule that will generate the flag files.
tempPath := tempPathForRestat(ctx, outputPath)
@@ -877,8 +895,8 @@
// If there are flag files that have been generated by fragments on which this depends then use
// them to validate the flag file generated by the rules created by this method.
- if len(allFlagsPaths) > 0 {
- validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, allFlagsPaths)
+ if len(flagSubsets) > 0 {
+ validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, flagSubsets)
// Add the file that indicates that the file generated by this is valid.
//
@@ -890,20 +908,82 @@
rule.Build(name, desc)
}
+// SignatureCsvSubset describes a subset of a monolithic flags file, i.e. either
+// out/soong/hiddenapi/hiddenapi-stub-flags.txt or out/soong/hiddenapi/hiddenapi-flags.csv
+type SignatureCsvSubset struct {
+ // The path to the CSV file containing hidden API flags.
+ //
+ // It has the dex member signature as the first column, with flags, one per column, in the
+ // subsequent columns.
+ CsvFile android.Path
+
+ // The path to the CSV file containing the signature patterns.
+ //
+ // It is a single column CSV file with the column containing a signature pattern.
+ SignaturePatternsFile android.Path
+}
+
+type SignatureCsvSubsets []SignatureCsvSubset
+
+func (s SignatureCsvSubsets) RelativeToTop() []string {
+ result := []string{}
+ for _, subset := range s {
+ result = append(result, fmt.Sprintf("%s:%s", subset.CsvFile.RelativeToTop(), subset.SignaturePatternsFile.RelativeToTop()))
+ }
+ return result
+}
+
+// buildRuleSignaturePatternsFile creates a rule to generate a file containing the set of signature
+// patterns that will select a subset of the monolithic flags.
+func buildRuleSignaturePatternsFile(ctx android.ModuleContext, flagsPath android.Path) android.Path {
+ patternsFile := android.PathForModuleOut(ctx, "modular-hiddenapi", "signature-patterns.csv")
+ // Create a rule to validate the output from the following rule.
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("signature_patterns").
+ FlagWithInput("--flags ", flagsPath).
+ FlagWithOutput("--output ", patternsFile)
+ rule.Build("hiddenAPISignaturePatterns", "hidden API signature patterns")
+
+ return patternsFile
+}
+
+// buildRuleRemoveBlockedFlag creates a rule that will remove entries from the input path which
+// only have blocked flags. It will not remove entries that have blocked as well as other flags,
+// e.g. blocked,core-platform-api.
+func buildRuleRemoveBlockedFlag(ctx android.BuilderContext, name string, desc string, inputPath android.Path, filteredPath android.WritablePath) {
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ Text(`grep -vE "^[^,]+,blocked$"`).Input(inputPath).Text(">").Output(filteredPath).
+ // Grep's exit code depends on whether it finds anything. It is 0 (build success) when it finds
+ // something and 1 (build failure) when it does not and 2 (when it encounters an error).
+ // However, while it is unlikely it is not an error if this does not find any matches. The
+ // following will only run if the grep does not find something and in that case it will treat
+ // an exit code of 1 as success and anything else as failure.
+ Text("|| test $? -eq 1")
+ rule.Build(name, desc)
+}
+
// buildRuleValidateOverlappingCsvFiles checks that the modular CSV files, i.e. the files generated
// by the individual bootclasspath_fragment modules are subsets of the monolithic CSV file.
-func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string, monolithicFilePath android.WritablePath, modularFilePaths android.Paths) android.WritablePath {
+func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string, monolithicFilePath android.WritablePath, csvSubsets SignatureCsvSubsets) android.WritablePath {
// The file which is used to record that the flags file is valid.
validFile := pathForValidation(ctx, monolithicFilePath)
// Create a rule to validate the output from the following rule.
rule := android.NewRuleBuilder(pctx, ctx)
- rule.Command().
+ command := rule.Command().
BuiltTool("verify_overlaps").
- Input(monolithicFilePath).
- Inputs(modularFilePaths).
- // If validation passes then update the file that records that.
- Text("&& touch").Output(validFile)
+ Input(monolithicFilePath)
+
+ for _, subset := range csvSubsets {
+ command.
+ Textf("%s:%s", subset.CsvFile, subset.SignaturePatternsFile).
+ Implicit(subset.CsvFile).Implicit(subset.SignaturePatternsFile)
+ }
+
+ // If validation passes then update the file that records that.
+ command.Text("&& touch").Output(validFile)
rule.Build(name+"Validation", desc+" validation")
return validFile
@@ -972,14 +1052,24 @@
encodedBootDexJarsByModule[name] = encodedDex
}
+ // Generate the filtered-stub-flags.csv file which contains the filtered stub flags that will be
+ // compared against the monolithic stub flags.
+ filteredStubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-stub-flags.csv")
+ buildRuleRemoveBlockedFlag(ctx, "modularHiddenApiFilteredStubFlags", "modular hiddenapi filtered stub flags", stubFlagsCSV, filteredStubFlagsCSV)
+
+ // Generate the filtered-flags.csv file which contains the filtered flags that will be compared
+ // against the monolithic flags.
+ filteredFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-flags.csv")
+ buildRuleRemoveBlockedFlag(ctx, "modularHiddenApiFilteredFlags", "modular hiddenapi filtered flags", allFlagsCSV, filteredFlagsCSV)
+
// Store the paths in the info for use by other modules and sdk snapshot generation.
output := HiddenAPIOutput{
HiddenAPIFlagOutput: HiddenAPIFlagOutput{
- StubFlagsPath: stubFlagsCSV,
+ StubFlagsPath: filteredStubFlagsCSV,
AnnotationFlagsPath: annotationFlagsCSV,
MetadataPath: metadataCSV,
IndexPath: indexCSV,
- AllFlagsPath: allFlagsCSV,
+ AllFlagsPath: filteredFlagsCSV,
},
EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
}
diff --git a/java/hiddenapi_monolithic.go b/java/hiddenapi_monolithic.go
index 404b4c1..5956e3c 100644
--- a/java/hiddenapi_monolithic.go
+++ b/java/hiddenapi_monolithic.go
@@ -29,9 +29,6 @@
// that category.
FlagsFilesByCategory FlagFilesByCategory
- // The paths to the generated stub-flags.csv files.
- StubFlagsPaths android.Paths
-
// The paths to the generated annotation-flags.csv files.
AnnotationFlagsPaths android.Paths
@@ -41,8 +38,13 @@
// The paths to the generated index.csv files.
IndexPaths android.Paths
- // The paths to the generated all-flags.csv files.
- AllFlagsPaths android.Paths
+ // The subsets of the monolithic hiddenapi-stubs-flags.txt file that are provided by each
+ // bootclasspath_fragment modules.
+ StubFlagSubsets SignatureCsvSubsets
+
+ // The subsets of the monolithic hiddenapi-flags.csv file that are provided by each
+ // bootclasspath_fragment modules.
+ FlagSubsets SignatureCsvSubsets
// The classes jars from the libraries on the platform bootclasspath.
ClassesJars android.Paths
@@ -80,11 +82,12 @@
// append appends all the files from the supplied info to the corresponding files in this struct.
func (i *MonolithicHiddenAPIInfo) append(other *HiddenAPIInfo) {
i.FlagsFilesByCategory.append(other.FlagFilesByCategory)
- i.StubFlagsPaths = append(i.StubFlagsPaths, other.StubFlagsPath)
i.AnnotationFlagsPaths = append(i.AnnotationFlagsPaths, other.AnnotationFlagsPath)
i.MetadataPaths = append(i.MetadataPaths, other.MetadataPath)
i.IndexPaths = append(i.IndexPaths, other.IndexPath)
- i.AllFlagsPaths = append(i.AllFlagsPaths, other.AllFlagsPath)
+
+ i.StubFlagSubsets = append(i.StubFlagSubsets, other.StubFlagSubset())
+ i.FlagSubsets = append(i.FlagSubsets, other.FlagSubset())
}
var MonolithicHiddenAPIInfoProvider = blueprint.NewProvider(MonolithicHiddenAPIInfo{})
diff --git a/java/java.go b/java/java.go
index b6e2a54..5bf3d79 100644
--- a/java/java.go
+++ b/java/java.go
@@ -248,13 +248,15 @@
type usesLibraryDependencyTag struct {
dependencyTag
- sdkVersion int // SDK version in which the library appared as a standalone library.
+ sdkVersion int // SDK version in which the library appared as a standalone library.
+ optional bool // If the dependency is optional or required.
}
-func makeUsesLibraryDependencyTag(sdkVersion int) usesLibraryDependencyTag {
+func makeUsesLibraryDependencyTag(sdkVersion int, optional bool) usesLibraryDependencyTag {
return usesLibraryDependencyTag{
dependencyTag: dependencyTag{name: fmt.Sprintf("uses-library-%d", sdkVersion)},
sdkVersion: sdkVersion,
+ optional: optional,
}
}
@@ -283,10 +285,11 @@
syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"}
jniInstallTag = installDependencyTag{name: "jni install"}
binaryInstallTag = installDependencyTag{name: "binary install"}
- usesLibTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion)
- usesLibCompat28Tag = makeUsesLibraryDependencyTag(28)
- usesLibCompat29Tag = makeUsesLibraryDependencyTag(29)
- usesLibCompat30Tag = makeUsesLibraryDependencyTag(30)
+ usesLibReqTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false)
+ usesLibOptTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, true)
+ usesLibCompat28OptTag = makeUsesLibraryDependencyTag(28, true)
+ usesLibCompat29ReqTag = makeUsesLibraryDependencyTag(29, false)
+ usesLibCompat30OptTag = makeUsesLibraryDependencyTag(30, true)
)
func IsLibDepTag(depTag blueprint.DependencyTag) bool {
@@ -1807,8 +1810,10 @@
}
depTag := ctx.OtherModuleDependencyTag(depModule)
- if depTag == libTag || depTag == usesLibTag {
+ if depTag == libTag {
// Ok, propagate <uses-library> through non-static library dependencies.
+ } else if tag, ok := depTag.(usesLibraryDependencyTag); ok && tag.sdkVersion == dexpreopt.AnySdkVersion {
+ // Ok, propagate <uses-library> through non-compatibility <uses-library> dependencies.
} else if depTag == staticLibTag {
// Propagate <uses-library> through static library dependencies, unless it is a component
// library (such as stubs). Component libraries have a dependency on their SDK library,
@@ -1826,7 +1831,7 @@
// <uses_library> and should not be added to CLC, but the transitive <uses-library> dependencies
// from its CLC should be added to the current CLC.
if sdkLib != nil {
- clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib,
+ clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, false,
dep.DexJarBuildPath(), dep.DexJarInstallPath(), dep.ClassLoaderContexts())
} else {
clcMap.AddContextMap(dep.ClassLoaderContexts(), depName)
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 3ff4c77..36baf7e 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -316,7 +316,7 @@
// Generate the monolithic stub-flags.csv file.
stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
- buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags", stubFlags, bootDexJarByModule.bootDexJars(), input, monolithicInfo.StubFlagsPaths)
+ buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags", stubFlags, bootDexJarByModule.bootDexJars(), input, monolithicInfo.StubFlagSubsets)
// Generate the annotation-flags.csv file from all the module annotations.
annotationFlags := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "annotation-flags-from-classes.csv")
@@ -329,7 +329,7 @@
allAnnotationFlagFiles := android.Paths{annotationFlags}
allAnnotationFlagFiles = append(allAnnotationFlagFiles, monolithicInfo.AnnotationFlagsPaths...)
allFlags := hiddenAPISingletonPaths(ctx).flags
- buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "monolithic hidden API flags", allFlags, stubFlags, allAnnotationFlagFiles, monolithicInfo.FlagsFilesByCategory, monolithicInfo.AllFlagsPaths, android.OptionalPath{})
+ buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "monolithic hidden API flags", allFlags, stubFlags, allAnnotationFlagFiles, monolithicInfo.FlagsFilesByCategory, monolithicInfo.FlagSubsets, android.OptionalPath{})
// Generate an intermediate monolithic hiddenapi-metadata.csv file directly from the annotations
// in the source code.
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 8e0618e..eeec504 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -156,8 +156,9 @@
// test if baz has exported SDK lib names foo and bar to qux
qux := result.ModuleForTests("qux", "android_common")
if quxLib, ok := qux.Module().(*Library); ok {
- sdkLibs := quxLib.ClassLoaderContexts().UsesLibs()
- android.AssertDeepEquals(t, "qux exports", []string{"foo", "bar", "fred", "quuz"}, sdkLibs)
+ requiredSdkLibs, optionalSdkLibs := quxLib.ClassLoaderContexts().UsesLibs()
+ android.AssertDeepEquals(t, "qux exports (required)", []string{"foo", "bar", "fred", "quuz"}, requiredSdkLibs)
+ android.AssertDeepEquals(t, "qux exports (optional)", []string{}, optionalSdkLibs)
}
}
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 7ceac41..30888c7 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -419,14 +419,7 @@
{"TARGET_COPY_OUT_TEST_HARNESS_RAMDISK", "test_harness_ramdisk"},
{"TARGET_COPY_OUT_ROOT", "root"},
{"TARGET_COPY_OUT_RECOVERY", "recovery"},
- {"TARGET_COPY_OUT_VENDOR", "||VENDOR-PATH-PH||"},
{"TARGET_COPY_OUT_VENDOR_RAMDISK", "vendor_ramdisk"},
- {"TARGET_COPY_OUT_PRODUCT", "||PRODUCT-PATH-PH||"},
- {"TARGET_COPY_OUT_PRODUCT_SERVICES", "||PRODUCT-PATH-PH||"},
- {"TARGET_COPY_OUT_SYSTEM_EXT", "||SYSTEM_EXT-PATH-PH||"},
- {"TARGET_COPY_OUT_ODM", "||ODM-PATH-PH||"},
- {"TARGET_COPY_OUT_VENDOR_DLKM", "||VENDOR_DLKM-PATH-PH||"},
- {"TARGET_COPY_OUT_ODM_DLKM", "||ODM_DLKM-PATH-PH||"},
// TODO(asmundak): to process internal config files, we need the following variables:
// BOARD_CONFIG_VENDOR_PATH
// TARGET_VENDOR
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index a14c7a4..ebaae28 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -259,7 +259,7 @@
ifdef PRODUCT_NAME
# Comment
else
- TARGET_COPY_OUT_VENDOR := foo
+ TARGET_COPY_OUT_RECOVERY := foo
endif
`,
expected: `load("//build/make/core:product_config.rbc", "rblf")
@@ -270,7 +270,7 @@
# Comment
pass
else:
- # MK2RBC TRANSLATION ERROR: cannot set predefined variable TARGET_COPY_OUT_VENDOR to "foo", its value should be "||VENDOR-PATH-PH||"
+ # MK2RBC TRANSLATION ERROR: cannot set predefined variable TARGET_COPY_OUT_RECOVERY to "foo", its value should be "recovery"
pass
rblf.warning("product.mk", "partially successful conversion")
`,
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 3470e51..be9e71e 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -29,7 +29,7 @@
defaultBindgenFlags = []string{""}
// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
- bindgenClangVersion = "clang-r416183b"
+ bindgenClangVersion = "clang-r428724"
_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
diff --git a/rust/builder.go b/rust/builder.go
index a5b3ab9..426a569 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -269,6 +269,17 @@
envVars = append(envVars, "ANDROID_RUST_VERSION="+config.RustDefaultVersion)
+ if ctx.RustModule().compiler.CargoEnvCompat() {
+ if _, ok := ctx.RustModule().compiler.(*binaryDecorator); ok {
+ envVars = append(envVars, "CARGO_BIN_NAME="+strings.TrimSuffix(outputFile.Base(), outputFile.Ext()))
+ }
+ envVars = append(envVars, "CARGO_CRATE_NAME="+ctx.RustModule().CrateName())
+ pkgVersion := ctx.RustModule().compiler.CargoPkgVersion()
+ if pkgVersion != "" {
+ envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
+ }
+ }
+
if flags.Clippy {
clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
ctx.Build(pctx, android.BuildParams{
diff --git a/rust/compiler.go b/rust/compiler.go
index de59f39..d9e21ff 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -65,7 +65,11 @@
)
type BaseCompilerProperties struct {
- // path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs)
+ // path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs).
+ // Only a single source file can be defined. Modules which generate source can be included by prefixing
+ // the module name with ":", for example ":libfoo_bindgen"
+ //
+ // If no source file is defined, a single generated source module can be defined to be used as the main source.
Srcs []string `android:"path,arch_variant"`
// name of the lint set that should be used to validate this module.
@@ -154,6 +158,14 @@
// linkage if all dependencies of the root binary module do not link against libstd\
// the same way.
Prefer_rlib *bool `android:"arch_variant"`
+
+ // Enables emitting certain Cargo environment variables. Only intended to be used for compatibility purposes.
+ // Will set CARGO_CRATE_NAME to the crate_name property's value.
+ // Will set CARGO_BIN_NAME to the output filename value without the extension.
+ Cargo_env_compat *bool
+
+ // If cargo_env_compat is true, sets the CARGO_PKG_VERSION env var to this value.
+ Cargo_pkg_version *string
}
type baseCompiler struct {
@@ -309,6 +321,14 @@
return android.OptionalPathForPath(compiler.cargoOutDir)
}
+func (compiler *baseCompiler) CargoEnvCompat() bool {
+ return Bool(compiler.Properties.Cargo_env_compat)
+}
+
+func (compiler *baseCompiler) CargoPkgVersion() string {
+ return String(compiler.Properties.Cargo_pkg_version)
+}
+
func (compiler *baseCompiler) strippedOutputFilePath() android.OptionalPath {
return compiler.strippedOutputFile
}
@@ -346,7 +366,9 @@
} else {
deps.SharedLibs = append(deps.SharedLibs, bionicLibs...)
}
-
+ if ctx.RustModule().StaticExecutable() {
+ deps.StaticLibs = append(deps.StaticLibs, "libunwind")
+ }
if libRuntimeBuiltins := config.BuiltinsRuntimeLibrary(ctx.toolchain()); libRuntimeBuiltins != "" {
deps.StaticLibs = append(deps.StaticLibs, libRuntimeBuiltins)
}
@@ -420,12 +442,18 @@
srcIndex = i
}
}
- if numSrcs != 1 {
+ if numSrcs > 1 {
ctx.PropertyErrorf("srcs", incorrectSourcesError)
}
+
+ // If a main source file is not provided we expect only a single SourceProvider module to be defined
+ // within srcs, with the expectation that the first source it provides is the entry point.
if srcIndex != 0 {
ctx.PropertyErrorf("srcs", "main source file must be the first in srcs")
+ } else if numSrcs > 1 {
+ ctx.PropertyErrorf("srcs", "only a single generated source module can be defined without a main source file.")
}
+
paths := android.PathsForModuleSrc(ctx, srcs)
return paths[srcIndex], paths[1:]
}
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index c331b4c..f589b69 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -98,6 +98,30 @@
}`)
}
+// Test environment vars for Cargo compat are set.
+func TestCargoCompat(t *testing.T) {
+ ctx := testRust(t, `
+ rust_binary {
+ name: "fizz",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ cargo_env_compat: true,
+ cargo_pkg_version: "1.0.0"
+ }`)
+
+ fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
+
+ if !strings.Contains(fizz.Args["envVars"], "CARGO_BIN_NAME=fizz") {
+ t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual envVars: %#v", fizz.Args["envVars"])
+ }
+ if !strings.Contains(fizz.Args["envVars"], "CARGO_CRATE_NAME=foo") {
+ t.Fatalf("expected 'CARGO_CRATE_NAME=foo' in envVars, actual envVars: %#v", fizz.Args["envVars"])
+ }
+ if !strings.Contains(fizz.Args["envVars"], "CARGO_PKG_VERSION=1.0.0") {
+ t.Fatalf("expected 'CARGO_PKG_VERSION=1.0.0' in envVars, actual envVars: %#v", fizz.Args["envVars"])
+ }
+}
+
func TestInstallDir(t *testing.T) {
ctx := testRust(t, `
rust_library_dylib {
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index e527aea..926d2ac 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -12,6 +12,7 @@
"external/libchromeos-rs",
"external/minijail",
"external/rust",
+ "external/selinux/libselinux",
"external/vm_tools/p9",
"frameworks/native/libs/binder/rust",
"frameworks/proto_logging/stats",
diff --git a/rust/config/global.go b/rust/config/global.go
index c390711..e5b334d 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.53.0"
+ RustDefaultVersion = "1.54.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2018"
Stdlibs = []string{
diff --git a/rust/coverage.go b/rust/coverage.go
index dac526a..050b811 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -55,7 +55,7 @@
flags.Coverage = true
coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface)
flags.RustFlags = append(flags.RustFlags,
- "-Z instrument-coverage", "-g", "-C link-dead-code")
+ "-Z instrument-coverage", "-g")
flags.LinkFlags = append(flags.LinkFlags,
profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open")
deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index 4b6c9d4..f3cd375 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -56,7 +56,7 @@
fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
- rustcCoverageFlags := []string{"-Z instrument-coverage", " -g ", "-C link-dead-code"}
+ rustcCoverageFlags := []string{"-Z instrument-coverage", " -g "}
for _, flag := range rustcCoverageFlags {
missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
diff --git a/rust/fuzz.go b/rust/fuzz.go
index 18b2513..5fb56ff 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -21,6 +21,7 @@
"android/soong/android"
"android/soong/cc"
+ "android/soong/fuzz"
"android/soong/rust/config"
)
@@ -32,7 +33,7 @@
type fuzzDecorator struct {
*binaryDecorator
- fuzzPackagedModule cc.FuzzPackagedModule
+ fuzzPackagedModule fuzz.FuzzPackagedModule
}
var _ compiler = (*binaryDecorator)(nil)
@@ -96,7 +97,7 @@
// Responsible for generating GNU Make rules that package fuzz targets into
// their architecture & target/host specific zip file.
type rustFuzzPackager struct {
- cc.FuzzPackager
+ fuzz.FuzzPackager
}
func rustFuzzPackagingFactory() android.Singleton {
@@ -105,7 +106,7 @@
func (s *rustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
// Map between each architecture + host/device combination.
- archDirs := make(map[cc.ArchOs][]cc.FileToZip)
+ archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip)
// List of individual fuzz targets.
s.FuzzTargets = make(map[string]bool)
@@ -117,7 +118,7 @@
return
}
- if ok := cc.IsValid(rustModule.FuzzModule); !ok || rustModule.Properties.PreventInstall {
+ if ok := fuzz.IsValid(rustModule.FuzzModule); !ok || rustModule.Properties.PreventInstall {
return
}
@@ -133,16 +134,16 @@
archString := rustModule.Arch().ArchType.String()
archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
- archOs := cc.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
+ archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
- var files []cc.FileToZip
+ var files []fuzz.FileToZip
builder := android.NewRuleBuilder(pctx, ctx)
// Package the artifacts (data, corpus, config and dictionary into a zipfile.
files = s.PackageArtifacts(ctx, module, fuzzModule.fuzzPackagedModule, archDir, builder)
// The executable.
- files = append(files, cc.FileToZip{rustModule.unstrippedOutputFile.Path(), ""})
+ files = append(files, fuzz.FileToZip{rustModule.unstrippedOutputFile.Path(), ""})
archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
if !ok {
@@ -150,7 +151,7 @@
}
})
- s.CreateFuzzPackage(ctx, archDirs, cc.Rust)
+ s.CreateFuzzPackage(ctx, archDirs, fuzz.Rust, pctx)
}
func (s *rustFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
diff --git a/rust/project_json.go b/rust/project_json.go
index c28bc7b..faa7db5 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -54,7 +54,6 @@
}
type rustProjectJson struct {
- Roots []string `json:"roots"`
Crates []rustProjectCrate `json:"crates"`
}
@@ -248,9 +247,6 @@
idx := len(singleton.project.Crates)
singleton.knownCrates[rModule.Name()] = crateInfo{Idx: idx, Deps: deps}
singleton.project.Crates = append(singleton.project.Crates, crate)
- // rust-analyzer requires that all crates belong to at least one root:
- // https://github.com/rust-analyzer/rust-analyzer/issues/4735.
- singleton.project.Roots = append(singleton.project.Roots, path.Dir(crate.RootModule))
return idx, true
}
diff --git a/rust/rust.go b/rust/rust.go
index 80be496..4ceeef1 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -25,6 +25,7 @@
"android/soong/bloaty"
"android/soong/cc"
cc_config "android/soong/cc/config"
+ "android/soong/fuzz"
"android/soong/rust/config"
)
@@ -123,7 +124,7 @@
}
type Module struct {
- cc.FuzzModule
+ fuzz.FuzzModule
VendorProperties cc.VendorProperties
@@ -433,6 +434,12 @@
// copied. This is equivalent to Cargo's OUT_DIR variable.
CargoOutDir() android.OptionalPath
+ // CargoPkgVersion returns the value of the Cargo_pkg_version property.
+ CargoPkgVersion() string
+
+ // CargoEnvCompat returns whether Cargo environment variables should be used.
+ CargoEnvCompat() bool
+
inData() bool
install(ctx ModuleContext)
relativeInstallPath() string
diff --git a/scripts/get_clang_version.py b/scripts/get_clang_version.py
index 622fca1..f6efc5f 100755
--- a/scripts/get_clang_version.py
+++ b/scripts/get_clang_version.py
@@ -30,7 +30,7 @@
with open(global_go) as infile:
contents = infile.read()
- regex_rev = r'\tClangDefaultVersion\s+= "clang-(?P<rev>r\d+[a-z]?\d?)"'
+ regex_rev = r'\tClangDefaultVersion\s+= "(?P<rev>clang-r\d+[a-z]?\d?)"'
match_rev = re.search(regex_rev, contents)
if match_rev is None:
raise RuntimeError('Parsing clang info failed')
diff --git a/scripts/hiddenapi/Android.bp b/scripts/hiddenapi/Android.bp
index c50dc24..7ffda62 100644
--- a/scripts/hiddenapi/Android.bp
+++ b/scripts/hiddenapi/Android.bp
@@ -83,3 +83,60 @@
},
},
}
+
+python_test_host {
+ name: "verify_overlaps_test",
+ main: "verify_overlaps_test.py",
+ srcs: [
+ "verify_overlaps.py",
+ "verify_overlaps_test.py",
+ ],
+ version: {
+ py2: {
+ enabled: false,
+ },
+ py3: {
+ enabled: true,
+ embedded_launcher: true,
+ },
+ },
+ test_options: {
+ unit_test: true,
+ },
+}
+
+python_binary_host {
+ name: "signature_patterns",
+ main: "signature_patterns.py",
+ srcs: ["signature_patterns.py"],
+ version: {
+ py2: {
+ enabled: false,
+ },
+ py3: {
+ enabled: true,
+ embedded_launcher: true,
+ },
+ },
+}
+
+python_test_host {
+ name: "signature_patterns_test",
+ main: "signature_patterns_test.py",
+ srcs: [
+ "signature_patterns.py",
+ "signature_patterns_test.py",
+ ],
+ version: {
+ py2: {
+ enabled: false,
+ },
+ py3: {
+ enabled: true,
+ embedded_launcher: true,
+ },
+ },
+ test_options: {
+ unit_test: true,
+ },
+}
diff --git a/scripts/hiddenapi/signature_patterns.py b/scripts/hiddenapi/signature_patterns.py
new file mode 100755
index 0000000..a7c5bb4
--- /dev/null
+++ b/scripts/hiddenapi/signature_patterns.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2021 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.
+"""
+Generate a set of signature patterns from the modular flags generated by a
+bootclasspath_fragment that can be used to select a subset of monolithic flags
+against which the modular flags can be compared.
+"""
+
+import argparse
+import csv
+
+def dict_reader(input):
+ return csv.DictReader(input, delimiter=',', quotechar='|', fieldnames=['signature'])
+
+def produce_patterns_from_file(file):
+ with open(file, 'r') as f:
+ return produce_patterns_from_stream(f)
+
+def produce_patterns_from_stream(stream):
+ # Read in all the signatures into a list and remove member names.
+ patterns = set()
+ for row in dict_reader(stream):
+ signature = row['signature']
+ text = signature.removeprefix("L")
+ # Remove the class specific member signature
+ pieces = text.split(";->")
+ qualifiedClassName = pieces[0]
+ # Remove inner class names as they cannot be separated from the containing outer class.
+ pieces = qualifiedClassName.split("$", maxsplit=1)
+ pattern = pieces[0]
+ patterns.add(pattern)
+
+ patterns = list(patterns)
+ patterns.sort()
+ return patterns
+
+def main(args):
+ args_parser = argparse.ArgumentParser(description='Generate a set of signature patterns that select a subset of monolithic hidden API files.')
+ args_parser.add_argument('--flags', help='The stub flags file which contains an entry for every dex member')
+ args_parser.add_argument('--output', help='Generated signature prefixes')
+ args = args_parser.parse_args(args)
+
+ # Read in all the patterns into a list.
+ patterns = produce_patterns_from_file(args.flags)
+
+ # Write out all the patterns.
+ with open(args.output, 'w') as outputFile:
+ for pattern in patterns:
+ outputFile.write(pattern)
+ outputFile.write("\n")
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/scripts/hiddenapi/signature_patterns_test.py b/scripts/hiddenapi/signature_patterns_test.py
new file mode 100755
index 0000000..0431f45
--- /dev/null
+++ b/scripts/hiddenapi/signature_patterns_test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2021 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.
+
+"""Unit tests for signature_patterns.py."""
+import io
+import unittest
+
+from signature_patterns import *
+
+class TestGeneratedPatterns(unittest.TestCase):
+
+ def produce_patterns_from_string(self, csv):
+ with io.StringIO(csv) as f:
+ return produce_patterns_from_stream(f)
+
+ def test_generate(self):
+ patterns = self.produce_patterns_from_string('''
+Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V,blocked
+Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;,public-api
+Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
+Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
+''')
+ expected = [
+ "java/lang/Character",
+ "java/lang/Object",
+ "java/lang/ProcessBuilder",
+ ]
+ self.assertEqual(expected, patterns)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/scripts/hiddenapi/verify_overlaps.py b/scripts/hiddenapi/verify_overlaps.py
index bb0917e..6432bf1 100755
--- a/scripts/hiddenapi/verify_overlaps.py
+++ b/scripts/hiddenapi/verify_overlaps.py
@@ -19,51 +19,361 @@
import argparse
import csv
+import sys
+from itertools import chain
-args_parser = argparse.ArgumentParser(description='Verify that one set of hidden API flags is a subset of another.')
-args_parser.add_argument('all', help='All the flags')
-args_parser.add_argument('subsets', nargs=argparse.REMAINDER, help='Subsets of the flags')
-args = args_parser.parse_args()
+class InteriorNode:
+ """
+ An interior node in a trie.
+ Each interior node has a dict that maps from an element of a signature to
+ either another interior node or a leaf. Each interior node represents either
+ a package, class or nested class. Class members are represented by a Leaf.
+
+ Associating the set of flags [public-api] with the signature
+ "Ljava/lang/Object;->String()Ljava/lang/String;" will cause the following
+ nodes to be created:
+ Node()
+ ^- package:java -> Node()
+ ^- package:lang -> Node()
+ ^- class:Object -> Node()
+ ^- member:String()Ljava/lang/String; -> Leaf([public-api])
+
+ Associating the set of flags [blocked,core-platform-api] with the signature
+ "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;"
+ will cause the following nodes to be created:
+ Node()
+ ^- package:java -> Node()
+ ^- package:lang -> Node()
+ ^- class:Character -> Node()
+ ^- class:UnicodeScript -> Node()
+ ^- member:of(I)Ljava/lang/Character$UnicodeScript;
+ -> Leaf([blocked,core-platform-api])
+
+ Attributes:
+ nodes: a dict from an element of the signature to the Node/Leaf
+ containing the next element/value.
+ """
+ def __init__(self):
+ self.nodes = {}
+
+ def signatureToElements(self, signature):
+ """
+ Split a signature or a prefix into a number of elements:
+ 1. The packages (excluding the leading L preceding the first package).
+ 2. The class names, from outermost to innermost.
+ 3. The member signature.
+
+ e.g. Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;
+ will be broken down into these elements:
+ 1. package:java
+ 2. package:lang
+ 3. class:Character
+ 4. class:UnicodeScript
+ 5. member:of(I)Ljava/lang/Character$UnicodeScript;
+ """
+ # Remove the leading L.
+ # - java/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;
+ text = signature.removeprefix("L")
+ # Split the signature between qualified class name and the class member
+ # signature.
+ # 0 - java/lang/Character$UnicodeScript
+ # 1 - of(I)Ljava/lang/Character$UnicodeScript;
+ parts = text.split(";->")
+ member = parts[1:]
+ # Split the qualified class name into packages, and class name.
+ # 0 - java
+ # 1 - lang
+ # 2 - Character$UnicodeScript
+ elements = parts[0].split("/")
+ packages = elements[0:-1]
+ className = elements[-1]
+ if className == "*" or className == "**":
+ # Cannot specify a wildcard and target a specific member
+ if len(member) != 0:
+ raise Exception("Invalid signature %s: contains wildcard %s and member signature %s"
+ % (signature, className, member[0]))
+ wildcard = [className]
+ # Assemble the parts into a single list, adding prefixes to identify
+ # the different parts.
+ # 0 - package:java
+ # 1 - package:lang
+ # 2 - *
+ return list(chain(map(lambda x : "package:" + x, packages),
+ wildcard))
+ else:
+ # Split the class name into outer / inner classes
+ # 0 - Character
+ # 1 - UnicodeScript
+ classes = className.split("$")
+ # Assemble the parts into a single list, adding prefixes to identify
+ # the different parts.
+ # 0 - package:java
+ # 1 - package:lang
+ # 2 - class:Character
+ # 3 - class:UnicodeScript
+ # 4 - member:of(I)Ljava/lang/Character$UnicodeScript;
+ return list(chain(map(lambda x : "package:" + x, packages),
+ map(lambda x : "class:" + x, classes),
+ map(lambda x : "member:" + x, member)))
+
+ def add(self, signature, value):
+ """
+ Associate the value with the specific signature.
+ :param signature: the member signature
+ :param value: the value to associated with the signature
+ :return: n/a
+ """
+ # Split the signature into elements.
+ elements = self.signatureToElements(signature)
+ # Find the Node associated with the deepest class.
+ node = self
+ for element in elements[:-1]:
+ if element in node.nodes:
+ node = node.nodes[element]
+ else:
+ next = InteriorNode()
+ node.nodes[element] = next
+ node = next
+ # Add a Leaf containing the value and associate it with the member
+ # signature within the class.
+ lastElement = elements[-1]
+ if not lastElement.startswith("member:"):
+ raise Exception("Invalid signature: %s, does not identify a specific member" % signature)
+ if lastElement in node.nodes:
+ raise Exception("Duplicate signature: %s" % signature)
+ node.nodes[lastElement] = Leaf(value)
+
+ def getMatchingRows(self, pattern):
+ """
+ Get the values (plural) associated with the pattern.
+
+ e.g. If the pattern is a full signature then this will return a list
+ containing the value associated with that signature.
+
+ If the pattern is a class then this will return a list containing the
+ values associated with all members of that class.
+
+ If the pattern is a package then this will return a list containing the
+ values associated with all the members of all the classes in that
+ package and sub-packages.
+
+ If the pattern ends with "*" then the preceding part is treated as a
+ package and this will return a list containing the values associated
+ with all the members of all the classes in that package.
+
+ If the pattern ends with "**" then the preceding part is treated
+ as a package and this will return a list containing the values
+ associated with all the members of all the classes in that package and
+ all sub-packages.
+
+ :param pattern: the pattern which could be a complete signature or a
+ class, or package wildcard.
+ :return: an iterable containing all the values associated with the
+ pattern.
+ """
+ elements = self.signatureToElements(pattern)
+ node = self
+ # Include all values from this node and all its children.
+ selector = lambda x : True
+ lastElement = elements[-1]
+ if lastElement == "*" or lastElement == "**":
+ elements = elements[:-1]
+ if lastElement == "*":
+ # Do not include values from sub-packages.
+ selector = lambda x : not x.startswith("package:")
+ for element in elements:
+ if element in node.nodes:
+ node = node.nodes[element]
+ else:
+ return []
+ return chain.from_iterable(node.values(selector))
+
+ def values(self, selector):
+ """
+ :param selector: a function that can be applied to a key in the nodes
+ attribute to determine whether to return its values.
+ :return: A list of iterables of all the values associated with this
+ node and its children.
+ """
+ values = []
+ self.appendValues(values, selector)
+ return values
+
+ def appendValues(self, values, selector):
+ """
+ Append the values associated with this node and its children to the
+ list.
+
+ For each item (key, child) in nodes the child node's values are returned
+ if and only if the selector returns True when called on its key. A child
+ node's values are all the values associated with it and all its
+ descendant nodes.
+
+ :param selector: a function that can be applied to a key in the nodes
+ attribute to determine whether to return its values.
+ :param values: a list of a iterables of values.
+ """
+ for key, node in self.nodes.items():
+ if selector(key):
+ node.appendValues(values, lambda x : True)
+
+class Leaf:
+ """
+ A leaf of the trie
+
+ Attributes:
+ value: the value associated with this leaf.
+ """
+ def __init__(self, value):
+ self.value = value
+
+ def values(self, selector):
+ """
+ :return: A list of a list of the value associated with this node.
+ """
+ return [[self.value]]
+
+ def appendValues(self, values, selector):
+ """
+ Appends a list of the value associated with this node to the list.
+ :param values: a list of a iterables of values.
+ """
+ values.append([self.value])
def dict_reader(input):
return csv.DictReader(input, delimiter=',', quotechar='|', fieldnames=['signature'])
-# Read in all the flags into a dict indexed by signature
-allFlagsBySignature = {}
-with open(args.all, 'r') as allFlagsFile:
- allFlagsReader = dict_reader(allFlagsFile)
- for row in allFlagsReader:
+def read_flag_trie_from_file(file):
+ with open(file, 'r') as stream:
+ return read_flag_trie_from_stream(stream)
+
+def read_flag_trie_from_stream(stream):
+ trie = InteriorNode()
+ reader = dict_reader(stream)
+ for row in reader:
signature = row['signature']
- allFlagsBySignature[signature]=row
+ trie.add(signature, row)
+ return trie
-failed = False
-for subsetPath in args.subsets:
- mismatchingSignatures = []
- with open(subsetPath, 'r') as subsetFlagsFile:
- subsetReader = dict_reader(subsetFlagsFile)
- for row in subsetReader:
+def extract_subset_from_monolithic_flags_as_dict_from_file(monolithicTrie, patternsFile):
+ """
+ Extract a subset of flags from the dict containing all the monolithic flags.
+
+ :param monolithicFlagsDict: the dict containing all the monolithic flags.
+ :param patternsFile: a file containing a list of signature patterns that
+ define the subset.
+ :return: the dict from signature to row.
+ """
+ with open(patternsFile, 'r') as stream:
+ return extract_subset_from_monolithic_flags_as_dict_from_stream(monolithicTrie, stream)
+
+def extract_subset_from_monolithic_flags_as_dict_from_stream(monolithicTrie, stream):
+ """
+ Extract a subset of flags from the trie containing all the monolithic flags.
+
+ :param monolithicTrie: the trie containing all the monolithic flags.
+ :param stream: a stream containing a list of signature patterns that define
+ the subset.
+ :return: the dict from signature to row.
+ """
+ dict = {}
+ for pattern in stream:
+ pattern = pattern.rstrip()
+ rows = monolithicTrie.getMatchingRows(pattern)
+ for row in rows:
signature = row['signature']
- if signature in allFlagsBySignature:
- allFlags = allFlagsBySignature.get(signature)
- if allFlags != row:
- mismatchingSignatures.append((signature, row.get(None, []), allFlags.get(None, [])))
- else:
- mismatchingSignatures.append((signature, row.get(None, []), []))
+ dict[signature] = row
+ return dict
+def read_signature_csv_from_stream_as_dict(stream):
+ """
+ Read the csv contents from the stream into a dict. The first column is assumed to be the
+ signature and used as the key. The whole row is stored as the value.
- if mismatchingSignatures:
- failed = True
- print("ERROR: Hidden API flags are inconsistent:")
- print("< " + subsetPath)
- print("> " + args.all)
- for mismatch in mismatchingSignatures:
- print()
- print("< " + mismatch[0] + "," + ",".join(mismatch[1]))
- if mismatch[2] != []:
- print("> " + mismatch[0] + "," + ",".join(mismatch[2]))
- else:
- print("> " + mismatch[0] + " - missing")
+ :param stream: the csv contents to read
+ :return: the dict from signature to row.
+ """
+ dict = {}
+ reader = dict_reader(stream)
+ for row in reader:
+ signature = row['signature']
+ dict[signature] = row
+ return dict
-if failed:
- sys.exit(1)
+def read_signature_csv_from_file_as_dict(csvFile):
+ """
+ Read the csvFile into a dict. The first column is assumed to be the
+ signature and used as the key. The whole row is stored as the value.
+
+ :param csvFile: the csv file to read
+ :return: the dict from signature to row.
+ """
+ with open(csvFile, 'r') as f:
+ return read_signature_csv_from_stream_as_dict(f)
+
+def compare_signature_flags(monolithicFlagsDict, modularFlagsDict):
+ """
+ Compare the signature flags between the two dicts.
+
+ :param monolithicFlagsDict: the dict containing the subset of the monolithic
+ flags that should be equal to the modular flags.
+ :param modularFlagsDict:the dict containing the flags produced by a single
+ bootclasspath_fragment module.
+ :return: list of mismatches., each mismatch is a tuple where the first item
+ is the signature, and the second and third items are lists of the flags from
+ modular dict, and monolithic dict respectively.
+ """
+ mismatchingSignatures = []
+ # Create a sorted set of all the signatures from both the monolithic and
+ # modular dicts.
+ allSignatures = sorted(set(chain(monolithicFlagsDict.keys(), modularFlagsDict.keys())))
+ for signature in allSignatures:
+ monolithicRow = monolithicFlagsDict.get(signature, {})
+ monolithicFlags = monolithicRow.get(None, [])
+ if signature in modularFlagsDict:
+ modularRow = modularFlagsDict.get(signature, {})
+ modularFlags = modularRow.get(None, [])
+ else:
+ modularFlags = ["blocked"]
+ if monolithicFlags != modularFlags:
+ mismatchingSignatures.append((signature, modularFlags, monolithicFlags))
+ return mismatchingSignatures
+
+def main(argv):
+ args_parser = argparse.ArgumentParser(description='Verify that sets of hidden API flags are each a subset of the monolithic flag file.')
+ args_parser.add_argument('monolithicFlags', help='The monolithic flag file')
+ args_parser.add_argument('modularFlags', nargs=argparse.REMAINDER, help='Flags produced by individual bootclasspath_fragment modules')
+ args = args_parser.parse_args(argv[1:])
+
+ # Read in all the flags into the trie
+ monolithicFlagsPath = args.monolithicFlags
+ monolithicTrie = read_flag_trie_from_file(monolithicFlagsPath)
+
+ # For each subset specified on the command line, create dicts for the flags
+ # provided by the subset and the corresponding flags from the complete set
+ # of flags and compare them.
+ failed = False
+ for modularPair in args.modularFlags:
+ parts = modularPair.split(":")
+ modularFlagsPath = parts[0]
+ modularPatternsPath = parts[1]
+ modularFlagsDict = read_signature_csv_from_file_as_dict(modularFlagsPath)
+ monolithicFlagsSubsetDict = extract_subset_from_monolithic_flags_as_dict_from_file(monolithicTrie, modularPatternsPath)
+ mismatchingSignatures = compare_signature_flags(monolithicFlagsSubsetDict, modularFlagsDict)
+ if mismatchingSignatures:
+ failed = True
+ print("ERROR: Hidden API flags are inconsistent:")
+ print("< " + modularFlagsPath)
+ print("> " + monolithicFlagsPath)
+ for mismatch in mismatchingSignatures:
+ signature = mismatch[0]
+ print()
+ print("< " + ",".join([signature]+ mismatch[1]))
+ print("> " + ",".join([signature]+ mismatch[2]))
+
+ if failed:
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/scripts/hiddenapi/verify_overlaps_test.py b/scripts/hiddenapi/verify_overlaps_test.py
new file mode 100755
index 0000000..00c0611
--- /dev/null
+++ b/scripts/hiddenapi/verify_overlaps_test.py
@@ -0,0 +1,341 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2021 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.
+
+"""Unit tests for verify_overlaps_test.py."""
+import io
+import unittest
+
+from verify_overlaps import *
+
+class TestSignatureToElements(unittest.TestCase):
+
+ def signatureToElements(self, signature):
+ return InteriorNode().signatureToElements(signature)
+
+ def test_signatureToElements_1(self):
+ expected = [
+ 'package:java',
+ 'package:lang',
+ 'class:ProcessBuilder',
+ 'class:Redirect',
+ 'class:1',
+ 'member:<init>()V',
+ ]
+ self.assertEqual(expected, self.signatureToElements(
+ "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V"))
+
+ def test_signatureToElements_2(self):
+ expected = [
+ 'package:java',
+ 'package:lang',
+ 'class:Object',
+ 'member:hashCode()I',
+ ]
+ self.assertEqual(expected, self.signatureToElements(
+ "Ljava/lang/Object;->hashCode()I"))
+
+ def test_signatureToElements_3(self):
+ expected = [
+ 'package:java',
+ 'package:lang',
+ 'class:CharSequence',
+ 'class:',
+ 'class:ExternalSyntheticLambda0',
+ 'member:<init>(Ljava/lang/CharSequence;)V',
+ ]
+ self.assertEqual(expected, self.signatureToElements(
+ "Ljava/lang/CharSequence$$ExternalSyntheticLambda0;"
+ "-><init>(Ljava/lang/CharSequence;)V"))
+
+class TestDetectOverlaps(unittest.TestCase):
+
+ def read_flag_trie_from_string(self, csv):
+ with io.StringIO(csv) as f:
+ return read_flag_trie_from_stream(f)
+
+ def read_signature_csv_from_string_as_dict(self, csv):
+ with io.StringIO(csv) as f:
+ return read_signature_csv_from_stream_as_dict(f)
+
+ def extract_subset_from_monolithic_flags_as_dict_from_string(self, monolithic, patterns):
+ with io.StringIO(patterns) as f:
+ return extract_subset_from_monolithic_flags_as_dict_from_stream(monolithic, f)
+
+ extractInput = '''
+Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
+Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
+Ljava/util/zip/ZipFile;-><clinit>()V,blocked
+Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;,blocked
+Ljava/lang/Character;->serialVersionUID:J,sdk
+Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V,blocked
+'''
+
+ def test_extract_subset_signature(self):
+ monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+
+ patterns = 'Ljava/lang/Object;->hashCode()I'
+
+ subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ expected = {
+ 'Ljava/lang/Object;->hashCode()I': {
+ None: ['public-api', 'system-api', 'test-api'],
+ 'signature': 'Ljava/lang/Object;->hashCode()I',
+ },
+ }
+ self.assertEqual(expected, subset)
+
+ def test_extract_subset_class(self):
+ monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+
+ patterns = 'java/lang/Object'
+
+ subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ expected = {
+ 'Ljava/lang/Object;->hashCode()I': {
+ None: ['public-api', 'system-api', 'test-api'],
+ 'signature': 'Ljava/lang/Object;->hashCode()I',
+ },
+ 'Ljava/lang/Object;->toString()Ljava/lang/String;': {
+ None: ['blocked'],
+ 'signature': 'Ljava/lang/Object;->toString()Ljava/lang/String;',
+ },
+ }
+ self.assertEqual(expected, subset)
+
+ def test_extract_subset_outer_class(self):
+ monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+
+ patterns = 'java/lang/Character'
+
+ subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ expected = {
+ 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;': {
+ None: ['blocked'],
+ 'signature': 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
+ },
+ 'Ljava/lang/Character;->serialVersionUID:J': {
+ None: ['sdk'],
+ 'signature': 'Ljava/lang/Character;->serialVersionUID:J',
+ },
+ }
+ self.assertEqual(expected, subset)
+
+ def test_extract_subset_nested_class(self):
+ monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+
+ patterns = 'java/lang/Character$UnicodeScript'
+
+ subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ expected = {
+ 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;': {
+ None: ['blocked'],
+ 'signature': 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
+ },
+ }
+ self.assertEqual(expected, subset)
+
+ def test_extract_subset_package(self):
+ monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+
+ patterns = 'java/lang/*'
+
+ subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ expected = {
+ 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;': {
+ None: ['blocked'],
+ 'signature': 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
+ },
+ 'Ljava/lang/Character;->serialVersionUID:J': {
+ None: ['sdk'],
+ 'signature': 'Ljava/lang/Character;->serialVersionUID:J',
+ },
+ 'Ljava/lang/Object;->hashCode()I': {
+ None: ['public-api', 'system-api', 'test-api'],
+ 'signature': 'Ljava/lang/Object;->hashCode()I',
+ },
+ 'Ljava/lang/Object;->toString()Ljava/lang/String;': {
+ None: ['blocked'],
+ 'signature': 'Ljava/lang/Object;->toString()Ljava/lang/String;',
+ },
+ 'Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V': {
+ None: ['blocked'],
+ 'signature': 'Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V',
+ },
+ }
+ self.assertEqual(expected, subset)
+
+ def test_extract_subset_recursive_package(self):
+ monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+
+ patterns = 'java/**'
+
+ subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ expected = {
+ 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;': {
+ None: ['blocked'],
+ 'signature': 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
+ },
+ 'Ljava/lang/Character;->serialVersionUID:J': {
+ None: ['sdk'],
+ 'signature': 'Ljava/lang/Character;->serialVersionUID:J',
+ },
+ 'Ljava/lang/Object;->hashCode()I': {
+ None: ['public-api', 'system-api', 'test-api'],
+ 'signature': 'Ljava/lang/Object;->hashCode()I',
+ },
+ 'Ljava/lang/Object;->toString()Ljava/lang/String;': {
+ None: ['blocked'],
+ 'signature': 'Ljava/lang/Object;->toString()Ljava/lang/String;',
+ },
+ 'Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V': {
+ None: ['blocked'],
+ 'signature': 'Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V',
+ },
+ 'Ljava/util/zip/ZipFile;-><clinit>()V': {
+ None: ['blocked'],
+ 'signature': 'Ljava/util/zip/ZipFile;-><clinit>()V',
+ },
+ }
+ self.assertEqual(expected, subset)
+
+ def test_extract_subset_invalid_pattern_wildcard_and_member(self):
+ monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+
+ patterns = 'Ljava/lang/*;->hashCode()I'
+
+ with self.assertRaises(Exception) as context:
+ self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ self.assertTrue("contains wildcard * and member signature hashCode()I" in str(context.exception))
+
+ def test_read_trie_duplicate(self):
+ with self.assertRaises(Exception) as context:
+ self.read_flag_trie_from_string('''
+Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
+Ljava/lang/Object;->hashCode()I,blocked
+''')
+ self.assertTrue("Duplicate signature: Ljava/lang/Object;->hashCode()I" in str(context.exception))
+
+ def test_read_trie_missing_member(self):
+ with self.assertRaises(Exception) as context:
+ self.read_flag_trie_from_string('''
+Ljava/lang/Object,public-api,system-api,test-api
+''')
+ self.assertTrue("Invalid signature: Ljava/lang/Object, does not identify a specific member" in str(context.exception))
+
+ def test_match(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
+''')
+ modular = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
+''')
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = []
+ self.assertEqual(expected, mismatches)
+
+ def test_mismatch_overlapping_flags(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,public-api
+''')
+ modular = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
+''')
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = [
+ (
+ 'Ljava/lang/Object;->toString()Ljava/lang/String;',
+ ['public-api', 'system-api', 'test-api'],
+ ['public-api'],
+ ),
+ ]
+ self.assertEqual(expected, mismatches)
+
+
+ def test_mismatch_monolithic_blocked(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
+''')
+ modular = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
+''')
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = [
+ (
+ 'Ljava/lang/Object;->toString()Ljava/lang/String;',
+ ['public-api', 'system-api', 'test-api'],
+ ['blocked'],
+ ),
+ ]
+ self.assertEqual(expected, mismatches)
+
+ def test_mismatch_modular_blocked(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
+''')
+ modular = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
+''')
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = [
+ (
+ 'Ljava/lang/Object;->toString()Ljava/lang/String;',
+ ['blocked'],
+ ['public-api', 'system-api', 'test-api'],
+ ),
+ ]
+ self.assertEqual(expected, mismatches)
+
+ def test_match_treat_missing_from_modular_as_blocked(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('')
+ modular = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
+''')
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = [
+ (
+ 'Ljava/lang/Object;->toString()Ljava/lang/String;',
+ ['public-api', 'system-api', 'test-api'],
+ [],
+ ),
+ ]
+ self.assertEqual(expected, mismatches)
+
+ def test_mismatch_treat_missing_from_modular_as_blocked(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
+''')
+ modular = {}
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = [
+ (
+ 'Ljava/lang/Object;->hashCode()I',
+ ['blocked'],
+ ['public-api', 'system-api', 'test-api'],
+ ),
+ ]
+ self.assertEqual(expected, mismatches)
+
+ def test_blocked_missing_from_modular(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->hashCode()I,blocked
+''')
+ modular = {}
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = []
+ self.assertEqual(expected, mismatches)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index c7ad798..bed2ecf 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -134,11 +134,12 @@
image_name: "art",
contents: ["mybootlib"],
hidden_api: {
- stub_flags: "hiddenapi/stub-flags.csv",
annotation_flags: "hiddenapi/annotation-flags.csv",
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
- all_flags: "hiddenapi/all-flags.csv",
+ signature_patterns: "hiddenapi/signature-patterns.csv",
+ stub_flags: "hiddenapi/filtered-stub-flags.csv",
+ all_flags: "hiddenapi/filtered-flags.csv",
},
}
@@ -161,11 +162,12 @@
image_name: "art",
contents: ["mysdk_mybootlib@current"],
hidden_api: {
- stub_flags: "hiddenapi/stub-flags.csv",
annotation_flags: "hiddenapi/annotation-flags.csv",
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
- all_flags: "hiddenapi/all-flags.csv",
+ signature_patterns: "hiddenapi/signature-patterns.csv",
+ stub_flags: "hiddenapi/filtered-stub-flags.csv",
+ all_flags: "hiddenapi/filtered-flags.csv",
},
}
@@ -185,11 +187,12 @@
}
`),
checkAllCopyRules(`
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
`),
snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
@@ -332,11 +335,12 @@
stub_libs: ["mycoreplatform"],
},
hidden_api: {
- stub_flags: "hiddenapi/stub-flags.csv",
annotation_flags: "hiddenapi/annotation-flags.csv",
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
- all_flags: "hiddenapi/all-flags.csv",
+ signature_patterns: "hiddenapi/signature-patterns.csv",
+ stub_flags: "hiddenapi/filtered-stub-flags.csv",
+ all_flags: "hiddenapi/filtered-flags.csv",
},
}
@@ -416,11 +420,12 @@
stub_libs: ["mysdk_mycoreplatform@current"],
},
hidden_api: {
- stub_flags: "hiddenapi/stub-flags.csv",
annotation_flags: "hiddenapi/annotation-flags.csv",
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
- all_flags: "hiddenapi/all-flags.csv",
+ signature_patterns: "hiddenapi/signature-patterns.csv",
+ stub_flags: "hiddenapi/filtered-stub-flags.csv",
+ all_flags: "hiddenapi/filtered-flags.csv",
},
}
@@ -494,11 +499,12 @@
}
`),
checkAllCopyRules(`
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
.intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
@@ -538,8 +544,16 @@
rule = module.Output("updatable-bcp-packages.txt")
expectedContents := `'mybootlib\nmyothersdklibrary\n'`
android.AssertStringEquals(t, "updatable-bcp-packages.txt", expectedContents, rule.Args["content"])
+
+ rule = module.Output("out/soong/hiddenapi/hiddenapi-flags.csv.valid")
+ android.AssertStringDoesContain(t, "verify-overlaps", rule.RuleParams.Command, " snapshot/hiddenapi/filtered-flags.csv:snapshot/hiddenapi/signature-patterns.csv ")
}),
snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot),
+ snapshotTestChecker(checkSnapshotWithSourcePreferred, func(t *testing.T, result *android.TestResult) {
+ module := result.ModuleForTests("platform-bootclasspath", "android_common")
+ rule := module.Output("out/soong/hiddenapi/hiddenapi-flags.csv.valid")
+ android.AssertStringDoesContain(t, "verify-overlaps", rule.RuleParams.Command, " out/soong/.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-flags.csv:out/soong/.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv ")
+ }),
snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot),
)
}
@@ -552,6 +566,7 @@
java.PrepareForTestWithJavaDefaultModules,
java.PrepareForTestWithJavaSdkLibraryFiles,
java.FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary"),
+ java.FixtureConfigureApexBootJars("someapex:mysdklibrary", "myotherapex:myotherlib"),
prepareForSdkTestWithApex,
// Some additional files needed for the myotherapex.
@@ -636,11 +651,12 @@
},
],
hidden_api: {
- stub_flags: "hiddenapi/stub-flags.csv",
annotation_flags: "hiddenapi/annotation-flags.csv",
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
- all_flags: "hiddenapi/all-flags.csv",
+ signature_patterns: "hiddenapi/signature-patterns.csv",
+ stub_flags: "hiddenapi/filtered-stub-flags.csv",
+ all_flags: "hiddenapi/filtered-flags.csv",
},
}
@@ -838,11 +854,12 @@
max_target_o_low_priority: ["hiddenapi/my-max-target-o-low-priority.txt"],
blocked: ["hiddenapi/my-blocked.txt"],
unsupported_packages: ["hiddenapi/my-unsupported-packages.txt"],
- stub_flags: "hiddenapi/stub-flags.csv",
annotation_flags: "hiddenapi/annotation-flags.csv",
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
- all_flags: "hiddenapi/all-flags.csv",
+ signature_patterns: "hiddenapi/signature-patterns.csv",
+ stub_flags: "hiddenapi/filtered-stub-flags.csv",
+ all_flags: "hiddenapi/filtered-flags.csv",
},
}
@@ -881,11 +898,12 @@
my-max-target-o-low-priority.txt -> hiddenapi/my-max-target-o-low-priority.txt
my-blocked.txt -> hiddenapi/my-blocked.txt
my-unsupported-packages.txt -> hiddenapi/my-unsupported-packages.txt
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index 1258684..9342d75 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -144,7 +144,7 @@
run_soong
local ninja_mtime1=$(stat -c "%y" out/soong/build.ninja)
- local glob_deps_file=out/soong/.primary/globs/0.d
+ local glob_deps_file=out/soong/.bootstrap/globs/0.d
if [ -e "$glob_deps_file" ]; then
fail "Glob deps file unexpectedly written on first build"
@@ -526,18 +526,14 @@
[[ -e out/soong/workspace ]] || fail "Bazel workspace not created"
}
-function test_bp2build_generates_fake_ninja_file {
+function test_bp2build_generates_marker_file {
setup
create_mock_bazel
run_bp2build
- if [[ ! -f "./out/soong/build.ninja" ]]; then
- fail "./out/soong/build.ninja was not generated"
- fi
-
- if ! grep "build nothing: phony" "./out/soong/build.ninja"; then
- fail "missing phony nothing target in out/soong/build.ninja"
+ if [[ ! -f "./out/soong/.bootstrap/bp2build_workspace_marker" ]]; then
+ fail "Marker file was not generated"
fi
}
@@ -577,10 +573,10 @@
setup
GENERATE_BAZEL_FILES=1 run_soong
- local mtime1=$(stat -c "%y" out/soong/build.ninja)
+ local mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
GENERATE_BAZEL_FILES=1 run_soong
- local mtime2=$(stat -c "%y" out/soong/build.ninja)
+ local mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
if [[ "$mtime1" != "$mtime2" ]]; then
fail "Output Ninja file changed on null build"
@@ -712,6 +708,41 @@
grep -q "b/${GENERATED_BUILD_FILE_NAME}' exist" "$MOCK_TOP/errors" || fail "Error for b/${GENERATED_BUILD_FILE_NAME} not found"
}
+function test_bp2build_back_and_forth_null_build {
+ setup
+
+ run_soong
+ local output_mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ GENERATE_BAZEL_FILES=1 run_soong
+ local output_mtime2=$(stat -c "%y" out/soong/build.ninja)
+ if [[ "$output_mtime1" != "$output_mtime2" ]]; then
+ fail "Output Ninja file changed when switching to bp2build"
+ fi
+
+ local marker_mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+
+ run_soong
+ local output_mtime3=$(stat -c "%y" out/soong/build.ninja)
+ local marker_mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+ if [[ "$output_mtime1" != "$output_mtime3" ]]; then
+ fail "Output Ninja file changed when switching to regular build from bp2build"
+ fi
+ if [[ "$marker_mtime1" != "$marker_mtime2" ]]; then
+ fail "bp2build marker file changed when switching to regular build from bp2build"
+ fi
+
+ GENERATE_BAZEL_FILES=1 run_soong
+ local output_mtime4=$(stat -c "%y" out/soong/build.ninja)
+ local marker_mtime3=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+ if [[ "$output_mtime1" != "$output_mtime4" ]]; then
+ fail "Output Ninja file changed when switching back to bp2build"
+ fi
+ if [[ "$marker_mtime1" != "$marker_mtime3" ]]; then
+ fail "bp2build marker file changed when switching back to bp2build"
+ fi
+}
+
test_smoke
test_null_build
test_null_build_after_docs
@@ -727,8 +758,9 @@
test_dump_json_module_graph
test_write_to_source_tree
test_bp2build_smoke
-test_bp2build_generates_fake_ninja_file
+test_bp2build_generates_marker_file
test_bp2build_null_build
+test_bp2build_back_and_forth_null_build
test_bp2build_add_android_bp
test_bp2build_add_to_glob
test_bp2build_bazel_workspace_structure
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index e357710..9bd85a4 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -8,6 +8,46 @@
readonly GENERATED_BUILD_FILE_NAME="BUILD.bazel"
+function test_bp2build_null_build() {
+ setup
+ run_bp2build
+ local output_mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+
+ run_bp2build
+ local output_mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+
+ if [[ "$output_mtime1" != "$output_mtime2" ]]; then
+ fail "Output bp2build marker file changed on null build"
+ fi
+}
+
+test_bp2build_null_build
+
+function test_bp2build_null_build_with_globs() {
+ setup
+
+ mkdir -p foo/bar
+ cat > foo/bar/Android.bp <<'EOF'
+filegroup {
+ name: "globs",
+ srcs: ["*.txt"],
+ }
+EOF
+ touch foo/bar/a.txt foo/bar/b.txt
+
+ run_bp2build
+ local output_mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+
+ run_bp2build
+ local output_mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+
+ if [[ "$output_mtime1" != "$output_mtime2" ]]; then
+ fail "Output bp2build marker file changed on null build"
+ fi
+}
+
+test_bp2build_null_build_with_globs
+
function test_bp2build_generates_all_buildfiles {
setup
create_mock_bazel
diff --git a/tests/lib.sh b/tests/lib.sh
index 1d9b8d4..813a9dd 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -113,6 +113,7 @@
symlink_directory prebuilts/bazel
symlink_directory prebuilts/jdk
+ symlink_directory external/bazel-skylib
symlink_file WORKSPACE
symlink_file BUILD
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 8399573..6304a11 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -6,3 +6,4 @@
"$TOP/build/soong/tests/bootstrap_test.sh"
"$TOP/build/soong/tests/mixed_mode_test.sh"
"$TOP/build/soong/tests/bp2build_bazel_test.sh"
+"$TOP/build/soong/tests/soong_test.sh"
diff --git a/tests/soong_test.sh b/tests/soong_test.sh
new file mode 100755
index 0000000..905d708
--- /dev/null
+++ b/tests/soong_test.sh
@@ -0,0 +1,22 @@
+#!/bin/bash -eu
+
+set -o pipefail
+
+# Tests of Soong functionality
+
+source "$(dirname "$0")/lib.sh"
+
+function test_m_clean_works {
+ setup
+
+ # Create a directory with files that cannot be removed
+ mkdir -p out/bad_directory_permissions
+ touch out/bad_directory_permissions/unremovable_file
+ # File permissions are fine but directory permissions are bad
+ chmod a+rwx out/bad_directory_permissions/unremovable_file
+ chmod a-rwx out/bad_directory_permissions
+
+ run_soong clean
+}
+
+test_m_clean_works
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 37940ba..3dc87f5 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -61,7 +61,6 @@
"proc_sync.go",
"rbe.go",
"sandbox_config.go",
- "signal.go",
"soong.go",
"test_build.go",
"upload.go",
diff --git a/ui/build/build.go b/ui/build/build.go
index 1ed9014..d869bf0 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -238,6 +238,11 @@
ctx.Verboseln("Skipping use of Kati ninja as requested")
what = what &^ RunKatiNinja
}
+ if config.SkipSoong() {
+ ctx.Verboseln("Skipping use of Soong as requested")
+ what = what &^ RunSoong
+ }
+
if config.SkipNinja() {
ctx.Verboseln("Skipping Ninja as requested")
what = what &^ RunNinja
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 19b5690..65b91bc 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -17,6 +17,7 @@
import (
"bytes"
"fmt"
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -46,9 +47,49 @@
}
}
+// Based on https://stackoverflow.com/questions/28969455/how-to-properly-instantiate-os-filemode
+// Because Go doesn't provide a nice way to set bits on a filemode
+const (
+ FILEMODE_READ = 04
+ FILEMODE_WRITE = 02
+ FILEMODE_EXECUTE = 01
+ FILEMODE_USER_SHIFT = 6
+ FILEMODE_USER_READ = FILEMODE_READ << FILEMODE_USER_SHIFT
+ FILEMODE_USER_WRITE = FILEMODE_WRITE << FILEMODE_USER_SHIFT
+ FILEMODE_USER_EXECUTE = FILEMODE_EXECUTE << FILEMODE_USER_SHIFT
+)
+
+// Ensures that files and directories in the out dir can be deleted.
+// For example, Bazen can generate output directories where the write bit isn't set, causing 'm' clean' to fail.
+func ensureOutDirRemovable(ctx Context, config Config) {
+ err := filepath.WalkDir(config.OutDir(), func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ return err
+ }
+ if d.IsDir() {
+ info, err := d.Info()
+ if err != nil {
+ return err
+ }
+ // Equivalent to running chmod u+rwx on each directory
+ newMode := info.Mode() | FILEMODE_USER_READ | FILEMODE_USER_WRITE | FILEMODE_USER_EXECUTE
+ if err := os.Chmod(path, newMode); err != nil {
+ return err
+ }
+ }
+ // Continue walking the out dir...
+ return nil
+ })
+ if err != nil && !os.IsNotExist(err) {
+ // Display the error, but don't crash.
+ ctx.Println(err.Error())
+ }
+}
+
// Remove everything under the out directory. Don't remove the out directory
// itself in case it's a symlink.
func clean(ctx Context, config Config) {
+ ensureOutDirRemovable(ctx, config)
removeGlobs(ctx, filepath.Join(config.OutDir(), "*"))
ctx.Println("Entire build directory removed.")
}
diff --git a/ui/build/config.go b/ui/build/config.go
index 918a956..956406d 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -49,6 +49,7 @@
skipConfig bool
skipKati bool
skipKatiNinja bool
+ skipSoong bool
skipNinja bool
skipSoongTests bool
@@ -582,6 +583,8 @@
arg := strings.TrimSpace(args[i])
if arg == "showcommands" {
c.verbose = true
+ } else if arg == "--empty-ninja-file" {
+ c.emptyNinjaFile = true
} else if arg == "--skip-ninja" {
c.skipNinja = true
} else if arg == "--skip-make" {
@@ -596,6 +599,10 @@
} else if arg == "--soong-only" {
c.skipKati = true
c.skipKatiNinja = true
+ } else if arg == "--config-only" {
+ c.skipKati = true
+ c.skipKatiNinja = true
+ c.skipSoong = true
} else if arg == "--skip-config" {
c.skipConfig = true
} else if arg == "--skip-soong-tests" {
@@ -690,54 +697,6 @@
}
}
-// Lunch configures the environment for a specific product similarly to the
-// `lunch` bash function.
-func (c *configImpl) Lunch(ctx Context, product, variant string) {
- if variant != "eng" && variant != "userdebug" && variant != "user" {
- ctx.Fatalf("Invalid variant %q. Must be one of 'user', 'userdebug' or 'eng'", variant)
- }
-
- c.environ.Set("TARGET_PRODUCT", product)
- c.environ.Set("TARGET_BUILD_VARIANT", variant)
- c.environ.Set("TARGET_BUILD_TYPE", "release")
- c.environ.Unset("TARGET_BUILD_APPS")
- c.environ.Unset("TARGET_BUILD_UNBUNDLED")
-}
-
-// Tapas configures the environment to build one or more unbundled apps,
-// similarly to the `tapas` bash function.
-func (c *configImpl) Tapas(ctx Context, apps []string, arch, variant string) {
- if len(apps) == 0 {
- apps = []string{"all"}
- }
- if variant == "" {
- variant = "eng"
- }
-
- if variant != "eng" && variant != "userdebug" && variant != "user" {
- ctx.Fatalf("Invalid variant %q. Must be one of 'user', 'userdebug' or 'eng'", variant)
- }
-
- var product string
- switch arch {
- case "arm", "":
- product = "aosp_arm"
- case "arm64":
- product = "aosm_arm64"
- case "x86":
- product = "aosp_x86"
- case "x86_64":
- product = "aosp_x86_64"
- default:
- ctx.Fatalf("Invalid architecture: %q", arch)
- }
-
- c.environ.Set("TARGET_PRODUCT", product)
- c.environ.Set("TARGET_BUILD_VARIANT", variant)
- c.environ.Set("TARGET_BUILD_TYPE", "release")
- c.environ.Set("TARGET_BUILD_APPS", strings.Join(apps, " "))
-}
-
func (c *configImpl) Environment() *Environment {
return c.environ
}
@@ -780,6 +739,14 @@
return filepath.Join(c.OutDir(), "soong")
}
+func (c *configImpl) MainNinjaFile() string {
+ return shared.JoinPath(c.SoongOutDir(), "build.ninja")
+}
+
+func (c *configImpl) Bp2BuildMarkerFile() string {
+ return shared.JoinPath(c.SoongOutDir(), ".bootstrap/bp2build_workspace_marker")
+}
+
func (c *configImpl) TempDir() string {
return shared.TempDirForOutDir(c.SoongOutDir())
}
@@ -817,6 +784,10 @@
return c.skipKatiNinja
}
+func (c *configImpl) SkipSoong() bool {
+ return c.skipSoong
+}
+
func (c *configImpl) SkipNinja() bool {
return c.skipNinja
}
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 190c955..8ef8c74 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -71,16 +71,11 @@
// A tiny struct used to tell Blueprint that it's in bootstrap mode. It would
// probably be nicer to use a flag in bootstrap.Args instead.
type BlueprintConfig struct {
- srcDir string
buildDir string
ninjaBuildDir string
debugCompilation bool
}
-func (c BlueprintConfig) SrcDir() string {
- return "."
-}
-
func (c BlueprintConfig) BuildDir() string {
return c.buildDir
}
@@ -114,17 +109,20 @@
}
}
-func bootstrapBlueprint(ctx Context, config Config, integratedBp2Build bool) {
+func bootstrapBlueprint(ctx Context, config Config) {
ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap")
defer ctx.EndTrace()
var args bootstrap.Args
- mainNinjaFile := shared.JoinPath(config.SoongOutDir(), "build.ninja")
bootstrapGlobFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build-globs.ninja")
- // .bootstrap/build.ninja "includes" .bootstrap/build-globs.ninja for incremental builds
- // generate an empty glob before running any rule in .bootstrap/build.ninja
+ bp2buildGlobFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build-globs.bp2build.ninja")
+
+ // The glob .ninja files are subninja'd. However, they are generated during
+ // the build itself so we write an empty file so that the subninja doesn't
+ // fail on clean builds
writeEmptyGlobFile(ctx, bootstrapGlobFile)
+ writeEmptyGlobFile(ctx, bp2buildGlobFile)
bootstrapDepFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja.d")
args.RunGoTests = !config.skipSoongTests
@@ -137,7 +135,7 @@
// The primary builder (aka soong_build) will use bootstrapGlobFile as the globFile to generate build.ninja(.d)
// Building soong_build does not require a glob file
// Using "" instead of "<soong_build_glob>.ninja" will ensure that an unused glob file is not written to out/soong/.bootstrap during StagePrimary
- args.GlobFile = ""
+ args.Subninjas = []string{bootstrapGlobFile, bp2buildGlobFile}
args.GeneratingPrimaryBuilder = true
args.EmptyNinjaFile = config.EmptyNinjaFile()
@@ -146,48 +144,51 @@
args.DelvePath = shared.ResolveDelveBinary()
}
- commonArgs := bootstrap.PrimaryBuilderExtraFlags(args, bootstrapGlobFile, mainNinjaFile)
- bp2BuildMarkerFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/bp2build_workspace_marker")
+ commonArgs := bootstrap.PrimaryBuilderExtraFlags(args, config.MainNinjaFile())
mainSoongBuildInputs := []string{"Android.bp"}
- if integratedBp2Build {
- mainSoongBuildInputs = append(mainSoongBuildInputs, bp2BuildMarkerFile)
+ if config.bazelBuildMode() == mixedBuild {
+ mainSoongBuildInputs = append(mainSoongBuildInputs, config.Bp2BuildMarkerFile())
}
- soongBuildArgs := make([]string, 0)
+ soongBuildArgs := []string{
+ "--globListDir", "globs",
+ "--globFile", bootstrapGlobFile,
+ }
+
soongBuildArgs = append(soongBuildArgs, commonArgs...)
soongBuildArgs = append(soongBuildArgs, environmentArgs(config, "")...)
soongBuildArgs = append(soongBuildArgs, "Android.bp")
mainSoongBuildInvocation := bootstrap.PrimaryBuilderInvocation{
Inputs: mainSoongBuildInputs,
- Outputs: []string{mainNinjaFile},
+ Outputs: []string{config.MainNinjaFile()},
Args: soongBuildArgs,
}
- if integratedBp2Build {
- bp2buildArgs := []string{"--bp2build_marker", bp2BuildMarkerFile}
- bp2buildArgs = append(bp2buildArgs, commonArgs...)
- bp2buildArgs = append(bp2buildArgs, environmentArgs(config, ".bp2build")...)
- bp2buildArgs = append(bp2buildArgs, "Android.bp")
+ bp2buildArgs := []string{
+ "--bp2build_marker", config.Bp2BuildMarkerFile(),
+ "--globListDir", "globs.bp2build",
+ "--globFile", bp2buildGlobFile,
+ }
- bp2buildInvocation := bootstrap.PrimaryBuilderInvocation{
- Inputs: []string{"Android.bp"},
- Outputs: []string{bp2BuildMarkerFile},
- Args: bp2buildArgs,
- }
- args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{bp2buildInvocation}
- if config.bazelBuildMode() == mixedBuild {
- args.PrimaryBuilderInvocations = append(args.PrimaryBuilderInvocations, mainSoongBuildInvocation)
- }
- } else {
- args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{mainSoongBuildInvocation}
+ bp2buildArgs = append(bp2buildArgs, commonArgs...)
+ bp2buildArgs = append(bp2buildArgs, environmentArgs(config, ".bp2build")...)
+ bp2buildArgs = append(bp2buildArgs, "Android.bp")
+
+ bp2buildInvocation := bootstrap.PrimaryBuilderInvocation{
+ Inputs: []string{"Android.bp"},
+ Outputs: []string{config.Bp2BuildMarkerFile()},
+ Args: bp2buildArgs,
+ }
+ args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{
+ bp2buildInvocation,
+ mainSoongBuildInvocation,
}
blueprintCtx := blueprint.NewContext()
blueprintCtx.SetIgnoreUnknownModuleTypes(true)
blueprintConfig := BlueprintConfig{
- srcDir: os.Getenv("TOP"),
buildDir: config.SoongOutDir(),
ninjaBuildDir: config.OutDir(),
debugCompilation: os.Getenv("SOONG_DELVE") != "",
@@ -220,18 +221,16 @@
// unused variables were changed?
envFile := filepath.Join(config.SoongOutDir(), availableEnvFile)
- for _, n := range []string{".bootstrap", ".minibootstrap"} {
- dir := filepath.Join(config.SoongOutDir(), n)
- if err := os.MkdirAll(dir, 0755); err != nil {
- ctx.Fatalf("Cannot mkdir " + dir)
- }
+ dir := filepath.Join(config.SoongOutDir(), ".bootstrap")
+ if err := os.MkdirAll(dir, 0755); err != nil {
+ ctx.Fatalf("Cannot mkdir " + dir)
}
buildMode := config.bazelBuildMode()
integratedBp2Build := (buildMode == mixedBuild) || (buildMode == generateBuildFiles)
// This is done unconditionally, but does not take a measurable amount of time
- bootstrapBlueprint(ctx, config, integratedBp2Build)
+ bootstrapBlueprint(ctx, config)
soongBuildEnv := config.Environment().Copy()
soongBuildEnv.Set("TOP", os.Getenv("TOP"))
@@ -265,10 +264,10 @@
}
}()
- runMicrofactory(ctx, config, ".minibootstrap/bpglob", "github.com/google/blueprint/bootstrap/bpglob",
+ runMicrofactory(ctx, config, ".bootstrap/bpglob", "github.com/google/blueprint/bootstrap/bpglob",
map[string]string{"github.com/google/blueprint": "build/blueprint"})
- ninja := func(name, file string) {
+ ninja := func(name, ninjaFile string, targets ...string) {
ctx.BeginTrace(metrics.RunSoong, name)
defer ctx.EndTrace()
@@ -276,8 +275,7 @@
nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo)
defer nr.Close()
- cmd := Command(ctx, config, "soong "+name,
- config.PrebuiltBuildTool("ninja"),
+ ninjaArgs := []string{
"-d", "keepdepfile",
"-d", "stats",
"-o", "usesphonyoutputs=yes",
@@ -287,7 +285,12 @@
"-w", "missingoutfile=err",
"-j", strconv.Itoa(config.Parallel()),
"--frontend_file", fifo,
- "-f", filepath.Join(config.SoongOutDir(), file))
+ "-f", filepath.Join(config.SoongOutDir(), ninjaFile),
+ }
+
+ ninjaArgs = append(ninjaArgs, targets...)
+ cmd := Command(ctx, config, "soong "+name,
+ config.PrebuiltBuildTool("ninja"), ninjaArgs...)
var ninjaEnv Environment
@@ -299,8 +302,17 @@
cmd.Sandbox = soongSandbox
cmd.RunAndStreamOrFatal()
}
- // This build generates <builddir>/build.ninja, which is used later by build/soong/ui/build/build.go#Build().
- ninja("bootstrap", ".bootstrap/build.ninja")
+
+ var target string
+
+ if config.bazelBuildMode() == generateBuildFiles {
+ target = config.Bp2BuildMarkerFile()
+ } else {
+ // This build generates <builddir>/build.ninja, which is used later by build/soong/ui/build/build.go#Build().
+ target = config.MainNinjaFile()
+ }
+
+ ninja("bootstrap", ".bootstrap/build.ninja", target)
var soongBuildMetrics *soong_metrics_proto.SoongBuildMetrics
if shouldCollectBuildSoongMetrics(config) {
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index a910c06..57ceaba 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -65,7 +65,6 @@
outDir := config.OutDir()
bootstrapDir := filepath.Join(outDir, "soong", ".bootstrap")
- miniBootstrapDir := filepath.Join(outDir, "soong", ".minibootstrap")
modulePathsDir := filepath.Join(outDir, ".module_paths")
variablesFilePath := filepath.Join(outDir, "soong", "soong.variables")
@@ -89,7 +88,6 @@
continue
}
if strings.HasPrefix(line, bootstrapDir) ||
- strings.HasPrefix(line, miniBootstrapDir) ||
strings.HasPrefix(line, modulePathsDir) ||
line == variablesFilePath ||
line == dexpreoptConfigFilePath ||
diff --git a/ui/signal/Android.bp b/ui/signal/Android.bp
new file mode 100644
index 0000000..08933a1
--- /dev/null
+++ b/ui/signal/Android.bp
@@ -0,0 +1,28 @@
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-ui-signal",
+ pkgPath: "android/soong/ui/signal",
+ srcs: [
+ "signal.go",
+ ],
+ deps: [
+ "soong-ui-logger",
+ ],
+}
diff --git a/ui/build/signal.go b/ui/signal/signal.go
similarity index 99%
rename from ui/build/signal.go
rename to ui/signal/signal.go
index 6643e2f..4929a7b 100644
--- a/ui/build/signal.go
+++ b/ui/signal/signal.go
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package build
+package signal
import (
"os"