Add direct deps on glob result files

n2 (a reimplemntation of ninja) adds a check that depfiles only add
dependencies on source files, not generated files, because generated
files are not guaranteed to exist before an action runs if there isn't
an explicit dependency between the two.

This is the case for our glob result files. However, we can rework the
build so that they're directly depended on instead of using a depfile.

Bug: 318434287
Test: rm -rf out && m nothing && m nothing
Change-Id: I513fa5536136e6bf19c347710f0722d696199612
This commit is contained in:
Cole Faust
2024-01-02 17:02:52 -08:00
parent ad579a8c71
commit 8c0b11ef79
2 changed files with 40 additions and 18 deletions

View File

@@ -28,6 +28,7 @@ import (
"android/soong/android/allowlists"
"android/soong/bp2build"
"android/soong/shared"
"github.com/google/blueprint"
"github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/deptools"
@@ -196,7 +197,7 @@ func writeJsonModuleGraphAndActions(ctx *android.Context, cmdArgs android.CmdArg
ctx.Context.PrintJSONGraphAndActions(graphFile, actionsFile)
}
func writeBuildGlobsNinjaFile(ctx *android.Context) []string {
func writeBuildGlobsNinjaFile(ctx *android.Context) {
ctx.EventHandler.Begin("globs_ninja_file")
defer ctx.EventHandler.End("globs_ninja_file")
@@ -208,7 +209,6 @@ func writeBuildGlobsNinjaFile(ctx *android.Context) []string {
SrcDir: ctx.SrcDir(),
}, ctx.Config())
maybeQuit(err, "")
return bootstrap.GlobFileListFiles(globDir)
}
func writeDepFile(outputFile string, eventHandler *metrics.EventHandler, ninjaDeps []string) {
@@ -238,8 +238,7 @@ func runSoongOnlyBuild(ctx *android.Context, extraNinjaDeps []string) string {
maybeQuit(err, "")
ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
globListFiles := writeBuildGlobsNinjaFile(ctx)
ninjaDeps = append(ninjaDeps, globListFiles...)
writeBuildGlobsNinjaFile(ctx)
// Convert the Soong module graph into Bazel BUILD files.
switch ctx.Config().BuildMode {

View File

@@ -36,6 +36,7 @@ import (
"github.com/google/blueprint"
"github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/microfactory"
"github.com/google/blueprint/pathtools"
"google.golang.org/protobuf/proto"
)
@@ -181,7 +182,15 @@ func getGlobPathName(config Config) string {
return globPathName
}
func (pb PrimaryBuilderFactory) primaryBuilderInvocation() bootstrap.PrimaryBuilderInvocation {
func getGlobPathNameFromPrimaryBuilderFactory(config Config, pb PrimaryBuilderFactory) string {
if pb.name == soongBuildTag {
// Glob path for soong build would be separated per product target
return getGlobPathName(config)
}
return pb.name
}
func (pb PrimaryBuilderFactory) primaryBuilderInvocation(config Config) bootstrap.PrimaryBuilderInvocation {
commonArgs := make([]string, 0, 0)
if !pb.config.skipSoongTests {
@@ -215,11 +224,7 @@ func (pb PrimaryBuilderFactory) primaryBuilderInvocation() bootstrap.PrimaryBuil
var allArgs []string
allArgs = append(allArgs, pb.specificArgs...)
globPathName := pb.name
// Glob path for soong build would be separated per product target
if pb.name == soongBuildTag {
globPathName = getGlobPathName(pb.config)
}
globPathName := getGlobPathNameFromPrimaryBuilderFactory(config, pb)
allArgs = append(allArgs,
"--globListDir", globPathName,
"--globFile", pb.config.NamedGlobFile(globPathName))
@@ -234,8 +239,11 @@ func (pb PrimaryBuilderFactory) primaryBuilderInvocation() bootstrap.PrimaryBuil
}
allArgs = append(allArgs, "Android.bp")
globfiles := bootstrap.GlobFileListFiles(bootstrap.GlobDirectory(config.SoongOutDir(), globPathName))
return bootstrap.PrimaryBuilderInvocation{
Inputs: []string{"Android.bp"},
Implicits: globfiles,
Outputs: []string{pb.output},
Args: allArgs,
Description: pb.description,
@@ -376,17 +384,10 @@ func bootstrapBlueprint(ctx Context, config Config) {
if debuggedInvocations[pbf.name] {
pbf.debugPort = delvePort
}
pbi := pbf.primaryBuilderInvocation()
pbi := pbf.primaryBuilderInvocation(config)
invocations = append(invocations, pbi)
}
// The glob .ninja files are subninja'd. However, they are generated during
// the build itself so we write an empty file if the file does not exist yet
// so that the subninja doesn't fail on clean builds
for _, globFile := range bootstrapGlobFileList(config) {
writeEmptyFile(ctx, globFile)
}
blueprintArgs := bootstrap.Args{
ModuleListFile: filepath.Join(config.FileListDir(), "Android.bp.list"),
OutFile: shared.JoinPath(config.SoongOutDir(), "bootstrap.ninja"),
@@ -408,6 +409,28 @@ func bootstrapBlueprint(ctx Context, config Config) {
primaryBuilderInvocations: invocations,
}
// The glob ninja files are generated during the main build phase. However, the
// primary buildifer invocation depends on all of its glob files, even before
// it's been run. Generate a "empty" glob ninja file on the first run,
// so that the files can be there to satisfy the dependency.
for _, pb := range pbfs {
globPathName := getGlobPathNameFromPrimaryBuilderFactory(config, pb)
globNinjaFile := config.NamedGlobFile(globPathName)
if _, err := os.Stat(globNinjaFile); os.IsNotExist(err) {
err := bootstrap.WriteBuildGlobsNinjaFile(&bootstrap.GlobSingleton{
GlobLister: func() pathtools.MultipleGlobResults { return nil },
GlobFile: globNinjaFile,
GlobDir: bootstrap.GlobDirectory(config.SoongOutDir(), globPathName),
SrcDir: ".",
}, blueprintConfig)
if err != nil {
ctx.Fatal(err)
}
} else if err != nil {
ctx.Fatal(err)
}
}
// since `bootstrap.ninja` is regenerated unconditionally, we ignore the deps, i.e. little
// reason to write a `bootstrap.ninja.d` file
_, err := bootstrap.RunBlueprint(blueprintArgs, bootstrap.DoEverything, blueprintCtx, blueprintConfig)