Merge changes Ic22603a5,I5330b571

* changes:
  Annotate dependency tags for dependencies of installed files
  Use the the preferred architecture symlink as the tool path if it exists
This commit is contained in:
Colin Cross 2020-11-16 23:11:10 +00:00 committed by Gerrit Code Review
commit f15c0558bf
15 changed files with 361 additions and 32 deletions

View file

@ -21,6 +21,7 @@ bootstrap_go_package {
"defaults.go",
"defs.go",
"depset.go",
"deptag.go",
"expand.go",
"filegroup.go",
"hooks.go",
@ -68,6 +69,7 @@ bootstrap_go_package {
"config_test.go",
"csuite_config_test.go",
"depset_test.go",
"deptag_test.go",
"expand_test.go",
"module_test.go",
"mutator_test.go",

View file

@ -598,6 +598,10 @@ var (
// has dependencies on all the OS variants.
CommonOS = NewOsType("common_os", Generic, false)
// CommonArch is the Arch for all modules that are os-specific but not arch specific,
// for example most Java modules.
CommonArch = Arch{ArchType: Common}
osArchTypeMap = map[OsType][]ArchType{
Linux: []ArchType{X86, X86_64},
LinuxBionic: []ArchType{Arm64, X86_64},
@ -661,7 +665,7 @@ func NewOsType(name string, class OsClass, defDisabled bool) OsType {
if _, found := commonTargetMap[name]; found {
panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
} else {
commonTargetMap[name] = Target{Os: os, Arch: Arch{ArchType: Common}}
commonTargetMap[name] = Target{Os: os, Arch: CommonArch}
}
return os
@ -819,9 +823,6 @@ type archDepTag struct {
// Identifies the dependency from CommonOS variant to the os specific variants.
var commonOsToOsSpecificVariantTag = archDepTag{name: "common os to os specific"}
// Identifies the dependency from arch variant to the common variant for a "common_first" multilib.
var firstArchToCommonArchDepTag = archDepTag{name: "first arch to common arch"}
// Get the OsType specific variants for the current CommonOS variant.
//
// The returned list will only contain enabled OsType specific variants of the
@ -960,12 +961,6 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) {
addTargetProperties(m, targets[i], multiTargets, i == 0)
m.base().setArchProperties(mctx)
}
if multilib == "common_first" && len(modules) >= 2 {
for i := range modules[1:] {
mctx.AddInterVariantDependency(firstArchToCommonArchDepTag, modules[i+1], modules[0])
}
}
}
func addTargetProperties(m Module, target Target, multiTargets []Target, primaryTarget bool) {

45
android/deptag.go Normal file
View file

@ -0,0 +1,45 @@
// 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 "github.com/google/blueprint"
// Dependency tags can implement this interface and return true from InstallDepNeeded to annotate
// that the installed files of the parent should depend on the installed files of the child.
type InstallNeededDependencyTag interface {
// If InstallDepNeeded returns true then the installed files of the parent will depend on the
// installed files of the child.
InstallDepNeeded() bool
}
// Dependency tags can embed this struct to annotate that the installed files of the parent should
// depend on the installed files of the child.
type InstallAlwaysNeededDependencyTag struct{}
func (i InstallAlwaysNeededDependencyTag) InstallDepNeeded() bool {
return true
}
var _ InstallNeededDependencyTag = InstallAlwaysNeededDependencyTag{}
// IsInstallDepNeeded returns true if the dependency tag implements the InstallNeededDependencyTag
// interface and the InstallDepNeeded returns true, meaning that the installed files of the parent
// should depend on the installed files of the child.
func IsInstallDepNeeded(tag blueprint.DependencyTag) bool {
if i, ok := tag.(InstallNeededDependencyTag); ok {
return i.InstallDepNeeded()
}
return false
}

135
android/deptag_test.go Normal file
View file

@ -0,0 +1,135 @@
// 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"
)
type testInstallDependencyTagModule struct {
ModuleBase
Properties struct {
Install_deps []string
Deps []string
}
}
func (t *testInstallDependencyTagModule) GenerateAndroidBuildActions(ctx ModuleContext) {
outputFile := PathForModuleOut(ctx, "out")
ctx.Build(pctx, BuildParams{
Rule: Touch,
Output: outputFile,
})
ctx.InstallFile(PathForModuleInstall(ctx), ctx.ModuleName(), outputFile)
}
var testInstallDependencyTagAlwaysDepTag = struct {
blueprint.DependencyTag
InstallAlwaysNeededDependencyTag
}{}
var testInstallDependencyTagNeverDepTag = struct {
blueprint.DependencyTag
}{}
func (t *testInstallDependencyTagModule) DepsMutator(ctx BottomUpMutatorContext) {
ctx.AddVariationDependencies(nil, testInstallDependencyTagAlwaysDepTag, t.Properties.Install_deps...)
ctx.AddVariationDependencies(nil, testInstallDependencyTagNeverDepTag, t.Properties.Deps...)
}
func testInstallDependencyTagModuleFactory() Module {
module := &testInstallDependencyTagModule{}
InitAndroidArchModule(module, HostAndDeviceDefault, MultilibCommon)
module.AddProperties(&module.Properties)
return module
}
func TestInstallDependencyTag(t *testing.T) {
bp := `
test_module {
name: "foo",
deps: ["dep"],
install_deps: ["install_dep"],
}
test_module {
name: "install_dep",
install_deps: ["transitive"],
}
test_module {
name: "transitive",
}
test_module {
name: "dep",
}
`
config := TestArchConfig(buildDir, nil, bp, nil)
ctx := NewTestArchContext(config)
ctx.RegisterModuleType("test_module", testInstallDependencyTagModuleFactory)
ctx.Register()
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
FailIfErrored(t, errs)
hostFoo := ctx.ModuleForTests("foo", config.BuildOSCommonTarget.String()).Description("install")
hostInstallDep := ctx.ModuleForTests("install_dep", config.BuildOSCommonTarget.String()).Description("install")
hostTransitive := ctx.ModuleForTests("transitive", config.BuildOSCommonTarget.String()).Description("install")
hostDep := ctx.ModuleForTests("dep", config.BuildOSCommonTarget.String()).Description("install")
if g, w := hostFoo.Implicits.Strings(), hostInstallDep.Output.String(); !InList(w, g) {
t.Errorf("expected host dependency %q, got %q", w, g)
}
if g, w := hostFoo.Implicits.Strings(), hostTransitive.Output.String(); !InList(w, g) {
t.Errorf("expected host dependency %q, got %q", w, g)
}
if g, w := hostInstallDep.Implicits.Strings(), hostTransitive.Output.String(); !InList(w, g) {
t.Errorf("expected host dependency %q, got %q", w, g)
}
if g, w := hostFoo.Implicits.Strings(), hostDep.Output.String(); InList(w, g) {
t.Errorf("expected no host dependency %q, got %q", w, g)
}
deviceFoo := ctx.ModuleForTests("foo", "android_common").Description("install")
deviceInstallDep := ctx.ModuleForTests("install_dep", "android_common").Description("install")
deviceTransitive := ctx.ModuleForTests("transitive", "android_common").Description("install")
deviceDep := ctx.ModuleForTests("dep", "android_common").Description("install")
if g, w := deviceFoo.OrderOnly.Strings(), deviceInstallDep.Output.String(); !InList(w, g) {
t.Errorf("expected device dependency %q, got %q", w, g)
}
if g, w := deviceFoo.OrderOnly.Strings(), deviceTransitive.Output.String(); !InList(w, g) {
t.Errorf("expected device dependency %q, got %q", w, g)
}
if g, w := deviceInstallDep.OrderOnly.Strings(), deviceTransitive.Output.String(); !InList(w, g) {
t.Errorf("expected device dependency %q, got %q", w, g)
}
if g, w := deviceFoo.OrderOnly.Strings(), deviceDep.Output.String(); InList(w, g) {
t.Errorf("expected no device dependency %q, got %q", w, g)
}
}

View file

@ -1242,14 +1242,18 @@ func (m *ModuleBase) ExportedToMake() bool {
return m.commonProperties.NamespaceExportedToMake
}
// computeInstallDeps finds the installed paths of all dependencies that have a dependency
// tag that is annotated as needing installation via the IsInstallDepNeeded method.
func (m *ModuleBase) computeInstallDeps(ctx blueprint.ModuleContext) InstallPaths {
var result InstallPaths
// TODO(ccross): we need to use WalkDeps and have some way to know which dependencies require installation
ctx.VisitDepsDepthFirst(func(m blueprint.Module) {
if a, ok := m.(Module); ok {
result = append(result, a.FilesToInstall()...)
ctx.WalkDeps(func(child, parent blueprint.Module) bool {
if a, ok := child.(Module); ok {
if IsInstallDepNeeded(ctx.OtherModuleDependencyTag(child)) {
result = append(result, a.FilesToInstall()...)
return true
}
}
return false
})
return result

View file

@ -95,6 +95,10 @@ type binaryDecorator struct {
// Names of symlinks to be installed for use in LOCAL_MODULE_SYMLINKS
symlinks []string
// If the module has symlink_preferred_arch set, the name of the symlink to the
// binary for the preferred arch.
preferredArchSymlink string
// Output archive of gcno coverage information
coverageOutputFile android.OptionalPath
@ -402,7 +406,9 @@ func (binary *binaryDecorator) link(ctx ModuleContext,
ctx.PropertyErrorf("symlink_preferred_arch", "must also specify suffix")
}
if ctx.TargetPrimary() {
binary.symlinks = append(binary.symlinks, binary.getStemWithoutSuffix(ctx))
symlinkName := binary.getStemWithoutSuffix(ctx)
binary.symlinks = append(binary.symlinks, symlinkName)
binary.preferredArchSymlink = symlinkName
}
}
@ -455,12 +461,26 @@ func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) {
binary.baseInstaller.subDir = "bootstrap"
}
binary.baseInstaller.install(ctx, file)
var preferredArchSymlinkPath android.OptionalPath
for _, symlink := range binary.symlinks {
ctx.InstallSymlink(binary.baseInstaller.installDir(ctx), symlink, binary.baseInstaller.path)
installedSymlink := ctx.InstallSymlink(binary.baseInstaller.installDir(ctx), symlink,
binary.baseInstaller.path)
if symlink == binary.preferredArchSymlink {
// If this is the preferred arch symlink, save the installed path for use as the
// tool path.
preferredArchSymlinkPath = android.OptionalPathForPath(installedSymlink)
}
}
if ctx.Os().Class == android.Host {
binary.toolPath = android.OptionalPathForPath(binary.baseInstaller.path)
// If the binary is multilib with a symlink to the preferred architecture, use the
// symlink instead of the binary because that's the more "canonical" name.
if preferredArchSymlinkPath.Valid() {
binary.toolPath = preferredArchSymlinkPath
} else {
binary.toolPath = android.OptionalPathForPath(binary.baseInstaller.path)
}
}
}

View file

@ -550,7 +550,15 @@ func (d libraryDependencyTag) static() bool {
return d.Kind == staticLibraryDependency
}
// dependencyTag is used for tagging miscellanous dependency types that don't fit into
// InstallDepNeeded returns true for shared libraries so that shared library dependencies of
// binaries or other shared libraries are installed as dependencies.
func (d libraryDependencyTag) InstallDepNeeded() bool {
return d.shared()
}
var _ android.InstallNeededDependencyTag = libraryDependencyTag{}
// dependencyTag is used for tagging miscellaneous dependency types that don't fit into
// libraryDependencyTag. Each tag object is created globally and reused for multiple
// dependencies (although since the object contains no references, assigning a tag to a
// variable and modifying it will not modify the original). Users can compare the tag
@ -560,6 +568,15 @@ type dependencyTag struct {
name string
}
// installDependencyTag is used for tagging miscellaneous dependency types that don't fit into
// libraryDependencyTag, but where the dependency needs to be installed when the parent is
// installed.
type installDependencyTag struct {
blueprint.BaseDependencyTag
android.InstallAlwaysNeededDependencyTag
name string
}
var (
genSourceDepTag = dependencyTag{name: "gen source"}
genHeaderDepTag = dependencyTag{name: "gen header"}
@ -571,7 +588,7 @@ var (
staticVariantTag = dependencyTag{name: "static variant"}
vndkExtDepTag = dependencyTag{name: "vndk extends"}
dataLibDepTag = dependencyTag{name: "data lib"}
runtimeDepTag = dependencyTag{name: "runtime lib"}
runtimeDepTag = installDependencyTag{name: "runtime lib"}
testPerSrcDepTag = dependencyTag{name: "test_per_src"}
stubImplDepTag = dependencyTag{name: "stub_impl"}
)
@ -598,8 +615,7 @@ func IsHeaderDepTag(depTag blueprint.DependencyTag) bool {
}
func IsRuntimeDepTag(depTag blueprint.DependencyTag) bool {
ccDepTag, ok := depTag.(dependencyTag)
return ok && ccDepTag == runtimeDepTag
return depTag == runtimeDepTag
}
func IsTestPerSrcDepTag(depTag blueprint.DependencyTag) bool {

View file

@ -3941,3 +3941,98 @@ func TestEmptyWholeStaticLibsAllowMissingDependencies(t *testing.T) {
}
}
func TestInstallSharedLibs(t *testing.T) {
bp := `
cc_binary {
name: "bin",
host_supported: true,
shared_libs: ["libshared"],
runtime_libs: ["libruntime"],
srcs: [":gen"],
}
cc_library_shared {
name: "libshared",
host_supported: true,
shared_libs: ["libtransitive"],
}
cc_library_shared {
name: "libtransitive",
host_supported: true,
}
cc_library_shared {
name: "libruntime",
host_supported: true,
}
cc_binary_host {
name: "tool",
srcs: ["foo.cpp"],
}
genrule {
name: "gen",
tools: ["tool"],
out: ["gen.cpp"],
cmd: "$(location tool) $(out)",
}
`
config := TestConfig(buildDir, android.Android, nil, bp, nil)
ctx := testCcWithConfig(t, config)
hostBin := ctx.ModuleForTests("bin", config.BuildOSTarget.String()).Description("install")
hostShared := ctx.ModuleForTests("libshared", config.BuildOSTarget.String()+"_shared").Description("install")
hostRuntime := ctx.ModuleForTests("libruntime", config.BuildOSTarget.String()+"_shared").Description("install")
hostTransitive := ctx.ModuleForTests("libtransitive", config.BuildOSTarget.String()+"_shared").Description("install")
hostTool := ctx.ModuleForTests("tool", config.BuildOSTarget.String()).Description("install")
if g, w := hostBin.Implicits.Strings(), hostShared.Output.String(); !android.InList(w, g) {
t.Errorf("expected host bin dependency %q, got %q", w, g)
}
if g, w := hostBin.Implicits.Strings(), hostTransitive.Output.String(); !android.InList(w, g) {
t.Errorf("expected host bin dependency %q, got %q", w, g)
}
if g, w := hostShared.Implicits.Strings(), hostTransitive.Output.String(); !android.InList(w, g) {
t.Errorf("expected host bin dependency %q, got %q", w, g)
}
if g, w := hostBin.Implicits.Strings(), hostRuntime.Output.String(); !android.InList(w, g) {
t.Errorf("expected host bin dependency %q, got %q", w, g)
}
if g, w := hostBin.Implicits.Strings(), hostTool.Output.String(); android.InList(w, g) {
t.Errorf("expected no host bin dependency %q, got %q", w, g)
}
deviceBin := ctx.ModuleForTests("bin", "android_arm64_armv8-a").Description("install")
deviceShared := ctx.ModuleForTests("libshared", "android_arm64_armv8-a_shared").Description("install")
deviceTransitive := ctx.ModuleForTests("libtransitive", "android_arm64_armv8-a_shared").Description("install")
deviceRuntime := ctx.ModuleForTests("libruntime", "android_arm64_armv8-a_shared").Description("install")
if g, w := deviceBin.OrderOnly.Strings(), deviceShared.Output.String(); !android.InList(w, g) {
t.Errorf("expected device bin dependency %q, got %q", w, g)
}
if g, w := deviceBin.OrderOnly.Strings(), deviceTransitive.Output.String(); !android.InList(w, g) {
t.Errorf("expected device bin dependency %q, got %q", w, g)
}
if g, w := deviceShared.OrderOnly.Strings(), deviceTransitive.Output.String(); !android.InList(w, g) {
t.Errorf("expected device bin dependency %q, got %q", w, g)
}
if g, w := deviceBin.OrderOnly.Strings(), deviceRuntime.Output.String(); !android.InList(w, g) {
t.Errorf("expected device bin dependency %q, got %q", w, g)
}
if g, w := deviceBin.OrderOnly.Strings(), hostTool.Output.String(); android.InList(w, g) {
t.Errorf("expected no device bin dependency %q, got %q", w, g)
}
}

View file

@ -16,6 +16,7 @@ package cc
import (
"android/soong/android"
"android/soong/genrule"
)
func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
@ -24,6 +25,7 @@ func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
RegisterBinaryBuildComponents(ctx)
RegisterLibraryBuildComponents(ctx)
RegisterLibraryHeadersBuildComponents(ctx)
genrule.RegisterGenruleBuildComponents(ctx)
ctx.RegisterModuleType("toolchain_library", ToolchainLibraryFactory)
ctx.RegisterModuleType("llndk_library", LlndkLibraryFactory)

View file

@ -31,10 +31,10 @@ import (
)
func init() {
registerGenruleBuildComponents(android.InitRegistrationContext)
RegisterGenruleBuildComponents(android.InitRegistrationContext)
}
func registerGenruleBuildComponents(ctx android.RegistrationContext) {
func RegisterGenruleBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("genrule_defaults", defaultsFactory)
ctx.RegisterModuleType("gensrcs", GenSrcsFactory)

View file

@ -57,7 +57,7 @@ func testContext(config android.Config) *android.TestContext {
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
ctx.RegisterModuleType("tool", toolFactory)
registerGenruleBuildComponents(ctx)
RegisterGenruleBuildComponents(ctx)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.Register()

View file

@ -547,6 +547,14 @@ type dependencyTag struct {
name string
}
// installDependencyTag is a dependency tag that is annotated to cause the installed files of the
// dependency to be installed when the parent module is installed.
type installDependencyTag struct {
blueprint.BaseDependencyTag
android.InstallAlwaysNeededDependencyTag
name string
}
type usesLibraryDependencyTag struct {
dependencyTag
sdkVersion int // SDK version in which the library appared as a standalone library.
@ -580,6 +588,8 @@ var (
instrumentationForTag = dependencyTag{name: "instrumentation_for"}
extraLintCheckTag = dependencyTag{name: "extra-lint-check"}
jniLibTag = dependencyTag{name: "jnilib"}
jniInstallTag = installDependencyTag{name: "jni install"}
binaryInstallTag = installDependencyTag{name: "binary install"}
usesLibTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion)
usesLibCompat28Tag = makeUsesLibraryDependencyTag(28)
usesLibCompat29Tag = makeUsesLibraryDependencyTag(29)
@ -2550,9 +2560,12 @@ func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) {
if ctx.Arch().ArchType == android.Common {
j.deps(ctx)
} else {
// This dependency ensures the host installation rules will install the jni libraries
// when the wrapper is installed.
ctx.AddVariationDependencies(nil, jniLibTag, j.binaryProperties.Jni_libs...)
// These dependencies ensure the host installation rules will install the jar file and
// the jni libraries when the wrapper is installed.
ctx.AddVariationDependencies(nil, jniInstallTag, j.binaryProperties.Jni_libs...)
ctx.AddVariationDependencies(
[]blueprint.Variation{{Mutator: "arch", Variation: android.CommonArch.String()}},
binaryInstallTag, ctx.ModuleName())
}
}

View file

@ -29,7 +29,6 @@ import (
"android/soong/android"
"android/soong/cc"
"android/soong/dexpreopt"
"android/soong/genrule"
"android/soong/python"
)
@ -80,7 +79,6 @@ func testContext(config android.Config) *android.TestContext {
RegisterSystemModulesBuildComponents(ctx)
ctx.RegisterModuleType("java_plugin", PluginFactory)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
ctx.RegisterModuleType("python_binary_host", python.PythonBinaryHostFactory)
RegisterDocsBuildComponents(ctx)
RegisterStubsBuildComponents(ctx)

View file

@ -286,6 +286,12 @@ func TestSourceProviderDeps(t *testing.T) {
srcs: ["src/any.h"],
out: ["src/any.rs"],
}
rust_binary_host {
name: "any_rust_binary",
srcs: [
"foo.rs",
],
}
rust_bindgen {
name: "libbindings",
crate_name: "bindings",

View file

@ -17,7 +17,6 @@ package rust
import (
"android/soong/android"
"android/soong/cc"
"android/soong/genrule"
)
func GatherRequiredDepsForTest() string {
@ -132,7 +131,6 @@ func CreateTestContext(config android.Config) *android.TestContext {
android.RegisterPrebuiltMutators(ctx)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
cc.RegisterRequiredBuildComponentsForTest(ctx)
ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
ctx.RegisterModuleType("rust_binary", RustBinaryFactory)
ctx.RegisterModuleType("rust_binary_host", RustBinaryHostFactory)
ctx.RegisterModuleType("rust_bindgen", RustBindgenFactory)