Add required, host_required, and target_required as dependencies

So far, the installation of required modules were handled by Make. This
prevents us from implementing the module installation and packaging
entirely in Soong.

This CL is the first step towards that goal. Soong now correctly tracks
the dependencies and they are correctly returned by
TransitivePackagingSpecs(), which is used by packaging modules like
android_system_image.

Bug: 321626681
Test: build
Change-Id: I9192b5333ceaa0b7d1c5c4abeec2af62febcd976
This commit is contained in:
Jiyong Park 2024-03-18 18:37:10 +09:00
parent 8fb0e9734c
commit 8bcf3c64f1
7 changed files with 119 additions and 1 deletions

View file

@ -305,6 +305,12 @@ type AllowDisabledModuleDependency interface {
AllowDisabledModuleDependency(target Module) bool
}
type AlwaysAllowDisabledModuleDependencyTag struct{}
func (t AlwaysAllowDisabledModuleDependencyTag) AllowDisabledModuleDependency(Module) bool {
return true
}
func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool, ignoreBlueprint bool) Module {
aModule, _ := module.(Module)

View file

@ -77,6 +77,11 @@ func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) {
if ctx.OtherModuleDependencyTag(dep) == DefaultsDepTag {
return
}
// The required dependencies just say modules A and B should be installed together.
// It doesn't mean that one is built using the other.
if ctx.OtherModuleDependencyTag(dep) == RequiredDepTag {
return
}
if info, ok := OtherModuleProvider(ctx, dep, LicenseMetadataProvider); ok {
allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath)

View file

@ -542,6 +542,15 @@ type TeamDepTagType struct {
var teamDepTag = TeamDepTagType{}
// Dependency tag for required, host_required, and target_required modules.
var RequiredDepTag = struct {
blueprint.BaseDependencyTag
InstallAlwaysNeededDependencyTag
// Requiring disabled module has been supported (as a side effect of this being implemented
// in Make). We may want to make it an error, but for now, let's keep the existing behavior.
AlwaysAllowDisabledModuleDependencyTag
}{}
// CommonTestOptions represents the common `test_options` properties in
// Android.bp.
type CommonTestOptions struct {
@ -1007,6 +1016,87 @@ func (m *ModuleBase) baseDepsMutator(ctx BottomUpMutatorContext) {
if m.Team() != "" {
ctx.AddDependency(ctx.Module(), teamDepTag, m.Team())
}
// TODO(jiyong): remove below case. This is to work around build errors happening
// on branches with reduced manifest like aosp_kernel-build-tools.
// In the branch, a build error occurs as follows.
// 1. aosp_kernel-build-tools is a reduced manifest branch. It doesn't have some git
// projects like external/bouncycastle
// 2. `boot_signer` is `required` by modules like `build_image` which is explicitly list as
// the top-level build goal (in the shell file that invokes Soong).
// 3. `boot_signer` depends on `bouncycastle-unbundled` which is in the missing git project.
// 4. aosp_kernel-build-tools invokes soong with `--skip-make`. Therefore, the absence of
// ALLOW_MISSING_DEPENDENCIES didn't cause a problem.
// 5. Now, since Soong understands `required` deps, it tries to build `boot_signer` and the
// absence of external/bouncycastle fails the build.
//
// Unfortunately, there's no way for Soong to correctly determine if it's running in a
// reduced manifest branch. Instead, here, we use the absence of DeviceArch or DeviceName as
// a strong signal, because that's very common across reduced manifest branches.
pv := ctx.Config().productVariables
fullManifest := pv.DeviceArch != nil && pv.DeviceName != nil
if fullManifest {
m.addRequiredDeps(ctx)
}
}
// addRequiredDeps adds required, target_required, and host_required as dependencies.
func (m *ModuleBase) addRequiredDeps(ctx BottomUpMutatorContext) {
addDep := func(target Target, depName string) {
if !ctx.OtherModuleExists(depName) {
if ctx.Config().AllowMissingDependencies() {
return
}
}
// If Android native module requires another Android native module, ensure that
// they have the same bitness. This mimics the policy in select-bitness-of-required-modules
// in build/make/core/main.mk.
// TODO(jiyong): the Make-side does this only when the required module is a shared
// library or a native test.
bothInAndroid := m.Device() && target.Os.Class == Device
nativeArch := m.Arch().ArchType.Multilib != string(MultilibCommon)
sameBitness := m.Arch().ArchType.Multilib == target.Arch.ArchType.Multilib
if bothInAndroid && nativeArch && !sameBitness {
return
}
variation := target.Variations()
if ctx.OtherModuleFarDependencyVariantExists(variation, depName) {
ctx.AddFarVariationDependencies(variation, RequiredDepTag, depName)
}
}
if m.Device() {
for _, depName := range m.RequiredModuleNames() {
for _, target := range ctx.Config().Targets[Android] {
addDep(target, depName)
}
}
for _, depName := range m.HostRequiredModuleNames() {
for _, target := range ctx.Config().Targets[ctx.Config().BuildOS] {
addDep(target, depName)
}
}
}
if m.Host() {
for _, depName := range m.RequiredModuleNames() {
for _, target := range ctx.Config().Targets[ctx.Config().BuildOS] {
// When a host module requires another host module, don't make a
// dependency if they have different OSes (i.e. hostcross).
if m.Target().HostCross != target.HostCross {
continue
}
addDep(target, depName)
}
}
for _, depName := range m.TargetRequiredModuleNames() {
for _, target := range ctx.Config().Targets[Android] {
addDep(target, depName)
}
}
}
}
// AddProperties "registers" the provided props

View file

@ -1821,6 +1821,9 @@ func (a *apexBundle) WalkPayloadDeps(ctx android.ModuleContext, do android.Paylo
if dt, ok := depTag.(*dependencyTag); ok && !dt.payload {
return false
}
if depTag == android.RequiredDepTag {
return false
}
ai, _ := android.OtherModuleProvider(ctx, child, android.ApexInfoProvider)
externalDep := !android.InList(ctx.ModuleName(), ai.InApexVariants)
@ -2314,6 +2317,8 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
// nothing
} else if depTag == android.DarwinUniversalVariantTag {
// nothing
} else if depTag == android.RequiredDepTag {
// nothing
} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
}

View file

@ -10047,7 +10047,6 @@ func TestAndroidMk_RequiredModules(t *testing.T) {
key: "myapex.key",
updatable: false,
java_libs: ["foo"],
required: ["otherapex"],
}
apex_key {

View file

@ -2980,6 +2980,9 @@ func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) {
if depTag == stubImplDepTag {
return false
}
if depTag == android.RequiredDepTag {
return false
}
// Even if target lib has no vendor variant, keep checking dependency
// graph in case it depends on vendor_available or product_available
@ -3157,6 +3160,10 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
return
}
if depTag == android.RequiredDepTag {
return
}
if dep.Target().Os != ctx.Os() {
ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
return

View file

@ -76,6 +76,11 @@ func TestFileSystemDeps(t *testing.T) {
cc_library {
name: "libbar",
required: ["libbaz"],
}
cc_library {
name: "libbaz",
}
`)
@ -87,6 +92,7 @@ func TestFileSystemDeps(t *testing.T) {
"bin/foo",
"lib/libbar.so",
"lib64/libbar.so",
"lib64/libbaz.so",
"etc/bpf/bpf.o",
}
for _, e := range expected {