1fb7c35129
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
441 lines
8.3 KiB
Go
441 lines
8.3 KiB
Go
// Copyright 2020 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package android
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/google/blueprint"
|
|
"github.com/google/blueprint/proptools"
|
|
)
|
|
|
|
// Module to be packaged
|
|
type componentTestModule struct {
|
|
ModuleBase
|
|
props struct {
|
|
Deps []string
|
|
Build_only_deps []string
|
|
Skip_install *bool
|
|
}
|
|
}
|
|
|
|
// dep tag used in this test. All dependencies are considered as installable.
|
|
type installDepTag struct {
|
|
blueprint.BaseDependencyTag
|
|
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)
|
|
InitAndroidArchModule(m, HostAndDeviceSupported, MultilibBoth)
|
|
return m
|
|
}
|
|
|
|
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) {
|
|
builtFile := PathForModuleOut(ctx, m.Name())
|
|
dir := ctx.Target().Arch.ArchType.Multilib
|
|
installDir := PathForModuleInstall(ctx, dir)
|
|
if proptools.Bool(m.props.Skip_install) {
|
|
m.SkipInstall()
|
|
}
|
|
ctx.InstallFile(installDir, m.Name(), builtFile)
|
|
}
|
|
|
|
// Module that itself is a package
|
|
type packageTestModule struct {
|
|
ModuleBase
|
|
PackagingBase
|
|
properties struct {
|
|
Install_deps []string `android:`
|
|
}
|
|
entries []string
|
|
}
|
|
|
|
func packageMultiTargetTestModuleFactory() Module {
|
|
module := &packageTestModule{}
|
|
InitPackageModule(module)
|
|
InitAndroidMultiTargetsArchModule(module, DeviceSupported, MultilibCommon)
|
|
module.AddProperties(&module.properties)
|
|
return module
|
|
}
|
|
|
|
func packageTestModuleFactory() Module {
|
|
module := &packageTestModule{}
|
|
InitPackageModule(module)
|
|
InitAndroidArchModule(module, DeviceSupported, MultilibBoth)
|
|
module.AddProperties(&module.properties)
|
|
return module
|
|
}
|
|
|
|
type packagingDepTag struct {
|
|
blueprint.BaseDependencyTag
|
|
PackagingItemAlwaysDepTag
|
|
}
|
|
|
|
func (m *packageTestModule) DepsMutator(ctx BottomUpMutatorContext) {
|
|
m.AddDeps(ctx, packagingDepTag{})
|
|
ctx.AddDependency(ctx.Module(), installDepTag{}, m.properties.Install_deps...)
|
|
}
|
|
|
|
func (m *packageTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
|
zipFile := PathForModuleOut(ctx, "myzip.zip")
|
|
m.entries = m.CopyDepsToZip(ctx, m.GatherPackagingSpecs(ctx), zipFile)
|
|
}
|
|
|
|
func runPackagingTest(t *testing.T, multitarget bool, bp string, expected []string) {
|
|
t.Helper()
|
|
|
|
var archVariant string
|
|
var moduleFactory ModuleFactory
|
|
if multitarget {
|
|
archVariant = "android_common"
|
|
moduleFactory = packageMultiTargetTestModuleFactory
|
|
} else {
|
|
archVariant = "android_arm64_armv8-a"
|
|
moduleFactory = packageTestModuleFactory
|
|
}
|
|
|
|
result := GroupFixturePreparers(
|
|
PrepareForTestWithArchMutator,
|
|
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
|
ctx.RegisterModuleType("component", componentTestModuleFactory)
|
|
ctx.RegisterModuleType("package_module", moduleFactory)
|
|
}),
|
|
FixtureWithRootAndroidBp(bp),
|
|
).RunTest(t)
|
|
|
|
p := result.Module("package", archVariant).(*packageTestModule)
|
|
actual := p.entries
|
|
actual = SortedUniqueStrings(actual)
|
|
expected = SortedUniqueStrings(expected)
|
|
AssertDeepEquals(t, "package entries", expected, actual)
|
|
}
|
|
|
|
func TestPackagingBaseMultiTarget(t *testing.T) {
|
|
multiTarget := true
|
|
runPackagingTest(t, multiTarget,
|
|
`
|
|
component {
|
|
name: "foo",
|
|
}
|
|
|
|
package_module {
|
|
name: "package",
|
|
deps: ["foo"],
|
|
}
|
|
`, []string{"lib64/foo"})
|
|
|
|
runPackagingTest(t, multiTarget,
|
|
`
|
|
component {
|
|
name: "foo",
|
|
deps: ["bar"],
|
|
}
|
|
|
|
component {
|
|
name: "bar",
|
|
}
|
|
|
|
package_module {
|
|
name: "package",
|
|
deps: ["foo"],
|
|
}
|
|
`, []string{"lib64/foo", "lib64/bar"})
|
|
|
|
runPackagingTest(t, multiTarget,
|
|
`
|
|
component {
|
|
name: "foo",
|
|
deps: ["bar"],
|
|
}
|
|
|
|
component {
|
|
name: "bar",
|
|
}
|
|
|
|
package_module {
|
|
name: "package",
|
|
deps: ["foo"],
|
|
compile_multilib: "both",
|
|
}
|
|
`, []string{"lib32/foo", "lib32/bar", "lib64/foo", "lib64/bar"})
|
|
|
|
runPackagingTest(t, multiTarget,
|
|
`
|
|
component {
|
|
name: "foo",
|
|
}
|
|
|
|
component {
|
|
name: "bar",
|
|
compile_multilib: "32",
|
|
}
|
|
|
|
package_module {
|
|
name: "package",
|
|
deps: ["foo"],
|
|
multilib: {
|
|
lib32: {
|
|
deps: ["bar"],
|
|
},
|
|
},
|
|
compile_multilib: "both",
|
|
}
|
|
`, []string{"lib32/foo", "lib32/bar", "lib64/foo"})
|
|
|
|
runPackagingTest(t, multiTarget,
|
|
`
|
|
component {
|
|
name: "foo",
|
|
}
|
|
|
|
component {
|
|
name: "bar",
|
|
}
|
|
|
|
package_module {
|
|
name: "package",
|
|
deps: ["foo"],
|
|
multilib: {
|
|
first: {
|
|
deps: ["bar"],
|
|
},
|
|
},
|
|
compile_multilib: "both",
|
|
}
|
|
`, []string{"lib32/foo", "lib64/foo", "lib64/bar"})
|
|
|
|
runPackagingTest(t, multiTarget,
|
|
`
|
|
component {
|
|
name: "foo",
|
|
}
|
|
|
|
component {
|
|
name: "bar",
|
|
}
|
|
|
|
component {
|
|
name: "baz",
|
|
}
|
|
|
|
package_module {
|
|
name: "package",
|
|
deps: ["foo"],
|
|
arch: {
|
|
arm64: {
|
|
deps: ["bar"],
|
|
},
|
|
x86_64: {
|
|
deps: ["baz"],
|
|
},
|
|
},
|
|
compile_multilib: "both",
|
|
}
|
|
`, []string{"lib32/foo", "lib64/foo", "lib64/bar"})
|
|
}
|
|
|
|
func TestPackagingBaseSingleTarget(t *testing.T) {
|
|
multiTarget := false
|
|
runPackagingTest(t, multiTarget,
|
|
`
|
|
component {
|
|
name: "foo",
|
|
}
|
|
|
|
package_module {
|
|
name: "package",
|
|
deps: ["foo"],
|
|
}
|
|
`, []string{"lib64/foo"})
|
|
|
|
runPackagingTest(t, multiTarget,
|
|
`
|
|
component {
|
|
name: "foo",
|
|
deps: ["bar"],
|
|
}
|
|
|
|
component {
|
|
name: "bar",
|
|
}
|
|
|
|
package_module {
|
|
name: "package",
|
|
deps: ["foo"],
|
|
}
|
|
`, []string{"lib64/foo", "lib64/bar"})
|
|
|
|
runPackagingTest(t, multiTarget,
|
|
`
|
|
component {
|
|
name: "foo",
|
|
}
|
|
|
|
component {
|
|
name: "bar",
|
|
compile_multilib: "32",
|
|
}
|
|
|
|
package_module {
|
|
name: "package",
|
|
deps: ["foo"],
|
|
multilib: {
|
|
lib32: {
|
|
deps: ["bar"],
|
|
},
|
|
},
|
|
}
|
|
`, []string{"lib64/foo"})
|
|
|
|
runPackagingTest(t, multiTarget,
|
|
`
|
|
component {
|
|
name: "foo",
|
|
}
|
|
|
|
component {
|
|
name: "bar",
|
|
}
|
|
|
|
package_module {
|
|
name: "package",
|
|
deps: ["foo"],
|
|
multilib: {
|
|
lib64: {
|
|
deps: ["bar"],
|
|
},
|
|
},
|
|
}
|
|
`, []string{"lib64/foo", "lib64/bar"})
|
|
|
|
runPackagingTest(t, multiTarget,
|
|
`
|
|
component {
|
|
name: "foo",
|
|
}
|
|
|
|
component {
|
|
name: "bar",
|
|
}
|
|
|
|
component {
|
|
name: "baz",
|
|
}
|
|
|
|
package_module {
|
|
name: "package",
|
|
deps: ["foo"],
|
|
arch: {
|
|
arm64: {
|
|
deps: ["bar"],
|
|
},
|
|
x86_64: {
|
|
deps: ["baz"],
|
|
},
|
|
},
|
|
}
|
|
`, []string{"lib64/foo", "lib64/bar"})
|
|
|
|
runPackagingTest(t, multiTarget,
|
|
`
|
|
component {
|
|
name: "foo",
|
|
}
|
|
|
|
component {
|
|
name: "bar",
|
|
}
|
|
|
|
package_module {
|
|
name: "package",
|
|
deps: ["foo"],
|
|
install_deps: ["bar"],
|
|
}
|
|
`, []string{"lib64/foo"})
|
|
}
|
|
|
|
func TestPackagingWithSkipInstallDeps(t *testing.T) {
|
|
// package -[dep]-> foo -[dep]-> bar -[dep]-> baz
|
|
// Packaging should continue transitively through modules that are not installed.
|
|
multiTarget := false
|
|
runPackagingTest(t, multiTarget,
|
|
`
|
|
component {
|
|
name: "foo",
|
|
deps: ["bar"],
|
|
}
|
|
|
|
component {
|
|
name: "bar",
|
|
deps: ["baz"],
|
|
skip_install: true,
|
|
}
|
|
|
|
component {
|
|
name: "baz",
|
|
}
|
|
|
|
package_module {
|
|
name: "package",
|
|
deps: ["foo"],
|
|
}
|
|
`, []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"})
|
|
}
|