Merge "Handle test_per_src modules as indirect dependencies in APEXes."

This commit is contained in:
Roland Levillain
2019-07-30 10:41:20 +00:00
committed by Gerrit Code Review
3 changed files with 104 additions and 78 deletions

View File

@@ -694,12 +694,6 @@ func getCopyManifestForExecutable(cc *cc.Module) (fileToCopy android.Path, dirIn
return return
} }
func getCopyManifestForTestPerSrcExecutables(cc *cc.Module) (filesToCopy []android.Path, dirInApex string) {
dirInApex = filepath.Join("bin", cc.RelativeInstallPath())
filesToCopy = cc.TestPerSrcOutputFiles()
return
}
func getCopyManifestForPyBinary(py *python.Module) (fileToCopy android.Path, dirInApex string) { func getCopyManifestForPyBinary(py *python.Module) (fileToCopy android.Path, dirInApex string) {
dirInApex = "bin" dirInApex = "bin"
fileToCopy = py.HostToolPath().Path() fileToCopy = py.HostToolPath().Path()
@@ -780,10 +774,10 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}) })
ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
depTag := ctx.OtherModuleDependencyTag(child)
depName := ctx.OtherModuleName(child)
if _, ok := parent.(*apexBundle); ok { if _, ok := parent.(*apexBundle); ok {
// direct dependencies // direct dependencies
depTag := ctx.OtherModuleDependencyTag(child)
depName := ctx.OtherModuleName(child)
switch depTag { switch depTag {
case sharedLibTag: case sharedLibTag:
if cc, ok := child.(*cc.Module); ok { if cc, ok := child.(*cc.Module); ok {
@@ -834,22 +828,19 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName) ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
} }
case testTag: case testTag:
if cc, ok := child.(*cc.Module); ok { if ccTest, ok := child.(*cc.Module); ok {
if cc.TestPerSrcOutputFiles() != nil { if ccTest.IsTestPerSrcAllTestsVariation() {
// Multiple-output test module (using `test_per_src`). // Multiple-output test module (where `test_per_src: true`).
filesToCopy, dirInApex := getCopyManifestForTestPerSrcExecutables(cc) //
for _, fileToCopy := range filesToCopy { // `ccTest` is the "" ("all tests") variation of a `test_per_src` module.
// Handle modules created as `test_per_src` variations of a single test module: // We do not add this variation to `filesInfo`, as it has no output;
// replace the name of the original test module (`depName`, shared by all // however, we do add the other variations of this module as indirect
// `test_per_src` variants of that module) with the name of the generated test // dependencies (see below).
// binary. return true
moduleName := filepath.Base(fileToCopy.String())
filesInfo = append(filesInfo, apexFile{fileToCopy, moduleName, dirInApex, nativeTest, cc, nil})
}
} else { } else {
// Single-output test module (not using `test_per_src`). // Single-output test module (where `test_per_src: false`).
fileToCopy, dirInApex := getCopyManifestForExecutable(cc) fileToCopy, dirInApex := getCopyManifestForExecutable(ccTest)
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeTest, cc, nil}) filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeTest, ccTest, nil})
} }
return true return true
} else { } else {
@@ -875,30 +866,46 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
} else { } else {
// indirect dependencies // indirect dependencies
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() { if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() {
if cc, ok := child.(*cc.Module); ok { // We cannot use a switch statement on `depTag` here as the checked
if android.InList(cc.Name(), providedNativeSharedLibs) { // tags used below are private (e.g. `cc.sharedDepTag`).
// If we're using a shared library which is provided from other APEX, if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
// don't include it in this APEX if cc, ok := child.(*cc.Module); ok {
return false if android.InList(cc.Name(), providedNativeSharedLibs) {
} // If we're using a shared library which is provided from other APEX,
if !a.Host() && (cc.IsStubs() || cc.HasStubsVariants()) { // don't include it in this APEX
// If the dependency is a stubs lib, don't include it in this APEX, return false
// but make sure that the lib is installed on the device.
// In case no APEX is having the lib, the lib is installed to the system
// partition.
//
// Always include if we are a host-apex however since those won't have any
// system libraries.
if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.externalDeps) {
a.externalDeps = append(a.externalDeps, cc.Name())
} }
// Don't track further if !a.Host() && (cc.IsStubs() || cc.HasStubsVariants()) {
return false // If the dependency is a stubs lib, don't include it in this APEX,
// but make sure that the lib is installed on the device.
// In case no APEX is having the lib, the lib is installed to the system
// partition.
//
// Always include if we are a host-apex however since those won't have any
// system libraries.
if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.externalDeps) {
a.externalDeps = append(a.externalDeps, cc.Name())
}
// Don't track further
return false
}
fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
return true
} }
depName := ctx.OtherModuleName(child) } else if cc.IsTestPerSrcDepTag(depTag) {
fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs) if cc, ok := child.(*cc.Module); ok {
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil}) fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
return true // Handle modules created as `test_per_src` variations of a single test module:
// use the name of the generated test binary (`fileToCopy`) instead of the name
// of the original test module (`depName`, shared by all `test_per_src`
// variations of that module).
moduleName := filepath.Base(fileToCopy.String())
filesInfo = append(filesInfo, apexFile{fileToCopy, moduleName, dirInApex, nativeTest, cc, nil})
return true
}
} else {
ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
} }
} }
} }

View File

@@ -1393,7 +1393,7 @@ func TestPrebuiltOverrides(t *testing.T) {
} }
func TestApexWithTests(t *testing.T) { func TestApexWithTests(t *testing.T) {
ctx, _ := testApex(t, ` ctx, config := testApex(t, `
apex_test { apex_test {
name: "myapex", name: "myapex",
key: "myapex.key", key: "myapex.key",
@@ -1445,6 +1445,22 @@ func TestApexWithTests(t *testing.T) {
ensureContains(t, copyCmds, "image.apex/bin/test/mytest1") ensureContains(t, copyCmds, "image.apex/bin/test/mytest1")
ensureContains(t, copyCmds, "image.apex/bin/test/mytest2") ensureContains(t, copyCmds, "image.apex/bin/test/mytest2")
ensureContains(t, copyCmds, "image.apex/bin/test/mytest3") ensureContains(t, copyCmds, "image.apex/bin/test/mytest3")
// Ensure the module is correctly translated.
apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
data := android.AndroidMkDataForTest(t, config, "", apexBundle)
name := apexBundle.BaseModuleName()
prefix := "TARGET_"
var builder strings.Builder
data.Custom(&builder, name, prefix, "", data)
androidMk := builder.String()
ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest\n")
ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest1\n")
ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest2\n")
ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest3\n")
ensureContains(t, androidMk, "LOCAL_MODULE := myapex.apex_manifest.json\n")
ensureContains(t, androidMk, "LOCAL_MODULE := myapex.apex_pubkey\n")
ensureContains(t, androidMk, "LOCAL_MODULE := myapex\n")
} }
func TestApexUsesOtherApex(t *testing.T) { func TestApexUsesOtherApex(t *testing.T) {

View File

@@ -342,6 +342,7 @@ type dependencyTag struct {
blueprint.BaseDependencyTag blueprint.BaseDependencyTag
name string name string
library bool library bool
shared bool
reexportFlags bool reexportFlags bool
@@ -353,10 +354,10 @@ type xref interface {
} }
var ( var (
sharedDepTag = dependencyTag{name: "shared", library: true} sharedDepTag = dependencyTag{name: "shared", library: true, shared: true}
sharedExportDepTag = dependencyTag{name: "shared", library: true, reexportFlags: true} sharedExportDepTag = dependencyTag{name: "shared", library: true, shared: true, reexportFlags: true}
earlySharedDepTag = dependencyTag{name: "early_shared", library: true} earlySharedDepTag = dependencyTag{name: "early_shared", library: true, shared: true}
lateSharedDepTag = dependencyTag{name: "late shared", library: true} lateSharedDepTag = dependencyTag{name: "late shared", library: true, shared: true}
staticDepTag = dependencyTag{name: "static", library: true} staticDepTag = dependencyTag{name: "static", library: true}
staticExportDepTag = dependencyTag{name: "static", library: true, reexportFlags: true} staticExportDepTag = dependencyTag{name: "static", library: true, reexportFlags: true}
lateStaticDepTag = dependencyTag{name: "late static", library: true} lateStaticDepTag = dependencyTag{name: "late static", library: true}
@@ -381,6 +382,21 @@ var (
testPerSrcDepTag = dependencyTag{name: "test_per_src"} testPerSrcDepTag = dependencyTag{name: "test_per_src"}
) )
func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
ccDepTag, ok := depTag.(dependencyTag)
return ok && ccDepTag.shared
}
func IsRuntimeDepTag(depTag blueprint.DependencyTag) bool {
ccDepTag, ok := depTag.(dependencyTag)
return ok && ccDepTag == runtimeDepTag
}
func IsTestPerSrcDepTag(depTag blueprint.DependencyTag) bool {
ccDepTag, ok := depTag.(dependencyTag)
return ok && ccDepTag == testPerSrcDepTag
}
// Module contains the properties and members used by all C/C++ module types, and implements // Module contains the properties and members used by all C/C++ module types, and implements
// the blueprint.Module interface. It delegates to compiler, linker, and installer interfaces // the blueprint.Module interface. It delegates to compiler, linker, and installer interfaces
// to construct the output file. Behavior can be customized with a Customizer interface // to construct the output file. Behavior can be customized with a Customizer interface
@@ -414,9 +430,6 @@ type Module struct {
outputFile android.OptionalPath outputFile android.OptionalPath
// Test output files, in the case of a test module using `test_per_src`.
testPerSrcOutputFiles []android.Path
cachedToolchain config.Toolchain cachedToolchain config.Toolchain
subAndroidMkOnce map[subAndroidMkProvider]bool subAndroidMkOnce map[subAndroidMkProvider]bool
@@ -441,10 +454,6 @@ func (c *Module) OutputFile() android.OptionalPath {
return c.outputFile return c.outputFile
} }
func (c *Module) TestPerSrcOutputFiles() []android.Path {
return c.testPerSrcOutputFiles
}
func (c *Module) UnstrippedOutputFile() android.Path { func (c *Module) UnstrippedOutputFile() android.Path {
if c.linker != nil { if c.linker != nil {
return c.linker.unstrippedOutputFilePath() return c.linker.unstrippedOutputFilePath()
@@ -962,28 +971,20 @@ func orderStaticModuleDeps(module *Module, staticDeps []*Module, sharedDeps []*M
return results return results
} }
func (c *Module) IsTestPerSrcAllTestsVariation() bool {
test, ok := c.linker.(testPerSrc)
return ok && test.isAllTestsVariation()
}
func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
// Handle the case of a test module split by `test_per_src` mutator. // Handle the case of a test module split by `test_per_src` mutator.
if test, ok := c.linker.(testPerSrc); ok { //
// The `test_per_src` mutator adds an extra variant named "", depending on all the // The `test_per_src` mutator adds an extra variation named "", depending on all the other
// other `test_per_src` variants of the test module. Collect the output files of // `test_per_src` variations of the test module. Set `outputFile` to an empty path for this
// these dependencies and record them in the `testPerSrcOutputFiles` for later use // module and return early, as this module does not produce an output file per se.
// (see e.g. `apexBundle.GenerateAndroidBuildActions`). if c.IsTestPerSrcAllTestsVariation() {
if test.isAllTestsVariation() { c.outputFile = android.OptionalPath{}
var testPerSrcOutputFiles []android.Path return
for _, dep := range actx.GetDirectDepsWithTag(testPerSrcDepTag) {
if ccDep, ok := dep.(*Module); ok {
depOutputFile := ccDep.OutputFile().Path()
testPerSrcOutputFiles =
append(testPerSrcOutputFiles, depOutputFile)
}
}
c.testPerSrcOutputFiles = testPerSrcOutputFiles
// Set outputFile to an empty path, as this module does not produce an
// output file per se.
c.outputFile = android.OptionalPath{}
return
}
} }
c.makeLinkType = c.getMakeLinkType(actx) c.makeLinkType = c.getMakeLinkType(actx)
@@ -2064,12 +2065,14 @@ func (c *Module) getMakeLinkType(actx android.ModuleContext) string {
} }
// Overrides ApexModule.IsInstallabeToApex() // Overrides ApexModule.IsInstallabeToApex()
// Only shared libraries are installable to APEX. // Only shared/runtime libraries and "test_per_src" tests are installable to APEX.
func (c *Module) IsInstallableToApex() bool { func (c *Module) IsInstallableToApex() bool {
if shared, ok := c.linker.(interface { if shared, ok := c.linker.(interface {
shared() bool shared() bool
}); ok { }); ok {
return shared.shared() return shared.shared()
} else if _, ok := c.linker.(testPerSrc); ok {
return true
} }
return false return false
} }