blob: 4af901e61d8f3f548dbe087514dff6b64afb1e81 [file]
// Copyright 2025 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 cc
import (
"android/soong/android"
"path/filepath"
"strings"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
func init() {
android.RegisterModuleType("ndk_translation_package", NdkTranslationPackageFactory)
}
func NdkTranslationPackageFactory() android.Module {
module := &ndkTranslationPackage{}
module.AddProperties(&module.properties)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
return module
}
type ndkTranslationPackage struct {
android.ModuleBase
properties ndkTranslationPackageProperties
}
type ndkTranslationPackageProperties struct {
// Dependencies with native bridge variants that should be packaged.
// (e.g. arm and arm64 on an x86_64 device)
Native_bridge_deps []string
// Non-native bridge variants that should be packaged.
// (e.g. x86 and x86_64 on an x86_64 device)
Device_both_deps []string
// Non-native bridge variants with lib64 that should be packaged.
// (e.g. x86_64 on an x86_64 device)
Device_64_deps []string
// Non-native bridge variants with lib32 that should be packaged.
// (e.g. x86 on an x86_64 device)
Device_32_deps []string
// Non-native bridge variants whose first variant should be packaged.
Device_first_deps []string
// Non-native bridge variants whose first variant should be packaged,
// but always into lib/, bin/ directories.
Device_first_to_32_deps []string
// Non-native bridge variants that should _not_ be packaged, but
// used as inputs to generate Android.mk and product.mk
Device_both_extra_allowed_deps []string
Device_32_extra_allowed_deps []string
// Version to use in generating the new sysprops
Version *string
// Path to Android.bp generator
Android_bp_gen_path *string
// Path to product.mk generator
Product_mk_gen_path *string
}
type ndkTranslationPackageDepTag struct {
blueprint.DependencyTag
name string
}
func (_ ndkTranslationPackageDepTag) ExcludeFromVisibilityEnforcement() {}
// Some dependencies do not support native bridge variants for riscv
func (_ ndkTranslationPackageDepTag) AllowDisabledModuleDependency(target android.Module) bool {
return target.Target().NativeBridge == android.NativeBridgeEnabled &&
target.Target().Arch.ArchType == android.Riscv64
}
func (_ ndkTranslationPackageDepTag) AllowDisabledModuleDependencyProxy(ctx android.OtherModuleProviderContext, mod android.ModuleProxy) bool {
commonInfo := android.OtherModulePointerProviderOrDefault(ctx, mod, android.CommonModuleInfoProvider)
return commonInfo.Target.NativeBridge == android.NativeBridgeEnabled &&
commonInfo.Target.Arch.ArchType == android.Riscv64
}
var (
ndkTranslationPackageTag = ndkTranslationPackageDepTag{name: "dep"}
ndkTranslationPackageFirstTo32SrcsTag = ndkTranslationPackageDepTag{name: "first_to_32"}
ndkTranslationExtraAllowedDepsTag = ndkTranslationPackageDepTag{name: "extra_allowed_deps"}
)
func (n *ndkTranslationPackage) DepsMutator(ctx android.BottomUpMutatorContext) {
for index, t := range ctx.MultiTargets() {
if t.NativeBridge == android.NativeBridgeEnabled {
ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageTag, n.properties.Native_bridge_deps...)
} else if t.Arch.ArchType == android.X86_64 {
ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageTag, n.properties.Device_64_deps...)
ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageTag, n.properties.Device_both_deps...)
ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationExtraAllowedDepsTag, n.properties.Device_both_extra_allowed_deps...)
} else if t.Arch.ArchType == android.X86 {
ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageTag, n.properties.Device_32_deps...)
ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageTag, n.properties.Device_both_deps...)
ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationExtraAllowedDepsTag, n.properties.Device_both_extra_allowed_deps...)
ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationExtraAllowedDepsTag, n.properties.Device_32_extra_allowed_deps...)
}
if index == 0 { // Primary arch
ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageTag, n.properties.Device_first_deps...)
ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageFirstTo32SrcsTag, n.properties.Device_first_to_32_deps...)
}
}
}
func (n *ndkTranslationPackage) GenerateAndroidBuildActions(ctx android.ModuleContext) {
var files []android.PackagingSpec // both arches
var files64 []android.PackagingSpec // 64 only
var extraFiles []android.PackagingSpec
var extraFiles64 []android.PackagingSpec
ctx.VisitDirectDepsProxy(func(child android.ModuleProxy) {
tag := ctx.OtherModuleDependencyTag(child)
info := android.OtherModuleProviderOrDefault(ctx, child, android.InstallFilesProvider)
commonInfo := android.OtherModulePointerProviderOrDefault(ctx, child, android.CommonModuleInfoProvider)
if tag == ndkTranslationExtraAllowedDepsTag {
extraFiles = append(extraFiles, info.PackagingSpecs...)
if commonInfo.Target.Arch.ArchType == android.X86_64 || commonInfo.Target.Arch.ArchType == android.Arm64 {
extraFiles64 = append(extraFiles64, info.PackagingSpecs...)
}
return
}
files = append(files, info.PackagingSpecs...)
if (commonInfo.Target.Arch.ArchType == android.X86_64 || commonInfo.Target.Arch.ArchType == android.Arm64) && tag != ndkTranslationPackageFirstTo32SrcsTag {
files64 = append(files64, info.PackagingSpecs...)
}
})
outBp := n.genAndroidBp(ctx, files)
outArm64ArmMk, outArm64Mk := n.genProductMk(ctx, files, files64, extraFiles, extraFiles64)
outZip := android.PathForModuleOut(ctx, "ndk_translation_package.zip")
builder := android.NewRuleBuilder(pctx, ctx)
cmd := builder.Command().
BuiltTool("soong_zip").
FlagWithOutput("-o ", outZip)
for _, buildFile := range []android.Path{outBp, outArm64ArmMk, outArm64Mk} {
cmd.
FlagWithArg("-C ", filepath.Dir(buildFile.String())).
FlagWithInput("-f ", buildFile)
}
for _, file := range files {
// Copy to relative path inside the zip
cmd.
FlagWithArg("-e ", "system/"+file.RelPathInPackage()).
FlagWithInput("-f ", file.SrcPath())
}
builder.Build("ndk_translation_package.zip", "Build ndk_translation_package")
ctx.CheckbuildFile(outZip)
ctx.DistForGoal("ndk_translation_package", outZip)
}
// Creates a build rule to generate Android.bp and returns path of the generated file.
func (n *ndkTranslationPackage) genAndroidBp(ctx android.ModuleContext, files []android.PackagingSpec) android.Path {
genDir := android.PathForModuleOut(ctx, "android_bp_dir")
generator := android.PathForModuleSrc(ctx, proptools.String(n.properties.Android_bp_gen_path))
builder := android.NewRuleBuilder(pctx, ctx).Sbox(
genDir,
android.PathForModuleOut(ctx, "Android.bp.sbox.textproto"),
)
outBp := genDir.Join(ctx, "Android.bp")
builder.Command().
Input(generator).
Implicits(specsToSrcPaths(files)).
Flag(strings.Join(filesRelativeToInstallDir(ctx, files), " ")).
FlagWithOutput("> ", outBp)
builder.Build("ndk_translation_package.Android.bp", "Build ndk_translation_package Android.bp")
return outBp
}
// Creates a build rule to generate product.mk and returns path of the generated files
func (n *ndkTranslationPackage) genProductMk(ctx android.ModuleContext, files, files64, extraFiles, extraFiles64 []android.PackagingSpec) (android.Path, android.Path) {
genDir := android.PathForModuleOut(ctx, "product_arm64_arm_dir")
generator := android.PathForModuleSrc(ctx, proptools.String(n.properties.Product_mk_gen_path))
// Both arches
builder := android.NewRuleBuilder(pctx, ctx).Sbox(
genDir,
android.PathForModuleOut(ctx, "product_arm64_arm.mk.textproto"),
)
outArm64ArmMk := genDir.Join(ctx, "product_arm64_arm.mk")
builder.Command().
Input(generator).
Implicits(specsToSrcPaths(files)).
FlagWithArg("--version=", proptools.String(n.properties.Version)).
Flag("--arm64 --arm").
FlagForEachArg("--extra_allowed_artifact ", filesRelativeToInstallDir(ctx, extraFiles)).
Flag(strings.Join(filesRelativeToInstallDir(ctx, files), " ")).
FlagWithOutput("> ", outArm64ArmMk)
builder.Build("ndk_translation_package.product_arm64_arm.mk", "Build ndk_translation_package product_arm64_arm.mk")
// Arm64 only
genDir = android.PathForModuleOut(ctx, "product_arm64_dir")
builder = android.NewRuleBuilder(pctx, ctx).Sbox(
genDir,
android.PathForModuleOut(ctx, "product_arm64.mk.textproto"),
)
outArm64Mk := genDir.Join(ctx, "product_arm64.mk")
builder.Command().
Input(generator).
Implicits(specsToSrcPaths(files64)).
FlagWithArg("--version=", proptools.String(n.properties.Version)).
Flag("--arm64").
FlagForEachArg("--extra_allowed_artifact ", filesRelativeToInstallDir(ctx, extraFiles64)).
Flag(strings.Join(filesRelativeToInstallDir(ctx, files64), " ")).
FlagWithOutput("> ", outArm64Mk)
builder.Build("ndk_translation_package.product_arm_64.mk", "Build ndk_translation_package product_arm64.mk")
return outArm64ArmMk, outArm64Mk
}
func filesRelativeToInstallDir(ctx android.ModuleContext, files []android.PackagingSpec) []string {
var ret []string
for _, file := range files {
ret = append(ret, "system/"+file.RelPathInPackage())
}
return ret
}
func specsToSrcPaths(specs []android.PackagingSpec) android.Paths {
var ret android.Paths
for _, spec := range specs {
ret = append(ret, spec.SrcPath())
}
return ret
}