Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  androidmk.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2015 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.

// This file offers AndroidMkEntriesProvider, which individual modules implement to output
// Android.mk entries that contain information about the modules built through Soong. Kati reads
// and combines them with the legacy Make-based module definitions to produce the complete view of
// the source tree, which makes this a critical point of Make-Soong interoperability.
//
// Naturally, Soong-only builds do not rely on this mechanism.

package android

import (
 "bytes"
 "fmt"
 "io"
 "os"
 "path/filepath"
 "reflect"
 "runtime"
 "sort"
 "strings"

 "github.com/google/blueprint"
 "github.com/google/blueprint/pathtools"
 "github.com/google/blueprint/proptools"
)

//go:generate go run ../../blueprint/gobtools/codegen

func init() {
 RegisterAndroidMkBuildComponents(InitRegistrationContext)
}

func RegisterAndroidMkBuildComponents(ctx RegistrationContext) {
 ctx.RegisterParallelSingletonType("androidmk", AndroidMkSingleton)
}

// Enable androidmk support.
// * Register the singleton
// * Configure that we are inside make
var PrepareForTestWithAndroidMk = GroupFixturePreparers(
 FixtureRegisterWithContext(RegisterAndroidMkBuildComponents),
 FixtureModifyConfig(SetKatiEnabledForTests),
)

// Deprecated: Use AndroidMkEntriesProvider instead, especially if you're not going to use the
// Custom function. It's easier to use and test.
type AndroidMkDataProvider interface {
 AndroidMk() AndroidMkData
 BaseModuleName() string
}

type AndroidMkData struct {
 Class           string
 SubName         string
 OutputFile      OptionalPath
 Include         string
 Required        []string
 Host_required   []string
 Target_required []string

 Custom func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData)

 Extra []AndroidMkExtraFunc

 Entries AndroidMkEntries
}

// @auto-generate: gob
type AndroidMkDataInfo struct {
 Class string
}

type AndroidMkExtraFunc func(w io.Writer, outputFile Path)

// Interface for modules to declare their Android.mk outputs. Note that every module needs to
// implement this in order to be included in the final Android-<product_name>.mk output, even if
// they only need to output the common set of entries without any customizations.
type AndroidMkEntriesProvider interface {
 // Returns AndroidMkEntries objects that contain all basic info plus extra customization data
 // if needed. This is the core func to implement.
 // Note that one can return multiple objects. For example, java_library may return an additional
 // AndroidMkEntries object for its hostdex sub-module.
 AndroidMkEntries() []AndroidMkEntries
 // Modules don't need to implement this as it's already implemented by ModuleBase.
 // AndroidMkEntries uses BaseModuleName() instead of ModuleName() because certain modules
 // e.g. Prebuilts, override the Name() func and return modified names.
 // If a different name is preferred, use SubName or OverrideName in AndroidMkEntries.
 BaseModuleName() string
}

// The core data struct that modules use to provide their Android.mk data.
type AndroidMkEntries struct {
 // Android.mk class string, e.g EXECUTABLES, JAVA_LIBRARIES, ETC
 Class string
 // Optional suffix to append to the module name. Useful when a module wants to return multiple
 // AndroidMkEntries objects. For example, when a java_library returns an additional entry for
 // its hostdex sub-module, this SubName field is set to "-hostdex" so that it can have a
 // different name than the parent's.
 SubName string
 // If set, this value overrides the base module name. SubName is still appended.
 OverrideName string
 // The output file for Kati to process and/or install. If absent, the module is skipped.
 OutputFile OptionalPath
 // The postprocessing mk file to include, e.g. $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk
 // If not set, $(BUILD_SYSTEM)/prebuilt.mk is used.
 Include string
 // Required modules that need to be built and included in the final build output when building
 // this module.
 Required []string
 // Required host modules that need to be built and included in the final build output when
 // building this module.
 Host_required []string
 // Required device modules that need to be built and included in the final build output when
 // building this module.
 Target_required []string

 header bytes.Buffer
 footer bytes.Buffer

 // Funcs to append additional Android.mk entries or modify the common ones. Multiple funcs are
 // accepted so that common logic can be factored out as a shared func.
 ExtraEntries []AndroidMkExtraEntriesFunc
 // Funcs to add extra lines to the module's Android.mk output. Unlike AndroidMkExtraEntriesFunc,
 // which simply sets Make variable values, this can be used for anything since it can write any
 // Make statements directly to the final Android-*.mk file.
 // Primarily used to call macros or declare/update Make targets.
 ExtraFooters []AndroidMkExtraFootersFunc

 // A map that holds the up-to-date Make variable values. Can be accessed from tests.
 EntryMap map[string][]string
 // A list of EntryMap keys in insertion order. This serves a few purposes:
 // 1. Prevents churns. Golang map doesn't provide consistent iteration order, so without this,
 // the outputted Android-*.mk file may change even though there have been no content changes.
 // 2. Allows modules to refer to other variables, like LOCAL_BAR_VAR := $(LOCAL_FOO_VAR),
 // without worrying about the variables being mixed up in the actual mk file.
 // 3. Makes troubleshooting and spotting errors easier.
 entryOrder []string

 // Provides data typically stored by Context objects that are commonly needed by
 //AndroidMkEntries objects.
 entryContext AndroidMkEntriesContext
}

type AndroidMkEntriesContext interface {
 OtherModuleProviderContext
 Config() Config
}

type AndroidMkExtraEntriesContext interface {
 Provider(provider blueprint.AnyProviderKey) (any, bool)
}

type androidMkExtraEntriesContext struct {
 ctx fillInEntriesContext
 mod Module
}

func (a *androidMkExtraEntriesContext) Provider(provider blueprint.AnyProviderKey) (any, bool) {
 return a.ctx.otherModuleProvider(a.mod, provider)
}

type AndroidMkExtraEntriesFunc func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries)
type AndroidMkExtraFootersFunc func(w io.Writer, name, prefix, moduleDir string)

// Utility funcs to manipulate Android.mk variable entries.

// SetString sets a Make variable with the given name to the given value.
func (a *AndroidMkEntries) SetString(name, value string) {
 if _, ok := a.EntryMap[name]; !ok {
  a.entryOrder = append(a.entryOrder, name)
 }
 a.EntryMap[name] = []string{value}
}

// SetPath sets a Make variable with the given name to the given path string.
func (a *AndroidMkEntries) SetPath(name string, path Path) {
 if _, ok := a.EntryMap[name]; !ok {
  a.entryOrder = append(a.entryOrder, name)
 }
 a.EntryMap[name] = []string{path.String()}
}

// SetOptionalPath sets a Make variable with the given name to the given path string if it is valid.
// It is a no-op if the given path is invalid.
func (a *AndroidMkEntries) SetOptionalPath(name string, path OptionalPath) {
 if path.Valid() {
  a.SetPath(name, path.Path())
 }
}

// AddPath appends the given path string to a Make variable with the given name.
func (a *AndroidMkEntries) AddPath(name string, path Path) {
 if _, ok := a.EntryMap[name]; !ok {
  a.entryOrder = append(a.entryOrder, name)
 }
 a.EntryMap[name] = append(a.EntryMap[name], path.String())
}

// AddOptionalPath appends the given path string to a Make variable with the given name if it is
// valid. It is a no-op if the given path is invalid.
func (a *AndroidMkEntries) AddOptionalPath(name string, path OptionalPath) {
 if path.Valid() {
  a.AddPath(name, path.Path())
 }
}

// SetPaths sets a Make variable with the given name to a slice of the given path strings.
func (a *AndroidMkEntries) SetPaths(name string, paths Paths) {
 if _, ok := a.EntryMap[name]; !ok {
  a.entryOrder = append(a.entryOrder, name)
 }
 a.EntryMap[name] = paths.Strings()
}

// SetOptionalPaths sets a Make variable with the given name to a slice of the given path strings
// only if there are a non-zero amount of paths.
func (a *AndroidMkEntries) SetOptionalPaths(name string, paths Paths) {
 if len(paths) > 0 {
  a.SetPaths(name, paths)
 }
}

// AddPaths appends the given path strings to a Make variable with the given name.
func (a *AndroidMkEntries) AddPaths(name string, paths Paths) {
 if _, ok := a.EntryMap[name]; !ok {
  a.entryOrder = append(a.entryOrder, name)
 }
 a.EntryMap[name] = append(a.EntryMap[name], paths.Strings()...)
}

// SetBoolIfTrue sets a Make variable with the given name to true if the given flag is true.
// It is a no-op if the given flag is false.
func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) {
 if flag {
  if _, ok := a.EntryMap[name]; !ok {
   a.entryOrder = append(a.entryOrder, name)
  }
  a.EntryMap[name] = []string{"true"}
 }
}

// SetBool sets a Make variable with the given name to if the given bool flag value.
func (a *AndroidMkEntries) SetBool(name string, flag bool) {
 if _, ok := a.EntryMap[name]; !ok {
  a.entryOrder = append(a.entryOrder, name)
 }
 if flag {
  a.EntryMap[name] = []string{"true"}
 } else {
  a.EntryMap[name] = []string{"false"}
 }
}

// AddStrings appends the given strings to a Make variable with the given name.
func (a *AndroidMkEntries) AddStrings(name string, value ...string) {
 if len(value) == 0 {
  return
 }
 if _, ok := a.EntryMap[name]; !ok {
  a.entryOrder = append(a.entryOrder, name)
 }
 a.EntryMap[name] = append(a.EntryMap[name], value...)
}

// AddCompatibilityTestSuites adds the supplied test suites to the EntryMap, with special handling
// for partial MTS and MCTS test suites.
func (a *AndroidMkEntries) AddCompatibilityTestSuites(suites ...string) {
 // M(C)TS supports a full test suite and partial per-module MTS test suites, with naming mts-${MODULE}.
 // To reduce repetition, if we find a partial M(C)TS test suite without an full M(C)TS test suite,
 // we add the full test suite to our list.
 if PrefixInList(suites, "mts-") && !InList("mts", suites) {
  suites = append(suites, "mts")
 }
 if PrefixInList(suites, "mcts-") && !InList("mcts", suites) {
  suites = append(suites, "mcts")
 }
 a.AddStrings("LOCAL_COMPATIBILITY_SUITE", suites...)
}

// generateDistContributionsForMake generates make rules that will generate the
// dist according to the instructions in the supplied distContribution.
func generateDistContributionsForMake(distContributions *distContributions) []string {
 var ret []string
 for _, d := range distContributions.copiesForGoals {
  goals := strings.Join(d.goals, " ")
  ret = append(ret, fmt.Sprintf(".PHONY: %s", goals))
  // Create dist-for-goals calls for each of the copy instructions.
  for _, c := range d.copies {
   if distContributions.licenseMetadataFile != nil {
    ret = append(
     ret,
     fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))",
      c.from.String(), c.from.String(), distContributions.licenseMetadataFile.String()))
   }
   ret = append(
    ret,
    fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)", goals, c.from.String(), c.dest))
  }
 }

 return ret
}

// Compute the list of Make strings to declare phony goals and dist-for-goals
// calls from the module's dist and dists properties.
func (a *AndroidMkEntries) GetDistForGoals(mod Module) []string {
 distContributions := getDistContributions(a.entryContext, mod)
 if distContributions == nil {
  return nil
 }

 return generateDistContributionsForMake(distContributions)
}

// fillInEntries goes through the common variable processing and calls the extra data funcs to
// generate and fill in AndroidMkEntries's in-struct data, ready to be flushed to a file.
type fillInEntriesContext interface {
 ModuleDir(module ModuleOrProxy) string
 ModuleSubDir(module ModuleOrProxy) string
 Config() Config
 otherModuleProvider(module ModuleOrProxy, provider blueprint.AnyProviderKey) (any, bool)
 ModuleType(module ModuleOrProxy) string
 OtherModulePropertyErrorf(module ModuleOrProxy, property string, fmt string, args ...interface{})
 HasMutatorFinished(mutatorName string) bool
}

func GetModuleInfoJSONInfo(ctx OtherModuleProviderContext, module ModuleOrProxy) *ModuleInfoJSONInfo {
 if commInfo, ok := OtherModuleProvider(ctx, module, CommonModuleInfoProvider); ok {
  return commInfo.ModuleInfoJSON
 }
 return nil
}

func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod Module) {
 a.entryContext = ctx
 a.EntryMap = make(map[string][]string)
 base := mod.base()
 name := base.BaseModuleName()
 if bmn, ok := mod.(baseModuleName); ok {
  name = bmn.BaseModuleName()
 }
 if a.OverrideName != "" {
  name = a.OverrideName
 }

 if a.Include == "" {
  a.Include = "$(BUILD_PREBUILT)"
 }
 a.Required = append(a.Required, mod.RequiredModuleNames(ctx)...)
 a.Required = append(a.Required, mod.VintfFragmentModuleNames(ctx)...)
 a.Host_required = append(a.Host_required, mod.HostRequiredModuleNames()...)
 a.Target_required = append(a.Target_required, mod.TargetRequiredModuleNames()...)

 for _, distString := range a.GetDistForGoals(mod) {
  fmt.Fprintln(&a.header, distString)
 }

 fmt.Fprintf(&a.header, "\ninclude $(CLEAR_VARS)  # type: %s, name: %s, variant: %s\n", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod))

 // Add the TestSuites from the provider to LOCAL_SOONG_PROVIDER_TEST_SUITES.
 // LOCAL_SOONG_PROVIDER_TEST_SUITES will be compared against LOCAL_COMPATIBILITY_SUITES
 // in make and enforced they're the same, to ensure we've successfully translated all
 // LOCAL_COMPATIBILITY_SUITES usages to the provider.
 if testSuiteInfo, ok := OtherModuleProvider(ctx, mod, TestSuiteInfoProvider); ok {
  a.AddStrings("LOCAL_SOONG_PROVIDER_TEST_SUITES", testSuiteInfo.TestSuites...)
 }

 // Collect make variable assignment entries.
 a.SetString("LOCAL_PATH", ctx.ModuleDir(mod))
 a.SetString("LOCAL_MODULE", name+a.SubName)
 a.SetString("LOCAL_MODULE_CLASS", a.Class)
 a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String())
 a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
 a.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...)
 a.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...)
 a.AddStrings("LOCAL_SOONG_MODULE_TYPE", ctx.ModuleType(mod))

 commInfo := OtherModulePointerProviderOrDefault(ctx, mod, CommonModuleInfoProvider)

 // If the install rule was generated by Soong tell Make about it.
 info := GetInstallFilesCommon(commInfo)
 if len(info.KatiInstalls) > 0 {
  // Assume the primary install file is last since it probably needs to depend on any other
  // installed files.  If that is not the case we can add a method to specify the primary
  // installed file.
  a.SetPath("LOCAL_SOONG_INSTALLED_MODULE", info.KatiInstalls[len(info.KatiInstalls)-1].to)
  a.SetString("LOCAL_SOONG_INSTALL_PAIRS", info.KatiInstalls.BuiltInstalled())
  a.SetPaths("LOCAL_SOONG_INSTALL_SYMLINKS", info.KatiSymlinks.InstallPaths().Paths())
 } else {
  // Soong may not have generated the install rule also when `no_full_install: true`.
  // Mark this module as uninstallable in order to prevent Make from creating an
  // install rule there.
  a.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install))
 }
 moduleBuildTargetsInfo := commInfo.ModuleBuildTargets

 if info.UncheckedModule {
  a.SetBool("LOCAL_DONT_CHECK_MODULE", true)
 } else if moduleBuildTargetsInfo != nil && moduleBuildTargetsInfo.CheckbuildTarget != nil {
  a.SetPath("LOCAL_CHECKED_MODULE", moduleBuildTargetsInfo.CheckbuildTarget)
 } else {
  a.SetOptionalPath("LOCAL_CHECKED_MODULE", a.OutputFile)
 }

 if moduleBuildTargetsInfo != nil && moduleBuildTargetsInfo.ModulePhonyTarget != nil {
  a.SetPath("LOCAL_ADDITIONAL_CHECKED_MODULE", moduleBuildTargetsInfo.ModulePhonyTarget)
 }

 if len(info.TestData) > 0 {
  a.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(info.TestData)...)
 }

 platformAvailabilityInfo := OtherModuleProviderOrDefault(ctx, mod, PlatformAvailabilityInfoProvider)
 a.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", platformAvailabilityInfo.NotAvailableToPlatform)

 archStr := base.Arch().ArchType.String()
 host := false
 switch base.Os().Class {
 case Host:
  if base.Target().HostCross {
   // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
   if base.Arch().ArchType != Common {
    a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr)
   }
  } else {
   // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
   if base.Arch().ArchType != Common {
    a.SetString("LOCAL_MODULE_HOST_ARCH", archStr)
   }
  }
  host = true
 case Device:
  // Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
  if base.Arch().ArchType != Common {
   if base.Target().NativeBridge {
    hostArchStr := base.Target().NativeBridgeHostArchName
    if hostArchStr != "" {
     a.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr)
    }
   } else {
    a.SetString("LOCAL_MODULE_TARGET_ARCH", archStr)
   }
  }

  if !base.InVendorRamdisk() {
   a.AddPaths("LOCAL_FULL_INIT_RC", info.InitRcPaths)
  }
  if len(info.VintfFragmentsPaths) > 0 {
   a.AddPaths("LOCAL_FULL_VINTF_FRAGMENTS", info.VintfFragmentsPaths)
  }
  a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(base.commonProperties.Proprietary))
  if Bool(base.commonProperties.Vendor) || Bool(base.commonProperties.Soc_specific) {
   a.SetString("LOCAL_VENDOR_MODULE", "true")
  }
  a.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(base.commonProperties.Device_specific))
  a.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(base.commonProperties.Product_specific))
  a.SetBoolIfTrue("LOCAL_SYSTEM_EXT_MODULE", Bool(base.commonProperties.System_ext_specific))
  if base.commonProperties.Owner != nil {
   a.SetString("LOCAL_MODULE_OWNER", *base.commonProperties.Owner)
  }
 }

 if host {
  makeOs := base.Os().String()
  if base.Os() == Linux || base.Os() == LinuxBionic || base.Os() == LinuxMusl {
   makeOs = "linux"
  }
  a.SetString("LOCAL_MODULE_HOST_OS", makeOs)
  a.SetString("LOCAL_IS_HOST_MODULE", "true")
 }

 prefix := ""
 if base.ArchSpecific() {
  switch base.Os().Class {
  case Host:
   if base.Target().HostCross {
    prefix = "HOST_CROSS_"
   } else {
    prefix = "HOST_"
   }
  case Device:
   prefix = "TARGET_"

  }

  if base.Arch().ArchType != ctx.Config().Targets[base.Os()][0].Arch.ArchType {
   prefix = "2ND_" + prefix
  }
 }

 if licenseMetadata := commInfo.LicenseMetadata; licenseMetadata != nil {
  a.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath)
 }

 if commInfo.ModuleInfoJSON != nil {
  a.SetBool("LOCAL_SOONG_MODULE_INFO_JSON", true)
 }

 extraCtx := &androidMkExtraEntriesContext{
  ctx: ctx,
  mod: mod,
 }

 for _, extra := range a.ExtraEntries {
  extra(extraCtx, a)
 }

 // Write to footer.
 fmt.Fprintln(&a.footer, "include "+a.Include)
 blueprintDir := ctx.ModuleDir(mod)
 for _, footerFunc := range a.ExtraFooters {
  footerFunc(&a.footer, name, prefix, blueprintDir)
 }
}

func (a *AndroidMkEntries) disabled() bool {
 return !a.OutputFile.Valid()
}

// write  flushes the AndroidMkEntries's in-struct data populated by AndroidMkEntries into the
// given Writer object.
func (a *AndroidMkEntries) write(w io.Writer) {
 if a.disabled() {
  return
 }

 w.Write(a.header.Bytes())
 for _, name := range a.entryOrder {
  AndroidMkEmitAssignList(w, name, a.EntryMap[name])
 }
 w.Write(a.footer.Bytes())
}

func (a *AndroidMkEntries) FooterLinesForTests() []string {
 return strings.Split(string(a.footer.Bytes()), "\n")
}

// AndroidMkSingleton is a singleton to collect Android.mk data from all modules and dump them into
// the final Android-<product_name>.mk file output.
func AndroidMkSingleton() Singleton {
 return &androidMkSingleton{}
}

type androidMkSingleton struct{}

func allModulesSorted(ctx SingletonContext) []ModuleOrProxy {
 var allModules []ModuleOrProxy

 ctx.VisitAllModulesOrProxies(func(module ModuleOrProxy) {
  allModules = append(allModules, module)
 })

 // Sort the module list by the module names to eliminate random churns, which may erroneously
 // invoke additional build processes.
 sort.SliceStable(allModules, func(i, j int) bool {
  return ctx.ModuleName(allModules[i]) < ctx.ModuleName(allModules[j])
 })

 return allModules
}

func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) {
 // If running in soong-only mode, more limited version of this singleton is run as
 // soong only androidmk singleton
 if !ctx.Config().KatiEnabled() {
  return
 }

 transMk := PathForOutput(ctx, "Android"+String(ctx.Config().productVariables.Make_suffix)+".mk")
 if ctx.Failed() {
  return
 }

 moduleInfoJSON := PathForOutput(ctx, "module-info"+String(ctx.Config().productVariables.Make_suffix)+".json")

 err := translateAndroidMk(ctx, absolutePath(transMk.String()), moduleInfoJSON, allModulesSorted(ctx))
 if err != nil {
  ctx.Errorf(err.Error())
 }

 ctx.Build(pctx, BuildParams{
  Rule:   blueprint.Phony,
  Output: transMk,
 })
}

func translateAndroidMk(ctx SingletonContext, absMkFile string, moduleInfoJSONPath WritablePath, mods []ModuleOrProxy) error {
 buf := &bytes.Buffer{}

 var moduleInfoJSONs []*ModuleInfoJSON

 fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))")

 typeStats := make(map[string]int)
 for _, mod := range mods {
  err := translateAndroidMkModule(ctx, buf, &moduleInfoJSONs, mod)
  if err != nil {
   os.Remove(absMkFile)
   return err
  }

  if ctx.IsPrimaryModule(mod) {
   typeStats[ctx.ModuleType(mod)] += 1
  }
 }

 keys := []string{}
 fmt.Fprintln(buf, "\nSTATS.SOONG_MODULE_TYPE :=")
 for k := range typeStats {
  keys = append(keys, k)
 }
 sort.Strings(keys)
 for _, mod_type := range keys {
  fmt.Fprintln(buf, "STATS.SOONG_MODULE_TYPE +=", mod_type)
  fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, typeStats[mod_type])
 }

 err := pathtools.WriteFileIfChanged(absMkFile, buf.Bytes(), 0666)
 if err != nil {
  return err
 }

 return writeModuleInfoJSON(ctx, moduleInfoJSONs, moduleInfoJSONPath)
}

func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON, mod ModuleOrProxy) error {
 defer func() {
  if r := recover(); r != nil {
   panic(fmt.Errorf("%s in translateAndroidMkModule for module %s variant %s",
    r, ctx.ModuleName(mod), ctx.ModuleSubDir(mod)))
  }
 }()

 // Additional cases here require review for correct license propagation to make.
 var err error

 if info, ok := OtherModuleProvider(ctx, mod, AndroidMkInfoProvider); ok {
  err = translateAndroidMkEntriesInfoModule(ctx, w, moduleInfoJSONs, mod, info)
 } else {
  switch x := mod.(type) {
  case AndroidMkDataProvider:
   err = translateAndroidModule(ctx, w, moduleInfoJSONs, mod.(Module), x)
  case AndroidMkEntriesProvider:
   err = translateAndroidMkEntriesModule(ctx, w, moduleInfoJSONs, mod.(Module), x)
  default:
   // Not exported to make so no make variables to set.
  }
 }

 if err != nil {
  return err
 }

 return err
}

func (data *AndroidMkData) fillInData(ctx fillInEntriesContext, mod Module) {
 // Get the preamble content through AndroidMkEntries logic.
 data.Entries = AndroidMkEntries{
  Class:           data.Class,
  SubName:         data.SubName,
  OutputFile:      data.OutputFile,
  Include:         data.Include,
  Required:        data.Required,
  Host_required:   data.Host_required,
  Target_required: data.Target_required,
 }
 data.Entries.fillInEntries(ctx, mod)

 // copy entries back to data since it is used in Custom
 data.Required = data.Entries.Required
 data.Host_required = data.Entries.Host_required
 data.Target_required = data.Entries.Target_required
}

// A support func for the deprecated AndroidMkDataProvider interface. Use AndroidMkEntryProvider
// instead.
func translateAndroidModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON,
 mod Module, provider AndroidMkDataProvider) error {

 amod := mod.base()
 if shouldSkipAndroidMkProcessing(ctx, amod) {
  return nil
 }

 data := provider.AndroidMk()

 if data.Include == "" {
  data.Include = "$(BUILD_PREBUILT)"
 }

 data.fillInData(ctx, mod)
 aconfigUpdateAndroidMkData(ctx, mod, &data)

 prefix := ""
 if amod.ArchSpecific() {
  switch amod.Os().Class {
  case Host:
   if amod.Target().HostCross {
    prefix = "HOST_CROSS_"
   } else {
    prefix = "HOST_"
   }
  case Device:
   prefix = "TARGET_"

  }

  if amod.Arch().ArchType != ctx.Config().Targets[amod.Os()][0].Arch.ArchType {
   prefix = "2ND_" + prefix
  }
 }

 name := provider.BaseModuleName()
 blueprintDir := filepath.Dir(ctx.BlueprintFile(mod))

 if data.Custom != nil {
  // List of module types allowed to use .Custom(...)
  // Additions to the list require careful review for proper license handling.
  switch reflect.TypeOf(mod).String() { // ctx.ModuleType(mod) doesn't work: aidl_interface creates phony without type
  case "*aidl.aidlApi": // writes non-custom before adding .phony
  case "*aidl.aidlMapping": // writes non-custom before adding .phony
  case "*android.customModule": // appears in tests only
  case "*android_sdk.sdkRepoHost": // doesn't go through base_rules
  case "*apex.apexBundle": // license properties written
  case "*bpf.bpf": // license properties written (both for module and objs)
  case "*libbpf_prog.libbpfProg": // license properties written (both for module and objs)
  case "*genrule.Module": // writes non-custom before adding .phony
  case "*java.SystemModules": // doesn't go through base_rules
  case "*java.systemModulesImport": // doesn't go through base_rules
  case "*phony.phony": // license properties written
  case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY`
  case "*selinux.selinuxContextsModule": // license properties written
  case "*sysprop.syspropLibrary": // license properties written
  case "*vintf.vintfCompatibilityMatrixRule": // use case like phony
  default:
   if !ctx.Config().IsEnvFalse("ANDROID_REQUIRE_LICENSES") {
    return fmt.Errorf("custom make rules not allowed for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), ctx.ModuleName(mod))
   }
  }
  data.Custom(w, name, prefix, blueprintDir, data)
 } else {
  WriteAndroidMkData(w, data)
 }

 if !data.Entries.disabled() {
  if moduleInfoJSON := GetModuleInfoJSONInfo(ctx, mod); moduleInfoJSON != nil {
   *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON.Data...)
  }
 }

 return nil
}

// A support func for the deprecated AndroidMkDataProvider interface. Use AndroidMkEntryProvider
// instead.
func WriteAndroidMkData(w io.Writer, data AndroidMkData) {
 if data.Entries.disabled() {
  return
 }

 // write preamble via Entries
 data.Entries.footer = bytes.Buffer{}
 data.Entries.write(w)

 for _, extra := range data.Extra {
  extra(w, data.OutputFile.Path())
 }

 fmt.Fprintln(w, "include "+data.Include)
}

func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON,
 mod Module, provider AndroidMkEntriesProvider) error {
 if shouldSkipAndroidMkProcessing(ctx, mod.base()) {
  return nil
 }

 entriesList := provider.AndroidMkEntries()
 aconfigUpdateAndroidMkEntries(ctx, mod, &entriesList)

 moduleInfoJSON := GetModuleInfoJSONInfo(ctx, mod)

 // Any new or special cases here need review to verify correct propagation of license information.
 for _, entries := range entriesList {
  entries.fillInEntries(ctx, mod)
  entries.write(w)

  if moduleInfoJSON != nil && !entries.disabled() {
   // append only the name matching moduleInfoJSON entry
   for _, m := range moduleInfoJSON.Data {
    if m.RegisterNameOverride == entries.OverrideName && m.SubName == entries.SubName {
     *moduleInfoJSONs = append(*moduleInfoJSONs, m)
    }
   }
  }
 }

 return nil
}

func ShouldSkipAndroidMkProcessing(ctx ConfigurableEvaluatorContext, module Module) bool {
 return shouldSkipAndroidMkProcessing(ctx, module.base())
}

func shouldSkipAndroidMkProcessing(ctx ConfigurableEvaluatorContext, module *ModuleBase) bool {
 if !module.commonProperties.NamespaceExportedToMake {
  // TODO(jeffrygaston) do we want to validate that there are no modules being
  // exported to Kati that depend on this module?
  return true
 }

 return !shouldGeneratePhonyTargets(ctx, module)
}

func shouldGeneratePhonyTargets(ctx ConfigurableEvaluatorContext, module *ModuleBase) bool {
 // On Mac, only expose host darwin modules to Make, as that's all we claim to support.
 // In reality, some of them depend on device-built (Java) modules, so we can't disable all
 // device modules in Soong, but we can hide them from Make (and thus the build user interface)
 if runtime.GOOS == "darwin" && module.Os() != Darwin {
  return false
 }

 // Only expose the primary Darwin target, as Make does not understand Darwin+Arm64
 if module.Os() == Darwin && module.Target().HostCross {
  return false
 }

 return module.Enabled(ctx) &&
  !module.commonProperties.HideFromMake &&
  // Make does not understand LinuxBionic
  module.Os() != LinuxBionic &&
  // Make does not understand LinuxMusl, except when we are building with USE_HOST_MUSL=true
  // and all host binaries are LinuxMusl
  !(module.Os() == LinuxMusl && module.Target().HostCross)
}

// A utility func to format LOCAL_TEST_DATA outputs. See the comments on DataPath to understand how
// to use this func.
func androidMkDataPaths(data []DataPath) []string {
 var testFiles []string
 for _, d := range data {
  rel := d.SrcPath.Rel()
  if d.WithoutRel {
   rel = d.SrcPath.Base()
  }
  path := d.SrcPath.String()
  // LOCAL_TEST_DATA requires the rel portion of the path to be removed from the path.
  if !strings.HasSuffix(path, rel) {
   panic(fmt.Errorf("path %q does not end with %q", path, rel))
  }
  path = strings.TrimSuffix(path, rel)
  testFileString := path + ":" + rel
  if len(d.RelativeInstallPath) > 0 {
   testFileString += ":" + d.RelativeInstallPath
  }
  testFiles = append(testFiles, testFileString)
 }
 return testFiles
}

// AndroidMkEmitAssignList emits the line
//
// VAR := ITEM ...
//
// Items are the elements to the given set of lists
// If all the passed lists are empty, no line will be emitted
func AndroidMkEmitAssignList(w io.Writer, varName string, lists ...[]string) {
 doPrint := false
 for _, l := range lists {
  if doPrint = len(l) > 0; doPrint {
   break
  }
 }
 if !doPrint {
  return
 }
 fmt.Fprint(w, varName, " :=")
 for _, l := range lists {
  for _, item := range l {
   fmt.Fprint(w, " ", item)
  }
 }
 fmt.Fprintln(w)
}

// @auto-generate: gob
type AndroidMkProviderInfo struct {
 PrimaryInfo AndroidMkInfo
 ExtraInfo   []AndroidMkInfo
}

// @auto-generate: gob
type AndroidMkInfo struct {
 // Android.mk class string, e.g. EXECUTABLES, JAVA_LIBRARIES, ETC
 Class string
 // Optional suffix to append to the module name. Useful when a module wants to return multiple
 // AndroidMkEntries objects. For example, when a java_library returns an additional entry for
 // its hostdex sub-module, this SubName field is set to "-hostdex" so that it can have a
 // different name than the parent's.
 SubName string
 // If set, this value overrides the base module name. SubName is still appended.
 OverrideName string
 // The output file for Kati to process and/or install. If absent, the module is skipped.
 OutputFile OptionalPath
 // The postprocessing mk file to include, e.g. $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk
 // If not set, $(BUILD_SYSTEM)/prebuilt.mk is used.
 Include string
 // Required modules that need to be built and included in the final build output when building
 // this module.
 Required []string
 // Required host modules that need to be built and included in the final build output when
 // building this module.
 Host_required []string
 // Required device modules that need to be built and included in the final build output when
 // building this module.
 Target_required []string

 HeaderStrings []string
 FooterStrings []string

 // A map that holds the up-to-date Make variable values. Can be accessed from tests.
 EntryMap map[string][]string
 // A list of EntryMap keys in insertion order. This serves a few purposes:
 // 1. Prevents churns. Golang map doesn't provide consistent iteration order, so without this,
 // the outputted Android-*.mk file may change even though there have been no content changes.
 // 2. Allows modules to refer to other variables, like LOCAL_BAR_VAR := $(LOCAL_FOO_VAR),
 // without worrying about the variables being mixed up in the actual mk file.
 // 3. Makes troubleshooting and spotting errors easier.
 EntryOrder []string
}

type AndroidMkProviderInfoProducer interface {
 PrepareAndroidMKProviderInfo(config Config) *AndroidMkProviderInfo
}

// TODO: rename it to AndroidMkEntriesProvider after AndroidMkEntriesProvider interface is gone.
var AndroidMkInfoProvider = blueprint.NewProvider[*AndroidMkProviderInfo]()

// TODO(b/397766191): Change the signature to take ModuleProxy
// Please only access the module's internal data through providers.
func translateAndroidMkEntriesInfoModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON,
 mod ModuleOrProxy, providerInfo *AndroidMkProviderInfo) error {
 commonInfo := OtherModulePointerProviderOrDefault(ctx, mod, CommonModuleInfoProvider)
 if commonInfo.SkipAndroidMkProcessing {
  return nil
 }

 // Deep copy the provider info since we need to modify the info later
 info := deepCopyAndroidMkProviderInfo(providerInfo)

 aconfigUpdateAndroidMkInfos(ctx, mod, &info)

 // Any new or special cases here need review to verify correct propagation of license information.
 info.PrimaryInfo.fillInEntries(ctx, mod, commonInfo)
 info.PrimaryInfo.write(w)
 if len(info.ExtraInfo) > 0 {
  for _, ei := range info.ExtraInfo {
   ei.fillInEntries(ctx, mod, commonInfo)
   ei.write(w)
  }
 }

 if !info.PrimaryInfo.disabled() {
  if moduleInfoJSON := commonInfo.ModuleInfoJSON; moduleInfoJSON != nil {
   *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON.Data...)
  }
 }

 return nil
}

// Utility funcs to manipulate Android.mk variable entries.

func (a *AndroidMkInfo) createMapIfNecessary() {
 if a.EntryMap == nil {
  a.EntryMap = make(map[string][]string)
 }
}

// SetString sets a Make variable with the given name to the given value.
func (a *AndroidMkInfo) SetString(name, value string) {
 a.createMapIfNecessary()
 if _, ok := a.EntryMap[name]; !ok {
  a.EntryOrder = append(a.EntryOrder, name)
 }
 a.EntryMap[name] = []string{value}
}

// SetPath sets a Make variable with the given name to the given path string.
func (a *AndroidMkInfo) SetPath(name string, path Path) {
 a.createMapIfNecessary()
 if _, ok := a.EntryMap[name]; !ok {
  a.EntryOrder = append(a.EntryOrder, name)
 }
 a.EntryMap[name] = []string{path.String()}
}

// SetOptionalPath sets a Make variable with the given name to the given path string if it is valid.
// It is a no-op if the given path is invalid.
func (a *AndroidMkInfo) SetOptionalPath(name string, path OptionalPath) {
 if path.Valid() {
  a.SetPath(name, path.Path())
 }
}

// AddPath appends the given path string to a Make variable with the given name.
func (a *AndroidMkInfo) AddPath(name string, path Path) {
 if _, ok := a.EntryMap[name]; !ok {
  a.EntryOrder = append(a.EntryOrder, name)
 }
 a.EntryMap[name] = append(a.EntryMap[name], path.String())
}

// AddOptionalPath appends the given path string to a Make variable with the given name if it is
// valid. It is a no-op if the given path is invalid.
func (a *AndroidMkInfo) AddOptionalPath(name string, path OptionalPath) {
 if path.Valid() {
  a.AddPath(name, path.Path())
 }
}

// SetPaths sets a Make variable with the given name to a slice of the given path strings.
func (a *AndroidMkInfo) SetPaths(name string, paths Paths) {
 a.createMapIfNecessary()
 if _, ok := a.EntryMap[name]; !ok {
  a.EntryOrder = append(a.EntryOrder, name)
 }
 a.EntryMap[name] = paths.Strings()
}

// SetOptionalPaths sets a Make variable with the given name to a slice of the given path strings
// only if there are a non-zero amount of paths.
func (a *AndroidMkInfo) SetOptionalPaths(name string, paths Paths) {
 if len(paths) > 0 {
  a.SetPaths(name, paths)
 }
}

// AddPaths appends the given path strings to a Make variable with the given name.
func (a *AndroidMkInfo) AddPaths(name string, paths Paths) {
 a.createMapIfNecessary()
 if _, ok := a.EntryMap[name]; !ok {
  a.EntryOrder = append(a.EntryOrder, name)
 }
 a.EntryMap[name] = append(a.EntryMap[name], paths.Strings()...)
}

// SetBoolIfTrue sets a Make variable with the given name to true if the given flag is true.
// It is a no-op if the given flag is false.
func (a *AndroidMkInfo) SetBoolIfTrue(name string, flag bool) {
 if flag {
  a.createMapIfNecessary()
  if _, ok := a.EntryMap[name]; !ok {
   a.EntryOrder = append(a.EntryOrder, name)
  }
  a.EntryMap[name] = []string{"true"}
 }
}

// SetBool sets a Make variable with the given name to if the given bool flag value.
func (a *AndroidMkInfo) SetBool(name string, flag bool) {
 a.createMapIfNecessary()
 if _, ok := a.EntryMap[name]; !ok {
  a.EntryOrder = append(a.EntryOrder, name)
 }
 if flag {
  a.EntryMap[name] = []string{"true"}
 } else {
  a.EntryMap[name] = []string{"false"}
 }
}

// AddStrings appends the given strings to a Make variable with the given name.
func (a *AndroidMkInfo) AddStrings(name string, value ...string) {
 if len(value) == 0 {
  return
 }
 a.createMapIfNecessary()
 if _, ok := a.EntryMap[name]; !ok {
  a.EntryOrder = append(a.EntryOrder, name)
 }
 a.EntryMap[name] = append(a.EntryMap[name], value...)
}

// AddCompatibilityTestSuites adds the supplied test suites to the EntryMap, with special handling
// for partial MTS and MCTS test suites.
func (a *AndroidMkInfo) AddCompatibilityTestSuites(suites ...string) {
 // M(C)TS supports a full test suite and partial per-module MTS test suites, with naming mts-${MODULE}.
 // To reduce repetition, if we find a partial M(C)TS test suite without an full M(C)TS test suite,
 // we add the full test suite to our list.
 if PrefixInList(suites, "mts-") && !InList("mts", suites) {
  suites = append(suites, "mts")
 }
 if PrefixInList(suites, "mcts-") && !InList("mcts", suites) {
  suites = append(suites, "mcts")
 }
 a.AddStrings("LOCAL_COMPATIBILITY_SUITE", suites...)
}

// TODO(b/397766191): Change the signature to take ModuleProxy
// Please only access the module's internal data through providers.
func (a *AndroidMkInfo) fillInEntries(ctx fillInEntriesContext, mod ModuleOrProxy, commonInfo *CommonModuleInfo) {
 helperInfo := AndroidMkInfo{}

 name := commonInfo.BaseModuleName
 if a.OverrideName != "" {
  name = a.OverrideName
 }

 if a.Include == "" {
  a.Include = "$(BUILD_PREBUILT)"
 }
 a.Required = append(a.Required, commonInfo.RequiredModuleNames...)
 a.Required = append(a.Required, commonInfo.VintfFragmentModuleNames...)
 a.Host_required = append(a.Host_required, commonInfo.HostRequiredModuleNames...)
 a.Target_required = append(a.Target_required, commonInfo.TargetRequiredModuleNames...)

 a.HeaderStrings = append(a.HeaderStrings, a.GetDistForGoals(ctx, mod)...)
 a.HeaderStrings = append(a.HeaderStrings, fmt.Sprintf("\ninclude $(CLEAR_VARS)  # type: %s, name: %s, variant: %s", ctx.ModuleType(mod), commonInfo.BaseModuleName, ctx.ModuleSubDir(mod)))

 // Add the TestSuites from the provider to LOCAL_SOONG_PROVIDER_TEST_SUITES.
 // LOCAL_SOONG_PROVIDER_TEST_SUITES will be compared against LOCAL_COMPATIBILITY_SUITES
 // in make and enforced they're the same, to ensure we've successfully translated all
 // LOCAL_COMPATIBILITY_SUITES usages to the provider.
 if testSuiteInfo, ok := OtherModuleProvider(ctx, mod, TestSuiteInfoProvider); ok {
  helperInfo.AddStrings("LOCAL_SOONG_PROVIDER_TEST_SUITES", testSuiteInfo.TestSuites...)
 }

 // Collect make variable assignment entries.
 helperInfo.SetString("LOCAL_PATH", ctx.ModuleDir(mod))
 helperInfo.SetString("LOCAL_MODULE", name+a.SubName)
 helperInfo.SetString("LOCAL_MODULE_CLASS", a.Class)
 helperInfo.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String())
 helperInfo.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
 helperInfo.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...)
 helperInfo.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...)
 helperInfo.AddStrings("LOCAL_SOONG_MODULE_TYPE", ctx.ModuleType(mod))

 // If the install rule was generated by Soong tell Make about it.
 info := GetInstallFilesCommon(commonInfo)
 if len(info.KatiInstalls) > 0 {
  // Assume the primary install file is last since it probably needs to depend on any other
  // installed files.  Don't override the value if it was already provided by PrepareAndroidMKProviderInfo.
  if _, exists := a.EntryMap["LOCAL_SOONG_INSTALLED_MODULE"]; !exists {
   helperInfo.SetPath("LOCAL_SOONG_INSTALLED_MODULE", info.KatiInstalls[len(info.KatiInstalls)-1].to)
  }
  helperInfo.SetString("LOCAL_SOONG_INSTALL_PAIRS", info.KatiInstalls.BuiltInstalled())
  helperInfo.SetPaths("LOCAL_SOONG_INSTALL_SYMLINKS", info.KatiSymlinks.InstallPaths().Paths())
 } else {
  // Soong may not have generated the install rule also when `no_full_install: true`.
  // Mark this module as uninstallable in order to prevent Make from creating an
  // install rule there.
  helperInfo.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", commonInfo.NoFullInstall)
 }

 moduleBuildTargetsInfo := commonInfo.ModuleBuildTargets

 if info.UncheckedModule {
  helperInfo.SetBool("LOCAL_DONT_CHECK_MODULE", true)
 } else if moduleBuildTargetsInfo != nil && moduleBuildTargetsInfo.CheckbuildTarget != nil {
  helperInfo.SetPath("LOCAL_CHECKED_MODULE", moduleBuildTargetsInfo.CheckbuildTarget)
 } else {
  helperInfo.SetOptionalPath("LOCAL_CHECKED_MODULE", a.OutputFile)
 }

 if moduleBuildTargetsInfo != nil && moduleBuildTargetsInfo.ModulePhonyTarget != nil {
  helperInfo.SetPath("LOCAL_ADDITIONAL_CHECKED_MODULE", moduleBuildTargetsInfo.ModulePhonyTarget)
 }

 if len(info.TestData) > 0 {
  helperInfo.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(info.TestData)...)
 }

 if platformAvailabilityInfo, ok := OtherModuleProvider(ctx, mod, PlatformAvailabilityInfoProvider); ok {
  helperInfo.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", platformAvailabilityInfo.NotAvailableToPlatform)
 }

 archStr := commonInfo.Target.Arch.ArchType.String()
 host := false
 switch commonInfo.Target.Os.Class {
 case Host:
  if commonInfo.Target.HostCross {
   // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
   if commonInfo.Target.Arch.ArchType != Common {
    helperInfo.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr)
   }
  } else {
   // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
   if commonInfo.Target.Arch.ArchType != Common {
    helperInfo.SetString("LOCAL_MODULE_HOST_ARCH", archStr)
   }
  }
  host = true
 case Device:
  // Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
  if commonInfo.Target.Arch.ArchType != Common {
   if commonInfo.Target.NativeBridge {
    hostArchStr := commonInfo.Target.NativeBridgeHostArchName
    if hostArchStr != "" {
     helperInfo.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr)
    }
   } else {
    helperInfo.SetString("LOCAL_MODULE_TARGET_ARCH", archStr)
   }
  }

  if !commonInfo.InVendorRamdisk {
   helperInfo.AddPaths("LOCAL_FULL_INIT_RC", info.InitRcPaths)
  }
  if len(info.VintfFragmentsPaths) > 0 {
   helperInfo.AddPaths("LOCAL_FULL_VINTF_FRAGMENTS", info.VintfFragmentsPaths)
  }
  helperInfo.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", commonInfo.Proprietary)
  if commonInfo.Vendor || commonInfo.SocSpecific {
   helperInfo.SetString("LOCAL_VENDOR_MODULE", "true")
  }
  helperInfo.SetBoolIfTrue("LOCAL_ODM_MODULE", commonInfo.DeviceSpecific)
  helperInfo.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", commonInfo.ProductSpecific)
  helperInfo.SetBoolIfTrue("LOCAL_SYSTEM_EXT_MODULE", commonInfo.SystemExtSpecific)
  if commonInfo.Owner != "" {
   helperInfo.SetString("LOCAL_MODULE_OWNER", commonInfo.Owner)
  }
 }

 if host {
  os := commonInfo.Target.Os
  makeOs := os.String()
  if os == Linux || os == LinuxBionic || os == LinuxMusl {
   makeOs = "linux"
  }
  helperInfo.SetString("LOCAL_MODULE_HOST_OS", makeOs)
  helperInfo.SetString("LOCAL_IS_HOST_MODULE", "true")
 }

 if licenseMetadata := commonInfo.LicenseMetadata; licenseMetadata != nil {
  helperInfo.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath)
 }

 if moduleInfoJSON := commonInfo.ModuleInfoJSON; moduleInfoJSON != nil {
  helperInfo.SetBool("LOCAL_SOONG_MODULE_INFO_JSON", true)
 }

 a.mergeEntries(&helperInfo)

 // Write to footer.
 a.FooterStrings = append([]string{"include " + a.Include}, a.FooterStrings...)
}

// This method merges the entries to helperInfo, then replaces a's EntryMap and
// EntryOrder with helperInfo's
func (a *AndroidMkInfo) mergeEntries(helperInfo *AndroidMkInfo) {
 for _, extraEntry := range a.EntryOrder {
  if v, ok := helperInfo.EntryMap[extraEntry]; ok {
   helperInfo.EntryMap[extraEntry] = append(v, a.EntryMap[extraEntry]...)
  } else {
   helperInfo.EntryMap[extraEntry] = a.EntryMap[extraEntry]
   helperInfo.EntryOrder = append(helperInfo.EntryOrder, extraEntry)
  }
 }
 a.EntryOrder = helperInfo.EntryOrder
 a.EntryMap = helperInfo.EntryMap
}

func (a *AndroidMkInfo) disabled() bool {
 return !a.OutputFile.Valid()
}

// write  flushes the AndroidMkEntries's in-struct data populated by AndroidMkEntries into the
// given Writer object.
func (a *AndroidMkInfo) write(w io.Writer) {
 if a.disabled() {
  return
 }

 combinedHeaderString := strings.Join(a.HeaderStrings, "\n") + "\n"
 combinedFooterString := strings.Join(a.FooterStrings, "\n") + "\n"
 w.Write([]byte(combinedHeaderString))
 for _, name := range a.EntryOrder {
  AndroidMkEmitAssignList(w, name, a.EntryMap[name])
 }
 w.Write([]byte(combinedFooterString))
}

// Compute the list of Make strings to declare phony goals and dist-for-goals
// calls from the module's dist and dists properties.
// TODO(b/397766191): Change the signature to take ModuleProxy
// Please only access the module's internal data through providers.
func (a *AndroidMkInfo) GetDistForGoals(ctx fillInEntriesContext, mod ModuleOrProxy) []string {
 distContributions := getDistContributions(ctx, mod)
 if distContributions == nil {
  return nil
 }

 return generateDistContributionsForMake(distContributions)
}

func deepCopyAndroidMkProviderInfo(providerInfo *AndroidMkProviderInfo) AndroidMkProviderInfo {
 info := AndroidMkProviderInfo{
  PrimaryInfo: deepCopyAndroidMkInfo(&providerInfo.PrimaryInfo),
 }
 if len(providerInfo.ExtraInfo) > 0 {
  for _, i := range providerInfo.ExtraInfo {
   info.ExtraInfo = append(info.ExtraInfo, deepCopyAndroidMkInfo(&i))
  }
 }
 return info
}

func deepCopyAndroidMkInfo(mkinfo *AndroidMkInfo) AndroidMkInfo {
 info := AndroidMkInfo{
  Class:        mkinfo.Class,
  SubName:      mkinfo.SubName,
  OverrideName: mkinfo.OverrideName,
  // There is no modification on OutputFile, so no need to
  // make their deep copy.
  OutputFile:      mkinfo.OutputFile,
  Include:         mkinfo.Include,
  Required:        deepCopyStringSlice(mkinfo.Required),
  Host_required:   deepCopyStringSlice(mkinfo.Host_required),
  Target_required: deepCopyStringSlice(mkinfo.Target_required),
  HeaderStrings:   deepCopyStringSlice(mkinfo.HeaderStrings),
  FooterStrings:   deepCopyStringSlice(mkinfo.FooterStrings),
  EntryOrder:      deepCopyStringSlice(mkinfo.EntryOrder),
 }
 info.EntryMap = make(map[string][]string)
 for k, v := range mkinfo.EntryMap {
  info.EntryMap[k] = deepCopyStringSlice(v)
 }

 return info
}

func deepCopyStringSlice(original []string) []string {
 result := make([]string, len(original))
 copy(result, original)
 return result
}

[Dauer der Verarbeitung: 0.28 Sekunden, vorverarbeitet 2026-06-28]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik