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:
@@ -66,7 +66,6 @@ bootstrap_go_package {
|
||||
"prebuilt.go",
|
||||
"prebuilt_build_tool.go",
|
||||
"proto.go",
|
||||
"queryview.go",
|
||||
"register.go",
|
||||
"rule_builder.go",
|
||||
"sandbox.go",
|
||||
|
@@ -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)
|
||||
}
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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())
|
||||
|
Reference in New Issue
Block a user