Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  bootstrap.go   Sprache: unbekannt

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

// Copyright 2014 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 bootstrap

import (
 "encoding/json"
 "fmt"
 "path/filepath"
 "runtime"
 "strings"

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

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

var (
 pctx = blueprint.NewPackageContext("github.com/google/blueprint/bootstrap")

 goTestMainCmd   = pctx.StaticVariable("goTestMainCmd", filepath.Join("$ToolDir", "gotestmain"))
 goTestRunnerCmd = pctx.StaticVariable("goTestRunnerCmd", filepath.Join("$ToolDir", "gotestrunner"))
 pluginGenSrcCmd = pctx.StaticVariable("pluginGenSrcCmd", filepath.Join("$ToolDir", "loadplugins"))
 gobGenCmd       = pctx.StaticVariable("gobGenCmd", filepath.Join("$ToolDir", "gob_gen"))

 goToolchainTarget = "go_toolchain"

 _ = pctx.VariableFunc("toybox", func(ctx blueprint.VariableFuncContext, config interface{}) (string, error) {
  prebuiltOs := func() string {
   switch runtime.GOOS {
   case "linux":
    switch runtime.GOARCH {
    case "amd64":
     return "linux-x86"
    case "arm64":
     return "linux-arm64"
    default:
     panic(fmt.Errorf("Unknown GOARCH %s", runtime.GOARCH))
    }
   case "darwin":
    return "darwin-x86"
   default:
    panic(fmt.Errorf("Unknown GOOS %s", runtime.GOOS))
   }
  }()
  return filepath.Join("prebuilts/build-tools", prebuiltOs, "bin/toybox"), nil
 })

 parallelCompile = pctx.StaticVariable("parallelCompile", func() string {
  numCpu := runtime.NumCPU()
  // This will cause us to recompile all go programs if the
  // number of cpus changes. We don't get a lot of benefit from
  // higher values, so cap this to make it cheaper to move trees
  // between machines.
  if numCpu > 8 {
   numCpu = 8
  }
  return fmt.Sprintf("-c %d", numCpu)
 }())

 // We must explicitly use the $toybox path for utilities like cmp, rm, and mv in
 // bootstrap rules. Unlike downstream Soong rules (which are wrapped by sbox or
 // RuleBuilder with injected $PATHs), bootstrap rules execute raw commands.
 // Explicit paths guarantee execution hermeticity on remote bots (RBE) that
 // lack basic POSIX tools in their base image.
 compile = pctx.StaticRule("compile",
  blueprint.RuleParams{
   Command: "GOROOT='$goRoot' $compileCmd $parallelCompile -o $out.tmp " +
    "$debugFlags -p $pkgPath -complete $incFlags $embedFlags -pack $in && " +
    "if $toybox cmp --quiet $out.tmp $out; then $toybox rm $out.tmp; else $toybox mv -f $out.tmp $out; fi",
   CommandDeps: []string{"$compileCmd", "${toybox}"},
   Description: "compile $out",
   Restat:      true,
  },
  "pkgPath", "incFlags", "embedFlags")

 // See comment on compile rule for why $toybox is explicitly prefixed.
 link = pctx.StaticRule("link",
  blueprint.RuleParams{
   Command: "GOROOT='$goRoot' $linkCmd -o $out.tmp $libDirFlags $in && " +
    "if $toybox cmp --quiet $out.tmp $out; then $toybox rm $out.tmp; else $toybox mv -f $out.tmp $out; fi",
   CommandDeps: []string{"$linkCmd", "${toybox}"},
   Description: "link $out",
   Restat:      true,
  },
  "libDirFlags")

 goTestMain = pctx.StaticRule("gotestmain",
  blueprint.RuleParams{
   Command:     "$goTestMainCmd -o $out -pkg $pkg $in",
   CommandDeps: []string{"$goTestMainCmd"},
   Description: "gotestmain $out",
  },
  "pkg")

 pluginGenSrc = pctx.StaticRule("pluginGenSrc",
  blueprint.RuleParams{
   Command:     "$pluginGenSrcCmd -o $out -p $pkg $plugins",
   CommandDeps: []string{"$pluginGenSrcCmd"},
   Description: "create $out",
  },
  "pkg", "plugins")

 verifySerializers = pctx.StaticRule("generateSerializers",
  blueprint.RuleParams{
   Command:     "${toybox} rm -f $out && $gobGenCmd -verify $in && ${toybox} touch $out",
   CommandDeps: []string{"$gobGenCmd", "${toybox}"},
   Description: "generate serializers $out",
  })

 test = pctx.StaticRule("test",
  blueprint.RuleParams{
   Command:     "$goTestRunnerCmd -p $pkgSrcDir -f $out -- $in -test.short",
   CommandDeps: []string{"$goTestRunnerCmd"},
   Description: "test $pkg",
  },
  "pkg", "pkgSrcDir")

 cp = pctx.StaticRule("cp",
  blueprint.RuleParams{
   Command:     "${toybox} cp -P $in $out",
   CommandDeps: []string{`${toybox}`},
   Description: "cp $out",
  },
  "generator")

 touch = pctx.StaticRule("touch",
  blueprint.RuleParams{
   Command:     "${toybox} touch $out",
   CommandDeps: []string{`${toybox}`},
   Description: "touch $out",
  },
  "depfile", "generator")

 cat = pctx.StaticRule("Cat",
  blueprint.RuleParams{
   Command:     "${toybox} rm -f $out && ${toybox} cat $in > $out",
   CommandDeps: []string{`${toybox}`},
   Description: "concatenate files to $out",
  })

 writeFile = pctx.StaticRule("writeFile",
  blueprint.RuleParams{
   Command:     `${toybox} rm -f $out && ${toybox} echo -e -n $content > $out`,
   CommandDeps: []string{`${toybox}`},
   Description: "writing file $out",
  },
  "content")

 generateBuildNinja = pctx.StaticRule("build.ninja",
  blueprint.RuleParams{
   // TODO: it's kinda ugly that some parameters are computed from
   // environment variables and some from Ninja parameters, but it's probably
   // better to not to touch that while Blueprint and Soong are separate
   // NOTE: The spaces at EOL are important because otherwise Ninja would
   // omit all spaces between the different options.
   Command: `cd "$$(dirname "$builder")" && ` +
    `BUILDER="$$PWD/$$(basename "$builder")" && ` +
    `cd / && ` +
    `env -i $env "$$BUILDER" ` +
    `    --top "$$TOP" ` +
    `    --soong_out "$soongOutDir" ` +
    `    --out "$outDir" ` +
    `    $extra`,
   CommandDeps:     []string{"$builder"},
   Description:     "$builder $out",
   Deps:            blueprint.DepsGCC,
   Depfile:         "$out.d",
   Restat:          true,
   SandboxDisabled: true,
  },
  "builder", "env", "extra", "pool")

 _ = pctx.VariableFunc("ToolDir", func(ctx blueprint.VariableFuncContext, config interface{}) (string, error) {
  return config.(BootstrapConfig).HostToolDir(), nil
 })
)

var (
 // echoEscaper escapes a string such that passing it to "echo -e" will produce the input value.
 echoEscaper = strings.NewReplacer(
  `\`, `\\`, // First escape existing backslashes so they aren't interpreted by `echo -e`.
  "\n", `\n`, // Then replace newlines with \n
 )
)

// shardString takes a string and returns a slice of strings where the length of each one is
// at most shardSize.
func shardString(s string, shardSize int) []string {
 if len(s) == 0 {
  return nil
 }
 ret := make([]string, 0, (len(s)+shardSize-1)/shardSize)
 for len(s) > shardSize {
  ret = append(ret, s[0:shardSize])
  s = s[shardSize:]
 }
 if len(s) > 0 {
  ret = append(ret, s)
 }
 return ret
}

// writeFileRule creates a ninja rule to write contents to a file.  The contents will be
// escaped so that the file contains exactly the contents passed to the function.
func writeFileRule(ctx blueprint.ModuleContext, outputFile string, content string) {
 // This is MAX_ARG_STRLEN subtracted with some safety to account for shell escapes
 const SHARD_SIZE = 131072 - 10000

 buildWriteFileRule := func(outputFile string, content string) {
  content = echoEscaper.Replace(content)
  content = proptools.NinjaEscape(proptools.ShellEscapeIncludingSpaces(content))
  if content == "" {
   content = "''"
  }
  ctx.Build(pctx, blueprint.BuildParams{
   Rule:        writeFile,
   Outputs:     []string{outputFile},
   Description: "write " + outputFile,
   Args: map[string]string{
    "content": content,
   },
  })
 }

 if len(content) > SHARD_SIZE {
  var chunks []string
  for i, c := range shardString(content, SHARD_SIZE) {
   tempPath := fmt.Sprintf("%s.%d", outputFile, i)
   buildWriteFileRule(tempPath, c)
   chunks = append(chunks, tempPath)
  }
  ctx.Build(pctx, blueprint.BuildParams{
   Rule:        cat,
   Inputs:      chunks,
   Outputs:     []string{outputFile},
   Description: "Merging to " + outputFile,
  })
  return
 }
 buildWriteFileRule(outputFile, content)
}

type pluginDependencyTag struct {
 blueprint.BaseDependencyTag
}

func (pluginDependencyTag) ExcludeFromVisibilityEnforcement() {}

type bootstrapDependencies interface {
 bootstrapDeps(ctx blueprint.BottomUpMutatorContext)
}

var PluginDepTag = pluginDependencyTag{}

func BootstrapDeps(ctx blueprint.BottomUpMutatorContext) {
 if pkg, ok := ctx.Module().(bootstrapDependencies); ok {
  pkg.bootstrapDeps(ctx)
 }
}

// @auto-generate: gob
type PackageInfo struct {
 PkgPath       string
 PkgRoot       string
 PackageTarget string
 TestTargets   []string

 TransitivePkgRoot       depset.DepSet[string]
 TransitivePackageTarget depset.DepSet[string]
}

var PackageProvider = blueprint.NewProvider[*PackageInfo]()

// @auto-generate: gob
type BinaryInfo struct {
 IntermediatePath string
 InstallPath      string
 TestTargets      []string
}

var BinaryProvider = blueprint.NewProvider[*BinaryInfo]()

// @auto-generate: gob
type DocsPackageInfo struct {
 PkgPath string
 Srcs    []string
}

var DocsPackageProvider = blueprint.NewMutatorProvider[*DocsPackageInfo]("bootstrap_deps")

// A GoPackage is a module for building Go packages.
type GoPackage struct {
 blueprint.ModuleBase
 blueprint.SimpleName
 properties struct {
  Deps      []string
  PkgPath   string
  Srcs      []string
  TestSrcs  []string
  TestData  []string
  PluginFor []string
  EmbedSrcs []string
  // The visibility property is unused in blueprint, but exists so that soong
  // can add one and not have the bp files fail to parse during the bootstrap build.
  Visibility []string

  Darwin struct {
   Srcs     []string
   TestSrcs []string
  }
  Linux struct {
   Srcs     []string
   TestSrcs []string
  }
 }
}

func newGoPackageModuleFactory() func() (blueprint.Module, []interface{}) {
 return func() (blueprint.Module, []interface{}) {
  module := &GoPackage{}
  return module, []interface{}{&module.properties, &module.SimpleName.Properties}
 }
}

// Properties returns the list of property structs to be used for registering a wrapped module type.
func (g *GoPackage) Properties() []interface{} {
 return []interface{}{&g.properties}
}

func (g *GoPackage) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string {
 return g.properties.Deps
}

func (g *GoPackage) bootstrapDeps(ctx blueprint.BottomUpMutatorContext) {
 for _, plugin := range g.properties.PluginFor {
  ctx.AddReverseDependency(ctx.Module(), PluginDepTag, plugin)
 }
 blueprint.SetProvider(ctx, DocsPackageProvider, &DocsPackageInfo{
  PkgPath: g.properties.PkgPath,
  Srcs:    g.properties.Srcs,
 })
}

func (g *GoPackage) GenerateBuildActions(ctx blueprint.ModuleContext) {
 var (
  name       = ctx.ModuleName()
  hasPlugins = false
  pluginSrc  = ""
  genSrcs    = []string{}
 )

 if g.properties.PkgPath == "" {
  ctx.ModuleErrorf("module %s did not specify a valid pkgPath", name)
  return
 }

 pkgRoot := packageRoot(ctx)
 archiveFile := filepath.Join(pkgRoot,
  filepath.FromSlash(g.properties.PkgPath)+".a")

 ctx.VisitDirectDepsProxy(func(module blueprint.ModuleProxy) {
  if ctx.OtherModuleDependencyTag(module) == PluginDepTag {
   hasPlugins = true
  }
 })
 if hasPlugins {
  pluginSrc = filepath.Join(moduleGenSrcDir(ctx), "plugin.go")
  genSrcs = append(genSrcs, pluginSrc)
 }

 if hasPlugins && !buildGoPluginLoader(ctx, g.properties.PkgPath, pluginSrc) {
  return
 }

 var srcs, testSrcs []string
 if runtime.GOOS == "darwin" {
  srcs = append(g.properties.Srcs, g.properties.Darwin.Srcs...)
  testSrcs = append(g.properties.TestSrcs, g.properties.Darwin.TestSrcs...)
 } else if runtime.GOOS == "linux" {
  srcs = append(g.properties.Srcs, g.properties.Linux.Srcs...)
  testSrcs = append(g.properties.TestSrcs, g.properties.Linux.TestSrcs...)
 }

 testArchiveFile := filepath.Join(testRoot(ctx),
  filepath.FromSlash(g.properties.PkgPath)+".a")
 testResultFile := buildGoTest(ctx, testRoot(ctx), testArchiveFile,
  g.properties.PkgPath, srcs, genSrcs, testSrcs, g.properties.EmbedSrcs)

 // Don't build for test-only packages
 if len(srcs) == 0 && len(genSrcs) == 0 {
  ctx.Build(pctx, blueprint.BuildParams{
   Rule:    touch,
   Outputs: []string{archiveFile},
  })
  return
 }

 incFlags, deps, _, _, transitivePkgRoot, transitivePackageTarget := collectGoDeps(ctx)

 buildGoPackage(ctx, pkgRoot, g.properties.PkgPath, archiveFile,
  srcs, genSrcs, g.properties.EmbedSrcs, incFlags, deps)

 blueprint.SetProvider(ctx, PackageProvider, &PackageInfo{
  PkgPath:       g.properties.PkgPath,
  PkgRoot:       pkgRoot,
  PackageTarget: archiveFile,
  TestTargets:   testResultFile,

  TransitivePkgRoot:       transitivePkgRoot,
  TransitivePackageTarget: transitivePackageTarget,
 })
}

func collectGoDeps(ctx blueprint.ModuleContext) (incFlags, incFlagsDeps, linkFlags, linkFlagsDeps []string,
 transitivePkgRoot, transitivePackageTarget depset.DepSet[string]) {

 transitivePkgRootBuilder := depset.NewBuilder[string](depset.POSTORDER)
 transitivePackageTargetBuilder := depset.NewBuilder[string](depset.POSTORDER)

 ctx.VisitDirectDepsProxy(func(module blueprint.ModuleProxy) {
  if info, ok := blueprint.OtherModuleProvider(ctx, module, PackageProvider); ok {
   incDir := info.PkgRoot
   target := info.PackageTarget
   incFlags = append(incFlags, "-I "+incDir)
   incFlagsDeps = append(incFlagsDeps, target)
   transitivePkgRootBuilder.Direct(info.PkgRoot).Transitive(info.TransitivePkgRoot)
   transitivePackageTargetBuilder.Direct(info.PackageTarget).Transitive(info.TransitivePackageTarget)
  }
 })

 transitivePkgRoot = transitivePkgRootBuilder.Build()
 transitivePackageTarget = transitivePackageTargetBuilder.Build()

 linkFlagsDeps = transitivePackageTarget.ToList()
 for _, libDir := range transitivePkgRoot.ToList() {
  linkFlags = append(linkFlags, "-L "+libDir)
 }
 return
}

func buildVerifySerializers(ctx blueprint.ModuleContext, outputFile string, srcs []string, archiveFile string) {
 var srcPaths []string
 for _, src := range srcs {
  srcPaths = append(srcPaths, filepath.Join(moduleSrcDir(ctx), src))
 }

 ctx.Build(pctx, blueprint.BuildParams{
  Rule:      verifySerializers,
  Inputs:    srcPaths,
  Implicits: []string{archiveFile},
  Outputs:   []string{outputFile},
 })
}

// A GoBinary is a module for building executable binaries from Go sources.
type GoBinary struct {
 blueprint.ModuleBase
 blueprint.SimpleName
 properties struct {
  Deps           []string
  Srcs           []string
  TestSrcs       []string
  TestData       []string
  EmbedSrcs      []string
  PrimaryBuilder bool
  Default        bool
  // The visibility property is unused in blueprint, but exists so that soong
  // can add one and not have the bp files fail to parse during the bootstrap build.
  Visibility []string

  Darwin struct {
   Srcs     []string
   TestSrcs []string
  }
  Linux struct {
   Srcs     []string
   TestSrcs []string
  }
 }

 installPath string

 // skipInstall can be set to true by a module type that wraps GoBinary to skip the install rule,
 // allowing the wrapping module type to create the install rule itself.
 skipInstall bool

 // outputFile is set to the path to the intermediate output file.
 outputFile string
}

func newGoBinaryModuleFactory() func() (blueprint.Module, []interface{}) {
 return func() (blueprint.Module, []interface{}) {
  module := &GoBinary{}
  return module, []interface{}{&module.properties, &module.SimpleName.Properties}
 }
}

func (g *GoBinary) DynamicDependencies(ctx blueprint.DynamicDependerModuleContext) []string {
 return g.properties.Deps
}

func (g *GoBinary) bootstrapDeps(ctx blueprint.BottomUpMutatorContext) {
 if g.properties.PrimaryBuilder {
  blueprint.SetProvider(ctx, PrimaryBuilderProvider, PrimaryBuilderInfo{})
 }
}

// IntermediateFile returns the path to the final linked intermedate file.
func (g *GoBinary) IntermediateFile() string {
 return g.outputFile
}

// SetSkipInstall is called by module types that wrap GoBinary to skip the install rule,
// allowing the wrapping module type to create the install rule itself.
func (g *GoBinary) SetSkipInstall() {
 g.skipInstall = true
}

// Properties returns the list of property structs to be used for registering a wrapped module type.
func (g *GoBinary) Properties() []interface{} {
 return []interface{}{&g.properties}
}

func (g *GoBinary) GenerateBuildActions(ctx blueprint.ModuleContext) {
 var (
  name            = ctx.ModuleName()
  objDir          = packageRoot(ctx)
  archiveFile     = filepath.Join(objDir, name+".a")
  testArchiveFile = filepath.Join(testRoot(ctx), name+".a")
  aoutFile        = filepath.Join(objDir, name)
  hasPlugins      = false
  pluginSrc       = ""
  genSrcs         = []string{}
 )

 if !g.skipInstall {
  g.installPath = filepath.Join(ctx.Config().(BootstrapConfig).HostToolDir(), name)
 }

 ctx.VisitDirectDepsProxy(func(module blueprint.ModuleProxy) {
  if ctx.OtherModuleDependencyTag(module) == PluginDepTag {
   hasPlugins = true
  }
 })
 if hasPlugins {
  pluginSrc = filepath.Join(moduleGenSrcDir(ctx), "plugin.go")
  genSrcs = append(genSrcs, pluginSrc)
 }

 if hasPlugins && !buildGoPluginLoader(ctx, "main", pluginSrc) {
  return
 }

 var srcs, testSrcs []string
 if runtime.GOOS == "darwin" {
  srcs = append(g.properties.Srcs, g.properties.Darwin.Srcs...)
  testSrcs = append(g.properties.TestSrcs, g.properties.Darwin.TestSrcs...)
 } else if runtime.GOOS == "linux" {
  srcs = append(g.properties.Srcs, g.properties.Linux.Srcs...)
  testSrcs = append(g.properties.TestSrcs, g.properties.Linux.TestSrcs...)
 }

 testResultFile := buildGoTest(ctx, testRoot(ctx), testArchiveFile,
  name, srcs, genSrcs, testSrcs, g.properties.EmbedSrcs)

 incFlags, deps, linkFlags, linkFlagsDeps, _, _ := collectGoDeps(ctx)

 buildGoPackage(ctx, objDir, "main", archiveFile, srcs, genSrcs, g.properties.EmbedSrcs, incFlags, deps)

 linkArgs := map[string]string{}
 if len(linkFlags) > 0 {
  linkArgs["libDirFlags"] = strings.Join(linkFlags, " ")
 }

 ctx.Build(pctx, blueprint.BuildParams{
  Rule:      link,
  Outputs:   []string{aoutFile},
  Inputs:    []string{archiveFile},
  Implicits: append(linkFlagsDeps, goToolchainPhony()),
  Args:      linkArgs,
 })

 g.outputFile = aoutFile

 var validations []string
 if ctx.Config().(BootstrapConfig).RunGoTests() {
  validations = testResultFile
 }

 if !g.skipInstall {
  ctx.Build(pctx, blueprint.BuildParams{
   Rule:        cp,
   Outputs:     []string{g.installPath},
   Inputs:      []string{aoutFile},
   Validations: validations,
   Default:     g.properties.Default,
  })
 }

 blueprint.SetProvider(ctx, BinaryProvider, &BinaryInfo{
  IntermediatePath: g.outputFile,
  InstallPath:      g.installPath,
  TestTargets:      testResultFile,
 })
}

func buildGoPluginLoader(ctx blueprint.ModuleContext, pkgPath, pluginSrc string) bool {
 ret := true

 var pluginPaths []string
 ctx.VisitDirectDepsProxy(func(module blueprint.ModuleProxy) {
  if ctx.OtherModuleDependencyTag(module) == PluginDepTag {
   if info, ok := blueprint.OtherModuleProvider(ctx, module, PackageProvider); ok {
    pluginPaths = append(pluginPaths, info.PkgPath)
   }
  }
 })

 ctx.Build(pctx, blueprint.BuildParams{
  Rule:    pluginGenSrc,
  Outputs: []string{pluginSrc},
  Args: map[string]string{
   "pkg":     pkgPath,
   "plugins": strings.Join(pluginPaths, " "),
  },
 })

 return ret
}

func generateEmbedcfgFile(ctx blueprint.ModuleContext, files []string, srcDir string, embedcfgFile string) {
 embedcfg := struct {
  Patterns map[string][]string
  Files    map[string]string
 }{
  make(map[string][]string, len(files)),
  make(map[string]string, len(files)),
 }

 for _, file := range files {
  embedcfg.Patterns[file] = []string{file}
  embedcfg.Files[file] = filepath.Join(srcDir, file)
 }

 embedcfgData, err := json.Marshal(&embedcfg)
 if err != nil {
  ctx.ModuleErrorf("Failed to marshal embedcfg data: %s", err.Error())
 }

 writeFileRule(ctx, embedcfgFile, string(embedcfgData))
}

func buildGoPackage(ctx blueprint.ModuleContext, pkgRoot string,
 pkgPath string, archiveFile string, srcs []string, genSrcs []string, embedSrcs []string,
 incFlags []string, deps []string) {

 srcDir := moduleSrcDir(ctx)
 srcFiles := pathtools.PrefixPaths(srcs, srcDir)
 srcFiles = append(srcFiles, genSrcs...)

 compileArgs := map[string]string{
  "pkgPath": pkgPath,
 }

 if len(incFlags) > 0 {
  compileArgs["incFlags"] = strings.Join(incFlags, " ")
 }

 if len(embedSrcs) > 0 {
  embedcfgFile := archiveFile + ".embedcfg"
  generateEmbedcfgFile(ctx, embedSrcs, srcDir, embedcfgFile)
  compileArgs["embedFlags"] = "-embedcfg " + embedcfgFile
  deps = append(deps, embedcfgFile)
  deps = append(deps, pathtools.PrefixPaths(embedSrcs, srcDir)...)
 }

 var validations []string

 if ctx.Config().(BootstrapConfig).IsBootstrap() {
  verifySerializers := archiveFile + ".verify_serializers"
  buildVerifySerializers(ctx, verifySerializers, srcs, archiveFile)
  validations = append(validations, verifySerializers)
 }

 ctx.Build(pctx, blueprint.BuildParams{
  Rule:        compile,
  Outputs:     []string{archiveFile},
  Inputs:      srcFiles,
  Implicits:   append(deps, goToolchainPhony()),
  Args:        compileArgs,
  Validations: validations,
 })
}

func buildGoTest(ctx blueprint.ModuleContext, testRoot, testPkgArchive,
 pkgPath string, srcs, genSrcs, testSrcs []string, embedSrcs []string) []string {

 var testDeps []string
 ctx.VisitDirectDepsProxy(func(module blueprint.ModuleProxy) {
  if info, ok := blueprint.OtherModuleProvider(ctx, module, PackageProvider); ok {
   testDeps = append(testDeps, info.TestTargets...)
  }
 })

 if len(testSrcs) == 0 {
  if len(testDeps) > 0 {
   testDependencies := filepath.Join(testRoot, "test.dependencies")
   ctx.Build(pctx, blueprint.BuildParams{
    Rule:        touch,
    Outputs:     []string{testDependencies},
    Validations: testDeps,
   })
   return []string{testDependencies}
  }
  return nil
 }

 srcDir := moduleSrcDir(ctx)
 testFiles := pathtools.PrefixPaths(testSrcs, srcDir)

 mainFile := filepath.Join(testRoot, "test.go")
 testArchive := filepath.Join(testRoot, "test.a")
 testFile := filepath.Join(testRoot, "test")
 testPassed := filepath.Join(testRoot, "test.passed")

 incFlags, deps, linkFlags, linkFlagsDeps, _, _ := collectGoDeps(ctx)

 buildGoPackage(ctx, testRoot, pkgPath, testPkgArchive,
  append(srcs, testSrcs...), genSrcs, embedSrcs, incFlags, deps)

 ctx.Build(pctx, blueprint.BuildParams{
  Rule:    goTestMain,
  Outputs: []string{mainFile},
  Inputs:  testFiles,
  Args: map[string]string{
   "pkg": pkgPath,
  },
 })

 linkFlagsDeps = append([]string{testPkgArchive}, linkFlagsDeps...)
 linkFlags = append([]string{"-L " + testRoot}, linkFlags...)

 ctx.Build(pctx, blueprint.BuildParams{
  Rule:      compile,
  Outputs:   []string{testArchive},
  Inputs:    []string{mainFile},
  Implicits: []string{testPkgArchive, goToolchainPhony()},
  Args: map[string]string{
   "pkgPath":  "main",
   "incFlags": "-I " + testRoot,
  },
 })

 ctx.Build(pctx, blueprint.BuildParams{
  Rule:      link,
  Outputs:   []string{testFile},
  Inputs:    []string{testArchive},
  Implicits: append(linkFlagsDeps, goToolchainPhony()),
  Args: map[string]string{
   "libDirFlags": strings.Join(linkFlags, " "),
  },
 })

 ctx.Build(pctx, blueprint.BuildParams{
  Rule:        test,
  Outputs:     []string{testPassed},
  Inputs:      []string{testFile},
  Validations: testDeps,
  Args: map[string]string{
   "pkg":       pkgPath,
   "pkgSrcDir": filepath.Dir(testFiles[0]),
  },
 })

 return []string{testPassed}
}

var PrimaryBuilderProvider = blueprint.NewMutatorProvider[PrimaryBuilderInfo]("bootstrap_deps")

// @auto-generate: gob
type PrimaryBuilderInfo struct{}

type singleton struct {
}

func newSingletonFactory() func() blueprint.Singleton {
 return func() blueprint.Singleton {
  return &singleton{}
 }
}

func (s *singleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
 // Create the go_toolchain phony rule in a singleton to ensure deterministic
 // Ninja file generation regardless of parallel module evaluation order.
 emitGoToolchainPhony(ctx)

 // Find the module that's marked as the "primary builder", which means it's
 // creating the binary that we'll use to generate the non-bootstrap
 // build.ninja file.
 var primaryBuilders []string
 // blueprintTools contains blueprint go binaries that will be built in StageMain
 var blueprintTools []string
 // blueprintTools contains the test outputs of go tests that can be run in StageMain
 var blueprintTests []string
 // blueprintGoPackages contains all blueprint go packages that can be built in StageMain
 var blueprintGoPackages []string
 ctx.VisitAllModuleProxies(func(module blueprint.ModuleProxy) {
  if ctx.IsPrimaryModule(module) {
   if binaryInfo, ok := blueprint.SingletonModuleProvider(ctx, module, BinaryProvider); ok {
    if binaryInfo.InstallPath != "" {
     blueprintTools = append(blueprintTools, binaryInfo.InstallPath)
    }
    blueprintTests = append(blueprintTests, binaryInfo.TestTargets...)
    if _, ok := blueprint.SingletonModuleProvider(ctx, module, PrimaryBuilderProvider); ok {
     primaryBuilders = append(primaryBuilders, binaryInfo.InstallPath)
    }
   }

   if packageInfo, ok := blueprint.SingletonModuleProvider(ctx, module, PackageProvider); ok {
    blueprintGoPackages = append(blueprintGoPackages, packageInfo.PackageTarget)
    blueprintTests = append(blueprintTests, packageInfo.TestTargets...)
   }
  }
 })

 var primaryBuilderCmdlinePrefix []string
 var primaryBuilderFile string

 if len(primaryBuilders) == 0 {
  ctx.Errorf("no primary builder module present")
  return
 } else if len(primaryBuilders) > 1 {
  ctx.Errorf("multiple primary builder modules present: %q", primaryBuilders)
  return
 } else {
  primaryBuilderFile = primaryBuilders[0]
 }

 ctx.SetOutDir(pctx, "${outDir}")

 for _, subninja := range ctx.Config().(BootstrapConfig).Subninjas() {
  ctx.AddSubninja(subninja)
 }

 for _, i := range ctx.Config().(BootstrapConfig).PrimaryBuilderInvocations() {
  flags := make([]string, 0)
  flags = append(flags, primaryBuilderCmdlinePrefix...)
  flags = append(flags, i.Args...)

  pool := ""
  if i.Console {
   pool = "console"
  }

  envAssignments := ""
  for k, v := range i.Env {
   // NB: This is rife with quoting issues but we don't care because we trust
   // soong_ui to not abuse this facility too much
   envAssignments += k + "=" + v + " "
  }

  // Build the main build.ninja
  ctx.Build(pctx, blueprint.BuildParams{
   Rule:      generateBuildNinja,
   Outputs:   i.Outputs,
   Inputs:    i.Inputs,
   Implicits: i.Implicits,
   OrderOnly: i.OrderOnlyInputs,
   Args: map[string]string{
    "builder": primaryBuilderFile,
    "env":     envAssignments,
    "extra":   strings.Join(flags, " "),
    "pool":    pool,
   },
   Description: i.Description,
  })
 }

 // Add a phony target for building various tools that are part of blueprint
 if len(blueprintTools) > 0 {
  ctx.Build(pctx, blueprint.BuildParams{
   Rule:    blueprint.Phony,
   Outputs: []string{"blueprint_tools"},
   Inputs:  blueprintTools,
  })
 }

 // Add a phony target for running various tests that are part of blueprint
 ctx.Build(pctx, blueprint.BuildParams{
  Rule:    blueprint.Phony,
  Outputs: []string{"blueprint_tests"},
  Inputs:  blueprintTests,
 })

 // Add a phony target for running go tests
 ctx.Build(pctx, blueprint.BuildParams{
  Rule:    blueprint.Phony,
  Outputs: []string{"blueprint_go_packages"},
  Inputs:  blueprintGoPackages,
 })
}

func (s *singleton) IncrementalSupported() bool {
 return false
}

// packageRoot returns the module-specific package root directory path.  This
// directory is where the final package .a files are output and where dependant
// modules search for this package via -I arguments.
func packageRoot(ctx blueprint.ModuleContext) string {
 toolDir := ctx.Config().(BootstrapConfig).HostToolDir()
 return filepath.Join(toolDir, "go", ctx.ModuleName(), ctx.ModuleSubDir(), "pkg")
}

// testRoot returns the module-specific package root directory path used for
// building tests. The .a files generated here will include everything from
// packageRoot, plus the test-only code.
func testRoot(ctx blueprint.ModuleContext) string {
 toolDir := ctx.Config().(BootstrapConfig).HostToolDir()
 return filepath.Join(toolDir, "go", ctx.ModuleName(), ctx.ModuleSubDir(), "test")
}

// moduleSrcDir returns the path of the directory that all source file paths are
// specified relative to.
func moduleSrcDir(ctx blueprint.ModuleContext) string {
 return ctx.ModuleDir()
}

// moduleGenSrcDir returns the module-specific generated sources path.
func moduleGenSrcDir(ctx blueprint.ModuleContext) string {
 toolDir := ctx.Config().(BootstrapConfig).HostToolDir()
 return filepath.Join(toolDir, "go", ctx.ModuleName(), ctx.ModuleSubDir(), "gen")
}

func goToolchainPhony() string {
 return goToolchainTarget
}

func emitGoToolchainPhony(ctx blueprint.SingletonContext) {
 goroot := goRoot()
 osArch := runtime.GOOS + "_" + runtime.GOARCH

 // Exclude Go race detector precompiled objects (e.g. linux_amd64_race)
 // which are not needed for standard bootstrap builds. We also exclude
 // pkg/tool here since specific rules add the exact binary as an implicit dep.
 //
 // The expected structure of GOROOT/pkg is:
 //   include/        <-- Headers
 //   linux_amd64/    <-- Standard library .a files
 //   linux_amd64_race/ (Excluded)
 //   tool/           (Excluded)
 pathsToGlob := []string{
  "pkg/include/**/*",
  "pkg/" + osArch + "/**/*",
 }

 var inputs []string
 for _, p := range pathsToGlob {
  files, err := ctx.GlobWithDeps(filepath.Join(goroot, p), nil)
  if err != nil {
   panic(fmt.Errorf("Failed to glob GOROOT %q subpath %q: %s", goroot, p, err))
  }
  for _, f := range files {
   if !strings.HasSuffix(f, "/") {
    inputs = append(inputs, f)
   }
  }
 }

 ctx.Build(pctx, blueprint.BuildParams{
  Rule:    blueprint.Phony,
  Outputs: []string{goToolchainTarget},
  Inputs:  inputs,
 })
}

[Dauer der Verarbeitung: 0.22 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