Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/soong/android/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 18 kB image not shown  

Quelle  soong_config_modules.go   Sprache: unbekannt

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

// Copyright 2019 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

// This file provides module types that implement wrapper module types that add conditionals on
// Soong config variables.

import (
 "fmt"
 "path/filepath"
 "reflect"
 "strings"
 "sync"
 "text/scanner"

 "github.com/google/blueprint"
 "github.com/google/blueprint/parser"
 "github.com/google/blueprint/proptools"

 "android/soong/android/soongconfig"
)

func init() {
 RegisterSoongConfigModuleBuildComponents(InitRegistrationContext)
}

func RegisterSoongConfigModuleBuildComponents(ctx RegistrationContext) {
 ctx.RegisterModuleType("soong_config_module_type_import", SoongConfigModuleTypeImportFactory)
 ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
 ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
 ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
 ctx.RegisterModuleType("soong_config_value_variable", SoongConfigValueVariableDummyFactory)
}

var PrepareForTestWithSoongConfigModuleBuildComponents = FixtureRegisterWithContext(RegisterSoongConfigModuleBuildComponents)

type soongConfigModuleTypeImport struct {
 ModuleBase
 properties soongConfigModuleTypeImportProperties
}

type soongConfigModuleTypeImportProperties struct {
 From         string
 Module_types []string
}

// soong_config_module_type_import imports module types with conditionals on Soong config
// variables from another Android.bp file.  The imported module type will exist for all
// modules after the import in the Android.bp file.
//
// Each soong_config_variable supports an additional value `conditions_default`. The properties
// specified in `conditions_default` will only be used under the following conditions:
//   bool variable: the variable is unspecified or not set to a true value
//   value variable: the variable is unspecified
//   list variable: the variable is unspecified
//   string variable: the variable is unspecified or the variable is set to a string unused in the
//                    given module. For example, string variable `test` takes values: "a" and "b",
//                    if the module contains a property `a` and `conditions_default`, when test=b,
//                    the properties under `conditions_default` will be used. To specify that no
//                    properties should be amended for `b`, you can set `b: {},`.
//
// For example, an Android.bp file could have:
//
//     soong_config_module_type_import {
//         from: "device/acme/Android.bp",
//         module_types: ["acme_cc_defaults"],
//     }
//
//     acme_cc_defaults {
//         name: "acme_defaults",
//         cflags: ["-DGENERIC"],
//         soong_config_variables: {
//             board: {
//                 soc_a: {
//                     cflags: ["-DSOC_A"],
//                 },
//                 soc_b: {
//                     cflags: ["-DSOC_B"],
//                 },
//                 conditions_default: {
//                     cflags: ["-DSOC_DEFAULT"],
//                 },
//             },
//             feature: {
//                 cflags: ["-DFEATURE"],
//                 conditions_default: {
//                     cflags: ["-DFEATURE_DEFAULT"],
//                 },
//             },
//             width: {
//                 cflags: ["-DWIDTH=%s"],
//                 conditions_default: {
//                     cflags: ["-DWIDTH=DEFAULT"],
//                 },
//             },
//             impl: {
//                 srcs: ["impl/%s"],
//                 conditions_default: {
//                     srcs: ["impl/default.cpp"],
//                 },
//             },
//         },
//     }
//
//     cc_library {
//         name: "libacme_foo",
//         defaults: ["acme_defaults"],
//         srcs: ["*.cpp"],
//     }
//
// And device/acme/Android.bp could have:
//
//     soong_config_module_type {
//         name: "acme_cc_defaults",
//         module_type: "cc_defaults",
//         config_namespace: "acme",
//         variables: ["board"],
//         bool_variables: ["feature"],
//         value_variables: ["width"],
//         list_variables: ["impl"],
//         properties: ["cflags", "srcs"],
//     }
//
//     soong_config_string_variable {
//         name: "board",
//         values: ["soc_a", "soc_b", "soc_c"],
//     }
//
// If an acme BoardConfig.mk file contained:
//     $(call add_soong_config_namespace, acme)
//     $(call add_soong_config_var_value, acme, board, soc_a)
//     $(call add_soong_config_var_value, acme, feature, true)
//     $(call add_soong_config_var_value, acme, width, 200)
//     $(call add_soong_config_var_value, acme, impl, foo.cpp bar.cpp)
//
// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200" and srcs
// ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"].
//
// Alternatively, if acme BoardConfig.mk file contained:
//
//     SOONG_CONFIG_NAMESPACES += acme
//     SOONG_CONFIG_acme += \
//         board \
//         feature \
//
//     SOONG_CONFIG_acme_feature := false
//
// Then libacme_foo would build with cflags:
//   "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT"
// and with srcs:
//   ["*.cpp", "impl/default.cpp"].
//
// Similarly, if acme BoardConfig.mk file contained:
//
//     SOONG_CONFIG_NAMESPACES += acme
//     SOONG_CONFIG_acme += \
//         board \
//         feature \
//
//     SOONG_CONFIG_acme_board := soc_c
//     SOONG_CONFIG_acme_impl := foo.cpp bar.cpp
//
// Then libacme_foo would build with cflags:
//   "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT"
// and with srcs:
//   ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"].
//

func SoongConfigModuleTypeImportFactory() Module {
 module := &soongConfigModuleTypeImport{}

 module.AddProperties(&module.properties)
 AddLoadHook(module, func(ctx LoadHookContext) {
  importModuleTypes(ctx, module.properties.From, module.properties.Module_types...)
 })

 initAndroidModuleBase(module)
 return module
}

func (m *soongConfigModuleTypeImport) Name() string {
 // The generated name is non-deterministic, but it does not
 // matter because this module does not emit any rules.
 return soongconfig.CanonicalizeToProperty(m.properties.From) +
  "soong_config_module_type_import_" + fmt.Sprintf("%p", m)
}

func (*soongConfigModuleTypeImport) Namespaceless()                            {}
func (*soongConfigModuleTypeImport) GenerateAndroidBuildActions(ModuleContext) {}

// Create dummy modules for soong_config_module_type and soong_config_*_variable

type soongConfigModuleTypeModule struct {
 ModuleBase
 properties soongconfig.ModuleTypeProperties
}

// soong_config_module_type defines module types with conditionals on Soong config
// variables.  The new module type will exist for all modules after the definition
// in an Android.bp file, and can be imported into other Android.bp files using
// soong_config_module_type_import.
//
// Each soong_config_variable supports an additional value `conditions_default`. The properties
// specified in `conditions_default` will only be used under the following conditions:
//
// bool variable: the variable is unspecified or not set to a true value
// value variable: the variable is unspecified
// list variable: the variable is unspecified
// string variable: the variable is unspecified or the variable is set to a string unused in the
//                  given module. For example, string variable `test` takes values: "a" and "b",
//                  if the module contains a property `a` and `conditions_default`, when test=b,
//                  the properties under `conditions_default` will be used. To specify that no
//                  properties should be amended for `b`, you can set `b: {},`.
//
// For example, an Android.bp file could have:
//
// soong_config_module_type {
//     name: "acme_cc_defaults",
//     module_type: "cc_defaults",
//     config_namespace: "acme",
//     variables: ["board"],
//     bool_variables: ["feature"],
//     value_variables: ["width"],
//     list_variables: ["impl"],
//     properties: ["cflags", "srcs"],
// }
//
// soong_config_string_variable {
//     name: "board",
//     values: ["soc_a", "soc_b"],
// }
//
// acme_cc_defaults {
//     name: "acme_defaults",
//     cflags: ["-DGENERIC"],
//     soong_config_variables: {
//         board: {
//             soc_a: {
//                 cflags: ["-DSOC_A"],
//             },
//             soc_b: {
//                 cflags: ["-DSOC_B"],
//             },
//             conditions_default: {
//                 cflags: ["-DSOC_DEFAULT"],
//             },
//         },
//         feature: {
//             cflags: ["-DFEATURE"],
//             conditions_default: {
//                 cflags: ["-DFEATURE_DEFAULT"],
//             },
//         },
//         width: {
//             cflags: ["-DWIDTH=%s"],
//             conditions_default: {
//                 cflags: ["-DWIDTH=DEFAULT"],
//             },
//         },
//         impl: {
//             srcs: ["impl/%s"],
//             conditions_default: {
//                 srcs: ["impl/default.cpp"],
//             },
//         },
//     },
// }
//
// cc_library {
//     name: "libacme_foo",
//     defaults: ["acme_defaults"],
//     srcs: ["*.cpp"],
// }
//
// If an acme BoardConfig.mk file contained:
//
// SOONG_CONFIG_NAMESPACES += acme
// SOONG_CONFIG_acme += \
//     board \
//     feature \
//
// SOONG_CONFIG_acme_board := soc_a
// SOONG_CONFIG_acme_feature := true
// SOONG_CONFIG_acme_width := 200
// SOONG_CONFIG_acme_impl := foo.cpp bar.cpp
//
// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE" and srcs
// ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"].
func SoongConfigModuleTypeFactory() Module {
 module := &soongConfigModuleTypeModule{}

 module.AddProperties(&module.properties)

 AddLoadHook(module, func(ctx LoadHookContext) {
  // A soong_config_module_type module should implicitly import itself.
  importModuleTypes(ctx, ctx.BlueprintsFile(), module.properties.Name)
 })

 initAndroidModuleBase(module)

 return module
}

func (m *soongConfigModuleTypeModule) Name() string {
 return m.properties.Name + fmt.Sprintf("%p", m)
}
func (*soongConfigModuleTypeModule) Namespaceless()                                {}
func (*soongConfigModuleTypeModule) GenerateAndroidBuildActions(ctx ModuleContext) {}

type soongConfigStringVariableDummyModule struct {
 ModuleBase
 properties       soongconfig.VariableProperties
 stringProperties soongconfig.StringVariableProperties
}

type soongConfigBoolVariableDummyModule struct {
 ModuleBase
 properties soongconfig.VariableProperties
}

type soongConfigValueVariableDummyModule struct {
 ModuleBase
 properties soongconfig.VariableProperties
}

// soong_config_string_variable defines a variable and a set of possible string values for use
// in a soong_config_module_type definition.
func SoongConfigStringVariableDummyFactory() Module {
 module := &soongConfigStringVariableDummyModule{}
 module.AddProperties(&module.properties, &module.stringProperties)
 initAndroidModuleBase(module)
 return module
}

// soong_config_string_variable defines a variable with true or false values for use
// in a soong_config_module_type definition.
func SoongConfigBoolVariableDummyFactory() Module {
 module := &soongConfigBoolVariableDummyModule{}
 module.AddProperties(&module.properties)
 initAndroidModuleBase(module)
 return module
}

// soong_config_value_variable defines a variable whose value can be expanded into
// the value of a string property.
func SoongConfigValueVariableDummyFactory() Module {
 module := &soongConfigValueVariableDummyModule{}
 module.AddProperties(&module.properties)
 initAndroidModuleBase(module)
 return module
}

func (m *soongConfigStringVariableDummyModule) Name() string {
 return m.properties.Name + fmt.Sprintf("%p", m)
}
func (*soongConfigStringVariableDummyModule) Namespaceless()                                {}
func (*soongConfigStringVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}

func (m *soongConfigBoolVariableDummyModule) Name() string {
 return m.properties.Name + fmt.Sprintf("%p", m)
}
func (*soongConfigBoolVariableDummyModule) Namespaceless()                                {}
func (*soongConfigBoolVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}

func (m *soongConfigValueVariableDummyModule) Name() string {
 return m.properties.Name + fmt.Sprintf("%p", m)
}
func (*soongConfigValueVariableDummyModule) Namespaceless()                                {}
func (*soongConfigValueVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}

// importModuleTypes registers the module factories for a list of module types defined
// in an Android.bp file. These module factories are scoped for the current Android.bp
// file only.
func importModuleTypes(ctx LoadHookContext, from string, moduleTypes ...string) {
 from = filepath.Clean(from)
 if filepath.Ext(from) != ".bp" {
  ctx.PropertyErrorf("from", "%q must be a file with extension .bp", from)
  return
 }

 if strings.HasPrefix(from, "../") {
  ctx.PropertyErrorf("from", "%q must not use ../ to escape the source tree",
   from)
  return
 }

 moduleTypeDefinitions := loadSoongConfigModuleTypeDefinition(ctx, from)
 if moduleTypeDefinitions == nil {
  return
 }
 for _, moduleType := range moduleTypes {
  if factory, ok := moduleTypeDefinitions[moduleType]; ok {
   ctx.registerScopedModuleType(moduleType, factory)
  } else {
   ctx.PropertyErrorf("module_types", "module type %q not defined in %q",
    moduleType, from)
  }
 }
}

// loadSoongConfigModuleTypeDefinition loads module types from an Android.bp file.  It caches the
// result so each file is only parsed once.
func loadSoongConfigModuleTypeDefinition(ctx LoadHookContext, from string) map[string]blueprint.ModuleFactory {
 type onceKeyType string
 key := NewCustomOnceKey(onceKeyType(filepath.Clean(from)))

 reportErrors := func(ctx LoadHookContext, filename string, errs ...error) {
  for _, err := range errs {
   if parseErr, ok := err.(*parser.ParseError); ok {
    ctx.Errorf(parseErr.Pos, "%s", parseErr.Err)
   } else {
    ctx.Errorf(scanner.Position{Filename: filename}, "%s", err)
   }
  }
 }

 return ctx.Config().Once(key, func() interface{} {
  ctx.AddNinjaFileDeps(from)
  r, err := ctx.Config().fs.Open(from)
  if err != nil {
   ctx.PropertyErrorf("from", "failed to open %q: %s", from, err)
   return (map[string]blueprint.ModuleFactory)(nil)
  }
  defer r.Close()

  mtDef, errs := soongconfig.Parse(r, from)
  if len(errs) > 0 {
   reportErrors(ctx, from, errs...)
   return (map[string]blueprint.ModuleFactory)(nil)
  }

  globalModuleTypes := ctx.moduleFactories()

  factories := make(map[string]blueprint.ModuleFactory)

  for name, moduleType := range mtDef.ModuleTypes {
   factory := globalModuleTypes[moduleType.BaseModuleType]
   if factory != nil {
    factories[name] = configModuleFactory(factory, moduleType)
   } else {
    reportErrors(ctx, from,
     fmt.Errorf("missing global module type factory for %q", moduleType.BaseModuleType))
   }
  }

  if ctx.Failed() {
   return (map[string]blueprint.ModuleFactory)(nil)
  }

  return factories
 }).(map[string]blueprint.ModuleFactory)
}

// configModuleFactory takes an existing soongConfigModuleFactory and a
// ModuleType to create a new ModuleFactory that uses a custom loadhook.
func configModuleFactory(factory blueprint.ModuleFactory, moduleType *soongconfig.ModuleType) blueprint.ModuleFactory {
 // Defer creation of conditional properties struct until the first call from the factory
 // method. That avoids having to make a special call to the factory to create the properties
 // structs from which the conditional properties struct is created. This is needed in order to
 // allow singleton modules to be customized by soong_config_module_type as the
 // SingletonModuleFactoryAdaptor factory registers a load hook for the singleton module
 // everytime that it is called. Calling the factory twice causes a build failure as the load
 // hook is called twice, the first time it updates the singleton module to indicate that it has
 // been registered as a module, and the second time it fails because it thinks it has been
 // registered again and a singleton module can only be registered once.
 //
 // This is an issue for singleton modules because:
 // * Load hooks are registered on the module object and are only called when the module object
 //   is created by Blueprint while processing the Android.bp file.
 // * The module factory for a singleton module returns the same module object each time it is
 //   called, and registers its load hook on that same module object.
 // * When the module factory is called by Blueprint it then calls all the load hooks that have
 //   been registered for every call to that module factory.
 //
 // It is not an issue for normal modules because they return a new module object each time the
 // factory is called and so any load hooks registered on module objects which are discarded will
 // not be run.
 once := &sync.Once{}
 conditionalFactoryProps := reflect.Value{}
 getConditionalFactoryProps := func(props []interface{}) reflect.Value {
  once.Do(func() {
   conditionalFactoryProps = soongconfig.CreateProperties(props, moduleType)
  })
  return conditionalFactoryProps
 }

 return func() (blueprint.Module, []interface{}) {
  module, props := factory()
  conditionalFactoryProps := getConditionalFactoryProps(props)
  if !conditionalFactoryProps.IsValid() {
   return module, props
  }

  conditionalProps := proptools.CloneEmptyProperties(conditionalFactoryProps)
  props = append(props, conditionalProps.Interface())

  if m, ok := module.(Module); ok {
   m.base().baseProperties.Soong_config_base_module_type = &moduleType.BaseModuleType
  }

  // Regular Soong operation wraps the existing module factory with a
  // conditional on Soong config variables by reading the product
  // config variables from Make.
  AddLoadHook(module, func(ctx LoadHookContext) {
   config := ctx.Config().VendorConfig(moduleType.ConfigNamespace)
   newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, config)
   if err != nil {
    ctx.ModuleErrorf("%s", err)
    return
   }
   for _, ps := range newProps {
    ctx.AppendProperties(ps)
   }
  })
  return module, props
 }
}

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