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

Quelle  bindgen.go   Sprache: unbekannt

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

// Copyright 2020 The Android Open Source Project
//
// 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 rust

import (
 "strings"

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

 "android/soong/android"
 "android/soong/cc"
 cc_config "android/soong/cc/config"
 "android/soong/rust/config"
)

var (
 defaultBindgenFlags = []string{
  "--blocklist-type",
  "max_align_t",
 }

 // bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
 bindgenClangVersion = "clang-r584948"

 _ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
  if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
   return override
  }
  return bindgenClangVersion
 })

 //TODO(b/160803703) Use a prebuilt bindgen instead of the built bindgen.
 _ = pctx.HostBinToolVariable("bindgenCmd", "bindgen")
 _ = pctx.VariableFunc("bindgenHostPrebuiltTag", func(ctx android.PackageVarContext) string {
  if ctx.Config().UseHostMusl() {
   // This is a hack to use the glibc bindgen binary until we have a musl version checked in.
   return "linux-x86"
  } else {
   return "${config.HostPrebuiltTag}"
  }
 })
 _ = pctx.VariableFunc("bindgenClangLibdir", func(ctx android.PackageVarContext) string {
  if ctx.Config().UseHostMusl() {
   return "musl/lib/"
  } else {
   return "lib/"
  }
 })
 _ = pctx.SourcePathVariable("bindgenClang",
  "${cc_config.ClangBase}/${bindgenHostPrebuiltTag}/${bindgenClangVersion}/bin/clang")
 _ = pctx.SourcePathVariable("bindgenLibClang",
  "${cc_config.ClangBase}/${bindgenHostPrebuiltTag}/${bindgenClangVersion}/${bindgenClangLibdir}")

 //TODO(ivanlozano) Switch this to RuleBuilder
 //
 //TODO Pass the flag files directly to bindgen e.g. with @file when it supports that.
 //See https://github.com/rust-lang/rust-bindgen/issues/2508.
 bindgen = pctx.AndroidStaticRule("bindgen",
  blueprint.RuleParams{
   Command: "CLANG_PATH=$bindgenClang LIBCLANG_PATH=$bindgenLibClang RUSTFMT=${config.RustBin}/rustfmt " +
    "$cmd $flags $$(cat $flagfiles) $in -o $out -- -MD -MF $out.d $cflags",
   CommandDeps:     []string{"$cmd"},
   Deps:            blueprint.DepsGCC,
   Depfile:         "$out.d",
   SandboxDisabled: true,
  },
  "cmd", "flags", "flagfiles", "cflags")
)

func init() {
 android.RegisterModuleType("rust_bindgen", RustBindgenFactory)
 android.RegisterModuleType("rust_bindgen_host", RustBindgenHostFactory)
}

var _ SourceProvider = (*bindgenDecorator)(nil)

type BindgenProperties struct {
 // The wrapper header file. By default this is assumed to be a C header unless the extension is ".hh" or ".hpp".
 // This is used to specify how to interpret the header and determines which '-std' flag to use by default.
 //
 // If your C++ header must have some other extension, then the default behavior can be overridden by setting the
 // cpp_std property.
 Wrapper_src *string `android:"path,arch_variant"`

 // list of bindgen-specific flags and options
 Bindgen_flags []string `android:"arch_variant"`

 // list of files containing extra bindgen flags
 Bindgen_flag_files []string `android:"arch_variant"`

 // module name of a custom binary/script which should be used instead of the 'bindgen' binary. This custom
 // binary must expect arguments in a similar fashion to bindgen, e.g.
 //
 // "my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]"
 Custom_bindgen string

 // flag to indicate if bindgen should handle `static inline` functions (default is false).
 // If true, Static_inline_library must be set.
 Handle_static_inline *bool

 // module name of the corresponding cc_library_static which includes the static_inline wrapper
 // generated functions from bindgen. Must be used together with handle_static_inline.
 //
 // If there are no static inline functions provided through the header file,
 // then bindgen (as of 0.69.2) will silently fail to output a .c file, and
 // the cc_library_static depending on this module will fail compilation.
 Static_inline_library *string
}

type bindgenDecorator struct {
 *BaseSourceProvider

 Properties      BindgenProperties
 ClangProperties cc.RustBindgenClangProperties
}

func (b *bindgenDecorator) getStdVersion(ctx ModuleContext, src android.Path) (string, bool) {
 // Assume headers are C headers
 isCpp := false
 stdVersion := ""

 switch src.Ext() {
 case ".hpp", ".hh":
  isCpp = true
 }

 if String(b.ClangProperties.Cpp_std) != "" && String(b.ClangProperties.C_std) != "" {
  ctx.PropertyErrorf("c_std", "c_std and cpp_std cannot both be defined at the same time.")
 }

 if b.ClangProperties.Cpp_std != nil {
  isCpp = true
  if String(b.ClangProperties.Cpp_std) == "experimental" {
   stdVersion = cc_config.ExperimentalCppStdVersion
  } else if String(b.ClangProperties.Cpp_std) == "default" || String(b.ClangProperties.Cpp_std) == "" {
   stdVersion = cc_config.CppStdVersion(ctx)
  } else {
   stdVersion = String(b.ClangProperties.Cpp_std)
  }
 } else if b.ClangProperties.C_std != nil {
  isCpp = false
  if String(b.ClangProperties.C_std) == "experimental" {
   stdVersion = cc_config.ExperimentalCStdVersion
  } else if String(b.ClangProperties.C_std) == "default" || String(b.ClangProperties.C_std) == "" {
   stdVersion = cc_config.CStdVersion
  } else {
   stdVersion = String(b.ClangProperties.C_std)
  }
 } else if isCpp {
  stdVersion = cc_config.CppStdVersion(ctx)
 } else {
  stdVersion = cc_config.CStdVersion
 }

 return stdVersion, isCpp
}

func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
 ccToolchain := ctx.RustModule().ccToolchain(ctx)

 var cflags []string
 var implicits android.Paths
 var implicitOutputs android.WritablePaths
 var validations android.Paths

 if Bool(b.Properties.Handle_static_inline) && b.Properties.Static_inline_library == nil {
  ctx.PropertyErrorf("handle_static_inline",
   "requires declaring static_inline_library to the corresponding cc_library module that includes the generated C source from bindgen.")
 }

 if b.Properties.Static_inline_library != nil && !Bool(b.Properties.Handle_static_inline) {
  ctx.PropertyErrorf("static_inline_library",
   "requires declaring handle_static_inline.")
 }

 implicits = append(implicits, deps.depGeneratedHeaders...)

 // Default clang flags
 cflags = append(cflags, "${cc_config.CommonGlobalCflags}")
 if ctx.Device() {
  cflags = append(cflags, "${cc_config.DeviceGlobalCflags}", "-nostdlibinc")
 }

 // Toolchain clang flags
 cflags = append(cflags, "-target "+ccToolchain.ClangTriple())
 cflags = append(cflags, strings.ReplaceAll(ccToolchain.Cflags(), "${config.", "${cc_config."))
 cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainCflags(), "${config.", "${cc_config."))

 if ctx.RustModule().InVendorOrProduct() {
  cflags = append(cflags, "-D__ANDROID_VNDK__")
  if ctx.RustModule().InVendor() {
   cflags = append(cflags, "-D__ANDROID_VENDOR__")
  } else if ctx.RustModule().InProduct() {
   cflags = append(cflags, "-D__ANDROID_PRODUCT__")
  }

  // Define __ANDROID_VENDOR_API__ for both product and vendor variants
  // because they both use the same LLNDK libraries.
  vendorApiLevel := ctx.Config().VendorApiLevel()
  if vendorApiLevel == "" {
   // TODO(b/314036847): This is a fallback for UDC targets.
   // This must be a build failure when UDC is no longer built
   // from this source tree.
   vendorApiLevel = ctx.Config().PlatformSdkVersion().String()
  }
  cflags = append(cflags, "-D__ANDROID_VENDOR_API__="+vendorApiLevel)
 }

 if ctx.RustModule().InRecovery() {
  cflags = append(cflags, "-D__ANDROID_RECOVERY__")
 }

 if mctx, ok := ctx.(*moduleContext); ok && mctx.apexVariationName() != "" {
  cflags = append(cflags, "-D__ANDROID_APEX__")
 }

 if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
  cflags = append(cflags, "-D__ANDROID_NATIVE_BRIDGE__")
 }

 // Dependency clang flags and include paths
 cflags = append(cflags, deps.depClangFlags...)
 for _, include := range deps.depIncludePaths {
  cflags = append(cflags, "-I"+include.String())
 }
 for _, include := range deps.depSystemIncludePaths {
  cflags = append(cflags, "-isystem "+include.String())
 }

 esc := proptools.NinjaAndShellEscapeList

 // Filter out invalid cflags
 cflagsProp := b.ClangProperties.Cflags.GetOrDefault(ctx, nil)
 for _, flag := range cflagsProp {
  if flag == "-x c++" || flag == "-xc++" {
   ctx.PropertyErrorf("cflags",
    "-x c++ should not be specified in cflags; setting cpp_std specifies this is a C++ header, or change the file extension to '.hpp' or '.hh'")
  }
  if strings.HasPrefix(flag, "-std=") {
   ctx.PropertyErrorf("cflags",
    "-std should not be specified in cflags; instead use c_std or cpp_std")
  }
 }

 // Module defined clang flags and include paths
 cflags = append(cflags, esc(cflagsProp)...)
 for _, include := range b.ClangProperties.Local_include_dirs.GetOrDefault(ctx, nil) {
  cflags = append(cflags, "-I"+android.PathForModuleSrc(ctx, include).String())
  implicits = append(implicits, android.PathForModuleSrc(ctx, include))
 }

 bindgenFlags := defaultBindgenFlags
 bindgenFlags = append(bindgenFlags, "--rust-target", config.GetRustVersion(ctx))
 bindgenFlags = append(bindgenFlags, esc(b.Properties.Bindgen_flags)...)
 if Bool(b.Properties.Handle_static_inline) {
  outputStaticFnsFile := android.PathForModuleOut(ctx, b.getStem(ctx)+".c")
  implicitOutputs = append(implicitOutputs, outputStaticFnsFile)
  validations = append(validations, outputStaticFnsFile)
  bindgenFlags = append(bindgenFlags, []string{"--experimental", "--wrap-static-fns", "--wrap-static-fns-path=" + outputStaticFnsFile.String()}...)
 }

 // cat reads from stdin if its command line is empty,
 // so we pass in /dev/null if there are no other flag files
 bindgenFlagFiles := []string{"/dev/null"}
 for _, flagFile := range b.Properties.Bindgen_flag_files {
  bindgenFlagFiles = append(bindgenFlagFiles, android.PathForModuleSrc(ctx, flagFile).String())
  implicits = append(implicits, android.PathForModuleSrc(ctx, flagFile))
 }

 wrapperFile := android.OptionalPathForModuleSrc(ctx, b.Properties.Wrapper_src)
 if !wrapperFile.Valid() {
  ctx.PropertyErrorf("wrapper_src", "invalid path to wrapper source")
 }

 // Add C std version flag
 stdVersion, isCpp := b.getStdVersion(ctx, wrapperFile.Path())
 cflags = append(cflags, "-std="+stdVersion)

 // Specify the header source language to avoid ambiguity.
 if isCpp {
  cflags = append(cflags, "-x c++")
  // Add any C++ only flags.
  cflags = append(cflags, esc(b.ClangProperties.Cppflags.GetOrDefault(ctx, nil))...)
 } else {
  cflags = append(cflags, "-x c")
 }

 // clang-r468909b complains about the -x c in the flags in clang-sys parse_search_paths:
 // clang: error: '-x c' after last input file has no effect [-Werror,-Wunused-command-line-argument]
 cflags = append(cflags, "-Wno-unused-command-line-argument")

 // The Clang version used by CXX can be newer than the one used by Bindgen, and uses warning related flags that
 // it cannot recognize. Turn off unknown warning flags warning.
 cflags = append(cflags, "-Wno-unknown-warning-option")

 // The main file for bindgen usually is header where #pragma once is actually best practice.
 // Don't pollute the build log with unnecessary warnings.
 cflags = append(cflags, "-Wno-pragma-once-outside-header")

 // Suppress warnings while testing a new compiler.
 if ctx.Config().IsEnvTrue("LLVM_NEXT") {
  cflags = append(cflags, "-Wno-everything")
 }

 outputFile := android.PathForModuleOut(ctx, b.getStem(ctx)+".rs")

 var cmd, cmdDesc string
 if b.Properties.Custom_bindgen != "" {
  m := ctx.GetDirectDepProxyWithTag(b.Properties.Custom_bindgen, customBindgenDepTag)
  if info := android.GetHostToolInfo(ctx, m); info != nil {
   cmd = info.HostToolPath.String()
  }
  cmdDesc = b.Properties.Custom_bindgen
 } else {
  cmd = "$bindgenCmd"
  cmdDesc = "bindgen"
 }

 ctx.Build(pctx, android.BuildParams{
  Rule:            bindgen,
  Description:     strings.Join([]string{cmdDesc, wrapperFile.Path().Rel()}, " "),
  Output:          outputFile,
  Input:           wrapperFile.Path(),
  Implicits:       implicits,
  ImplicitOutputs: implicitOutputs,
  Validations:     validations,
  Args: map[string]string{
   "cmd":       cmd,
   "flags":     strings.Join(bindgenFlags, " "),
   "flagfiles": strings.Join(bindgenFlagFiles, " "),
   "cflags":    strings.Join(cflags, " "),
  },
 })

 b.OutputFiles = android.Paths{outputFile}

 // Append any additional implicit outputs after the entry point source.
 // We append any generated .c file here so it can picked up by cc_library_static modules.
 // Those CC modules need to be sure not to pass any included .rs files to Clang.
 // We don't have to worry about the additional .c files for Rust modules as only the entry point
 // is passed to rustc.
 b.OutputFiles = append(b.OutputFiles, implicitOutputs.Paths()...)

 return outputFile
}

func (b *bindgenDecorator) SourceProviderProps() []any {
 return append(b.BaseSourceProvider.SourceProviderProps(),
  &b.Properties, &b.ClangProperties)
}

// rust_bindgen generates Rust FFI bindings to C libraries using bindgen given a wrapper header as the primary input.
// Bindgen has a number of flags to control the generated source, and additional flags can be passed to clang to ensure
// the header and generated source is appropriately handled. It is recommended to add it as a dependency in the
// rlibs or rustlibs property. It may also be added in the srcs property for external crates, using the ":"
// prefix.
func RustBindgenFactory() android.Module {
 module, _ := NewRustBindgen(android.HostAndDeviceSupported)
 return module.Init()
}

func RustBindgenHostFactory() android.Module {
 module, _ := NewRustBindgen(android.HostSupported)
 return module.Init()
}

func NewRustBindgen(hod android.HostOrDeviceSupported) (*Module, *bindgenDecorator) {
 bindgen := &bindgenDecorator{
  BaseSourceProvider: NewSourceProvider(),
  Properties:         BindgenProperties{},
  ClangProperties:    cc.RustBindgenClangProperties{},
 }

 module := NewSourceProviderModule(hod, bindgen, false, false)

 android.AddLoadHook(module, func(ctx android.LoadHookContext) {
  type stub_props struct {
   Visibility []string
  }
  props := &stub_props{[]string{":__subpackages__"}}
  ctx.PrependProperties(props)
 })

 return module, bindgen
}

func (b *bindgenDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
 deps = b.BaseSourceProvider.SourceProviderDeps(ctx, deps)
 if ctx.toolchain().Bionic() && !ctx.RustModule().compiler.noStdlibs() {
  deps = bionicDeps(ctx, deps, false)
 } else if ctx.Os() == android.LinuxMusl {
  deps = muslDeps(ctx, deps, false)
 }

 if !ctx.RustModule().Source() && b.Properties.Static_inline_library != nil {
  // This is not the source variant, so add the static inline library as a dependency.
  //
  // This is necessary to avoid a circular dependency between the source variant and the
  // dependent cc module.
  deps.WholeStaticLibs = append(deps.WholeStaticLibs, String(b.Properties.Static_inline_library))
 }

 deps.SharedLibs = append(deps.SharedLibs, b.ClangProperties.Shared_libs.GetOrDefault(ctx, nil)...)
 deps.StaticLibs = append(deps.StaticLibs, b.ClangProperties.Static_libs.GetOrDefault(ctx, nil)...)
 deps.HeaderLibs = append(deps.HeaderLibs, b.ClangProperties.Header_libs.GetOrDefault(ctx, nil)...)
 return deps
}

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