Merge "Add dependency to list of asset files"
diff --git a/android/apex.go b/android/apex.go
index a4ff0f9..4a71b40 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -257,7 +257,7 @@
canHaveApexVariants bool
apexInfos []ApexInfo
- apexInfosLock sync.Mutex // protects apexInfos during parallel apexDepsMutator
+ apexInfosLock sync.Mutex // protects apexInfos during parallel apexInfoMutator
}
// Initializes ApexModuleBase struct. Not calling this (even when inheriting from ApexModuleBase)
@@ -442,7 +442,7 @@
} else {
apexInfos = base.apexInfos
}
- // base.apexInfos is only needed to propagate the list of apexes from apexDepsMutator to
+ // base.apexInfos is only needed to propagate the list of apexes from apexInfoMutator to
// apexMutator. It is no longer accurate after mergeApexVariations, and won't be copied to
// all but the first created variant. Clear it so it doesn't accidentally get used later.
base.apexInfos = nil
diff --git a/android/module.go b/android/module.go
index f805acd..429f311 100644
--- a/android/module.go
+++ b/android/module.go
@@ -340,10 +340,51 @@
ExpandSource(srcFile, prop string) Path
ExpandOptionalSource(srcFile *string, prop string) OptionalPath
+ // InstallExecutable creates a rule to copy srcPath to name in the installPath directory,
+ // with the given additional dependencies. The file is marked executable after copying.
+ //
+ // The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+ // installed file will be returned by PackagingSpecs() on this module or by
+ // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+ // for which IsInstallDepNeeded returns true.
InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
+
+ // InstallFile creates a rule to copy srcPath to name in the installPath directory,
+ // with the given additional dependencies.
+ //
+ // The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+ // installed file will be returned by PackagingSpecs() on this module or by
+ // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+ // for which IsInstallDepNeeded returns true.
InstallFile(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
+
+ // InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
+ // directory.
+ //
+ // The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
+ // installed file will be returned by PackagingSpecs() on this module or by
+ // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+ // for which IsInstallDepNeeded returns true.
InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath
+
+ // InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name
+ // in the installPath directory.
+ //
+ // The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
+ // installed file will be returned by PackagingSpecs() on this module or by
+ // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+ // for which IsInstallDepNeeded returns true.
InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath
+
+ // PackageFile creates a PackagingSpec as if InstallFile was called, but without creating
+ // the rule to copy the file. This is useful to define how a module would be packaged
+ // without installing it into the global installation directories.
+ //
+ // The created PackagingSpec for the will be returned by PackagingSpecs() on this module or by
+ // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+ // for which IsInstallDepNeeded returns true.
+ PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec
+
CheckbuildFile(srcPath Path)
InstallInData() bool
@@ -2430,6 +2471,22 @@
return m.installFile(installPath, name, srcPath, deps, true)
}
+func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec {
+ fullInstallPath := installPath.Join(m, name)
+ return m.packageFile(fullInstallPath, srcPath, false)
+}
+
+func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec {
+ spec := PackagingSpec{
+ relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
+ srcPath: srcPath,
+ symlinkTarget: "",
+ executable: executable,
+ }
+ m.packagingSpecs = append(m.packagingSpecs, spec)
+ return spec
+}
+
func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []Path, executable bool) InstallPath {
fullInstallPath := installPath.Join(m, name)
@@ -2466,12 +2523,7 @@
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.packageFile(fullInstallPath, srcPath, executable)
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
return fullInstallPath
@@ -2683,7 +2735,11 @@
}
}
+// Modules can implement HostToolProvider and return a valid OptionalPath from HostToolPath() to
+// specify that they can be used as a tool by a genrule module.
type HostToolProvider interface {
+ // HostToolPath returns the path to the host tool for the module if it is one, or an invalid
+ // OptionalPath.
HostToolPath() OptionalPath
}
diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go
index e2555e4..b00dc2f 100644
--- a/android/prebuilt_build_tool.go
+++ b/android/prebuilt_build_tool.go
@@ -57,7 +57,7 @@
func (t *prebuiltBuildTool) GenerateAndroidBuildActions(ctx ModuleContext) {
sourcePath := t.prebuilt.SingleSourcePath(ctx)
- installedPath := PathForModuleOut(ctx, t.ModuleBase.Name())
+ installedPath := PathForModuleOut(ctx, t.BaseModuleName())
deps := PathsForModuleSrc(ctx, t.properties.Deps)
var fromPath = sourcePath.String()
@@ -75,6 +75,12 @@
},
})
+ packagingDir := PathForModuleInstall(ctx, t.BaseModuleName())
+ ctx.PackageFile(packagingDir, sourcePath.String(), sourcePath)
+ for _, dep := range deps {
+ ctx.PackageFile(packagingDir, dep.String(), dep)
+ }
+
t.toolPath = OptionalPathForPath(installedPath)
}
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 6c76ad3f..e7f8b7f 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -425,6 +425,15 @@
for _, dist := range data.Entries.GetDistForGoals(a) {
fmt.Fprintf(w, dist)
}
+
+ if a.coverageOutputPath.String() != "" {
+ goal := "apps_only"
+ distFile := a.coverageOutputPath.String()
+ fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+
+ " $(call dist-for-goals,%s,%s:ndk_apis_usedby_apex/$(notdir %s))\n"+
+ "endif",
+ goal, distFile, distFile)
+ }
}
}}
}
diff --git a/apex/apex.go b/apex/apex.go
index dae0f26..2a81b9b 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -55,7 +55,7 @@
}
func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("apex_deps", apexDepsMutator).Parallel()
+ ctx.TopDown("apex_info", apexInfoMutator).Parallel()
ctx.BottomUp("apex_unique", apexUniqueVariationsMutator).Parallel()
ctx.BottomUp("apex_test_for_deps", apexTestForDepsMutator).Parallel()
ctx.BottomUp("apex_test_for", apexTestForMutator).Parallel()
@@ -491,12 +491,12 @@
// 1) DepsMutator: from the properties like native_shared_libs, java_libs, etc., modules are added
// to the (direct) dependencies of this APEX bundle.
//
-// 2) apexDepsMutator: this is a post-deps mutator, so runs after DepsMutator. Its goal is to
+// 2) apexInfoMutator: this is a post-deps mutator, so runs after DepsMutator. Its goal is to
// collect modules that are direct and transitive dependencies of each APEX bundle. The collected
// modules are marked as being included in the APEX via BuildForApex().
//
-// 3) apexMutator: this is a post-deps mutator that runs after apexDepsMutator. For each module that
-// are marked by the apexDepsMutator, apex variations are created using CreateApexVariations().
+// 3) apexMutator: this is a post-deps mutator that runs after apexInfoMutator. For each module that
+// are marked by the apexInfoMutator, apex variations are created using CreateApexVariations().
type dependencyTag struct {
blueprint.BaseDependencyTag
@@ -530,11 +530,8 @@
if ctx.Device() {
binVariations = append(binVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
- libVariations = append(libVariations,
- blueprint.Variation{Mutator: "image", Variation: imageVariation},
- blueprint.Variation{Mutator: "version", Variation: ""}) // "" is the non-stub variant
- rustLibVariations = append(rustLibVariations,
- blueprint.Variation{Mutator: "image", Variation: imageVariation})
+ libVariations = append(libVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
+ rustLibVariations = append(rustLibVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
}
// Use *FarVariation* to be able to depend on modules having conflicting variations with
@@ -729,14 +726,20 @@
Contents *android.ApexContents
}
-var ApexBundleInfoProvider = blueprint.NewMutatorProvider(ApexBundleInfo{}, "apex_deps")
+var ApexBundleInfoProvider = blueprint.NewMutatorProvider(ApexBundleInfo{}, "apex_info")
-// apexDepsMutator is responsible for collecting modules that need to have apex variants. They are
+// apexInfoMutator is responsible for collecting modules that need to have apex variants. They are
// identified by doing a graph walk starting from an apexBundle. Basically, all the (direct and
// indirect) dependencies are collected. But a few types of modules that shouldn't be included in
// the apexBundle (e.g. stub libraries) are not collected. Note that a single module can be depended
// on by multiple apexBundles. In that case, the module is collected for all of the apexBundles.
-func apexDepsMutator(mctx android.TopDownMutatorContext) {
+//
+// For each dependency between an apex and an ApexModule an ApexInfo object describing the apex
+// is passed to that module's BuildForApex(ApexInfo) method which collates them all in a list.
+// The apexMutator uses that list to create module variants for the apexes to which it belongs.
+// The relationship between module variants and apexes is not one-to-one as variants will be
+// shared between compatible apexes.
+func apexInfoMutator(mctx android.TopDownMutatorContext) {
if !mctx.Module().Enabled() {
return
}
@@ -918,7 +921,7 @@
}
// apexMutator visits each module and creates apex variations if the module was marked in the
-// previous run of apexDepsMutator.
+// previous run of apexInfoMutator.
func apexMutator(mctx android.BottomUpMutatorContext) {
if !mctx.Module().Enabled() {
return
@@ -1530,6 +1533,9 @@
provideNativeLibs = append(provideNativeLibs, fi.stem())
}
return true // track transitive dependencies
+ } else if r, ok := child.(*rust.Module); ok {
+ fi := apexFileForRustLibrary(ctx, r)
+ filesInfo = append(filesInfo, fi)
} else {
propertyName := "native_shared_libs"
if isJniLib {
@@ -1704,6 +1710,11 @@
filesInfo = append(filesInfo, af)
return true // track transitive dependencies
+ } else if rm, ok := child.(*rust.Module); ok {
+ af := apexFileForRustLibrary(ctx, rm)
+ af.transitiveDep = true
+ filesInfo = append(filesInfo, af)
+ return true // track transitive dependencies
}
} else if cc.IsTestPerSrcDepTag(depTag) {
if cc, ok := child.(*cc.Module); ok {
@@ -1718,6 +1729,8 @@
filesInfo = append(filesInfo, af)
return true // track transitive dependencies
}
+ } else if cc.IsHeaderDepTag(depTag) {
+ // nothing
} else if java.IsJniDepTag(depTag) {
// Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
return false
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 16c01ca..ab8ae16 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -362,7 +362,10 @@
androidManifest: ":myapex.androidmanifest",
key: "myapex.key",
binaries: ["foo.rust"],
- native_shared_libs: ["mylib"],
+ native_shared_libs: [
+ "mylib",
+ "libfoo.ffi",
+ ],
rust_dyn_libs: ["libfoo.dylib.rust"],
multilib: {
both: {
@@ -399,7 +402,10 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
- shared_libs: ["mylib2"],
+ shared_libs: [
+ "mylib2",
+ "libbar.ffi",
+ ],
system_shared_libs: [],
stl: "none",
// TODO: remove //apex_available:platform
@@ -451,6 +457,20 @@
apex_available: ["myapex"],
}
+ rust_ffi_shared {
+ name: "libfoo.ffi",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ apex_available: ["myapex"],
+ }
+
+ rust_ffi_shared {
+ name: "libbar.ffi",
+ srcs: ["foo.rs"],
+ crate_name: "bar",
+ apex_available: ["myapex"],
+ }
+
apex {
name: "com.android.gki.fake",
binaries: ["foo"],
@@ -566,12 +586,14 @@
ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_apex10000")
ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_apex10000")
ensureListContains(t, ctx.ModuleVariantsForTests("foo.rust"), "android_arm64_armv8-a_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("libfoo.ffi"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that apex variant is created for the indirect dep
ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000")
ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_apex10000")
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")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
@@ -579,6 +601,8 @@
ensureContains(t, copyCmds, "image.apex/javalib/myjar_stem.jar")
ensureContains(t, copyCmds, "image.apex/javalib/myjar_dex.jar")
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")
// .. but not for java libs
ensureNotContains(t, copyCmds, "image.apex/javalib/myotherjar.jar")
ensureNotContains(t, copyCmds, "image.apex/javalib/msharedjar.jar")
@@ -1789,6 +1813,31 @@
min_sdk_version: "30",
}
`)
+
+ testApexError(t, `module "libfoo.ffi".*: should support min_sdk_version\(29\)`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo.ffi"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ rust_ffi_shared {
+ name: "libfoo.ffi",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ apex_available: [
+ "myapex",
+ ],
+ min_sdk_version: "30",
+ }
+ `)
}
func TestApexMinSdkVersion_Okay(t *testing.T) {
@@ -5642,6 +5691,13 @@
],
}
`
+
+ testDexpreoptWithApexes(t, bp, errmsg, transformDexpreoptConfig)
+}
+
+func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
+ t.Helper()
+
bp += cc.GatherRequiredDepsForTest(android.Android)
bp += java.GatherRequiredDepsForTest()
bp += dexpreopt.BpToolModulesForTest()
diff --git a/cc/Android.bp b/cc/Android.bp
index 88104e2..33f3db2 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -31,6 +31,7 @@
"sanitize.go",
"sabi.go",
"sdk.go",
+ "snapshot_prebuilt.go",
"snapshot_utils.go",
"stl.go",
"strip.go",
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 9b61e55..4f4b047 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -113,7 +113,7 @@
entries.SetString("LOCAL_SOONG_VNDK_VERSION", c.VndkVersion())
// VNDK libraries available to vendor are not installed because
// they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go)
- if !c.isVndkExt() {
+ if !c.IsVndkExt() {
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
}
}
diff --git a/cc/cc.go b/cc/cc.go
index ae75c1d..9383e39 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -409,7 +409,7 @@
isVndkPrivate(config android.Config) bool
isVndk() bool
isVndkSp() bool
- isVndkExt() bool
+ IsVndkExt() bool
inProduct() bool
inVendor() bool
inRamdisk() bool
@@ -1035,7 +1035,7 @@
return isLlndkLibrary(name, config) && !isVndkPrivateLibrary(name, config)
}
-func (c *Module) isVndkPrivate(config android.Config) bool {
+func (c *Module) IsVndkPrivate(config android.Config) bool {
// Returns true for LLNDK-private, VNDK-SP-private, and VNDK-core-private.
return isVndkPrivateLibrary(c.BaseModuleName(), config)
}
@@ -1068,7 +1068,7 @@
return false
}
-func (c *Module) isVndkExt() bool {
+func (c *Module) IsVndkExt() bool {
if vndkdep := c.vndkdep; vndkdep != nil {
return vndkdep.isVndkExt()
}
@@ -1252,7 +1252,7 @@
}
func (ctx *moduleContextImpl) isVndkPrivate(config android.Config) bool {
- return ctx.mod.isVndkPrivate(config)
+ return ctx.mod.IsVndkPrivate(config)
}
func (ctx *moduleContextImpl) isVndk() bool {
@@ -1271,8 +1271,8 @@
return ctx.mod.isVndkSp()
}
-func (ctx *moduleContextImpl) isVndkExt() bool {
- return ctx.mod.isVndkExt()
+func (ctx *moduleContextImpl) IsVndkExt() bool {
+ return ctx.mod.IsVndkExt()
}
func (ctx *moduleContextImpl) mustUseVendorVariant() bool {
@@ -1425,7 +1425,7 @@
// "current", it will append the VNDK version to the name suffix.
var vndkVersion string
var nameSuffix string
- if c.inProduct() {
+ if c.InProduct() {
vndkVersion = ctx.DeviceConfig().ProductVndkVersion()
nameSuffix = productSuffix
} else {
@@ -1459,7 +1459,7 @@
c.hideApexVariantFromMake = true
}
- c.makeLinkType = c.getMakeLinkType(actx)
+ c.makeLinkType = GetMakeLinkType(actx, c)
c.Properties.SubName = ""
@@ -1601,7 +1601,7 @@
// glob exported headers for snapshot, if BOARD_VNDK_VERSION is current.
if i, ok := c.linker.(snapshotLibraryInterface); ok && ctx.DeviceConfig().VndkVersion() == "current" {
- if isSnapshotAware(ctx, c, apexInfo) {
+ if shouldCollectHeadersForSnapshot(ctx, c, apexInfo) {
i.collectHeadersForSnapshot(ctx)
}
}
@@ -1892,13 +1892,6 @@
}
}
- buildStubs := false
- if versioned, ok := c.linker.(versionedInterface); ok {
- if versioned.buildStubs() {
- buildStubs = true
- }
- }
-
rewriteSnapshotLibs := func(lib string, snapshotMap *snapshotMap) string {
// only modules with BOARD_VNDK_VERSION uses snapshot.
if c.VndkVersion() != actx.DeviceConfig().VndkVersion() {
@@ -1921,7 +1914,7 @@
lib = rewriteSnapshotLibs(lib, vendorSnapshotHeaderLibs)
- if buildStubs {
+ if c.IsStubs() {
actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()),
depTag, lib)
} else {
@@ -1929,12 +1922,6 @@
}
}
- if buildStubs {
- // Stubs lib does not have dependency to other static/shared libraries.
- // Don't proceed.
- return
- }
-
// sysprop_library has to support both C++ and Java. So sysprop_library internally creates one
// C++ implementation library and one Java implementation library. When a module links against
// sysprop_library, the C++ implementation library has to be linked. syspropImplLibraries is a
@@ -2114,7 +2101,7 @@
return
}
- if from.Module().Target().Os != android.Android {
+ if from.Target().Os != android.Android {
// Host code is not restricted
return
}
@@ -2128,6 +2115,11 @@
if ccFrom.vndkdep != nil {
ccFrom.vndkdep.vndkCheckLinkType(ctx, ccTo, tag)
}
+ } else if linkableMod, ok := to.(LinkableInterface); ok {
+ // Static libraries from other languages can be linked
+ if !linkableMod.Static() {
+ ctx.ModuleErrorf("Attempting to link VNDK cc.Module with unsupported module type")
+ }
} else {
ctx.ModuleErrorf("Attempting to link VNDK cc.Module with unsupported module type")
}
@@ -2254,6 +2246,11 @@
return false
}
+ depTag := ctx.OtherModuleDependencyTag(child)
+ if IsHeaderDepTag(depTag) {
+ return false
+ }
+
// Even if target lib has no vendor variant, keep checking dependency
// graph in case it depends on vendor_available or product_available
// but not double_loadable transtively.
@@ -2505,6 +2502,12 @@
}
}
+ // Stubs lib doesn't link to the shared lib dependencies. Don't set
+ // linkFile, depFile, and ptr.
+ if c.IsStubs() {
+ break
+ }
+
linkFile = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary)
depFile = sharedLibraryInfo.TableOfContents
@@ -2532,6 +2535,13 @@
}
return
}
+
+ // Stubs lib doesn't link to the static lib dependencies. Don't set
+ // linkFile, depFile, and ptr.
+ if c.IsStubs() {
+ break
+ }
+
staticLibraryInfo := ctx.OtherModuleProvider(dep, StaticLibraryInfoProvider).(StaticLibraryInfo)
linkFile = android.OptionalPathForPath(staticLibraryInfo.StaticLibrary)
if libDepTag.wholeStatic {
@@ -2659,7 +2669,9 @@
c.Properties.AndroidMkStaticLibs, makeLibName)
}
}
- } else {
+ } else if !c.IsStubs() {
+ // Stubs lib doesn't link to the runtime lib, object, crt, etc. dependencies.
+
switch depTag {
case runtimeDepTag:
c.Properties.AndroidMkRuntimeLibs = append(
@@ -2784,7 +2796,7 @@
return libName + vendorRamdiskSuffix
} else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() {
return libName + recoverySuffix
- } else if ccDep.Module().Target().NativeBridge == android.NativeBridgeEnabled {
+ } else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled {
return libName + nativeBridgeSuffix
} else {
return libName
@@ -2896,22 +2908,24 @@
return false
}
-func (c *Module) getMakeLinkType(actx android.ModuleContext) string {
+func GetMakeLinkType(actx android.ModuleContext, c LinkableInterface) string {
if c.UseVndk() {
- if lib, ok := c.linker.(*llndkStubDecorator); ok {
- if Bool(lib.Properties.Vendor_available) {
- return "native:vndk"
+ if ccModule, ok := c.Module().(*Module); ok {
+ // Only CC modules provide stubs at the moment.
+ if lib, ok := ccModule.linker.(*llndkStubDecorator); ok {
+ if Bool(lib.Properties.Vendor_available) {
+ return "native:vndk"
+ }
+ return "native:vndk_private"
}
- return "native:vndk_private"
}
- if c.IsVndk() && !c.isVndkExt() {
- // Product_available, if defined, must have the same value with Vendor_available.
- if Bool(c.VendorProperties.Vendor_available) {
- return "native:vndk"
+ if c.IsVndk() && !c.IsVndkExt() {
+ if c.IsVndkPrivate(actx.Config()) {
+ return "native:vndk_private"
}
- return "native:vndk_private"
+ return "native:vndk"
}
- if c.inProduct() {
+ if c.InProduct() {
return "native:product"
}
return "native:vendor"
@@ -2921,7 +2935,7 @@
return "native:vendor_ramdisk"
} else if c.InRecovery() {
return "native:recovery"
- } else if c.Target().Os == android.Android && String(c.Properties.Sdk_version) != "" {
+ } else if c.Target().Os == android.Android && c.SdkVersion() != "" {
return "native:ndk:none:none"
// TODO(b/114741097): use the correct ndk stl once build errors have been fixed
//family, link := getNdkStlFamilyAndLinkType(c)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index af9b943..c16cce8 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -250,8 +250,8 @@
// Check VNDK extension properties.
isVndkExt := extends != ""
- if mod.isVndkExt() != isVndkExt {
- t.Errorf("%q isVndkExt() must equal to %t", name, isVndkExt)
+ if mod.IsVndkExt() != isVndkExt {
+ t.Errorf("%q IsVndkExt() must equal to %t", name, isVndkExt)
}
if actualExtends := mod.getVndkExtendsModuleName(); actualExtends != extends {
@@ -4056,3 +4056,35 @@
}
}
+
+func TestStubsLibReexportsHeaders(t *testing.T) {
+ ctx := testCc(t, `
+ cc_library_shared {
+ name: "libclient",
+ srcs: ["foo.c"],
+ shared_libs: ["libfoo#1"],
+ }
+
+ cc_library_shared {
+ name: "libfoo",
+ srcs: ["foo.c"],
+ shared_libs: ["libbar"],
+ export_shared_lib_headers: ["libbar"],
+ stubs: {
+ symbol_file: "foo.map.txt",
+ versions: ["1", "2", "3"],
+ },
+ }
+
+ cc_library_shared {
+ name: "libbar",
+ export_include_dirs: ["include/libbar"],
+ srcs: ["foo.c"],
+ }`)
+
+ cFlags := ctx.ModuleForTests("libclient", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"]
+
+ if !strings.Contains(cFlags, "-Iinclude/libbar") {
+ t.Errorf("expected %q in cflags, got %q", "-Iinclude/libbar", cFlags)
+ }
+}
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index a548452..8a0d7bd 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -21,10 +21,10 @@
"android.hardware.automotive.occupant_awareness-ndk_platform",
"android.hardware.light-ndk_platform",
"android.hardware.identity-ndk_platform",
- "android.hardware.keymint-unstable-ndk_platform",
"android.hardware.nfc@1.2",
"android.hardware.power-ndk_platform",
"android.hardware.rebootescrow-ndk_platform",
+ "android.hardware.security.keymint-unstable-ndk_platform",
"android.hardware.vibrator-ndk_platform",
"android.system.keystore2-unstable-ndk_platform",
"libbinder",
diff --git a/cc/coverage.go b/cc/coverage.go
index aa1fdf6..acf98dd 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -149,6 +149,7 @@
coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module)
deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
+ flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,open")
}
}
diff --git a/cc/image.go b/cc/image.go
index 3d6769e..32325b9 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -41,7 +41,7 @@
return hostImageVariant
} else if c.inVendor() {
return vendorImageVariant
- } else if c.inProduct() {
+ } else if c.InProduct() {
return productImageVariant
} else if c.InRamdisk() {
return ramdiskImageVariant
@@ -67,7 +67,7 @@
func (ctx *moduleContext) ProductSpecific() bool {
//TODO(b/150902910): Replace HasNonSystemVariants() with HasProductVariant()
return ctx.ModuleContext.ProductSpecific() ||
- (ctx.mod.HasNonSystemVariants() && ctx.mod.inProduct())
+ (ctx.mod.HasNonSystemVariants() && ctx.mod.InProduct())
}
func (ctx *moduleContext) SocSpecific() bool {
@@ -76,7 +76,7 @@
}
func (ctx *moduleContextImpl) inProduct() bool {
- return ctx.mod.inProduct()
+ return ctx.mod.InProduct()
}
func (ctx *moduleContextImpl) inVendor() bool {
@@ -111,7 +111,7 @@
}
// Returns true if the module is "product" variant. Usually these modules are installed in /product
-func (c *Module) inProduct() bool {
+func (c *Module) InProduct() bool {
return c.Properties.ImageVariationPrefix == ProductVariationPrefix
}
@@ -265,7 +265,7 @@
} else {
mctx.ModuleErrorf("version is unknown for snapshot prebuilt")
}
- } else if m.HasNonSystemVariants() && !m.isVndkExt() {
+ } else if m.HasNonSystemVariants() && !m.IsVndkExt() {
// This will be available to /system unless it is product_specific
// which will be handled later.
coreVariantNeeded = true
diff --git a/cc/library.go b/cc/library.go
index b796aaf..06b9905 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -610,13 +610,13 @@
}
if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate(ctx.Config()) {
if ctx.isVndkSp() {
- if ctx.isVndkExt() {
+ if ctx.IsVndkExt() {
return "VNDK-SP-ext"
} else {
return "VNDK-SP"
}
} else {
- if ctx.isVndkExt() {
+ if ctx.IsVndkExt() {
return "VNDK-ext"
} else {
return "VNDK-core"
@@ -767,7 +767,7 @@
func (library *libraryDecorator) getLibName(ctx BaseModuleContext) string {
name := library.getLibNameHelper(ctx.baseModuleName(), ctx.useVndk())
- if ctx.isVndkExt() {
+ if ctx.IsVndkExt() {
// vndk-ext lib should have the same name with original lib
ctx.VisitDirectDepsWithTag(vndkExtDepTag, func(module android.Module) {
originalName := module.(*Module).outputFile.Path()
@@ -1190,7 +1190,7 @@
library.sAbiDiff = sourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
refAbiDumpFile, fileName, exportedHeaderFlags,
Bool(library.Properties.Header_abi_checker.Check_all_apis),
- ctx.isLlndk(ctx.Config()), ctx.isNdk(ctx.Config()), ctx.isVndkExt())
+ ctx.isLlndk(ctx.Config()), ctx.isNdk(ctx.Config()), ctx.IsVndkExt())
}
}
}
@@ -1320,7 +1320,7 @@
if library.shared() {
if ctx.Device() && ctx.useVndk() {
// set subDir for VNDK extensions
- if ctx.isVndkExt() {
+ if ctx.IsVndkExt() {
if ctx.isVndkSp() {
library.baseInstaller.subDir = "vndk-sp"
} else {
@@ -1329,7 +1329,7 @@
}
// In some cases we want to use core variant for VNDK-Core libs
- if ctx.isVndk() && !ctx.isVndkSp() && !ctx.isVndkExt() {
+ if ctx.isVndk() && !ctx.isVndkSp() && !ctx.IsVndkExt() {
mayUseCoreVariant := true
if ctx.mustUseVendorVariant() {
@@ -1350,7 +1350,7 @@
// do not install vndk libs
// vndk libs are packaged into VNDK APEX
- if ctx.isVndk() && !ctx.isVndkExt() {
+ if ctx.isVndk() && !ctx.IsVndkExt() {
return
}
} else if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.directlyInAnyApex() {
diff --git a/cc/linkable.go b/cc/linkable.go
index ddf3950..4efe2a7 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -8,6 +8,8 @@
// LinkableInterface is an interface for a type of module that is linkable in a C++ library.
type LinkableInterface interface {
+ android.Module
+
Module() android.Module
CcLibrary() bool
CcLibraryInterface() bool
@@ -42,7 +44,10 @@
UseVndk() bool
MustUseVendorVariant() bool
IsVndk() bool
+ IsVndkExt() bool
+ IsVndkPrivate(config android.Config) bool
HasVendorVariant() bool
+ InProduct() bool
SdkVersion() string
AlwaysSdk() bool
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
new file mode 100644
index 0000000..b291bd0
--- /dev/null
+++ b/cc/snapshot_prebuilt.go
@@ -0,0 +1,844 @@
+// 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 cc
+
+// This file defines snapshot prebuilt modules, e.g. vendor snapshot and recovery snapshot. Such
+// snapshot modules will override original source modules with setting BOARD_VNDK_VERSION, with
+// snapshot mutators and snapshot information maps which are also defined in this file.
+
+import (
+ "strings"
+ "sync"
+
+ "android/soong/android"
+)
+
+// Defines the specifics of different images to which the snapshot process is applicable, e.g.,
+// vendor, recovery, ramdisk.
+type snapshotImage 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 vendorSnapshotImage struct{}
+type recoverySnapshotImage struct{}
+
+func (vendorSnapshotImage) 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 (vendorSnapshotImage) inImage(m *Module) func() bool {
+ return m.inVendor
+}
+
+func (vendorSnapshotImage) available(m *Module) *bool {
+ return m.VendorProperties.Vendor_available
+}
+
+func (vendorSnapshotImage) isProprietaryPath(dir string) bool {
+ return isVendorProprietaryPath(dir)
+}
+
+// vendor snapshot includes static/header libraries with vndk: {enabled: true}.
+func (vendorSnapshotImage) includeVndk() bool {
+ return true
+}
+
+func (vendorSnapshotImage) excludeFromSnapshot(m *Module) bool {
+ return m.ExcludeFromVendorSnapshot()
+}
+
+func (recoverySnapshotImage) 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 (recoverySnapshotImage) inImage(m *Module) func() bool {
+ return m.InRecovery
+}
+
+func (recoverySnapshotImage) available(m *Module) *bool {
+ return m.Properties.Recovery_available
+}
+
+func (recoverySnapshotImage) isProprietaryPath(dir string) bool {
+ return isRecoveryProprietaryPath(dir)
+}
+
+// recovery snapshot does NOT treat vndk specially.
+func (recoverySnapshotImage) includeVndk() bool {
+ return false
+}
+
+func (recoverySnapshotImage) excludeFromSnapshot(m *Module) bool {
+ return m.ExcludeFromRecoverySnapshot()
+}
+
+var vendorSnapshotImageSingleton vendorSnapshotImage
+var recoverySnapshotImageSingleton recoverySnapshotImage
+
+func init() {
+ vendorSnapshotImageSingleton.init()
+ recoverySnapshotImageSingleton.init()
+}
+
+const (
+ vendorSnapshotHeaderSuffix = ".vendor_header."
+ vendorSnapshotSharedSuffix = ".vendor_shared."
+ vendorSnapshotStaticSuffix = ".vendor_static."
+ vendorSnapshotBinarySuffix = ".vendor_binary."
+ 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")
+ vendorSnapshotHeaderLibsKey = android.NewOnceKey("vendorSnapshotHeaderLibs")
+ vendorSnapshotStaticLibsKey = android.NewOnceKey("vendorSnapshotStaticLibs")
+ vendorSnapshotSharedLibsKey = android.NewOnceKey("vendorSnapshotSharedLibs")
+ vendorSnapshotBinariesKey = android.NewOnceKey("vendorSnapshotBinaries")
+ vendorSnapshotObjectsKey = android.NewOnceKey("vendorSnapshotObjects")
+)
+
+// vendorSuffixModules holds names of modules whose vendor variants should have the vendor suffix.
+// This is determined by source modules, and then this will be used when exporting snapshot modules
+// to Makefile.
+//
+// For example, if libbase has "vendor_available: true", the name of core variant will be "libbase"
+// while the name of vendor variant will be "libbase.vendor". In such cases, the vendor snapshot of
+// "libbase" should be exported with the name "libbase.vendor".
+//
+// Refer to VendorSnapshotSourceMutator and makeLibName which use this.
+func vendorSuffixModules(config android.Config) map[string]bool {
+ return config.Once(vendorSuffixModulesKey, func() interface{} {
+ return make(map[string]bool)
+ }).(map[string]bool)
+}
+
+// these are vendor snapshot maps holding names of vendor snapshot modules
+func vendorSnapshotHeaderLibs(config android.Config) *snapshotMap {
+ return config.Once(vendorSnapshotHeaderLibsKey, func() interface{} {
+ return newSnapshotMap()
+ }).(*snapshotMap)
+}
+
+func vendorSnapshotSharedLibs(config android.Config) *snapshotMap {
+ return config.Once(vendorSnapshotSharedLibsKey, func() interface{} {
+ return newSnapshotMap()
+ }).(*snapshotMap)
+}
+
+func vendorSnapshotStaticLibs(config android.Config) *snapshotMap {
+ return config.Once(vendorSnapshotStaticLibsKey, func() interface{} {
+ return newSnapshotMap()
+ }).(*snapshotMap)
+}
+
+func vendorSnapshotBinaries(config android.Config) *snapshotMap {
+ return config.Once(vendorSnapshotBinariesKey, func() interface{} {
+ return newSnapshotMap()
+ }).(*snapshotMap)
+}
+
+func vendorSnapshotObjects(config android.Config) *snapshotMap {
+ return config.Once(vendorSnapshotObjectsKey, func() interface{} {
+ return newSnapshotMap()
+ }).(*snapshotMap)
+}
+
+type baseSnapshotDecoratorProperties struct {
+ // snapshot version.
+ Version string
+
+ // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64')
+ Target_arch string
+}
+
+// baseSnapshotDecorator provides common basic functions for all snapshot modules, such as snapshot
+// version, snapshot arch, etc. It also adds a special suffix to Soong module name, so it doesn't
+// collide with source modules. e.g. the following example module,
+//
+// vendor_snapshot_static {
+// name: "libbase",
+// arch: "arm64",
+// version: 30,
+// ...
+// }
+//
+// will be seen as "libbase.vendor_static.30.arm64" by Soong.
+type baseSnapshotDecorator struct {
+ baseProperties baseSnapshotDecoratorProperties
+ moduleSuffix string
+}
+
+func (p *baseSnapshotDecorator) Name(name string) string {
+ return name + p.NameSuffix()
+}
+
+func (p *baseSnapshotDecorator) NameSuffix() string {
+ versionSuffix := p.version()
+ if p.arch() != "" {
+ versionSuffix += "." + p.arch()
+ }
+
+ return p.moduleSuffix + versionSuffix
+}
+
+func (p *baseSnapshotDecorator) version() string {
+ return p.baseProperties.Version
+}
+
+func (p *baseSnapshotDecorator) arch() string {
+ return p.baseProperties.Target_arch
+}
+
+func (p *baseSnapshotDecorator) isSnapshotPrebuilt() bool {
+ return true
+}
+
+// Call this with a module suffix after creating a snapshot module, such as
+// vendorSnapshotSharedSuffix, recoverySnapshotBinarySuffix, etc.
+func (p *baseSnapshotDecorator) init(m *Module, suffix string) {
+ p.moduleSuffix = suffix
+ m.AddProperties(&p.baseProperties)
+ android.AddLoadHook(m, func(ctx android.LoadHookContext) {
+ vendorSnapshotLoadHook(ctx, p)
+ })
+}
+
+// vendorSnapshotLoadHook disables snapshots if it's not BOARD_VNDK_VERSION.
+// As vendor snapshot is only for vendor, such modules won't be used at all.
+func vendorSnapshotLoadHook(ctx android.LoadHookContext, p *baseSnapshotDecorator) {
+ if p.version() != ctx.DeviceConfig().VndkVersion() {
+ ctx.Module().Disable()
+ return
+ }
+}
+
+//
+// Module definitions for snapshots of libraries (shared, static, header).
+//
+// Modules (vendor|recovery)_snapshot_(shared|static|header) are defined here. Shared libraries and
+// static libraries have their prebuilt library files (.so for shared, .a for static) as their src,
+// which can be installed or linked against. Also they export flags needed when linked, such as
+// include directories, c flags, sanitize dependency information, etc.
+//
+// These modules are auto-generated by development/vendor_snapshot/update.py.
+type snapshotLibraryProperties struct {
+ // Prebuilt file for each arch.
+ Src *string `android:"arch_variant"`
+
+ // list of directories that will be added to the include path (using -I).
+ Export_include_dirs []string `android:"arch_variant"`
+
+ // list of directories that will be added to the system path (using -isystem).
+ Export_system_include_dirs []string `android:"arch_variant"`
+
+ // list of flags that will be used for any module that links against this module.
+ Export_flags []string `android:"arch_variant"`
+
+ // Whether this prebuilt needs to depend on sanitize ubsan runtime or not.
+ Sanitize_ubsan_dep *bool `android:"arch_variant"`
+
+ // Whether this prebuilt needs to depend on sanitize minimal runtime or not.
+ Sanitize_minimal_dep *bool `android:"arch_variant"`
+}
+
+type snapshotSanitizer interface {
+ isSanitizerEnabled(t sanitizerType) bool
+ setSanitizerVariation(t sanitizerType, enabled bool)
+}
+
+type snapshotLibraryDecorator struct {
+ baseSnapshotDecorator
+ *libraryDecorator
+ properties snapshotLibraryProperties
+ sanitizerProperties struct {
+ CfiEnabled bool `blueprint:"mutated"`
+
+ // Library flags for cfi variant.
+ Cfi snapshotLibraryProperties `android:"arch_variant"`
+ }
+ androidMkVendorSuffix bool
+}
+
+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 *snapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
+ arches := config.Arches()
+ if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
+ return false
+ }
+ if !p.header() && p.properties.Src == nil {
+ return false
+ }
+ return true
+}
+
+// cc modules' link functions are to link compiled objects into final binaries.
+// As snapshots are prebuilts, this just returns the prebuilt binary after doing things which are
+// done by normal library decorator, e.g. exporting flags.
+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()]
+
+ if p.header() {
+ return p.libraryDecorator.link(ctx, flags, deps, objs)
+ }
+
+ if p.sanitizerProperties.CfiEnabled {
+ p.properties = p.sanitizerProperties.Cfi
+ }
+
+ if !p.matchesWithDevice(ctx.DeviceConfig()) {
+ return nil
+ }
+
+ 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...)
+
+ in := android.PathForModuleSrc(ctx, *p.properties.Src)
+ p.unstrippedOutputFile = in
+
+ if p.shared() {
+ libName := in.Base()
+ builderFlags := flagsToBuilderFlags(flags)
+
+ // Optimize out relinking against shared libraries whose interface hasn't changed by
+ // depending on a table of contents file instead of the library itself.
+ tocFile := android.PathForModuleOut(ctx, libName+".toc")
+ p.tocFile = android.OptionalPathForPath(tocFile)
+ transformSharedObjectToToc(ctx, in, tocFile, builderFlags)
+
+ ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+ SharedLibrary: in,
+ UnstrippedSharedLibrary: p.unstrippedOutputFile,
+
+ TableOfContents: p.tocFile,
+ })
+ }
+
+ if p.static() {
+ depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(in).Build()
+ ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+ StaticLibrary: in,
+
+ TransitiveStaticLibrariesForOrdering: depSet,
+ })
+ }
+
+ p.libraryDecorator.flagExporter.setProvider(ctx)
+
+ return in
+}
+
+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 *snapshotLibraryDecorator) nativeCoverage() bool {
+ return false
+}
+
+func (p *snapshotLibraryDecorator) isSanitizerEnabled(t sanitizerType) bool {
+ switch t {
+ case cfi:
+ return p.sanitizerProperties.Cfi.Src != nil
+ default:
+ return false
+ }
+}
+
+func (p *snapshotLibraryDecorator) setSanitizerVariation(t sanitizerType, enabled bool) {
+ if !enabled {
+ return
+ }
+ switch t {
+ case cfi:
+ p.sanitizerProperties.CfiEnabled = true
+ default:
+ return
+ }
+}
+
+func snapshotLibraryFactory(suffix string) (*Module, *snapshotLibraryDecorator) {
+ module, library := NewLibrary(android.DeviceSupported)
+
+ module.stl = nil
+ module.sanitize = nil
+ library.disableStripping()
+
+ prebuilt := &snapshotLibraryDecorator{
+ libraryDecorator: library,
+ }
+
+ prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true)
+ prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true)
+
+ // Prevent default system libs (libc, libm, and libdl) from being linked
+ if prebuilt.baseLinker.Properties.System_shared_libs == nil {
+ prebuilt.baseLinker.Properties.System_shared_libs = []string{}
+ }
+
+ module.compiler = nil
+ module.linker = prebuilt
+ module.installer = prebuilt
+
+ prebuilt.init(module, suffix)
+ module.AddProperties(
+ &prebuilt.properties,
+ &prebuilt.sanitizerProperties,
+ )
+
+ return module, prebuilt
+}
+
+// vendor_snapshot_shared is a special prebuilt shared library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_shared
+// overrides the vendor variant of the cc shared library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func VendorSnapshotSharedFactory() android.Module {
+ module, prebuilt := snapshotLibraryFactory(vendorSnapshotSharedSuffix)
+ prebuilt.libraryDecorator.BuildOnlyShared()
+ return module.Init()
+}
+
+// recovery_snapshot_shared is a special prebuilt shared library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_shared
+// overrides the recovery variant of the cc shared library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func RecoverySnapshotSharedFactory() android.Module {
+ module, prebuilt := snapshotLibraryFactory(recoverySnapshotSharedSuffix)
+ prebuilt.libraryDecorator.BuildOnlyShared()
+ return module.Init()
+}
+
+// vendor_snapshot_static is a special prebuilt static library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_static
+// overrides the vendor variant of the cc static library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func VendorSnapshotStaticFactory() android.Module {
+ module, prebuilt := snapshotLibraryFactory(vendorSnapshotStaticSuffix)
+ prebuilt.libraryDecorator.BuildOnlyStatic()
+ return module.Init()
+}
+
+// recovery_snapshot_static is a special prebuilt static library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_static
+// overrides the recovery variant of the cc static library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func RecoverySnapshotStaticFactory() android.Module {
+ module, prebuilt := snapshotLibraryFactory(recoverySnapshotStaticSuffix)
+ prebuilt.libraryDecorator.BuildOnlyStatic()
+ return module.Init()
+}
+
+// vendor_snapshot_header is a special header library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_header
+// overrides the vendor variant of the cc header library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func VendorSnapshotHeaderFactory() android.Module {
+ module, prebuilt := snapshotLibraryFactory(vendorSnapshotHeaderSuffix)
+ prebuilt.libraryDecorator.HeaderOnly()
+ return module.Init()
+}
+
+// recovery_snapshot_header is a special header library which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_header
+// overrides the recovery variant of the cc header library with the same name, if BOARD_VNDK_VERSION
+// is set.
+func RecoverySnapshotHeaderFactory() android.Module {
+ module, prebuilt := snapshotLibraryFactory(recoverySnapshotHeaderSuffix)
+ prebuilt.libraryDecorator.HeaderOnly()
+ return module.Init()
+}
+
+var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
+
+//
+// Module definitions for snapshots of executable binaries.
+//
+// Modules (vendor|recovery)_snapshot_binary are defined here. They have their prebuilt executable
+// binaries (e.g. toybox, sh) as their src, which can be installed.
+//
+// These modules are auto-generated by development/vendor_snapshot/update.py.
+type snapshotBinaryProperties struct {
+ // Prebuilt file for each arch.
+ Src *string `android:"arch_variant"`
+}
+
+type snapshotBinaryDecorator struct {
+ baseSnapshotDecorator
+ *binaryDecorator
+ properties snapshotBinaryProperties
+ androidMkVendorSuffix bool
+}
+
+func (p *snapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
+ if config.DeviceArch() != p.arch() {
+ return false
+ }
+ if p.properties.Src == nil {
+ return false
+ }
+ return true
+}
+
+// cc modules' link functions are to link compiled objects into final binaries.
+// As snapshots are prebuilts, this just returns the prebuilt binary
+func (p *snapshotBinaryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
+ if !p.matchesWithDevice(ctx.DeviceConfig()) {
+ return nil
+ }
+
+ in := android.PathForModuleSrc(ctx, *p.properties.Src)
+ p.unstrippedOutputFile = in
+ binName := in.Base()
+
+ m := ctx.Module().(*Module)
+ p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
+
+ // use cpExecutable to make it executable
+ outputFile := android.PathForModuleOut(ctx, binName)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.CpExecutable,
+ Description: "prebuilt",
+ Output: outputFile,
+ Input: in,
+ })
+
+ return outputFile
+}
+
+func (p *snapshotBinaryDecorator) nativeCoverage() bool {
+ return false
+}
+
+// vendor_snapshot_binary is a special prebuilt executable binary which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_binary
+// overrides the vendor variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set.
+func VendorSnapshotBinaryFactory() android.Module {
+ return snapshotBinaryFactory(vendorSnapshotBinarySuffix)
+}
+
+// recovery_snapshot_binary is a special prebuilt executable binary which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_binary
+// overrides the recovery variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set.
+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)
+
+ // Prevent default system libs (libc, libm, and libdl) from being linked
+ if binary.baseLinker.Properties.System_shared_libs == nil {
+ binary.baseLinker.Properties.System_shared_libs = []string{}
+ }
+
+ prebuilt := &snapshotBinaryDecorator{
+ binaryDecorator: binary,
+ }
+
+ module.compiler = nil
+ module.sanitize = nil
+ module.stl = nil
+ module.linker = prebuilt
+
+ prebuilt.init(module, suffix)
+ module.AddProperties(&prebuilt.properties)
+ return module.Init()
+}
+
+//
+// Module definitions for snapshots of object files (*.o).
+//
+// Modules (vendor|recovery)_snapshot_object are defined here. They have their prebuilt object
+// files (*.o) as their src.
+//
+// These modules are auto-generated by development/vendor_snapshot/update.py.
+type vendorSnapshotObjectProperties struct {
+ // Prebuilt file for each arch.
+ Src *string `android:"arch_variant"`
+}
+
+type snapshotObjectLinker struct {
+ baseSnapshotDecorator
+ objectLinker
+ properties vendorSnapshotObjectProperties
+ androidMkVendorSuffix bool
+}
+
+func (p *snapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool {
+ if config.DeviceArch() != p.arch() {
+ return false
+ }
+ if p.properties.Src == nil {
+ return false
+ }
+ return true
+}
+
+// cc modules' link functions are to link compiled objects into final binaries.
+// As snapshots are prebuilts, this just returns the prebuilt binary
+func (p *snapshotObjectLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
+ if !p.matchesWithDevice(ctx.DeviceConfig()) {
+ return nil
+ }
+
+ m := ctx.Module().(*Module)
+ p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
+
+ return android.PathForModuleSrc(ctx, *p.properties.Src)
+}
+
+func (p *snapshotObjectLinker) nativeCoverage() bool {
+ return false
+}
+
+// vendor_snapshot_object is a special prebuilt compiled object file which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_object
+// overrides the vendor variant of the cc object with the same name, if BOARD_VNDK_VERSION is set.
+func VendorSnapshotObjectFactory() android.Module {
+ module := newObject()
+
+ prebuilt := &snapshotObjectLinker{
+ objectLinker: objectLinker{
+ baseLinker: NewBaseLinker(nil),
+ },
+ }
+ module.linker = prebuilt
+
+ prebuilt.init(module, vendorSnapshotObjectSuffix)
+ module.AddProperties(&prebuilt.properties)
+ return module.Init()
+}
+
+// recovery_snapshot_object is a special prebuilt compiled object file which is auto-generated by
+// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_object
+// overrides the recovery variant of the cc object with the same name, if BOARD_VNDK_VERSION is set.
+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()
+}
+
+type snapshotInterface interface {
+ matchesWithDevice(config android.DeviceConfig) bool
+}
+
+var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil)
+var _ snapshotInterface = (*snapshotLibraryDecorator)(nil)
+var _ snapshotInterface = (*snapshotBinaryDecorator)(nil)
+var _ snapshotInterface = (*snapshotObjectLinker)(nil)
+
+//
+// Mutators that helps vendor snapshot modules override source modules.
+//
+
+// VendorSnapshotMutator gathers all snapshots for vendor, and disable all snapshots which don't
+// match with device, e.g.
+// - snapshot version is different with BOARD_VNDK_VERSION
+// - snapshot arch is different with device's arch (e.g. arm vs x86)
+//
+// This also handles vndk_prebuilt_shared, except for they won't be disabled in any cases, given
+// that any versions of VNDK might be packed into vndk APEX.
+//
+// TODO(b/145966707): remove mutator and utilize android.Prebuilt to override source modules
+func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) {
+ vndkVersion := ctx.DeviceConfig().VndkVersion()
+ // don't need snapshot if current
+ if vndkVersion == "current" || vndkVersion == "" {
+ return
+ }
+
+ module, ok := ctx.Module().(*Module)
+ if !ok || !module.Enabled() || module.VndkVersion() != vndkVersion {
+ return
+ }
+
+ if !module.isSnapshotPrebuilt() {
+ return
+ }
+
+ // isSnapshotPrebuilt ensures snapshotInterface
+ if !module.linker.(snapshotInterface).matchesWithDevice(ctx.DeviceConfig()) {
+ // Disable unnecessary snapshot module, but do not disable
+ // vndk_prebuilt_shared because they might be packed into vndk APEX
+ if !module.IsVndk() {
+ module.Disable()
+ }
+ return
+ }
+
+ var snapshotMap *snapshotMap
+
+ if lib, ok := module.linker.(libraryInterface); ok {
+ if lib.static() {
+ snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
+ } else if lib.shared() {
+ snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
+ } else {
+ // header
+ snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
+ }
+ } else if _, ok := module.linker.(*snapshotBinaryDecorator); ok {
+ snapshotMap = vendorSnapshotBinaries(ctx.Config())
+ } else if _, ok := module.linker.(*snapshotObjectLinker); ok {
+ snapshotMap = vendorSnapshotObjects(ctx.Config())
+ } else {
+ return
+ }
+
+ vendorSnapshotsLock.Lock()
+ defer vendorSnapshotsLock.Unlock()
+ snapshotMap.add(module.BaseModuleName(), ctx.Arch().ArchType, ctx.ModuleName())
+}
+
+// VendorSnapshotSourceMutator disables source modules which have corresponding snapshots.
+func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) {
+ if !ctx.Device() {
+ return
+ }
+
+ vndkVersion := ctx.DeviceConfig().VndkVersion()
+ // don't need snapshot if current
+ if vndkVersion == "current" || vndkVersion == "" {
+ return
+ }
+
+ module, ok := ctx.Module().(*Module)
+ if !ok {
+ return
+ }
+
+ // vendor suffix should be added to snapshots if the source module isn't vendor: true.
+ if !module.SocSpecific() {
+ // But we can't just check SocSpecific() since we already passed the image mutator.
+ // Check ramdisk and recovery to see if we are real "vendor: true" module.
+ ramdisk_available := module.InRamdisk() && !module.OnlyInRamdisk()
+ vendor_ramdisk_available := module.InVendorRamdisk() && !module.OnlyInVendorRamdisk()
+ recovery_available := module.InRecovery() && !module.OnlyInRecovery()
+
+ if !ramdisk_available && !recovery_available && !vendor_ramdisk_available {
+ vendorSnapshotsLock.Lock()
+ defer vendorSnapshotsLock.Unlock()
+
+ vendorSuffixModules(ctx.Config())[ctx.ModuleName()] = true
+ }
+ }
+
+ if module.isSnapshotPrebuilt() || module.VndkVersion() != ctx.DeviceConfig().VndkVersion() {
+ // only non-snapshot modules with BOARD_VNDK_VERSION
+ return
+ }
+
+ // .. and also filter out llndk library
+ if module.isLlndk(ctx.Config()) {
+ return
+ }
+
+ var snapshotMap *snapshotMap
+
+ if lib, ok := module.linker.(libraryInterface); ok {
+ if lib.static() {
+ snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
+ } else if lib.shared() {
+ snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
+ } else {
+ // header
+ snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
+ }
+ } else if module.binary() {
+ snapshotMap = vendorSnapshotBinaries(ctx.Config())
+ } else if module.object() {
+ snapshotMap = vendorSnapshotObjects(ctx.Config())
+ } else {
+ return
+ }
+
+ if _, ok := snapshotMap.get(ctx.ModuleName(), ctx.Arch().ArchType); !ok {
+ // Corresponding snapshot doesn't exist
+ return
+ }
+
+ // Disables source modules if corresponding snapshot exists.
+ if lib, ok := module.linker.(libraryInterface); ok && lib.buildStatic() && lib.buildShared() {
+ // But do not disable because the shared variant depends on the static variant.
+ module.SkipInstall()
+ module.Properties.HideFromMake = true
+ } else {
+ module.Disable()
+ }
+}
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index a3d52e6..e841a54 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -13,6 +13,8 @@
// limitations under the License.
package cc
+// This file contains utility types and functions for VNDK / vendor snapshot.
+
import (
"android/soong/android"
)
@@ -21,15 +23,24 @@
headerExts = []string{".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"}
)
+// snapshotLibraryInterface is an interface for libraries captured to VNDK / vendor snapshots.
type snapshotLibraryInterface interface {
libraryInterface
+
+ // collectHeadersForSnapshot is called in GenerateAndroidBuildActions for snapshot aware
+ // modules (See isSnapshotAware below).
+ // This function should gather all headers needed for snapshot.
collectHeadersForSnapshot(ctx android.ModuleContext)
+
+ // snapshotHeaders should return collected headers by collectHeadersForSnapshot.
+ // Calling snapshotHeaders before collectHeadersForSnapshot is an error.
snapshotHeaders() android.Paths
}
var _ snapshotLibraryInterface = (*prebuiltLibraryLinker)(nil)
var _ snapshotLibraryInterface = (*libraryDecorator)(nil)
+// snapshotMap is a helper wrapper to a map from base module name to snapshot module name.
type snapshotMap struct {
snapshots map[string]string
}
@@ -57,43 +68,14 @@
return snapshot, found
}
-func isSnapshotAware(ctx android.ModuleContext, m *Module, apexInfo android.ApexInfo) bool {
- if _, _, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m, apexInfo); ok {
+// shouldCollectHeadersForSnapshot determines if the module is a possible candidate for snapshot.
+// If it's true, collectHeadersForSnapshot will be called in GenerateAndroidBuildActions.
+func shouldCollectHeadersForSnapshot(ctx android.ModuleContext, m *Module, apexInfo android.ApexInfo) bool {
+ if _, _, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo); ok {
return ctx.Config().VndkSnapshotBuildArtifacts()
- } else if isVendorSnapshotModule(m, isVendorProprietaryPath(ctx.ModuleDir()), apexInfo) ||
- isRecoverySnapshotModule(m, isVendorProprietaryPath(ctx.ModuleDir()), apexInfo) {
+ } else if isVendorSnapshotAware(m, isVendorProprietaryPath(ctx.ModuleDir()), apexInfo) ||
+ isRecoverySnapshotAware(m, isRecoveryProprietaryPath(ctx.ModuleDir()), apexInfo) {
return true
}
return false
}
-
-func copyFile(ctx android.SingletonContext, path android.Path, out string) android.OutputPath {
- outPath := android.PathForOutput(ctx, out)
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cp,
- Input: path,
- Output: outPath,
- Description: "Cp " + out,
- Args: map[string]string{
- "cpFlags": "-f -L",
- },
- })
- return outPath
-}
-
-func combineNotices(ctx android.SingletonContext, paths android.Paths, out string) android.OutputPath {
- outPath := android.PathForOutput(ctx, out)
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cat,
- Inputs: paths,
- Output: outPath,
- Description: "combine notices for " + out,
- })
- return outPath
-}
-
-func writeStringToFile(ctx android.SingletonContext, content, out string) android.OutputPath {
- outPath := android.PathForOutput(ctx, out)
- android.WriteFileRule(ctx, outPath, content)
- return outPath
-}
diff --git a/cc/testing.go b/cc/testing.go
index 85f12b7..fc5b030 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -335,7 +335,7 @@
},
apex_available: [
"//apex_available:platform",
- "myapex"
+ "//apex_available:anyapex",
],
}
cc_library {
diff --git a/cc/util.go b/cc/util.go
index 40374bf..1220d84 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -125,3 +125,52 @@
return "mkdir -p " + dir + " && " +
"ln -sf " + target + " " + filepath.Join(dir, linkName)
}
+
+func copyFileRule(ctx android.SingletonContext, path android.Path, out string) android.OutputPath {
+ outPath := android.PathForOutput(ctx, out)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: path,
+ Output: outPath,
+ Description: "copy " + path.String() + " -> " + out,
+ Args: map[string]string{
+ "cpFlags": "-f -L",
+ },
+ })
+ return outPath
+}
+
+func combineNoticesRule(ctx android.SingletonContext, paths android.Paths, out string) android.OutputPath {
+ outPath := android.PathForOutput(ctx, out)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cat,
+ Inputs: paths,
+ Output: outPath,
+ Description: "combine notices for " + out,
+ })
+ return outPath
+}
+
+func writeStringToFileRule(ctx android.SingletonContext, content, out string) android.OutputPath {
+ outPath := android.PathForOutput(ctx, out)
+ android.WriteFileRule(ctx, outPath, content)
+ return outPath
+}
+
+// Dump a map to a list file as:
+//
+// {key1} {value1}
+// {key2} {value2}
+// ...
+func installMapListFileRule(ctx android.SingletonContext, m map[string]string, path string) android.OutputPath {
+ var txtBuilder strings.Builder
+ for idx, k := range android.SortedStringKeys(m) {
+ if idx > 0 {
+ txtBuilder.WriteString("\n")
+ }
+ txtBuilder.WriteString(k)
+ txtBuilder.WriteString(" ")
+ txtBuilder.WriteString(m[k])
+ }
+ return writeStringToFileRule(ctx, txtBuilder.String(), path)
+}
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 3ef0b62..da37d0f 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -13,625 +13,27 @@
// limitations under the License.
package cc
+// This file contains singletons to capture vendor and recovery snapshot. They consist of prebuilt
+// modules under AOSP so older vendor and recovery can be built with a newer system in a single
+// source tree.
+
import (
"encoding/json"
"path/filepath"
"sort"
"strings"
- "sync"
"github.com/google/blueprint/proptools"
"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."
- vendorSnapshotStaticSuffix = ".vendor_static."
- vendorSnapshotBinarySuffix = ".vendor_binary."
- 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")
- vendorSnapshotHeaderLibsKey = android.NewOnceKey("vendorSnapshotHeaderLibs")
- vendorSnapshotStaticLibsKey = android.NewOnceKey("vendorSnapshotStaticLibs")
- vendorSnapshotSharedLibsKey = android.NewOnceKey("vendorSnapshotSharedLibs")
- vendorSnapshotBinariesKey = android.NewOnceKey("vendorSnapshotBinaries")
- vendorSnapshotObjectsKey = android.NewOnceKey("vendorSnapshotObjects")
-)
-
-// vendor snapshot maps hold names of vendor snapshot modules per arch
-func vendorSuffixModules(config android.Config) map[string]bool {
- return config.Once(vendorSuffixModulesKey, func() interface{} {
- return make(map[string]bool)
- }).(map[string]bool)
-}
-
-func vendorSnapshotHeaderLibs(config android.Config) *snapshotMap {
- return config.Once(vendorSnapshotHeaderLibsKey, func() interface{} {
- return newSnapshotMap()
- }).(*snapshotMap)
-}
-
-func vendorSnapshotSharedLibs(config android.Config) *snapshotMap {
- return config.Once(vendorSnapshotSharedLibsKey, func() interface{} {
- return newSnapshotMap()
- }).(*snapshotMap)
-}
-
-func vendorSnapshotStaticLibs(config android.Config) *snapshotMap {
- return config.Once(vendorSnapshotStaticLibsKey, func() interface{} {
- return newSnapshotMap()
- }).(*snapshotMap)
-}
-
-func vendorSnapshotBinaries(config android.Config) *snapshotMap {
- return config.Once(vendorSnapshotBinariesKey, func() interface{} {
- return newSnapshotMap()
- }).(*snapshotMap)
-}
-
-func vendorSnapshotObjects(config android.Config) *snapshotMap {
- return config.Once(vendorSnapshotObjectsKey, func() interface{} {
- return newSnapshotMap()
- }).(*snapshotMap)
-}
-
-type vendorSnapshotBaseProperties struct {
- // snapshot version.
- Version string
-
- // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64')
- Target_arch string
-}
-
-// vendorSnapshotModuleBase provides common basic functions for all snapshot modules.
-type vendorSnapshotModuleBase struct {
- baseProperties vendorSnapshotBaseProperties
- moduleSuffix string
-}
-
-func (p *vendorSnapshotModuleBase) Name(name string) string {
- return name + p.NameSuffix()
-}
-
-func (p *vendorSnapshotModuleBase) NameSuffix() string {
- versionSuffix := p.version()
- if p.arch() != "" {
- versionSuffix += "." + p.arch()
- }
-
- return p.moduleSuffix + versionSuffix
-}
-
-func (p *vendorSnapshotModuleBase) version() string {
- return p.baseProperties.Version
-}
-
-func (p *vendorSnapshotModuleBase) arch() string {
- return p.baseProperties.Target_arch
-}
-
-func (p *vendorSnapshotModuleBase) isSnapshotPrebuilt() bool {
- return true
-}
-
-// Call this after creating a snapshot module with module suffix
-// such as vendorSnapshotSharedSuffix
-func (p *vendorSnapshotModuleBase) init(m *Module, suffix string) {
- p.moduleSuffix = suffix
- m.AddProperties(&p.baseProperties)
- android.AddLoadHook(m, func(ctx android.LoadHookContext) {
- vendorSnapshotLoadHook(ctx, p)
- })
-}
-
-func vendorSnapshotLoadHook(ctx android.LoadHookContext, p *vendorSnapshotModuleBase) {
- if p.version() != ctx.DeviceConfig().VndkVersion() {
- ctx.Module().Disable()
- return
- }
-}
-
-type snapshotLibraryProperties struct {
- // Prebuilt file for each arch.
- Src *string `android:"arch_variant"`
-
- // list of directories that will be added to the include path (using -I).
- Export_include_dirs []string `android:"arch_variant"`
-
- // list of directories that will be added to the system path (using -isystem).
- Export_system_include_dirs []string `android:"arch_variant"`
-
- // list of flags that will be used for any module that links against this module.
- Export_flags []string `android:"arch_variant"`
-
- // Whether this prebuilt needs to depend on sanitize ubsan runtime or not.
- Sanitize_ubsan_dep *bool `android:"arch_variant"`
-
- // Whether this prebuilt needs to depend on sanitize minimal runtime or not.
- Sanitize_minimal_dep *bool `android:"arch_variant"`
-}
-
-type snapshotSanitizer interface {
- isSanitizerEnabled(t sanitizerType) bool
- setSanitizerVariation(t sanitizerType, enabled bool)
-}
-
-type snapshotLibraryDecorator struct {
- vendorSnapshotModuleBase
- *libraryDecorator
- properties snapshotLibraryProperties
- sanitizerProperties struct {
- CfiEnabled bool `blueprint:"mutated"`
-
- // Library flags for cfi variant.
- Cfi snapshotLibraryProperties `android:"arch_variant"`
- }
- androidMkVendorSuffix bool
-}
-
-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 *snapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
- arches := config.Arches()
- if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
- return false
- }
- if !p.header() && p.properties.Src == nil {
- return false
- }
- return true
-}
-
-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()]
-
- if p.header() {
- return p.libraryDecorator.link(ctx, flags, deps, objs)
- }
-
- if p.sanitizerProperties.CfiEnabled {
- p.properties = p.sanitizerProperties.Cfi
- }
-
- if !p.matchesWithDevice(ctx.DeviceConfig()) {
- return nil
- }
-
- 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...)
-
- in := android.PathForModuleSrc(ctx, *p.properties.Src)
- p.unstrippedOutputFile = in
-
- if p.shared() {
- libName := in.Base()
- builderFlags := flagsToBuilderFlags(flags)
-
- // Optimize out relinking against shared libraries whose interface hasn't changed by
- // depending on a table of contents file instead of the library itself.
- tocFile := android.PathForModuleOut(ctx, libName+".toc")
- p.tocFile = android.OptionalPathForPath(tocFile)
- transformSharedObjectToToc(ctx, in, tocFile, builderFlags)
-
- ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
- SharedLibrary: in,
- UnstrippedSharedLibrary: p.unstrippedOutputFile,
-
- TableOfContents: p.tocFile,
- })
- }
-
- if p.static() {
- depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(in).Build()
- ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
- StaticLibrary: in,
-
- TransitiveStaticLibrariesForOrdering: depSet,
- })
- }
-
- p.libraryDecorator.flagExporter.setProvider(ctx)
-
- return in
-}
-
-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 *snapshotLibraryDecorator) nativeCoverage() bool {
- return false
-}
-
-func (p *snapshotLibraryDecorator) isSanitizerEnabled(t sanitizerType) bool {
- switch t {
- case cfi:
- return p.sanitizerProperties.Cfi.Src != nil
- default:
- return false
- }
-}
-
-func (p *snapshotLibraryDecorator) setSanitizerVariation(t sanitizerType, enabled bool) {
- if !enabled {
- return
- }
- switch t {
- case cfi:
- p.sanitizerProperties.CfiEnabled = true
- default:
- return
- }
-}
-
-func snapshotLibrary(suffix string) (*Module, *snapshotLibraryDecorator) {
- module, library := NewLibrary(android.DeviceSupported)
-
- module.stl = nil
- module.sanitize = nil
- library.disableStripping()
-
- prebuilt := &snapshotLibraryDecorator{
- libraryDecorator: library,
- }
-
- prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true)
- prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true)
-
- // Prevent default system libs (libc, libm, and libdl) from being linked
- if prebuilt.baseLinker.Properties.System_shared_libs == nil {
- prebuilt.baseLinker.Properties.System_shared_libs = []string{}
- }
-
- module.compiler = nil
- module.linker = prebuilt
- module.installer = prebuilt
-
- prebuilt.init(module, suffix)
- module.AddProperties(
- &prebuilt.properties,
- &prebuilt.sanitizerProperties,
- )
-
- return module, prebuilt
-}
-
-func VendorSnapshotSharedFactory() android.Module {
- 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 := 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 := snapshotLibrary(vendorSnapshotHeaderSuffix)
- prebuilt.libraryDecorator.HeaderOnly()
- return module.Init()
-}
-
-func RecoverySnapshotHeaderFactory() android.Module {
- module, prebuilt := snapshotLibrary(recoverySnapshotHeaderSuffix)
- prebuilt.libraryDecorator.HeaderOnly()
- return module.Init()
-}
-
-var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
-
-type snapshotBinaryProperties struct {
- // Prebuilt file for each arch.
- Src *string `android:"arch_variant"`
-}
-
-type snapshotBinaryDecorator struct {
- vendorSnapshotModuleBase
- *binaryDecorator
- properties snapshotBinaryProperties
- androidMkVendorSuffix bool
-}
-
-func (p *snapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
- if config.DeviceArch() != p.arch() {
- return false
- }
- if p.properties.Src == nil {
- return false
- }
- return true
-}
-
-func (p *snapshotBinaryDecorator) link(ctx ModuleContext,
- flags Flags, deps PathDeps, objs Objects) android.Path {
- if !p.matchesWithDevice(ctx.DeviceConfig()) {
- return nil
- }
-
- in := android.PathForModuleSrc(ctx, *p.properties.Src)
- stripFlags := flagsToStripFlags(flags)
- p.unstrippedOutputFile = in
- binName := in.Base()
- if p.stripper.NeedsStrip(ctx) {
- stripped := android.PathForModuleOut(ctx, "stripped", binName)
- p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags)
- in = stripped
- }
-
- m := ctx.Module().(*Module)
- p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
-
- // use cpExecutable to make it executable
- outputFile := android.PathForModuleOut(ctx, binName)
- ctx.Build(pctx, android.BuildParams{
- Rule: android.CpExecutable,
- Description: "prebuilt",
- Output: outputFile,
- Input: in,
- })
-
- return outputFile
-}
-
-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)
-
- // Prevent default system libs (libc, libm, and libdl) from being linked
- if binary.baseLinker.Properties.System_shared_libs == nil {
- binary.baseLinker.Properties.System_shared_libs = []string{}
- }
-
- prebuilt := &snapshotBinaryDecorator{
- binaryDecorator: binary,
- }
-
- module.compiler = nil
- module.sanitize = nil
- module.stl = nil
- module.linker = prebuilt
-
- prebuilt.init(module, suffix)
- module.AddProperties(&prebuilt.properties)
- return module.Init()
-}
-
-type vendorSnapshotObjectProperties struct {
- // Prebuilt file for each arch.
- Src *string `android:"arch_variant"`
-}
-
-type snapshotObjectLinker struct {
- vendorSnapshotModuleBase
- objectLinker
- properties vendorSnapshotObjectProperties
- androidMkVendorSuffix bool
-}
-
-func (p *snapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool {
- if config.DeviceArch() != p.arch() {
- return false
- }
- if p.properties.Src == nil {
- return false
- }
- return true
-}
-
-func (p *snapshotObjectLinker) link(ctx ModuleContext,
- flags Flags, deps PathDeps, objs Objects) android.Path {
- if !p.matchesWithDevice(ctx.DeviceConfig()) {
- return nil
- }
-
- m := ctx.Module().(*Module)
- p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
-
- return android.PathForModuleSrc(ctx, *p.properties.Src)
-}
-
-func (p *snapshotObjectLinker) nativeCoverage() bool {
- return false
-}
-
-func VendorSnapshotObjectFactory() android.Module {
- module := newObject()
-
- prebuilt := &snapshotObjectLinker{
- objectLinker: objectLinker{
- baseLinker: NewBaseLinker(nil),
- },
- }
- module.linker = prebuilt
-
- prebuilt.init(module, vendorSnapshotObjectSuffix)
- module.AddProperties(&prebuilt.properties)
- 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() {
- vendorImageSingleton.init()
- recoveryImageSingleton.init()
-}
-
var vendorSnapshotSingleton = snapshotSingleton{
"vendor",
"SOONG_VENDOR_SNAPSHOT_ZIP",
android.OptionalPath{},
true,
- vendorImageSingleton,
+ vendorSnapshotImageSingleton,
}
var recoverySnapshotSingleton = snapshotSingleton{
@@ -639,7 +41,7 @@
"SOONG_RECOVERY_SNAPSHOT_ZIP",
android.OptionalPath{},
false,
- recoveryImageSingleton,
+ recoverySnapshotImageSingleton,
}
func VendorSnapshotSingleton() android.Singleton {
@@ -667,13 +69,12 @@
// 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
+ image snapshotImage
}
var (
// 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
vendorProprietaryDirs = []string{
"device",
"kernel",
@@ -683,7 +84,6 @@
// 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",
@@ -694,7 +94,6 @@
// 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
aospDirsUnderProprietary = []string{
"kernel/configs",
"kernel/prebuilts",
@@ -738,10 +137,8 @@
}
func isVendorProprietaryModule(ctx android.BaseModuleContext) bool {
-
// Any module in a vendor proprietary path is a vendor proprietary
// module.
-
if isVendorProprietaryPath(ctx.ModuleDir()) {
return true
}
@@ -750,7 +147,6 @@
// still be a vendor proprietary module. This happens for cc modules
// that are excluded from the vendor snapshot, and it means that the
// vendor has assumed control of the framework-provided module.
-
if c, ok := ctx.Module().(*Module); ok {
if c.ExcludeFromVendorSnapshot() {
return true
@@ -766,15 +162,21 @@
// AOSP. They are not guaranteed to be compatible with older vendor images. (e.g. might
// 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 isVendorSnapshotAware(m *Module, inVendorProprietaryPath bool, apexInfo android.ApexInfo) bool {
+ return isSnapshotAware(m, inVendorProprietaryPath, apexInfo, vendorSnapshotImageSingleton)
}
-func isRecoverySnapshotModule(m *Module, inRecoveryProprietaryPath bool, apexInfo android.ApexInfo) bool {
- return isSnapshotModule(m, inRecoveryProprietaryPath, apexInfo, recoveryImageSingleton)
+// Determine if a module is going to be included in recovery snapshot or not.
+//
+// Targets of recovery snapshot are "recovery: true" or "recovery_available: true"
+// modules in AOSP. They are not guaranteed to be compatible with older recovery images.
+// So they are captured as recovery snapshot To build older recovery image.
+func isRecoverySnapshotAware(m *Module, inRecoveryProprietaryPath bool, apexInfo android.ApexInfo) bool {
+ return isSnapshotAware(m, inRecoveryProprietaryPath, apexInfo, recoverySnapshotImageSingleton)
}
-func isSnapshotModule(m *Module, inProprietaryPath bool, apexInfo android.ApexInfo, image image) bool {
+// Determines if the module is a candidate for snapshot.
+func isSnapshotAware(m *Module, inProprietaryPath bool, apexInfo android.ApexInfo, image snapshotImage) bool {
if !m.Enabled() || m.Properties.HideFromMake {
return false
}
@@ -799,7 +201,7 @@
if m.Target().NativeBridge == android.NativeBridgeEnabled {
return false
}
- // the module must be installed in /vendor
+ // the module must be installed in target image
if !apexInfo.IsForPlatform() || m.isSnapshotPrebuilt() || !image.inImage(m)() {
return false
}
@@ -817,7 +219,6 @@
// Libraries
if l, ok := m.linker.(snapshotLibraryInterface); ok {
- // TODO(b/65377115): add full support for sanitizer
if m.sanitize != nil {
// scs and hwasan export both sanitized and unsanitized variants for static and header
// Always use unsanitized variants of them.
@@ -827,6 +228,8 @@
}
}
// cfi also exports both variants. But for static, we capture both.
+ // This is because cfi static libraries can't be linked from non-cfi modules,
+ // and vice versa. This isn't the case for scs and hwasan sanitizers.
if !l.static() && !l.shared() && m.sanitize.isSanitizerEnabled(cfi) {
return false
}
@@ -842,7 +245,7 @@
if !m.IsVndk() {
return true
}
- return m.isVndkExt()
+ return m.IsVndkExt()
}
}
return true
@@ -856,6 +259,33 @@
return false
}
+// This is to be saved as .json files, which is for development/vendor_snapshot/update.py.
+// These flags become Android.bp snapshot module properties.
+type snapshotJsonFlags struct {
+ ModuleName string `json:",omitempty"`
+ RelativeInstallPath string `json:",omitempty"`
+
+ // library flags
+ ExportedDirs []string `json:",omitempty"`
+ ExportedSystemDirs []string `json:",omitempty"`
+ ExportedFlags []string `json:",omitempty"`
+ Sanitize string `json:",omitempty"`
+ SanitizeMinimalDep bool `json:",omitempty"`
+ SanitizeUbsanDep bool `json:",omitempty"`
+
+ // binary flags
+ Symlinks []string `json:",omitempty"`
+
+ // dependencies
+ SharedLibs []string `json:",omitempty"`
+ RuntimeLibs []string `json:",omitempty"`
+ Required []string `json:",omitempty"`
+
+ // extra config files
+ InitRc []string `json:",omitempty"`
+ VintfFragments []string `json:",omitempty"`
+}
+
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" {
@@ -909,6 +339,8 @@
var headers android.Paths
+ // installSnapshot function copies prebuilt file (.so, .a, or executable) and json flag file.
+ // For executables, init_rc and vintf_fragments files are also copied.
installSnapshot := func(m *Module) android.Paths {
targetArch := "arch-" + m.Target().Arch.ArchType.String()
if m.Target().Arch.ArchVariant != "" {
@@ -917,34 +349,11 @@
var ret android.Paths
- prop := struct {
- ModuleName string `json:",omitempty"`
- RelativeInstallPath string `json:",omitempty"`
-
- // library flags
- ExportedDirs []string `json:",omitempty"`
- ExportedSystemDirs []string `json:",omitempty"`
- ExportedFlags []string `json:",omitempty"`
- Sanitize string `json:",omitempty"`
- SanitizeMinimalDep bool `json:",omitempty"`
- SanitizeUbsanDep bool `json:",omitempty"`
-
- // binary flags
- Symlinks []string `json:",omitempty"`
-
- // dependencies
- SharedLibs []string `json:",omitempty"`
- RuntimeLibs []string `json:",omitempty"`
- Required []string `json:",omitempty"`
-
- // extra config files
- InitRc []string `json:",omitempty"`
- VintfFragments []string `json:",omitempty"`
- }{}
+ prop := snapshotJsonFlags{}
// Common properties among snapshots.
prop.ModuleName = ctx.ModuleName(m)
- if c.supportsVndkExt && m.isVndkExt() {
+ if c.supportsVndkExt && m.IsVndkExt() {
// vndk exts are installed to /vendor/lib(64)?/vndk(-sp)?
if m.isVndkSp() {
prop.RelativeInstallPath = "vndk-sp"
@@ -968,7 +377,7 @@
out := filepath.Join(configsDir, path.Base())
if !installedConfigs[out] {
installedConfigs[out] = true
- ret = append(ret, copyFile(ctx, path, out))
+ ret = append(ret, copyFileRule(ctx, path, out))
}
}
@@ -1019,7 +428,7 @@
prop.ModuleName += ".cfi"
}
snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem)
- ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
+ ret = append(ret, copyFileRule(ctx, libPath, snapshotLibOut))
} else {
stem = ctx.ModuleName(m)
}
@@ -1033,7 +442,7 @@
// install bin
binPath := m.outputFile.Path()
snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base())
- ret = append(ret, copyFile(ctx, binPath, snapshotBinOut))
+ ret = append(ret, copyFileRule(ctx, binPath, snapshotBinOut))
propOut = snapshotBinOut + ".json"
} else if m.object() {
// object files aren't installed to the device, so their names can conflict.
@@ -1041,7 +450,7 @@
objPath := m.outputFile.Path()
snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object",
ctx.ModuleName(m)+filepath.Ext(objPath.Base()))
- ret = append(ret, copyFile(ctx, objPath, snapshotObjOut))
+ ret = append(ret, copyFileRule(ctx, objPath, snapshotObjOut))
propOut = snapshotObjOut + ".json"
} else {
ctx.Errorf("unknown module %q in vendor snapshot", m.String())
@@ -1053,7 +462,7 @@
ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
return nil
}
- ret = append(ret, writeStringToFile(ctx, string(j), propOut))
+ ret = append(ret, writeStringToFileRule(ctx, string(j), propOut))
return ret
}
@@ -1088,11 +497,14 @@
}
}
- if !isSnapshotModule(m, inProprietaryPath, apexInfo, c.image) {
+ if !isSnapshotAware(m, inProprietaryPath, apexInfo, c.image) {
return
}
+ // installSnapshot installs prebuilts and json flag files
snapshotOutputs = append(snapshotOutputs, installSnapshot(m)...)
+
+ // just gather headers and notice files here, because they are to be deduplicated
if l, ok := m.linker.(snapshotLibraryInterface); ok {
headers = append(headers, l.snapshotHeaders()...)
}
@@ -1103,7 +515,7 @@
// skip already copied notice file
if !installedNotices[noticeOut] {
installedNotices[noticeOut] = true
- snapshotOutputs = append(snapshotOutputs, combineNotices(
+ snapshotOutputs = append(snapshotOutputs, combineNoticesRule(
ctx, m.NoticeFiles(), noticeOut))
}
}
@@ -1111,7 +523,7 @@
// install all headers after removing duplicates
for _, header := range android.FirstUniquePaths(headers) {
- snapshotOutputs = append(snapshotOutputs, copyFile(
+ snapshotOutputs = append(snapshotOutputs, copyFileRule(
ctx, header, filepath.Join(includeDir, header.String())))
}
@@ -1155,141 +567,3 @@
c.makeVar,
c.snapshotZipFile.String())
}
-
-type snapshotInterface interface {
- matchesWithDevice(config android.DeviceConfig) bool
-}
-
-var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(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
-func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) {
- vndkVersion := ctx.DeviceConfig().VndkVersion()
- // don't need snapshot if current
- if vndkVersion == "current" || vndkVersion == "" {
- return
- }
-
- module, ok := ctx.Module().(*Module)
- if !ok || !module.Enabled() || module.VndkVersion() != vndkVersion {
- return
- }
-
- if !module.isSnapshotPrebuilt() {
- return
- }
-
- // isSnapshotPrebuilt ensures snapshotInterface
- if !module.linker.(snapshotInterface).matchesWithDevice(ctx.DeviceConfig()) {
- // Disable unnecessary snapshot module, but do not disable
- // vndk_prebuilt_shared because they might be packed into vndk APEX
- if !module.IsVndk() {
- module.Disable()
- }
- return
- }
-
- var snapshotMap *snapshotMap
-
- if lib, ok := module.linker.(libraryInterface); ok {
- if lib.static() {
- snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
- } else if lib.shared() {
- snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
- } else {
- // header
- snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
- }
- } else if _, ok := module.linker.(*snapshotBinaryDecorator); ok {
- snapshotMap = vendorSnapshotBinaries(ctx.Config())
- } else if _, ok := module.linker.(*snapshotObjectLinker); ok {
- snapshotMap = vendorSnapshotObjects(ctx.Config())
- } else {
- return
- }
-
- vendorSnapshotsLock.Lock()
- defer vendorSnapshotsLock.Unlock()
- snapshotMap.add(module.BaseModuleName(), ctx.Arch().ArchType, ctx.ModuleName())
-}
-
-// Disables source modules which have snapshots
-func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) {
- if !ctx.Device() {
- return
- }
-
- vndkVersion := ctx.DeviceConfig().VndkVersion()
- // don't need snapshot if current
- if vndkVersion == "current" || vndkVersion == "" {
- return
- }
-
- module, ok := ctx.Module().(*Module)
- if !ok {
- return
- }
-
- // vendor suffix should be added to snapshots if the source module isn't vendor: true.
- if !module.SocSpecific() {
- // But we can't just check SocSpecific() since we already passed the image mutator.
- // Check ramdisk and recovery to see if we are real "vendor: true" module.
- ramdisk_available := module.InRamdisk() && !module.OnlyInRamdisk()
- vendor_ramdisk_available := module.InVendorRamdisk() && !module.OnlyInVendorRamdisk()
- recovery_available := module.InRecovery() && !module.OnlyInRecovery()
-
- if !ramdisk_available && !recovery_available && !vendor_ramdisk_available {
- vendorSnapshotsLock.Lock()
- defer vendorSnapshotsLock.Unlock()
-
- vendorSuffixModules(ctx.Config())[ctx.ModuleName()] = true
- }
- }
-
- if module.isSnapshotPrebuilt() || module.VndkVersion() != ctx.DeviceConfig().VndkVersion() {
- // only non-snapshot modules with BOARD_VNDK_VERSION
- return
- }
-
- // .. and also filter out llndk library
- if module.isLlndk(ctx.Config()) {
- return
- }
-
- var snapshotMap *snapshotMap
-
- if lib, ok := module.linker.(libraryInterface); ok {
- if lib.static() {
- snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
- } else if lib.shared() {
- snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
- } else {
- // header
- snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
- }
- } else if module.binary() {
- snapshotMap = vendorSnapshotBinaries(ctx.Config())
- } else if module.object() {
- snapshotMap = vendorSnapshotObjects(ctx.Config())
- } else {
- return
- }
-
- if _, ok := snapshotMap.get(ctx.ModuleName(), ctx.Arch().ArchType); !ok {
- // Corresponding snapshot doesn't exist
- return
- }
-
- // Disables source modules if corresponding snapshot exists.
- if lib, ok := module.linker.(libraryInterface); ok && lib.buildStatic() && lib.buildShared() {
- // But do not disable because the shared variant depends on the static variant.
- module.SkipInstall()
- module.Properties.HideFromMake = true
- } else {
- module.Disable()
- }
-}
diff --git a/cc/vndk.go b/cc/vndk.go
index d57cdf7..1529ac5 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -389,7 +389,7 @@
useCoreVariant := m.VndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() &&
mctx.DeviceConfig().VndkUseCoreVariant() && !m.MustUseVendorVariant()
- return lib.shared() && m.inVendor() && m.IsVndk() && !m.isVndkExt() && !useCoreVariant
+ return lib.shared() && m.inVendor() && m.IsVndk() && !m.IsVndkExt() && !useCoreVariant
}
return false
}
@@ -533,7 +533,7 @@
vndkSnapshotZipFile android.OptionalPath
}
-func isVndkSnapshotLibrary(config android.DeviceConfig, m *Module,
+func isVndkSnapshotAware(config android.DeviceConfig, m *Module,
apexInfo android.ApexInfo) (i snapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
if m.Target().NativeBridge == android.NativeBridgeEnabled {
@@ -549,7 +549,7 @@
if !ok || !l.shared() {
return nil, "", false
}
- if m.VndkVersion() == config.PlatformVndkVersion() && m.IsVndk() && !m.isVndkExt() {
+ if m.VndkVersion() == config.PlatformVndkVersion() && m.IsVndk() && !m.IsVndkExt() {
if m.isVndkSp() {
return l, "vndk-sp", true
} else {
@@ -622,6 +622,9 @@
var headers android.Paths
+ // installVndkSnapshotLib copies built .so file from the module.
+ // Also, if the build artifacts is on, write a json file which contains all exported flags
+ // with FlagExporterInfo.
installVndkSnapshotLib := func(m *Module, vndkType string) (android.Paths, bool) {
var ret android.Paths
@@ -632,7 +635,7 @@
libPath := m.outputFile.Path()
snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "shared", vndkType, libPath.Base())
- ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
+ ret = append(ret, copyFileRule(ctx, libPath, snapshotLibOut))
if ctx.Config().VndkSnapshotBuildArtifacts() {
prop := struct {
@@ -654,7 +657,7 @@
ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
return nil, false
}
- ret = append(ret, writeStringToFile(ctx, string(j), propOut))
+ ret = append(ret, writeStringToFileRule(ctx, string(j), propOut))
}
return ret, true
}
@@ -667,11 +670,21 @@
apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
- l, vndkType, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m, apexInfo)
+ l, vndkType, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo)
if !ok {
return
}
+ // For all snapshot candidates, the followings are captured.
+ // - .so files
+ // - notice files
+ //
+ // The followings are also captured if VNDK_SNAPSHOT_BUILD_ARTIFACTS.
+ // - .json files containing exported flags
+ // - exported headers from collectHeadersForSnapshot()
+ //
+ // Headers are deduplicated after visiting all modules.
+
// install .so files for appropriate modules.
// Also install .json files if VNDK_SNAPSHOT_BUILD_ARTIFACTS
libs, ok := installVndkSnapshotLib(m, vndkType)
@@ -690,7 +703,7 @@
// skip already copied notice file
if _, ok := noticeBuilt[noticeName]; !ok {
noticeBuilt[noticeName] = true
- snapshotOutputs = append(snapshotOutputs, combineNotices(
+ snapshotOutputs = append(snapshotOutputs, combineNoticesRule(
ctx, m.NoticeFiles(), filepath.Join(noticeDir, noticeName)))
}
}
@@ -702,7 +715,7 @@
// install all headers after removing duplicates
for _, header := range android.FirstUniquePaths(headers) {
- snapshotOutputs = append(snapshotOutputs, copyFile(
+ snapshotOutputs = append(snapshotOutputs, copyFileRule(
ctx, header, filepath.Join(includeDir, header.String())))
}
@@ -712,38 +725,18 @@
if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt {
return
}
- snapshotOutputs = append(snapshotOutputs, copyFile(
+ snapshotOutputs = append(snapshotOutputs, copyFileRule(
ctx, m.OutputFile(), filepath.Join(configsDir, m.Name())))
})
/*
- Dump a map to a list file as:
-
- {key1} {value1}
- {key2} {value2}
- ...
- */
- installMapListFile := func(m map[string]string, path string) android.OutputPath {
- var txtBuilder strings.Builder
- for idx, k := range android.SortedStringKeys(m) {
- if idx > 0 {
- txtBuilder.WriteString("\n")
- }
- txtBuilder.WriteString(k)
- txtBuilder.WriteString(" ")
- txtBuilder.WriteString(m[k])
- }
- return writeStringToFile(ctx, txtBuilder.String(), path)
- }
-
- /*
module_paths.txt contains paths on which VNDK modules are defined.
e.g.,
libbase.so system/libbase
libc.so bionic/libc
...
*/
- snapshotOutputs = append(snapshotOutputs, installMapListFile(modulePaths, filepath.Join(configsDir, "module_paths.txt")))
+ snapshotOutputs = append(snapshotOutputs, installMapListFileRule(ctx, modulePaths, filepath.Join(configsDir, "module_paths.txt")))
/*
module_names.txt contains names as which VNDK modules are defined,
@@ -754,7 +747,7 @@
libprotobuf-cpp-full-3.9.2.so libprotobuf-cpp-full
...
*/
- snapshotOutputs = append(snapshotOutputs, installMapListFile(moduleNames, filepath.Join(configsDir, "module_names.txt")))
+ snapshotOutputs = append(snapshotOutputs, installMapListFileRule(ctx, moduleNames, filepath.Join(configsDir, "module_names.txt")))
// All artifacts are ready. Sort them to normalize ninja and then zip.
sort.Slice(snapshotOutputs, func(i, j int) bool {
@@ -764,7 +757,7 @@
zipPath := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+".zip")
zipRule := android.NewRuleBuilder(pctx, ctx)
- // filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with xargs
+ // filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr
snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+"_list")
zipRule.Command().
Text("tr").
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 0a9b156..c079e83 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -185,7 +185,11 @@
Status: stat,
}}
- config := build.NewConfig(buildCtx)
+ args := ""
+ if *alternateResultDir {
+ args = "dist"
+ }
+ config := build.NewConfig(buildCtx, args)
if *outDir == "" {
name := "multiproduct"
if !*incremental {
@@ -212,15 +216,10 @@
os.MkdirAll(logsDir, 0777)
build.SetupOutDir(buildCtx, config)
- if *alternateResultDir {
- distLogsDir := filepath.Join(config.DistDir(), "logs")
- os.MkdirAll(distLogsDir, 0777)
- log.SetOutput(filepath.Join(distLogsDir, "soong.log"))
- trace.SetOutput(filepath.Join(distLogsDir, "build.trace"))
- } else {
- log.SetOutput(filepath.Join(config.OutDir(), "soong.log"))
- trace.SetOutput(filepath.Join(config.OutDir(), "build.trace"))
- }
+
+ os.MkdirAll(config.LogsDir(), 0777)
+ log.SetOutput(filepath.Join(config.LogsDir(), "soong.log"))
+ trace.SetOutput(filepath.Join(config.LogsDir(), "build.trace"))
var jobs = *numJobs
if jobs < 1 {
@@ -344,7 +343,7 @@
FileArgs: []zip.FileArg{
{GlobDir: logsDir, SourcePrefixToStrip: logsDir},
},
- OutputFilePath: filepath.Join(config.DistDir(), "logs.zip"),
+ OutputFilePath: filepath.Join(config.RealDistDir(), "logs.zip"),
NumParallelJobs: runtime.NumCPU(),
CompressionLevel: 5,
}
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 4ffe944..bd1d450 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -18,6 +18,7 @@
"context"
"flag"
"fmt"
+ "io/ioutil"
"os"
"path/filepath"
"strconv"
@@ -173,13 +174,18 @@
build.SetupOutDir(buildCtx, config)
+ if config.UseBazel() {
+ defer populateExternalDistDir(buildCtx, config)
+ }
+
// Set up files to be outputted in the log directory.
logsDir := config.LogsDir()
+ // Common list of metric file definition.
buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error")
rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
- defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, buildErrorFile, rbeMetricsFile, soongMetricsFile)
+
build.PrintOutDirWarning(buildCtx, config)
os.MkdirAll(logsDir, 0777)
@@ -195,8 +201,22 @@
buildCtx.Verbosef("Parallelism (local/remote/highmem): %v/%v/%v",
config.Parallel(), config.RemoteParallel(), config.HighmemParallel())
- defer met.Dump(soongMetricsFile)
- defer build.DumpRBEMetrics(buildCtx, config, rbeMetricsFile)
+ {
+ // The order of the function calls is important. The last defer function call
+ // is the first one that is executed to save the rbe metrics to a protobuf
+ // file. The soong metrics file is then next. Bazel profiles are written
+ // before the uploadMetrics is invoked. The written files are then uploaded
+ // if the uploading of the metrics is enabled.
+ files := []string{
+ buildErrorFile, // build error strings
+ rbeMetricsFile, // high level metrics related to remote build execution.
+ soongMetricsFile, // high level metrics related to this build system.
+ config.BazelMetricsDir(), // directory that contains a set of bazel metrics.
+ }
+ defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, files...)
+ defer met.Dump(soongMetricsFile)
+ defer build.DumpRBEMetrics(buildCtx, config, rbeMetricsFile)
+ }
// Read the time at the starting point.
if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
@@ -510,3 +530,72 @@
// command not found
return nil, nil, fmt.Errorf("Command not found: %q", args)
}
+
+// For Bazel support, this moves files and directories from e.g. out/dist/$f to DIST_DIR/$f if necessary.
+func populateExternalDistDir(ctx build.Context, config build.Config) {
+ // Make sure that internalDistDirPath and externalDistDirPath are both absolute paths, so we can compare them
+ var err error
+ var internalDistDirPath string
+ var externalDistDirPath string
+ if internalDistDirPath, err = filepath.Abs(config.DistDir()); err != nil {
+ ctx.Fatalf("Unable to find absolute path of %s: %s", internalDistDirPath, err)
+ }
+ if externalDistDirPath, err = filepath.Abs(config.RealDistDir()); err != nil {
+ ctx.Fatalf("Unable to find absolute path of %s: %s", externalDistDirPath, err)
+ }
+ if externalDistDirPath == internalDistDirPath {
+ return
+ }
+
+ // Make sure the external DIST_DIR actually exists before trying to write to it
+ if err = os.MkdirAll(externalDistDirPath, 0755); err != nil {
+ ctx.Fatalf("Unable to make directory %s: %s", externalDistDirPath, err)
+ }
+
+ ctx.Println("Populating external DIST_DIR...")
+
+ populateExternalDistDirHelper(ctx, config, internalDistDirPath, externalDistDirPath)
+}
+
+func populateExternalDistDirHelper(ctx build.Context, config build.Config, internalDistDirPath string, externalDistDirPath string) {
+ files, err := ioutil.ReadDir(internalDistDirPath)
+ if err != nil {
+ ctx.Fatalf("Can't read internal distdir %s: %s", internalDistDirPath, err)
+ }
+ for _, f := range files {
+ internalFilePath := filepath.Join(internalDistDirPath, f.Name())
+ externalFilePath := filepath.Join(externalDistDirPath, f.Name())
+
+ if f.IsDir() {
+ // Moving a directory - check if there is an existing directory to merge with
+ externalLstat, err := os.Lstat(externalFilePath)
+ if err != nil {
+ if !os.IsNotExist(err) {
+ ctx.Fatalf("Can't lstat external %s: %s", externalDistDirPath, err)
+ }
+ // Otherwise, if the error was os.IsNotExist, that's fine and we fall through to the rename at the bottom
+ } else {
+ if externalLstat.IsDir() {
+ // Existing dir - try to merge the directories?
+ populateExternalDistDirHelper(ctx, config, internalFilePath, externalFilePath)
+ continue
+ } else {
+ // Existing file being replaced with a directory. Delete the existing file...
+ if err := os.RemoveAll(externalFilePath); err != nil {
+ ctx.Fatalf("Unable to remove existing %s: %s", externalFilePath, err)
+ }
+ }
+ }
+ } else {
+ // Moving a file (not a dir) - delete any existing file or directory
+ if err := os.RemoveAll(externalFilePath); err != nil {
+ ctx.Fatalf("Unable to remove existing %s: %s", externalFilePath, err)
+ }
+ }
+
+ // The actual move - do a rename instead of a copy in order to save disk space.
+ if err := os.Rename(internalFilePath, externalFilePath); err != nil {
+ ctx.Fatalf("Unable to rename %s -> %s due to error %s", internalFilePath, externalFilePath, err)
+ }
+ }
+}
diff --git a/rust/Android.bp b/rust/Android.bp
index 8618207..df731db 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -15,6 +15,7 @@
"clippy.go",
"compiler.go",
"coverage.go",
+ "image.go",
"library.go",
"prebuilt.go",
"proc_macro.go",
@@ -33,6 +34,7 @@
"clippy_test.go",
"compiler_test.go",
"coverage_test.go",
+ "image_test.go",
"library_test.go",
"project_json_test.go",
"protobuf_test.go",
diff --git a/rust/androidmk.go b/rust/androidmk.go
index c181d67..e9da6fa 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -58,6 +58,7 @@
entries.AddStrings("LOCAL_PROC_MACRO_LIBRARIES", mod.Properties.AndroidMkProcMacroLibs...)
entries.AddStrings("LOCAL_SHARED_LIBRARIES", mod.Properties.AndroidMkSharedLibs...)
entries.AddStrings("LOCAL_STATIC_LIBRARIES", mod.Properties.AndroidMkStaticLibs...)
+ entries.AddStrings("LOCAL_SOONG_LINK_TYPE", mod.makeLinkType)
},
},
}
diff --git a/rust/builder.go b/rust/builder.go
index 6079e30..8ec2da2 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -189,6 +189,7 @@
implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...)
implicits = append(implicits, deps.StaticLibs...)
implicits = append(implicits, deps.SharedLibs...)
+ implicits = append(implicits, deps.srcProviderFiles...)
if deps.CrtBegin.Valid() {
implicits = append(implicits, deps.CrtBegin.Path(), deps.CrtEnd.Path())
diff --git a/rust/image.go b/rust/image.go
new file mode 100644
index 0000000..4951d2b
--- /dev/null
+++ b/rust/image.go
@@ -0,0 +1,153 @@
+// 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 (
+ "strings"
+
+ "android/soong/android"
+ "android/soong/cc"
+)
+
+var _ android.ImageInterface = (*Module)(nil)
+
+func (mod *Module) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
+func (mod *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+ return mod.Properties.CoreVariantNeeded
+}
+
+func (mod *Module) RamdiskVariantNeeded(android.BaseModuleContext) bool {
+ return mod.InRamdisk()
+}
+
+func (mod *Module) RecoveryVariantNeeded(android.BaseModuleContext) bool {
+ return mod.InRecovery()
+}
+
+func (mod *Module) ExtraImageVariations(android.BaseModuleContext) []string {
+ return mod.Properties.ExtraVariants
+}
+
+func (ctx *moduleContext) ProductSpecific() bool {
+ return false
+}
+
+func (mod *Module) InRecovery() bool {
+ // TODO(b/165791368)
+ return false
+}
+
+func (mod *Module) OnlyInRamdisk() bool {
+ // TODO(b/165791368)
+ return false
+}
+
+func (mod *Module) OnlyInRecovery() bool {
+ // TODO(b/165791368)
+ return false
+}
+
+func (mod *Module) OnlyInVendorRamdisk() bool {
+ return false
+}
+
+// Returns true when this module is configured to have core and vendor variants.
+func (mod *Module) HasVendorVariant() bool {
+ return mod.IsVndk() || Bool(mod.VendorProperties.Vendor_available)
+}
+
+func (c *Module) VendorAvailable() bool {
+ return Bool(c.VendorProperties.Vendor_available)
+}
+
+func (c *Module) InProduct() bool {
+ return false
+}
+
+func (mod *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
+ m := module.(*Module)
+ if strings.HasPrefix(variant, cc.VendorVariationPrefix) {
+ m.Properties.ImageVariationPrefix = cc.VendorVariationPrefix
+ m.Properties.VndkVersion = strings.TrimPrefix(variant, cc.VendorVariationPrefix)
+
+ // Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION.
+ // Hide other vendor variants to avoid collision.
+ vndkVersion := ctx.DeviceConfig().VndkVersion()
+ if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion {
+ m.Properties.HideFromMake = true
+ m.SkipInstall()
+ }
+ }
+}
+
+func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
+ vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
+ platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
+
+ // Rust does not support installing to the product image yet.
+ if mod.VendorProperties.Product_available != nil {
+ mctx.PropertyErrorf("product_available",
+ "Rust modules do not yet support being available to the product image")
+ } else if mctx.ProductSpecific() {
+ mctx.PropertyErrorf("product_specific",
+ "Rust modules do not yet support installing to the product image.")
+ } else if mod.VendorProperties.Double_loadable != nil {
+ mctx.PropertyErrorf("double_loadable",
+ "Rust modules do not yet support double loading")
+ }
+
+ coreVariantNeeded := true
+ var vendorVariants []string
+
+ if mod.VendorProperties.Vendor_available != nil {
+ if vendorSpecific {
+ mctx.PropertyErrorf("vendor_available",
+ "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`")
+ }
+
+ if lib, ok := mod.compiler.(libraryInterface); ok {
+ // Explicitly disallow rust_ffi variants which produce shared libraries from setting vendor_available.
+ // Vendor variants do not produce an error for dylibs, rlibs with dylib-std linkage are disabled in the respective library
+ // mutators until support is added.
+ //
+ // We can't check shared() here because image mutator is called before the library mutator, so we need to
+ // check buildShared()
+ if lib.buildShared() {
+ mctx.PropertyErrorf("vendor_available",
+ "vendor_available can only be set for rust_ffi_static modules.")
+ } else if Bool(mod.VendorProperties.Vendor_available) == true {
+ vendorVariants = append(vendorVariants, platformVndkVersion)
+ }
+ }
+ }
+
+ if vendorSpecific {
+ if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && !lib.static()) {
+ mctx.ModuleErrorf("Rust vendor specific modules are currently only supported for rust_ffi_static modules.")
+ } else {
+ coreVariantNeeded = false
+ vendorVariants = append(vendorVariants, platformVndkVersion)
+ }
+ }
+
+ mod.Properties.CoreVariantNeeded = coreVariantNeeded
+ for _, variant := range android.FirstUniqueStrings(vendorVariants) {
+ mod.Properties.ExtraVariants = append(mod.Properties.ExtraVariants, cc.VendorVariationPrefix+variant)
+ }
+
+}
diff --git a/rust/image_test.go b/rust/image_test.go
new file mode 100644
index 0000000..025b0fd
--- /dev/null
+++ b/rust/image_test.go
@@ -0,0 +1,73 @@
+// 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 (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/cc"
+)
+
+// Test that cc_binaries can link against rust_ffi_static libraries.
+func TestVendorLinkage(t *testing.T) {
+ ctx := testRust(t, `
+ cc_binary {
+ name: "fizz_vendor",
+ static_libs: ["libfoo_vendor"],
+ soc_specific: true,
+ }
+ rust_ffi_static {
+ name: "libfoo_vendor",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ vendor_available: true,
+ }
+ `)
+
+ vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_arm64_armv8-a").Module().(*cc.Module)
+
+ if !android.InList("libfoo_vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
+ t.Errorf("vendorBinary should have a dependency on libfoo_vendor")
+ }
+}
+
+// Test that shared libraries cannot be made vendor available until proper support is added.
+func TestForbiddenVendorLinkage(t *testing.T) {
+ testRustError(t, "vendor_available can only be set for rust_ffi_static modules", `
+ rust_ffi_shared {
+ name: "libfoo_vendor",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ vendor_available: true,
+ }
+ `)
+ testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", `
+ rust_ffi {
+ name: "libfoo_vendor",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ vendor: true,
+ }
+ `)
+ testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", `
+ rust_library {
+ name: "libfoo_vendor",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ vendor: true,
+ }
+ `)
+}
diff --git a/rust/library.go b/rust/library.go
index 9d731e6..4ac52b4 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -433,6 +433,7 @@
if library.sourceProvider != nil {
// Assume the first source from the source provider is the library entry point.
srcPath = library.sourceProvider.Srcs()[0]
+ deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...)
} else {
srcPath, _ = srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
}
@@ -604,6 +605,11 @@
v.(*Module).compiler.(libraryInterface).setRlib()
case dylibVariation:
v.(*Module).compiler.(libraryInterface).setDylib()
+ if v.(*Module).ModuleBase.ImageVariation().Variation != android.CoreVariation {
+ // TODO(b/165791368)
+ // Disable dylib non-core variations until we support these.
+ v.(*Module).Disable()
+ }
case "source":
v.(*Module).compiler.(libraryInterface).setSource()
// The source variant does not produce any library.
@@ -640,6 +646,12 @@
dylib := modules[1].(*Module)
rlib.compiler.(libraryInterface).setRlibStd()
dylib.compiler.(libraryInterface).setDylibStd()
+ if dylib.ModuleBase.ImageVariation().Variation != android.CoreVariation {
+ // TODO(b/165791368)
+ // Disable rlibs that link against dylib-std on non-core variations until non-core dylib
+ // variants are properly supported.
+ dylib.Disable()
+ }
rlib.Properties.SubName += RlibStdlibSuffix
dylib.Properties.SubName += DylibStdlibSuffix
}
diff --git a/rust/protobuf.go b/rust/protobuf.go
index 0e79089..4fba34f 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -46,7 +46,7 @@
var _ SourceProvider = (*protobufDecorator)(nil)
type ProtobufProperties struct {
- // List of realtive paths to proto files that will be used to generate the source
+ // List of relative paths to proto files that will be used to generate the source
Protos []string `android:"path,arch_variant"`
// List of additional flags to pass to aprotoc
@@ -80,6 +80,10 @@
protoFiles := android.PathsForModuleSrc(ctx, proto.Properties.Protos)
+ if len(protoFiles) == 0 {
+ ctx.PropertyErrorf("protos", "at least one protobuf must be defined.")
+ }
+
// Add exported dependency include paths
for _, include := range deps.depIncludePaths {
protoFlags.Flags = append(protoFlags.Flags, "-I"+include.String())
@@ -91,7 +95,7 @@
stemFile := android.PathForModuleOut(ctx, "mod_"+stem+".rs")
// stemFile must be first here as the first path in BaseSourceProvider.OutputFiles is the library entry-point.
- outputs := android.WritablePaths{stemFile}
+ var outputs android.WritablePaths
rule := android.NewRuleBuilder(pctx, ctx)
for _, protoFile := range protoFiles {
@@ -112,14 +116,12 @@
outputs = append(outputs, ruleOutputs...)
}
- rule.Command().
- Implicits(outputs.Paths()).
- Text("printf '" + proto.genModFileContents(ctx, protoNames) + "' >").
- Output(stemFile)
+ android.WriteFileRule(ctx, stemFile, proto.genModFileContents(ctx, protoNames))
rule.Build("protoc_"+ctx.ModuleName(), "protoc "+ctx.ModuleName())
- proto.BaseSourceProvider.OutputFiles = outputs.Paths()
+ // stemFile must be first here as the first path in BaseSourceProvider.OutputFiles is the library entry-point.
+ proto.BaseSourceProvider.OutputFiles = append(android.Paths{stemFile}, outputs.Paths()...)
// mod_stem.rs is the entry-point for our library modules, so this is what we return.
return stemFile
@@ -145,7 +147,7 @@
"}")
}
- return strings.Join(lines, "\\n")
+ return strings.Join(lines, "\n")
}
func (proto *protobufDecorator) setupPlugin(ctx ModuleContext, protoFlags android.ProtoFlags, outDir android.ModuleOutPath) (android.Paths, android.ProtoFlags) {
diff --git a/rust/rust.go b/rust/rust.go
index 38caad3..3d70121 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -65,7 +65,16 @@
AndroidMkSharedLibs []string
AndroidMkStaticLibs []string
- SubName string `blueprint:"mutated"`
+ ImageVariationPrefix string `blueprint:"mutated"`
+ VndkVersion string `blueprint:"mutated"`
+ SubName string `blueprint:"mutated"`
+
+ // Set by imageMutator
+ CoreVariantNeeded bool `blueprint:"mutated"`
+ ExtraVariants []string `blueprint:"mutated"`
+
+ // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+ Min_sdk_version *string
PreventInstall bool
HideFromMake bool
@@ -76,11 +85,15 @@
android.DefaultableModuleBase
android.ApexModuleBase
+ VendorProperties cc.VendorProperties
+
Properties BaseProperties
hod android.HostOrDeviceSupported
multilib android.Multilib
+ makeLinkType string
+
compiler compiler
coverage *coverage
clippy *clippy
@@ -109,33 +122,6 @@
}
}
-var _ android.ImageInterface = (*Module)(nil)
-
-func (mod *Module) ImageMutatorBegin(ctx android.BaseModuleContext) {}
-
-func (mod *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
- return true
-}
-
-func (mod *Module) RamdiskVariantNeeded(android.BaseModuleContext) bool {
- return mod.InRamdisk()
-}
-
-func (mod *Module) VendorRamdiskVariantNeeded(android.BaseModuleContext) bool {
- return mod.InVendorRamdisk()
-}
-
-func (mod *Module) RecoveryVariantNeeded(android.BaseModuleContext) bool {
- return mod.InRecovery()
-}
-
-func (mod *Module) ExtraImageVariations(android.BaseModuleContext) []string {
- return nil
-}
-
-func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
-}
-
func (mod *Module) SelectedStl() string {
return ""
}
@@ -176,24 +162,18 @@
panic(fmt.Errorf("Toc() called on non-library module: %q", mod.BaseModuleName()))
}
-func (mod *Module) OnlyInRamdisk() bool {
- return false
-}
-
-func (mod *Module) OnlyInVendorRamdisk() bool {
- return false
-}
-
-func (mod *Module) OnlyInRecovery() bool {
- return false
-}
-
func (mod *Module) UseSdk() bool {
return false
}
+// Returns true if the module is using VNDK libraries instead of the libraries in /system/lib or /system/lib64.
+// "product" and "vendor" variant modules return true for this function.
+// When BOARD_VNDK_VERSION is set, vendor variants of "vendor_available: true", "vendor: true",
+// "soc_specific: true" and more vendor installed modules are included here.
+// When PRODUCT_PRODUCT_VNDK_VERSION is set, product variants of "vendor_available: true" or
+// "product_specific: true" modules are included here.
func (mod *Module) UseVndk() bool {
- return false
+ return mod.Properties.VndkVersion != ""
}
func (mod *Module) MustUseVendorVariant() bool {
@@ -201,10 +181,15 @@
}
func (mod *Module) IsVndk() bool {
+ // TODO(b/165791368)
return false
}
-func (mod *Module) HasVendorVariant() bool {
+func (mod *Module) IsVndkExt() bool {
+ return false
+}
+
+func (c *Module) IsVndkPrivate(config android.Config) bool {
return false
}
@@ -260,7 +245,8 @@
CrtEnd android.OptionalPath
// Paths to generated source files
- SrcDeps android.Paths
+ SrcDeps android.Paths
+ srcProviderFiles android.Paths
}
type RustLibraries []RustLibrary
@@ -376,6 +362,7 @@
module.AddProperties(props...)
module.AddProperties(
&BaseProperties{},
+ &cc.VendorProperties{},
&BindgenProperties{},
&BaseCompilerProperties{},
&BinaryCompilerProperties{},
@@ -472,11 +459,6 @@
return mod.outputFile
}
-func (mod *Module) InRecovery() bool {
- // For now, Rust has no notion of the recovery image
- return false
-}
-
func (mod *Module) CoverageFiles() android.Paths {
if mod.compiler != nil {
if !mod.compiler.nativeCoverage() {
@@ -496,6 +478,7 @@
func (mod *Module) Init() android.Module {
mod.AddProperties(&mod.Properties)
+ mod.AddProperties(&mod.VendorProperties)
if mod.compiler != nil {
mod.AddProperties(mod.compiler.compilerProps()...)
@@ -615,6 +598,12 @@
}
toolchain := mod.toolchain(ctx)
+ mod.makeLinkType = cc.GetMakeLinkType(actx, mod)
+
+ // Differentiate static libraries that are vendor available
+ if mod.UseVndk() {
+ mod.Properties.SubName += ".vendor"
+ }
if !toolchain.Supported() {
// This toolchain's unsupported, there's nothing to do for this mod.
@@ -956,10 +945,6 @@
deps := mod.deps(ctx)
var commonDepVariations []blueprint.Variation
- if !mod.Host() {
- commonDepVariations = append(commonDepVariations,
- blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
- }
stdLinkage := "dylib-std"
if mod.compiler.stdLinkage(ctx) == RlibLinkage {
@@ -1076,7 +1061,29 @@
var _ android.ApexModule = (*Module)(nil)
+func (mod *Module) minSdkVersion() string {
+ return String(mod.Properties.Min_sdk_version)
+}
+
func (mod *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
+ minSdkVersion := mod.minSdkVersion()
+ if minSdkVersion == "apex_inherit" {
+ return nil
+ }
+ if minSdkVersion == "" {
+ return fmt.Errorf("min_sdk_version is not specificed")
+ }
+
+ // Not using nativeApiLevelFromUser because the context here is not
+ // necessarily a native context.
+ ver, err := android.ApiLevelFromUser(ctx, minSdkVersion)
+ if err != nil {
+ return err
+ }
+
+ if ver.GreaterThan(sdkVersion) {
+ return fmt.Errorf("newer SDK(%v)", ver)
+ }
return nil
}
diff --git a/rust/testing.go b/rust/testing.go
index a8496d9..963a4ea 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -78,6 +78,7 @@
nocrt: true,
system_shared_libs: [],
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
+ min_sdk_version: "29",
}
cc_library {
name: "libprotobuf-cpp-full",
@@ -92,9 +93,11 @@
srcs: ["foo.rs"],
no_stdlibs: true,
host_supported: true,
+ vendor_available: true,
native_coverage: false,
sysroot: true,
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
+ min_sdk_version: "29",
}
rust_library {
name: "libtest",
@@ -102,9 +105,11 @@
srcs: ["foo.rs"],
no_stdlibs: true,
host_supported: true,
+ vendor_available: true,
native_coverage: false,
sysroot: true,
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
+ min_sdk_version: "29",
}
rust_library {
name: "libprotobuf",
diff --git a/ui/build/bazel.go b/ui/build/bazel.go
index d9c2266..4f2d645 100644
--- a/ui/build/bazel.go
+++ b/ui/build/bazel.go
@@ -78,7 +78,10 @@
bazelEnv["PACKAGE_NINJA"] = config.KatiPackageNinjaFile()
bazelEnv["SOONG_NINJA"] = config.SoongNinjaFile()
+ // NOTE: When Bazel is used, config.DistDir() is rigged to return a fake distdir under config.OutDir()
+ // This is to ensure that Bazel can actually write there. See config.go for more details.
bazelEnv["DIST_DIR"] = config.DistDir()
+
bazelEnv["SHELL"] = "/bin/bash"
// `tools/bazel` is the default entry point for executing Bazel in the AOSP
@@ -189,13 +192,14 @@
// currently hardcoded as ninja_build.output_root.
bazelNinjaBuildOutputRoot := filepath.Join(outputBasePath, "..", "out")
- ctx.Println("Creating output symlinks..")
- symlinkOutdir(ctx, config, bazelNinjaBuildOutputRoot, ".")
+ ctx.Println("Populating output directory...")
+ populateOutdir(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) {
+// NOTE: For distdir paths we rename files instead of creating symlinks, so that the distdir is independent.
+func populateOutdir(ctx Context, config Config, rootPath string, relativePath string) {
destDir := filepath.Join(rootPath, relativePath)
os.MkdirAll(destDir, 0755)
files, err := ioutil.ReadDir(destDir)
@@ -220,7 +224,7 @@
if srcLstatErr == nil {
if srcLstatResult.IsDir() && destLstatResult.IsDir() {
// src and dest are both existing dirs - recurse on the dest dir contents...
- symlinkOutdir(ctx, config, rootPath, filepath.Join(relativePath, f.Name()))
+ populateOutdir(ctx, config, rootPath, filepath.Join(relativePath, f.Name()))
} else {
// Ignore other pre-existing src files (could be pre-existing files, directories, symlinks, ...)
// This can arise for files which are generated under OutDir outside of soong_build, such as .bootstrap files.
@@ -231,9 +235,17 @@
ctx.Fatalf("Unable to Lstat src %s: %s", srcPath, srcLstatErr)
}
- // src does not exist, so try to create a src -> dest symlink (i.e. a Soong path -> Bazel path symlink)
- if symlinkErr := os.Symlink(destPath, srcPath); symlinkErr != nil {
- ctx.Fatalf("Unable to create symlink %s -> %s due to error %s", srcPath, destPath, symlinkErr)
+ if strings.Contains(destDir, config.DistDir()) {
+ // We need to make a "real" file/dir instead of making a symlink (because the distdir can't have symlinks)
+ // Rename instead of copy in order to save disk space.
+ if err := os.Rename(destPath, srcPath); err != nil {
+ ctx.Fatalf("Unable to rename %s -> %s due to error %s", srcPath, destPath, err)
+ }
+ } else {
+ // src does not exist, so try to create a src -> dest symlink (i.e. a Soong path -> Bazel path symlink)
+ if err := os.Symlink(destPath, srcPath); err != nil {
+ ctx.Fatalf("Unable to create symlink %s -> %s due to error %s", srcPath, destPath, err)
+ }
}
}
}
diff --git a/ui/build/build.go b/ui/build/build.go
index e8f0fc4..926da31 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -302,7 +302,7 @@
}
subDir := filepath.Join(subDirs...)
- destDir := filepath.Join(config.DistDir(), "soong_ui", subDir)
+ destDir := filepath.Join(config.RealDistDir(), "soong_ui", subDir)
if err := os.MkdirAll(destDir, 0777); err != nil { // a+rwx
ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
@@ -321,7 +321,7 @@
}
subDir := filepath.Join(subDirs...)
- destDir := filepath.Join(config.DistDir(), "soong_ui", subDir)
+ destDir := filepath.Join(config.RealDistDir(), "soong_ui", subDir)
if err := os.MkdirAll(destDir, 0777); err != nil { // a+rwx
ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
diff --git a/ui/build/config.go b/ui/build/config.go
index 72ae3fe..ecca4de 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -65,6 +65,12 @@
brokenNinjaEnvVars []string
pathReplaced bool
+
+ useBazel bool
+
+ // During Bazel execution, Bazel cannot write outside OUT_DIR.
+ // So if DIST_DIR is set to an external dir (outside of OUT_DIR), we need to rig it temporarily and then migrate files at the end of the build.
+ riggedDistDirForBazel string
}
const srcDirFileCheck = "build/soong/root.bp"
@@ -221,7 +227,7 @@
ctx.Fatalln("Directory names containing spaces are not supported")
}
- if distDir := ret.DistDir(); strings.ContainsRune(distDir, ' ') {
+ if distDir := ret.RealDistDir(); strings.ContainsRune(distDir, ' ') {
ctx.Println("The absolute path of your dist directory ($DIST_DIR) contains a space character:")
ctx.Println()
ctx.Printf("%q\n", distDir)
@@ -279,12 +285,22 @@
if err := os.RemoveAll(bpd); err != nil {
ctx.Fatalf("Unable to remove bazel profile directory %q: %v", bpd, err)
}
+
+ ret.useBazel = ret.environ.IsEnvTrue("USE_BAZEL")
+
if ret.UseBazel() {
if err := os.MkdirAll(bpd, 0777); err != nil {
ctx.Fatalf("Failed to create bazel profile directory %q: %v", bpd, err)
}
}
+ if ret.UseBazel() {
+ ret.riggedDistDirForBazel = filepath.Join(ret.OutDir(), "dist")
+ } else {
+ // Not rigged
+ ret.riggedDistDirForBazel = ret.distDir
+ }
+
c := Config{ret}
storeConfigMetrics(ctx, c)
return c
@@ -697,6 +713,14 @@
}
func (c *configImpl) DistDir() string {
+ if c.UseBazel() {
+ return c.riggedDistDirForBazel
+ } else {
+ return c.distDir
+ }
+}
+
+func (c *configImpl) RealDistDir() string {
return c.distDir
}
@@ -863,13 +887,7 @@
}
func (c *configImpl) UseBazel() bool {
- if v, ok := c.environ.Get("USE_BAZEL"); ok {
- v = strings.TrimSpace(v)
- if v != "" && v != "false" {
- return true
- }
- }
- return false
+ return c.useBazel
}
func (c *configImpl) StartRBE() bool {
@@ -886,14 +904,14 @@
return true
}
-func (c *configImpl) logDir() string {
+func (c *configImpl) rbeLogDir() string {
for _, f := range []string{"RBE_log_dir", "FLAG_log_dir"} {
if v, ok := c.environ.Get(f); ok {
return v
}
}
if c.Dist() {
- return filepath.Join(c.DistDir(), "logs")
+ return c.LogsDir()
}
return c.OutDir()
}
@@ -904,7 +922,7 @@
return v
}
}
- return c.logDir()
+ return c.rbeLogDir()
}
func (c *configImpl) rbeLogPath() string {
@@ -913,7 +931,7 @@
return v
}
}
- return fmt.Sprintf("text://%v/reproxy_log.txt", c.logDir())
+ return fmt.Sprintf("text://%v/reproxy_log.txt", c.rbeLogDir())
}
func (c *configImpl) rbeExecRoot() string {
@@ -1128,7 +1146,8 @@
// is <dist_dir>/logs.
func (c *configImpl) LogsDir() string {
if c.Dist() {
- return filepath.Join(c.DistDir(), "logs")
+ // Always write logs to the real dist dir, even if Bazel is using a rigged dist dir for other files
+ return filepath.Join(c.RealDistDir(), "logs")
}
return c.OutDir()
}
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 64f3d4c..d9c33f6 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -74,7 +74,7 @@
func getRBEVars(ctx Context, config Config) map[string]string {
vars := map[string]string{
"RBE_log_path": config.rbeLogPath(),
- "RBE_log_dir": config.logDir(),
+ "RBE_log_dir": config.rbeLogDir(),
"RBE_re_proxy": config.rbeReproxy(),
"RBE_exec_root": config.rbeExecRoot(),
"RBE_output_dir": config.rbeStatsOutputDir(),
diff --git a/ui/build/upload.go b/ui/build/upload.go
index 4f30136..55ca800 100644
--- a/ui/build/upload.go
+++ b/ui/build/upload.go
@@ -40,13 +40,42 @@
tmpDir = ioutil.TempDir
)
+// pruneMetricsFiles iterates the list of paths, checking if a path exist.
+// If a path is a file, it is added to the return list. If the path is a
+// directory, a recursive call is made to add the children files of the
+// path.
+func pruneMetricsFiles(paths []string) []string {
+ var metricsFiles []string
+ for _, p := range paths {
+ fi, err := os.Stat(p)
+ // Some paths passed may not exist. For example, build errors protobuf
+ // file may not exist since the build was successful.
+ if err != nil {
+ continue
+ }
+
+ if fi.IsDir() {
+ if l, err := ioutil.ReadDir(p); err == nil {
+ files := make([]string, 0, len(l))
+ for _, fi := range l {
+ files = append(files, filepath.Join(p, fi.Name()))
+ }
+ metricsFiles = append(metricsFiles, pruneMetricsFiles(files)...)
+ }
+ } else {
+ metricsFiles = append(metricsFiles, p)
+ }
+ }
+ return metricsFiles
+}
+
// UploadMetrics uploads a set of metrics files to a server for analysis. An
// uploader full path is specified in ANDROID_ENABLE_METRICS_UPLOAD environment
// variable in order to upload the set of metrics files. The metrics files are
// first copied to a temporary directory and the uploader is then executed in
// the background to allow the user/system to continue working. Soong communicates
// to the uploader through the upload_proto raw protobuf file.
-func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, files ...string) {
+func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, paths ...string) {
ctx.BeginTrace(metrics.RunSetupTool, "upload_metrics")
defer ctx.EndTrace()
@@ -56,15 +85,8 @@
return
}
- // Some files passed in to this function may not exist. For example,
- // build errors protobuf file may not exist since the build was successful.
- var metricsFiles []string
- for _, f := range files {
- if _, err := os.Stat(f); err == nil {
- metricsFiles = append(metricsFiles, f)
- }
- }
-
+ // Several of the files might be directories.
+ metricsFiles := pruneMetricsFiles(paths)
if len(metricsFiles) == 0 {
return
}
diff --git a/ui/build/upload_test.go b/ui/build/upload_test.go
index 768b031..b740c11 100644
--- a/ui/build/upload_test.go
+++ b/ui/build/upload_test.go
@@ -19,6 +19,8 @@
"io/ioutil"
"os"
"path/filepath"
+ "reflect"
+ "sort"
"strconv"
"strings"
"testing"
@@ -27,6 +29,49 @@
"android/soong/ui/logger"
)
+func TestPruneMetricsFiles(t *testing.T) {
+ rootDir := t.TempDir()
+
+ dirs := []string{
+ filepath.Join(rootDir, "d1"),
+ filepath.Join(rootDir, "d1", "d2"),
+ filepath.Join(rootDir, "d1", "d2", "d3"),
+ }
+
+ files := []string{
+ filepath.Join(rootDir, "d1", "f1"),
+ filepath.Join(rootDir, "d1", "d2", "f1"),
+ filepath.Join(rootDir, "d1", "d2", "d3", "f1"),
+ }
+
+ for _, d := range dirs {
+ if err := os.MkdirAll(d, 0777); err != nil {
+ t.Fatalf("got %v, expecting nil error for making directory %q", err, d)
+ }
+ }
+
+ for _, f := range files {
+ if err := ioutil.WriteFile(f, []byte{}, 0777); err != nil {
+ t.Fatalf("got %v, expecting nil error on writing file %q", err, f)
+ }
+ }
+
+ want := []string{
+ filepath.Join(rootDir, "d1", "f1"),
+ filepath.Join(rootDir, "d1", "d2", "f1"),
+ filepath.Join(rootDir, "d1", "d2", "d3", "f1"),
+ }
+
+ got := pruneMetricsFiles([]string{rootDir})
+
+ sort.Strings(got)
+ sort.Strings(want)
+
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("got %q, want %q after pruning metrics files", got, want)
+ }
+}
+
func TestUploadMetrics(t *testing.T) {
ctx := testContext()
tests := []struct {