Invoke queryview from the bootstrap Ninja file.

It used to be invoked from out/soong/build.ninja, which required two
soong_build invocations one after the other (ne to generate
out/soong/build.ninja, one to generate the queryview workspace). This
was slower and required some shell-quoted-in-ninja-quoted-in-Go .

Test: Presubmits.
Change-Id: Idda79c067606663b66e9f94626fa24f3b5af4114
This commit is contained in:
Lukacs T. Berki
2021-09-06 17:08:02 +02:00
parent a1b9372ef7
commit 3a82169a55
6 changed files with 70 additions and 119 deletions

View File

@@ -66,7 +66,6 @@ bootstrap_go_package {
"prebuilt.go",
"prebuilt_build_tool.go",
"proto.go",
"queryview.go",
"register.go",
"rule_builder.go",
"sandbox.go",

View File

@@ -1,112 +0,0 @@
// Copyright 2020 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
import (
"fmt"
"os"
"strings"
"github.com/google/blueprint"
)
// The Bazel QueryView singleton is responsible for generating the Ninja actions
// for calling the soong_build primary builder in the main build.ninja file.
func init() {
RegisterSingletonType("bazel_queryview", BazelQueryViewSingleton)
}
// BazelQueryViewSingleton is the singleton responsible for registering the
// soong_build build statement that will convert the Soong module graph after
// applying *all* mutators, enabing the feature to query the final state of the
// Soong graph. This mode is meant for querying the build graph state, and not meant
// for generating BUILD files to be checked in.
func BazelQueryViewSingleton() Singleton {
return &bazelQueryViewSingleton{}
}
// BazelConverterSingleton is the singleton responsible for registering the soong_build
// build statement that will convert the Soong module graph by applying an alternate
// pipeline of mutators, with the goal of reaching semantic equivalence between the original
// Blueprint and final BUILD files. Using this mode, the goal is to be able to
// build with these BUILD files directly in the source tree.
func BazelConverterSingleton() Singleton {
return &bazelConverterSingleton{}
}
type bazelQueryViewSingleton struct{}
type bazelConverterSingleton struct{}
func generateBuildActionsForBazelConversion(ctx SingletonContext, converterMode bool) {
name := "queryview"
descriptionTemplate := "[EXPERIMENTAL, PRE-PRODUCTION] Creating the Bazel QueryView workspace with %s at $outDir"
// Create a build and rule statement, using the Bazel QueryView's WORKSPACE
// file as the output file marker.
var deps Paths
moduleListFilePath := pathForBuildToolDep(ctx, ctx.Config().moduleListFile)
deps = append(deps, moduleListFilePath)
deps = append(deps, pathForBuildToolDep(ctx, ctx.Config().ProductVariablesFileName))
bazelQueryViewDirectory := PathForOutput(ctx, name)
bazelQueryViewWorkspaceFile := bazelQueryViewDirectory.Join(ctx, "WORKSPACE")
primaryBuilder := primaryBuilderPath(ctx)
bazelQueryView := ctx.Rule(pctx, "bazelQueryView",
blueprint.RuleParams{
Command: fmt.Sprintf(
`rm -rf "${outDir}/"* && `+
`mkdir -p "${outDir}" && `+
`echo WORKSPACE: $$(cat "%s") > "${outDir}/.queryview-depfile.d" && `+
`BUILDER="%s" && `+
`echo BUILDER=$$BUILDER && `+
`cd "$$(dirname "$$BUILDER")" && `+
`echo PWD=$$PWD && `+
`ABSBUILDER="$$PWD/$$(basename "$$BUILDER")" && `+
`echo ABSBUILDER=$$ABSBUILDER && `+
`cd / && `+
`env -i "$$ABSBUILDER" --bazel_queryview_dir "${outDir}" "%s"`,
moduleListFilePath.String(), // Use the contents of Android.bp.list as the depfile.
primaryBuilder.String(),
strings.Join(os.Args[1:], "\" \""),
),
CommandDeps: []string{primaryBuilder.String()},
Description: fmt.Sprintf(
descriptionTemplate,
primaryBuilder.Base()),
Deps: blueprint.DepsGCC,
Depfile: "${outDir}/.queryview-depfile.d",
},
"outDir")
ctx.Build(pctx, BuildParams{
Rule: bazelQueryView,
Output: bazelQueryViewWorkspaceFile,
Inputs: deps,
Args: map[string]string{
"outDir": bazelQueryViewDirectory.String(),
},
})
// Add a phony target for generating the workspace
ctx.Phony(name, bazelQueryViewWorkspaceFile)
}
func (c *bazelQueryViewSingleton) GenerateBuildActions(ctx SingletonContext) {
generateBuildActionsForBazelConversion(ctx, false)
}
func (c *bazelConverterSingleton) GenerateBuildActions(ctx SingletonContext) {
generateBuildActionsForBazelConversion(ctx, true)
}

View File

@@ -156,13 +156,15 @@ func runMixedModeBuild(configuration android.Config, firstCtx *android.Context,
}
// Run the code-generation phase to convert BazelTargetModules to BUILD files.
func runQueryView(configuration android.Config, ctx *android.Context) {
func runQueryView(queryviewDir, queryviewMarker string, configuration android.Config, ctx *android.Context) {
codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.QueryView)
absoluteQueryViewDir := shared.JoinPath(topDir, bazelQueryViewDir)
absoluteQueryViewDir := shared.JoinPath(topDir, queryviewDir)
if err := createBazelQueryView(codegenContext, absoluteQueryViewDir); err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
}
touch(shared.JoinPath(topDir, queryviewMarker))
}
func runSoongDocs(configuration android.Config) {
@@ -244,8 +246,10 @@ func doChosenActivity(configuration android.Config, extraNinjaDeps []string) str
// Convert the Soong module graph into Bazel BUILD files.
if generateQueryView {
runQueryView(configuration, ctx)
return cmdlineArgs.OutFile // TODO: This is a lie
queryviewMarkerFile := bazelQueryViewDir + ".marker"
runQueryView(bazelQueryViewDir, queryviewMarkerFile, configuration, ctx)
writeDepFile(queryviewMarkerFile, ninjaDeps)
return queryviewMarkerFile
} else if moduleGraphFile != "" {
writeJsonModuleGraph(ctx, moduleGraphFile)
writeDepFile(moduleGraphFile, ninjaDeps)

View File

@@ -785,6 +785,28 @@ function test_bp2build_back_and_forth_null_build {
fi
}
function test_queryview_smoke() {
setup
run_soong queryview
[[ -e out/soong/queryview/WORKSPACE ]] || fail "queryview WORKSPACE file not created"
}
function test_queryview_null_build() {
setup
run_soong queryview
local output_mtime1=$(stat -c "%y" out/soong/queryview.marker)
run_soong queryview
local output_mtime2=$(stat -c "%y" out/soong/queryview.marker)
if [[ "$output_mtime1" != "$output_mtime2" ]]; then
fail "Queryview marker file changed on null build"
fi
}
test_smoke
test_null_build
test_null_build_after_docs
@@ -801,6 +823,8 @@ test_multiple_soong_build_modes
test_dump_json_module_graph
test_json_module_graph_back_and_forth_null_build
test_write_to_source_tree
test_queryview_smoke
test_queryview_null_build
test_bp2build_smoke
test_bp2build_generates_marker_file
test_bp2build_null_build

View File

@@ -49,6 +49,7 @@ type configImpl struct {
dist bool
jsonModuleGraph bool
bp2build bool
queryview bool
skipConfig bool
skipKati bool
skipKatiNinja bool
@@ -643,6 +644,8 @@ func (c *configImpl) parseArgs(ctx Context, args []string) {
c.jsonModuleGraph = true
} else if arg == "bp2build" {
c.bp2build = true
} else if arg == "queryview" {
c.queryview = true
} else {
if arg == "checkbuild" {
c.checkbuild = true
@@ -720,7 +723,7 @@ func (c *configImpl) SoongBuildInvocationNeeded() bool {
return true
}
if !c.JsonModuleGraph() && !c.Bp2Build() {
if !c.JsonModuleGraph() && !c.Bp2Build() && !c.Queryview() {
// Command line was empty, the default Ninja target is built
return true
}
@@ -785,6 +788,10 @@ func (c *configImpl) Bp2BuildMarkerFile() string {
return shared.JoinPath(c.SoongOutDir(), ".bootstrap/bp2build_workspace_marker")
}
func (c *configImpl) QueryviewMarkerFile() string {
return shared.JoinPath(c.SoongOutDir(), "queryview.marker")
}
func (c *configImpl) ModuleGraphFile() string {
return shared.JoinPath(c.SoongOutDir(), "module-graph.json")
}
@@ -822,6 +829,10 @@ func (c *configImpl) Bp2Build() bool {
return c.bp2build
}
func (c *configImpl) Queryview() bool {
return c.queryview
}
func (c *configImpl) IsVerbose() bool {
return c.verbose
}

View File

@@ -142,6 +142,7 @@ func bootstrapBlueprint(ctx Context, config Config) {
bootstrapGlobFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build-globs.ninja")
bp2buildGlobFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build-globs.bp2build.ninja")
queryviewGlobFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build-globs.queryview.ninja")
moduleGraphGlobFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build-globs.modulegraph.ninja")
// The glob .ninja files are subninja'd. However, they are generated during
@@ -149,6 +150,9 @@ func bootstrapBlueprint(ctx Context, config Config) {
// fail on clean builds
writeEmptyGlobFile(ctx, bootstrapGlobFile)
writeEmptyGlobFile(ctx, bp2buildGlobFile)
writeEmptyGlobFile(ctx, queryviewGlobFile)
writeEmptyGlobFile(ctx, moduleGraphGlobFile)
bootstrapDepFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja.d")
args.RunGoTests = !config.skipSoongTests
@@ -160,7 +164,7 @@ func bootstrapBlueprint(ctx Context, config Config) {
// The primary builder (aka soong_build) will use bootstrapGlobFile as the globFile to generate build.ninja(.d)
// Building soong_build does not require a glob file
// Using "" instead of "<soong_build_glob>.ninja" will ensure that an unused glob file is not written to out/soong/.bootstrap during StagePrimary
args.Subninjas = []string{bootstrapGlobFile, bp2buildGlobFile}
args.Subninjas = []string{bootstrapGlobFile, bp2buildGlobFile, moduleGraphGlobFile, queryviewGlobFile}
args.EmptyNinjaFile = config.EmptyNinjaFile()
args.DelveListen = os.Getenv("SOONG_DELVE")
@@ -206,6 +210,22 @@ func bootstrapBlueprint(ctx Context, config Config) {
Args: bp2buildArgs,
}
queryviewArgs := []string{
"--bazel_queryview_dir", filepath.Join(config.SoongOutDir(), "queryview"),
"--globListDir", "queryview",
"--globFile", queryviewGlobFile,
}
queryviewArgs = append(queryviewArgs, commonArgs...)
queryviewArgs = append(queryviewArgs, environmentArgs(config, ".queryview")...)
queryviewArgs = append(queryviewArgs, "Android.bp")
queryviewInvocation := bootstrap.PrimaryBuilderInvocation{
Inputs: []string{"Android.bp"},
Outputs: []string{config.QueryviewMarkerFile()},
Args: queryviewArgs,
}
moduleGraphArgs := []string{
"--module_graph_file", config.ModuleGraphFile(),
"--globListDir", "modulegraph",
@@ -226,6 +246,7 @@ func bootstrapBlueprint(ctx Context, config Config) {
bp2buildInvocation,
mainSoongBuildInvocation,
moduleGraphInvocation,
queryviewInvocation,
}
blueprintCtx := blueprint.NewContext()
@@ -361,6 +382,10 @@ func runSoong(ctx Context, config Config) {
targets = append(targets, config.Bp2BuildMarkerFile())
}
if config.Queryview() {
targets = append(targets, config.QueryviewMarkerFile())
}
if config.SoongBuildInvocationNeeded() {
// This build generates <builddir>/build.ninja, which is used later by build/soong/ui/build/build.go#Build().
targets = append(targets, config.MainNinjaFile())