Add SkipToTransitiveDepsTag interface for dependency tags
Consider this dependency graph:
A --> B --> C
And let's assume that B is built into A (e.g. static_libs), while B -->
C is a runtime dependency (e.g. required).
We want to install C (but not B of course) when A gets installed.
However, before this change, it was not supported because the dependency
A -> B was not tracked in computeInstallDeps. One had to explicitly add
a A -> C dependency.
This change fixes the problem by introducing the new interface
SkipToTransitiveDepsTag. computeInstallDeps uses it to decide whether to
take all install files and packaging specs or only those from transitive
dependencies. In the above example, if the dependency A --> B implements
the new interface and returns true, B's transitive dependencies (i.e. C)
are added into A's transitive dependencies. B's outputs are not added.
Bug: N/A
Test: go test ./... under soong/android
Change-Id: I3ca03a21633883f320ecb9e5bc82eb134519cd88
diff --git a/android/deptag.go b/android/deptag.go
index c7ba4d3..77b9d61 100644
--- a/android/deptag.go
+++ b/android/deptag.go
@@ -44,6 +44,21 @@
return false
}
+// Dependency tags can implement this interface and return true from SkipToTransitiveDeps to
+// annotate that this dependency isn't installed, but its transitive dependencies are. This is
+// useful when a module is built into another module (ex: static linking) but the module still has
+// runtime dependencies.
+type SkipToTransitiveDepsTag interface {
+ SkipToTransitiveDeps() bool
+}
+
+func IsSkipToTransitiveDepsTag(tag blueprint.DependencyTag) bool {
+ if i, ok := tag.(SkipToTransitiveDepsTag); ok {
+ return i.SkipToTransitiveDeps()
+ }
+ return false
+}
+
type PropagateAconfigValidationDependencyTag interface {
PropagateAconfigValidation() bool
}
diff --git a/android/module.go b/android/module.go
index 40a5910..1664f03 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1470,15 +1470,27 @@
var installDeps []*DepSet[InstallPath]
var packagingSpecs []*DepSet[PackagingSpec]
ctx.VisitDirectDeps(func(dep Module) {
- if isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) {
+ depTag := ctx.OtherModuleDependencyTag(dep)
+ // If this is true, the direct outputs from the module is not gathered, but its
+ // transitive deps are still gathered.
+ skipToTransitive := IsSkipToTransitiveDepsTag(depTag)
+ if isInstallDepNeeded(dep, depTag) || skipToTransitive {
// Installation is still handled by Make, so anything hidden from Make is not
// installable.
if !dep.IsHideFromMake() && !dep.IsSkipInstall() {
- installDeps = append(installDeps, dep.base().installFilesDepSet)
+ if skipToTransitive {
+ installDeps = append(installDeps, dep.base().installFilesDepSet.transitive...)
+ } else {
+ installDeps = append(installDeps, dep.base().installFilesDepSet)
+ }
}
// Add packaging deps even when the dependency is not installed so that uninstallable
// modules can still be packaged. Often the package will be installed instead.
- packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet)
+ if skipToTransitive {
+ packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet.transitive...)
+ } else {
+ packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet)
+ }
}
})
diff --git a/android/packaging_test.go b/android/packaging_test.go
index 3833437..4b72c24 100644
--- a/android/packaging_test.go
+++ b/android/packaging_test.go
@@ -25,8 +25,9 @@
type componentTestModule struct {
ModuleBase
props struct {
- Deps []string
- Skip_install *bool
+ Deps []string
+ Build_only_deps []string
+ Skip_install *bool
}
}
@@ -36,6 +37,18 @@
InstallAlwaysNeededDependencyTag
}
+// dep tag for build_only_deps
+type buildOnlyDepTag struct {
+ blueprint.BaseDependencyTag
+ InstallAlwaysNeededDependencyTag
+}
+
+var _ SkipToTransitiveDepsTag = (*buildOnlyDepTag)(nil)
+
+func (tag buildOnlyDepTag) SkipToTransitiveDeps() bool {
+ return true
+}
+
func componentTestModuleFactory() Module {
m := &componentTestModule{}
m.AddProperties(&m.props)
@@ -45,6 +58,7 @@
func (m *componentTestModule) DepsMutator(ctx BottomUpMutatorContext) {
ctx.AddDependency(ctx.Module(), installDepTag{}, m.props.Deps...)
+ ctx.AddDependency(ctx.Module(), buildOnlyDepTag{}, m.props.Build_only_deps...)
}
func (m *componentTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
@@ -398,3 +412,30 @@
}
`, []string{"lib64/foo", "lib64/bar", "lib64/baz"})
}
+
+func TestPackagingWithSkipToTransitvDeps(t *testing.T) {
+ // packag -[deps]-> foo -[build_only_deps]-> bar -[deps]-> baz
+ // bar isn't installed, but it brings baz to its parent.
+ multiTarget := false
+ runPackagingTest(t, multiTarget,
+ `
+ component {
+ name: "foo",
+ build_only_deps: ["bar"],
+ }
+
+ component {
+ name: "bar",
+ deps: ["baz"],
+ }
+
+ component {
+ name: "baz",
+ }
+
+ package_module {
+ name: "package",
+ deps: ["foo"],
+ }
+ `, []string{"lib64/foo", "lib64/baz"})
+}