Merge changes from topic "roll-rust-1.47.0"
* changes:
Use Rust 1.47.0 prebuilts
rust: set STD_ENV_ARCH
diff --git a/android/config.go b/android/config.go
index a499057..e87a4ac 100644
--- a/android/config.go
+++ b/android/config.go
@@ -974,13 +974,21 @@
return c.productVariables.ModulesLoadedByPrivilegedModules
}
-func (c *config) DexpreoptGlobalConfig(ctx PathContext) ([]byte, error) {
+func (c *config) DexpreoptGlobalConfigPath(ctx PathContext) OptionalPath {
if c.productVariables.DexpreoptGlobalConfig == nil {
+ return OptionalPathForPath(nil)
+ }
+ return OptionalPathForPath(
+ pathForBuildToolDep(ctx, *c.productVariables.DexpreoptGlobalConfig))
+}
+
+func (c *config) DexpreoptGlobalConfig(ctx PathContext) ([]byte, error) {
+ path := c.DexpreoptGlobalConfigPath(ctx)
+ if !path.Valid() {
return nil, nil
}
- path := absolutePath(*c.productVariables.DexpreoptGlobalConfig)
- ctx.AddNinjaFileDeps(path)
- return ioutil.ReadFile(path)
+ ctx.AddNinjaFileDeps(path.String())
+ return ioutil.ReadFile(absolutePath(path.String()))
}
func (c *config) FrameworksBaseDirExists(ctx PathContext) bool {
diff --git a/android/writedocs.go b/android/writedocs.go
index 4eb15e6..91c2318 100644
--- a/android/writedocs.go
+++ b/android/writedocs.go
@@ -48,6 +48,13 @@
deps = append(deps, pathForBuildToolDep(ctx, ctx.Config().moduleListFile))
deps = append(deps, pathForBuildToolDep(ctx, ctx.Config().ProductVariablesFileName))
+ // The dexpreopt configuration may not exist, but if it does, it's a dependency
+ // of soong_build.
+ dexpreoptConfigPath := ctx.Config().DexpreoptGlobalConfigPath(ctx)
+ if dexpreoptConfigPath.Valid() {
+ deps = append(deps, dexpreoptConfigPath.Path())
+ }
+
// Generate build system docs for the primary builder. Generating docs reads the source
// files used to build the primary builder, but that dependency will be picked up through
// the dependency on the primary builder itself. There are no dependencies on the
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index e5b91e5..8c70a56 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -235,6 +235,7 @@
libc_headers(minSdkVersion:apex_inherit)
libc_headers_arch(minSdkVersion:apex_inherit)
libcap(minSdkVersion:29)
+libclang_rt.hwasan-aarch64-android.llndk(minSdkVersion:(no version))
libcodec2(minSdkVersion:29)
libcodec2_headers(minSdkVersion:29)
libcodec2_hidl@1.0(minSdkVersion:29)
diff --git a/apex/apex.go b/apex/apex.go
index b02711e..fdc105e 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -276,8 +276,6 @@
"libc_malloc_debug_backtrace",
"libcamera_client",
"libcamera_metadata",
- "libdexfile_external_headers",
- "libdexfile_support",
"libdvr_headers",
"libexpat",
"libfifo",
@@ -304,10 +302,6 @@
"libmp4extractor",
"libmpeg2extractor",
"libnativebase_headers",
- "libnativebridge-headers",
- "libnativebridge_lazy",
- "libnativeloader-headers",
- "libnativeloader_lazy",
"libnativewindow_headers",
"libnblog",
"liboggextractor",
@@ -431,7 +425,6 @@
"libcodec2_soft_vp9dec",
"libcodec2_soft_vp9enc",
"libcodec2_vndk",
- "libdexfile_support",
"libdvr_headers",
"libfmq",
"libfmq",
@@ -454,8 +447,6 @@
"libmedia_headers",
"libmpeg2dec",
"libnativebase_headers",
- "libnativebridge_lazy",
- "libnativeloader_lazy",
"libnativewindow_headers",
"libpdx_headers",
"libscudo_wrapper",
@@ -563,8 +554,6 @@
"libdebuggerd_common_headers",
"libdebuggerd_handler_core",
"libdebuggerd_handler_fallback",
- "libdexfile_external_headers",
- "libdexfile_support",
"libdl_static",
"libjemalloc5",
"liblinker_main",
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index 803e0c5..ee9fc81 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -100,6 +100,8 @@
"new_allowed_deps": newAllowedDeps.String(),
},
})
+
+ ctx.Phony("apex-allowed-deps-check", s.allowedApexDepsInfoCheckResult)
}
func (s *apexDepsInfoSingleton) MakeVars(ctx android.MakeVarsContext) {
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index dddd5ac..6029f5a 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -52,7 +52,7 @@
// VNDK snapshot version.
Version *string
- // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab')
+ // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64')
Target_arch *string
// If the prebuilt snapshot lib is built with 32 bit binder, this must be set to true.
diff --git a/cmd/soong_build/bazel_overlay.go b/cmd/soong_build/bazel_overlay.go
index cdc5775..fc1b492 100644
--- a/cmd/soong_build/bazel_overlay.go
+++ b/cmd/soong_build/bazel_overlay.go
@@ -370,7 +370,7 @@
// Canonicalize and normalize module property types to Bazel attribute types
starlarkAttrType := prop.Type
- if starlarkAttrType == "list of strings" {
+ if starlarkAttrType == "list of string" {
starlarkAttrType = "string_list"
} else if starlarkAttrType == "int64" {
starlarkAttrType = "int"
diff --git a/cmd/soong_build/bazel_overlay_test.go b/cmd/soong_build/bazel_overlay_test.go
index de060bb..548888e 100644
--- a/cmd/soong_build/bazel_overlay_test.go
+++ b/cmd/soong_build/bazel_overlay_test.go
@@ -277,7 +277,7 @@
},
bpdoc.Property{
Name: "string_list_prop",
- Type: "list of strings",
+ Type: "list of string",
},
bpdoc.Property{
Name: "nested_prop",
diff --git a/python/python.go b/python/python.go
index 479c729..945e264 100644
--- a/python/python.go
+++ b/python/python.go
@@ -101,6 +101,13 @@
// this property name is hidden from users' perspectives, and soong will populate it during
// runtime.
Actual_version string `blueprint:"mutated"`
+
+ // true, if the module is required to be built with actual_version.
+ Enabled *bool `blueprint:"mutated"`
+
+ // true, if the binary is required to be built with embedded launcher.
+ // TODO(nanzhang): Remove this flag when embedded Python3 is supported later.
+ Embedded_launcher *bool `blueprint:"mutated"`
}
type pathMapping struct {
@@ -228,15 +235,18 @@
return func(mctx android.BottomUpMutatorContext) {
if base, ok := mctx.Module().(*Module); ok {
versionNames := []string{}
+ versionProps := []VersionProperties{}
// PY3 is first so that we alias the PY3 variant rather than PY2 if both
// are available
if !(base.properties.Version.Py3.Enabled != nil &&
*(base.properties.Version.Py3.Enabled) == false) {
versionNames = append(versionNames, pyVersion3)
+ versionProps = append(versionProps, base.properties.Version.Py3)
}
if base.properties.Version.Py2.Enabled != nil &&
*(base.properties.Version.Py2.Enabled) == true {
versionNames = append(versionNames, pyVersion2)
+ versionProps = append(versionProps, base.properties.Version.Py2)
}
modules := mctx.CreateVariations(versionNames...)
if len(versionNames) > 0 {
@@ -245,6 +255,11 @@
for i, v := range versionNames {
// set the actual version for Python module.
modules[i].(*Module).properties.Actual_version = v
+ // append versioned properties for the Python module
+ err := proptools.AppendMatchingProperties([]interface{}{&modules[i].(*Module).properties}, &versionProps[i], nil)
+ if err != nil {
+ panic(err)
+ }
}
}
}
@@ -270,15 +285,8 @@
}
}
-func (p *Module) isEmbeddedLauncherEnabled(actual_version string) bool {
- switch actual_version {
- case pyVersion2:
- return Bool(p.properties.Version.Py2.Embedded_launcher)
- case pyVersion3:
- return Bool(p.properties.Version.Py3.Embedded_launcher)
- }
-
- return false
+func (p *Module) isEmbeddedLauncherEnabled() bool {
+ return Bool(p.properties.Embedded_launcher)
}
func hasSrcExt(srcs []string, ext string) bool {
@@ -292,18 +300,7 @@
}
func (p *Module) hasSrcExt(ctx android.BottomUpMutatorContext, ext string) bool {
- if hasSrcExt(p.properties.Srcs, protoExt) {
- return true
- }
- switch p.properties.Actual_version {
- case pyVersion2:
- return hasSrcExt(p.properties.Version.Py2.Srcs, protoExt)
- case pyVersion3:
- return hasSrcExt(p.properties.Version.Py3.Srcs, protoExt)
- default:
- panic(fmt.Errorf("unknown Python Actual_version: %q for module: %q.",
- p.properties.Actual_version, ctx.ModuleName()))
- }
+ return hasSrcExt(p.properties.Srcs, protoExt)
}
func (p *Module) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -312,13 +309,12 @@
if p.hasSrcExt(ctx, protoExt) && p.Name() != "libprotobuf-python" {
ctx.AddVariationDependencies(nil, pythonLibTag, "libprotobuf-python")
}
+ ctx.AddVariationDependencies(nil, pythonLibTag, android.LastUniqueStrings(p.properties.Libs)...)
+
switch p.properties.Actual_version {
case pyVersion2:
- ctx.AddVariationDependencies(nil, pythonLibTag,
- uniqueLibs(ctx, p.properties.Libs, "version.py2.libs",
- p.properties.Version.Py2.Libs)...)
- if p.bootstrapper != nil && p.isEmbeddedLauncherEnabled(pyVersion2) {
+ if p.bootstrapper != nil && p.isEmbeddedLauncherEnabled() {
ctx.AddVariationDependencies(nil, pythonLibTag, "py2-stdlib")
launcherModule := "py2-launcher"
@@ -340,11 +336,8 @@
}
case pyVersion3:
- ctx.AddVariationDependencies(nil, pythonLibTag,
- uniqueLibs(ctx, p.properties.Libs, "version.py3.libs",
- p.properties.Version.Py3.Libs)...)
- if p.bootstrapper != nil && p.isEmbeddedLauncherEnabled(pyVersion3) {
+ if p.bootstrapper != nil && p.isEmbeddedLauncherEnabled() {
ctx.AddVariationDependencies(nil, pythonLibTag, "py3-stdlib")
launcherModule := "py3-launcher"
@@ -375,34 +368,6 @@
}
}
-// check "libs" duplicates from current module dependencies.
-func uniqueLibs(ctx android.BottomUpMutatorContext,
- commonLibs []string, versionProp string, versionLibs []string) []string {
- set := make(map[string]string)
- ret := []string{}
-
- // deps from "libs" property.
- for _, l := range commonLibs {
- if _, found := set[l]; found {
- ctx.PropertyErrorf("libs", "%q has duplicates within libs.", l)
- } else {
- set[l] = "libs"
- ret = append(ret, l)
- }
- }
- // deps from "version.pyX.libs" property.
- for _, l := range versionLibs {
- if _, found := set[l]; found {
- ctx.PropertyErrorf(versionProp, "%q has duplicates within %q.", set[l])
- } else {
- set[l] = versionProp
- ret = append(ret, l)
- }
- }
-
- return ret
-}
-
func (p *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
p.GeneratePythonBuildActions(ctx)
@@ -410,11 +375,7 @@
if p.bootstrapper != nil {
p.walkTransitiveDeps(ctx)
embeddedLauncher := false
- if p.properties.Actual_version == pyVersion2 {
- embeddedLauncher = p.isEmbeddedLauncherEnabled(pyVersion2)
- } else {
- embeddedLauncher = p.isEmbeddedLauncherEnabled(pyVersion3)
- }
+ embeddedLauncher = p.isEmbeddedLauncherEnabled()
p.installSource = p.bootstrapper.bootstrap(ctx, p.properties.Actual_version,
embeddedLauncher, p.srcsPathMappings, p.srcsZip, p.depsSrcsZips)
}
@@ -439,17 +400,6 @@
// expand python files from "srcs" property.
srcs := p.properties.Srcs
exclude_srcs := p.properties.Exclude_srcs
- switch p.properties.Actual_version {
- case pyVersion2:
- srcs = append(srcs, p.properties.Version.Py2.Srcs...)
- exclude_srcs = append(exclude_srcs, p.properties.Version.Py2.Exclude_srcs...)
- case pyVersion3:
- srcs = append(srcs, p.properties.Version.Py3.Srcs...)
- exclude_srcs = append(exclude_srcs, p.properties.Version.Py3.Exclude_srcs...)
- default:
- panic(fmt.Errorf("unknown Python Actual_version: %q for module: %q.",
- p.properties.Actual_version, ctx.ModuleName()))
- }
expandedSrcs := android.PathsForModuleSrcExcludes(ctx, srcs, exclude_srcs)
requiresSrcs := true
if p.bootstrapper != nil && !p.bootstrapper.autorun() {
diff --git a/python/python_test.go b/python/python_test.go
index 23db24e..10b565a 100644
--- a/python/python_test.go
+++ b/python/python_test.go
@@ -395,10 +395,11 @@
if !reflect.DeepEqual(actualPyRunfiles, expectedPyRunfiles) {
testErrs = append(testErrs, errors.New(fmt.Sprintf(
- `binary "%s" variant "%s" has unexpected pyRunfiles: %q!`,
+ `binary "%s" variant "%s" has unexpected pyRunfiles: %q! (expected: %q)`,
base.Name(),
base.properties.Actual_version,
- actualPyRunfiles)))
+ actualPyRunfiles,
+ expectedPyRunfiles)))
}
if base.srcsZip.String() != strings.Replace(expectedSrcsZip, "@prefix@", buildDir, 1) {
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 3db2d65..09af649 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -32,7 +32,7 @@
bindgenClangVersion = "clang-r383902c"
//TODO(b/160803703) Use a prebuilt bindgen instead of the built bindgen.
- _ = pctx.SourcePathVariable("bindgenCmd", "out/host/${config.HostPrebuiltTag}/bin/bindgen")
+ _ = pctx.HostBinToolVariable("bindgenCmd", "bindgen")
_ = pctx.SourcePathVariable("bindgenClang",
"${cc_config.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/bin/clang")
_ = pctx.SourcePathVariable("bindgenLibClang",
diff --git a/rust/protobuf.go b/rust/protobuf.go
index ebb1c3c..28a4597 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -22,9 +22,18 @@
defaultProtobufFlags = []string{""}
)
+type PluginType int
+
+const (
+ Protobuf PluginType = iota
+ Grpc
+)
+
func init() {
android.RegisterModuleType("rust_protobuf", RustProtobufFactory)
android.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory)
+ android.RegisterModuleType("rust_grpcio", RustGrpcioFactory)
+ android.RegisterModuleType("rust_grpcio_host", RustGrpcioHostFactory)
}
var _ SourceProvider = (*protobufDecorator)(nil)
@@ -41,15 +50,18 @@
*BaseSourceProvider
Properties ProtobufProperties
+ plugin PluginType
}
func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
var protoFlags android.ProtoFlags
- pluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
+ var pluginPath android.Path
protoFlags.OutTypeFlag = "--rust_out"
+ outDir := android.PathForModuleOut(ctx)
- protoFlags.Flags = append(protoFlags.Flags, " --plugin="+pluginPath.String())
+ pluginPath, protoFlags = proto.setupPlugin(ctx, protoFlags, outDir)
+
protoFlags.Flags = append(protoFlags.Flags, defaultProtobufFlags...)
protoFlags.Flags = append(protoFlags.Flags, proto.Properties.Proto_flags...)
@@ -60,7 +72,6 @@
ctx.PropertyErrorf("proto", "invalid path to proto file")
}
- outDir := android.PathForModuleOut(ctx)
stem := proto.BaseSourceProvider.getStem(ctx)
// rust protobuf-codegen output <stem>.rs
stemFile := android.PathForModuleOut(ctx, stem+".rs")
@@ -79,6 +90,23 @@
return modFile
}
+func (proto *protobufDecorator) setupPlugin(ctx ModuleContext, protoFlags android.ProtoFlags, outDir android.ModuleOutPath) (android.Path, android.ProtoFlags) {
+ var pluginPath android.Path
+
+ if proto.plugin == Protobuf {
+ pluginPath = ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
+ protoFlags.Flags = append(protoFlags.Flags, "--plugin="+pluginPath.String())
+ } else if proto.plugin == Grpc {
+ pluginPath = ctx.Config().HostToolPath(ctx, "grpc_rust_plugin")
+ protoFlags.Flags = append(protoFlags.Flags, "--grpc_out="+outDir.String())
+ protoFlags.Flags = append(protoFlags.Flags, "--plugin=protoc-gen-grpc="+pluginPath.String())
+ } else {
+ ctx.ModuleErrorf("Unknown protobuf plugin type requested")
+ }
+
+ return pluginPath, protoFlags
+}
+
func (proto *protobufDecorator) SourceProviderProps() []interface{} {
return append(proto.BaseSourceProvider.SourceProviderProps(), &proto.Properties)
}
@@ -104,10 +132,34 @@
return module.Init()
}
+func RustGrpcioFactory() android.Module {
+ module, _ := NewRustGrpcio(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+// A host-only variant of rust_protobuf. Refer to rust_protobuf for more details.
+func RustGrpcioHostFactory() android.Module {
+ module, _ := NewRustGrpcio(android.HostSupported)
+ return module.Init()
+}
+
func NewRustProtobuf(hod android.HostOrDeviceSupported) (*Module, *protobufDecorator) {
protobuf := &protobufDecorator{
BaseSourceProvider: NewSourceProvider(),
Properties: ProtobufProperties{},
+ plugin: Protobuf,
+ }
+
+ module := NewSourceProviderModule(hod, protobuf, false)
+
+ return module, protobuf
+}
+
+func NewRustGrpcio(hod android.HostOrDeviceSupported) (*Module, *protobufDecorator) {
+ protobuf := &protobufDecorator{
+ BaseSourceProvider: NewSourceProvider(),
+ Properties: ProtobufProperties{},
+ plugin: Grpc,
}
module := NewSourceProviderModule(hod, protobuf, false)
diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go
index bd11a5a..7c39071 100644
--- a/rust/protobuf_test.go
+++ b/rust/protobuf_test.go
@@ -15,8 +15,10 @@
package rust
import (
- "android/soong/android"
+ "strings"
"testing"
+
+ "android/soong/android"
)
func TestRustProtobuf(t *testing.T) {
@@ -28,12 +30,41 @@
source_stem: "buf",
}
`)
- // Check that there's a rule to generate the expected output
- _ = ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("buf.rs")
-
// Check that libprotobuf is added as a dependency.
librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module)
if !android.InList("libprotobuf", librust_proto.Properties.AndroidMkDylibs) {
t.Errorf("libprotobuf dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)")
}
+
+ // Make sure the correct plugin is being used.
+ librust_proto_out := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("buf.rs")
+ cmd := librust_proto_out.RuleParams.Command
+ if w := "protoc-gen-rust"; !strings.Contains(cmd, w) {
+ t.Errorf("expected %q in %q", w, cmd)
+ }
+
+}
+
+func TestRustGrpcio(t *testing.T) {
+ ctx := testRust(t, `
+ rust_grpcio {
+ name: "librust_grpcio",
+ proto: "buf.proto",
+ crate_name: "rust_grpcio",
+ source_stem: "buf",
+ }
+ `)
+
+ // Check that libprotobuf is added as a dependency.
+ librust_grpcio_module := ctx.ModuleForTests("librust_grpcio", "android_arm64_armv8-a_dylib").Module().(*Module)
+ if !android.InList("libprotobuf", librust_grpcio_module.Properties.AndroidMkDylibs) {
+ t.Errorf("libprotobuf dependency missing for rust_grpcio (dependency missing from AndroidMkDylibs)")
+ }
+
+ // Make sure the correct plugin is being used.
+ librust_grpcio_out := ctx.ModuleForTests("librust_grpcio", "android_arm64_armv8-a_source").Output("buf.rs")
+ cmd := librust_grpcio_out.RuleParams.Command
+ if w := "protoc-gen-grpc"; !strings.Contains(cmd, w) {
+ t.Errorf("expected %q in %q", w, cmd)
+ }
}
diff --git a/rust/testing.go b/rust/testing.go
index 42b0da1..4a1894c 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -132,6 +132,8 @@
ctx.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
ctx.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
ctx.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory)
+ ctx.RegisterModuleType("rust_grpcio", RustGrpcioFactory)
+ ctx.RegisterModuleType("rust_grpcio_host", RustGrpcioHostFactory)
ctx.RegisterModuleType("rust_proc_macro", ProcMacroFactory)
ctx.RegisterModuleType("rust_protobuf", RustProtobufFactory)
ctx.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory)
diff --git a/ui/build/bazel.go b/ui/build/bazel.go
index c5702c0..978553d 100644
--- a/ui/build/bazel.go
+++ b/ui/build/bazel.go
@@ -15,6 +15,8 @@
package build
import (
+ "io/ioutil"
+ "os"
"path/filepath"
"strings"
)
@@ -32,12 +34,6 @@
bazelExecutable := filepath.Join("tools", "bazel")
args := []string{
"build",
- "--verbose_failures",
- "--show_progress_rate_limit=0.05",
- "--color=yes",
- "--curses=yes",
- "--show_timestamps",
- "--announce_rc",
"--output_groups=" + outputGroups,
"//:" + config.TargetProduct() + "-" + config.TargetBuildVariant(),
}
@@ -51,4 +47,57 @@
cmd.Dir = filepath.Join(config.OutDir(), "..")
ctx.Status.Status("Starting Bazel..")
cmd.RunAndStreamOrFatal()
+
+ // Obtain the Bazel output directory for ninja_build.
+ infoArgs := []string{
+ "info",
+ "output_path",
+ }
+
+ infoCmd := Command(ctx, config, "bazel", bazelExecutable, infoArgs...)
+
+ infoCmd.Environment.Set("DIST_DIR", config.DistDir())
+ infoCmd.Environment.Set("SHELL", "/bin/bash")
+ infoCmd.Dir = filepath.Join(config.OutDir(), "..")
+ ctx.Status.Status("Getting Bazel Info..")
+ outputBasePath := string(infoCmd.OutputOrFatal())
+ // TODO: Don't hardcode out/ as the bazel output directory. This is
+ // currently hardcoded as ninja_build.output_root.
+ bazelNinjaBuildOutputRoot := filepath.Join(outputBasePath, "..", "out")
+
+ symlinkOutdir(ctx, config, bazelNinjaBuildOutputRoot, ".")
+}
+
+// For all files F recursively under rootPath/relativePath, creates symlinks
+// such that OutDir/F resolves to rootPath/F via symlinks.
+func symlinkOutdir(ctx Context, config Config, rootPath string, relativePath string) {
+ destDir := filepath.Join(rootPath, relativePath)
+ os.MkdirAll(destDir, 0755)
+ files, err := ioutil.ReadDir(destDir)
+ if err != nil {
+ ctx.Fatal(err)
+ }
+ for _, f := range files {
+ destPath := filepath.Join(destDir, f.Name())
+ srcPath := filepath.Join(config.OutDir(), relativePath, f.Name())
+ if statResult, err := os.Stat(srcPath); err == nil {
+ if statResult.Mode().IsDir() && f.IsDir() {
+ // Directory under OutDir already exists, so recurse on its contents.
+ symlinkOutdir(ctx, config, rootPath, filepath.Join(relativePath, f.Name()))
+ } else if !statResult.Mode().IsDir() && !f.IsDir() {
+ // File exists both in source and destination, and it's not a directory
+ // in either location. Do nothing.
+ // This can arise for files which are generated under OutDir outside of
+ // soong_build, such as .bootstrap files.
+ } else {
+ // File is a directory in one location but not the other. Raise an error.
+ ctx.Fatalf("Could not link %s to %s due to conflict", srcPath, destPath)
+ }
+ } else if os.IsNotExist(err) {
+ // Create symlink srcPath -> fullDestPath.
+ os.Symlink(destPath, srcPath)
+ } else {
+ ctx.Fatalf("Unable to stat %s: %s", srcPath, err)
+ }
+ }
}
diff --git a/ui/build/exec.go b/ui/build/exec.go
index 053bbae..8f92269 100644
--- a/ui/build/exec.go
+++ b/ui/build/exec.go
@@ -66,8 +66,11 @@
}
func (c *Cmd) report() {
- if c.Cmd.ProcessState != nil {
- rusage := c.Cmd.ProcessState.SysUsage().(*syscall.Rusage)
+ if state := c.Cmd.ProcessState; state != nil {
+ if c.ctx.Metrics != nil {
+ c.ctx.Metrics.EventTracer.AddProcResInfo(c.name, state)
+ }
+ rusage := state.SysUsage().(*syscall.Rusage)
c.ctx.Verbosef("%q finished with exit code %d (%s real, %s user, %s system, %dMB maxrss)",
c.name, c.Cmd.ProcessState.ExitCode(),
time.Since(c.started).Round(time.Millisecond),
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 83b3807..3164680 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -68,6 +68,12 @@
miniBootstrapDir := filepath.Join(outDir, "soong", ".minibootstrap")
modulePathsDir := filepath.Join(outDir, ".module_paths")
variablesFilePath := filepath.Join(outDir, "soong", "soong.variables")
+ // dexpreopt.config is an input to the soong_docs action, which runs the
+ // soong_build primary builder. However, this file is created from $(shell)
+ // invocation at Kati parse time, so it's not an explicit output of any
+ // Ninja action, but it is present during the build itself and can be
+ // treated as an source file.
+ dexpreoptConfigFilePath := filepath.Join(outDir, "soong", "dexpreopt.config")
danglingRules := make(map[string]bool)
@@ -81,7 +87,8 @@
if strings.HasPrefix(line, bootstrapDir) ||
strings.HasPrefix(line, miniBootstrapDir) ||
strings.HasPrefix(line, modulePathsDir) ||
- line == variablesFilePath {
+ line == variablesFilePath ||
+ line == dexpreoptConfigFilePath {
// Leaf node is in one of Soong's bootstrap directories, which do not have
// full build rules in the primary build.ninja file.
continue
diff --git a/ui/metrics/event.go b/ui/metrics/event.go
index 5a62847..6becfd1 100644
--- a/ui/metrics/event.go
+++ b/ui/metrics/event.go
@@ -15,6 +15,8 @@
package metrics
import (
+ "os"
+ "syscall"
"time"
"android/soong/ui/metrics/metrics_proto"
@@ -31,11 +33,15 @@
// the time that the event started to occur.
start time.Time
+
+ // The list of process resource information that was executed
+ procResInfo []*soong_metrics_proto.ProcessResourceInfo
}
type EventTracer interface {
Begin(name, desc string, thread tracer.Thread)
End(thread tracer.Thread) soong_metrics_proto.PerfInfo
+ AddProcResInfo(string, *os.ProcessState)
}
type eventTracerImpl struct {
@@ -48,6 +54,34 @@
return time.Now()
}
+// AddProcResInfo adds information on an executed process such as max resident set memory
+// and the number of voluntary context switches.
+func (t *eventTracerImpl) AddProcResInfo(name string, state *os.ProcessState) {
+ if len(t.activeEvents) < 1 {
+ return
+ }
+
+ rusage := state.SysUsage().(*syscall.Rusage)
+ // The implementation of the metrics system is a stacked based system. The steps of the
+ // build system in the UI layer is sequential so the Begin function is invoked when a
+ // function (or scoped code) is invoked. That is translated to a new event which is added
+ // at the end of the activeEvents array. When the invoking function is completed, End is
+ // invoked which is a pop operation from activeEvents.
+ curEvent := &t.activeEvents[len(t.activeEvents)-1]
+ curEvent.procResInfo = append(curEvent.procResInfo, &soong_metrics_proto.ProcessResourceInfo{
+ Name: proto.String(name),
+ UserTimeMicros: proto.Uint64(uint64(rusage.Utime.Usec)),
+ SystemTimeMicros: proto.Uint64(uint64(rusage.Stime.Usec)),
+ MinorPageFaults: proto.Uint64(uint64(rusage.Minflt)),
+ MajorPageFaults: proto.Uint64(uint64(rusage.Majflt)),
+ // ru_inblock and ru_oublock are measured in blocks of 512 bytes.
+ IoInputKb: proto.Uint64(uint64(rusage.Inblock / 2)),
+ IoOutputKb: proto.Uint64(uint64(rusage.Oublock / 2)),
+ VoluntaryContextSwitches: proto.Uint64(uint64(rusage.Nvcsw)),
+ InvoluntaryContextSwitches: proto.Uint64(uint64(rusage.Nivcsw)),
+ })
+}
+
func (t *eventTracerImpl) Begin(name, desc string, _ tracer.Thread) {
t.activeEvents = append(t.activeEvents, event{name: name, desc: desc, start: _now()})
}
@@ -61,9 +95,10 @@
realTime := uint64(_now().Sub(lastEvent.start).Nanoseconds())
return soong_metrics_proto.PerfInfo{
- Desc: proto.String(lastEvent.desc),
- Name: proto.String(lastEvent.name),
- StartTime: proto.Uint64(uint64(lastEvent.start.UnixNano())),
- RealTime: proto.Uint64(realTime),
+ Desc: proto.String(lastEvent.desc),
+ Name: proto.String(lastEvent.name),
+ StartTime: proto.Uint64(uint64(lastEvent.start.UnixNano())),
+ RealTime: proto.Uint64(realTime),
+ ProcessesResourceInfo: lastEvent.procResInfo,
}
}