Merge "Use packagepath and local_repository for mixed builds"
diff --git a/android/Android.bp b/android/Android.bp
index 7bd1450..c6f01fe 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -37,6 +37,7 @@
"override_module.go",
"package.go",
"package_ctx.go",
+ "packaging.go",
"path_properties.go",
"paths.go",
"phony.go",
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index a1ba8c9..7d8d12f 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -192,8 +192,7 @@
func (context *bazelContext) issueBazelCommand(command string, labels []string,
extraFlags ...string) (string, error) {
- cmdFlags := []string{"--bazelrc=build/bazel/common.bazelrc",
- "--output_base=" + context.outputBase, command}
+ cmdFlags := []string{"--output_base=" + context.outputBase, command}
cmdFlags = append(cmdFlags, labels...)
cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+context.intermediatesDir())
cmdFlags = append(cmdFlags, extraFlags...)
diff --git a/android/module.go b/android/module.go
index d677406..3cef3f5 100644
--- a/android/module.go
+++ b/android/module.go
@@ -440,6 +440,7 @@
TargetRequiredModuleNames() []string
FilesToInstall() InstallPaths
+ PackagingSpecs() []PackagingSpec
}
// Qualified id for a module
@@ -934,6 +935,7 @@
noAddressSanitizer bool
installFiles InstallPaths
checkbuildFiles Paths
+ packagingSpecs []PackagingSpec
noticeFiles Paths
phonies map[string]Paths
@@ -1259,6 +1261,10 @@
return m.installFiles
}
+func (m *ModuleBase) PackagingSpecs() []PackagingSpec {
+ return m.packagingSpecs
+}
+
func (m *ModuleBase) NoAddressSanitizer() bool {
return m.noAddressSanitizer
}
@@ -1581,6 +1587,7 @@
m.installFiles = append(m.installFiles, ctx.installFiles...)
m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...)
+ m.packagingSpecs = append(m.packagingSpecs, ctx.packagingSpecs...)
m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
for k, v := range ctx.phonies {
@@ -1748,6 +1755,7 @@
type moduleContext struct {
bp blueprint.ModuleContext
baseModuleContext
+ packagingSpecs []PackagingSpec
installDeps InstallPaths
installFiles InstallPaths
checkbuildFiles Paths
@@ -2284,16 +2292,15 @@
func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
deps ...Path) InstallPath {
- return m.installFile(installPath, name, srcPath, Cp, deps)
+ return m.installFile(installPath, name, srcPath, deps, false)
}
func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
deps ...Path) InstallPath {
- return m.installFile(installPath, name, srcPath, CpExecutable, deps)
+ return m.installFile(installPath, name, srcPath, deps, true)
}
-func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path,
- rule blueprint.Rule, deps []Path) InstallPath {
+func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []Path, executable bool) InstallPath {
fullInstallPath := installPath.Join(m, name)
m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false)
@@ -2312,6 +2319,11 @@
orderOnlyDeps = deps
}
+ rule := Cp
+ if executable {
+ rule = CpExecutable
+ }
+
m.Build(pctx, BuildParams{
Rule: rule,
Description: "install " + fullInstallPath.Base(),
@@ -2324,6 +2336,14 @@
m.installFiles = append(m.installFiles, fullInstallPath)
}
+
+ m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
+ relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
+ srcPath: srcPath,
+ symlinkTarget: "",
+ executable: executable,
+ })
+
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
return fullInstallPath
}
@@ -2332,12 +2352,12 @@
fullInstallPath := installPath.Join(m, name)
m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true)
+ relPath, err := filepath.Rel(path.Dir(fullInstallPath.String()), srcPath.String())
+ if err != nil {
+ panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err))
+ }
if !m.skipInstall(fullInstallPath) {
- relPath, err := filepath.Rel(path.Dir(fullInstallPath.String()), srcPath.String())
- if err != nil {
- panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err))
- }
m.Build(pctx, BuildParams{
Rule: Symlink,
Description: "install symlink " + fullInstallPath.Base(),
@@ -2352,6 +2372,14 @@
m.installFiles = append(m.installFiles, fullInstallPath)
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
}
+
+ m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
+ relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
+ srcPath: nil,
+ symlinkTarget: relPath,
+ executable: false,
+ })
+
return fullInstallPath
}
@@ -2374,6 +2402,14 @@
m.installFiles = append(m.installFiles, fullInstallPath)
}
+
+ m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
+ relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
+ srcPath: nil,
+ symlinkTarget: absPath,
+ executable: false,
+ })
+
return fullInstallPath
}
diff --git a/android/packaging.go b/android/packaging.go
new file mode 100644
index 0000000..8d0de9e
--- /dev/null
+++ b/android/packaging.go
@@ -0,0 +1,34 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License")
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+// PackagingSpec abstracts a request to place a built artifact at a certain path in a package.
+// A package can be the traditional <partition>.img, but isn't limited to those. Other examples could
+// be a new filesystem image that is a subset of system.img (e.g. for an Android-like mini OS running
+// on a VM), or a zip archive for some of the host tools.
+type PackagingSpec struct {
+ // Path relative to the root of the package
+ relPathInPackage string
+
+ // The path to the built artifact
+ srcPath Path
+
+ // If this is not empty, then relPathInPackage should be a symlink to this target. (Then
+ // srcPath is of course ignored.)
+ symlinkTarget string
+
+ // Whether relPathInPackage should be marked as executable or not
+ executable bool
+}
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index 739a965..4540a1f 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -214,6 +214,8 @@
"LOCAL_PRIVATE_PLATFORM_APIS": "platform_apis",
"LOCAL_JETIFIER_ENABLED": "jetifier",
+
+ "LOCAL_IS_UNIT_TEST": "unit_test",
})
}
diff --git a/bazel/bazelenv.sh b/bazel/bazelenv.sh
deleted file mode 100755
index fcf71f1..0000000
--- a/bazel/bazelenv.sh
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/bin/bash
-
-# Copyright 2020 Google Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Helper script for setting environment variables required for Bazel/Soong
-# mixed builds prototype. For development use only.
-#
-# Usage:
-# export BAZEL_PATH=[some_bazel_path] && source bazelenv.sh
-#
-# If BAZEL_PATH is not set, `which bazel` will be used
-# to locate the appropriate bazel to use.
-
-
-# Function to find top of the source tree (if $TOP isn't set) by walking up the
-# tree.
-function gettop
-{
- local TOPFILE=build/soong/root.bp
- if [ -n "${TOP-}" -a -f "${TOP-}/${TOPFILE}" ] ; then
- # The following circumlocution ensures we remove symlinks from TOP.
- (cd $TOP; PWD= /bin/pwd)
- else
- if [ -f $TOPFILE ] ; then
- # The following circumlocution (repeated below as well) ensures
- # that we record the true directory name and not one that is
- # faked up with symlink names.
- PWD= /bin/pwd
- else
- local HERE=$PWD
- T=
- while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
- \cd ..
- T=`PWD= /bin/pwd -P`
- done
- \cd $HERE
- if [ -f "$T/$TOPFILE" ]; then
- echo $T
- fi
- fi
- fi
-}
-
-BASE_DIR="$(mktemp -d)"
-
-if [ -z "$BAZEL_PATH" ] ; then
- export BAZEL_PATH="$(which bazel)"
-fi
-
-# TODO(cparsons): Use USE_BAZEL=1 instead once "mixed Soong/Bazel builds" are
-# production ready.
-export USE_BAZEL_ANALYSIS=1
-# TODO(cparsons): Retrieve this information in either envsetup.sh or
-# bazel.sh.
-export BAZEL_HOME="$BASE_DIR/bazelhome"
-export BAZEL_OUTPUT_BASE="$BASE_DIR/output"
-export BAZEL_WORKSPACE="$(gettop)"
-
-echo "USE_BAZEL_ANALYSIS=${USE_BAZEL_ANALYSIS}"
-echo "BAZEL_PATH=${BAZEL_PATH}"
-echo "BAZEL_HOME=${BAZEL_HOME}"
-echo "BAZEL_OUTPUT_BASE=${BAZEL_OUTPUT_BASE}"
-echo "BAZEL_WORKSPACE=${BAZEL_WORKSPACE}"
-
-mkdir -p $BAZEL_HOME
-mkdir -p $BAZEL_OUTPUT_BASE
diff --git a/bazel/master.WORKSPACE.bazel b/bazel/master.WORKSPACE.bazel
deleted file mode 100644
index e69de29..0000000
--- a/bazel/master.WORKSPACE.bazel
+++ /dev/null
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 38269cb..d32e4de 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -370,6 +370,9 @@
entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
}
entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", test.Properties.Test_mainline_modules...)
+ if Bool(test.Properties.Test_options.Unit_test) {
+ entries.SetBool("LOCAL_IS_UNIT_TEST", true)
+ }
})
androidMkWriteTestData(test.data, ctx, entries)
@@ -505,7 +508,7 @@
})
}
-func (c *vendorSnapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+func (c *snapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
// Each vendor snapshot is exported to androidMk only when BOARD_VNDK_VERSION != current
// and the version of the prebuilt is same as BOARD_VNDK_VERSION.
if c.shared() {
@@ -549,7 +552,7 @@
})
}
-func (c *vendorSnapshotBinaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+func (c *snapshotBinaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
entries.Class = "EXECUTABLES"
if c.androidMkVendorSuffix {
@@ -563,7 +566,7 @@
})
}
-func (c *vendorSnapshotObjectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+func (c *snapshotObjectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
entries.Class = "STATIC_LIBRARIES"
if c.androidMkVendorSuffix {
diff --git a/cc/cc.go b/cc/cc.go
index 5e4faf2..a2d6cd9 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -305,10 +305,11 @@
// Normally Soong uses the directory structure to decide which modules
// should be included (framework) or excluded (non-framework) from the
- // vendor snapshot, but this property allows a partner to exclude a
- // module normally thought of as a framework module from the vendor
- // snapshot.
- Exclude_from_vendor_snapshot *bool
+ // different snapshots (vendor, recovery, etc.), but these properties
+ // allow a partner to exclude a module normally thought of as a
+ // framework module from a snapshot.
+ Exclude_from_vendor_snapshot *bool
+ Exclude_from_recovery_snapshot *bool
}
type VendorProperties struct {
@@ -1051,6 +1052,10 @@
return Bool(c.Properties.Exclude_from_vendor_snapshot)
}
+func (c *Module) ExcludeFromRecoverySnapshot() bool {
+ return Bool(c.Properties.Exclude_from_recovery_snapshot)
+}
+
func isBionic(name string) bool {
switch name {
case "libc", "libm", "libdl", "libdl_android", "linker":
diff --git a/cc/cc_test.go b/cc/cc_test.go
index f616cf3..f5ce867 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -1551,6 +1551,8 @@
android.CheckErrorsAgainstExpectations(t, errs, []string{
`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
+ `module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
+ `module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
})
}
@@ -1597,6 +1599,132 @@
})
}
+func TestRecoverySnapshotCapture(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ recovery_available: true,
+ product_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "librecovery",
+ recovery: true,
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "librecovery_available",
+ recovery_available: true,
+ nocrt: true,
+ }
+
+ cc_library_headers {
+ name: "librecovery_headers",
+ recovery_available: true,
+ nocrt: true,
+ }
+
+ cc_binary {
+ name: "recovery_bin",
+ recovery: true,
+ nocrt: true,
+ }
+
+ cc_binary {
+ name: "recovery_available_bin",
+ recovery_available: true,
+ nocrt: true,
+ }
+
+ toolchain_library {
+ name: "libb",
+ recovery_available: true,
+ src: "libb.a",
+ }
+
+ cc_object {
+ name: "obj",
+ recovery_available: true,
+ }
+`
+ config := TestConfig(buildDir, android.Android, nil, bp, nil)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ ctx := testCcWithConfig(t, config)
+
+ // Check Recovery snapshot output.
+
+ snapshotDir := "recovery-snapshot"
+ snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+ snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
+
+ var jsonFiles []string
+
+ for _, arch := range [][]string{
+ []string{"arm64", "armv8-a"},
+ } {
+ archType := arch[0]
+ archVariant := arch[1]
+ archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+ // For shared libraries, only recovery_available modules are captured.
+ sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
+ sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+ checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", sharedDir, sharedVariant)
+ checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
+ checkSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
+ jsonFiles = append(jsonFiles,
+ filepath.Join(sharedDir, "libvndk.so.json"),
+ filepath.Join(sharedDir, "librecovery.so.json"),
+ filepath.Join(sharedDir, "librecovery_available.so.json"))
+
+ // For static libraries, all recovery:true and recovery_available modules are captured.
+ staticVariant := fmt.Sprintf("android_recovery_%s_%s_static", archType, archVariant)
+ staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
+ checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
+ checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.a", staticDir, staticVariant)
+ checkSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.a", staticDir, staticVariant)
+ jsonFiles = append(jsonFiles,
+ filepath.Join(staticDir, "libb.a.json"),
+ filepath.Join(staticDir, "librecovery.a.json"),
+ filepath.Join(staticDir, "librecovery_available.a.json"))
+
+ // For binary executables, all recovery:true and recovery_available modules are captured.
+ if archType == "arm64" {
+ binaryVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant)
+ binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
+ checkSnapshot(t, ctx, snapshotSingleton, "recovery_bin", "recovery_bin", binaryDir, binaryVariant)
+ checkSnapshot(t, ctx, snapshotSingleton, "recovery_available_bin", "recovery_available_bin", binaryDir, binaryVariant)
+ jsonFiles = append(jsonFiles,
+ filepath.Join(binaryDir, "recovery_bin.json"),
+ filepath.Join(binaryDir, "recovery_available_bin.json"))
+ }
+
+ // For header libraries, all vendor:true and vendor_available modules are captured.
+ headerDir := filepath.Join(snapshotVariantPath, archDir, "header")
+ jsonFiles = append(jsonFiles, filepath.Join(headerDir, "librecovery_headers.json"))
+
+ // For object modules, all vendor:true and vendor_available modules are captured.
+ objectVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant)
+ objectDir := filepath.Join(snapshotVariantPath, archDir, "object")
+ checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant)
+ jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json"))
+ }
+
+ for _, jsonFile := range jsonFiles {
+ // verify all json files exist
+ if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+ t.Errorf("%q expected but not found", jsonFile)
+ }
+ }
+}
+
func TestDoubleLoadableDepError(t *testing.T) {
// Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib.
testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
diff --git a/cc/compiler.go b/cc/compiler.go
index 3c86d20..04ed80d 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -687,6 +687,9 @@
// list of shared libraries that provide headers for this binding.
Shared_libs []string `android:"arch_variant"`
+ // List of libraries which export include paths required for this module
+ Header_libs []string `android:"arch_variant,variant_prepend"`
+
// list of clang flags required to correctly interpret the headers.
Cflags []string `android:"arch_variant"`
diff --git a/cc/sanitize.go b/cc/sanitize.go
index b1326d9..eb61525 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -847,7 +847,7 @@
return true
}
- if p, ok := d.linker.(*vendorSnapshotLibraryDecorator); ok {
+ if p, ok := d.linker.(*snapshotLibraryDecorator); ok {
if Bool(p.properties.Sanitize_minimal_dep) {
c.sanitize.Properties.MinimalRuntimeDep = true
}
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index 05c06ac..a3d52e6 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -60,7 +60,8 @@
func isSnapshotAware(ctx android.ModuleContext, m *Module, apexInfo android.ApexInfo) bool {
if _, _, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m, apexInfo); ok {
return ctx.Config().VndkSnapshotBuildArtifacts()
- } else if isVendorSnapshotModule(m, isVendorProprietaryPath(ctx.ModuleDir()), apexInfo) {
+ } else if isVendorSnapshotModule(m, isVendorProprietaryPath(ctx.ModuleDir()), apexInfo) ||
+ isRecoverySnapshotModule(m, isVendorProprietaryPath(ctx.ModuleDir()), apexInfo) {
return true
}
return false
diff --git a/cc/test.go b/cc/test.go
index 619dc4d..3772691 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -46,6 +46,9 @@
// a list of extra test configuration files that should be installed with the module.
Extra_test_configs []string `android:"path,arch_variant"`
+
+ // If the test is a hostside(no device required) unittest that shall be run during presubmit check.
+ Unit_test *bool
}
type TestBinaryProperties struct {
diff --git a/cc/testing.go b/cc/testing.go
index 5a311f4..7161313 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -563,6 +563,7 @@
RegisterRequiredBuildComponentsForTest(ctx)
ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
+ ctx.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton)
return ctx
}
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 78bde38..6563f6e 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -25,6 +25,115 @@
"android/soong/android"
)
+// Defines the specifics of different images to which the snapshot process is
+// applicable, e.g., vendor, recovery, ramdisk.
+type image interface {
+ // Used to register callbacks with the build system.
+ init()
+
+ // Function that returns true if the module is included in this image.
+ // Using a function return instead of a value to prevent early
+ // evalution of a function that may be not be defined.
+ inImage(m *Module) func() bool
+
+ // Returns the value of the "available" property for a given module for
+ // and snapshot, e.g., "vendor_available", "recovery_available", etc.
+ // or nil if the property is not defined.
+ available(m *Module) *bool
+
+ // Returns true if a dir under source tree is an SoC-owned proprietary
+ // directory, such as device/, vendor/, etc.
+ //
+ // For a given snapshot (e.g., vendor, recovery, etc.) if
+ // isProprietaryPath(dir) returns true, then the module in dir will be
+ // built from sources.
+ isProprietaryPath(dir string) bool
+
+ // Whether to include VNDK in the snapshot for this image.
+ includeVndk() bool
+
+ // Whether a given module has been explicitly excluded from the
+ // snapshot, e.g., using the exclude_from_vendor_snapshot or
+ // exclude_from_recovery_snapshot properties.
+ excludeFromSnapshot(m *Module) bool
+}
+
+type vendorImage struct{}
+type recoveryImage struct{}
+
+func (vendorImage) init() {
+ android.RegisterSingletonType(
+ "vendor-snapshot", VendorSnapshotSingleton)
+ android.RegisterModuleType(
+ "vendor_snapshot_shared", VendorSnapshotSharedFactory)
+ android.RegisterModuleType(
+ "vendor_snapshot_static", VendorSnapshotStaticFactory)
+ android.RegisterModuleType(
+ "vendor_snapshot_header", VendorSnapshotHeaderFactory)
+ android.RegisterModuleType(
+ "vendor_snapshot_binary", VendorSnapshotBinaryFactory)
+ android.RegisterModuleType(
+ "vendor_snapshot_object", VendorSnapshotObjectFactory)
+}
+
+func (vendorImage) inImage(m *Module) func() bool {
+ return m.inVendor
+}
+
+func (vendorImage) available(m *Module) *bool {
+ return m.VendorProperties.Vendor_available
+}
+
+func (vendorImage) isProprietaryPath(dir string) bool {
+ return isVendorProprietaryPath(dir)
+}
+
+func (vendorImage) includeVndk() bool {
+ return true
+}
+
+func (vendorImage) excludeFromSnapshot(m *Module) bool {
+ return m.ExcludeFromVendorSnapshot()
+}
+
+func (recoveryImage) init() {
+ android.RegisterSingletonType(
+ "recovery-snapshot", RecoverySnapshotSingleton)
+ android.RegisterModuleType(
+ "recovery_snapshot_shared", RecoverySnapshotSharedFactory)
+ android.RegisterModuleType(
+ "recovery_snapshot_static", RecoverySnapshotStaticFactory)
+ android.RegisterModuleType(
+ "recovery_snapshot_header", RecoverySnapshotHeaderFactory)
+ android.RegisterModuleType(
+ "recovery_snapshot_binary", RecoverySnapshotBinaryFactory)
+ android.RegisterModuleType(
+ "recovery_snapshot_object", RecoverySnapshotObjectFactory)
+}
+
+func (recoveryImage) inImage(m *Module) func() bool {
+ return m.InRecovery
+}
+
+func (recoveryImage) available(m *Module) *bool {
+ return m.Properties.Recovery_available
+}
+
+func (recoveryImage) isProprietaryPath(dir string) bool {
+ return isRecoveryProprietaryPath(dir)
+}
+
+func (recoveryImage) includeVndk() bool {
+ return false
+}
+
+func (recoveryImage) excludeFromSnapshot(m *Module) bool {
+ return m.ExcludeFromRecoverySnapshot()
+}
+
+var vendorImageSingleton vendorImage
+var recoveryImageSingleton recoveryImage
+
const (
vendorSnapshotHeaderSuffix = ".vendor_header."
vendorSnapshotSharedSuffix = ".vendor_shared."
@@ -33,6 +142,14 @@
vendorSnapshotObjectSuffix = ".vendor_object."
)
+const (
+ recoverySnapshotHeaderSuffix = ".recovery_header."
+ recoverySnapshotSharedSuffix = ".recovery_shared."
+ recoverySnapshotStaticSuffix = ".recovery_static."
+ recoverySnapshotBinarySuffix = ".recovery_binary."
+ recoverySnapshotObjectSuffix = ".recovery_object."
+)
+
var (
vendorSnapshotsLock sync.Mutex
vendorSuffixModulesKey = android.NewOnceKey("vendorSuffixModules")
@@ -136,7 +253,7 @@
}
}
-type vendorSnapshotLibraryProperties struct {
+type snapshotLibraryProperties struct {
// Prebuilt file for each arch.
Src *string `android:"arch_variant"`
@@ -161,25 +278,25 @@
setSanitizerVariation(t sanitizerType, enabled bool)
}
-type vendorSnapshotLibraryDecorator struct {
+type snapshotLibraryDecorator struct {
vendorSnapshotModuleBase
*libraryDecorator
- properties vendorSnapshotLibraryProperties
+ properties snapshotLibraryProperties
sanitizerProperties struct {
CfiEnabled bool `blueprint:"mutated"`
// Library flags for cfi variant.
- Cfi vendorSnapshotLibraryProperties `android:"arch_variant"`
+ Cfi snapshotLibraryProperties `android:"arch_variant"`
}
androidMkVendorSuffix bool
}
-func (p *vendorSnapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+func (p *snapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), p.NameSuffix())
return p.libraryDecorator.linkerFlags(ctx, flags)
}
-func (p *vendorSnapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
+func (p *snapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
arches := config.Arches()
if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
return false
@@ -190,7 +307,7 @@
return true
}
-func (p *vendorSnapshotLibraryDecorator) link(ctx ModuleContext,
+func (p *snapshotLibraryDecorator) link(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
m := ctx.Module().(*Module)
p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
@@ -246,17 +363,17 @@
return in
}
-func (p *vendorSnapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) {
+func (p *snapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) {
if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) {
p.baseInstaller.install(ctx, file)
}
}
-func (p *vendorSnapshotLibraryDecorator) nativeCoverage() bool {
+func (p *snapshotLibraryDecorator) nativeCoverage() bool {
return false
}
-func (p *vendorSnapshotLibraryDecorator) isSanitizerEnabled(t sanitizerType) bool {
+func (p *snapshotLibraryDecorator) isSanitizerEnabled(t sanitizerType) bool {
switch t {
case cfi:
return p.sanitizerProperties.Cfi.Src != nil
@@ -265,7 +382,7 @@
}
}
-func (p *vendorSnapshotLibraryDecorator) setSanitizerVariation(t sanitizerType, enabled bool) {
+func (p *snapshotLibraryDecorator) setSanitizerVariation(t sanitizerType, enabled bool) {
if !enabled {
return
}
@@ -277,14 +394,14 @@
}
}
-func vendorSnapshotLibrary(suffix string) (*Module, *vendorSnapshotLibraryDecorator) {
+func snapshotLibrary(suffix string) (*Module, *snapshotLibraryDecorator) {
module, library := NewLibrary(android.DeviceSupported)
module.stl = nil
module.sanitize = nil
library.disableStripping()
- prebuilt := &vendorSnapshotLibraryDecorator{
+ prebuilt := &snapshotLibraryDecorator{
libraryDecorator: library,
}
@@ -310,38 +427,56 @@
}
func VendorSnapshotSharedFactory() android.Module {
- module, prebuilt := vendorSnapshotLibrary(vendorSnapshotSharedSuffix)
+ module, prebuilt := snapshotLibrary(vendorSnapshotSharedSuffix)
+ prebuilt.libraryDecorator.BuildOnlyShared()
+ return module.Init()
+}
+
+func RecoverySnapshotSharedFactory() android.Module {
+ module, prebuilt := snapshotLibrary(recoverySnapshotSharedSuffix)
prebuilt.libraryDecorator.BuildOnlyShared()
return module.Init()
}
func VendorSnapshotStaticFactory() android.Module {
- module, prebuilt := vendorSnapshotLibrary(vendorSnapshotStaticSuffix)
+ module, prebuilt := snapshotLibrary(vendorSnapshotStaticSuffix)
+ prebuilt.libraryDecorator.BuildOnlyStatic()
+ return module.Init()
+}
+
+func RecoverySnapshotStaticFactory() android.Module {
+ module, prebuilt := snapshotLibrary(recoverySnapshotStaticSuffix)
prebuilt.libraryDecorator.BuildOnlyStatic()
return module.Init()
}
func VendorSnapshotHeaderFactory() android.Module {
- module, prebuilt := vendorSnapshotLibrary(vendorSnapshotHeaderSuffix)
+ module, prebuilt := snapshotLibrary(vendorSnapshotHeaderSuffix)
prebuilt.libraryDecorator.HeaderOnly()
return module.Init()
}
-var _ snapshotSanitizer = (*vendorSnapshotLibraryDecorator)(nil)
+func RecoverySnapshotHeaderFactory() android.Module {
+ module, prebuilt := snapshotLibrary(recoverySnapshotHeaderSuffix)
+ prebuilt.libraryDecorator.HeaderOnly()
+ return module.Init()
+}
-type vendorSnapshotBinaryProperties struct {
+var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
+
+type snapshotBinaryProperties struct {
// Prebuilt file for each arch.
Src *string `android:"arch_variant"`
}
-type vendorSnapshotBinaryDecorator struct {
+type snapshotBinaryDecorator struct {
vendorSnapshotModuleBase
*binaryDecorator
- properties vendorSnapshotBinaryProperties
+ properties snapshotBinaryProperties
androidMkVendorSuffix bool
}
-func (p *vendorSnapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
+func (p *snapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
if config.DeviceArch() != p.arch() {
return false
}
@@ -351,7 +486,7 @@
return true
}
-func (p *vendorSnapshotBinaryDecorator) link(ctx ModuleContext,
+func (p *snapshotBinaryDecorator) link(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
if !p.matchesWithDevice(ctx.DeviceConfig()) {
return nil
@@ -382,11 +517,19 @@
return outputFile
}
-func (p *vendorSnapshotBinaryDecorator) nativeCoverage() bool {
+func (p *snapshotBinaryDecorator) nativeCoverage() bool {
return false
}
func VendorSnapshotBinaryFactory() android.Module {
+ return snapshotBinaryFactory(vendorSnapshotBinarySuffix)
+}
+
+func RecoverySnapshotBinaryFactory() android.Module {
+ return snapshotBinaryFactory(recoverySnapshotBinarySuffix)
+}
+
+func snapshotBinaryFactory(suffix string) android.Module {
module, binary := NewBinary(android.DeviceSupported)
binary.baseLinker.Properties.No_libcrt = BoolPtr(true)
binary.baseLinker.Properties.Nocrt = BoolPtr(true)
@@ -396,7 +539,7 @@
binary.baseLinker.Properties.System_shared_libs = []string{}
}
- prebuilt := &vendorSnapshotBinaryDecorator{
+ prebuilt := &snapshotBinaryDecorator{
binaryDecorator: binary,
}
@@ -405,7 +548,7 @@
module.stl = nil
module.linker = prebuilt
- prebuilt.init(module, vendorSnapshotBinarySuffix)
+ prebuilt.init(module, suffix)
module.AddProperties(&prebuilt.properties)
return module.Init()
}
@@ -415,14 +558,14 @@
Src *string `android:"arch_variant"`
}
-type vendorSnapshotObjectLinker struct {
+type snapshotObjectLinker struct {
vendorSnapshotModuleBase
objectLinker
properties vendorSnapshotObjectProperties
androidMkVendorSuffix bool
}
-func (p *vendorSnapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool {
+func (p *snapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool {
if config.DeviceArch() != p.arch() {
return false
}
@@ -432,7 +575,7 @@
return true
}
-func (p *vendorSnapshotObjectLinker) link(ctx ModuleContext,
+func (p *snapshotObjectLinker) link(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
if !p.matchesWithDevice(ctx.DeviceConfig()) {
return nil
@@ -444,14 +587,14 @@
return android.PathForModuleSrc(ctx, *p.properties.Src)
}
-func (p *vendorSnapshotObjectLinker) nativeCoverage() bool {
+func (p *snapshotObjectLinker) nativeCoverage() bool {
return false
}
func VendorSnapshotObjectFactory() android.Module {
module := newObject()
- prebuilt := &vendorSnapshotObjectLinker{
+ prebuilt := &snapshotObjectLinker{
objectLinker: objectLinker{
baseLinker: NewBaseLinker(nil),
},
@@ -463,21 +606,68 @@
return module.Init()
}
+func RecoverySnapshotObjectFactory() android.Module {
+ module := newObject()
+
+ prebuilt := &snapshotObjectLinker{
+ objectLinker: objectLinker{
+ baseLinker: NewBaseLinker(nil),
+ },
+ }
+ module.linker = prebuilt
+
+ prebuilt.init(module, recoverySnapshotObjectSuffix)
+ module.AddProperties(&prebuilt.properties)
+ return module.Init()
+}
+
func init() {
- android.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
- android.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory)
- android.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory)
- android.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory)
- android.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory)
- android.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory)
+ vendorImageSingleton.init()
+ recoveryImageSingleton.init()
+}
+
+var vendorSnapshotSingleton = snapshotSingleton{
+ "vendor",
+ "SOONG_VENDOR_SNAPSHOT_ZIP",
+ android.OptionalPath{},
+ true,
+ vendorImageSingleton,
+}
+
+var recoverySnapshotSingleton = snapshotSingleton{
+ "recovery",
+ "SOONG_RECOVERY_SNAPSHOT_ZIP",
+ android.OptionalPath{},
+ false,
+ recoveryImageSingleton,
}
func VendorSnapshotSingleton() android.Singleton {
- return &vendorSnapshotSingleton{}
+ return &vendorSnapshotSingleton
}
-type vendorSnapshotSingleton struct {
- vendorSnapshotZipFile android.OptionalPath
+func RecoverySnapshotSingleton() android.Singleton {
+ return &recoverySnapshotSingleton
+}
+
+type snapshotSingleton struct {
+ // Name, e.g., "vendor", "recovery", "ramdisk".
+ name string
+
+ // Make variable that points to the snapshot file, e.g.,
+ // "SOONG_RECOVERY_SNAPSHOT_ZIP".
+ makeVar string
+
+ // Path to the snapshot zip file.
+ snapshotZipFile android.OptionalPath
+
+ // Whether the image supports VNDK extension modules.
+ supportsVndkExt bool
+
+ // Implementation of the image interface specific to the image
+ // associated with this snapshot (e.g., specific to the vendor image,
+ // recovery image, etc.).
+ image image
}
var (
@@ -491,6 +681,17 @@
"hardware",
}
+ // Modules under following directories are ignored. They are OEM's and vendor's
+ // proprietary modules(device/, kernel/, vendor/, and hardware/).
+ // TODO(b/65377115): Clean up these with more maintainable way
+ recoveryProprietaryDirs = []string{
+ "bootable/recovery",
+ "device",
+ "hardware",
+ "kernel",
+ "vendor",
+ }
+
// Modules under following directories are included as they are in AOSP,
// although hardware/ and kernel/ are normally for vendor's own.
// TODO(b/65377115): Clean up these with more maintainable way
@@ -508,7 +709,17 @@
// Determine if a dir under source tree is an SoC-owned proprietary directory, such as
// device/, vendor/, etc.
func isVendorProprietaryPath(dir string) bool {
- for _, p := range vendorProprietaryDirs {
+ return isProprietaryPath(dir, vendorProprietaryDirs)
+}
+
+func isRecoveryProprietaryPath(dir string) bool {
+ return isProprietaryPath(dir, recoveryProprietaryDirs)
+}
+
+// Determine if a dir under source tree is an SoC-owned proprietary directory, such as
+// device/, vendor/, etc.
+func isProprietaryPath(dir string, proprietaryDirs []string) bool {
+ for _, p := range proprietaryDirs {
if strings.HasPrefix(dir, p) {
// filter out AOSP defined directories, e.g. hardware/interfaces/
aosp := false
@@ -556,6 +767,14 @@
// depend on newer VNDK) So they are captured as vendor snapshot To build older vendor
// image and newer system image altogether.
func isVendorSnapshotModule(m *Module, inVendorProprietaryPath bool, apexInfo android.ApexInfo) bool {
+ return isSnapshotModule(m, inVendorProprietaryPath, apexInfo, vendorImageSingleton)
+}
+
+func isRecoverySnapshotModule(m *Module, inRecoveryProprietaryPath bool, apexInfo android.ApexInfo) bool {
+ return isSnapshotModule(m, inRecoveryProprietaryPath, apexInfo, recoveryImageSingleton)
+}
+
+func isSnapshotModule(m *Module, inProprietaryPath bool, apexInfo android.ApexInfo, image image) bool {
if !m.Enabled() || m.Properties.HideFromMake {
return false
}
@@ -564,8 +783,9 @@
if m.IsSkipInstall() {
return false
}
- // skip proprietary modules, but include all VNDK (static)
- if inVendorProprietaryPath && !m.IsVndk() {
+ // skip proprietary modules, but (for the vendor snapshot only)
+ // include all VNDK (static)
+ if inProprietaryPath && (!image.includeVndk() || !m.IsVndk()) {
return false
}
// If the module would be included based on its path, check to see if
@@ -580,7 +800,7 @@
return false
}
// the module must be installed in /vendor
- if !apexInfo.IsForPlatform() || m.isSnapshotPrebuilt() || !m.inVendor() {
+ if !apexInfo.IsForPlatform() || m.isSnapshotPrebuilt() || !image.inImage(m)() {
return false
}
// skip kernel_headers which always depend on vendor
@@ -612,29 +832,31 @@
}
}
if l.static() {
- return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
+ return m.outputFile.Valid() && proptools.BoolDefault(image.available(m), true)
}
if l.shared() {
if !m.outputFile.Valid() {
return false
}
- if !m.IsVndk() {
- return true
+ if image.includeVndk() {
+ if !m.IsVndk() {
+ return true
+ }
+ return m.isVndkExt()
}
- return m.isVndkExt()
}
return true
}
// Binaries and Objects
if m.binary() || m.object() {
- return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
+ return m.outputFile.Valid() && proptools.BoolDefault(image.available(m), true)
}
return false
}
-func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
// BOARD_VNDK_VERSION must be set to 'current' in order to generate a vendor snapshot.
if ctx.DeviceConfig().VndkVersion() != "current" {
return
@@ -675,7 +897,7 @@
(header files of same directory structure with source tree)
*/
- snapshotDir := "vendor-snapshot"
+ snapshotDir := c.name + "-snapshot"
snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
includeDir := filepath.Join(snapshotArchDir, "include")
@@ -722,7 +944,7 @@
// Common properties among snapshots.
prop.ModuleName = ctx.ModuleName(m)
- if m.isVndkExt() {
+ if c.supportsVndkExt && m.isVndkExt() {
// vndk exts are installed to /vendor/lib(64)?/vndk(-sp)?
if m.isVndkSp() {
prop.RelativeInstallPath = "vndk-sp"
@@ -843,26 +1065,30 @@
}
moduleDir := ctx.ModuleDir(module)
- inVendorProprietaryPath := isVendorProprietaryPath(moduleDir)
+ inProprietaryPath := c.image.isProprietaryPath(moduleDir)
apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
if m.ExcludeFromVendorSnapshot() {
- if inVendorProprietaryPath {
+ if inProprietaryPath {
// Error: exclude_from_vendor_snapshot applies
// to framework-path modules only.
ctx.Errorf("module %q in vendor proprietary path %q may not use \"exclude_from_vendor_snapshot: true\"", m.String(), moduleDir)
return
}
- if Bool(m.VendorProperties.Vendor_available) {
+ if Bool(c.image.available(m)) {
// Error: may not combine "vendor_available:
// true" with "exclude_from_vendor_snapshot:
// true".
- ctx.Errorf("module %q may not use both \"vendor_available: true\" and \"exclude_from_vendor_snapshot: true\"", m.String())
+ ctx.Errorf(
+ "module %q may not use both \""+
+ c.name+
+ "_available: true\" and \"exclude_from_vendor_snapshot: true\"",
+ m.String())
return
}
}
- if !isVendorSnapshotModule(m, inVendorProprietaryPath, apexInfo) {
+ if !isSnapshotModule(m, inProprietaryPath, apexInfo, c.image) {
return
}
@@ -894,11 +1120,17 @@
return snapshotOutputs[i].String() < snapshotOutputs[j].String()
})
- zipPath := android.PathForOutput(ctx, snapshotDir, "vendor-"+ctx.Config().DeviceName()+".zip")
+ zipPath := android.PathForOutput(
+ ctx,
+ snapshotDir,
+ c.name+"-"+ctx.Config().DeviceName()+".zip")
zipRule := android.NewRuleBuilder()
// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr
- snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "vendor-"+ctx.Config().DeviceName()+"_list")
+ snapshotOutputList := android.PathForOutput(
+ ctx,
+ snapshotDir,
+ c.name+"-"+ctx.Config().DeviceName()+"_list")
zipRule.Command().
Text("tr").
FlagWithArg("-d ", "\\'").
@@ -913,13 +1145,15 @@
FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
FlagWithInput("-l ", snapshotOutputList)
- zipRule.Build(pctx, ctx, zipPath.String(), "vendor snapshot "+zipPath.String())
+ zipRule.Build(pctx, ctx, zipPath.String(), c.name+" snapshot "+zipPath.String())
zipRule.DeleteTemporaryFiles()
- c.vendorSnapshotZipFile = android.OptionalPathForPath(zipPath)
+ c.snapshotZipFile = android.OptionalPathForPath(zipPath)
}
-func (c *vendorSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
- ctx.Strict("SOONG_VENDOR_SNAPSHOT_ZIP", c.vendorSnapshotZipFile.String())
+func (c *snapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
+ ctx.Strict(
+ c.makeVar,
+ c.snapshotZipFile.String())
}
type snapshotInterface interface {
@@ -927,9 +1161,9 @@
}
var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil)
-var _ snapshotInterface = (*vendorSnapshotLibraryDecorator)(nil)
-var _ snapshotInterface = (*vendorSnapshotBinaryDecorator)(nil)
-var _ snapshotInterface = (*vendorSnapshotObjectLinker)(nil)
+var _ snapshotInterface = (*snapshotLibraryDecorator)(nil)
+var _ snapshotInterface = (*snapshotBinaryDecorator)(nil)
+var _ snapshotInterface = (*snapshotObjectLinker)(nil)
// gathers all snapshot modules for vendor, and disable unnecessary snapshots
// TODO(b/145966707): remove mutator and utilize android.Prebuilt to override source modules
@@ -970,9 +1204,9 @@
// header
snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
}
- } else if _, ok := module.linker.(*vendorSnapshotBinaryDecorator); ok {
+ } else if _, ok := module.linker.(*snapshotBinaryDecorator); ok {
snapshotMap = vendorSnapshotBinaries(ctx.Config())
- } else if _, ok := module.linker.(*vendorSnapshotObjectLinker); ok {
+ } else if _, ok := module.linker.(*snapshotObjectLinker); ok {
snapshotMap = vendorSnapshotObjects(ctx.Config())
} else {
return
diff --git a/java/androidmk.go b/java/androidmk.go
index f263cb8..386a97f 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -160,6 +160,9 @@
entries.SetString("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", "true")
}
entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", j.testProperties.Test_mainline_modules...)
+ if Bool(j.testProperties.Test_options.Unit_test) {
+ entries.SetBool("LOCAL_IS_UNIT_TEST", true)
+ }
})
return entriesList
diff --git a/java/java.go b/java/java.go
index 5ded041..a23c649 100644
--- a/java/java.go
+++ b/java/java.go
@@ -2226,6 +2226,9 @@
type TestOptions struct {
// a list of extra test configuration files that should be installed with the module.
Extra_test_configs []string `android:"path,arch_variant"`
+
+ // If the test is a hostside(no device required) unittest that shall be run during presubmit check.
+ Unit_test *bool
}
type testProperties struct {
diff --git a/python/androidmk.go b/python/androidmk.go
index 8ad5889..040b6be 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -80,6 +80,10 @@
fmt.Fprintln(w, "LOCAL_TEST_DATA :=",
strings.Join(android.AndroidMkDataPaths(p.data), " "))
}
+
+ if Bool(p.testProperties.Test_options.Unit_test) {
+ fmt.Fprintln(w, "LOCAL_IS_UNIT_TEST := true")
+ }
})
base.subAndroidMk(ret, p.binaryDecorator.pythonInstaller)
}
diff --git a/python/test.go b/python/test.go
index 434e71a..f9baa46 100644
--- a/python/test.go
+++ b/python/test.go
@@ -26,6 +26,12 @@
android.RegisterModuleType("python_test", PythonTestFactory)
}
+// Test option struct.
+type TestOptions struct {
+ // If the test is a hostside(no device required) unittest that shall be run during presubmit check.
+ Unit_test *bool
+}
+
type TestProperties struct {
// the name of the test configuration (for example "AndroidTest.xml") that should be
// installed with the module.
@@ -38,6 +44,9 @@
// list of files or filegroup modules that provide data that should be installed alongside
// the test
Data []string `android:"path,arch_variant"`
+
+ // Test options.
+ Test_options TestOptions
}
type testDecorator struct {
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 29e4bd7..f98360a 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -116,6 +116,9 @@
if !BoolDefault(test.Properties.Auto_gen_config, true) {
fmt.Fprintln(w, "LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true")
}
+ if Bool(test.Properties.Test_options.Unit_test) {
+ fmt.Fprintln(w, "LOCAL_IS_UNIT_TEST := true")
+ }
})
// TODO(chh): add test data with androidMkWriteTestData(test.data, ctx, ret)
}
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 7cc0fc8..35a807b 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -258,5 +258,6 @@
deps.SharedLibs = append(deps.SharedLibs, b.ClangProperties.Shared_libs...)
deps.StaticLibs = append(deps.StaticLibs, b.ClangProperties.Static_libs...)
+ deps.HeaderLibs = append(deps.StaticLibs, b.ClangProperties.Header_libs...)
return deps
}
diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go
index c7ce42b..af04cfc 100644
--- a/rust/bindgen_test.go
+++ b/rust/bindgen_test.go
@@ -32,6 +32,7 @@
cflags: ["--clang-flag()"],
shared_libs: ["libfoo_shared"],
static_libs: ["libfoo_static"],
+ header_libs: ["libfoo_header"],
}
cc_library_shared {
name: "libfoo_shared",
@@ -41,6 +42,10 @@
name: "libfoo_static",
export_include_dirs: ["static_include"],
}
+ cc_library_headers {
+ name: "libfoo_header",
+ export_include_dirs: ["header_include"],
+ }
cc_defaults {
name: "cc_defaults_flags",
cflags: ["--default-flag"],
@@ -60,6 +65,9 @@
if !strings.Contains(libbindgen.Args["cflags"], "-Istatic_include") {
t.Errorf("missing static_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
}
+ if !strings.Contains(libbindgen.Args["cflags"], "-Iheader_include") {
+ t.Errorf("missing static_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
+ }
if !strings.Contains(libbindgen.Args["cflags"], "--default-flag") {
t.Errorf("rust_bindgen missing cflags defined in cc_defaults: cflags %#v", libbindgen.Args["cflags"])
}
diff --git a/rust/protobuf.go b/rust/protobuf.go
index 76fed30..7d6e1fd 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -53,7 +53,7 @@
Proto_flags []string `android:"arch_variant"`
// List of libraries which export include paths required for this module
- Header_libs []string `android:"arch_variant"`
+ Header_libs []string `android:"arch_variant,variant_prepend"`
}
type protobufDecorator struct {
diff --git a/rust/test.go b/rust/test.go
index bc7f53c..408e03a 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -19,6 +19,12 @@
"android/soong/tradefed"
)
+// Test option struct.
+type TestOptions struct {
+ // If the test is a hostside(no device required) unittest that shall be run during presubmit check.
+ Unit_test *bool
+}
+
type TestProperties 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
@@ -44,6 +50,9 @@
// if set, build with the standard Rust test harness. Defaults to true.
Test_harness *bool
+
+ // Test options.
+ Test_options TestOptions
}
// A test module is a binary module with extra --test compiler flag
diff --git a/ui/build/bazel.go b/ui/build/bazel.go
index 7cc7caf..2d36f67 100644
--- a/ui/build/bazel.go
+++ b/ui/build/bazel.go
@@ -24,8 +24,8 @@
"android/soong/ui/metrics"
)
-// Main entry point to construct the Bazel build command line, environment variables
-// and post-processing steps (e.g. converge output directories)
+// Main entry point to construct the Bazel build command line, environment
+// variables and post-processing steps (e.g. converge output directories)
func runBazel(ctx Context, config Config) {
ctx.BeginTrace(metrics.RunBazel, "bazel")
defer ctx.EndTrace()
@@ -41,53 +41,86 @@
outputGroups = strings.Join(config.ninjaArgs, ",")
}
+ // Environment variables are the primary mechanism to pass information from
+ // soong_ui configuration or context to Bazel.
+ //
+ // Use *_NINJA variables to pass the root-relative path of the combined,
+ // kati-generated, soong-generated, and packaging Ninja files to Bazel.
+ // Bazel reads these from the lunch() repository rule.
config.environ.Set("COMBINED_NINJA", config.CombinedNinjaFile())
config.environ.Set("KATI_NINJA", config.KatiBuildNinjaFile())
config.environ.Set("PACKAGE_NINJA", config.KatiPackageNinjaFile())
config.environ.Set("SOONG_NINJA", config.SoongNinjaFile())
+ // `tools/bazel` is the default entry point for executing Bazel in the AOSP
+ // source tree.
bazelExecutable := filepath.Join("tools", "bazel")
cmd := Command(ctx, config, "bazel", bazelExecutable)
- if extra_startup_args, ok := cmd.Environment.Get("BAZEL_STARTUP_ARGS"); ok {
- cmd.Args = append(cmd.Args, strings.Fields(extra_startup_args)...)
+ // Append custom startup flags to the Bazel command. Startup flags affect
+ // the Bazel server itself, and any changes to these flags would incur a
+ // restart of the server, losing much of the in-memory incrementality.
+ if extraStartupArgs, ok := cmd.Environment.Get("BAZEL_STARTUP_ARGS"); ok {
+ cmd.Args = append(cmd.Args, strings.Fields(extraStartupArgs)...)
}
+ // Start constructing the `build` command.
actionName := "build"
cmd.Args = append(cmd.Args,
actionName,
+ // Use output_groups to select the set of outputs to produce from a
+ // ninja_build target.
"--output_groups="+outputGroups,
+ // Generate a performance profile
"--profile="+filepath.Join(shared.BazelMetricsFilename(config.OutDir(), actionName)),
"--slim_profile=true",
)
- if extra_build_args, ok := cmd.Environment.Get("BAZEL_BUILD_ARGS"); ok {
- cmd.Args = append(cmd.Args, strings.Fields(extra_build_args)...)
+ // Append custom build flags to the Bazel command. Changes to these flags
+ // may invalidate Bazel's analysis cache.
+ if extraBuildArgs, ok := cmd.Environment.Get("BAZEL_BUILD_ARGS"); ok {
+ cmd.Args = append(cmd.Args, strings.Fields(extraBuildArgs)...)
}
+ // Append the label of the default ninja_build target.
cmd.Args = append(cmd.Args,
"//:"+config.TargetProduct()+"-"+config.TargetBuildVariant(),
)
+ // Ensure that the PATH environment variable value used in the action
+ // environment is the restricted set computed from soong_ui, and not a
+ // user-provided one, for hermeticity reasons.
if pathEnvValue, ok := config.environ.Get("PATH"); ok {
cmd.Environment.Set("PATH", pathEnvValue)
cmd.Args = append(cmd.Args, "--action_env=PATH="+pathEnvValue)
}
+
cmd.Environment.Set("DIST_DIR", config.DistDir())
cmd.Environment.Set("SHELL", "/bin/bash")
+ // Print the full command line for debugging purposes.
ctx.Println(cmd.Cmd)
+
+ // Execute the command at the root of the directory.
cmd.Dir = filepath.Join(config.OutDir(), "..")
ctx.Status.Status("Starting Bazel..")
+
+ // Execute the build command.
cmd.RunAndStreamOrFatal()
+ // Post-processing steps start here. Once the Bazel build completes, the
+ // output files are still stored in the execution root, not in $OUT_DIR.
+ // Ensure that the $OUT_DIR contains the expected set of files by symlinking
+ // the files from the execution root's output direction into $OUT_DIR.
+
// Obtain the Bazel output directory for ninja_build.
infoCmd := Command(ctx, config, "bazel", bazelExecutable)
- if extra_startup_args, ok := infoCmd.Environment.Get("BAZEL_STARTUP_ARGS"); ok {
- infoCmd.Args = append(infoCmd.Args, strings.Fields(extra_startup_args)...)
+ if extraStartupArgs, ok := infoCmd.Environment.Get("BAZEL_STARTUP_ARGS"); ok {
+ infoCmd.Args = append(infoCmd.Args, strings.Fields(extraStartupArgs)...)
}
+ // Obtain the output directory path in the execution root.
infoCmd.Args = append(infoCmd.Args,
"info",
"output_path",
diff --git a/ui/build/config.go b/ui/build/config.go
index 641aae6..229bd5c 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -703,6 +703,10 @@
return c.ninjaArgs
}
+func (c *configImpl) BazelOutDir() string {
+ return filepath.Join(c.OutDir(), "bazel")
+}
+
func (c *configImpl) SoongOutDir() string {
return filepath.Join(c.OutDir(), "soong")
}
diff --git a/ui/build/finder.go b/ui/build/finder.go
index 7a85657..2eb84ca 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -27,8 +27,10 @@
"android/soong/ui/metrics"
)
-// This file provides an interface to the Finder for use in Soong UI
-// This file stores configuration information about which files to find
+// This file provides an interface to the Finder type for soong_ui. Finder is
+// used to recursively traverse the source tree to gather paths of files, such
+// as Android.bp or Android.mk, and store the lists/database of paths in files
+// under `$OUT_DIR/.module_paths`. This directory can also be dist'd.
// NewSourceFinder returns a new Finder configured to search for source files.
// Callers of NewSourceFinder should call <f.Shutdown()> when done
@@ -36,14 +38,18 @@
ctx.BeginTrace(metrics.RunSetupTool, "find modules")
defer ctx.EndTrace()
+ // Set up the working directory for the Finder.
dir, err := os.Getwd()
if err != nil {
ctx.Fatalf("No working directory for module-finder: %v", err.Error())
}
filesystem := fs.OsFs
- // if the root dir is ignored, then the subsequent error messages are very confusing,
- // so check for that upfront
+ // .out-dir and .find-ignore are markers for Finder to ignore siblings and
+ // subdirectories of the directory Finder finds them in, hence stopping the
+ // search recursively down those branches. It's possible that these files
+ // are in the root directory, and if they are, then the subsequent error
+ // messages are very confusing, so check for that here.
pruneFiles := []string{".out-dir", ".find-ignore"}
for _, name := range pruneFiles {
prunePath := filepath.Join(dir, name)
@@ -53,22 +59,34 @@
}
}
+ // Set up configuration parameters for the Finder cache.
cacheParams := finder.CacheParams{
WorkingDirectory: dir,
RootDirs: []string{"."},
ExcludeDirs: []string{".git", ".repo"},
PruneFiles: pruneFiles,
IncludeFiles: []string{
+ // Kati build definitions.
"Android.mk",
+ // Product configuration files.
"AndroidProducts.mk",
+ // General Soong build definitions, using the Blueprint syntax.
"Android.bp",
+ // build/blueprint build definitions, using the Blueprint syntax.
"Blueprints",
+ // Bazel build definitions.
"BUILD.bazel",
+ // Kati clean definitions.
"CleanSpec.mk",
+ // Ownership definition.
"OWNERS",
+ // Test configuration for modules in directories that contain this
+ // file.
"TEST_MAPPING",
+ // Bazel top-level file to mark a directory as a Bazel workspace.
"WORKSPACE",
},
+ // Bazel Starlark configuration files.
IncludeSuffixes: []string{".bzl"},
}
dumpDir := config.FileListDir()
@@ -80,6 +98,7 @@
return f
}
+// Finds the list of Bazel-related files (BUILD, WORKSPACE and Starlark) in the tree.
func findBazelFiles(entries finder.DirEntries) (dirNames []string, fileNames []string) {
matches := []string{}
for _, foundName := range entries.FileNames {
@@ -98,12 +117,21 @@
dumpDir := config.FileListDir()
os.MkdirAll(dumpDir, 0777)
+ // Stop searching a subdirectory recursively after finding an Android.mk.
androidMks := f.FindFirstNamedAt(".", "Android.mk")
err := dumpListToFile(ctx, config, androidMks, filepath.Join(dumpDir, "Android.mk.list"))
if err != nil {
ctx.Fatalf("Could not export module list: %v", err)
}
+ // Stop searching a subdirectory recursively after finding a CleanSpec.mk.
+ cleanSpecs := f.FindFirstNamedAt(".", "CleanSpec.mk")
+ err = dumpListToFile(ctx, config, cleanSpecs, filepath.Join(dumpDir, "CleanSpec.mk.list"))
+ if err != nil {
+ ctx.Fatalf("Could not export module list: %v", err)
+ }
+
+ // Only consider AndroidProducts.mk in device/, vendor/ and product/, recursively in these directories.
androidProductsMks := f.FindNamedAt("device", "AndroidProducts.mk")
androidProductsMks = append(androidProductsMks, f.FindNamedAt("vendor", "AndroidProducts.mk")...)
androidProductsMks = append(androidProductsMks, f.FindNamedAt("product", "AndroidProducts.mk")...)
@@ -112,31 +140,30 @@
ctx.Fatalf("Could not export product list: %v", err)
}
+ // Recursively look for all Bazel related files.
bazelFiles := f.FindMatching(".", findBazelFiles)
err = dumpListToFile(ctx, config, bazelFiles, filepath.Join(dumpDir, "bazel.list"))
if err != nil {
ctx.Fatalf("Could not export bazel BUILD list: %v", err)
}
- cleanSpecs := f.FindFirstNamedAt(".", "CleanSpec.mk")
- err = dumpListToFile(ctx, config, cleanSpecs, filepath.Join(dumpDir, "CleanSpec.mk.list"))
- if err != nil {
- ctx.Fatalf("Could not export module list: %v", err)
- }
-
+ // Recursively look for all OWNERS files.
owners := f.FindNamedAt(".", "OWNERS")
err = dumpListToFile(ctx, config, owners, filepath.Join(dumpDir, "OWNERS.list"))
if err != nil {
ctx.Fatalf("Could not find OWNERS: %v", err)
}
+ // Recursively look for all TEST_MAPPING files.
testMappings := f.FindNamedAt(".", "TEST_MAPPING")
err = dumpListToFile(ctx, config, testMappings, filepath.Join(dumpDir, "TEST_MAPPING.list"))
if err != nil {
ctx.Fatalf("Could not find TEST_MAPPING: %v", err)
}
+ // Recursively look for all Android.bp files
androidBps := f.FindNamedAt(".", "Android.bp")
+ // The files are named "Blueprints" only in the build/blueprint directory.
androidBps = append(androidBps, f.FindNamedAt("build/blueprint", "Blueprints")...)
if len(androidBps) == 0 {
ctx.Fatalf("No Android.bp found")
@@ -148,10 +175,12 @@
if config.Dist() {
f.WaitForDbDump()
+ // Dist the files.db plain text database.
distFile(ctx, config, f.DbPath, "module_paths")
}
}
+// Write the .list files to disk.
func dumpListToFile(ctx Context, config Config, list []string, filePath string) (err error) {
desiredText := strings.Join(list, "\n")
desiredBytes := []byte(desiredText)
diff --git a/ui/build/soong.go b/ui/build/soong.go
index b20237c..bb5cbf0 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -133,6 +133,13 @@
"-j", strconv.Itoa(config.Parallel()),
"--frontend_file", fifo,
"-f", filepath.Join(config.SoongOutDir(), file))
+
+ // For Bazel mixed builds.
+ cmd.Environment.Set("BAZEL_PATH", "./tools/bazel")
+ cmd.Environment.Set("BAZEL_HOME", filepath.Join(config.BazelOutDir(), "bazelhome"))
+ cmd.Environment.Set("BAZEL_OUTPUT_BASE", filepath.Join(config.BazelOutDir(), "output"))
+ cmd.Environment.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
+
cmd.Environment.Set("SOONG_SANDBOX_SOONG_BUILD", "true")
cmd.Sandbox = soongSandbox
cmd.RunAndStreamOrFatal()
diff --git a/zip/cmd/main.go b/zip/cmd/main.go
index d603586..fc976f6 100644
--- a/zip/cmd/main.go
+++ b/zip/cmd/main.go
@@ -12,6 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// soong_zip is a utility used during the build to create a zip archive by pulling the entries from
+// various sources:
+// * explicitly specified files
+// * files whose paths are read from a file
+// * directories traversed recursively
+// It can optionally change the recorded path of an entry.
+
package main
import (
diff --git a/zip/zip.go b/zip/zip.go
index e27432c..cb85f5c 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -126,6 +126,7 @@
return b
}
+// List reads the file names from the given file and adds them to the source files list.
func (b *FileArgsBuilder) List(name string) *FileArgsBuilder {
if b.err != nil {
return b
@@ -150,6 +151,7 @@
return b
}
+// RspFile reads the file names from given .rsp file and adds them to the source files list.
func (b *FileArgsBuilder) RspFile(name string) *FileArgsBuilder {
if b.err != nil {
return b
@@ -291,7 +293,7 @@
return args
}
-func ZipTo(args ZipArgs, w io.Writer) error {
+func zipTo(args ZipArgs, w io.Writer) error {
if args.EmulateJar {
args.AddDirectoryEntriesToZip = true
}
@@ -392,6 +394,7 @@
return z.write(w, pathMappings, args.ManifestSourcePath, args.EmulateJar, args.SrcJar, args.NumParallelJobs)
}
+// Zip creates an output zip archive from given sources.
func Zip(args ZipArgs) error {
if args.OutputFilePath == "" {
return fmt.Errorf("output file path must be nonempty")
@@ -416,7 +419,7 @@
out = f
}
- err := ZipTo(args, out)
+ err := zipTo(args, out)
if err != nil {
return err
}
@@ -450,7 +453,6 @@
RelativeRoot: fa.SourcePrefixToStrip,
}
}
-
}
dest = filepath.Join(fa.PathPrefixInZip, dest)
@@ -465,10 +467,9 @@
}
func jarSort(mappings []pathMapping) {
- less := func(i int, j int) (smaller bool) {
+ sort.SliceStable(mappings, func(i int, j int) bool {
return jar.EntryNamesLess(mappings[i].dest, mappings[j].dest)
- }
- sort.SliceStable(mappings, less)
+ })
}
func (z *ZipWriter) write(f io.Writer, pathMappings []pathMapping, manifest string, emulateJar, srcJar bool,
@@ -709,7 +710,7 @@
}
}
-func (z *ZipWriter) addManifest(dest string, src string, method uint16) error {
+func (z *ZipWriter) addManifest(dest string, src string, _ uint16) error {
if prev, exists := z.createdDirs[dest]; exists {
return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src)
}
@@ -963,7 +964,7 @@
dir = filepath.Clean(dir)
// discover any uncreated directories in the path
- zipDirs := []string{}
+ var zipDirs []string
for dir != "" && dir != "." {
if _, exists := z.createdDirs[dir]; exists {
break
diff --git a/zip/zip_test.go b/zip/zip_test.go
index 302a749..a16e092 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -442,7 +442,7 @@
args.Stderr = &bytes.Buffer{}
buf := &bytes.Buffer{}
- err := ZipTo(args, buf)
+ err := zipTo(args, buf)
if (err != nil) != (test.err != nil) {
t.Fatalf("want error %v, got %v", test.err, err)
@@ -627,7 +627,7 @@
args.Stderr = &bytes.Buffer{}
buf := &bytes.Buffer{}
- err := ZipTo(args, buf)
+ err := zipTo(args, buf)
if err != nil {
t.Fatalf("got error %v", err)
}