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
This commit is contained in:
Jiyong Park
2024-05-10 11:17:33 +09:00
parent ef5511ff77
commit 1fb7c35129
3 changed files with 73 additions and 5 deletions

View File

@@ -44,6 +44,21 @@ func IsInstallDepNeededTag(tag blueprint.DependencyTag) bool {
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
}

View File

@@ -1470,16 +1470,28 @@ func (m *ModuleBase) computeInstallDeps(ctx ModuleContext) ([]*DepSet[InstallPat
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() {
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.
if skipToTransitive {
packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet.transitive...)
} else {
packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet)
}
}
})
return installDeps, packagingSpecs

View File

@@ -26,6 +26,7 @@ type componentTestModule struct {
ModuleBase
props struct {
Deps []string
Build_only_deps []string
Skip_install *bool
}
}
@@ -36,6 +37,18 @@ type installDepTag struct {
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 componentTestModuleFactory() Module {
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 @@ func TestPackagingWithSkipInstallDeps(t *testing.T) {
}
`, []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"})
}