Merge "SdkSpec is fully using ApiLevel"
diff --git a/android/Android.bp b/android/Android.bp
index a32e8f2..f5e5606 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -78,9 +78,6 @@
"variable.go",
"visibility.go",
"writedocs.go",
-
- // Lock down environment access last
- "env.go",
],
testSrcs: [
"android_test.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index 9317567..66a1036 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -546,7 +546,7 @@
}
if !amod.InRamdisk() && !amod.InVendorRamdisk() {
- a.AddStrings("LOCAL_INIT_RC", amod.commonProperties.Init_rc...)
+ a.AddPaths("LOCAL_FULL_INIT_RC", amod.initRcPaths)
}
a.AddStrings("LOCAL_VINTF_FRAGMENTS", amod.commonProperties.Vintf_fragments...)
a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(amod.commonProperties.Proprietary))
diff --git a/android/apex.go b/android/apex.go
index 7f9f0f5..cfda2aa 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -919,7 +919,7 @@
"Consider adding 'min_sdk_version: %q' to %q",
minSdkVersion, ctx.ModuleName(), err.Error(),
ctx.GetPathString(false),
- minSdkVersion, ctx.ModuleName())
+ minSdkVersion, toName)
return false
}
}
diff --git a/android/bazel.go b/android/bazel.go
index b2170be..b3f9d88 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -135,45 +135,57 @@
// Per-module denylist to always opt modules out.
bp2buildModuleDoNotConvertList = []string{
- "libBionicBenchmarksUtils", // ruperts@, cc_library_static
+ "libBionicBenchmarksUtils", // ruperts@, cc_library_static, 'map' file not found
"libbionic_spawn_benchmark", // ruperts@, cc_library_static, depends on //system/libbase
"libc_jemalloc_wrapper", // ruperts@, cc_library_static, depends on //external/jemalloc_new
- "libc_bootstrap", // ruperts@, cc_library_static
- "libc_init_static", // ruperts@, cc_library_static
- "libc_init_dynamic", // ruperts@, cc_library_static
- "libc_tzcode", // ruperts@, cc_library_static
- "libc_freebsd", // ruperts@, cc_library_static
- "libc_freebsd_large_stack", // ruperts@, cc_library_static
- "libc_netbsd", // ruperts@, cc_library_static
- "libc_openbsd_ndk", // ruperts@, cc_library_static
- "libc_openbsd_large_stack", // ruperts@, cc_library_static
- "libc_openbsd", // ruperts@, cc_library_static
- "libc_gdtoa", // ruperts@, cc_library_static
- "libc_fortify", // ruperts@, cc_library_static
- "libc_bionic", // ruperts@, cc_library_static
+ "libc_bootstrap", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_init_static", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_init_dynamic", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_tzcode", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_freebsd", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_freebsd_large_stack", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_netbsd", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_openbsd_ndk", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_openbsd_large_stack", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_openbsd", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_gdtoa", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_fortify", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_bionic", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
"libc_bionic_ndk", // ruperts@, cc_library_static, depends on //bionic/libc/system_properties
- "libc_bionic_systrace", // ruperts@, cc_library_static
- "libc_pthread", // ruperts@, cc_library_static
- "libc_syscalls", // ruperts@, cc_library_static
- "libc_aeabi", // ruperts@, cc_library_static
+ "libc_bionic_systrace", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_pthread", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_syscalls", // ruperts@, cc_library_static, mutator panic cannot get direct dep syscalls-arm64.S of libc_syscalls
+ "libc_aeabi", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
"libc_ndk", // ruperts@, cc_library_static, depends on //bionic/libm:libm
"libc_nopthread", // ruperts@, cc_library_static, depends on //external/arm-optimized-routines
"libc_common", // ruperts@, cc_library_static, depends on //bionic/libc:libc_nopthread
- "libc_static_dispatch", // ruperts@, cc_library_static
- "libc_dynamic_dispatch", // ruperts@, cc_library_static
+ "libc_static_dispatch", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+ "libc_dynamic_dispatch", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
"libc_common_static", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common
"libc_common_shared", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common
- "libc_unwind_static", // ruperts@, cc_library_static
+ "libc_unwind_static", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
"libc_nomalloc", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common
- "libasync_safe", // ruperts@, cc_library_static
+ "libasync_safe", // ruperts@, cc_library_static, 'private/CachedProperty.h' file not found
"libc_malloc_debug_backtrace", // ruperts@, cc_library_static, depends on //system/libbase
"libsystemproperties", // ruperts@, cc_library_static, depends on //system/core/property_service/libpropertyinfoparser
- "libdl_static", // ruperts@, cc_library_static
+ "libdl_static", // ruperts@, cc_library_static, 'private/CFIShadow.h' file not found
"liblinker_main", // ruperts@, cc_library_static, depends on //system/libbase
"liblinker_malloc", // ruperts@, cc_library_static, depends on //system/logging/liblog:liblog
"liblinker_debuggerd_stub", // ruperts@, cc_library_static, depends on //system/libbase
- "libbionic_tests_headers_posix", // ruperts@, cc_library_static
- "libc_dns", // ruperts@, cc_library_static
+ "libbionic_tests_headers_posix", // ruperts@, cc_library_static, 'complex.h' file not found
+ "libc_dns", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage
+
+ "note_memtag_heap_async", // jingwen@, b/185079815, features.h includes not found
+ "note_memtag_heap_sync", // jingwen@, b/185079815, features.h includes not found
+
+ // List of all full_cc_libraries in //bionic, with their immediate failures
+ "libc", // jingwen@, cc_library, depends on //external/gwp_asan
+ "libc_malloc_debug", // jingwen@, cc_library, fatal error: 'assert.h' file not found
+ "libc_malloc_hooks", // jingwen@, cc_library, fatal error: 'errno.h' file not found
+ "libdl", // jingwen@, cc_library, ld.lld: error: no input files
+ "libm", // jingwen@, cc_library, fatal error: 'freebsd-compat.h' file not found
+ "libseccomp_policy", // jingwen@, cc_library, fatal error: 'seccomp_policy.h' file not found
+ "libstdc++", // jingwen@, cc_library, depends on //external/gwp_asan
}
// Used for quicker lookups
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 5b9d3bf..2697007 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -34,10 +34,26 @@
"android/soong/shared"
)
+type cqueryRequest interface {
+ // Name returns a string name for this request type. Such request type names must be unique,
+ // and must only consist of alphanumeric characters.
+ Name() string
+
+ // 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.
+ StarlarkFunctionBody() string
+}
+
// Map key to describe bazel cquery requests.
type cqueryKey struct {
label string
- requestType cquery.RequestType
+ requestType cqueryRequest
archType ArchType
}
@@ -51,7 +67,7 @@
// TODO(cparsons): Other cquery-related methods should be added here.
// Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
- GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool)
+ GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error)
// ** End cquery methods
@@ -69,16 +85,24 @@
BuildStatementsToRegister() []bazel.BuildStatement
}
-// A context object which tracks queued requests that need to be made to Bazel,
-// and their results after the requests have been made.
-type bazelContext struct {
+type bazelRunner interface {
+ issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) (string, string, error)
+}
+
+type bazelPaths struct {
homeDir string
bazelPath string
outputBase string
workspaceDir string
buildDir string
metricsDir string
+}
+// A context object which tracks queued requests that need to be made to Bazel,
+// and their results after the requests have been made.
+type bazelContext struct {
+ bazelRunner
+ paths *bazelPaths
requests map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel
requestMutex sync.Mutex // requests can be written in parallel
@@ -97,17 +121,20 @@
// A bazel context to use for tests.
type MockBazelContext struct {
- AllFiles map[string][]string
+ OutputBaseDir string
+
+ LabelToOutputFiles map[string][]string
+ LabelToCcInfo map[string]cquery.CcInfo
}
func (m MockBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
- result, ok := m.AllFiles[label]
+ result, ok := m.LabelToOutputFiles[label]
return result, ok
}
-func (m MockBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
- result, ok := m.AllFiles[label]
- return result, result, ok
+func (m MockBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
+ result, ok := m.LabelToCcInfo[label]
+ return result, ok, nil
}
func (m MockBazelContext) InvokeBazel() error {
@@ -118,9 +145,7 @@
return true
}
-func (m MockBazelContext) OutputBase() string {
- return "outputbase"
-}
+func (m MockBazelContext) OutputBase() string { return m.OutputBaseDir }
func (m MockBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
return []bazel.BuildStatement{}
@@ -133,31 +158,31 @@
var ret []string
if ok {
bazelOutput := strings.TrimSpace(rawString)
- ret = cquery.GetOutputFiles.ParseResult(bazelOutput).([]string)
+ ret = cquery.GetOutputFiles.ParseResult(bazelOutput)
}
return ret, ok
}
-func (bazelCtx *bazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
- var outputFiles []string
- var ccObjects []string
-
- result, ok := bazelCtx.cquery(label, cquery.GetOutputFilesAndCcObjectFiles, archType)
- if ok {
- bazelOutput := strings.TrimSpace(result)
- returnResult := cquery.GetOutputFilesAndCcObjectFiles.ParseResult(bazelOutput).(cquery.GetOutputFilesAndCcObjectFiles_Result)
- outputFiles = returnResult.OutputFiles
- ccObjects = returnResult.CcObjectFiles
+func (bazelCtx *bazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
+ result, ok := bazelCtx.cquery(label, cquery.GetCcInfo, archType)
+ if !ok {
+ return cquery.CcInfo{}, ok, nil
}
- return outputFiles, ccObjects, ok
+ bazelOutput := strings.TrimSpace(result)
+ ret, err := cquery.GetCcInfo.ParseResult(bazelOutput)
+ return ret, ok, err
}
func (n noopBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
panic("unimplemented")
}
-func (n noopBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
+func (n noopBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
+ panic("unimplemented")
+}
+
+func (n noopBazelContext) GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool) {
panic("unimplemented")
}
@@ -184,42 +209,56 @@
return noopBazelContext{}, nil
}
- bazelCtx := bazelContext{buildDir: c.buildDir, requests: make(map[cqueryKey]bool)}
+ p, err := bazelPathsFromConfig(c)
+ if err != nil {
+ return nil, err
+ }
+ return &bazelContext{
+ bazelRunner: &builtinBazelRunner{},
+ paths: p,
+ requests: make(map[cqueryKey]bool),
+ }, nil
+}
+
+func bazelPathsFromConfig(c *config) (*bazelPaths, error) {
+ p := bazelPaths{
+ buildDir: c.buildDir,
+ }
missingEnvVars := []string{}
if len(c.Getenv("BAZEL_HOME")) > 1 {
- bazelCtx.homeDir = c.Getenv("BAZEL_HOME")
+ p.homeDir = c.Getenv("BAZEL_HOME")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_HOME")
}
if len(c.Getenv("BAZEL_PATH")) > 1 {
- bazelCtx.bazelPath = c.Getenv("BAZEL_PATH")
+ p.bazelPath = c.Getenv("BAZEL_PATH")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_PATH")
}
if len(c.Getenv("BAZEL_OUTPUT_BASE")) > 1 {
- bazelCtx.outputBase = c.Getenv("BAZEL_OUTPUT_BASE")
+ p.outputBase = c.Getenv("BAZEL_OUTPUT_BASE")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_OUTPUT_BASE")
}
if len(c.Getenv("BAZEL_WORKSPACE")) > 1 {
- bazelCtx.workspaceDir = c.Getenv("BAZEL_WORKSPACE")
+ p.workspaceDir = c.Getenv("BAZEL_WORKSPACE")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_WORKSPACE")
}
if len(c.Getenv("BAZEL_METRICS_DIR")) > 1 {
- bazelCtx.metricsDir = c.Getenv("BAZEL_METRICS_DIR")
+ p.metricsDir = c.Getenv("BAZEL_METRICS_DIR")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_METRICS_DIR")
}
if len(missingEnvVars) > 0 {
return nil, errors.New(fmt.Sprintf("missing required env vars to use bazel: %s", missingEnvVars))
} else {
- return &bazelCtx, nil
+ return &p, nil
}
}
-func (context *bazelContext) BazelMetricsDir() string {
- return context.metricsDir
+func (p *bazelPaths) BazelMetricsDir() string {
+ return p.metricsDir
}
func (context *bazelContext) BazelEnabled() bool {
@@ -231,7 +270,7 @@
// If the given request was already made (and the results are available), then
// returns (result, true). If the request is queued but no results are available,
// then returns ("", false).
-func (context *bazelContext) cquery(label string, requestType cquery.RequestType,
+func (context *bazelContext) cquery(label string, requestType cqueryRequest,
archType ArchType) (string, bool) {
key := cqueryKey{label, requestType, archType}
if result, ok := context.results[key]; ok {
@@ -252,17 +291,40 @@
return ""
}
+type bazelCommand struct {
+ command string
+ // query or label
+ expression string
+}
+
+type mockBazelRunner struct {
+ bazelCommandResults map[bazelCommand]string
+ commands []bazelCommand
+}
+
+func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths,
+ runName bazel.RunName,
+ command bazelCommand,
+ extraFlags ...string) (string, string, error) {
+ r.commands = append(r.commands, command)
+ if ret, ok := r.bazelCommandResults[command]; ok {
+ return ret, "", nil
+ }
+ return "", "", nil
+}
+
+type builtinBazelRunner struct{}
+
// Issues the given bazel command with given build label and additional flags.
// Returns (stdout, stderr, error). The first and second return values are strings
// containing the stdout and stderr of the run command, and an error is returned if
// the invocation returned an error code.
-func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command string, labels []string,
+func (r *builtinBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand,
extraFlags ...string) (string, string, error) {
-
- cmdFlags := []string{"--output_base=" + context.outputBase, command}
- cmdFlags = append(cmdFlags, labels...)
- cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+context.intermediatesDir())
- cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(context, runName))
+ cmdFlags := []string{"--output_base=" + paths.outputBase, command.command}
+ cmdFlags = append(cmdFlags, command.expression)
+ cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+paths.intermediatesDir())
+ cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(paths, runName))
// Set default platforms to canonicalized values for mixed builds requests.
// If these are set in the bazelrc, they will have values that are
@@ -284,9 +346,9 @@
cmdFlags = append(cmdFlags, "--experimental_repository_disable_download")
cmdFlags = append(cmdFlags, extraFlags...)
- bazelCmd := exec.Command(context.bazelPath, cmdFlags...)
- bazelCmd.Dir = context.workspaceDir
- bazelCmd.Env = append(os.Environ(), "HOME="+context.homeDir, pwdPrefix(),
+ bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
+ bazelCmd.Dir = paths.workspaceDir
+ bazelCmd.Env = append(os.Environ(), "HOME="+paths.homeDir, pwdPrefix(),
// Disables local host detection of gcc; toolchain information is defined
// explicitly in BUILD files.
"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1")
@@ -310,15 +372,20 @@
# This file is generated by soong_build. Do not edit.
local_repository(
name = "sourceroot",
- path = "%s",
+ path = "%[1]s",
)
local_repository(
name = "rules_cc",
- path = "%s/build/bazel/rules_cc",
+ path = "%[1]s/build/bazel/rules_cc",
+)
+
+local_repository(
+ name = "bazel_skylib",
+ path = "%[1]s/build/bazel/bazel_skylib",
)
`
- return []byte(fmt.Sprintf(formatString, context.workspaceDir, context.workspaceDir))
+ return []byte(fmt.Sprintf(formatString, context.paths.workspaceDir))
}
func (context *bazelContext) mainBzlFileContents() []byte {
@@ -449,7 +516,7 @@
// and grouped by their request type. The data retrieved for each label depends on its
// request type.
func (context *bazelContext) cqueryStarlarkFileContents() []byte {
- requestTypeToCqueryIdEntries := map[cquery.RequestType][]string{}
+ requestTypeToCqueryIdEntries := map[cqueryRequest][]string{}
for val, _ := range context.requests {
cqueryId := getCqueryId(val)
mapEntryString := fmt.Sprintf("%q : True", cqueryId)
@@ -528,8 +595,8 @@
// Returns a workspace-relative path containing build-related metadata required
// for interfacing with Bazel. Example: out/soong/bazel.
-func (context *bazelContext) intermediatesDir() string {
- return filepath.Join(context.buildDir, "bazel")
+func (p *bazelPaths) intermediatesDir() string {
+ return filepath.Join(p.buildDir, "bazel")
}
// Issues commands to Bazel to receive results for all cquery requests
@@ -541,7 +608,7 @@
var cqueryErr string
var err error
- intermediatesDirPath := absolutePath(context.intermediatesDir())
+ intermediatesDirPath := absolutePath(context.paths.intermediatesDir())
if _, err := os.Stat(intermediatesDirPath); os.IsNotExist(err) {
err = os.Mkdir(intermediatesDirPath, 0777)
}
@@ -550,38 +617,38 @@
return err
}
err = ioutil.WriteFile(
- absolutePath(filepath.Join(context.intermediatesDir(), "main.bzl")),
+ filepath.Join(intermediatesDirPath, "main.bzl"),
context.mainBzlFileContents(), 0666)
if err != nil {
return err
}
err = ioutil.WriteFile(
- absolutePath(filepath.Join(context.intermediatesDir(), "BUILD.bazel")),
+ filepath.Join(intermediatesDirPath, "BUILD.bazel"),
context.mainBuildFileContents(), 0666)
if err != nil {
return err
}
- cqueryFileRelpath := filepath.Join(context.intermediatesDir(), "buildroot.cquery")
+ cqueryFileRelpath := filepath.Join(context.paths.intermediatesDir(), "buildroot.cquery")
err = ioutil.WriteFile(
absolutePath(cqueryFileRelpath),
context.cqueryStarlarkFileContents(), 0666)
if err != nil {
return err
}
- workspaceFileRelpath := filepath.Join(context.intermediatesDir(), "WORKSPACE.bazel")
err = ioutil.WriteFile(
- absolutePath(workspaceFileRelpath),
+ filepath.Join(intermediatesDirPath, "WORKSPACE.bazel"),
context.workspaceFileContents(), 0666)
if err != nil {
return err
}
buildrootLabel := "//:buildroot"
- cqueryOutput, cqueryErr, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery",
- []string{fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)},
+ cqueryOutput, cqueryErr, err = context.issueBazelCommand(
+ context.paths,
+ bazel.CqueryBuildRootRunName,
+ bazelCommand{"cquery", fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)},
"--output=starlark",
"--starlark:file="+cqueryFileRelpath)
- err = ioutil.WriteFile(
- absolutePath(filepath.Join(context.intermediatesDir(), "cquery.out")),
+ err = ioutil.WriteFile(filepath.Join(intermediatesDirPath, "cquery.out"),
[]byte(cqueryOutput), 0666)
if err != nil {
return err
@@ -612,11 +679,13 @@
//
// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
var aqueryOutput string
- aqueryOutput, _, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery",
- []string{fmt.Sprintf("deps(%s)", buildrootLabel),
- // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
- // proto sources, which would add a number of unnecessary dependencies.
- "--output=jsonproto"})
+ aqueryOutput, _, err = context.issueBazelCommand(
+ context.paths,
+ bazel.AqueryBuildRootRunName,
+ bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)},
+ // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
+ // proto sources, which would add a number of unnecessary dependencies.
+ "--output=jsonproto")
if err != nil {
return err
@@ -630,8 +699,10 @@
// Issue a build command of the phony root to generate symlink forests for dependencies of the
// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
// but some of symlinks may be required to resolve source dependencies of the build.
- _, _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build",
- []string{"//:phonyroot"})
+ _, _, err = context.issueBazelCommand(
+ context.paths,
+ bazel.BazelBuildPhonyRootRunName,
+ bazelCommand{"build", "//:phonyroot"})
if err != nil {
return err
@@ -647,7 +718,7 @@
}
func (context *bazelContext) OutputBase() string {
- return context.outputBase
+ return context.paths.outputBase
}
// Singleton used for registering BUILD file ninja dependencies (needed
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
new file mode 100644
index 0000000..85f701f
--- /dev/null
+++ b/android/bazel_handler_test.go
@@ -0,0 +1,118 @@
+package android
+
+import (
+ "os"
+ "path/filepath"
+ "reflect"
+ "testing"
+)
+
+func TestRequestResultsAfterInvokeBazel(t *testing.T) {
+ label := "//foo:bar"
+ arch := Arm64
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
+ bazelCommand{command: "cquery", expression: "kind(rule, deps(//:buildroot))"}: `@sourceroot//foo:bar|arm64>>out/foo/bar.txt`,
+ })
+ g, ok := bazelContext.GetOutputFiles(label, arch)
+ if ok {
+ t.Errorf("Did not expect cquery results prior to running InvokeBazel(), but got %s", g)
+ }
+ err := bazelContext.InvokeBazel()
+ if err != nil {
+ t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+ }
+ g, ok = bazelContext.GetOutputFiles(label, arch)
+ if !ok {
+ t.Errorf("Expected cquery results after running InvokeBazel(), but got none")
+ } else if w := []string{"out/foo/bar.txt"}; !reflect.DeepEqual(w, g) {
+ t.Errorf("Expected output %s, got %s", w, g)
+ }
+}
+
+func TestInvokeBazelWritesBazelFiles(t *testing.T) {
+ bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
+ err := bazelContext.InvokeBazel()
+ if err != nil {
+ t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+ }
+ if _, err := os.Stat(filepath.Join(baseDir, "bazel", "main.bzl")); os.IsNotExist(err) {
+ t.Errorf("Expected main.bzl to exist, but it does not")
+ } else if err != nil {
+ t.Errorf("Unexpected error stating main.bzl %s", err)
+ }
+
+ if _, err := os.Stat(filepath.Join(baseDir, "bazel", "BUILD.bazel")); os.IsNotExist(err) {
+ t.Errorf("Expected BUILD.bazel to exist, but it does not")
+ } else if err != nil {
+ t.Errorf("Unexpected error stating BUILD.bazel %s", err)
+ }
+
+ if _, err := os.Stat(filepath.Join(baseDir, "bazel", "WORKSPACE.bazel")); os.IsNotExist(err) {
+ t.Errorf("Expected WORKSPACE.bazel to exist, but it does not")
+ } else if err != nil {
+ t.Errorf("Unexpected error stating WORKSPACE.bazel %s", err)
+ }
+}
+
+func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
+ bazelCommand{command: "aquery", expression: "deps(//:buildroot)"}: `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ }, {
+ "id": 2,
+ "pathFragmentId": 2
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "x",
+ "arguments": ["touch", "foo"],
+ "inputDepSetIds": [1],
+ "outputIds": [1],
+ "primaryOutputId": 1
+ }],
+ "depSetOfFiles": [{
+ "id": 1,
+ "directArtifactIds": [1, 2]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "one"
+ }, {
+ "id": 2,
+ "label": "two"
+ }]
+}`,
+ })
+ err := bazelContext.InvokeBazel()
+ if err != nil {
+ t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+ }
+
+ got := bazelContext.BuildStatementsToRegister()
+ if want := 1; len(got) != want {
+ t.Errorf("Expected %d registered build statements, got %#v", want, got)
+ }
+}
+
+func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*bazelContext, string) {
+ t.Helper()
+ p := bazelPaths{
+ buildDir: t.TempDir(),
+ outputBase: "outputbase",
+ workspaceDir: "workspace_dir",
+ }
+ aqueryCommand := bazelCommand{command: "aquery", expression: "deps(//:buildroot)"}
+ if _, exists := bazelCommandResults[aqueryCommand]; !exists {
+ bazelCommandResults[aqueryCommand] = "{}\n"
+ }
+ runner := &mockBazelRunner{bazelCommandResults: bazelCommandResults}
+ return &bazelContext{
+ bazelRunner: runner,
+ paths: &p,
+ requests: map[cqueryKey]bool{},
+ }, p.buildDir
+}
diff --git a/android/config.go b/android/config.go
index cfbc37f..c566e34 100644
--- a/android/config.go
+++ b/android/config.go
@@ -345,7 +345,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)
+ newConfig, err := NewConfig(c.srcDir, c.buildDir, c.moduleListFile, c.env)
if err != nil {
return Config{}, err
}
@@ -356,12 +356,12 @@
// 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) (Config, error) {
+func NewConfig(srcDir, buildDir string, moduleListFile string, availableEnv map[string]string) (Config, error) {
// Make a config with default options.
config := &config{
ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
- env: originalEnv,
+ env: availableEnv,
srcDir: srcDir,
buildDir: buildDir,
@@ -1498,6 +1498,10 @@
return c.config.productVariables.BuildBrokenTrebleSyspropNeverallow
}
+func (c *deviceConfig) BuildDebugfsRestrictionsEnabled() bool {
+ return c.config.productVariables.BuildDebugfsRestrictionsEnabled
+}
+
func (c *deviceConfig) BuildBrokenVendorPropertyNamespace() bool {
return c.config.productVariables.BuildBrokenVendorPropertyNamespace
}
diff --git a/android/env.go b/android/env.go
deleted file mode 100644
index 725a145..0000000
--- a/android/env.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2015 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package android
-
-import (
- "android/soong/shared"
-)
-
-// This file supports dependencies on environment variables. During build
-// manifest generation, any dependency on an environment variable is added to a
-// list. At the end of the build, a JSON file called soong.environment.used is
-// written containing the current value of all used environment variables. The
-// next time the top-level build script is run, soong_ui parses the compare the
-// contents of the used environment variables, then, if they changed, deletes
-// soong.environment.used to cause a rebuild.
-//
-// The dependency of build.ninja on soong.environment.used is declared in
-// build.ninja.d
-
-var originalEnv map[string]string
-
-func InitEnvironment(envFile string) {
- var err error
- originalEnv, err = shared.EnvFromFile(envFile)
- if err != nil {
- panic(err)
- }
-}
diff --git a/android/paths.go b/android/paths.go
index ba1ab11..df12228 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -421,6 +421,9 @@
// bazel-compatible labels. Properties passed as the paths or excludes argument must have been
// annotated with struct tag `android:"path"` so that dependencies on other modules will have
// already been handled by the path_properties mutator.
+//
+// With expanded globs, we can catch package boundaries problem instead of
+// silently failing to potentially missing files from Bazel's globs.
func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList {
return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil))
}
@@ -431,6 +434,9 @@
// passed as the paths or excludes argument must have been annotated with struct tag
// `android:"path"` so that dependencies on other modules will have already been handled by the
// path_properties mutator.
+//
+// With expanded globs, we can catch package boundaries problem instead of
+// silently failing to potentially missing files from Bazel's globs.
func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList {
excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil))
excluded := make([]string, 0, len(excludeLabels.Includes))
@@ -1095,11 +1101,12 @@
// a single file.
files, err = gctx.GlobWithDeps(path.String(), nil)
} else {
- var deps []string
+ var result pathtools.GlobResult
// We cannot add build statements in this context, so we fall back to
// AddNinjaFileDeps
- files, deps, err = ctx.Config().fs.Glob(path.String(), nil, pathtools.FollowSymlinks)
- ctx.AddNinjaFileDeps(deps...)
+ result, err = ctx.Config().fs.Glob(path.String(), nil, pathtools.FollowSymlinks)
+ ctx.AddNinjaFileDeps(result.Deps...)
+ files = result.Matches
}
if err != nil {
diff --git a/android/variable.go b/android/variable.go
index dff48c2..f25143d 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -385,6 +385,8 @@
BuildBrokenTrebleSyspropNeverallow bool `json:",omitempty"`
BuildBrokenVendorPropertyNamespace bool `json:",omitempty"`
+ BuildDebugfsRestrictionsEnabled bool `json:",omitempty"`
+
RequiresInsecureExecmemForSwiftshader bool `json:",omitempty"`
SelinuxIgnoreNeverallows bool `json:",omitempty"`
diff --git a/apex/Android.bp b/apex/Android.bp
index 1890b89..7b52402 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -31,6 +31,7 @@
testSrcs: [
"apex_test.go",
"boot_image_test.go",
+ "platform_bootclasspath_test.go",
"vndk_test.go",
],
pluginFor: ["soong_build"],
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 99cd75e..9fc701d 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -284,7 +284,7 @@
// To install companion files (init_rc, vintf_fragments)
// Copy some common properties of apexBundle to apex_manifest
commonProperties := []string{
- "LOCAL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
+ "LOCAL_FULL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
}
for _, name := range commonProperties {
if value, ok := apexAndroidMkData.Entries.EntryMap[name]; ok {
@@ -394,7 +394,7 @@
// Because apex writes .mk with Custom(), we need to write manually some common properties
// which are available via data.Entries
commonProperties := []string{
- "LOCAL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
+ "LOCAL_FULL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
"LOCAL_PROPRIETARY_MODULE", "LOCAL_VENDOR_MODULE", "LOCAL_ODM_MODULE", "LOCAL_PRODUCT_MODULE", "LOCAL_SYSTEM_EXT_MODULE",
"LOCAL_MODULE_OWNER",
}
diff --git a/apex/apex.go b/apex/apex.go
index 2820b48..0eacf6d 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1927,6 +1927,10 @@
filesInfo = append(filesInfo, af)
return true // track transitive dependencies
}
+ } else if rust.IsRlibDepTag(depTag) {
+ // Rlib is statically linked, but it might have shared lib
+ // dependencies. Track them.
+ return true
} else if java.IsbootImageContentDepTag(depTag) {
// Add the contents of the boot image to the apex.
switch child.(type) {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index bdff41e..f39c7e3 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -392,6 +392,15 @@
srcs: ["foo.rs"],
crate_name: "foo",
apex_available: ["myapex"],
+ shared_libs: ["libfoo.shared_from_rust"],
+ }
+
+ cc_library_shared {
+ name: "libfoo.shared_from_rust",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: ["myapex"],
}
rust_library_dylib {
@@ -539,6 +548,7 @@
ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.rlib.rust"), "android_arm64_armv8-a_rlib_dylib-std_apex10000")
ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.dylib.rust"), "android_arm64_armv8-a_dylib_apex10000")
ensureListContains(t, ctx.ModuleVariantsForTests("libbar.ffi"), "android_arm64_armv8-a_shared_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.shared_from_rust"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
@@ -548,6 +558,7 @@
ensureContains(t, copyCmds, "image.apex/lib64/libfoo.dylib.rust.dylib.so")
ensureContains(t, copyCmds, "image.apex/lib64/libfoo.ffi.so")
ensureContains(t, copyCmds, "image.apex/lib64/libbar.ffi.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
// .. but not for java libs
ensureNotContains(t, copyCmds, "image.apex/javalib/myotherjar.jar")
ensureNotContains(t, copyCmds, "image.apex/javalib/msharedjar.jar")
@@ -2745,7 +2756,7 @@
data.Custom(&builder, name, prefix, "", data)
androidMk := builder.String()
ensureContains(t, androidMk, "LOCAL_VINTF_FRAGMENTS := fragment.xml\n")
- ensureContains(t, androidMk, "LOCAL_INIT_RC := init.rc\n")
+ ensureContains(t, androidMk, "LOCAL_FULL_INIT_RC := init.rc\n")
}
func TestStaticLinking(t *testing.T) {
@@ -4364,9 +4375,7 @@
// These tests verify that the prebuilt_apex/deapexer to java_import wiring allows for the
// propagation of paths to dex implementation jars from the former to the latter.
func TestPrebuiltExportDexImplementationJars(t *testing.T) {
- transform := func(config *dexpreopt.GlobalConfig) {
- // Empty transformation.
- }
+ transform := android.NullFixturePreparer
checkDexJarBuildPath := func(t *testing.T, ctx *android.TestContext, name string) {
// Make sure the import has been given the correct path to the dex jar.
@@ -4536,9 +4545,7 @@
}
func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
- transform := func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"myapex:libfoo", "myapex:libbar"})
- }
+ preparer := java.FixtureConfigureBootJars("myapex:libfoo", "myapex:libbar")
checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) {
t.Helper()
@@ -4594,7 +4601,7 @@
}
`
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
@@ -4605,6 +4612,40 @@
`)
})
+ t.Run("apex_set only", func(t *testing.T) {
+ bp := `
+ apex_set {
+ name: "myapex",
+ set: "myapex.apks",
+ exported_java_libs: ["libfoo", "libbar"],
+ }
+
+ java_import {
+ name: "libfoo",
+ jars: ["libfoo.jar"],
+ apex_available: ["myapex"],
+ }
+
+ java_sdk_library_import {
+ name: "libbar",
+ public: {
+ jars: ["libbar.jar"],
+ },
+ apex_available: ["myapex"],
+ }
+ `
+
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
+ checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+ checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
+
+ // Make sure that the dex file from the apex_set contributes to the hiddenapi index file.
+ checkHiddenAPIIndexInputs(t, ctx, `
+.intermediates/libbar/android_common_myapex/hiddenapi/index.csv
+.intermediates/libfoo/android_common_myapex/hiddenapi/index.csv
+`)
+ })
+
t.Run("prebuilt with source library preferred", func(t *testing.T) {
bp := `
prebuilt_apex {
@@ -4653,7 +4694,7 @@
// prebuilt_apex module always depends on the prebuilt, and so it doesn't
// find the dex boot jar in it. We either need to disable the source libfoo
// or make the prebuilt libfoo preferred.
- testDexpreoptWithApexes(t, bp, "failed to find a dex jar path for module 'libfoo'", transform)
+ testDexpreoptWithApexes(t, bp, "failed to find a dex jar path for module 'libfoo'", preparer)
})
t.Run("prebuilt library preferred with source", func(t *testing.T) {
@@ -4701,7 +4742,7 @@
}
`
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
@@ -4768,7 +4809,7 @@
}
`
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/libfoo/android_common_apex10000/hiddenapi/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/libbar/android_common_myapex/hiddenapi/libbar.jar")
@@ -4785,7 +4826,7 @@
name: "myapex",
enabled: false,
key: "myapex.key",
- java_libs: ["libfoo"],
+ java_libs: ["libfoo", "libbar"],
}
apex_key {
@@ -4837,14 +4878,14 @@
}
`
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
// Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
checkHiddenAPIIndexInputs(t, ctx, `
-.intermediates/prebuilt_libbar/android_common_prebuilt_myapex/hiddenapi/index.csv
-.intermediates/prebuilt_libfoo/android_common_prebuilt_myapex/hiddenapi/index.csv
+.intermediates/prebuilt_libbar/android_common_myapex/hiddenapi/index.csv
+.intermediates/prebuilt_libfoo/android_common_myapex/hiddenapi/index.csv
`)
})
}
@@ -6368,8 +6409,7 @@
}
func TestAppSetBundlePrebuilt(t *testing.T) {
- ctx := testApex(t, "", android.FixtureModifyMockFS(func(fs android.MockFS) {
- bp := `
+ bp := `
apex_set {
name: "myapex",
filename: "foo_v2.apex",
@@ -6377,27 +6417,26 @@
none: { set: "myapex.apks", },
hwaddress: { set: "myapex.hwasan.apks", },
},
- }`
- fs["Android.bp"] = []byte(bp)
- }),
- prepareForTestWithSantitizeHwaddress,
- )
+ }
+ `
+ ctx := testApex(t, bp, prepareForTestWithSantitizeHwaddress)
- m := ctx.ModuleForTests("myapex", "android_common")
- extractedApex := m.Output("out/soong/.intermediates/myapex/android_common/foo_v2.apex")
+ // Check that the extractor produces the correct output file from the correct input file.
+ extractorOutput := "out/soong/.intermediates/myapex.apex.extractor/android_common/extracted/myapex.hwasan.apks"
- actual := extractedApex.Inputs
- if len(actual) != 1 {
- t.Errorf("expected a single input")
- }
+ m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
+ extractedApex := m.Output(extractorOutput)
- expected := "myapex.hwasan.apks"
- if actual[0].String() != expected {
- t.Errorf("expected %s, got %s", expected, actual[0].String())
- }
+ android.AssertArrayString(t, "extractor input", []string{"myapex.hwasan.apks"}, extractedApex.Inputs.Strings())
+
+ // Ditto for the apex.
+ m = ctx.ModuleForTests("myapex", "android_common")
+ copiedApex := m.Output("out/soong/.intermediates/myapex/android_common/foo_v2.apex")
+
+ android.AssertStringEquals(t, "myapex input", extractorOutput, copiedApex.Input.String())
}
-func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
+func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, preparer android.FixturePreparer) {
t.Helper()
bp := `
@@ -6485,10 +6524,10 @@
}
`
- testDexpreoptWithApexes(t, bp, errmsg, transformDexpreoptConfig)
+ testDexpreoptWithApexes(t, bp, errmsg, preparer)
}
-func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) *android.TestContext {
+func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.FixturePreparer) *android.TestContext {
t.Helper()
fs := android.MockFS{
@@ -6514,18 +6553,13 @@
java.PrepareForTestWithJavaDefaultModules,
java.PrepareForTestWithJavaSdkLibraryFiles,
PrepareForTestWithApexBuildComponents,
- android.FixtureModifyConfig(func(config android.Config) {
- pathCtx := android.PathContextForTesting(config)
- dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
- transformDexpreoptConfig(dexpreoptConfig)
- dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
-
- // Make sure that any changes to these dexpreopt properties are mirrored in the corresponding
- // product variables.
- config.TestProductVariables.BootJars = dexpreoptConfig.BootJars
- config.TestProductVariables.UpdatableBootJars = dexpreoptConfig.UpdatableBootJars
- }),
+ preparer,
fs.AddToFixture(),
+ android.FixtureAddTextFile("frameworks/base/boot/Android.bp", `
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ }
+ `),
).
ExtendWithErrorHandler(errorHandler).
RunTestWithBp(t, bp)
@@ -6565,92 +6599,95 @@
}
func TestNoUpdatableJarsInBootImage(t *testing.T) {
- var err string
- var transform func(*dexpreopt.GlobalConfig)
+ // Set the BootJars in dexpreopt.GlobalConfig and productVariables to the same value. This can
+ // result in an invalid configuration as it does not set the ArtApexJars and allows art apex
+ // modules to be included in the BootJars.
+ prepareSetBootJars := func(bootJars ...string) android.FixturePreparer {
+ return android.GroupFixturePreparers(
+ dexpreopt.FixtureSetBootJars(bootJars...),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
+ }),
+ )
+ }
+
+ // Set the ArtApexJars and BootJars in dexpreopt.GlobalConfig and productVariables all to the
+ // same value. This can result in an invalid configuration as it allows non art apex jars to be
+ // specified in the ArtApexJars configuration.
+ prepareSetArtJars := func(bootJars ...string) android.FixturePreparer {
+ return android.GroupFixturePreparers(
+ dexpreopt.FixtureSetArtBootJars(bootJars...),
+ dexpreopt.FixtureSetBootJars(bootJars...),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
+ }),
+ )
+ }
t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) {
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"com.android.art.debug:some-art-lib"})
- }
- testNoUpdatableJarsInBootImage(t, "", transform)
+ preparer := java.FixtureConfigureBootJars("com.android.art.debug:some-art-lib")
+ testNoUpdatableJarsInBootImage(t, "", preparer)
})
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`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"com.android.art.debug:some-art-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ 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")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
- err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the ART boot image`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"some-updatable-apex:some-updatable-apex-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the ART boot image`
+ // Update the dexpreopt ArtApexJars directly.
+ preparer := prepareSetArtJars("some-updatable-apex:some-updatable-apex-lib")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
- err = `module "some-non-updatable-apex-lib" is not allowed in the ART boot image`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `module "some-non-updatable-apex-lib" is not allowed in the ART boot image`
+ // Update the dexpreopt ArtApexJars directly.
+ preparer := prepareSetArtJars("some-non-updatable-apex:some-non-updatable-apex-lib")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
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`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"some-updatable-apex:some-updatable-apex-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ 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")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("non-updatable jar from some other apex in the framework boot image => ok", func(t *testing.T) {
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
- }
- testNoUpdatableJarsInBootImage(t, "", transform)
+ preparer := java.FixtureConfigureBootJars("some-non-updatable-apex:some-non-updatable-apex-lib")
+ testNoUpdatableJarsInBootImage(t, "", preparer)
})
t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) {
- err = "failed to find a dex jar path for module 'nonexistent'"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"platform:nonexistent"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `"platform-bootclasspath" depends on undefined module "nonexistent"`
+ preparer := java.FixtureConfigureBootJars("platform:nonexistent")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("nonexistent jar in the framework boot image => error", func(t *testing.T) {
- err = "failed to find a dex jar path for module 'nonexistent'"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"platform:nonexistent"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `"platform-bootclasspath" depends on undefined module "nonexistent"`
+ preparer := java.FixtureConfigureBootJars("platform:nonexistent")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("platform jar in the ART boot image => error", func(t *testing.T) {
- err = `module "some-platform-lib" is not allowed in the ART boot image`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"platform:some-platform-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `module "some-platform-lib" is not allowed in the ART boot image`
+ // Update the dexpreopt ArtApexJars directly.
+ preparer := prepareSetArtJars("platform:some-platform-lib")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("platform jar in the framework boot image => ok", func(t *testing.T) {
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"platform:some-platform-lib"})
- }
- testNoUpdatableJarsInBootImage(t, "", transform)
+ preparer := java.FixtureConfigureBootJars("platform:some-platform-lib")
+ testNoUpdatableJarsInBootImage(t, "", preparer)
})
-
}
func TestDexpreoptAccessDexFilesFromPrebuiltApex(t *testing.T) {
- transform := func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"myapex:libfoo"})
- }
+ preparer := java.FixtureConfigureBootJars("myapex:libfoo")
t.Run("prebuilt no source", func(t *testing.T) {
testDexpreoptWithApexes(t, `
prebuilt_apex {
@@ -6670,7 +6707,7 @@
name: "libfoo",
jars: ["libfoo.jar"],
}
-`, "", transform)
+`, "", preparer)
})
t.Run("prebuilt no source", func(t *testing.T) {
@@ -6692,7 +6729,7 @@
name: "libfoo",
jars: ["libfoo.jar"],
}
-`, "", transform)
+`, "", preparer)
})
}
@@ -7030,10 +7067,10 @@
}),
)
- m := ctx.ModuleForTests("myapex", "android_common")
+ m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
// Check extract_apks tool parameters.
- extractedApex := m.Output("out/soong/.intermediates/myapex/android_common/foo_v2.apex")
+ extractedApex := m.Output("extracted/myapex.apks")
actual := extractedApex.Args["abis"]
expected := "ARMEABI_V7A,ARM64_V8A"
if actual != expected {
@@ -7045,6 +7082,7 @@
t.Errorf("Unexpected abis parameter - expected %q vs actual %q", expected, actual)
}
+ m = ctx.ModuleForTests("myapex", "android_common")
a := m.Module().(*ApexSet)
expectedOverrides := []string{"foo"}
actualOverrides := android.AndroidMkEntriesForTest(t, ctx, a)[0].EntryMap["LOCAL_OVERRIDES_MODULES"]
diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go
index aa0d9c4..d447d70 100644
--- a/apex/boot_image_test.go
+++ b/apex/boot_image_test.go
@@ -19,7 +19,6 @@
"testing"
"android/soong/android"
- "android/soong/dexpreopt"
"android/soong/java"
)
@@ -42,8 +41,7 @@
result := android.GroupFixturePreparers(
prepareForTestWithBootImage,
// Configure some libraries in the art and framework boot images.
- dexpreopt.FixtureSetArtBootJars("com.android.art:baz", "com.android.art:quuz"),
- dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar"),
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo", "platform:bar"),
prepareForTestWithArtApex,
java.PrepareForTestWithJavaSdkLibraryFiles,
@@ -169,7 +167,7 @@
prepareForTestWithArtApex,
// Configure some libraries in the art boot image.
- dexpreopt.FixtureSetArtBootJars("com.android.art:foo", "com.android.art:bar"),
+ java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
).RunTestWithBp(t, `
apex {
name: "com.android.art",
@@ -264,7 +262,7 @@
}),
// Configure some libraries in the art boot image.
- dexpreopt.FixtureSetArtBootJars("com.android.art:foo", "com.android.art:bar"),
+ java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
).RunTestWithBp(t, `
prebuilt_apex {
name: "com.android.art",
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
new file mode 100644
index 0000000..74830d3
--- /dev/null
+++ b/apex/platform_bootclasspath_test.go
@@ -0,0 +1,175 @@
+// 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.
+
+package apex
+
+import (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/java"
+ "github.com/google/blueprint"
+)
+
+// Contains tests for platform_bootclasspath logic from java/platform_bootclasspath.go that requires
+// apexes.
+
+var prepareForTestWithPlatformBootclasspath = android.GroupFixturePreparers(
+ java.PrepareForTestWithDexpreopt,
+ PrepareForTestWithApexBuildComponents,
+)
+
+func TestPlatformBootclasspathDependencies(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ prepareForTestWithArtApex,
+ prepareForTestWithMyapex,
+ // Configure some libraries in the art and framework boot images.
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo"),
+ java.FixtureConfigureUpdatableBootJars("myapex:bar"),
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
+ apex {
+ name: "com.android.art",
+ key: "com.android.art.key",
+ bootclasspath_fragments: [
+ "art-bootclasspath-fragment",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "com.android.art.key",
+ public_key: "com.android.art.avbpubkey",
+ private_key: "com.android.art.pem",
+ }
+
+ bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
+ apex_available: [
+ "com.android.art",
+ ],
+ contents: [
+ "baz",
+ "quuz",
+ ],
+ }
+
+ java_library {
+ name: "baz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ installable: true,
+ }
+
+ // Add a java_import that is not preferred and so won't have an appropriate apex variant created
+ // for it to make sure that the platform_bootclasspath doesn't try and add a dependency onto it.
+ java_import {
+ name: "baz",
+ apex_available: [
+ "com.android.art",
+ ],
+ jars: ["b.jar"],
+ }
+
+ java_library {
+ name: "quuz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ installable: true,
+ }
+
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ java_libs: [
+ "bar",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_sdk_library {
+ name: "foo",
+ srcs: ["b.java"],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ permitted_packages: ["bar"],
+ }
+
+ platform_bootclasspath {
+ name: "myplatform-bootclasspath",
+
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+ }
+`,
+ )
+
+ java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{
+ "com.android.art:baz",
+ "com.android.art:quuz",
+ "platform:foo",
+ "myapex:bar",
+ })
+
+ java.CheckPlatformBootclasspathFragments(t, result, "myplatform-bootclasspath", []string{
+ `com.android.art:art-bootclasspath-fragment`,
+ })
+
+ // Make sure that the myplatform-bootclasspath has the correct dependencies.
+ CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
+ `platform:dex2oatd`,
+ `com.android.art:baz`,
+ `com.android.art:quuz`,
+ `platform:foo`,
+ `myapex:bar`,
+ `com.android.art:art-bootclasspath-fragment`,
+ })
+}
+
+// CheckModuleDependencies checks the dependencies of the selected module against the expected list.
+//
+// The expected list must be a list of strings of the form "<apex>:<module>", where <apex> is the
+// name of the apex, or platform is it is not part of an apex and <module> is the module name.
+func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
+ t.Helper()
+ module := ctx.ModuleForTests(name, variant).Module()
+ modules := []android.Module{}
+ ctx.VisitDirectDeps(module, func(m blueprint.Module) {
+ modules = append(modules, m.(android.Module))
+ })
+
+ pairs := java.ApexNamePairsFromModules(ctx, modules)
+ android.AssertDeepEquals(t, "module dependencies", expected, pairs)
+}
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 9d84281..a9d24a7 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -48,6 +48,9 @@
type prebuiltCommon struct {
prebuilt android.Prebuilt
properties prebuiltCommonProperties
+
+ deapexerProperties DeapexerProperties
+ selectedApexProperties SelectedApexProperties
}
type sanitizedPrebuilt interface {
@@ -91,6 +94,96 @@
return false
}
+func (p *prebuiltCommon) deapexerDeps(ctx android.BottomUpMutatorContext) {
+ // Add dependencies onto the java modules that represent the java libraries that are provided by
+ // and exported from this prebuilt apex.
+ for _, lib := range p.deapexerProperties.Exported_java_libs {
+ dep := prebuiltApexExportedModuleName(ctx, lib)
+ ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedJavaLibTag, dep)
+ }
+}
+
+// apexInfoMutator marks any modules for which this apex exports a file as requiring an apex
+// specific variant and checks that they are supported.
+//
+// The apexMutator will ensure that the ApexInfo objects passed to BuildForApex(ApexInfo) are
+// associated with the apex specific variant using the ApexInfoProvider for later retrieval.
+//
+// Unlike the source apex module type the prebuilt_apex module type cannot share compatible variants
+// across prebuilt_apex modules. That is because there is no way to determine whether two
+// prebuilt_apex modules that export files for the same module are compatible. e.g. they could have
+// been built from different source at different times or they could have been built with different
+// build options that affect the libraries.
+//
+// While it may be possible to provide sufficient information to determine whether two prebuilt_apex
+// modules were compatible it would be a lot of work and would not provide much benefit for a couple
+// of reasons:
+// * The number of prebuilt_apex modules that will be exporting files for the same module will be
+// low as the prebuilt_apex only exports files for the direct dependencies that require it and
+// very few modules are direct dependencies of multiple prebuilt_apex modules, e.g. there are a
+// few com.android.art* apex files that contain the same contents and could export files for the
+// same modules but only one of them needs to do so. Contrast that with source apex modules which
+// need apex specific variants for every module that contributes code to the apex, whether direct
+// or indirect.
+// * The build cost of a prebuilt_apex variant is generally low as at worst it will involve some
+// extra copying of files. Contrast that with source apex modules that has to build each variant
+// from source.
+func (p *prebuiltCommon) apexInfoMutator(mctx android.TopDownMutatorContext) {
+
+ // Collect direct dependencies into contents.
+ contents := make(map[string]android.ApexMembership)
+
+ // Collect the list of dependencies.
+ var dependencies []android.ApexModule
+ mctx.VisitDirectDeps(func(m android.Module) {
+ tag := mctx.OtherModuleDependencyTag(m)
+ if tag == exportedJavaLibTag {
+ depName := mctx.OtherModuleName(m)
+
+ // It is an error if the other module is not a prebuilt.
+ if _, ok := m.(android.PrebuiltInterface); !ok {
+ mctx.PropertyErrorf("exported_java_libs", "%q is not a prebuilt module", depName)
+ return
+ }
+
+ // It is an error if the other module is not an ApexModule.
+ if _, ok := m.(android.ApexModule); !ok {
+ mctx.PropertyErrorf("exported_java_libs", "%q is not usable within an apex", depName)
+ return
+ }
+
+ // Strip off the prebuilt_ prefix if present before storing content to ensure consistent
+ // behavior whether there is a corresponding source module present or not.
+ depName = android.RemoveOptionalPrebuiltPrefix(depName)
+
+ // Remember that this module was added as a direct dependency.
+ contents[depName] = contents[depName].Add(true)
+
+ // Add the module to the list of dependencies that need to have an APEX variant.
+ dependencies = append(dependencies, m.(android.ApexModule))
+ }
+ })
+
+ // Create contents for the prebuilt_apex and store it away for later use.
+ apexContents := android.NewApexContents(contents)
+ mctx.SetProvider(ApexBundleInfoProvider, ApexBundleInfo{
+ Contents: apexContents,
+ })
+
+ // Create an ApexInfo for the prebuilt_apex.
+ apexInfo := android.ApexInfo{
+ ApexVariationName: android.RemoveOptionalPrebuiltPrefix(mctx.ModuleName()),
+ InApexes: []string{mctx.ModuleName()},
+ ApexContents: []*android.ApexContents{apexContents},
+ ForPrebuiltApex: true,
+ }
+
+ // Mark the dependencies of this module as requiring a variant for this module.
+ for _, am := range dependencies {
+ am.BuildForApex(apexInfo)
+ }
+}
+
// prebuiltApexSelectorModule is a private module type that is only created by the prebuilt_apex
// module. It selects the apex to use and makes it available for use by prebuilt_apex and the
// deapexer.
@@ -197,7 +290,6 @@
type PrebuiltProperties struct {
ApexFileProperties
- DeapexerProperties
Installable *bool
// Optional name for the installed apex. If unspecified, name of the
@@ -267,7 +359,7 @@
//
func PrebuiltFactory() android.Module {
module := &Prebuilt{}
- module.AddProperties(&module.properties, &module.selectedApexProperties)
+ module.AddProperties(&module.properties, &module.deapexerProperties, &module.selectedApexProperties)
android.InitSingleSourcePrebuiltModule(module, &module.selectedApexProperties, "Selected_apex")
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
@@ -278,8 +370,8 @@
createApexSelectorModule(ctx, apexSelectorModuleName, &module.properties.ApexFileProperties)
apexFileSource := ":" + apexSelectorModuleName
- if len(module.properties.Exported_java_libs) != 0 {
- createDeapexerModule(ctx, deapexerModuleName(baseModuleName), apexFileSource, &module.properties.DeapexerProperties)
+ if len(module.deapexerProperties.Exported_java_libs) != 0 {
+ createDeapexerModule(ctx, deapexerModuleName(baseModuleName), apexFileSource, &module.deapexerProperties)
}
// Add a source reference to retrieve the selected apex from the selector module.
@@ -363,95 +455,13 @@
)
func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
- // Add dependencies onto the java modules that represent the java libraries that are provided by
- // and exported from this prebuilt apex.
- for _, lib := range p.properties.Exported_java_libs {
- dep := prebuiltApexExportedModuleName(ctx, lib)
- ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedJavaLibTag, dep)
- }
+ p.deapexerDeps(ctx)
}
var _ ApexInfoMutator = (*Prebuilt)(nil)
-// ApexInfoMutator marks any modules for which this apex exports a file as requiring an apex
-// specific variant and checks that they are supported.
-//
-// The apexMutator will ensure that the ApexInfo objects passed to BuildForApex(ApexInfo) are
-// associated with the apex specific variant using the ApexInfoProvider for later retrieval.
-//
-// Unlike the source apex module type the prebuilt_apex module type cannot share compatible variants
-// across prebuilt_apex modules. That is because there is no way to determine whether two
-// prebuilt_apex modules that export files for the same module are compatible. e.g. they could have
-// been built from different source at different times or they could have been built with different
-// build options that affect the libraries.
-//
-// While it may be possible to provide sufficient information to determine whether two prebuilt_apex
-// modules were compatible it would be a lot of work and would not provide much benefit for a couple
-// of reasons:
-// * The number of prebuilt_apex modules that will be exporting files for the same module will be
-// low as the prebuilt_apex only exports files for the direct dependencies that require it and
-// very few modules are direct dependencies of multiple prebuilt_apex modules, e.g. there are a
-// few com.android.art* apex files that contain the same contents and could export files for the
-// same modules but only one of them needs to do so. Contrast that with source apex modules which
-// need apex specific variants for every module that contributes code to the apex, whether direct
-// or indirect.
-// * The build cost of a prebuilt_apex variant is generally low as at worst it will involve some
-// extra copying of files. Contrast that with source apex modules that has to build each variant
-// from source.
func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) {
-
- // Collect direct dependencies into contents.
- contents := make(map[string]android.ApexMembership)
-
- // Collect the list of dependencies.
- var dependencies []android.ApexModule
- mctx.VisitDirectDeps(func(m android.Module) {
- tag := mctx.OtherModuleDependencyTag(m)
- if tag == exportedJavaLibTag {
- depName := mctx.OtherModuleName(m)
-
- // It is an error if the other module is not a prebuilt.
- if _, ok := m.(android.PrebuiltInterface); !ok {
- mctx.PropertyErrorf("exported_java_libs", "%q is not a prebuilt module", depName)
- return
- }
-
- // It is an error if the other module is not an ApexModule.
- if _, ok := m.(android.ApexModule); !ok {
- mctx.PropertyErrorf("exported_java_libs", "%q is not usable within an apex", depName)
- return
- }
-
- // Strip off the prebuilt_ prefix if present before storing content to ensure consistent
- // behavior whether there is a corresponding source module present or not.
- depName = android.RemoveOptionalPrebuiltPrefix(depName)
-
- // Remember that this module was added as a direct dependency.
- contents[depName] = contents[depName].Add(true)
-
- // Add the module to the list of dependencies that need to have an APEX variant.
- dependencies = append(dependencies, m.(android.ApexModule))
- }
- })
-
- // Create contents for the prebuilt_apex and store it away for later use.
- apexContents := android.NewApexContents(contents)
- mctx.SetProvider(ApexBundleInfoProvider, ApexBundleInfo{
- Contents: apexContents,
- })
-
- // Create an ApexInfo for the prebuilt_apex.
- apexInfo := android.ApexInfo{
- ApexVariationName: mctx.ModuleName(),
- InApexes: []string{mctx.ModuleName()},
- ApexContents: []*android.ApexContents{apexContents},
- ForPrebuiltApex: true,
- }
-
- // Mark the dependencies of this module as requiring a variant for this module.
- for _, am := range dependencies {
- am.BuildForApex(apexInfo)
- }
+ p.apexInfoMutator(mctx)
}
func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -505,6 +515,49 @@
}}
}
+// prebuiltApexExtractorModule is a private module type that is only created by the prebuilt_apex
+// module. It extracts the correct apex to use and makes it available for use by apex_set.
+type prebuiltApexExtractorModule struct {
+ android.ModuleBase
+
+ properties ApexExtractorProperties
+
+ extractedApex android.WritablePath
+}
+
+func privateApexExtractorModuleFactory() android.Module {
+ module := &prebuiltApexExtractorModule{}
+ module.AddProperties(
+ &module.properties,
+ )
+ android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ return module
+}
+
+func (p *prebuiltApexExtractorModule) Srcs() android.Paths {
+ return android.Paths{p.extractedApex}
+}
+
+func (p *prebuiltApexExtractorModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ srcsSupplier := func(ctx android.BaseModuleContext, prebuilt android.Module) []string {
+ return p.properties.prebuiltSrcs(ctx)
+ }
+ apexSet := android.SingleSourcePathFromSupplier(ctx, srcsSupplier, "set")
+ p.extractedApex = android.PathForModuleOut(ctx, "extracted", apexSet.Base())
+ ctx.Build(pctx,
+ android.BuildParams{
+ Rule: extractMatchingApex,
+ Description: "Extract an apex from an apex set",
+ Inputs: android.Paths{apexSet},
+ Output: p.extractedApex,
+ Args: map[string]string{
+ "abis": strings.Join(java.SupportedAbis(ctx), ","),
+ "allow-prereleased": strconv.FormatBool(proptools.Bool(p.properties.Prerelease)),
+ "sdk-version": ctx.Config().PlatformSdkVersion().String(),
+ },
+ })
+}
+
type ApexSet struct {
android.ModuleBase
prebuiltCommon
@@ -523,7 +576,7 @@
postInstallCommands []string
}
-type ApexSetProperties struct {
+type ApexExtractorProperties struct {
// the .apks file path that contains prebuilt apex files to be extracted.
Set *string
@@ -539,6 +592,37 @@
}
}
+ // apexes in this set use prerelease SDK version
+ Prerelease *bool
+}
+
+func (e *ApexExtractorProperties) prebuiltSrcs(ctx android.BaseModuleContext) []string {
+ var srcs []string
+ if e.Set != nil {
+ srcs = append(srcs, *e.Set)
+ }
+
+ var sanitizers []string
+ if ctx.Host() {
+ sanitizers = ctx.Config().SanitizeHost()
+ } else {
+ sanitizers = ctx.Config().SanitizeDevice()
+ }
+
+ if android.InList("address", sanitizers) && e.Sanitized.Address.Set != nil {
+ srcs = append(srcs, *e.Sanitized.Address.Set)
+ } else if android.InList("hwaddress", sanitizers) && e.Sanitized.Hwaddress.Set != nil {
+ srcs = append(srcs, *e.Sanitized.Hwaddress.Set)
+ } else if e.Sanitized.None.Set != nil {
+ srcs = append(srcs, *e.Sanitized.None.Set)
+ }
+
+ return srcs
+}
+
+type ApexSetProperties struct {
+ ApexExtractorProperties
+
// whether the extracted apex file installable.
Installable *bool
@@ -552,33 +636,6 @@
// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
// from PRODUCT_PACKAGES.
Overrides []string
-
- // apexes in this set use prerelease SDK version
- Prerelease *bool
-}
-
-func (a *ApexSet) prebuiltSrcs(ctx android.BaseModuleContext) []string {
- var srcs []string
- if a.properties.Set != nil {
- srcs = append(srcs, *a.properties.Set)
- }
-
- var sanitizers []string
- if ctx.Host() {
- sanitizers = ctx.Config().SanitizeHost()
- } else {
- sanitizers = ctx.Config().SanitizeDevice()
- }
-
- if android.InList("address", sanitizers) && a.properties.Sanitized.Address.Set != nil {
- srcs = append(srcs, *a.properties.Sanitized.Address.Set)
- } else if android.InList("hwaddress", sanitizers) && a.properties.Sanitized.Hwaddress.Set != nil {
- srcs = append(srcs, *a.properties.Sanitized.Hwaddress.Set)
- } else if a.properties.Sanitized.None.Set != nil {
- srcs = append(srcs, *a.properties.Sanitized.None.Set)
- }
-
- return srcs
}
func (a *ApexSet) hasSanitizedSource(sanitizer string) bool {
@@ -611,15 +668,54 @@
// prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
func apexSetFactory() android.Module {
module := &ApexSet{}
- module.AddProperties(&module.properties)
+ module.AddProperties(&module.properties, &module.selectedApexProperties, &module.deapexerProperties)
- srcsSupplier := func(ctx android.BaseModuleContext, _ android.Module) []string {
- return module.prebuiltSrcs(ctx)
+ android.InitSingleSourcePrebuiltModule(module, &module.selectedApexProperties, "Selected_apex")
+ android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ baseModuleName := module.BaseModuleName()
+
+ apexExtractorModuleName := apexExtractorModuleName(baseModuleName)
+ createApexExtractorModule(ctx, apexExtractorModuleName, &module.properties.ApexExtractorProperties)
+
+ apexFileSource := ":" + apexExtractorModuleName
+ if len(module.deapexerProperties.Exported_java_libs) != 0 {
+ createDeapexerModule(ctx, deapexerModuleName(baseModuleName), apexFileSource, &module.deapexerProperties)
+ }
+
+ // After passing the arch specific src properties to the creating the apex selector module
+ module.selectedApexProperties.Selected_apex = proptools.StringPtr(apexFileSource)
+ })
+
+ return module
+}
+
+func createApexExtractorModule(ctx android.LoadHookContext, name string, apexExtractorProperties *ApexExtractorProperties) {
+ props := struct {
+ Name *string
+ }{
+ Name: proptools.StringPtr(name),
}
- android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "set")
- android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
- return module
+ ctx.CreateModule(privateApexExtractorModuleFactory,
+ &props,
+ apexExtractorProperties,
+ )
+}
+
+func apexExtractorModuleName(baseModuleName string) string {
+ return baseModuleName + ".apex.extractor"
+}
+
+func (a *ApexSet) DepsMutator(ctx android.BottomUpMutatorContext) {
+ a.deapexerDeps(ctx)
+}
+
+var _ ApexInfoMutator = (*ApexSet)(nil)
+
+func (a *ApexSet) ApexInfoMutator(mctx android.TopDownMutatorContext) {
+ a.apexInfoMutator(mctx)
}
func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -628,20 +724,13 @@
ctx.ModuleErrorf("filename should end in %s for apex_set", imageApexSuffix)
}
- apexSet := a.prebuiltCommon.prebuilt.SingleSourcePath(ctx)
+ inputApex := android.OptionalPathForModuleSrc(ctx, a.selectedApexProperties.Selected_apex).Path()
a.outputApex = android.PathForModuleOut(ctx, a.installFilename)
- ctx.Build(pctx,
- android.BuildParams{
- Rule: extractMatchingApex,
- Description: "Extract an apex from an apex set",
- Inputs: android.Paths{apexSet},
- Output: a.outputApex,
- Args: map[string]string{
- "abis": strings.Join(java.SupportedAbis(ctx), ","),
- "allow-prereleased": strconv.FormatBool(proptools.Bool(a.properties.Prerelease)),
- "sdk-version": ctx.Config().PlatformSdkVersion().String(),
- },
- })
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: inputApex,
+ Output: a.outputApex,
+ })
if a.prebuiltCommon.checkForceDisable(ctx) {
a.HideFromMake()
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index affb5ce..8049108 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -1,86 +1,110 @@
package cquery
import (
+ "fmt"
"strings"
)
var (
- GetOutputFiles RequestType = &getOutputFilesRequestType{}
- GetOutputFilesAndCcObjectFiles RequestType = &getOutputFilesAndCcObjectFilesType{}
+ GetOutputFiles = &getOutputFilesRequestType{}
+ GetCcInfo = &getCcInfoType{}
)
-type GetOutputFilesAndCcObjectFiles_Result struct {
- OutputFiles []string
- CcObjectFiles []string
-}
-
-type RequestType interface {
- // Name returns a string name for this request type. Such request type names must be unique,
- // and must only consist of alphanumeric characters.
- Name() string
-
- // StarlarkFunctionBody returns a straark 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.
- StarlarkFunctionBody() string
-
- // 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.
- // The type of this value depends on the request type; it is up to the caller to
- // cast to the correct type.
- ParseResult(rawString string) interface{}
+type CcInfo struct {
+ OutputFiles []string
+ CcObjectFiles []string
+ CcStaticLibraryFiles []string
}
type getOutputFilesRequestType 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 {
return "getOutputFiles"
}
+// 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 getOutputFilesRequestType) StarlarkFunctionBody() string {
return "return ', '.join([f.path for f in target.files.to_list()])"
}
-func (g getOutputFilesRequestType) ParseResult(rawString string) interface{} {
- return strings.Split(rawString, ", ")
+// 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 getOutputFilesRequestType) ParseResult(rawString string) []string {
+ return splitOrEmpty(rawString, ", ")
}
-type getOutputFilesAndCcObjectFilesType struct{}
+type getCcInfoType struct{}
-func (g getOutputFilesAndCcObjectFilesType) Name() string {
- return "getOutputFilesAndCcObjectFiles"
+// 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 getCcInfoType) Name() string {
+ return "getCcInfo"
}
-func (g getOutputFilesAndCcObjectFilesType) StarlarkFunctionBody() string {
+// 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 getCcInfoType) StarlarkFunctionBody() string {
return `
outputFiles = [f.path for f in target.files.to_list()]
ccObjectFiles = []
+staticLibraries = []
linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
for linker_input in linker_inputs:
for library in linker_input.libraries:
for object in library.objects:
ccObjectFiles += [object.path]
-return ', '.join(outputFiles) + "|" + ', '.join(ccObjectFiles)`
+ if library.static_library:
+ staticLibraries.append(library.static_library.path)
+
+returns = [
+ outputFiles,
+ staticLibraries,
+ ccObjectFiles,
+]
+
+return "|".join([", ".join(r) for r in returns])`
}
-func (g getOutputFilesAndCcObjectFilesType) ParseResult(rawString string) interface{} {
+// 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 getCcInfoType) ParseResult(rawString string) (CcInfo, error) {
var outputFiles []string
var ccObjects []string
splitString := strings.Split(rawString, "|")
+ if expectedLen := 3; len(splitString) != expectedLen {
+ return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString)
+ }
outputFilesString := splitString[0]
- ccObjectsString := splitString[1]
+ ccStaticLibrariesString := splitString[1]
+ ccObjectsString := splitString[2]
outputFiles = splitOrEmpty(outputFilesString, ", ")
+ ccStaticLibraries := splitOrEmpty(ccStaticLibrariesString, ", ")
ccObjects = splitOrEmpty(ccObjectsString, ", ")
- return GetOutputFilesAndCcObjectFiles_Result{outputFiles, ccObjects}
+ return CcInfo{
+ OutputFiles: outputFiles,
+ CcObjectFiles: ccObjects,
+ CcStaticLibraryFiles: ccStaticLibraries,
+ }, nil
}
// splitOrEmpty is a modification of strings.Split() that returns an empty list
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
new file mode 100644
index 0000000..56e03e2
--- /dev/null
+++ b/bazel/cquery/request_type_test.go
@@ -0,0 +1,89 @@
+package cquery
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+)
+
+func TestGetOutputFilesParseResults(t *testing.T) {
+ testCases := []struct {
+ description string
+ input string
+ expectedOutput []string
+ }{
+ {
+ description: "no result",
+ input: "",
+ expectedOutput: []string{},
+ },
+ {
+ description: "one result",
+ input: "test",
+ expectedOutput: []string{"test"},
+ },
+ {
+ description: "splits on comma with space",
+ input: "foo, bar",
+ expectedOutput: []string{"foo", "bar"},
+ },
+ }
+ for _, tc := range testCases {
+ actualOutput := GetOutputFiles.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
+ input string
+ expectedOutput CcInfo
+ expectedErrorMessage string
+ }{
+ {
+ description: "no result",
+ input: "||",
+ expectedOutput: CcInfo{
+ OutputFiles: []string{},
+ CcObjectFiles: []string{},
+ CcStaticLibraryFiles: []string{},
+ },
+ },
+ {
+ description: "only output",
+ input: "test||",
+ expectedOutput: CcInfo{
+ OutputFiles: []string{"test"},
+ CcObjectFiles: []string{},
+ CcStaticLibraryFiles: []string{},
+ },
+ },
+ {
+ description: "all items set",
+ input: "out1, out2|static_lib1, static_lib2|object1, object2",
+ expectedOutput: CcInfo{
+ OutputFiles: []string{"out1", "out2"},
+ CcObjectFiles: []string{"object1", "object2"},
+ CcStaticLibraryFiles: []string{"static_lib1", "static_lib2"},
+ },
+ },
+ {
+ description: "too few result splits",
+ input: "|",
+ expectedOutput: CcInfo{},
+ expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 3, []string{"", ""}),
+ },
+ }
+ for _, tc := range testCases {
+ actualOutput, err := GetCcInfo.ParseResult(tc.input)
+ if (err == nil && tc.expectedErrorMessage != "") ||
+ (err != nil && err.Error() != tc.expectedErrorMessage) {
+ t.Errorf("%q: expected Error %s, got %s", tc.description, tc.expectedErrorMessage, err)
+ } else if err == nil && !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+ t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
+ }
+ }
+}
diff --git a/bazel/properties.go b/bazel/properties.go
index 148386f..4bb2391 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "path/filepath"
"regexp"
"sort"
)
@@ -47,6 +48,57 @@
Excludes []Label
}
+// GlobsInDir returns a list of glob expressions for a list of extensions
+// (optionally recursive) within a directory.
+func GlobsInDir(dir string, recursive bool, extensions []string) []string {
+ globs := []string{}
+
+ globInfix := ""
+ if dir == "." {
+ if recursive {
+ // e.g "**/*.h"
+ globInfix = "**/"
+ } // else e.g. "*.h"
+ for _, ext := range extensions {
+ globs = append(globs, globInfix+"*"+ext)
+ }
+ } else {
+ if recursive {
+ // e.g. "foo/bar/**/*.h"
+ dir += "/**"
+ } // else e.g. "foo/bar/*.h"
+ for _, ext := range extensions {
+ globs = append(globs, dir+"/*"+ext)
+ }
+ }
+ return globs
+}
+
+// LooseHdrsGlobs returns the list of non-recursive header globs for each parent directory of
+// each source file in this LabelList's Includes.
+func (ll *LabelList) LooseHdrsGlobs(exts []string) []string {
+ var globs []string
+ for _, parentDir := range ll.uniqueParentDirectories() {
+ globs = append(globs,
+ GlobsInDir(parentDir, false, exts)...)
+ }
+ return globs
+}
+
+// uniqueParentDirectories returns a list of the unique parent directories for
+// all files in ll.Includes.
+func (ll *LabelList) uniqueParentDirectories() []string {
+ dirMap := map[string]bool{}
+ for _, label := range ll.Includes {
+ dirMap[filepath.Dir(label.Label)] = true
+ }
+ dirs := []string{}
+ for dir := range dirMap {
+ dirs = append(dirs, dir)
+ }
+ return dirs
+}
+
// Append appends the fields of other labelList to the corresponding fields of ll.
func (ll *LabelList) Append(other LabelList) {
if len(ll.Includes) > 0 || len(other.Includes) > 0 {
@@ -224,6 +276,26 @@
return LabelListAttribute{Value: UniqueBazelLabelList(value)}
}
+// Append appends all values, including os and arch specific ones, from another
+// LabelListAttribute to this LabelListAttribute.
+func (attrs *LabelListAttribute) Append(other LabelListAttribute) {
+ for arch := range PlatformArchMap {
+ this := attrs.GetValueForArch(arch)
+ that := other.GetValueForArch(arch)
+ this.Append(that)
+ attrs.SetValueForArch(arch, this)
+ }
+
+ for os := range PlatformOsMap {
+ this := attrs.GetValueForOS(os)
+ that := other.GetValueForOS(os)
+ this.Append(that)
+ attrs.SetValueForOS(os, this)
+ }
+
+ attrs.Value.Append(other.Value)
+}
+
// HasArchSpecificValues returns true if the attribute contains
// architecture-specific label_list values.
func (attrs LabelListAttribute) HasConfigurableValues() bool {
diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go
index 653c489..764cded 100644
--- a/bloaty/bloaty.go
+++ b/bloaty/bloaty.go
@@ -23,7 +23,7 @@
)
const bloatyDescriptorExt = ".bloaty.csv"
-const protoFilename = "binary_sizes.pb"
+const protoFilename = "binary_sizes.pb.gz"
var (
fileSizeMeasurerKey blueprint.ProviderKey
diff --git a/bloaty/bloaty_merger.py b/bloaty/bloaty_merger.py
index c873fb8..1034462 100644
--- a/bloaty/bloaty_merger.py
+++ b/bloaty/bloaty_merger.py
@@ -16,12 +16,13 @@
Merges a list of .csv files from Bloaty into a protobuf. It takes the list as
a first argument and the output as second. For instance:
- $ bloaty_merger binary_sizes.lst binary_sizes.pb
+ $ bloaty_merger binary_sizes.lst binary_sizes.pb.gz
"""
import argparse
import csv
+import gzip
import ninja_rsp
@@ -57,7 +58,8 @@
Args:
input_list: The path to the file which contains the list of CSV files. Each
filepath is separated by a space.
- output_proto: The path for the output protobuf.
+ output_proto: The path for the output protobuf. It will be compressed using
+ gzip.
"""
metrics = file_sections_pb2.FileSizeMetrics()
reader = ninja_rsp.NinjaRspFileReader(input_list)
@@ -65,7 +67,7 @@
file_proto = parse_csv(csv_path)
if file_proto:
metrics.files.append(file_proto)
- with open(output_proto, "wb") as output:
+ with gzip.open(output_proto, "wb") as output:
output.write(metrics.SerializeToString())
def main():
diff --git a/bloaty/bloaty_merger_test.py b/bloaty/bloaty_merger_test.py
index 0e3641d..9de049a 100644
--- a/bloaty/bloaty_merger_test.py
+++ b/bloaty/bloaty_merger_test.py
@@ -11,6 +11,7 @@
# 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.
+import gzip
import unittest
from pyfakefs import fake_filesystem_unittest
@@ -53,10 +54,10 @@
self.fs.create_file("file1.bloaty.csv", contents=file1_content)
self.fs.create_file("file2.bloaty.csv", contents=file2_content)
- bloaty_merger.create_file_size_metrics("files.lst", "output.pb")
+ bloaty_merger.create_file_size_metrics("files.lst", "output.pb.gz")
metrics = file_sections_pb2.FileSizeMetrics()
- with open("output.pb", "rb") as output:
+ with gzip.open("output.pb.gz", "rb") as output:
metrics.ParseFromString(output.read())
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index cc616f2..d2a8729 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -26,6 +26,7 @@
testSrcs: [
"build_conversion_test.go",
"bzl_conversion_test.go",
+ "cc_library_conversion_test.go",
"cc_library_headers_conversion_test.go",
"cc_library_static_conversion_test.go",
"cc_object_conversion_test.go",
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index dd14c7d..b7a2810 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -374,16 +374,9 @@
// value>)" to set the default value of unset attributes. In the cases
// where the bp2build converter didn't set the default value within the
// mutator when creating the BazelTargetModule, this would be a zero
- // value. For those cases, we return a non-surprising default value so
- // generated BUILD files are syntactically correct.
- switch propertyValue.Kind() {
- case reflect.Slice:
- return "[]", nil
- case reflect.Map:
- return "{}", nil
- default:
- return "", nil
- }
+ // value. For those cases, we return an empty string so we don't
+ // unnecessarily generate empty values.
+ return "", nil
}
var ret string
@@ -397,21 +390,38 @@
case reflect.Ptr:
return prettyPrint(propertyValue.Elem(), indent)
case reflect.Slice:
- ret = "[\n"
- for i := 0; i < propertyValue.Len(); i++ {
- indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
+ if propertyValue.Len() == 0 {
+ return "", nil
+ }
+
+ if propertyValue.Len() == 1 {
+ // Single-line list for list with only 1 element
+ ret += "["
+ indexedValue, err := prettyPrint(propertyValue.Index(0), indent)
if err != nil {
return "", err
}
+ ret += indexedValue
+ ret += "]"
+ } else {
+ // otherwise, use a multiline list.
+ ret += "[\n"
+ for i := 0; i < propertyValue.Len(); i++ {
+ indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
+ if err != nil {
+ return "", err
+ }
- if indexedValue != "" {
- ret += makeIndent(indent + 1)
- ret += indexedValue
- ret += ",\n"
+ if indexedValue != "" {
+ ret += makeIndent(indent + 1)
+ ret += indexedValue
+ ret += ",\n"
+ }
}
+ ret += makeIndent(indent)
+ ret += "]"
}
- ret += makeIndent(indent)
- ret += "]"
+
case reflect.Struct:
// Special cases where the bp2build sends additional information to the codegenerator
// by wrapping the attributes in a custom struct type.
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 49897b3..1ede442 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -27,9 +27,7 @@
expectedBazelTarget string
}{
{
- bp: `custom {
- name: "foo",
-}
+ bp: `custom { name: "foo" }
`,
expectedBazelTarget: `soong_module(
name = "foo",
@@ -85,9 +83,7 @@
soong_module_variant = "",
soong_module_deps = [
],
- required = [
- "bar",
- ],
+ required = ["bar"],
)`,
},
{
@@ -116,12 +112,10 @@
targets: ["goal_foo"],
tag: ".foo",
},
- dists: [
- {
- targets: ["goal_bar"],
- tag: ".bar",
- },
- ],
+ dists: [{
+ targets: ["goal_bar"],
+ tag: ".bar",
+ }],
}
`,
expectedBazelTarget: `soong_module(
@@ -133,18 +127,12 @@
],
dist = {
"tag": ".foo",
- "targets": [
- "goal_foo",
- ],
+ "targets": ["goal_foo"],
},
- dists = [
- {
- "tag": ".bar",
- "targets": [
- "goal_bar",
- ],
- },
- ],
+ dists = [{
+ "tag": ".bar",
+ "targets": ["goal_bar"],
+ }],
)`,
},
{
@@ -169,19 +157,13 @@
soong_module_variant = "",
soong_module_deps = [
],
- dists = [
- {
- "tag": ".tag",
- "targets": [
- "my_goal",
- ],
- },
- ],
+ dists = [{
+ "tag": ".tag",
+ "targets": ["my_goal"],
+ }],
owner = "custom_owner",
ramdisk = True,
- required = [
- "bar",
- ],
+ required = ["bar"],
target_required = [
"qux",
"bazqux",
@@ -553,9 +535,7 @@
}`,
expectedBazelTargets: []string{`filegroup(
name = "fg_foo",
- srcs = [
- "b",
- ],
+ srcs = ["b"],
)`,
},
},
@@ -625,7 +605,7 @@
bp: `filegroup {
name: "foobar",
srcs: [
- ":foo",
+ ":foo",
"c",
],
bazel_module: { bp2build_available: true },
@@ -671,25 +651,15 @@
`genrule(
name = "foo",
cmd = "$(location :foo.tool) --genDir=$(GENDIR) arg $(SRCS) $(OUTS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
- tools = [
- ":foo.tool",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
+ tools = [":foo.tool"],
)`,
`genrule(
name = "foo.tool",
cmd = "cp $(SRCS) $(OUTS)",
- outs = [
- "foo_tool.out",
- ],
- srcs = [
- "foo_tool.in",
- ],
+ outs = ["foo_tool.out"],
+ srcs = ["foo_tool.in"],
)`,
},
},
@@ -718,15 +688,9 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(locations :foo.tools) -s $(OUTS) $(SRCS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
- tools = [
- ":foo.tools",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
+ tools = [":foo.tools"],
)`,
`genrule(
name = "foo.tools",
@@ -735,9 +699,7 @@
"foo_tool.out",
"foo_tool2.out",
],
- srcs = [
- "foo_tool.in",
- ],
+ srcs = ["foo_tool.in"],
)`,
},
},
@@ -758,15 +720,9 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
- tools = [
- "//other:foo.tool",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
+ tools = ["//other:foo.tool"],
)`,
},
fs: otherGenruleBp,
@@ -788,15 +744,9 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "//other:other.tool",
- ],
- tools = [
- "//other:foo.tool",
- ],
+ outs = ["foo.out"],
+ srcs = ["//other:other.tool"],
+ tools = ["//other:foo.tool"],
)`,
},
fs: otherGenruleBp,
@@ -818,12 +768,8 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(location //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
tools = [
"//other:foo.tool",
"//other:other.tool",
@@ -849,12 +795,8 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
tools = [
"//other:foo.tool",
"//other:other.tool",
@@ -879,12 +821,8 @@
expectedBazelTargets: []string{`genrule(
name = "foo",
cmd = "cp $(SRCS) $(OUTS)",
- outs = [
- "foo.out",
- ],
- srcs = [
- "foo.in",
- ],
+ outs = ["foo.out"],
+ srcs = ["foo.in"],
)`,
},
},
@@ -988,12 +926,8 @@
expectedBazelTarget: `genrule(
name = "gen",
cmd = "do-something $(SRCS) $(OUTS)",
- outs = [
- "out",
- ],
- srcs = [
- "in1",
- ],
+ outs = ["out"],
+ srcs = ["in1"],
)`,
description: "genrule applies properties from a genrule_defaults dependency if not specified",
},
@@ -1062,12 +996,8 @@
expectedBazelTarget: `genrule(
name = "gen",
cmd = "cp $(SRCS) $(OUTS)",
- outs = [
- "out",
- ],
- srcs = [
- "in1",
- ],
+ outs = ["out"],
+ srcs = ["in1"],
)`,
description: "genrule applies properties from list of genrule_defaults",
},
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
new file mode 100644
index 0000000..783af2e
--- /dev/null
+++ b/bp2build/cc_library_conversion_test.go
@@ -0,0 +1,271 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+ "android/soong/android"
+ "android/soong/cc"
+ "strings"
+ "testing"
+)
+
+const (
+ // See cc/testing.go for more context
+ soongCcLibraryPreamble = `
+cc_defaults {
+ name: "linux_bionic_supported",
+}
+
+toolchain_library {
+ name: "libclang_rt.builtins-x86_64-android",
+ defaults: ["linux_bionic_supported"],
+ vendor_available: true,
+ vendor_ramdisk_available: true,
+ product_available: true,
+ recovery_available: true,
+ native_bridge_supported: true,
+ src: "",
+}`
+)
+
+func TestCcLibraryBp2Build(t *testing.T) {
+ testCases := []struct {
+ description string
+ moduleTypeUnderTest string
+ moduleTypeUnderTestFactory android.ModuleFactory
+ moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+ bp string
+ expectedBazelTargets []string
+ filesystem map[string]string
+ dir string
+ }{
+ {
+ description: "cc_library - simple example",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ filesystem: map[string]string{
+ "android.cpp": "",
+ "darwin.cpp": "",
+ // Refer to cc.headerExts for the supported header extensions in Soong.
+ "header.h": "",
+ "header.hh": "",
+ "header.hpp": "",
+ "header.hxx": "",
+ "header.h++": "",
+ "header.inl": "",
+ "header.inc": "",
+ "header.ipp": "",
+ "header.h.generic": "",
+ "impl.cpp": "",
+ "linux.cpp": "",
+ "x86.cpp": "",
+ "x86_64.cpp": "",
+ "foo-dir/a.h": "",
+ },
+ bp: soongCcLibraryPreamble + `
+cc_library_headers { name: "some-headers" }
+cc_library {
+ name: "foo-lib",
+ srcs: ["impl.cpp"],
+ cflags: ["-Wall"],
+ header_libs: ["some-headers"],
+ export_include_dirs: ["foo-dir"],
+ ldflags: ["-Wl,--exclude-libs=bar.a"],
+ arch: {
+ x86: {
+ ldflags: ["-Wl,--exclude-libs=baz.a"],
+ srcs: ["x86.cpp"],
+ },
+ x86_64: {
+ ldflags: ["-Wl,--exclude-libs=qux.a"],
+ srcs: ["x86_64.cpp"],
+ },
+ },
+ target: {
+ android: {
+ srcs: ["android.cpp"],
+ },
+ linux_glibc: {
+ srcs: ["linux.cpp"],
+ },
+ darwin: {
+ srcs: ["darwin.cpp"],
+ },
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "foo-lib",
+ copts = ["-Wall"],
+ deps = [":some-headers"],
+ hdrs = [
+ "header.h",
+ "header.hh",
+ "header.hpp",
+ "header.hxx",
+ "header.h++",
+ "header.inl",
+ "header.inc",
+ "header.ipp",
+ "header.h.generic",
+ "foo-dir/a.h",
+ ],
+ includes = ["foo-dir"],
+ linkopts = ["-Wl,--exclude-libs=bar.a"] + select({
+ "//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=baz.a"],
+ "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=qux.a"],
+ "//conditions:default": [],
+ }),
+ srcs = ["impl.cpp"] + select({
+ "//build/bazel/platforms/arch:x86": ["x86.cpp"],
+ "//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": ["android.cpp"],
+ "//build/bazel/platforms/os:darwin": ["darwin.cpp"],
+ "//build/bazel/platforms/os:linux": ["linux.cpp"],
+ "//conditions:default": [],
+ }),
+)`},
+ },
+ {
+ description: "cc_library - trimmed example of //bionic/linker:ld-android",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ filesystem: map[string]string{
+ "ld-android.cpp": "",
+ "linked_list.h": "",
+ "linker.h": "",
+ "linker_block_allocator.h": "",
+ "linker_cfi.h": "",
+ },
+ bp: soongCcLibraryPreamble + `
+cc_library_headers { name: "libc_headers" }
+cc_library {
+ name: "fake-ld-android",
+ srcs: ["ld_android.cpp"],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Wunused",
+ "-Werror",
+ ],
+ header_libs: ["libc_headers"],
+ ldflags: [
+ "-Wl,--exclude-libs=libgcc.a",
+ "-Wl,--exclude-libs=libgcc_stripped.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
+ ],
+ arch: {
+ x86: {
+ ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+ },
+ x86_64: {
+ ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
+ },
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library(
+ name = "fake-ld-android",
+ copts = [
+ "-Wall",
+ "-Wextra",
+ "-Wunused",
+ "-Werror",
+ ],
+ deps = [":libc_headers"],
+ hdrs = [
+ "linked_list.h",
+ "linker.h",
+ "linker_block_allocator.h",
+ "linker_cfi.h",
+ ],
+ linkopts = [
+ "-Wl,--exclude-libs=libgcc.a",
+ "-Wl,--exclude-libs=libgcc_stripped.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a",
+ "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
+ ] + select({
+ "//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=libgcc_eh.a"],
+ "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=libgcc_eh.a"],
+ "//conditions:default": [],
+ }),
+ srcs = ["ld_android.cpp"],
+)`},
+ },
+ }
+
+ dir := "."
+ for _, testCase := range testCases {
+ filesystem := make(map[string][]byte)
+ toParse := []string{
+ "Android.bp",
+ }
+ for f, content := range testCase.filesystem {
+ if strings.HasSuffix(f, "Android.bp") {
+ toParse = append(toParse, f)
+ }
+ filesystem[f] = []byte(content)
+ }
+ config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
+ ctx := android.NewTestContext(config)
+
+ cc.RegisterCCBuildComponents(ctx)
+ ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
+ ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
+ ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+ ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
+ ctx.RegisterBp2BuildConfig(bp2buildConfig) // TODO(jingwen): make this the default for all tests
+ ctx.RegisterForBazelConversion()
+
+ _, errs := ctx.ParseFileList(dir, toParse)
+ if Errored(t, testCase.description, errs) {
+ continue
+ }
+ _, errs = ctx.ResolveDependencies(config)
+ if Errored(t, testCase.description, errs) {
+ continue
+ }
+
+ checkDir := dir
+ if testCase.dir != "" {
+ checkDir = testCase.dir
+ }
+ codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+ bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
+ if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
+ t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
+ } else {
+ for i, target := range bazelTargets {
+ if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
+ t.Errorf(
+ "%s: Expected generated Bazel target to be '%s', got '%s'",
+ testCase.description,
+ w,
+ g,
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index 74226ae..c59241f 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -23,7 +23,7 @@
const (
// See cc/testing.go for more context
- soongCcLibraryPreamble = `
+ soongCcLibraryHeadersPreamble = `
cc_defaults {
name: "linux_bionic_supported",
}
@@ -98,7 +98,7 @@
"arch_x86_exported_include_dir/b.h": "",
"arch_x86_64_exported_include_dir/c.h": "",
},
- bp: soongCcLibraryPreamble + `
+ bp: soongCcLibraryHeadersPreamble + `
cc_library_headers {
name: "lib-1",
export_include_dirs: ["lib-1"],
@@ -141,30 +141,18 @@
"dir-2/dir2a.h",
"dir-2/dir2b.h",
] + select({
- "//build/bazel/platforms/arch:arm64": [
- "arch_arm64_exported_include_dir/a.h",
- ],
- "//build/bazel/platforms/arch:x86": [
- "arch_x86_exported_include_dir/b.h",
- ],
- "//build/bazel/platforms/arch:x86_64": [
- "arch_x86_64_exported_include_dir/c.h",
- ],
+ "//build/bazel/platforms/arch:arm64": ["arch_arm64_exported_include_dir/a.h"],
+ "//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir/b.h"],
+ "//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir/c.h"],
"//conditions:default": [],
}),
includes = [
"dir-1",
"dir-2",
] + select({
- "//build/bazel/platforms/arch:arm64": [
- "arch_arm64_exported_include_dir",
- ],
- "//build/bazel/platforms/arch:x86": [
- "arch_x86_exported_include_dir",
- ],
- "//build/bazel/platforms/arch:x86_64": [
- "arch_x86_64_exported_include_dir",
- ],
+ "//build/bazel/platforms/arch:arm64": ["arch_arm64_exported_include_dir"],
+ "//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir"],
+ "//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir"],
"//conditions:default": [],
}),
)`, `cc_library_headers(
@@ -173,18 +161,14 @@
"lib-1/lib1a.h",
"lib-1/lib1b.h",
],
- includes = [
- "lib-1",
- ],
+ includes = ["lib-1"],
)`, `cc_library_headers(
name = "lib-2",
hdrs = [
"lib-2/lib2a.h",
"lib-2/lib2b.h",
],
- includes = [
- "lib-2",
- ],
+ includes = ["lib-2"],
)`},
},
{
@@ -223,27 +207,13 @@
name = "darwin-lib",
)`, `cc_library_headers(
name = "foo_headers",
- deps = [
- ":base-lib",
- ] + select({
- "//build/bazel/platforms/os:android": [
- ":android-lib",
- ],
- "//build/bazel/platforms/os:darwin": [
- ":darwin-lib",
- ],
- "//build/bazel/platforms/os:fuchsia": [
- ":fuchsia-lib",
- ],
- "//build/bazel/platforms/os:linux": [
- ":linux-lib",
- ],
- "//build/bazel/platforms/os:linux_bionic": [
- ":linux_bionic-lib",
- ],
- "//build/bazel/platforms/os:windows": [
- ":windows-lib",
- ],
+ deps = [":base-lib"] + select({
+ "//build/bazel/platforms/os:android": [":android-lib"],
+ "//build/bazel/platforms/os:darwin": [":darwin-lib"],
+ "//build/bazel/platforms/os:fuchsia": [":fuchsia-lib"],
+ "//build/bazel/platforms/os:linux": [":linux-lib"],
+ "//build/bazel/platforms/os:linux_bionic": [":linux_bionic-lib"],
+ "//build/bazel/platforms/os:windows": [":windows-lib"],
"//conditions:default": [],
}),
)`, `cc_library_headers(
@@ -278,7 +248,7 @@
name = "exported-lib",
)`, `cc_library_headers(
name = "foo_headers",
- deps = [] + select({
+ deps = select({
"//build/bazel/platforms/os:android": [
":android-lib",
":exported-lib",
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 467b0b2..427aed3 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -101,6 +101,9 @@
"export_include_dir_1/export_include_dir_1_b.h": "",
"export_include_dir_2/export_include_dir_2_a.h": "",
"export_include_dir_2/export_include_dir_2_b.h": "",
+ // NOTE: Soong implicitly includes headers in the current directory
+ "implicit_include_1.h": "",
+ "implicit_include_2.h": "",
},
bp: soongCcLibraryStaticPreamble + `
cc_library_headers {
@@ -191,6 +194,8 @@
":whole_static_lib_2",
],
hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
"export_include_dir_1/export_include_dir_1_a.h",
"export_include_dir_1/export_include_dir_1_b.h",
"export_include_dir_2/export_include_dir_2_a.h",
@@ -203,35 +208,74 @@
"include_dir_2",
"local_include_dir_1",
"local_include_dir_2",
+ ".",
],
linkstatic = True,
srcs = [
"foo_static1.cc",
"foo_static2.cc",
+ "include_dir_1/include_dir_1_a.h",
+ "include_dir_1/include_dir_1_b.h",
+ "include_dir_2/include_dir_2_a.h",
+ "include_dir_2/include_dir_2_b.h",
+ "local_include_dir_1/local_include_dir_1_a.h",
+ "local_include_dir_1/local_include_dir_1_b.h",
+ "local_include_dir_2/local_include_dir_2_a.h",
+ "local_include_dir_2/local_include_dir_2_b.h",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`, `cc_library_static(
name = "static_lib_1",
+ hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
+ ],
+ includes = ["."],
linkstatic = True,
srcs = [
"static_lib_1.cc",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`, `cc_library_static(
name = "static_lib_2",
+ hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
+ ],
+ includes = ["."],
linkstatic = True,
srcs = [
"static_lib_2.cc",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`, `cc_library_static(
name = "whole_static_lib_1",
+ hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
+ ],
+ includes = ["."],
linkstatic = True,
srcs = [
"whole_static_lib_1.cc",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`, `cc_library_static(
name = "whole_static_lib_2",
+ hdrs = [
+ "implicit_include_1.h",
+ "implicit_include_2.h",
+ ],
+ includes = ["."],
linkstatic = True,
srcs = [
"whole_static_lib_2.cc",
+ "implicit_include_1.h",
+ "implicit_include_2.h",
],
)`},
},
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index 4f3babe..a9d24ac 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -52,7 +52,6 @@
"-Werror",
],
srcs: [
- "a/b/*.h",
"a/b/*.c"
],
exclude_srcs: ["a/b/exclude.c"],
@@ -68,15 +67,15 @@
"-Wall",
"-Werror",
],
+ hdrs = [
+ "a/b/bar.h",
+ "a/b/foo.h",
+ ],
local_include_dirs = [
"include",
".",
],
- srcs = [
- "a/b/bar.h",
- "a/b/c.c",
- "a/b/foo.h",
- ],
+ srcs = ["a/b/c.c"],
)`,
},
},
@@ -123,9 +122,7 @@
"include",
".",
],
- srcs = [
- "a/b/c.c",
- ],
+ srcs = ["a/b/c.c"],
)`,
},
},
@@ -155,29 +152,15 @@
`,
expectedBazelTargets: []string{`cc_object(
name = "bar",
- copts = [
- "-fno-addrsig",
- ],
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "x/y/z.c",
- ],
+ copts = ["-fno-addrsig"],
+ local_include_dirs = ["."],
+ srcs = ["x/y/z.c"],
)`, `cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ],
- deps = [
- ":bar",
- ],
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "a/b/c.c",
- ],
+ copts = ["-fno-addrsig"],
+ deps = [":bar"],
+ local_include_dirs = ["."],
+ srcs = ["a/b/c.c"],
)`,
},
},
@@ -200,12 +183,8 @@
`,
expectedBazelTargets: []string{`cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ],
- srcs = [
- "a/b/c.c",
- ],
+ copts = ["-fno-addrsig"],
+ srcs = ["a/b/c.c"],
)`,
},
},
@@ -228,12 +207,8 @@
`,
expectedBazelTargets: []string{`cc_object(
name = "foo",
- asflags = [
- "-DPLATFORM_SDK_VERSION={Platform_sdk_version}",
- ],
- copts = [
- "-fno-addrsig",
- ],
+ asflags = ["-DPLATFORM_SDK_VERSION={Platform_sdk_version}"],
+ copts = ["-fno-addrsig"],
)`,
},
},
@@ -321,23 +296,13 @@
expectedBazelTargets: []string{
`cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ] + select({
- "//build/bazel/platforms/arch:x86": [
- "-fPIC",
- ],
+ copts = ["-fno-addrsig"] + select({
+ "//build/bazel/platforms/arch:x86": ["-fPIC"],
"//conditions:default": [],
}),
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "a.cpp",
- ] + select({
- "//build/bazel/platforms/arch:arm": [
- "arch/arm/file.S",
- ],
+ local_include_dirs = ["."],
+ srcs = ["a.cpp"] + select({
+ "//build/bazel/platforms/arch:arm": ["arch/arm/file.S"],
"//conditions:default": [],
}),
)`,
@@ -375,41 +340,19 @@
expectedBazelTargets: []string{
`cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ] + select({
- "//build/bazel/platforms/arch:arm": [
- "-Wall",
- ],
- "//build/bazel/platforms/arch:arm64": [
- "-Wall",
- ],
- "//build/bazel/platforms/arch:x86": [
- "-fPIC",
- ],
- "//build/bazel/platforms/arch:x86_64": [
- "-fPIC",
- ],
+ copts = ["-fno-addrsig"] + select({
+ "//build/bazel/platforms/arch:arm": ["-Wall"],
+ "//build/bazel/platforms/arch:arm64": ["-Wall"],
+ "//build/bazel/platforms/arch:x86": ["-fPIC"],
+ "//build/bazel/platforms/arch:x86_64": ["-fPIC"],
"//conditions:default": [],
}),
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "base.cpp",
- ] + select({
- "//build/bazel/platforms/arch:arm": [
- "arm.cpp",
- ],
- "//build/bazel/platforms/arch:arm64": [
- "arm64.cpp",
- ],
- "//build/bazel/platforms/arch:x86": [
- "x86.cpp",
- ],
- "//build/bazel/platforms/arch:x86_64": [
- "x86_64.cpp",
- ],
+ local_include_dirs = ["."],
+ srcs = ["base.cpp"] + select({
+ "//build/bazel/platforms/arch:arm": ["arm.cpp"],
+ "//build/bazel/platforms/arch:arm64": ["arm64.cpp"],
+ "//build/bazel/platforms/arch:x86": ["x86.cpp"],
+ "//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
"//conditions:default": [],
}),
)`,
@@ -440,26 +383,14 @@
expectedBazelTargets: []string{
`cc_object(
name = "foo",
- copts = [
- "-fno-addrsig",
- ] + select({
- "//build/bazel/platforms/os:android": [
- "-fPIC",
- ],
- "//build/bazel/platforms/os:darwin": [
- "-Wall",
- ],
- "//build/bazel/platforms/os:windows": [
- "-fPIC",
- ],
+ copts = ["-fno-addrsig"] + select({
+ "//build/bazel/platforms/os:android": ["-fPIC"],
+ "//build/bazel/platforms/os:darwin": ["-Wall"],
+ "//build/bazel/platforms/os:windows": ["-fPIC"],
"//conditions:default": [],
}),
- local_include_dirs = [
- ".",
- ],
- srcs = [
- "base.cpp",
- ],
+ local_include_dirs = ["."],
+ srcs = ["base.cpp"],
)`,
},
},
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index b2b3379..97729df 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -69,20 +69,26 @@
return ret, err
}
- // Create the selects for arch specific values.
- selectMap, err := prettyPrintSelectMap(archSelects, "[]", indent)
+ // Convenience function to append selects components to an attribute value.
+ appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
+ selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
+ if err != nil {
+ return "", err
+ }
+ if s != "" && selectMap != "" {
+ s += " + "
+ }
+ s += selectMap
+
+ return s, nil
+ }
+
+ ret, err = appendSelects(archSelects, "[]", ret)
if err != nil {
return "", err
}
- ret += selectMap
- // Create the selects for target os specific values.
- selectMap, err = prettyPrintSelectMap(osSelects, "[]", indent)
- if err != nil {
- return "", err
- }
- ret += selectMap
-
+ ret, err = appendSelects(osSelects, "[]", ret)
return ret, err
}
@@ -113,7 +119,7 @@
}
// Create the map.
- ret := " + select({\n"
+ ret := "select({\n"
ret += selects
// default condition comes last.
ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), "//conditions:default", defaultValue)
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 7600e36..2054e06 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -33,24 +33,15 @@
blueprint: `python_binary_host {
name: "foo",
main: "a.py",
- srcs: [
- "**/*.py"
- ],
- exclude_srcs: [
- "b/e.py"
- ],
- data: [
- "files/data.txt",
- ],
-
+ srcs: ["**/*.py"],
+ exclude_srcs: ["b/e.py"],
+ data: ["files/data.txt",],
bazel_module: { bp2build_available: true },
}
`,
expectedBazelTargets: []string{`py_binary(
name = "foo",
- data = [
- "files/data.txt",
- ],
+ data = ["files/data.txt"],
main = "a.py",
srcs = [
"a.py",
@@ -83,9 +74,7 @@
expectedBazelTargets: []string{`py_binary(
name = "foo",
python_version = "PY2",
- srcs = [
- "a.py",
- ],
+ srcs = ["a.py"],
)`,
},
},
@@ -113,9 +102,7 @@
// python_version is PY3 by default.
`py_binary(
name = "foo",
- srcs = [
- "a.py",
- ],
+ srcs = ["a.py"],
)`,
},
},
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
index 2aa373c..37f542e 100644
--- a/bp2build/sh_conversion_test.go
+++ b/bp2build/sh_conversion_test.go
@@ -74,9 +74,7 @@
}`,
expectedBazelTargets: []string{`sh_binary(
name = "foo",
- srcs = [
- "foo.sh",
- ],
+ srcs = ["foo.sh"],
)`},
},
}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index cffeb24..0bca30a 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -59,72 +59,111 @@
ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...)
}
-// bp2buildParseCflags creates a label list attribute containing the cflags of a module, including
-func bp2BuildParseCflags(ctx android.TopDownMutatorContext, module *Module) bazel.StringListAttribute {
- var ret bazel.StringListAttribute
+// Convenience struct to hold all attributes parsed from compiler properties.
+type compilerAttributes struct {
+ copts bazel.StringListAttribute
+ srcs bazel.LabelListAttribute
+ hdrs bazel.LabelListAttribute
+}
+
+// bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes.
+func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Module) compilerAttributes {
+ var hdrs, srcs bazel.LabelListAttribute
+ var copts bazel.StringListAttribute
+
+ hdrsAndSrcs := func(baseCompilerProps *BaseCompilerProperties) (bazel.LabelList, bazel.LabelList) {
+ srcsList := android.BazelLabelForModuleSrcExcludes(
+ ctx, baseCompilerProps.Srcs, baseCompilerProps.Exclude_srcs)
+ hdrsList := android.BazelLabelForModuleSrc(ctx, srcsList.LooseHdrsGlobs(headerExts))
+ return hdrsList, srcsList
+ }
+
for _, props := range module.compiler.compilerProps() {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
- ret.Value = baseCompilerProps.Cflags
+ hdrs.Value, srcs.Value = hdrsAndSrcs(baseCompilerProps)
+ copts.Value = baseCompilerProps.Cflags
break
}
}
for arch, props := range module.GetArchProperties(&BaseCompilerProperties{}) {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
- ret.SetValueForArch(arch.Name, baseCompilerProps.Cflags)
+ hdrsList, srcsList := hdrsAndSrcs(baseCompilerProps)
+ hdrs.SetValueForArch(arch.Name, bazel.SubtractBazelLabelList(hdrsList, hdrs.Value))
+ srcs.SetValueForArch(arch.Name, srcsList)
+ copts.SetValueForArch(arch.Name, baseCompilerProps.Cflags)
}
}
for os, props := range module.GetTargetProperties(&BaseCompilerProperties{}) {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
- ret.SetValueForOS(os.Name, baseCompilerProps.Cflags)
+ hdrsList, srcsList := hdrsAndSrcs(baseCompilerProps)
+ hdrs.SetValueForOS(os.Name, bazel.SubtractBazelLabelList(hdrsList, hdrs.Value))
+ srcs.SetValueForOS(os.Name, srcsList)
+ copts.SetValueForOS(os.Name, baseCompilerProps.Cflags)
}
}
- return ret
+ return compilerAttributes{
+ hdrs: hdrs,
+ srcs: srcs,
+ copts: copts,
+ }
}
-// bp2BuildParseHeaderLibs creates a label list attribute containing the header library deps of a module, including
+// Convenience struct to hold all attributes parsed from linker properties.
+type linkerAttributes struct {
+ deps bazel.LabelListAttribute
+ linkopts bazel.StringListAttribute
+}
+
+// bp2BuildParseLinkerProps creates a label list attribute containing the header library deps of a module, including
// configurable attribute values.
-func bp2BuildParseHeaderLibs(ctx android.TopDownMutatorContext, module *Module) bazel.LabelListAttribute {
- var ret bazel.LabelListAttribute
+func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) linkerAttributes {
+
+ var deps bazel.LabelListAttribute
+ var linkopts bazel.StringListAttribute
+
for _, linkerProps := range module.linker.linkerProps() {
if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok {
libs := baseLinkerProps.Header_libs
libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
- ret = bazel.MakeLabelListAttribute(
+ deps = bazel.MakeLabelListAttribute(
android.BazelLabelForModuleDeps(ctx, android.SortedUniqueStrings(libs)))
+ linkopts.Value = baseLinkerProps.Ldflags
break
}
}
+ for arch, p := range module.GetArchProperties(&BaseLinkerProperties{}) {
+ if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
+ libs := baseLinkerProps.Header_libs
+ libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
+ libs = android.SortedUniqueStrings(libs)
+ deps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, libs))
+ linkopts.SetValueForArch(arch.Name, baseLinkerProps.Ldflags)
+ }
+ }
+
for os, p := range module.GetTargetProperties(&BaseLinkerProperties{}) {
if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
libs := baseLinkerProps.Header_libs
libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
libs = android.SortedUniqueStrings(libs)
- ret.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs))
+ deps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs))
+ linkopts.SetValueForOS(os.Name, baseLinkerProps.Ldflags)
}
}
- return ret
+ return linkerAttributes{
+ deps: deps,
+ linkopts: linkopts,
+ }
}
func bp2BuildListHeadersInDir(ctx android.TopDownMutatorContext, includeDir string) bazel.LabelList {
- var globInfix string
-
- if includeDir == "." {
- globInfix = ""
- } else {
- globInfix = "/**"
- }
-
- var includeDirGlobs []string
- includeDirGlobs = append(includeDirGlobs, includeDir+globInfix+"/*.h")
- includeDirGlobs = append(includeDirGlobs, includeDir+globInfix+"/*.inc")
- includeDirGlobs = append(includeDirGlobs, includeDir+globInfix+"/*.hpp")
-
- return android.BazelLabelForModuleSrc(ctx, includeDirGlobs)
+ globs := bazel.GlobsInDir(includeDir, includeDir != ".", headerExts)
+ return android.BazelLabelForModuleSrc(ctx, globs)
}
// Bazel wants include paths to be relative to the module
diff --git a/cc/builder.go b/cc/builder.go
index 8c9743f..da8501c 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -132,7 +132,7 @@
blueprint.RuleParams{
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
- Command: "CROSS_COMPILE=$crossCompile XZ=$xzCmd CLANG_BIN=${config.ClangBin} $stripPath ${args} -i ${in} -o ${out} -d ${out}.d",
+ Command: "XZ=$xzCmd CLANG_BIN=${config.ClangBin} $stripPath ${args} -i ${in} -o ${out} -d ${out}.d",
CommandDeps: []string{"$stripPath", "$xzCmd"},
Pool: darwinStripPool,
},
diff --git a/cc/cc.go b/cc/cc.go
index 1ce83a9..9176bc3 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -56,8 +56,8 @@
ctx.TopDown("asan_deps", sanitizerDepsMutator(Asan))
ctx.BottomUp("asan", sanitizerMutator(Asan)).Parallel()
- ctx.TopDown("hwasan_deps", sanitizerDepsMutator(hwasan))
- ctx.BottomUp("hwasan", sanitizerMutator(hwasan)).Parallel()
+ ctx.TopDown("hwasan_deps", sanitizerDepsMutator(Hwasan))
+ ctx.BottomUp("hwasan", sanitizerMutator(Hwasan)).Parallel()
ctx.TopDown("fuzzer_deps", sanitizerDepsMutator(Fuzzer))
ctx.BottomUp("fuzzer", sanitizerMutator(Fuzzer)).Parallel()
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 465283d..e4dfc97 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -244,6 +244,120 @@
}
}
+func checkInstallPartition(t *testing.T, ctx *android.TestContext, name, variant, expected string) {
+ mod := ctx.ModuleForTests(name, variant).Module().(*Module)
+ partitionDefined := false
+ checkPartition := func(specific bool, partition string) {
+ if specific {
+ if expected != partition && !partitionDefined {
+ // The variant is installed to the 'partition'
+ t.Errorf("%s variant of %q must not be installed to %s partition", variant, name, partition)
+ }
+ partitionDefined = true
+ } else {
+ // The variant is not installed to the 'partition'
+ if expected == partition {
+ t.Errorf("%s variant of %q must be installed to %s partition", variant, name, partition)
+ }
+ }
+ }
+ socSpecific := func(m *Module) bool {
+ return m.SocSpecific() || m.socSpecificModuleContext()
+ }
+ deviceSpecific := func(m *Module) bool {
+ return m.DeviceSpecific() || m.deviceSpecificModuleContext()
+ }
+ productSpecific := func(m *Module) bool {
+ return m.ProductSpecific() || m.productSpecificModuleContext()
+ }
+ systemExtSpecific := func(m *Module) bool {
+ return m.SystemExtSpecific()
+ }
+ checkPartition(socSpecific(mod), "vendor")
+ checkPartition(deviceSpecific(mod), "odm")
+ checkPartition(productSpecific(mod), "product")
+ checkPartition(systemExtSpecific(mod), "system_ext")
+ if !partitionDefined && expected != "system" {
+ t.Errorf("%s variant of %q is expected to be installed to %s partition,"+
+ " but installed to system partition", variant, name, expected)
+ }
+}
+
+func TestInstallPartition(t *testing.T) {
+ t.Helper()
+ ctx := prepareForCcTest.RunTestWithBp(t, `
+ cc_library {
+ name: "libsystem",
+ }
+ cc_library {
+ name: "libsystem_ext",
+ system_ext_specific: true,
+ }
+ cc_library {
+ name: "libproduct",
+ product_specific: true,
+ }
+ cc_library {
+ name: "libvendor",
+ vendor: true,
+ }
+ cc_library {
+ name: "libodm",
+ device_specific: true,
+ }
+ cc_library {
+ name: "liball_available",
+ vendor_available: true,
+ product_available: true,
+ }
+ cc_library {
+ name: "libsystem_ext_all_available",
+ system_ext_specific: true,
+ vendor_available: true,
+ product_available: true,
+ }
+ cc_library {
+ name: "liball_available_odm",
+ odm_available: true,
+ product_available: true,
+ }
+ cc_library {
+ name: "libproduct_vendoravailable",
+ product_specific: true,
+ vendor_available: true,
+ }
+ cc_library {
+ name: "libproduct_odmavailable",
+ product_specific: true,
+ odm_available: true,
+ }
+ `).TestContext
+
+ checkInstallPartition(t, ctx, "libsystem", coreVariant, "system")
+ checkInstallPartition(t, ctx, "libsystem_ext", coreVariant, "system_ext")
+ checkInstallPartition(t, ctx, "libproduct", productVariant, "product")
+ checkInstallPartition(t, ctx, "libvendor", vendorVariant, "vendor")
+ checkInstallPartition(t, ctx, "libodm", vendorVariant, "odm")
+
+ checkInstallPartition(t, ctx, "liball_available", coreVariant, "system")
+ checkInstallPartition(t, ctx, "liball_available", productVariant, "product")
+ checkInstallPartition(t, ctx, "liball_available", vendorVariant, "vendor")
+
+ checkInstallPartition(t, ctx, "libsystem_ext_all_available", coreVariant, "system_ext")
+ checkInstallPartition(t, ctx, "libsystem_ext_all_available", productVariant, "product")
+ checkInstallPartition(t, ctx, "libsystem_ext_all_available", vendorVariant, "vendor")
+
+ checkInstallPartition(t, ctx, "liball_available_odm", coreVariant, "system")
+ checkInstallPartition(t, ctx, "liball_available_odm", productVariant, "product")
+ checkInstallPartition(t, ctx, "liball_available_odm", vendorVariant, "odm")
+
+ checkInstallPartition(t, ctx, "libproduct_vendoravailable", productVariant, "product")
+ checkInstallPartition(t, ctx, "libproduct_vendoravailable", vendorVariant, "vendor")
+
+ checkInstallPartition(t, ctx, "libproduct_odmavailable", productVariant, "product")
+ checkInstallPartition(t, ctx, "libproduct_odmavailable", vendorVariant, "odm")
+}
+
func checkVndkModule(t *testing.T, ctx *android.TestContext, name, subDir string,
isVndkSp bool, extends string, variant string) {
diff --git a/cc/gen.go b/cc/gen.go
index 83c019c..b152e02 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -111,9 +111,7 @@
return ret
}
-func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile android.Path,
- outFile, depFile android.ModuleGenPath, aidlFlags string) android.Paths {
-
+func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile android.Path, aidlFlags string) (cppFile android.OutputPath, headerFiles android.Paths) {
aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base())
baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext())
shortName := baseName
@@ -126,6 +124,8 @@
}
outDir := android.PathForModuleGen(ctx, "aidl")
+ cppFile = outDir.Join(ctx, aidlPackage, baseName+".cpp")
+ depFile := outDir.Join(ctx, aidlPackage, baseName+".cpp.d")
headerI := outDir.Join(ctx, aidlPackage, baseName+".h")
headerBn := outDir.Join(ctx, aidlPackage, "Bn"+shortName+".h")
headerBp := outDir.Join(ctx, aidlPackage, "Bp"+shortName+".h")
@@ -142,14 +142,14 @@
Flag(aidlFlags).
Input(aidlFile).
OutputDir().
- Output(outFile).
+ Output(cppFile).
ImplicitOutputs(android.WritablePaths{
headerI,
headerBn,
headerBp,
})
- return android.Paths{
+ return cppFile, android.Paths{
headerI,
headerBn,
headerBp,
@@ -293,10 +293,9 @@
aidlRule = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "aidl"),
android.PathForModuleGen(ctx, "aidl.sbox.textproto"))
}
- cppFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp")
- depFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp.d")
+ cppFile, aidlHeaders := genAidl(ctx, aidlRule, srcFile, buildFlags.aidlFlags)
srcFiles[i] = cppFile
- aidlHeaders := genAidl(ctx, aidlRule, srcFile, cppFile, depFile, buildFlags.aidlFlags)
+
info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...)
// Use the generated headers as order only deps to ensure that they are up to date when
// needed.
diff --git a/cc/image.go b/cc/image.go
index afe6a0e..ca00ac9 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -49,21 +49,15 @@
)
func (ctx *moduleContext) ProductSpecific() bool {
- // Additionally check if this module is inProduct() that means it is a "product" variant of a
- // module. As well as product specific modules, product variants must be installed to /product.
- return ctx.ModuleContext.ProductSpecific() || ctx.mod.InProduct()
+ return ctx.ModuleContext.ProductSpecific() || ctx.mod.productSpecificModuleContext()
}
func (ctx *moduleContext) SocSpecific() bool {
- // Additionally check if this module is inVendor() that means it is a "vendor" variant of a
- // module. As well as SoC specific modules, vendor variants must be installed to /vendor
- // unless they have "odm_available: true".
- return ctx.ModuleContext.SocSpecific() || (ctx.mod.InVendor() && !ctx.mod.VendorVariantToOdm())
+ return ctx.ModuleContext.SocSpecific() || ctx.mod.socSpecificModuleContext()
}
func (ctx *moduleContext) DeviceSpecific() bool {
- // Some vendor variants want to be installed to /odm by setting "odm_available: true".
- return ctx.ModuleContext.DeviceSpecific() || (ctx.mod.InVendor() && ctx.mod.VendorVariantToOdm())
+ return ctx.ModuleContext.DeviceSpecific() || ctx.mod.deviceSpecificModuleContext()
}
func (ctx *moduleContextImpl) inProduct() bool {
@@ -86,6 +80,24 @@
return ctx.mod.InRecovery()
}
+func (c *Module) productSpecificModuleContext() bool {
+ // Additionally check if this module is inProduct() that means it is a "product" variant of a
+ // module. As well as product specific modules, product variants must be installed to /product.
+ return c.InProduct()
+}
+
+func (c *Module) socSpecificModuleContext() bool {
+ // Additionally check if this module is inVendor() that means it is a "vendor" variant of a
+ // module. As well as SoC specific modules, vendor variants must be installed to /vendor
+ // unless they have "odm_available: true".
+ return c.HasVendorVariant() && c.InVendor() && !c.VendorVariantToOdm()
+}
+
+func (c *Module) deviceSpecificModuleContext() bool {
+ // Some vendor variants want to be installed to /odm by setting "odm_available: true".
+ return c.InVendor() && c.VendorVariantToOdm()
+}
+
// Returns true when this module is configured to have core and vendor variants.
func (c *Module) HasVendorVariant() bool {
return Bool(c.VendorProperties.Vendor_available) || Bool(c.VendorProperties.Odm_available)
diff --git a/cc/library.go b/cc/library.go
index b49f1e5..53be3a5 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -206,6 +206,7 @@
RegisterLibraryBuildComponents(android.InitRegistrationContext)
android.RegisterBp2BuildMutator("cc_library_static", CcLibraryStaticBp2Build)
+ android.RegisterBp2BuildMutator("cc_library", CcLibraryBp2Build)
}
func RegisterLibraryBuildComponents(ctx android.RegistrationContext) {
@@ -216,6 +217,67 @@
ctx.RegisterModuleType("cc_library_host_shared", LibraryHostSharedFactory)
}
+// For bp2build conversion.
+type bazelCcLibraryAttributes struct {
+ Srcs bazel.LabelListAttribute
+ Hdrs bazel.LabelListAttribute
+ Copts bazel.StringListAttribute
+ Linkopts bazel.StringListAttribute
+ Deps bazel.LabelListAttribute
+ User_link_flags bazel.StringListAttribute
+ Includes bazel.StringListAttribute
+}
+
+type bazelCcLibrary struct {
+ android.BazelTargetModuleBase
+ bazelCcLibraryAttributes
+}
+
+func (m *bazelCcLibrary) Name() string {
+ return m.BaseModuleName()
+}
+
+func (m *bazelCcLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
+func BazelCcLibraryFactory() android.Module {
+ module := &bazelCcLibrary{}
+ module.AddProperties(&module.bazelCcLibraryAttributes)
+ android.InitBazelTargetModule(module)
+ return module
+}
+
+func CcLibraryBp2Build(ctx android.TopDownMutatorContext) {
+ m, ok := ctx.Module().(*Module)
+ if !ok || !m.ConvertWithBp2build(ctx) {
+ return
+ }
+
+ if ctx.ModuleType() != "cc_library" {
+ return
+ }
+
+ compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
+ linkerAttrs := bp2BuildParseLinkerProps(ctx, m)
+ exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, m)
+ compilerAttrs.hdrs.Append(exportedIncludesHeaders)
+
+ attrs := &bazelCcLibraryAttributes{
+ Srcs: compilerAttrs.srcs,
+ Hdrs: compilerAttrs.hdrs,
+ Copts: compilerAttrs.copts,
+ Linkopts: linkerAttrs.linkopts,
+ Deps: linkerAttrs.deps,
+ Includes: exportedIncludes,
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "cc_library",
+ Bzl_load_location: "//build/bazel/rules:full_cc_library.bzl",
+ }
+
+ ctx.CreateBazelTargetModule(BazelCcLibraryFactory, m.Name(), props, attrs)
+}
+
// cc_library creates both static and/or shared libraries for a device and/or
// host. By default, a cc_library has a single variant that targets the device.
// Specifying `host_supported: true` also creates a library that targets the
@@ -421,10 +483,16 @@
func (handler *staticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
- outputPaths, objPaths, ok := bazelCtx.GetOutputFilesAndCcObjectFiles(label, ctx.Arch().ArchType)
+ ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
+ if err != nil {
+ ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
+ return false
+ }
if !ok {
return ok
}
+ outputPaths := ccInfo.OutputFiles
+ objPaths := ccInfo.CcObjectFiles
if len(outputPaths) > 1 {
// TODO(cparsons): This is actually expected behavior for static libraries with no srcs.
// We should support this.
@@ -2058,9 +2126,10 @@
}
type bazelCcLibraryStaticAttributes struct {
- Copts []string
+ Copts bazel.StringListAttribute
Srcs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
+ Linkopts bazel.StringListAttribute
Linkstatic bool
Includes bazel.StringListAttribute
Hdrs bazel.LabelListAttribute
@@ -2091,24 +2160,37 @@
return
}
- var copts []string
- var srcs []string
+ compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
+
var includeDirs []string
var localIncludeDirs []string
for _, props := range module.compiler.compilerProps() {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
- copts = baseCompilerProps.Cflags
- srcs = baseCompilerProps.Srcs
+ // TODO: these should be arch and os specific.
includeDirs = bp2BuildMakePathsRelativeToModule(ctx, baseCompilerProps.Include_dirs)
localIncludeDirs = bp2BuildMakePathsRelativeToModule(ctx, baseCompilerProps.Local_include_dirs)
break
}
}
- srcsLabels := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, srcs))
+
+ // Soong implicitly includes headers from the module's directory.
+ // For Bazel builds to work we have to make these header includes explicit.
+ if module.compiler.(*libraryDecorator).includeBuildDirectory() {
+ localIncludeDirs = append(localIncludeDirs, ".")
+ }
+
+ // For Bazel, be more explicit about headers - list all header files in include dirs as srcs
+ for _, includeDir := range includeDirs {
+ compilerAttrs.srcs.Value.Append(bp2BuildListHeadersInDir(ctx, includeDir))
+ }
+ for _, localIncludeDir := range localIncludeDirs {
+ compilerAttrs.srcs.Value.Append(bp2BuildListHeadersInDir(ctx, localIncludeDir))
+ }
var staticLibs []string
var wholeStaticLibs []string
for _, props := range module.linker.linkerProps() {
+ // TODO: move this into bp2buildParseLinkerProps
if baseLinkerProperties, ok := props.(*BaseLinkerProperties); ok {
staticLibs = baseLinkerProperties.Static_libs
wholeStaticLibs = baseLinkerProperties.Whole_static_libs
@@ -2130,16 +2212,18 @@
allIncludes.Value = append(allIncludes.Value, includeDirs...)
allIncludes.Value = append(allIncludes.Value, localIncludeDirs...)
- headerLibsLabels := bp2BuildParseHeaderLibs(ctx, module)
- depsLabels.Append(headerLibsLabels.Value)
+ compilerAttrs.hdrs.Append(exportedIncludesHeaders)
+
+ linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
+ depsLabels.Append(linkerAttrs.deps.Value)
attrs := &bazelCcLibraryStaticAttributes{
- Copts: copts,
- Srcs: srcsLabels,
+ Copts: compilerAttrs.copts,
+ Srcs: compilerAttrs.srcs,
Deps: bazel.MakeLabelListAttribute(depsLabels),
Linkstatic: true,
Includes: allIncludes,
- Hdrs: exportedIncludesHeaders,
+ Hdrs: compilerAttrs.hdrs,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/cc/library_headers.go b/cc/library_headers.go
index d35748b..076ce80 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -96,14 +96,14 @@
}
exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, module)
-
- headerLibs := bp2BuildParseHeaderLibs(ctx, module)
+ compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
+ linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
attrs := &bazelCcLibraryHeadersAttributes{
- Copts: bp2BuildParseCflags(ctx, module),
+ Copts: compilerAttrs.copts,
Includes: exportedIncludes,
Hdrs: exportedIncludesHeaders,
- Deps: headerLibs,
+ Deps: linkerAttrs.deps,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/cc/object.go b/cc/object.go
index 4f8797d..9bb279a 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -113,6 +113,7 @@
// For bp2build conversion.
type bazelObjectAttributes struct {
Srcs bazel.LabelListAttribute
+ Hdrs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
Copts bazel.StringListAttribute
Asflags []string
@@ -156,16 +157,11 @@
}
// Set arch-specific configurable attributes
- var srcs bazel.LabelListAttribute
+ compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
var localIncludeDirs []string
var asFlags []string
for _, props := range m.compiler.compilerProps() {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
- srcs = bazel.MakeLabelListAttribute(
- android.BazelLabelForModuleSrcExcludes(
- ctx,
- baseCompilerProps.Srcs,
- baseCompilerProps.Exclude_srcs))
localIncludeDirs = baseCompilerProps.Local_include_dirs
break
}
@@ -200,16 +196,11 @@
}
// TODO(b/183595872) warn/error if we're not handling product variables
- for arch, p := range m.GetArchProperties(&BaseCompilerProperties{}) {
- if cProps, ok := p.(*BaseCompilerProperties); ok {
- srcs.SetValueForArch(arch.Name, android.BazelLabelForModuleSrcExcludes(ctx, cProps.Srcs, cProps.Exclude_srcs))
- }
- }
-
attrs := &bazelObjectAttributes{
- Srcs: srcs,
+ Srcs: compilerAttrs.srcs,
+ Hdrs: compilerAttrs.hdrs,
Deps: deps,
- Copts: bp2BuildParseCflags(ctx, m),
+ Copts: compilerAttrs.copts,
Asflags: asFlags,
Local_include_dirs: localIncludeDirs,
}
diff --git a/cc/object_test.go b/cc/object_test.go
index 6ff8a00..f82d544 100644
--- a/cc/object_test.go
+++ b/cc/object_test.go
@@ -15,6 +15,7 @@
package cc
import (
+ "android/soong/android"
"testing"
)
@@ -27,5 +28,28 @@
linker_script: "foo.lds",
}`)
})
+}
+func TestCcObjectWithBazel(t *testing.T) {
+ bp := `
+cc_object {
+ name: "foo",
+ srcs: ["baz.o"],
+ bazel_module: { label: "//foo/bar:bar" },
+}`
+ config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: "outputbase",
+ LabelToOutputFiles: map[string][]string{
+ "//foo/bar:bar": []string{"bazel_out.o"}}}
+ ctx := testCcWithConfig(t, config)
+
+ module := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon").Module()
+ outputFiles, err := module.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+
+ expectedOutputFiles := []string{"outputbase/execroot/__main__/bazel_out.o"}
+ android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 6b9a3d5..c19b1ff 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -305,6 +305,7 @@
func NewPrebuiltStaticLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
module, library := NewPrebuiltLibrary(hod)
library.BuildOnlyStatic()
+ module.bazelHandler = &prebuiltStaticLibraryBazelHandler{module: module, library: library}
return module, library
}
@@ -319,6 +320,56 @@
properties prebuiltObjectProperties
}
+type prebuiltStaticLibraryBazelHandler struct {
+ bazelHandler
+
+ module *Module
+ library *libraryDecorator
+}
+
+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 {
+ ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
+ }
+ if !ok {
+ return false
+ }
+ staticLibs := ccInfo.CcStaticLibraryFiles
+ if len(staticLibs) > 1 {
+ ctx.ModuleErrorf("expected 1 static library from bazel target %q, got %s", label, staticLibs)
+ return false
+ }
+
+ // TODO(b/184543518): cc_prebuilt_library_static may have properties for re-exporting flags
+
+ // TODO(eakammer):Add stub-related flags if this library is a stub library.
+ // h.library.exportVersioningMacroIfNeeded(ctx)
+
+ // Dependencies on this library will expect collectedSnapshotHeaders to be set, otherwise
+ // validation will fail. For now, set this to an empty list.
+ // TODO(cparsons): More closely mirror the collectHeadersForSnapshot implementation.
+ h.library.collectedSnapshotHeaders = android.Paths{}
+
+ if len(staticLibs) == 0 {
+ h.module.outputFile = android.OptionalPath{}
+ return true
+ }
+
+ out := android.PathForBazelOut(ctx, staticLibs[0])
+ h.module.outputFile = android.OptionalPathForPath(out)
+
+ depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(out).Build()
+ ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+ StaticLibrary: out,
+
+ TransitiveStaticLibrariesForOrdering: depSet,
+ })
+
+ return true
+}
+
func (p *prebuiltObjectLinker) prebuilt() *android.Prebuilt {
return &p.Prebuilt
}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index e1ac9f0..397121e 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -83,7 +83,7 @@
const (
Asan SanitizerType = iota + 1
- hwasan
+ Hwasan
tsan
intOverflow
cfi
@@ -97,7 +97,7 @@
switch t {
case Asan:
return "asan"
- case hwasan:
+ case Hwasan:
return "hwasan"
case tsan:
return "tsan"
@@ -121,7 +121,7 @@
switch t {
case Asan:
return "address"
- case hwasan:
+ case Hwasan:
return "hwaddress"
case memtag_heap:
return "memtag_heap"
@@ -144,7 +144,7 @@
switch t {
case Asan:
return true
- case hwasan:
+ case Hwasan:
return true
case tsan:
return true
@@ -163,7 +163,7 @@
// incompatibleWithCfi returns true if a sanitizer is incompatible with CFI.
func (t SanitizerType) incompatibleWithCfi() bool {
- return t == Asan || t == Fuzzer || t == hwasan
+ return t == Asan || t == Fuzzer || t == Hwasan
}
type SanitizeUserProps struct {
@@ -745,7 +745,7 @@
switch t {
case Asan:
return sanitize.Properties.Sanitize.Address
- case hwasan:
+ case Hwasan:
return sanitize.Properties.Sanitize.Hwaddress
case tsan:
return sanitize.Properties.Sanitize.Thread
@@ -767,7 +767,7 @@
// isUnsanitizedVariant returns true if no sanitizers are enabled.
func (sanitize *sanitize) isUnsanitizedVariant() bool {
return !sanitize.isSanitizerEnabled(Asan) &&
- !sanitize.isSanitizerEnabled(hwasan) &&
+ !sanitize.isSanitizerEnabled(Hwasan) &&
!sanitize.isSanitizerEnabled(tsan) &&
!sanitize.isSanitizerEnabled(cfi) &&
!sanitize.isSanitizerEnabled(scs) &&
@@ -778,7 +778,7 @@
// isVariantOnProductionDevice returns true if variant is for production devices (no non-production sanitizers enabled).
func (sanitize *sanitize) isVariantOnProductionDevice() bool {
return !sanitize.isSanitizerEnabled(Asan) &&
- !sanitize.isSanitizerEnabled(hwasan) &&
+ !sanitize.isSanitizerEnabled(Hwasan) &&
!sanitize.isSanitizerEnabled(tsan) &&
!sanitize.isSanitizerEnabled(Fuzzer)
}
@@ -787,7 +787,7 @@
switch t {
case Asan:
sanitize.Properties.Sanitize.Address = boolPtr(b)
- case hwasan:
+ case Hwasan:
sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
case tsan:
sanitize.Properties.Sanitize.Thread = boolPtr(b)
@@ -902,7 +902,7 @@
if d, ok := child.(PlatformSanitizeable); ok && d.SanitizePropDefined() &&
!d.SanitizeNever() &&
!d.IsSanitizerExplicitlyDisabled(t) {
- if t == cfi || t == hwasan || t == scs {
+ if t == cfi || t == Hwasan || t == scs {
if d.StaticallyLinked() && d.SanitizerSupported(t) {
// Rust does not support some of these sanitizers, so we need to check if it's
// supported before setting this true.
@@ -1080,6 +1080,12 @@
if Bool(c.sanitize.Properties.Sanitize.Diag.Memtag_heap) {
noteDep = "note_memtag_heap_sync"
}
+ // If we're using snapshots, redirect to snapshot whenever possible
+ // TODO(b/178470649): clean manual snapshot redirections
+ snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo)
+ if lib, ok := snapshot.StaticLibs[noteDep]; ok {
+ noteDep = lib
+ }
depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true}
variations := append(mctx.Target().Variations(),
blueprint.Variation{Mutator: "link", Variation: "static"})
@@ -1280,7 +1286,7 @@
// For cfi/scs/hwasan, we can export both sanitized and un-sanitized variants
// to Make, because the sanitized version has a different suffix in name.
// For other types of sanitizers, suppress the variation that is disabled.
- if t != cfi && t != scs && t != hwasan {
+ if t != cfi && t != scs && t != Hwasan {
if isSanitizerEnabled {
modules[0].(PlatformSanitizeable).SetPreventInstall()
modules[0].(PlatformSanitizeable).SetHideFromMake()
@@ -1294,7 +1300,7 @@
if c.StaticallyLinked() && c.ExportedToMake() {
if t == cfi {
cfiStaticLibs(mctx.Config()).add(c, c.Module().Name())
- } else if t == hwasan {
+ } else if t == Hwasan {
hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name())
}
}
@@ -1411,7 +1417,7 @@
func hwasanStaticLibs(config android.Config) *sanitizerStaticLibsMap {
return config.Once(hwasanStaticLibsKey, func() interface{} {
- return newSanitizerStaticLibsMap(hwasan)
+ return newSanitizerStaticLibsMap(Hwasan)
}).(*sanitizerStaticLibsMap)
}
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index af05102..aa70768 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -559,10 +559,18 @@
return nil
}
+ // Flags specified directly to this module.
p.libraryDecorator.reexportDirs(android.PathsForModuleSrc(ctx, p.properties.Export_include_dirs)...)
p.libraryDecorator.reexportSystemDirs(android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...)
p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
+ // Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
+ p.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
+ p.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
+ p.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
+ p.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
+ p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
+
in := android.PathForModuleSrc(ctx, *p.properties.Src)
p.unstrippedOutputFile = in
diff --git a/cc/stl.go b/cc/stl.go
index 594231d..4f8865f 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -140,6 +140,17 @@
}
func staticUnwinder(ctx android.BaseModuleContext) string {
+ vndkVersion := ctx.Module().(*Module).VndkVersion()
+
+ // Modules using R vndk use different unwinder
+ if vndkVersion == "30" {
+ if ctx.Arch().ArchType == android.Arm {
+ return "libunwind_llvm"
+ } else {
+ return "libgcc_stripped"
+ }
+ }
+
return "libunwind"
}
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 3d31be4..3437d77 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -196,7 +196,7 @@
if m.sanitize != nil {
// scs and hwasan export both sanitized and unsanitized variants for static and header
// Always use unsanitized variants of them.
- for _, t := range []SanitizerType{scs, hwasan} {
+ for _, t := range []SanitizerType{scs, Hwasan} {
if !l.shared() && m.sanitize.isSanitizerEnabled(t) {
return false
}
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index 8f77c28..66396f7 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -334,7 +334,7 @@
vndkBp := `
vndk_prebuilt_shared {
name: "libvndk",
- version: "28",
+ version: "30",
target_arch: "arm64",
vendor_available: true,
product_available: true,
@@ -378,7 +378,7 @@
// different arch snapshot which has to be ignored
vndk_prebuilt_shared {
name: "libvndk",
- version: "28",
+ version: "30",
target_arch: "arm",
vendor_available: true,
product_available: true,
@@ -424,12 +424,26 @@
srcs: ["client.cpp"],
}
+ cc_library_shared {
+ name: "libclient_cfi",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ static_libs: ["libvendor"],
+ sanitize: {
+ cfi: true,
+ },
+ srcs: ["client.cpp"],
+ }
+
cc_binary {
name: "bin_without_snapshot",
vendor: true,
nocrt: true,
no_libcrt: true,
- stl: "none",
+ stl: "libc++_static",
system_shared_libs: [],
static_libs: ["libvndk"],
srcs: ["bin.cpp"],
@@ -437,13 +451,16 @@
vendor_snapshot {
name: "vendor_snapshot",
- version: "28",
+ version: "30",
arch: {
arm64: {
vndk_libs: [
"libvndk",
],
static_libs: [
+ "libc++_static",
+ "libc++demangle",
+ "libgcc_stripped",
"libvendor",
"libvendor_available",
"libvndk",
@@ -482,25 +499,25 @@
vendor_snapshot_static {
name: "libvndk",
- version: "28",
+ version: "30",
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
arch: {
arm64: {
src: "libvndk.a",
- export_include_dirs: ["include/libvndk"],
},
arm: {
src: "libvndk.a",
- export_include_dirs: ["include/libvndk"],
},
},
+ shared_libs: ["libvndk"],
+ export_shared_lib_headers: ["libvndk"],
}
vendor_snapshot_shared {
name: "libvendor",
- version: "28",
+ version: "30",
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
@@ -523,7 +540,7 @@
vendor_snapshot_static {
name: "lib32",
- version: "28",
+ version: "30",
target_arch: "arm64",
compile_multilib: "32",
vendor: true,
@@ -536,7 +553,7 @@
vendor_snapshot_shared {
name: "lib32",
- version: "28",
+ version: "30",
target_arch: "arm64",
compile_multilib: "32",
vendor: true,
@@ -549,7 +566,7 @@
vendor_snapshot_static {
name: "lib64",
- version: "28",
+ version: "30",
target_arch: "arm64",
compile_multilib: "64",
vendor: true,
@@ -562,7 +579,7 @@
vendor_snapshot_shared {
name: "lib64",
- version: "28",
+ version: "30",
target_arch: "arm64",
compile_multilib: "64",
vendor: true,
@@ -575,16 +592,24 @@
vendor_snapshot_static {
name: "libvendor",
- version: "28",
+ version: "30",
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
arch: {
arm64: {
+ cfi: {
+ src: "libvendor.cfi.a",
+ export_include_dirs: ["include/libvendor_cfi"],
+ },
src: "libvendor.a",
export_include_dirs: ["include/libvendor"],
},
arm: {
+ cfi: {
+ src: "libvendor.cfi.a",
+ export_include_dirs: ["include/libvendor_cfi"],
+ },
src: "libvendor.a",
export_include_dirs: ["include/libvendor"],
},
@@ -593,7 +618,7 @@
vendor_snapshot_shared {
name: "libvendor_available",
- version: "28",
+ version: "30",
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
@@ -611,7 +636,7 @@
vendor_snapshot_static {
name: "libvendor_available",
- version: "28",
+ version: "30",
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
@@ -627,9 +652,48 @@
},
}
+ vendor_snapshot_static {
+ name: "libc++_static",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "libc++_static.a",
+ },
+ },
+ }
+
+ vendor_snapshot_static {
+ name: "libc++demangle",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "libc++demangle.a",
+ },
+ },
+ }
+
+ vendor_snapshot_static {
+ name: "libgcc_stripped",
+ version: "30",
+ target_arch: "arm64",
+ compile_multilib: "64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "libgcc_stripped.a",
+ },
+ },
+ }
+
vendor_snapshot_binary {
name: "bin",
- version: "28",
+ version: "30",
target_arch: "arm64",
compile_multilib: "64",
vendor: true,
@@ -642,7 +706,7 @@
vendor_snapshot_binary {
name: "bin32",
- version: "28",
+ version: "30",
target_arch: "arm64",
compile_multilib: "32",
vendor: true,
@@ -670,7 +734,7 @@
// different arch snapshot which has to be ignored
vendor_snapshot_binary {
name: "bin",
- version: "28",
+ version: "30",
target_arch: "arm",
compile_multilib: "first",
vendor: true,
@@ -684,30 +748,36 @@
depsBp := GatherRequiredDepsForTest(android.Android)
mockFS := map[string][]byte{
- "deps/Android.bp": []byte(depsBp),
- "framework/Android.bp": []byte(frameworkBp),
- "vendor/Android.bp": []byte(vendorProprietaryBp),
- "vendor/bin": nil,
- "vendor/bin32": nil,
- "vendor/bin.cpp": nil,
- "vendor/client.cpp": nil,
- "vendor/include/libvndk/a.h": nil,
- "vendor/include/libvendor/b.h": nil,
- "vendor/libvndk.a": nil,
- "vendor/libvendor.a": nil,
- "vendor/libvendor.so": nil,
- "vendor/lib32.a": nil,
- "vendor/lib32.so": nil,
- "vendor/lib64.a": nil,
- "vendor/lib64.so": nil,
- "vndk/Android.bp": []byte(vndkBp),
- "vndk/include/libvndk/a.h": nil,
- "vndk/libvndk.so": nil,
+ "deps/Android.bp": []byte(depsBp),
+ "framework/Android.bp": []byte(frameworkBp),
+ "framework/symbol.txt": nil,
+ "vendor/Android.bp": []byte(vendorProprietaryBp),
+ "vendor/bin": nil,
+ "vendor/bin32": nil,
+ "vendor/bin.cpp": nil,
+ "vendor/client.cpp": nil,
+ "vendor/include/libvndk/a.h": nil,
+ "vendor/include/libvendor/b.h": nil,
+ "vendor/include/libvendor_cfi/c.h": nil,
+ "vendor/libc++_static.a": nil,
+ "vendor/libc++demangle.a": nil,
+ "vendor/libgcc_striped.a": nil,
+ "vendor/libvndk.a": nil,
+ "vendor/libvendor.a": nil,
+ "vendor/libvendor.cfi.a": nil,
+ "vendor/libvendor.so": nil,
+ "vendor/lib32.a": nil,
+ "vendor/lib32.so": nil,
+ "vendor/lib64.a": nil,
+ "vendor/lib64.so": nil,
+ "vndk/Android.bp": []byte(vndkBp),
+ "vndk/include/libvndk/a.h": nil,
+ "vndk/libvndk.so": nil,
}
config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
- config.TestProductVariables.DeviceVndkVersion = StringPtr("28")
- config.TestProductVariables.Platform_vndk_version = StringPtr("29")
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("30")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("31")
ctx := CreateTestContext(config)
ctx.Register()
@@ -716,14 +786,17 @@
_, errs = ctx.PrepareBuildActions(config)
android.FailIfErrored(t, errs)
- sharedVariant := "android_vendor.28_arm64_armv8-a_shared"
- staticVariant := "android_vendor.28_arm64_armv8-a_static"
- binaryVariant := "android_vendor.28_arm64_armv8-a"
+ sharedVariant := "android_vendor.30_arm64_armv8-a_shared"
+ staticVariant := "android_vendor.30_arm64_armv8-a_static"
+ binaryVariant := "android_vendor.30_arm64_armv8-a"
- shared32Variant := "android_vendor.28_arm_armv7-a-neon_shared"
- binary32Variant := "android_vendor.28_arm_armv7-a-neon"
+ sharedCfiVariant := "android_vendor.30_arm64_armv8-a_shared_cfi"
+ staticCfiVariant := "android_vendor.30_arm64_armv8-a_static_cfi"
- // libclient uses libvndk.vndk.28.arm64, libvendor.vendor_static.28.arm64, libvendor_without_snapshot
+ shared32Variant := "android_vendor.30_arm_armv7-a-neon_shared"
+ binary32Variant := "android_vendor.30_arm_armv7-a-neon"
+
+ // libclient uses libvndk.vndk.30.arm64, libvendor.vendor_static.30.arm64, libvendor_without_snapshot
libclientCcFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("cc").Args["cFlags"]
for _, includeFlags := range []string{
"-Ivndk/include/libvndk", // libvndk
@@ -737,8 +810,8 @@
libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld").Args["libFlags"]
for _, input := range [][]string{
- []string{sharedVariant, "libvndk.vndk.28.arm64"},
- []string{staticVariant, "libvendor.vendor_static.28.arm64"},
+ []string{sharedVariant, "libvndk.vndk.30.arm64"},
+ []string{staticVariant, "libvendor.vendor_static.30.arm64"},
[]string{staticVariant, "libvendor_without_snapshot"},
} {
outputPaths := getOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */)
@@ -762,45 +835,58 @@
t.Errorf("wanted libclient32 AndroidMkSharedLibs %q, got %q", w, g)
}
- // bin_without_snapshot uses libvndk.vendor_static.28.arm64
+ // libclient_cfi uses libvendor.vendor_static.30.arm64's cfi variant
+ libclientCfiCcFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("cc").Args["cFlags"]
+ if !strings.Contains(libclientCfiCcFlags, "-Ivendor/include/libvendor_cfi") {
+ t.Errorf("flags for libclient_cfi must contain %#v, but was %#v.",
+ "-Ivendor/include/libvendor_cfi", libclientCfiCcFlags)
+ }
+
+ libclientCfiLdFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("ld").Args["libFlags"]
+ libvendorCfiOutputPaths := getOutputPaths(ctx, staticCfiVariant, []string{"libvendor.vendor_static.30.arm64"})
+ if !strings.Contains(libclientCfiLdFlags, libvendorCfiOutputPaths[0].String()) {
+ t.Errorf("libflags for libclientCfi must contain %#v, but was %#v", libvendorCfiOutputPaths[0], libclientCfiLdFlags)
+ }
+
+ // bin_without_snapshot uses libvndk.vendor_static.30.arm64 (which reexports vndk's exported headers)
binWithoutSnapshotCcFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("cc").Args["cFlags"]
- if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivendor/include/libvndk") {
+ if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivndk/include/libvndk") {
t.Errorf("flags for bin_without_snapshot must contain %#v, but was %#v.",
"-Ivendor/include/libvndk", binWithoutSnapshotCcFlags)
}
binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld").Args["libFlags"]
- libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.28.arm64"})
+ libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.30.arm64"})
if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) {
t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
libVndkStaticOutputPaths[0], binWithoutSnapshotLdFlags)
}
- // libvendor.so is installed by libvendor.vendor_shared.28.arm64
- ctx.ModuleForTests("libvendor.vendor_shared.28.arm64", sharedVariant).Output("libvendor.so")
+ // libvendor.so is installed by libvendor.vendor_shared.30.arm64
+ ctx.ModuleForTests("libvendor.vendor_shared.30.arm64", sharedVariant).Output("libvendor.so")
- // lib64.so is installed by lib64.vendor_shared.28.arm64
- ctx.ModuleForTests("lib64.vendor_shared.28.arm64", sharedVariant).Output("lib64.so")
+ // lib64.so is installed by lib64.vendor_shared.30.arm64
+ ctx.ModuleForTests("lib64.vendor_shared.30.arm64", sharedVariant).Output("lib64.so")
- // lib32.so is installed by lib32.vendor_shared.28.arm64
- ctx.ModuleForTests("lib32.vendor_shared.28.arm64", shared32Variant).Output("lib32.so")
+ // lib32.so is installed by lib32.vendor_shared.30.arm64
+ ctx.ModuleForTests("lib32.vendor_shared.30.arm64", shared32Variant).Output("lib32.so")
- // libvendor_available.so is installed by libvendor_available.vendor_shared.28.arm64
- ctx.ModuleForTests("libvendor_available.vendor_shared.28.arm64", sharedVariant).Output("libvendor_available.so")
+ // libvendor_available.so is installed by libvendor_available.vendor_shared.30.arm64
+ ctx.ModuleForTests("libvendor_available.vendor_shared.30.arm64", sharedVariant).Output("libvendor_available.so")
// libvendor_without_snapshot.so is installed by libvendor_without_snapshot
ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so")
- // bin is installed by bin.vendor_binary.28.arm64
- ctx.ModuleForTests("bin.vendor_binary.28.arm64", binaryVariant).Output("bin")
+ // bin is installed by bin.vendor_binary.30.arm64
+ ctx.ModuleForTests("bin.vendor_binary.30.arm64", binaryVariant).Output("bin")
- // bin32 is installed by bin32.vendor_binary.28.arm64
- ctx.ModuleForTests("bin32.vendor_binary.28.arm64", binary32Variant).Output("bin32")
+ // bin32 is installed by bin32.vendor_binary.30.arm64
+ ctx.ModuleForTests("bin32.vendor_binary.30.arm64", binary32Variant).Output("bin32")
// bin_without_snapshot is installed by bin_without_snapshot
ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot")
- // libvendor, libvendor_available and bin don't have vendor.28 variant
+ // libvendor, libvendor_available and bin don't have vendor.30 variant
libvendorVariants := ctx.ModuleVariantsForTests("libvendor")
if inList(sharedVariant, libvendorVariants) {
t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant)
@@ -819,6 +905,18 @@
func TestVendorSnapshotSanitizer(t *testing.T) {
bp := `
+ vendor_snapshot {
+ name: "vendor_snapshot",
+ version: "28",
+ arch: {
+ arm64: {
+ static_libs: [
+ "libsnapshot",
+ "note_memtag_heap_sync",
+ ],
+ },
+ },
+ }
vendor_snapshot_static {
name: "libsnapshot",
vendor: true,
@@ -833,8 +931,41 @@
},
},
}
+
+ vendor_snapshot_static {
+ name: "note_memtag_heap_sync",
+ vendor: true,
+ target_arch: "arm64",
+ version: "28",
+ arch: {
+ arm64: {
+ src: "note_memtag_heap_sync.a",
+ },
+ },
+ }
+
+ cc_test {
+ name: "vstest",
+ gtest: false,
+ vendor: true,
+ compile_multilib: "64",
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ static_libs: ["libsnapshot"],
+ system_shared_libs: [],
+ }
`
- config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
+
+ mockFS := map[string][]byte{
+ "vendor/Android.bp": []byte(bp),
+ "vendor/libc++demangle.a": nil,
+ "vendor/libsnapshot.a": nil,
+ "vendor/libsnapshot.cfi.a": nil,
+ "vendor/note_memtag_heap_sync.a": nil,
+ }
+
+ config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
config.TestProductVariables.DeviceVndkVersion = StringPtr("28")
config.TestProductVariables.Platform_vndk_version = StringPtr("29")
ctx := testCcWithConfig(t, config)
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 1863ece..a4554fc 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -75,8 +75,8 @@
return ctx
}
-func newConfig(srcDir string) android.Config {
- configuration, err := android.NewConfig(srcDir, bootstrap.CmdlineBuildDir(), bootstrap.CmdlineModuleListFile())
+func newConfig(srcDir, outDir string, availableEnv map[string]string) android.Config {
+ configuration, err := android.NewConfig(srcDir, outDir, bootstrap.CmdlineModuleListFile(), availableEnv)
if err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
@@ -127,7 +127,7 @@
}
func writeMetrics(configuration android.Config) {
- metricsFile := filepath.Join(bootstrap.CmdlineBuildDir(), "soong_build_metrics.pb")
+ metricsFile := filepath.Join(configuration.BuildDir(), "soong_build_metrics.pb")
err := android.WriteMetrics(configuration, metricsFile)
if err != nil {
fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err)
@@ -188,12 +188,31 @@
shared.ReexecWithDelveMaybe(delveListen, delvePath)
android.InitSandbox(topDir)
- android.InitEnvironment(shared.JoinPath(topDir, outDir, "soong.environment.available"))
- usedVariablesFile := shared.JoinPath(outDir, "soong.environment.used")
+ // soong_ui dumps the available environment variables to
+ // soong.environment.available . Then soong_build itself is run with an empty
+ // environment so that the only way environment variables can be accessed is
+ // using Config, which tracks access to them.
+
+ // At the end of the build, a file called soong.environment.used is written
+ // containing the current value of all used environment variables. The next
+ // time soong_ui is run, it checks whether any environment variables that was
+ // used had changed and if so, it deletes soong.environment.used to cause a
+ // rebuild.
+ //
+ // The dependency of build.ninja on soong.environment.used is declared in
+ // build.ninja.d
+ availableEnvFile := shared.JoinPath(topDir, outDir, "soong.environment.available")
+ usedEnvFile := shared.JoinPath(topDir, outDir, "soong.environment.used")
+ availableEnv, err := shared.EnvFromFile(availableEnvFile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error reading available environment file %s: %s\n", availableEnvFile, err)
+ os.Exit(1)
+ }
+
// The top-level Blueprints file is passed as the first argument.
srcDir := filepath.Dir(flag.Arg(0))
- configuration := newConfig(srcDir)
+ configuration := newConfig(srcDir, outDir, availableEnv)
extraNinjaDeps := []string{
configuration.ProductVariablesFileName,
shared.JoinPath(outDir, "soong.environment.used"),
@@ -203,10 +222,6 @@
configuration.SetAllowMissingDependencies()
}
- // These two are here so that we restart a non-debugged soong_build when the
- // user sets SOONG_DELVE the first time.
- configuration.Getenv("SOONG_DELVE")
- configuration.Getenv("SOONG_DELVE_PATH")
if shared.IsDebugging() {
// Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is
// enabled even if it completed successfully.
@@ -223,19 +238,19 @@
}
doChosenActivity(configuration, extraNinjaDeps)
- writeUsedVariablesFile(shared.JoinPath(topDir, usedVariablesFile), configuration)
+ writeUsedEnvironmentFile(usedEnvFile, configuration)
}
-func writeUsedVariablesFile(path string, configuration android.Config) {
+func writeUsedEnvironmentFile(path string, configuration android.Config) {
data, err := shared.EnvFileContents(configuration.EnvDeps())
if err != nil {
- fmt.Fprintf(os.Stderr, "error writing used variables file %s: %s\n", path, err)
+ fmt.Fprintf(os.Stderr, "error writing used environment file %s: %s\n", path, err)
os.Exit(1)
}
err = ioutil.WriteFile(path, data, 0666)
if err != nil {
- fmt.Fprintf(os.Stderr, "error writing used variables file %s: %s\n", path, err)
+ fmt.Fprintf(os.Stderr, "error writing used environment file %s: %s\n", path, err)
os.Exit(1)
}
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 3dcc416..29a8a39 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -61,7 +61,7 @@
Vendor_boot *bool
// Optional kernel commandline
- Cmdline *string
+ Cmdline *string `android:"arch_variant"`
// File that contains bootconfig parameters. This can be set only when `vendor_boot` is true
// and `header_version` is greater than or equal to 4.
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 3f1e9f3..3ce4f85 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -696,7 +696,8 @@
result := android.GroupFixturePreparers(
prepareForGenRuleTest, android.FixtureModifyConfig(func(config android.Config) {
config.BazelContext = android.MockBazelContext{
- AllFiles: map[string][]string{
+ OutputBaseDir: "outputbase",
+ LabelToOutputFiles: map[string][]string{
"//foo/bar:bar": []string{"bazelone.txt", "bazeltwo.txt"}}}
})).RunTestWithBp(t, testGenruleBp()+bp)
diff --git a/java/Android.bp b/java/Android.bp
index 8334b85..2a4b596 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -32,6 +32,7 @@
"boot_image.go",
"boot_jars.go",
"builder.go",
+ "classpath_fragment.go",
"device_host_converter.go",
"dex.go",
"dexpreopt.go",
@@ -42,6 +43,7 @@
"gen.go",
"genrule.go",
"hiddenapi.go",
+ "hiddenapi_modular.go",
"hiddenapi_singleton.go",
"jacoco.go",
"java.go",
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
new file mode 100644
index 0000000..adbe490
--- /dev/null
+++ b/java/classpath_fragment.go
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package java
+
+import (
+ "android/soong/android"
+)
+
+// Build rules and utilities to generate individual packages/modules/SdkExtensions/proto/classpaths.proto
+// config files based on build configuration to embed into /system and /apex on a device.
+//
+// See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables
+// on the device.
+
+type classpathType int
+
+const (
+ // Matches definition in packages/modules/SdkExtensions/proto/classpaths.proto
+ BOOTCLASSPATH classpathType = iota
+ DEX2OATBOOTCLASSPATH
+ SYSTEMSERVERCLASSPATH
+)
+
+func (c classpathType) String() string {
+ return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH"}[c]
+}
+
+type classpathFragmentProperties struct {
+}
+
+// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH
+// variables at runtime.
+type classpathFragment interface {
+ android.Module
+
+ classpathFragmentBase() *classpathFragmentBase
+}
+
+// classpathFragmentBase is meant to be embedded in any module types that implement classpathFragment;
+// such modules are expected to call initClasspathFragment().
+type classpathFragmentBase struct {
+ properties classpathFragmentProperties
+
+ classpathType classpathType
+
+ outputFilepath android.OutputPath
+}
+
+// Initializes classpathFragmentBase struct. Must be called by all modules that include classpathFragmentBase.
+func initClasspathFragment(c classpathFragment) {
+ base := c.classpathFragmentBase()
+ c.AddProperties(&base.properties)
+}
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
new file mode 100644
index 0000000..bed11fe
--- /dev/null
+++ b/java/hiddenapi_modular.go
@@ -0,0 +1,172 @@
+// 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.
+
+package java
+
+import (
+ "android/soong/android"
+)
+
+// Contains support for processing hiddenAPI in a modular fashion.
+
+// HiddenAPIAugmentationProperties contains paths to the files that can be used to augment the information
+// obtained from annotations within the source code in order to create the complete set of flags
+// that should be applied to the dex implementation jars on the bootclasspath.
+//
+// Each property contains a list of paths. With the exception of the Unsupported_packages the paths
+// of each property reference a plain text file that contains a java signature per line. The flags
+// for each of those signatures will be updated in a property specific way.
+//
+// The Unsupported_packages property contains a list of paths, each of which is a plain text file
+// with one Java package per line. All members of all classes within that package (but not nested
+// packages) will be updated in a property specific way.
+type HiddenAPIAugmentationProperties struct {
+ // Marks each signature in the referenced files as being unsupported.
+ Unsupported []string `android:"path"`
+
+ // Marks each signature in the referenced files as being unsupported because it has been removed.
+ // Any conflicts with other flags are ignored.
+ Removed []string `android:"path"`
+
+ // Marks each signature in the referenced files as being supported only for targetSdkVersion <= R
+ // and low priority.
+ Max_target_r_low_priority []string `android:"path"`
+
+ // Marks each signature in the referenced files as being supported only for targetSdkVersion <= Q.
+ Max_target_q []string `android:"path"`
+
+ // Marks each signature in the referenced files as being supported only for targetSdkVersion <= P.
+ Max_target_p []string `android:"path"`
+
+ // Marks each signature in the referenced files as being supported only for targetSdkVersion <= O
+ // and low priority. Any conflicts with other flags are ignored.
+ Max_target_o_low_priority []string `android:"path"`
+
+ // Marks each signature in the referenced files as being blocked.
+ Blocked []string `android:"path"`
+
+ // Marks each signature in every package in the referenced files as being unsupported.
+ Unsupported_packages []string `android:"path"`
+}
+
+func (p *HiddenAPIAugmentationProperties) hiddenAPIAugmentationInfo(ctx android.ModuleContext) hiddenAPIAugmentationInfo {
+ paths := func(paths []string) android.Paths { return android.PathsForModuleSrc(ctx, paths) }
+ return hiddenAPIAugmentationInfo{
+ Unsupported: paths(p.Unsupported),
+ Removed: paths(p.Removed),
+ Max_target_r_low_priority: paths(p.Max_target_r_low_priority),
+ Max_target_q: paths(p.Max_target_q),
+ Max_target_p: paths(p.Max_target_p),
+ Max_target_o_low_priority: paths(p.Max_target_o_low_priority),
+ Blocked: paths(p.Blocked),
+ Unsupported_packages: paths(p.Unsupported_packages),
+ }
+}
+
+// hiddenAPIAugmentationInfo contains paths resolved from HiddenAPIAugmentationProperties
+type hiddenAPIAugmentationInfo struct {
+ // See HiddenAPIAugmentationProperties.Unsupported
+ Unsupported android.Paths
+
+ // See HiddenAPIAugmentationProperties.Removed
+ Removed android.Paths
+
+ // See HiddenAPIAugmentationProperties.Max_target_r_low_priority
+ Max_target_r_low_priority android.Paths
+
+ // See HiddenAPIAugmentationProperties.Max_target_q
+ Max_target_q android.Paths
+
+ // See HiddenAPIAugmentationProperties.Max_target_p
+ Max_target_p android.Paths
+
+ // See HiddenAPIAugmentationProperties.Max_target_o_low_priority
+ Max_target_o_low_priority android.Paths
+
+ // See HiddenAPIAugmentationProperties.Blocked
+ Blocked android.Paths
+
+ // See HiddenAPIAugmentationProperties.Unsupported_packages
+ Unsupported_packages android.Paths
+}
+
+// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the
+// flags from all the modules, the stub flags, augmented with some additional configuration files.
+//
+// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
+// an entry for every single member in the dex implementation jars of the individual modules. Every
+// signature in any of the other files MUST be included in this file.
+//
+// moduleSpecificFlagsPaths are the paths to the flags files generated by each module using
+// information from the baseFlagsPath as well as from annotations within the source.
+//
+// augmentationInfo is a struct containing paths to files that augment the information provided by
+// the moduleSpecificFlagsPaths.
+// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the
+// flags from all the modules, the stub flags, augmented with some additional configuration files.
+//
+// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
+// an entry for every single member in the dex implementation jars of the individual modules. Every
+// signature in any of the other files MUST be included in this file.
+//
+// moduleSpecificFlagsPaths are the paths to the flags files generated by each module using
+// information from the baseFlagsPath as well as from annotations within the source.
+//
+// augmentationInfo is a struct containing paths to files that augment the information provided by
+// the moduleSpecificFlagsPaths.
+func ruleToGenerateHiddenApiFlags(ctx android.BuilderContext, outputPath android.WritablePath, baseFlagsPath android.Path, moduleSpecificFlagsPaths android.Paths, augmentationInfo hiddenAPIAugmentationInfo) {
+ tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp")
+ rule := android.NewRuleBuilder(pctx, ctx)
+ command := rule.Command().
+ BuiltTool("generate_hiddenapi_lists").
+ FlagWithInput("--csv ", baseFlagsPath).
+ Inputs(moduleSpecificFlagsPaths).
+ FlagWithOutput("--output ", tempPath)
+
+ for _, path := range augmentationInfo.Unsupported {
+ command.FlagWithInput("--unsupported ", path)
+ }
+
+ for _, path := range augmentationInfo.Removed {
+ command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
+ }
+
+ for _, path := range augmentationInfo.Max_target_r_low_priority {
+ command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
+ }
+
+ for _, path := range augmentationInfo.Max_target_q {
+ command.FlagWithInput("--max-target-q ", path)
+ }
+
+ for _, path := range augmentationInfo.Max_target_p {
+ command.FlagWithInput("--max-target-p ", path)
+ }
+
+ for _, path := range augmentationInfo.Max_target_o_low_priority {
+ command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
+ }
+
+ for _, path := range augmentationInfo.Blocked {
+ command.FlagWithInput("--blocked ", path)
+ }
+
+ for _, path := range augmentationInfo.Unsupported_packages {
+ command.FlagWithInput("--unsupported ", path).Flag("--packages ")
+ }
+
+ commitChangeForRestat(rule, tempPath, outputPath)
+
+ rule.Build("hiddenAPIFlagsFile", "hiddenapi flags")
+}
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 7e9477b..6ba5f35 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -15,10 +15,7 @@
package java
import (
- "fmt"
-
"android/soong/android"
- "android/soong/genrule"
)
func init() {
@@ -28,7 +25,6 @@
func RegisterHiddenApiSingletonComponents(ctx android.RegistrationContext) {
ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
ctx.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory)
- ctx.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory)
}
var PrepareForTestWithHiddenApiBuildComponents = android.FixtureRegisterWithContext(RegisterHiddenApiSingletonComponents)
@@ -102,11 +98,15 @@
// yet been created.
func hiddenAPISingletonPaths(ctx android.PathContext) hiddenAPISingletonPathsStruct {
return ctx.Config().Once(hiddenAPISingletonPathsKey, func() interface{} {
+ // Make the paths relative to the out/soong/hiddenapi directory instead of to the out/soong/
+ // directory. This ensures that if they are used as java_resources they do not end up in a
+ // hiddenapi directory in the resulting APK.
+ hiddenapiDir := android.PathForOutput(ctx, "hiddenapi")
return hiddenAPISingletonPathsStruct{
- flags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-flags.csv"),
- index: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-index.csv"),
- metadata: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-unsupported.csv"),
- stubFlags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-stub-flags.txt"),
+ flags: hiddenapiDir.Join(ctx, "hiddenapi-flags.csv"),
+ index: hiddenapiDir.Join(ctx, "hiddenapi-index.csv"),
+ metadata: hiddenapiDir.Join(ctx, "hiddenapi-unsupported.csv"),
+ stubFlags: hiddenapiDir.Join(ctx, "hiddenapi-stub-flags.txt"),
}
}).(hiddenAPISingletonPathsStruct)
}
@@ -321,63 +321,10 @@
return outputPath
}
-// flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and
-// the unsupported API.
+// flagsRule is a placeholder that simply returns the location of the file, the generation of the
+// ninja rules is done in generateHiddenAPIBuildActions.
func flagsRule(ctx android.SingletonContext) android.Path {
- var flagsCSV android.Paths
- var combinedRemovedApis android.Path
-
- ctx.VisitAllModules(func(module android.Module) {
- if h, ok := module.(hiddenAPIIntf); ok {
- if csv := h.flagsCSV(); csv != nil {
- flagsCSV = append(flagsCSV, csv)
- }
- } else if g, ok := module.(*genrule.Module); ok {
- if ctx.ModuleName(module) == "combined-removed-dex" {
- if len(g.GeneratedSourceFiles()) != 1 || combinedRemovedApis != nil {
- ctx.Errorf("Expected 1 combined-removed-dex module that generates 1 output file.")
- }
- combinedRemovedApis = g.GeneratedSourceFiles()[0]
- }
- }
- })
-
- if combinedRemovedApis == nil {
- ctx.Errorf("Failed to find combined-removed-dex.")
- }
-
- rule := android.NewRuleBuilder(pctx, ctx)
-
outputPath := hiddenAPISingletonPaths(ctx).flags
- tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp")
-
- stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
-
- rule.Command().
- BuiltTool("generate_hiddenapi_lists").
- FlagWithInput("--csv ", stubFlags).
- Inputs(flagsCSV).
- FlagWithInput("--unsupported ",
- android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-unsupported.txt")).
- FlagWithInput("--unsupported ", combinedRemovedApis).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed").
- FlagWithInput("--max-target-r ",
- android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt")).FlagWithArg("--tag ", "lo-prio").
- FlagWithInput("--max-target-q ",
- android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-q.txt")).
- FlagWithInput("--max-target-p ",
- android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-p.txt")).
- FlagWithInput("--max-target-o ", android.PathForSource(
- ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-o.txt")).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio").
- FlagWithInput("--blocked ",
- android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-force-blocked.txt")).
- FlagWithInput("--unsupported ", android.PathForSource(
- ctx, "frameworks/base/boot/hiddenapi/hiddenapi-unsupported-packages.txt")).Flag("--packages ").
- FlagWithOutput("--output ", tempPath)
-
- commitChangeForRestat(rule, tempPath, outputPath)
-
- rule.Build("hiddenAPIFlagsFile", "hiddenapi flags")
-
return outputPath
}
@@ -442,51 +389,6 @@
Text(")")
}
-type hiddenAPIFlagsProperties struct {
- // name of the file into which the flags will be copied.
- Filename *string
-}
-
-type hiddenAPIFlags struct {
- android.ModuleBase
-
- properties hiddenAPIFlagsProperties
-
- outputFilePath android.OutputPath
-}
-
-func (h *hiddenAPIFlags) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- filename := String(h.properties.Filename)
-
- inputPath := hiddenAPISingletonPaths(ctx).flags
- h.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
-
- // This ensures that outputFilePath has the correct name for others to
- // use, as the source file may have a different name.
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cp,
- Output: h.outputFilePath,
- Input: inputPath,
- })
-}
-
-func (h *hiddenAPIFlags) OutputFiles(tag string) (android.Paths, error) {
- switch tag {
- case "":
- return android.Paths{h.outputFilePath}, nil
- default:
- return nil, fmt.Errorf("unsupported module reference tag %q", tag)
- }
-}
-
-// hiddenapi-flags provides access to the hiddenapi-flags.csv file generated during the build.
-func hiddenAPIFlagsFactory() android.Module {
- module := &hiddenAPIFlags{}
- module.AddProperties(&module.properties)
- android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
- return module
-}
-
func hiddenAPIIndexSingletonFactory() android.Singleton {
return &hiddenAPIIndexSingleton{}
}
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index 5c449e5..e5e1c25 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -23,12 +23,6 @@
"github.com/google/blueprint/proptools"
)
-func fixtureSetBootJarsProductVariable(bootJars ...string) android.FixturePreparer {
- return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
- })
-}
-
func fixtureSetPrebuiltHiddenApiDirProductVariable(prebuiltHiddenApiDir *string) android.FixturePreparer {
return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.PrebuiltHiddenApiDir = prebuiltHiddenApiDir
@@ -41,7 +35,7 @@
func TestHiddenAPISingleton(t *testing.T) {
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).RunTestWithBp(t, `
java_library {
name: "foo",
@@ -61,7 +55,7 @@
hiddenApiFixtureFactory,
PrepareForTestWithJavaSdkLibraryFiles,
FixtureWithLastReleaseApis("bar"),
- fixtureSetBootJarsProductVariable("platform:foo", "platform:bar"),
+ FixtureConfigureBootJars("platform:foo", "platform:bar"),
).RunTestWithBp(t, `
java_library {
name: "foo",
@@ -119,7 +113,7 @@
android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorMessage)).
RunTestWithBp(t, `
java_library {
@@ -139,7 +133,7 @@
func TestHiddenAPISingletonWithPrebuilt(t *testing.T) {
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).RunTestWithBp(t, `
java_import {
name: "foo",
@@ -157,7 +151,7 @@
func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) {
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).RunTestWithBp(t, `
java_library {
name: "foo",
@@ -185,7 +179,7 @@
func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) {
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).RunTestWithBp(t, `
java_library {
name: "foo",
@@ -295,7 +289,7 @@
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
fixtureSetPrebuiltHiddenApiDirProductVariable(&prebuiltHiddenApiDir),
).RunTestWithBp(t, `
java_import {
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 5507077..d700980 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -15,8 +15,12 @@
package java
import (
+ "fmt"
+
"android/soong/android"
"android/soong/dexpreopt"
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
func init() {
@@ -25,18 +29,114 @@
func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("platform_bootclasspath", platformBootclasspathFactory)
+
+ ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("platform_bootclasspath_deps", platformBootclasspathDepsMutator)
+ })
}
+type platformBootclasspathDependencyTag struct {
+ blueprint.BaseDependencyTag
+
+ name string
+}
+
+// Avoid having to make platform bootclasspath content visible to the platform bootclasspath.
+//
+// This is a temporary workaround to make it easier to migrate to platform bootclasspath with proper
+// dependencies.
+// TODO(b/177892522): Remove this and add needed visibility.
+func (t platformBootclasspathDependencyTag) ExcludeFromVisibilityEnforcement() {
+}
+
+// The tag used for the dependency between the platform bootclasspath and any configured boot jars.
+var platformBootclasspathModuleDepTag = platformBootclasspathDependencyTag{name: "module"}
+
+// The tag used for the dependency between the platform bootclasspath and bootclasspath_fragments.
+var platformBootclasspathFragmentDepTag = platformBootclasspathDependencyTag{name: "fragment"}
+
+var _ android.ExcludeFromVisibilityEnforcementTag = platformBootclasspathDependencyTag{}
+
type platformBootclasspathModule struct {
android.ModuleBase
+
+ properties platformBootclasspathProperties
+
+ // The apex:module pairs obtained from the configured modules.
+ //
+ // Currently only for testing.
+ configuredModules []android.Module
+
+ // The apex:module pairs obtained from the fragments.
+ //
+ // Currently only for testing.
+ fragments []android.Module
+
+ // Path to the monolithic hiddenapi-flags.csv file.
+ hiddenAPIFlagsCSV android.OutputPath
+
+ // Path to the monolithic hiddenapi-index.csv file.
+ hiddenAPIIndexCSV android.OutputPath
+
+ // Path to the monolithic hiddenapi-unsupported.csv file.
+ hiddenAPIMetadataCSV android.OutputPath
+}
+
+// ApexVariantReference specifies a particular apex variant of a module.
+type ApexVariantReference struct {
+ // The name of the module apex variant, i.e. the apex containing the module variant.
+ //
+ // If this is not specified then it defaults to "platform" which will cause a dependency to be
+ // added to the module's platform variant.
+ Apex *string
+
+ // The name of the module.
+ Module *string
+}
+
+type platformBootclasspathProperties struct {
+ // The names of the bootclasspath_fragment modules that form part of this
+ // platform_bootclasspath.
+ Fragments []ApexVariantReference
+
+ Hidden_api HiddenAPIAugmentationProperties
}
func platformBootclasspathFactory() android.Module {
m := &platformBootclasspathModule{}
+ m.AddProperties(&m.properties)
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
return m
}
+var _ android.OutputFileProducer = (*platformBootclasspathModule)(nil)
+
+// A minimal AndroidMkEntries is needed in order to support the dists property.
+func (b *platformBootclasspathModule) AndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{
+ {
+ Class: "FAKE",
+ // Need at least one output file in order for this to take effect.
+ OutputFile: android.OptionalPathForPath(b.hiddenAPIFlagsCSV),
+ Include: "$(BUILD_PHONY_PACKAGE)",
+ },
+ }
+}
+
+// Make the hidden API files available from the platform-bootclasspath module.
+func (b *platformBootclasspathModule) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "hiddenapi-flags.csv":
+ return android.Paths{b.hiddenAPIFlagsCSV}, nil
+ case "hiddenapi-index.csv":
+ return android.Paths{b.hiddenAPIIndexCSV}, nil
+ case "hiddenapi-metadata.csv":
+ return android.Paths{b.hiddenAPIMetadataCSV}, nil
+ }
+
+ return nil, fmt.Errorf("unknown tag %s", tag)
+}
+
func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorContext) {
if SkipDexpreoptBootJars(ctx) {
return
@@ -47,7 +147,115 @@
dexpreopt.RegisterToolDeps(ctx)
}
+func platformBootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
+ m := ctx.Module()
+ if p, ok := m.(*platformBootclasspathModule); ok {
+ // Add dependencies on all the modules configured in the "art" boot image.
+ artImageConfig := genBootImageConfigs(ctx)[artBootImageName]
+ addDependenciesOntoBootImageModules(ctx, artImageConfig.modules)
+
+ // Add dependencies on all the modules configured in the "boot" boot image. That does not
+ // include modules configured in the "art" boot image.
+ bootImageConfig := p.getImageConfig(ctx)
+ addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules)
+
+ // Add dependencies on all the updatable modules.
+ updatableModules := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars
+ addDependenciesOntoBootImageModules(ctx, updatableModules)
+
+ // Add dependencies on all the fragments.
+ addDependencyOntoApexVariants(ctx, "fragments", p.properties.Fragments, platformBootclasspathFragmentDepTag)
+ }
+}
+
+func addDependencyOntoApexVariants(ctx android.BottomUpMutatorContext, propertyName string, refs []ApexVariantReference, tag blueprint.DependencyTag) {
+ for i, ref := range refs {
+ apex := proptools.StringDefault(ref.Apex, "platform")
+
+ if ref.Module == nil {
+ ctx.PropertyErrorf(propertyName, "missing module name at position %d", i)
+ continue
+ }
+ name := proptools.String(ref.Module)
+
+ addDependencyOntoApexModulePair(ctx, apex, name, tag)
+ }
+}
+
+func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex string, name string, tag blueprint.DependencyTag) {
+ var variations []blueprint.Variation
+ if apex != "platform" {
+ // Pick the correct apex variant.
+ variations = []blueprint.Variation{
+ {Mutator: "apex", Variation: apex},
+ }
+ }
+
+ addedDep := false
+ if ctx.OtherModuleDependencyVariantExists(variations, name) {
+ ctx.AddFarVariationDependencies(variations, tag, name)
+ addedDep = true
+ }
+
+ // Add a dependency on the prebuilt module if it exists.
+ prebuiltName := android.PrebuiltNameFromSource(name)
+ if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) {
+ ctx.AddVariationDependencies(variations, tag, prebuiltName)
+ addedDep = true
+ }
+
+ // If no appropriate variant existing for this, so no dependency could be added, then it is an
+ // error, unless missing dependencies are allowed. The simplest way to handle that is to add a
+ // dependency that will not be satisfied and the default behavior will handle it.
+ if !addedDep {
+ // Add dependency on the unprefixed (i.e. source or renamed prebuilt) module which we know does
+ // not exist. The resulting error message will contain useful information about the available
+ // variants.
+ reportMissingVariationDependency(ctx, variations, name)
+
+ // Add dependency on the missing prefixed prebuilt variant too if a module with that name exists
+ // so that information about its available variants will be reported too.
+ if ctx.OtherModuleExists(prebuiltName) {
+ reportMissingVariationDependency(ctx, variations, prebuiltName)
+ }
+ }
+}
+
+// reportMissingVariationDependency intentionally adds a dependency on a missing variation in order
+// to generate an appropriate error message with information about the available variations.
+func reportMissingVariationDependency(ctx android.BottomUpMutatorContext, variations []blueprint.Variation, name string) {
+ modules := ctx.AddFarVariationDependencies(variations, nil, name)
+ if len(modules) != 1 {
+ panic(fmt.Errorf("Internal Error: expected one module, found %d", len(modules)))
+ return
+ }
+ if modules[0] != nil {
+ panic(fmt.Errorf("Internal Error: expected module to be missing but was found: %q", modules[0]))
+ return
+ }
+}
+
+func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList) {
+ for i := 0; i < modules.Len(); i++ {
+ apex := modules.Apex(i)
+ name := modules.Jar(i)
+
+ addDependencyOntoApexModulePair(ctx, apex, name, platformBootclasspathModuleDepTag)
+ }
+}
+
func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) {
+ tag := ctx.OtherModuleDependencyTag(module)
+ if tag == platformBootclasspathModuleDepTag {
+ b.configuredModules = append(b.configuredModules, module)
+ } else if tag == platformBootclasspathFragmentDepTag {
+ b.fragments = append(b.fragments, module)
+ }
+ })
+
+ b.generateHiddenAPIBuildActions(ctx, b.configuredModules)
+
// Nothing to do if skipping the dexpreopt of boot image jars.
if SkipDexpreoptBootJars(ctx) {
return
@@ -72,3 +280,43 @@
func (b *platformBootclasspathModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
return defaultBootImageConfig(ctx)
}
+
+// generateHiddenAPIBuildActions generates all the hidden API related build rules.
+func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module) {
+
+ // Save the paths to the monolithic files for retrieval via OutputFiles().
+ b.hiddenAPIFlagsCSV = hiddenAPISingletonPaths(ctx).flags
+ b.hiddenAPIIndexCSV = hiddenAPISingletonPaths(ctx).index
+ b.hiddenAPIMetadataCSV = hiddenAPISingletonPaths(ctx).metadata
+
+ // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. This is a performance
+ // optimization that can be used to reduce the incremental build time but as its name suggests it
+ // can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath.
+ if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV}
+ for _, path := range paths {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Touch,
+ Output: path,
+ })
+ }
+ return
+ }
+
+ moduleSpecificFlagsPaths := android.Paths{}
+ for _, module := range modules {
+ if h, ok := module.(hiddenAPIIntf); ok {
+ if csv := h.flagsCSV(); csv != nil {
+ moduleSpecificFlagsPaths = append(moduleSpecificFlagsPaths, csv)
+ }
+ } else {
+ ctx.ModuleErrorf("module %s of type %s does not implement hiddenAPIIntf", module, ctx.OtherModuleType(module))
+ }
+ }
+
+ augmentationInfo := b.properties.Hidden_api.hiddenAPIAugmentationInfo(ctx)
+
+ outputPath := hiddenAPISingletonPaths(ctx).flags
+ baseFlagsPath := hiddenAPISingletonPaths(ctx).stubFlags
+ ruleToGenerateHiddenApiFlags(ctx, outputPath, baseFlagsPath, moduleSpecificFlagsPaths, augmentationInfo)
+}
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index 1c81cfd..c740911 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -29,10 +29,146 @@
)
func TestPlatformBootclasspath(t *testing.T) {
- prepareForTestWithPlatformBootclasspath.
- RunTestWithBp(t, `
+ preparer := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ FixtureConfigureBootJars("platform:foo", "platform:bar"),
+ android.FixtureWithRootAndroidBp(`
platform_bootclasspath {
name: "platform-bootclasspath",
}
- `)
+
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `),
+ )
+
+ var addSourceBootclassPathModule = android.FixtureAddTextFile("source/Android.bp", `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `)
+
+ var addPrebuiltBootclassPathModule = android.FixtureAddTextFile("prebuilt/Android.bp", `
+ java_import {
+ name: "foo",
+ jars: ["a.jar"],
+ compile_dex: true,
+ prefer: false,
+ }
+ `)
+
+ var addPrebuiltPreferredBootclassPathModule = android.FixtureAddTextFile("prebuilt/Android.bp", `
+ java_import {
+ name: "foo",
+ jars: ["a.jar"],
+ compile_dex: true,
+ prefer: true,
+ }
+ `)
+
+ t.Run("missing", func(t *testing.T) {
+ preparer.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`"platform-bootclasspath" depends on undefined module "foo"`)).
+ RunTest(t)
+ })
+
+ t.Run("source", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ addSourceBootclassPathModule,
+ ).RunTest(t)
+
+ CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
+ "platform:foo",
+ "platform:bar",
+ })
+ })
+
+ t.Run("prebuilt", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ addPrebuiltBootclassPathModule,
+ ).RunTest(t)
+
+ CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
+ "platform:prebuilt_foo",
+ "platform:bar",
+ })
+ })
+
+ t.Run("source+prebuilt - source preferred", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ addSourceBootclassPathModule,
+ addPrebuiltBootclassPathModule,
+ ).RunTest(t)
+
+ CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
+ "platform:foo",
+ "platform:bar",
+ })
+ })
+
+ t.Run("source+prebuilt - prebuilt preferred", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ addSourceBootclassPathModule,
+ addPrebuiltPreferredBootclassPathModule,
+ ).RunTest(t)
+
+ CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
+ "platform:prebuilt_foo",
+ "platform:bar",
+ })
+ })
+}
+
+func TestPlatformBootclasspath_Dist(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ FixtureConfigureBootJars("platform:foo", "platform:bar"),
+ android.PrepareForTestWithAndroidMk,
+ android.FixtureWithRootAndroidBp(`
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ dists: [
+ {
+ targets: ["droidcore"],
+ tag: "hiddenapi-flags.csv",
+ },
+ ],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `),
+ ).RunTest(t)
+
+ platformBootclasspath := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, platformBootclasspath)
+ goals := entries[0].GetDistForGoals(platformBootclasspath)
+ android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore\n", goals[0])
+ android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[1]))
}
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 8a442b5..c33e6c2 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -253,14 +253,8 @@
files := getPrebuiltFilesInSubdir(mctx, nextApiDir, "api/*incompatibilities.txt")
for _, f := range files {
localPath := strings.TrimPrefix(f, mydir)
- module, _, scope := parseApiFilePath(mctx, localPath)
-
- // Figure out which module is referenced by this file. Special case for "android".
- referencedModule := strings.TrimSuffix(module, "incompatibilities")
- referencedModule = strings.TrimSuffix(referencedModule, "-")
- if referencedModule == "" {
- referencedModule = "android"
- }
+ filename, _, scope := parseApiFilePath(mctx, localPath)
+ referencedModule := strings.TrimSuffix(filename, "-incompatibilities")
createApiModule(mctx, apiModuleName(referencedModule+"-incompatibilities", scope, "latest"), localPath)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 24c5d9f..e5ee397 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -201,8 +201,12 @@
return scope
}
+func (scope *apiScope) stubsLibraryModuleNameSuffix() string {
+ return ".stubs" + scope.moduleSuffix
+}
+
func (scope *apiScope) stubsLibraryModuleName(baseName string) string {
- return baseName + ".stubs" + scope.moduleSuffix
+ return baseName + scope.stubsLibraryModuleNameSuffix()
}
func (scope *apiScope) stubsSourceModuleName(baseName string) string {
@@ -1684,16 +1688,20 @@
func moduleStubLinkType(name string) (stub bool, ret sdkLinkType) {
// This suffix-based approach is fragile and could potentially mis-trigger.
// TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly.
- if strings.HasSuffix(name, ".stubs.public") || strings.HasSuffix(name, "-stubs-publicapi") {
+ if strings.HasSuffix(name, apiScopePublic.stubsLibraryModuleNameSuffix()) {
+ if name == "hwbinder.stubs" || name == "libcore_private.stubs" {
+ // Due to a previous bug, these modules were not considered stubs, so we retain that.
+ return false, javaPlatform
+ }
return true, javaSdk
}
- if strings.HasSuffix(name, ".stubs.system") || strings.HasSuffix(name, "-stubs-systemapi") {
+ if strings.HasSuffix(name, apiScopeSystem.stubsLibraryModuleNameSuffix()) {
return true, javaSystem
}
- if strings.HasSuffix(name, ".stubs.module_lib") || strings.HasSuffix(name, "-stubs-module_libs_api") {
+ if strings.HasSuffix(name, apiScopeModuleLib.stubsLibraryModuleNameSuffix()) {
return true, javaModule
}
- if strings.HasSuffix(name, ".stubs.test") {
+ if strings.HasSuffix(name, apiScopeTest.stubsLibraryModuleNameSuffix()) {
return true, javaSystem
}
return false, javaPlatform
diff --git a/java/testing.go b/java/testing.go
index 80c107d..aee0710 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -178,6 +178,43 @@
return fs
}
+// FixtureConfigureBootJars configures the boot jars in both the dexpreopt.GlobalConfig and
+// Config.productVariables structs. As a side effect that enables dexpreopt.
+func FixtureConfigureBootJars(bootJars ...string) android.FixturePreparer {
+ artBootJars := []string{}
+ for _, j := range bootJars {
+ artApex := false
+ for _, artApexName := range artApexNames {
+ if strings.HasPrefix(j, artApexName+":") {
+ artApex = true
+ break
+ }
+ }
+ if artApex {
+ artBootJars = append(artBootJars, j)
+ }
+ }
+ return android.GroupFixturePreparers(
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
+ }),
+ dexpreopt.FixtureSetBootJars(bootJars...),
+ dexpreopt.FixtureSetArtBootJars(artBootJars...),
+ )
+}
+
+// FixtureConfigureUpdatableBootJars configures the updatable boot jars in both the
+// dexpreopt.GlobalConfig and Config.productVariables structs. As a side effect that enables
+// dexpreopt.
+func FixtureConfigureUpdatableBootJars(bootJars ...string) android.FixturePreparer {
+ return android.GroupFixturePreparers(
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.UpdatableBootJars = android.CreateTestConfiguredJarList(bootJars)
+ }),
+ dexpreopt.FixtureSetUpdatableBootJars(bootJars...),
+ )
+}
+
// registerRequiredBuildComponentsForTest registers the build components used by
// PrepareForTestWithJavaDefaultModules.
//
@@ -300,6 +337,46 @@
}
}
+// CheckPlatformBootclasspathModules returns the apex:module pair for the modules depended upon by
+// the platform-bootclasspath module.
+func CheckPlatformBootclasspathModules(t *testing.T, result *android.TestResult, name string, expected []string) {
+ t.Helper()
+ platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule)
+ pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.configuredModules)
+ android.AssertDeepEquals(t, fmt.Sprintf("%s modules", "platform-bootclasspath"), expected, pairs)
+}
+
+// ApexNamePairsFromModules returns the apex:module pair for the supplied modules.
+func ApexNamePairsFromModules(ctx *android.TestContext, modules []android.Module) []string {
+ pairs := []string{}
+ for _, module := range modules {
+ pairs = append(pairs, apexNamePairFromModule(ctx, module))
+ }
+ return pairs
+}
+
+func apexNamePairFromModule(ctx *android.TestContext, module android.Module) string {
+ name := module.Name()
+ var apex string
+ apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+ if apexInfo.IsForPlatform() {
+ apex = "platform"
+ } else {
+ apex = apexInfo.InApexes[0]
+ }
+
+ return fmt.Sprintf("%s:%s", apex, name)
+}
+
+// CheckPlatformBootclasspathFragments returns the apex:module pair for the fragments depended upon
+// by the platform-bootclasspath module.
+func CheckPlatformBootclasspathFragments(t *testing.T, result *android.TestResult, name string, expected []string) {
+ t.Helper()
+ platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule)
+ pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.fragments)
+ android.AssertDeepEquals(t, fmt.Sprintf("%s fragments", "platform-bootclasspath"), expected, pairs)
+}
+
func CheckHiddenAPIRuleInputs(t *testing.T, expected string, hiddenAPIRule android.TestingBuildParams) {
t.Helper()
actual := strings.TrimSpace(strings.Join(android.NormalizePathsForTesting(hiddenAPIRule.Implicits), "\n"))
diff --git a/rust/Android.bp b/rust/Android.bp
index a29c474..a6c4e07 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -14,6 +14,7 @@
],
srcs: [
"androidmk.go",
+ "benchmark.go",
"binary.go",
"bindgen.go",
"builder.go",
@@ -35,6 +36,7 @@
"testing.go",
],
testSrcs: [
+ "benchmark_test.go",
"binary_test.go",
"bindgen_test.go",
"builder_test.go",
diff --git a/rust/androidmk.go b/rust/androidmk.go
index b0e6967..940710e 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -70,6 +70,11 @@
// If the compiler is disabled, this is a SourceProvider.
mod.SubAndroidMk(&ret, mod.sourceProvider)
}
+
+ if mod.sanitize != nil {
+ mod.SubAndroidMk(&ret, mod.sanitize)
+ }
+
ret.SubName += mod.Properties.SubName
return []android.AndroidMkEntries{ret}
@@ -102,6 +107,20 @@
cc.AndroidMkWriteTestData(test.data, ret)
}
+func (benchmark *benchmarkDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
+ benchmark.binaryDecorator.AndroidMk(ctx, ret)
+ ret.Class = "NATIVE_TESTS"
+ ret.ExtraEntries = append(ret.ExtraEntries,
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.AddCompatibilityTestSuites(benchmark.Properties.Test_suites...)
+ if benchmark.testConfig != nil {
+ entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String())
+ }
+ entries.SetBool("LOCAL_NATIVE_BENCHMARK", true)
+ entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(benchmark.Properties.Auto_gen_config, true))
+ })
+}
+
func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
ctx.SubAndroidMk(ret, library.baseCompiler)
diff --git a/rust/benchmark.go b/rust/benchmark.go
new file mode 100644
index 0000000..b89f5cd
--- /dev/null
+++ b/rust/benchmark.go
@@ -0,0 +1,129 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+ "android/soong/android"
+ "android/soong/tradefed"
+)
+
+type BenchmarkProperties struct {
+ // Disables the creation of a test-specific directory when used with
+ // relative_install_path. Useful if several tests need to be in the same
+ // directory, but test_per_src doesn't work.
+ No_named_install_directory *bool
+
+ // the name of the test configuration (for example "AndroidBenchmark.xml") that should be
+ // installed with the module.
+ Test_config *string `android:"path,arch_variant"`
+
+ // the name of the test configuration template (for example "AndroidBenchmarkTemplate.xml") that
+ // should be installed with the module.
+ Test_config_template *string `android:"path,arch_variant"`
+
+ // list of compatibility suites (for example "cts", "vts") that the module should be
+ // installed into.
+ Test_suites []string `android:"arch_variant"`
+
+ // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
+ // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
+ // explicitly.
+ Auto_gen_config *bool
+}
+
+type benchmarkDecorator struct {
+ *binaryDecorator
+ Properties BenchmarkProperties
+ testConfig android.Path
+}
+
+func NewRustBenchmark(hod android.HostOrDeviceSupported) (*Module, *benchmarkDecorator) {
+ // Build both 32 and 64 targets for device benchmarks.
+ // Cannot build both for host benchmarks yet if the benchmark depends on
+ // something like proc-macro2 that cannot be built for both.
+ multilib := android.MultilibBoth
+ if hod != android.DeviceSupported && hod != android.HostAndDeviceSupported {
+ multilib = android.MultilibFirst
+ }
+ module := newModule(hod, multilib)
+
+ benchmark := &benchmarkDecorator{
+ binaryDecorator: &binaryDecorator{
+ baseCompiler: NewBaseCompiler("nativebench", "nativebench64", InstallInData),
+ },
+ }
+
+ module.compiler = benchmark
+ module.AddProperties(&benchmark.Properties)
+ return module, benchmark
+}
+
+func init() {
+ android.RegisterModuleType("rust_benchmark", RustBenchmarkFactory)
+ android.RegisterModuleType("rust_benchmark_host", RustBenchmarkHostFactory)
+}
+
+func RustBenchmarkFactory() android.Module {
+ module, _ := NewRustBenchmark(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+func RustBenchmarkHostFactory() android.Module {
+ module, _ := NewRustBenchmark(android.HostSupported)
+ return module.Init()
+}
+
+func (benchmark *benchmarkDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
+ return rlibAutoDep
+}
+
+func (benchmark *benchmarkDecorator) stdLinkage(ctx *depsContext) RustLinkage {
+ return RlibLinkage
+}
+
+func (benchmark *benchmarkDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+ flags = benchmark.binaryDecorator.compilerFlags(ctx, flags)
+ return flags
+}
+
+func (benchmark *benchmarkDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
+ deps = benchmark.binaryDecorator.compilerDeps(ctx, deps)
+
+ deps.Rustlibs = append(deps.Rustlibs, "libcriterion")
+
+ return deps
+}
+
+func (benchmark *benchmarkDecorator) compilerProps() []interface{} {
+ return append(benchmark.binaryDecorator.compilerProps(), &benchmark.Properties)
+}
+
+func (benchmark *benchmarkDecorator) install(ctx ModuleContext) {
+ benchmark.testConfig = tradefed.AutoGenRustBenchmarkConfig(ctx,
+ benchmark.Properties.Test_config,
+ benchmark.Properties.Test_config_template,
+ benchmark.Properties.Test_suites,
+ nil,
+ benchmark.Properties.Auto_gen_config)
+
+ // default relative install path is module name
+ if !Bool(benchmark.Properties.No_named_install_directory) {
+ benchmark.baseCompiler.relative = ctx.ModuleName()
+ } else if String(benchmark.baseCompiler.Properties.Relative_install_path) == "" {
+ ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set")
+ }
+
+ benchmark.binaryDecorator.install(ctx)
+}
diff --git a/rust/benchmark_test.go b/rust/benchmark_test.go
new file mode 100644
index 0000000..734dda7
--- /dev/null
+++ b/rust/benchmark_test.go
@@ -0,0 +1,54 @@
+// Copyright 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.
+
+package rust
+
+import (
+ "strings"
+ "testing"
+
+ "android/soong/android"
+)
+
+func TestRustBenchmark(t *testing.T) {
+ ctx := testRust(t, `
+ rust_benchmark_host {
+ name: "my_bench",
+ srcs: ["foo.rs"],
+ }`)
+
+ testingModule := ctx.ModuleForTests("my_bench", "linux_glibc_x86_64")
+ expectedOut := "my_bench/linux_glibc_x86_64/my_bench"
+ outPath := testingModule.Output("my_bench").Output.String()
+ if !strings.Contains(outPath, expectedOut) {
+ t.Errorf("wrong output path: %v; expected: %v", outPath, expectedOut)
+ }
+}
+
+func TestRustBenchmarkLinkage(t *testing.T) {
+ ctx := testRust(t, `
+ rust_benchmark {
+ name: "my_bench",
+ srcs: ["foo.rs"],
+ }`)
+
+ testingModule := ctx.ModuleForTests("my_bench", "android_arm64_armv8-a").Module().(*Module)
+
+ if !android.InList("libcriterion.rlib-std", testingModule.Properties.AndroidMkRlibs) {
+ t.Errorf("rlib-std variant for libcriterion not detected as a rustlib-defined rlib dependency for device rust_benchmark module")
+ }
+ if !android.InList("libstd", testingModule.Properties.AndroidMkRlibs) {
+ t.Errorf("Device rust_benchmark module 'my_bench' does not link libstd as an rlib")
+ }
+}
diff --git a/rust/builder.go b/rust/builder.go
index 9d462d4..197c703 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -51,9 +51,12 @@
Command: "$envVars $clippyCmd " +
// Because clippy-driver uses rustc as backend, we need to have some output even during the linting.
// Use the metadata output as it has the smallest footprint.
- "--emit metadata -o $out $in ${libFlags} " +
- "$rustcFlags $clippyFlags",
+ "--emit metadata -o $out --emit dep-info=$out.d.raw $in ${libFlags} " +
+ "$rustcFlags $clippyFlags" +
+ " && grep \"^$out:\" $out.d.raw > $out.d",
CommandDeps: []string{"$clippyCmd"},
+ Deps: blueprint.DepsGCC,
+ Depfile: "$out.d",
},
"rustcFlags", "libFlags", "clippyFlags", "envVars")
diff --git a/rust/compiler.go b/rust/compiler.go
index 2e85f5a..aaa1924 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -76,7 +76,7 @@
// errors). The default value is "default".
Lints *string
- // flags to pass to rustc
+ // flags to pass to rustc. To enable configuration options or features, use the "cfgs" or "features" properties.
Flags []string `android:"path,arch_variant"`
// flags to pass to the linker
@@ -125,6 +125,9 @@
// list of features to enable for this crate
Features []string `android:"arch_variant"`
+ // list of configuration options to enable for this crate. To enable features, use the "features" property.
+ Cfgs []string `android:"arch_variant"`
+
// specific rust edition that should be used if the default version is not desired
Edition *string `android:"arch_variant"`
@@ -210,9 +213,17 @@
return []interface{}{&compiler.Properties}
}
-func (compiler *baseCompiler) featuresToFlags(features []string) []string {
+func (compiler *baseCompiler) cfgsToFlags() []string {
flags := []string{}
- for _, feature := range features {
+ for _, cfg := range compiler.Properties.Cfgs {
+ flags = append(flags, "--cfg '"+cfg+"'")
+ }
+ return flags
+}
+
+func (compiler *baseCompiler) featuresToFlags() []string {
+ flags := []string{}
+ for _, feature := range compiler.Properties.Features {
flags = append(flags, "--cfg 'feature=\""+feature+"\"'")
}
return flags
@@ -226,7 +237,8 @@
}
flags.RustFlags = append(flags.RustFlags, lintFlags)
flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...)
- flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...)
+ flags.RustFlags = append(flags.RustFlags, compiler.cfgsToFlags()...)
+ flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags()...)
flags.RustFlags = append(flags.RustFlags, "--edition="+compiler.edition())
flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...)
flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...)
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index c752762..5ca9e7f 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -42,6 +42,27 @@
}
}
+// Test that cfgs flags are being correctly generated.
+func TestCfgsToFlags(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_host {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ cfgs: [
+ "std",
+ "cfg1=\"one\""
+ ],
+ }`)
+
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
+
+ if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'std'") ||
+ !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'cfg1=\"one\"'") {
+ t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+ }
+}
+
// Test that we reject multiple source files.
func TestEnforceSingleSourceFile(t *testing.T) {
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 1c8e43e..394fcc5 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -23,6 +23,7 @@
"system/extras/profcollectd",
"system/extras/simpleperf",
"system/hardware/interfaces/keystore2",
+ "system/logging/rust",
"system/security",
"system/tools/aidl",
}
diff --git a/rust/config/global.go b/rust/config/global.go
index 9208ddb..18776ab 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.50.0"
+ RustDefaultVersion = "1.51.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2018"
Stdlibs = []string{
diff --git a/rust/config/lints.go b/rust/config/lints.go
index 7c05e4f..ef6b315 100644
--- a/rust/config/lints.go
+++ b/rust/config/lints.go
@@ -54,6 +54,7 @@
"-A clippy::type-complexity",
"-A clippy::unnecessary-wraps",
"-A clippy::unusual-byte-groupings",
+ "-A clippy::upper-case-acronyms",
}
// Rust lints for vendor code.
diff --git a/rust/fuzz.go b/rust/fuzz.go
index 6035e68..6b0a943 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -70,10 +70,12 @@
}
func (fuzzer *fuzzDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
- deps.StaticLibs = append(deps.StaticLibs,
- config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
- deps.SharedLibs = append(deps.SharedLibs,
- config.LibclangRuntimeLibrary(ctx.toolchain(), "asan"))
+ if libFuzzerRuntimeLibrary := config.LibFuzzerRuntimeLibrary(ctx.toolchain()); libFuzzerRuntimeLibrary != "" {
+ deps.StaticLibs = append(deps.StaticLibs, libFuzzerRuntimeLibrary)
+ }
+ if libclangRuntimeLibrary := config.LibclangRuntimeLibrary(ctx.toolchain(), "asan"); libclangRuntimeLibrary != "" {
+ deps.SharedLibs = append(deps.SharedLibs, libclangRuntimeLibrary)
+ }
deps.SharedLibs = append(deps.SharedLibs, "libc++")
deps.Rlibs = append(deps.Rlibs, "liblibfuzzer_sys")
diff --git a/rust/rust.go b/rust/rust.go
index 566ad37..ca85d74 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -434,6 +434,7 @@
module.AddProperties(
&BaseProperties{},
&cc.VendorProperties{},
+ &BenchmarkProperties{},
&BindgenProperties{},
&BaseCompilerProperties{},
&BinaryCompilerProperties{},
@@ -798,6 +799,11 @@
return ok && tag == dylibDepTag
}
+func IsRlibDepTag(depTag blueprint.DependencyTag) bool {
+ tag, ok := depTag.(dependencyTag)
+ return ok && tag == rlibDepTag
+}
+
type autoDep struct {
variation string
depTag dependencyTag
diff --git a/rust/sanitize.go b/rust/sanitize.go
index 2498aa1..ae3eff0 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -23,11 +23,12 @@
)
type SanitizeProperties struct {
- // enable AddressSanitizer, ThreadSanitizer, or UndefinedBehaviorSanitizer
+ // enable AddressSanitizer, HWAddressSanitizer, and others.
Sanitize struct {
- Address *bool `android:"arch_variant"`
- Fuzzer *bool `android:"arch_variant"`
- Never *bool `android:"arch_variant"`
+ Address *bool `android:"arch_variant"`
+ Hwaddress *bool `android:"arch_variant"`
+ Fuzzer *bool `android:"arch_variant"`
+ Never *bool `android:"arch_variant"`
}
SanitizerEnabled bool `blueprint:"mutated"`
SanitizeDep bool `blueprint:"mutated"`
@@ -43,7 +44,6 @@
"-C llvm-args=-sanitizer-coverage-level=3",
"-C llvm-args=-sanitizer-coverage-trace-compares",
"-C llvm-args=-sanitizer-coverage-inline-8bit-counters",
- "-C llvm-args=-sanitizer-coverage-stack-depth",
"-C llvm-args=-sanitizer-coverage-trace-geps",
"-C llvm-args=-sanitizer-coverage-prune-blocks=0",
"-Z sanitizer=address",
@@ -57,6 +57,11 @@
"-Z sanitizer=address",
}
+var hwasanFlags = []string{
+ "-Z sanitizer=hwaddress",
+ "-C target-feature=+tagged-globals",
+}
+
func boolPtr(v bool) *bool {
if v {
return &v
@@ -83,6 +88,15 @@
if ctx.Os() == android.Android && Bool(s.Address) {
sanitize.Properties.SanitizerEnabled = true
}
+
+ // HWASan requires AArch64 hardware feature (top-byte-ignore).
+ if ctx.Arch().ArchType != android.Arm64 {
+ s.Hwaddress = nil
+ }
+
+ if ctx.Os() == android.Android && Bool(s.Hwaddress) {
+ sanitize.Properties.SanitizerEnabled = true
+ }
}
type sanitize struct {
@@ -99,6 +113,9 @@
if Bool(sanitize.Properties.Sanitize.Address) {
flags.RustFlags = append(flags.RustFlags, asanFlags...)
}
+ if Bool(sanitize.Properties.Sanitize.Hwaddress) {
+ flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
+ }
return flags, deps
}
@@ -111,11 +128,38 @@
if !mod.Enabled() {
return
}
+
+ variations := mctx.Target().Variations()
+ var depTag blueprint.DependencyTag
+ var deps []string
+
if Bool(mod.sanitize.Properties.Sanitize.Fuzzer) || Bool(mod.sanitize.Properties.Sanitize.Address) {
- mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
- {Mutator: "link", Variation: "shared"},
- }...), cc.SharedDepTag(), config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan"))
+ variations = append(variations,
+ blueprint.Variation{Mutator: "link", Variation: "shared"})
+ depTag = cc.SharedDepTag()
+ deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")}
+ } else if mod.IsSanitizerEnabled(cc.Hwasan) {
+ // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet.
+ if binary, ok := mod.compiler.(*binaryDecorator); ok {
+ if Bool(binary.Properties.Static_executable) {
+ mctx.ModuleErrorf("HWASan is not supported for static Rust executables yet.")
+ }
+ }
+
+ if mod.StaticallyLinked() {
+ variations = append(variations,
+ blueprint.Variation{Mutator: "link", Variation: "static"})
+ depTag = cc.StaticDepTag(false)
+ deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan_static")}
+ } else {
+ variations = append(variations,
+ blueprint.Variation{Mutator: "link", Variation: "shared"})
+ depTag = cc.SharedDepTag()
+ deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")}
+ }
}
+
+ mctx.AddFarVariationDependencies(variations, depTag, deps...)
}
}
@@ -128,6 +172,9 @@
case cc.Asan:
sanitize.Properties.Sanitize.Address = boolPtr(b)
sanitizerSet = true
+ case cc.Hwasan:
+ sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
+ sanitizerSet = true
default:
panic(fmt.Errorf("setting unsupported sanitizerType %d", t))
}
@@ -169,11 +216,23 @@
return sanitize.Properties.Sanitize.Fuzzer
case cc.Asan:
return sanitize.Properties.Sanitize.Address
+ case cc.Hwasan:
+ return sanitize.Properties.Sanitize.Hwaddress
default:
return nil
}
}
+func (sanitize *sanitize) AndroidMk(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ // Add a suffix for hwasan rlib libraries to allow surfacing both the sanitized and
+ // non-sanitized variants to make without a name conflict.
+ if entries.Class == "RLIB_LIBRARIES" || entries.Class == "STATIC_LIBRARIES" {
+ if sanitize.isSanitizerEnabled(cc.Hwasan) {
+ entries.SubName += ".hwasan"
+ }
+ }
+}
+
func (mod *Module) SanitizerSupported(t cc.SanitizerType) bool {
if mod.Host() {
return false
@@ -183,6 +242,8 @@
return true
case cc.Asan:
return true
+ case cc.Hwasan:
+ return true
default:
return false
}
diff --git a/rust/testing.go b/rust/testing.go
index 75adcfc..1e01cc0 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -192,11 +192,19 @@
srcs:["foo.rs"],
host_supported: true,
}
+ rust_library {
+ name: "libcriterion",
+ crate_name: "criterion",
+ srcs:["foo.rs"],
+ host_supported: true,
+ }
`
return bp
}
func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("rust_benchmark", RustBenchmarkFactory)
+ ctx.RegisterModuleType("rust_benchmark_host", RustBenchmarkHostFactory)
ctx.RegisterModuleType("rust_binary", RustBinaryFactory)
ctx.RegisterModuleType("rust_binary_host", RustBinaryHostFactory)
ctx.RegisterModuleType("rust_bindgen", RustBindgenFactory)
diff --git a/scripts/strip.sh b/scripts/strip.sh
index 43e6cbf..e3e5273 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -18,7 +18,6 @@
# Inputs:
# Environment:
# CLANG_BIN: path to the clang bin directory
-# CROSS_COMPILE: prefix added to readelf, objcopy tools
# XZ: path to the xz binary
# Arguments:
# -i ${file}: input file (required)
@@ -69,7 +68,7 @@
KEEP_SYMBOLS="--strip-unneeded-symbol=* --keep-symbols="
KEEP_SYMBOLS+="${outfile}.symbolList"
- "${CROSS_COMPILE}objcopy" -w "${infile}" "${outfile}.tmp" ${KEEP_SYMBOLS}
+ "${CLANG_BIN}/llvm-objcopy" -w "${infile}" "${outfile}.tmp" ${KEEP_SYMBOLS}
}
do_strip_keep_mini_debug_info() {
@@ -78,18 +77,13 @@
"${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes --remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true
if [ -z $fail ]; then
- # Current prebult llvm-objcopy does not support --only-keep-debug flag,
- # and cannot process object files that are produced with the flag. Use
- # GNU objcopy instead for now. (b/141010852)
- "${CROSS_COMPILE}objcopy" --only-keep-debug "${infile}" "${outfile}.debug"
+ "${CLANG_BIN}/llvm-objcopy" --only-keep-debug "${infile}" "${outfile}.debug"
"${CLANG_BIN}/llvm-nm" -D "${infile}" --format=posix --defined-only 2> /dev/null | awk '{ print $1 }' | sort >"${outfile}.dynsyms"
"${CLANG_BIN}/llvm-nm" "${infile}" --format=posix --defined-only | awk '{ if ($2 == "T" || $2 == "t" || $2 == "D") print $1 }' | sort > "${outfile}.funcsyms"
comm -13 "${outfile}.dynsyms" "${outfile}.funcsyms" > "${outfile}.keep_symbols"
echo >> "${outfile}.keep_symbols" # Ensure that the keep_symbols file is not empty.
- "${CROSS_COMPILE}objcopy" --rename-section .debug_frame=saved_debug_frame "${outfile}.debug" "${outfile}.mini_debuginfo"
- "${CROSS_COMPILE}objcopy" -S --remove-section .gdb_index --remove-section .comment --remove-section .rustc --keep-symbols="${outfile}.keep_symbols" "${outfile}.mini_debuginfo"
- "${CROSS_COMPILE}objcopy" --rename-section saved_debug_frame=.debug_frame "${outfile}.mini_debuginfo"
- "${XZ}" --block-size=64k --threads=0 "${outfile}.mini_debuginfo"
+ "${CLANG_BIN}/llvm-objcopy" -S --keep-section .debug_frame --keep-symbols="${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo"
+ "${XZ}" --keep --block-size=64k --threads=0 "${outfile}.mini_debuginfo"
"${CLANG_BIN}/llvm-objcopy" --add-section .gnu_debugdata="${outfile}.mini_debuginfo.xz" "${outfile}.tmp"
rm -f "${outfile}.dynsyms" "${outfile}.funcsyms" "${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo" "${outfile}.mini_debuginfo.xz"
@@ -196,7 +190,6 @@
cat <<EOF > "${depsfile}"
${outfile}: \
${infile} \
- ${CROSS_COMPILE}objcopy \
${CLANG_BIN}/llvm-nm \
${CLANG_BIN}/llvm-objcopy \
${CLANG_BIN}/llvm-readelf \
diff --git a/bootstrap_test.sh b/tests/bootstrap_test.sh
similarity index 77%
rename from bootstrap_test.sh
rename to tests/bootstrap_test.sh
index 9d87697..5271f8d 100755
--- a/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -3,106 +3,13 @@
# This test exercises the bootstrapping process of the build system
# in a source tree that only contains enough files for Bazel and Soong to work.
-HARDWIRED_MOCK_TOP=
-# Uncomment this to be able to view the source tree after a test is run
-# HARDWIRED_MOCK_TOP=/tmp/td
-
-REAL_TOP="$(readlink -f "$(dirname "$0")"/../..)"
-
-function fail {
- echo ERROR: $1
- exit 1
-}
-
-function copy_directory() {
- local dir="$1"
- local parent="$(dirname "$dir")"
-
- mkdir -p "$MOCK_TOP/$parent"
- cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
-}
-
-function symlink_file() {
- local file="$1"
-
- mkdir -p "$MOCK_TOP/$(dirname "$file")"
- ln -s "$REAL_TOP/$file" "$MOCK_TOP/$file"
-}
-
-function symlink_directory() {
- local dir="$1"
-
- mkdir -p "$MOCK_TOP/$dir"
- # We need to symlink the contents of the directory individually instead of
- # using one symlink for the whole directory because finder.go doesn't follow
- # symlinks when looking for Android.bp files
- for i in $(ls "$REAL_TOP/$dir"); do
- local target="$MOCK_TOP/$dir/$i"
- local source="$REAL_TOP/$dir/$i"
-
- if [[ -e "$target" ]]; then
- if [[ ! -d "$source" || ! -d "$target" ]]; then
- fail "Trying to symlink $dir twice"
- fi
- else
- ln -s "$REAL_TOP/$dir/$i" "$MOCK_TOP/$dir/$i";
- fi
- done
-}
-
-function setup_bazel() {
- copy_directory build/bazel
-
- symlink_directory prebuilts/bazel
- symlink_directory prebuilts/jdk
-
- symlink_file WORKSPACE
- symlink_file tools/bazel
-}
-
-function setup() {
- if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
- MOCK_TOP="$HARDWIRED_MOCK_TOP"
- rm -fr "$MOCK_TOP"
- mkdir -p "$MOCK_TOP"
- else
- MOCK_TOP=$(mktemp -t -d st.XXXXX)
- trap 'echo cd / && echo rm -fr "$MOCK_TOP"' EXIT
- fi
-
- echo "Test case: ${FUNCNAME[1]}, mock top path: $MOCK_TOP"
- cd "$MOCK_TOP"
-
- copy_directory build/blueprint
- copy_directory build/soong
-
- symlink_directory prebuilts/go
- symlink_directory prebuilts/build-tools
- symlink_directory external/golang-protobuf
-
- touch "$MOCK_TOP/Android.bp"
-
- export ALLOW_MISSING_DEPENDENCIES=true
-
- mkdir -p out/soong
-}
-
-function run_soong() {
- build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests
-}
+source "$(dirname "$0")/lib.sh"
function test_smoke {
setup
run_soong
}
-function test_bazel_smoke {
- setup
- setup_bazel
-
- tools/bazel info
-
-}
function test_null_build() {
setup
run_soong
@@ -388,6 +295,118 @@
grep -q "Make it so" out/soong/build.ninja || fail "New action not present"
}
+# Tests a glob in a build= statement in an Android.bp file, which is interpreted
+# during bootstrapping.
+function test_glob_during_bootstrapping() {
+ setup
+
+ mkdir -p a
+ cat > a/Android.bp <<'EOF'
+build=["foo*.bp"]
+EOF
+ cat > a/fooa.bp <<'EOF'
+bootstrap_go_package {
+ name: "picard-soong-rules",
+ pkgPath: "android/soong/picard",
+ deps: [
+ "blueprint",
+ "soong",
+ "soong-android",
+ ],
+ srcs: [
+ "picard.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+EOF
+
+ cat > a/picard.go <<'EOF'
+package picard
+
+import (
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+var (
+ pctx = android.NewPackageContext("picard")
+)
+
+func init() {
+ android.RegisterSingletonType("picard", PicardSingleton)
+}
+
+func PicardSingleton() android.Singleton {
+ return &picardSingleton{}
+}
+
+type picardSingleton struct{}
+
+var Message = "Make it so."
+
+func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ picardRule := ctx.Rule(pctx, "picard",
+ blueprint.RuleParams{
+ Command: "echo " + Message + " > ${out}",
+ CommandDeps: []string{},
+ Description: "Something quotable",
+ })
+
+ outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
+ var deps android.Paths
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: picardRule,
+ Output: outputFile,
+ Inputs: deps,
+ })
+}
+
+EOF
+
+ run_soong
+ local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ grep -q "Make it so" out/soong/build.ninja || fail "Original action not present"
+
+ cat > a/foob.bp <<'EOF'
+bootstrap_go_package {
+ name: "worf-soong-rules",
+ pkgPath: "android/soong/worf",
+ deps: [
+ "blueprint",
+ "soong",
+ "soong-android",
+ "picard-soong-rules",
+ ],
+ srcs: [
+ "worf.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+EOF
+
+ cat > a/worf.go <<'EOF'
+package worf
+
+import "android/soong/picard"
+
+func init() {
+ picard.Message = "Engage."
+}
+EOF
+
+ run_soong
+ local mtime2=$(stat -c "%y" out/soong/build.ninja)
+ if [[ "$mtime1" == "$mtime2" ]]; then
+ fail "Output Ninja file did not change"
+ fi
+
+ grep -q "Engage" out/soong/build.ninja || fail "New action not present"
+
+ grep -q "Make it so" out/soong/build.ninja && fail "Original action still present"
+}
+
function test_null_build_after_docs {
setup
run_soong
@@ -410,7 +429,6 @@
fi
}
-test_bazel_smoke
test_smoke
test_null_build
test_null_build_after_docs
@@ -420,5 +438,6 @@
test_change_android_bp
test_delete_android_bp
test_add_file_to_soong_build
+test_glob_during_bootstrapping
test_soong_build_rerun_iff_environment_changes
test_dump_json_module_graph
diff --git a/tests/lib.sh b/tests/lib.sh
new file mode 100644
index 0000000..3c97e14
--- /dev/null
+++ b/tests/lib.sh
@@ -0,0 +1,79 @@
+#!/bin/bash -eu
+
+HARDWIRED_MOCK_TOP=
+# Uncomment this to be able to view the source tree after a test is run
+# HARDWIRED_MOCK_TOP=/tmp/td
+
+REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
+
+function fail {
+ echo ERROR: $1
+ exit 1
+}
+
+function copy_directory() {
+ local dir="$1"
+ local parent="$(dirname "$dir")"
+
+ mkdir -p "$MOCK_TOP/$parent"
+ cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
+}
+
+function symlink_file() {
+ local file="$1"
+
+ mkdir -p "$MOCK_TOP/$(dirname "$file")"
+ ln -s "$REAL_TOP/$file" "$MOCK_TOP/$file"
+}
+
+function symlink_directory() {
+ local dir="$1"
+
+ mkdir -p "$MOCK_TOP/$dir"
+ # We need to symlink the contents of the directory individually instead of
+ # using one symlink for the whole directory because finder.go doesn't follow
+ # symlinks when looking for Android.bp files
+ for i in $(ls "$REAL_TOP/$dir"); do
+ local target="$MOCK_TOP/$dir/$i"
+ local source="$REAL_TOP/$dir/$i"
+
+ if [[ -e "$target" ]]; then
+ if [[ ! -d "$source" || ! -d "$target" ]]; then
+ fail "Trying to symlink $dir twice"
+ fi
+ else
+ ln -s "$REAL_TOP/$dir/$i" "$MOCK_TOP/$dir/$i";
+ fi
+ done
+}
+
+function setup() {
+ if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
+ MOCK_TOP="$HARDWIRED_MOCK_TOP"
+ rm -fr "$MOCK_TOP"
+ mkdir -p "$MOCK_TOP"
+ else
+ MOCK_TOP=$(mktemp -t -d st.XXXXX)
+ trap 'echo cd / && echo rm -fr "$MOCK_TOP"' EXIT
+ fi
+
+ echo "Test case: ${FUNCNAME[1]}, mock top path: $MOCK_TOP"
+ cd "$MOCK_TOP"
+
+ copy_directory build/blueprint
+ copy_directory build/soong
+
+ symlink_directory prebuilts/go
+ symlink_directory prebuilts/build-tools
+ symlink_directory external/golang-protobuf
+
+ touch "$MOCK_TOP/Android.bp"
+
+ export ALLOW_MISSING_DEPENDENCIES=true
+
+ mkdir -p out/soong
+}
+
+function run_soong() {
+ build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests
+}
diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh
new file mode 100755
index 0000000..54f0689
--- /dev/null
+++ b/tests/mixed_mode_test.sh
@@ -0,0 +1,28 @@
+#!/bin/bash -eu
+
+# This test exercises mixed builds where Soong and Bazel cooperate in building
+# Android.
+#
+# When the execroot is deleted, the Bazel server process will automatically
+# terminate itself.
+
+source "$(dirname "$0")/lib.sh"
+
+function setup_bazel() {
+ copy_directory build/bazel
+
+ symlink_directory prebuilts/bazel
+ symlink_directory prebuilts/jdk
+
+ symlink_file WORKSPACE
+ symlink_file tools/bazel
+}
+
+function test_bazel_smoke {
+ setup
+ setup_bazel
+
+ tools/bazel info
+}
+
+test_bazel_smoke
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
new file mode 100755
index 0000000..db24037
--- /dev/null
+++ b/tests/run_integration_tests.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+TOP="$(readlink -f "$(dirname "$0")"/../../..)"
+"$TOP/build/soong/tests/bootstrap_test.sh"
+"$TOP/build/soong/tests/mixed_mode_test.sh"
+
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 27d71e8..3d96c84 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -245,6 +245,25 @@
return path
}
+func AutoGenRustBenchmarkConfig(ctx android.ModuleContext, testConfigProp *string,
+ testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path {
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
+ if autogenPath != nil {
+ templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
+ if templatePath.Valid() {
+ autogenTemplate(ctx, autogenPath, templatePath.String(), config, "")
+ } else {
+ if ctx.Device() {
+ autogenTemplate(ctx, autogenPath, "${RustDeviceBenchmarkConfigTemplate}", config, "")
+ } else {
+ autogenTemplate(ctx, autogenPath, "${RustHostBenchmarkConfigTemplate}", config, "")
+ }
+ }
+ return autogenPath
+ }
+ return path
+}
+
func AutoGenRobolectricTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string,
testSuites []string, autoGenConfig *bool) android.Path {
path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
diff --git a/tradefed/config.go b/tradefed/config.go
index f3566a8..999424c 100644
--- a/tradefed/config.go
+++ b/tradefed/config.go
@@ -34,6 +34,8 @@
pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml")
pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml")
pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml")
+ pctx.SourcePathVariable("RustDeviceBenchmarkConfigTemplate", "build/make/core/rust_device_benchmark_config_template.xml")
+ pctx.SourcePathVariable("RustHostBenchmarkConfigTemplate", "build/make/core/rust_host_benchmark_config_template.xml")
pctx.SourcePathVariable("RobolectricTestConfigTemplate", "build/make/core/robolectric_test_config_template.xml")
pctx.SourcePathVariable("ShellTestConfigTemplate", "build/make/core/shell_test_config_template.xml")
diff --git a/tradefed/makevars.go b/tradefed/makevars.go
index f9682e4..9b5a20f 100644
--- a/tradefed/makevars.go
+++ b/tradefed/makevars.go
@@ -33,6 +33,8 @@
ctx.Strict("PYTHON_BINARY_HOST_TEST_CONFIG_TEMPLATE", "${PythonBinaryHostTestConfigTemplate}")
ctx.Strict("RUST_DEVICE_TEST_CONFIG_TEMPLATE", "${RustDeviceTestConfigTemplate}")
ctx.Strict("RUST_HOST_TEST_CONFIG_TEMPLATE", "${RustHostTestConfigTemplate}")
+ ctx.Strict("RUST_DEVICE_BENCHMARK_CONFIG_TEMPLATE", "${RustDeviceBenchmarkConfigTemplate}")
+ ctx.Strict("RUST_HOST_BENCHMARK_CONFIG_TEMPLATE", "${RustHostBenchmarkConfigTemplate}")
ctx.Strict("SHELL_TEST_CONFIG_TEMPLATE", "${ShellTestConfigTemplate}")
ctx.Strict("EMPTY_TEST_CONFIG", "${EmptyTestConfig}")
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 9afcb88..0089075 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -104,6 +104,11 @@
args.GlobFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/soong-build-globs.ninja")
args.GeneratingPrimaryBuilder = true
+ args.DelveListen = os.Getenv("SOONG_DELVE")
+ if args.DelveListen != "" {
+ args.DelvePath = shared.ResolveDelveBinary()
+ }
+
blueprintCtx := blueprint.NewContext()
blueprintCtx.SetIgnoreUnknownModuleTypes(true)
blueprintConfig := BlueprintConfig{
@@ -138,11 +143,6 @@
soongBuildEnv := config.Environment().Copy()
soongBuildEnv.Set("TOP", os.Getenv("TOP"))
- // These two dependencies are read from bootstrap.go, but also need to be here
- // so that soong_build can declare a dependency on them
- soongBuildEnv.Set("SOONG_DELVE", os.Getenv("SOONG_DELVE"))
- soongBuildEnv.Set("SOONG_DELVE_PATH", os.Getenv("SOONG_DELVE_PATH"))
- soongBuildEnv.Set("SOONG_OUTDIR", config.SoongOutDir())
// For Bazel mixed builds.
soongBuildEnv.Set("BAZEL_PATH", "./tools/bazel")
soongBuildEnv.Set("BAZEL_HOME", filepath.Join(config.BazelOutDir(), "bazelhome"))
@@ -215,13 +215,6 @@
// This is currently how the command line to invoke soong_build finds the
// root of the source tree and the output root
ninjaEnv.Set("TOP", os.Getenv("TOP"))
- ninjaEnv.Set("SOONG_OUTDIR", config.SoongOutDir())
-
- // For debugging
- if os.Getenv("SOONG_DELVE") != "" {
- ninjaEnv.Set("SOONG_DELVE", os.Getenv("SOONG_DELVE"))
- ninjaEnv.Set("SOONG_DELVE_PATH", shared.ResolveDelveBinary())
- }
cmd.Environment = &ninjaEnv
cmd.Sandbox = soongSandbox
diff --git a/zip/zip.go b/zip/zip.go
index a6490d4..84e974b 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -292,11 +292,11 @@
continue
}
- globbed, _, err := z.fs.Glob(s, nil, followSymlinks)
+ result, err := z.fs.Glob(s, nil, followSymlinks)
if err != nil {
return err
}
- if len(globbed) == 0 {
+ if len(result.Matches) == 0 {
err := &os.PathError{
Op: "lstat",
Path: s,
@@ -308,7 +308,7 @@
return err
}
}
- srcs = append(srcs, globbed...)
+ srcs = append(srcs, result.Matches...)
}
if fa.GlobDir != "" {
if exists, isDir, err := z.fs.Exists(fa.GlobDir); err != nil {
@@ -336,11 +336,11 @@
return err
}
}
- globbed, _, err := z.fs.Glob(filepath.Join(fa.GlobDir, "**/*"), nil, followSymlinks)
+ result, err := z.fs.Glob(filepath.Join(fa.GlobDir, "**/*"), nil, followSymlinks)
if err != nil {
return err
}
- srcs = append(srcs, globbed...)
+ srcs = append(srcs, result.Matches...)
}
for _, src := range srcs {
err := fillPathPairs(fa, src, &pathMappings, args.NonDeflatedFiles, noCompression)