2020-09-29 08:23:17 +02:00
|
|
|
// 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 (
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2020-10-13 05:44:08 +02:00
|
|
|
"io/ioutil"
|
2020-09-29 08:23:17 +02:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
2020-10-13 05:44:08 +02:00
|
|
|
"path/filepath"
|
2020-09-29 08:23:17 +02:00
|
|
|
"runtime"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
2020-10-13 05:44:08 +02:00
|
|
|
|
2021-03-11 17:08:46 +01:00
|
|
|
"android/soong/bazel/cquery"
|
2021-03-03 22:40:52 +01:00
|
|
|
|
2020-12-12 07:24:26 +01:00
|
|
|
"android/soong/bazel"
|
|
|
|
"android/soong/shared"
|
2020-09-29 08:23:17 +02:00
|
|
|
)
|
|
|
|
|
2021-04-02 19:37:39 +02:00
|
|
|
type cqueryRequest interface {
|
|
|
|
// Name returns a string name for this request type. Such request type names must be unique,
|
|
|
|
// and must only consist of alphanumeric characters.
|
|
|
|
Name() string
|
|
|
|
|
|
|
|
// StarlarkFunctionBody returns a starlark function body to process this request type.
|
|
|
|
// The returned string is the body of a Starlark function which obtains
|
|
|
|
// all request-relevant information about a target and returns a string containing
|
|
|
|
// this information.
|
|
|
|
// The function should have the following properties:
|
|
|
|
// - `target` is the only parameter to this function (a configured target).
|
|
|
|
// - The return value must be a string.
|
|
|
|
// - The function body should not be indented outside of its own scope.
|
|
|
|
StarlarkFunctionBody() string
|
|
|
|
}
|
|
|
|
|
2020-09-29 08:23:17 +02:00
|
|
|
// Map key to describe bazel cquery requests.
|
|
|
|
type cqueryKey struct {
|
2020-10-23 22:48:08 +02:00
|
|
|
label string
|
2021-04-02 19:37:39 +02:00
|
|
|
requestType cqueryRequest
|
2021-02-22 22:13:50 +01:00
|
|
|
archType ArchType
|
2020-09-29 08:23:17 +02:00
|
|
|
}
|
|
|
|
|
2021-08-11 18:46:13 +02:00
|
|
|
// bazelHandler is the interface for a helper object related to deferring to Bazel for
|
|
|
|
// processing a module (during Bazel mixed builds). Individual module types should define
|
|
|
|
// their own bazel handler if they support deferring to Bazel.
|
|
|
|
type BazelHandler interface {
|
|
|
|
// Issue query to Bazel to retrieve information about Bazel's view of the current module.
|
|
|
|
// If Bazel returns this information, set module properties on the current module to reflect
|
|
|
|
// the returned information.
|
|
|
|
// Returns true if information was available from Bazel, false if bazel invocation still needs to occur.
|
|
|
|
GenerateBazelBuildActions(ctx ModuleContext, label string) bool
|
|
|
|
}
|
|
|
|
|
2020-09-29 08:23:17 +02:00
|
|
|
type BazelContext interface {
|
|
|
|
// The below methods involve queuing cquery requests to be later invoked
|
|
|
|
// by bazel. If any of these methods return (_, false), then the request
|
|
|
|
// has been queued to be run later.
|
|
|
|
|
|
|
|
// Returns result files built by building the given bazel target label.
|
2021-03-11 17:08:46 +01:00
|
|
|
GetOutputFiles(label string, archType ArchType) ([]string, bool)
|
2021-02-22 22:13:50 +01:00
|
|
|
|
2021-03-11 17:08:46 +01:00
|
|
|
// TODO(cparsons): Other cquery-related methods should be added here.
|
|
|
|
// Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
|
2021-04-09 22:17:05 +02:00
|
|
|
GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error)
|
2021-04-03 00:47:09 +02:00
|
|
|
|
2021-08-11 18:48:30 +02:00
|
|
|
// Returns the executable binary resultant from building together the python sources
|
|
|
|
GetPythonBinary(label string, archType ArchType) (string, bool)
|
|
|
|
|
2020-09-29 08:23:17 +02:00
|
|
|
// ** End cquery methods
|
|
|
|
|
|
|
|
// Issues commands to Bazel to receive results for all cquery requests
|
|
|
|
// queued in the BazelContext.
|
|
|
|
InvokeBazel() error
|
|
|
|
|
|
|
|
// Returns true if bazel is enabled for the given configuration.
|
|
|
|
BazelEnabled() bool
|
2020-12-10 23:19:18 +01:00
|
|
|
|
|
|
|
// Returns the bazel output base (the root directory for all bazel intermediate outputs).
|
|
|
|
OutputBase() string
|
|
|
|
|
|
|
|
// Returns build statements which should get registered to reflect Bazel's outputs.
|
|
|
|
BuildStatementsToRegister() []bazel.BuildStatement
|
2020-09-29 08:23:17 +02:00
|
|
|
}
|
|
|
|
|
2021-04-08 15:47:28 +02:00
|
|
|
type bazelRunner interface {
|
|
|
|
issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) (string, string, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
type bazelPaths struct {
|
2020-09-29 08:23:17 +02:00
|
|
|
homeDir string
|
|
|
|
bazelPath string
|
|
|
|
outputBase string
|
|
|
|
workspaceDir string
|
2021-08-26 15:07:24 +02:00
|
|
|
soongOutDir string
|
2020-12-12 07:24:26 +01:00
|
|
|
metricsDir string
|
2021-04-08 15:47:28 +02:00
|
|
|
}
|
2020-09-29 08:23:17 +02:00
|
|
|
|
2021-04-08 15:47:28 +02:00
|
|
|
// A context object which tracks queued requests that need to be made to Bazel,
|
|
|
|
// and their results after the requests have been made.
|
|
|
|
type bazelContext struct {
|
|
|
|
bazelRunner
|
|
|
|
paths *bazelPaths
|
2020-09-29 08:23:17 +02:00
|
|
|
requests map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel
|
|
|
|
requestMutex sync.Mutex // requests can be written in parallel
|
|
|
|
|
|
|
|
results map[cqueryKey]string // Results of cquery requests after Bazel invocations
|
2020-12-10 23:19:18 +01:00
|
|
|
|
|
|
|
// Build statements which should get registered to reflect Bazel's outputs.
|
|
|
|
buildStatements []bazel.BuildStatement
|
2020-09-29 08:23:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ BazelContext = &bazelContext{}
|
|
|
|
|
|
|
|
// A bazel context to use when Bazel is disabled.
|
|
|
|
type noopBazelContext struct{}
|
|
|
|
|
|
|
|
var _ BazelContext = noopBazelContext{}
|
|
|
|
|
|
|
|
// A bazel context to use for tests.
|
|
|
|
type MockBazelContext struct {
|
2021-04-08 02:25:21 +02:00
|
|
|
OutputBaseDir string
|
|
|
|
|
2021-08-11 18:48:30 +02:00
|
|
|
LabelToOutputFiles map[string][]string
|
|
|
|
LabelToCcInfo map[string]cquery.CcInfo
|
|
|
|
LabelToPythonBinary map[string]string
|
2020-09-29 08:23:17 +02:00
|
|
|
}
|
|
|
|
|
2021-03-11 17:08:46 +01:00
|
|
|
func (m MockBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
|
2021-04-08 02:25:21 +02:00
|
|
|
result, ok := m.LabelToOutputFiles[label]
|
2021-02-22 22:13:50 +01:00
|
|
|
return result, ok
|
|
|
|
}
|
|
|
|
|
2021-04-09 22:17:05 +02:00
|
|
|
func (m MockBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
|
2021-04-09 20:07:00 +02:00
|
|
|
result, ok := m.LabelToCcInfo[label]
|
2021-04-09 22:17:05 +02:00
|
|
|
return result, ok, nil
|
2021-04-03 00:47:09 +02:00
|
|
|
}
|
|
|
|
|
2021-08-11 18:48:30 +02:00
|
|
|
func (m MockBazelContext) GetPythonBinary(label string, archType ArchType) (string, bool) {
|
|
|
|
result, ok := m.LabelToPythonBinary[label]
|
|
|
|
return result, ok
|
|
|
|
}
|
|
|
|
|
2020-09-29 08:23:17 +02:00
|
|
|
func (m MockBazelContext) InvokeBazel() error {
|
|
|
|
panic("unimplemented")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m MockBazelContext) BazelEnabled() bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2021-04-08 02:25:21 +02:00
|
|
|
func (m MockBazelContext) OutputBase() string { return m.OutputBaseDir }
|
2020-12-10 23:19:18 +01:00
|
|
|
|
|
|
|
func (m MockBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
|
|
|
|
return []bazel.BuildStatement{}
|
|
|
|
}
|
|
|
|
|
2020-09-29 08:23:17 +02:00
|
|
|
var _ BazelContext = MockBazelContext{}
|
|
|
|
|
2021-03-11 17:08:46 +01:00
|
|
|
func (bazelCtx *bazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
|
|
|
|
rawString, ok := bazelCtx.cquery(label, cquery.GetOutputFiles, archType)
|
|
|
|
var ret []string
|
2021-02-22 22:13:50 +01:00
|
|
|
if ok {
|
2021-03-11 17:08:46 +01:00
|
|
|
bazelOutput := strings.TrimSpace(rawString)
|
2021-04-02 19:37:39 +02:00
|
|
|
ret = cquery.GetOutputFiles.ParseResult(bazelOutput)
|
2021-02-22 22:13:50 +01:00
|
|
|
}
|
2021-03-11 17:08:46 +01:00
|
|
|
return ret, ok
|
2021-02-22 22:13:50 +01:00
|
|
|
}
|
|
|
|
|
2021-04-09 22:17:05 +02:00
|
|
|
func (bazelCtx *bazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
|
2021-04-09 20:07:00 +02:00
|
|
|
result, ok := bazelCtx.cquery(label, cquery.GetCcInfo, archType)
|
2021-04-03 00:47:09 +02:00
|
|
|
if !ok {
|
2021-04-09 22:17:05 +02:00
|
|
|
return cquery.CcInfo{}, ok, nil
|
2021-04-03 00:47:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bazelOutput := strings.TrimSpace(result)
|
2021-04-09 22:17:05 +02:00
|
|
|
ret, err := cquery.GetCcInfo.ParseResult(bazelOutput)
|
|
|
|
return ret, ok, err
|
2021-04-03 00:47:09 +02:00
|
|
|
}
|
|
|
|
|
2021-08-11 18:48:30 +02:00
|
|
|
func (bazelCtx *bazelContext) GetPythonBinary(label string, archType ArchType) (string, bool) {
|
|
|
|
rawString, ok := bazelCtx.cquery(label, cquery.GetPythonBinary, archType)
|
|
|
|
var ret string
|
|
|
|
if ok {
|
|
|
|
bazelOutput := strings.TrimSpace(rawString)
|
|
|
|
ret = cquery.GetPythonBinary.ParseResult(bazelOutput)
|
|
|
|
}
|
|
|
|
return ret, ok
|
|
|
|
}
|
|
|
|
|
2021-03-11 17:08:46 +01:00
|
|
|
func (n noopBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
|
2021-02-22 22:13:50 +01:00
|
|
|
panic("unimplemented")
|
|
|
|
}
|
|
|
|
|
2021-04-09 22:17:05 +02:00
|
|
|
func (n noopBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
|
2021-03-10 02:43:32 +01:00
|
|
|
panic("unimplemented")
|
|
|
|
}
|
|
|
|
|
2021-08-11 18:48:30 +02:00
|
|
|
func (n noopBazelContext) GetPythonBinary(label string, archType ArchType) (string, bool) {
|
|
|
|
panic("unimplemented")
|
|
|
|
}
|
|
|
|
|
2021-04-03 00:47:09 +02:00
|
|
|
func (n noopBazelContext) GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool) {
|
|
|
|
panic("unimplemented")
|
|
|
|
}
|
|
|
|
|
2020-09-29 08:23:17 +02:00
|
|
|
func (n noopBazelContext) InvokeBazel() error {
|
|
|
|
panic("unimplemented")
|
|
|
|
}
|
|
|
|
|
2020-12-10 23:19:18 +01:00
|
|
|
func (m noopBazelContext) OutputBase() string {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2020-09-29 08:23:17 +02:00
|
|
|
func (n noopBazelContext) BazelEnabled() bool {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-12-10 23:19:18 +01:00
|
|
|
func (m noopBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
|
|
|
|
return []bazel.BuildStatement{}
|
|
|
|
}
|
|
|
|
|
2020-09-29 08:23:17 +02:00
|
|
|
func NewBazelContext(c *config) (BazelContext, error) {
|
2020-10-27 23:59:25 +01:00
|
|
|
// TODO(cparsons): Assess USE_BAZEL=1 instead once "mixed Soong/Bazel builds"
|
|
|
|
// are production ready.
|
2021-06-17 09:02:15 +02:00
|
|
|
if !c.IsEnvTrue("USE_BAZEL_ANALYSIS") {
|
2020-09-29 08:23:17 +02:00
|
|
|
return noopBazelContext{}, nil
|
|
|
|
}
|
|
|
|
|
2021-04-08 15:47:28 +02:00
|
|
|
p, err := bazelPathsFromConfig(c)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &bazelContext{
|
|
|
|
bazelRunner: &builtinBazelRunner{},
|
|
|
|
paths: p,
|
|
|
|
requests: make(map[cqueryKey]bool),
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func bazelPathsFromConfig(c *config) (*bazelPaths, error) {
|
|
|
|
p := bazelPaths{
|
2021-08-26 15:07:24 +02:00
|
|
|
soongOutDir: c.soongOutDir,
|
2021-04-08 15:47:28 +02:00
|
|
|
}
|
2020-09-29 08:23:17 +02:00
|
|
|
missingEnvVars := []string{}
|
|
|
|
if len(c.Getenv("BAZEL_HOME")) > 1 {
|
2021-04-08 15:47:28 +02:00
|
|
|
p.homeDir = c.Getenv("BAZEL_HOME")
|
2020-09-29 08:23:17 +02:00
|
|
|
} else {
|
|
|
|
missingEnvVars = append(missingEnvVars, "BAZEL_HOME")
|
|
|
|
}
|
|
|
|
if len(c.Getenv("BAZEL_PATH")) > 1 {
|
2021-04-08 15:47:28 +02:00
|
|
|
p.bazelPath = c.Getenv("BAZEL_PATH")
|
2020-09-29 08:23:17 +02:00
|
|
|
} else {
|
|
|
|
missingEnvVars = append(missingEnvVars, "BAZEL_PATH")
|
|
|
|
}
|
|
|
|
if len(c.Getenv("BAZEL_OUTPUT_BASE")) > 1 {
|
2021-04-08 15:47:28 +02:00
|
|
|
p.outputBase = c.Getenv("BAZEL_OUTPUT_BASE")
|
2020-09-29 08:23:17 +02:00
|
|
|
} else {
|
|
|
|
missingEnvVars = append(missingEnvVars, "BAZEL_OUTPUT_BASE")
|
|
|
|
}
|
|
|
|
if len(c.Getenv("BAZEL_WORKSPACE")) > 1 {
|
2021-04-08 15:47:28 +02:00
|
|
|
p.workspaceDir = c.Getenv("BAZEL_WORKSPACE")
|
2020-09-29 08:23:17 +02:00
|
|
|
} else {
|
|
|
|
missingEnvVars = append(missingEnvVars, "BAZEL_WORKSPACE")
|
|
|
|
}
|
2020-12-12 07:24:26 +01:00
|
|
|
if len(c.Getenv("BAZEL_METRICS_DIR")) > 1 {
|
2021-04-08 15:47:28 +02:00
|
|
|
p.metricsDir = c.Getenv("BAZEL_METRICS_DIR")
|
2020-12-12 07:24:26 +01:00
|
|
|
} else {
|
|
|
|
missingEnvVars = append(missingEnvVars, "BAZEL_METRICS_DIR")
|
|
|
|
}
|
2020-09-29 08:23:17 +02:00
|
|
|
if len(missingEnvVars) > 0 {
|
|
|
|
return nil, errors.New(fmt.Sprintf("missing required env vars to use bazel: %s", missingEnvVars))
|
|
|
|
} else {
|
2021-04-08 15:47:28 +02:00
|
|
|
return &p, nil
|
2020-09-29 08:23:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-08 15:47:28 +02:00
|
|
|
func (p *bazelPaths) BazelMetricsDir() string {
|
|
|
|
return p.metricsDir
|
2020-12-12 07:24:26 +01:00
|
|
|
}
|
|
|
|
|
2020-09-29 08:23:17 +02:00
|
|
|
func (context *bazelContext) BazelEnabled() bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adds a cquery request to the Bazel request queue, to be later invoked, or
|
|
|
|
// returns the result of the given request if the request was already made.
|
|
|
|
// If the given request was already made (and the results are available), then
|
|
|
|
// returns (result, true). If the request is queued but no results are available,
|
|
|
|
// then returns ("", false).
|
2021-04-02 19:37:39 +02:00
|
|
|
func (context *bazelContext) cquery(label string, requestType cqueryRequest,
|
2021-02-22 22:13:50 +01:00
|
|
|
archType ArchType) (string, bool) {
|
|
|
|
key := cqueryKey{label, requestType, archType}
|
2020-09-29 08:23:17 +02:00
|
|
|
if result, ok := context.results[key]; ok {
|
|
|
|
return result, true
|
|
|
|
} else {
|
|
|
|
context.requestMutex.Lock()
|
|
|
|
defer context.requestMutex.Unlock()
|
|
|
|
context.requests[key] = true
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func pwdPrefix() string {
|
|
|
|
// Darwin doesn't have /proc
|
|
|
|
if runtime.GOOS != "darwin" {
|
|
|
|
return "PWD=/proc/self/cwd"
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2021-04-08 15:47:28 +02:00
|
|
|
type bazelCommand struct {
|
|
|
|
command string
|
|
|
|
// query or label
|
|
|
|
expression string
|
|
|
|
}
|
|
|
|
|
|
|
|
type mockBazelRunner struct {
|
|
|
|
bazelCommandResults map[bazelCommand]string
|
|
|
|
commands []bazelCommand
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths,
|
|
|
|
runName bazel.RunName,
|
|
|
|
command bazelCommand,
|
|
|
|
extraFlags ...string) (string, string, error) {
|
|
|
|
r.commands = append(r.commands, command)
|
|
|
|
if ret, ok := r.bazelCommandResults[command]; ok {
|
|
|
|
return ret, "", nil
|
|
|
|
}
|
|
|
|
return "", "", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type builtinBazelRunner struct{}
|
|
|
|
|
2021-03-10 02:43:32 +01:00
|
|
|
// Issues the given bazel command with given build label and additional flags.
|
|
|
|
// Returns (stdout, stderr, error). The first and second return values are strings
|
|
|
|
// containing the stdout and stderr of the run command, and an error is returned if
|
|
|
|
// the invocation returned an error code.
|
2021-04-08 15:47:28 +02:00
|
|
|
func (r *builtinBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand,
|
2021-03-10 02:43:32 +01:00
|
|
|
extraFlags ...string) (string, string, error) {
|
2021-08-27 17:59:39 +02:00
|
|
|
cmdFlags := []string{
|
|
|
|
// --noautodetect_server_javabase has the practical consequence of preventing Bazel from
|
|
|
|
// attempting to download rules_java, which is incompatible with
|
|
|
|
// --experimental_repository_disable_download set further below.
|
|
|
|
// rules_java is also not needed until mixed builds start building java targets.
|
|
|
|
// TODO(b/197958133): Once rules_java is pulled into AOSP, remove this flag.
|
|
|
|
"--noautodetect_server_javabase",
|
|
|
|
"--output_base=" + absolutePath(paths.outputBase),
|
|
|
|
command.command,
|
|
|
|
}
|
2021-04-08 15:47:28 +02:00
|
|
|
cmdFlags = append(cmdFlags, command.expression)
|
|
|
|
cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(paths, runName))
|
Add os/target configurable selects for label list attributes.
This CL is pretty large, so I recommend starting with reading the newly
added tests for the expected behavior.
This change works in conjunction with the linked CLs in the Gerrit topic.
Those CLs add support for new platform() definitions for OS targets
specified in Soong's arch.go, which are configurable through
Android.bp's `target {}` property. It works similary to previous CLs
adding support for the `arch {}` property.
These configurable props are keyed by the OS: android, linux_bionic,
windows, and so on. They map to `select` statements in label list
attributes, which this CL enables for cc_library_headers' header_libs
and export_header_lib_headers props.
This enables //bionic/libc:libc_headers to be generated correctly, from:
cc_library_headers {
name: "libc_headers",
target: {
android: {
header_libs: ["libc_headers_arch"],
export_header_lib_headers: ["libc_headers_arch"],
},
linux_bionic: {
header_libs: ["libc_headers_arch"],
export_header_lib_headers: ["libc_headers_arch"],
},
},
// omitted props
}
to:
cc_library_headers(
name = "libc_headers",
deps = [] + select({
"//build/bazel/platforms/os:android": [
":libc_headers_arch",
],
"//build/bazel/platforms/os:linux_bionic": [
":libc_headers_arch",
],
"//conditions:default": [],
}),
)
Test: TH
Test: Verify generated //bionic/libc:libc_headers
Fixes: 183597786
Change-Id: I01016cc2cc9a71449f02300d747f01decebf3f6e
2021-03-24 07:18:33 +01:00
|
|
|
|
|
|
|
// Set default platforms to canonicalized values for mixed builds requests.
|
|
|
|
// If these are set in the bazelrc, they will have values that are
|
|
|
|
// non-canonicalized to @sourceroot labels, and thus be invalid when
|
|
|
|
// referenced from the buildroot.
|
|
|
|
//
|
|
|
|
// The actual platform values here may be overridden by configuration
|
|
|
|
// transitions from the buildroot.
|
2021-02-09 05:04:59 +01:00
|
|
|
cmdFlags = append(cmdFlags,
|
2021-07-26 23:38:47 +02:00
|
|
|
fmt.Sprintf("--platforms=%s", "//build/bazel/platforms:android_target"))
|
2021-02-09 05:04:59 +01:00
|
|
|
cmdFlags = append(cmdFlags,
|
2021-04-20 13:01:07 +02:00
|
|
|
fmt.Sprintf("--extra_toolchains=%s", "//prebuilts/clang/host/linux-x86:all"))
|
Add os/target configurable selects for label list attributes.
This CL is pretty large, so I recommend starting with reading the newly
added tests for the expected behavior.
This change works in conjunction with the linked CLs in the Gerrit topic.
Those CLs add support for new platform() definitions for OS targets
specified in Soong's arch.go, which are configurable through
Android.bp's `target {}` property. It works similary to previous CLs
adding support for the `arch {}` property.
These configurable props are keyed by the OS: android, linux_bionic,
windows, and so on. They map to `select` statements in label list
attributes, which this CL enables for cc_library_headers' header_libs
and export_header_lib_headers props.
This enables //bionic/libc:libc_headers to be generated correctly, from:
cc_library_headers {
name: "libc_headers",
target: {
android: {
header_libs: ["libc_headers_arch"],
export_header_lib_headers: ["libc_headers_arch"],
},
linux_bionic: {
header_libs: ["libc_headers_arch"],
export_header_lib_headers: ["libc_headers_arch"],
},
},
// omitted props
}
to:
cc_library_headers(
name = "libc_headers",
deps = [] + select({
"//build/bazel/platforms/os:android": [
":libc_headers_arch",
],
"//build/bazel/platforms/os:linux_bionic": [
":libc_headers_arch",
],
"//conditions:default": [],
}),
)
Test: TH
Test: Verify generated //bionic/libc:libc_headers
Fixes: 183597786
Change-Id: I01016cc2cc9a71449f02300d747f01decebf3f6e
2021-03-24 07:18:33 +01:00
|
|
|
// This should be parameterized on the host OS, but let's restrict to linux
|
|
|
|
// to keep things simple for now.
|
|
|
|
cmdFlags = append(cmdFlags,
|
2021-04-20 13:01:07 +02:00
|
|
|
fmt.Sprintf("--host_platform=%s", "//build/bazel/platforms:linux_x86_64"))
|
Add os/target configurable selects for label list attributes.
This CL is pretty large, so I recommend starting with reading the newly
added tests for the expected behavior.
This change works in conjunction with the linked CLs in the Gerrit topic.
Those CLs add support for new platform() definitions for OS targets
specified in Soong's arch.go, which are configurable through
Android.bp's `target {}` property. It works similary to previous CLs
adding support for the `arch {}` property.
These configurable props are keyed by the OS: android, linux_bionic,
windows, and so on. They map to `select` statements in label list
attributes, which this CL enables for cc_library_headers' header_libs
and export_header_lib_headers props.
This enables //bionic/libc:libc_headers to be generated correctly, from:
cc_library_headers {
name: "libc_headers",
target: {
android: {
header_libs: ["libc_headers_arch"],
export_header_lib_headers: ["libc_headers_arch"],
},
linux_bionic: {
header_libs: ["libc_headers_arch"],
export_header_lib_headers: ["libc_headers_arch"],
},
},
// omitted props
}
to:
cc_library_headers(
name = "libc_headers",
deps = [] + select({
"//build/bazel/platforms/os:android": [
":libc_headers_arch",
],
"//build/bazel/platforms/os:linux_bionic": [
":libc_headers_arch",
],
"//conditions:default": [],
}),
)
Test: TH
Test: Verify generated //bionic/libc:libc_headers
Fixes: 183597786
Change-Id: I01016cc2cc9a71449f02300d747f01decebf3f6e
2021-03-24 07:18:33 +01:00
|
|
|
|
2021-02-22 22:13:50 +01:00
|
|
|
// Explicitly disable downloading rules (such as canonical C++ and Java rules) from the network.
|
|
|
|
cmdFlags = append(cmdFlags, "--experimental_repository_disable_download")
|
2020-09-29 08:23:17 +02:00
|
|
|
cmdFlags = append(cmdFlags, extraFlags...)
|
|
|
|
|
2021-04-08 15:47:28 +02:00
|
|
|
bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
|
2021-04-20 13:01:07 +02:00
|
|
|
bazelCmd.Dir = absolutePath(paths.syntheticWorkspaceDir())
|
2021-05-11 16:54:29 +02:00
|
|
|
bazelCmd.Env = append(os.Environ(),
|
|
|
|
"HOME="+paths.homeDir,
|
|
|
|
pwdPrefix(),
|
2021-08-26 15:07:24 +02:00
|
|
|
"BUILD_DIR="+absolutePath(paths.soongOutDir),
|
2021-06-01 13:19:53 +02:00
|
|
|
// Make OUT_DIR absolute here so tools/bazel.sh uses the correct
|
|
|
|
// OUT_DIR at <root>/out, instead of <root>/out/soong/workspace/out.
|
|
|
|
"OUT_DIR="+absolutePath(paths.outDir()),
|
2021-02-22 22:13:50 +01:00
|
|
|
// Disables local host detection of gcc; toolchain information is defined
|
|
|
|
// explicitly in BUILD files.
|
|
|
|
"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1")
|
2020-10-10 04:24:15 +02:00
|
|
|
stderr := &bytes.Buffer{}
|
|
|
|
bazelCmd.Stderr = stderr
|
2020-09-29 08:23:17 +02:00
|
|
|
|
|
|
|
if output, err := bazelCmd.Output(); err != nil {
|
2021-03-10 02:43:32 +01:00
|
|
|
return "", string(stderr.Bytes()),
|
|
|
|
fmt.Errorf("bazel command failed. command: [%s], env: [%s], error [%s]", bazelCmd, bazelCmd.Env, stderr)
|
2020-09-29 08:23:17 +02:00
|
|
|
} else {
|
2021-03-10 02:43:32 +01:00
|
|
|
return string(output), string(stderr.Bytes()), nil
|
2020-09-29 08:23:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-23 22:48:08 +02:00
|
|
|
func (context *bazelContext) mainBzlFileContents() []byte {
|
2021-02-22 22:13:50 +01:00
|
|
|
// TODO(cparsons): Define configuration transitions programmatically based
|
|
|
|
// on available archs.
|
2020-10-23 22:48:08 +02:00
|
|
|
contents := `
|
2020-12-10 23:19:18 +01:00
|
|
|
#####################################################
|
2020-10-23 22:48:08 +02:00
|
|
|
# This file is generated by soong_build. Do not edit.
|
2020-12-10 23:19:18 +01:00
|
|
|
#####################################################
|
|
|
|
|
2021-03-30 03:09:24 +02:00
|
|
|
def _config_node_transition_impl(settings, attr):
|
2021-02-22 22:13:50 +01:00
|
|
|
return {
|
2021-04-20 13:01:07 +02:00
|
|
|
"//command_line_option:platforms": "@//build/bazel/platforms:android_%s" % attr.arch,
|
2021-02-22 22:13:50 +01:00
|
|
|
}
|
|
|
|
|
2021-03-30 03:09:24 +02:00
|
|
|
_config_node_transition = transition(
|
|
|
|
implementation = _config_node_transition_impl,
|
2021-02-22 22:13:50 +01:00
|
|
|
inputs = [],
|
|
|
|
outputs = [
|
|
|
|
"//command_line_option:platforms",
|
|
|
|
],
|
|
|
|
)
|
|
|
|
|
2021-03-30 03:09:24 +02:00
|
|
|
def _passthrough_rule_impl(ctx):
|
|
|
|
return [DefaultInfo(files = depset(ctx.files.deps))]
|
2021-02-22 22:13:50 +01:00
|
|
|
|
2021-03-30 03:09:24 +02:00
|
|
|
config_node = rule(
|
|
|
|
implementation = _passthrough_rule_impl,
|
|
|
|
attrs = {
|
|
|
|
"arch" : attr.string(mandatory = True),
|
|
|
|
"deps" : attr.label_list(cfg = _config_node_transition),
|
|
|
|
"_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"),
|
|
|
|
},
|
2021-02-22 22:13:50 +01:00
|
|
|
)
|
|
|
|
|
2020-10-23 22:48:08 +02:00
|
|
|
|
2020-12-10 23:19:18 +01:00
|
|
|
# Rule representing the root of the build, to depend on all Bazel targets that
|
|
|
|
# are required for the build. Building this target will build the entire Bazel
|
|
|
|
# build tree.
|
2020-10-23 22:48:08 +02:00
|
|
|
mixed_build_root = rule(
|
2021-03-30 03:09:24 +02:00
|
|
|
implementation = _passthrough_rule_impl,
|
2021-02-22 22:13:50 +01:00
|
|
|
attrs = {
|
2021-03-30 03:09:24 +02:00
|
|
|
"deps" : attr.label_list(),
|
2021-02-22 22:13:50 +01:00
|
|
|
},
|
2020-10-23 22:48:08 +02:00
|
|
|
)
|
2020-12-10 23:19:18 +01:00
|
|
|
|
|
|
|
def _phony_root_impl(ctx):
|
|
|
|
return []
|
|
|
|
|
|
|
|
# Rule to depend on other targets but build nothing.
|
|
|
|
# This is useful as follows: building a target of this rule will generate
|
|
|
|
# symlink forests for all dependencies of the target, without executing any
|
|
|
|
# actions of the build.
|
|
|
|
phony_root = rule(
|
|
|
|
implementation = _phony_root_impl,
|
|
|
|
attrs = {"deps" : attr.label_list()},
|
|
|
|
)
|
2020-10-23 22:48:08 +02:00
|
|
|
`
|
|
|
|
return []byte(contents)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (context *bazelContext) mainBuildFileContents() []byte {
|
2021-02-22 22:13:50 +01:00
|
|
|
// TODO(cparsons): Map label to attribute programmatically; don't use hard-coded
|
|
|
|
// architecture mapping.
|
2020-10-23 22:48:08 +02:00
|
|
|
formatString := `
|
|
|
|
# This file is generated by soong_build. Do not edit.
|
2021-03-30 03:09:24 +02:00
|
|
|
load(":main.bzl", "config_node", "mixed_build_root", "phony_root")
|
|
|
|
|
|
|
|
%s
|
2020-10-23 22:48:08 +02:00
|
|
|
|
|
|
|
mixed_build_root(name = "buildroot",
|
2021-03-30 03:09:24 +02:00
|
|
|
deps = [%s],
|
2020-10-23 22:48:08 +02:00
|
|
|
)
|
2020-12-10 23:19:18 +01:00
|
|
|
|
|
|
|
phony_root(name = "phonyroot",
|
|
|
|
deps = [":buildroot"],
|
|
|
|
)
|
2020-10-23 22:48:08 +02:00
|
|
|
`
|
2021-03-30 03:09:24 +02:00
|
|
|
configNodeFormatString := `
|
|
|
|
config_node(name = "%s",
|
|
|
|
arch = "%s",
|
|
|
|
deps = [%s],
|
|
|
|
)
|
|
|
|
`
|
|
|
|
|
|
|
|
configNodesSection := ""
|
|
|
|
|
|
|
|
labelsByArch := map[string][]string{}
|
2020-10-23 22:48:08 +02:00
|
|
|
for val, _ := range context.requests {
|
2021-04-20 13:01:07 +02:00
|
|
|
labelString := fmt.Sprintf("\"@%s\"", val.label)
|
2021-03-30 03:09:24 +02:00
|
|
|
archString := getArchString(val)
|
|
|
|
labelsByArch[archString] = append(labelsByArch[archString], labelString)
|
|
|
|
}
|
|
|
|
|
|
|
|
configNodeLabels := []string{}
|
|
|
|
for archString, labels := range labelsByArch {
|
|
|
|
configNodeLabels = append(configNodeLabels, fmt.Sprintf("\":%s\"", archString))
|
|
|
|
labelsString := strings.Join(labels, ",\n ")
|
|
|
|
configNodesSection += fmt.Sprintf(configNodeFormatString, archString, archString, labelsString)
|
2020-10-23 22:48:08 +02:00
|
|
|
}
|
|
|
|
|
2021-03-30 03:09:24 +02:00
|
|
|
return []byte(fmt.Sprintf(formatString, configNodesSection, strings.Join(configNodeLabels, ",\n ")))
|
2020-10-23 22:48:08 +02:00
|
|
|
}
|
|
|
|
|
2021-03-11 17:08:46 +01:00
|
|
|
func indent(original string) string {
|
|
|
|
result := ""
|
|
|
|
for _, line := range strings.Split(original, "\n") {
|
|
|
|
result += " " + line + "\n"
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2021-03-10 02:43:32 +01:00
|
|
|
// Returns the file contents of the buildroot.cquery file that should be used for the cquery
|
|
|
|
// expression in order to obtain information about buildroot and its dependencies.
|
|
|
|
// The contents of this file depend on the bazelContext's requests; requests are enumerated
|
|
|
|
// and grouped by their request type. The data retrieved for each label depends on its
|
|
|
|
// request type.
|
2020-10-23 22:48:08 +02:00
|
|
|
func (context *bazelContext) cqueryStarlarkFileContents() []byte {
|
2021-04-02 19:37:39 +02:00
|
|
|
requestTypeToCqueryIdEntries := map[cqueryRequest][]string{}
|
2021-03-11 17:08:46 +01:00
|
|
|
for val, _ := range context.requests {
|
|
|
|
cqueryId := getCqueryId(val)
|
|
|
|
mapEntryString := fmt.Sprintf("%q : True", cqueryId)
|
|
|
|
requestTypeToCqueryIdEntries[val.requestType] =
|
|
|
|
append(requestTypeToCqueryIdEntries[val.requestType], mapEntryString)
|
|
|
|
}
|
|
|
|
labelRegistrationMapSection := ""
|
|
|
|
functionDefSection := ""
|
|
|
|
mainSwitchSection := ""
|
2020-10-23 22:48:08 +02:00
|
|
|
|
2021-03-11 17:08:46 +01:00
|
|
|
mapDeclarationFormatString := `
|
|
|
|
%s = {
|
2021-02-22 22:13:50 +01:00
|
|
|
%s
|
|
|
|
}
|
2021-03-11 17:08:46 +01:00
|
|
|
`
|
|
|
|
functionDefFormatString := `
|
|
|
|
def %s(target):
|
|
|
|
%s
|
|
|
|
`
|
|
|
|
mainSwitchSectionFormatString := `
|
|
|
|
if id_string in %s:
|
|
|
|
return id_string + ">>" + %s(target)
|
|
|
|
`
|
2021-02-22 22:13:50 +01:00
|
|
|
|
2021-04-02 19:26:07 +02:00
|
|
|
for requestType, _ := range requestTypeToCqueryIdEntries {
|
2021-03-11 17:08:46 +01:00
|
|
|
labelMapName := requestType.Name() + "_Labels"
|
|
|
|
functionName := requestType.Name() + "_Fn"
|
|
|
|
labelRegistrationMapSection += fmt.Sprintf(mapDeclarationFormatString,
|
|
|
|
labelMapName,
|
|
|
|
strings.Join(requestTypeToCqueryIdEntries[requestType], ",\n "))
|
|
|
|
functionDefSection += fmt.Sprintf(functionDefFormatString,
|
|
|
|
functionName,
|
|
|
|
indent(requestType.StarlarkFunctionBody()))
|
|
|
|
mainSwitchSection += fmt.Sprintf(mainSwitchSectionFormatString,
|
|
|
|
labelMapName, functionName)
|
|
|
|
}
|
2021-03-10 02:43:32 +01:00
|
|
|
|
2021-03-11 17:08:46 +01:00
|
|
|
formatString := `
|
|
|
|
# This file is generated by soong_build. Do not edit.
|
2021-03-10 02:43:32 +01:00
|
|
|
|
2021-03-11 17:08:46 +01:00
|
|
|
# Label Map Section
|
|
|
|
%s
|
2021-02-22 22:13:50 +01:00
|
|
|
|
2021-03-11 17:08:46 +01:00
|
|
|
# Function Def Section
|
|
|
|
%s
|
2021-02-22 22:13:50 +01:00
|
|
|
|
|
|
|
def get_arch(target):
|
|
|
|
buildoptions = build_options(target)
|
|
|
|
platforms = build_options(target)["//command_line_option:platforms"]
|
|
|
|
if len(platforms) != 1:
|
|
|
|
# An individual configured target should have only one platform architecture.
|
|
|
|
# Note that it's fine for there to be multiple architectures for the same label,
|
|
|
|
# but each is its own configured target.
|
|
|
|
fail("expected exactly 1 platform for " + str(target.label) + " but got " + str(platforms))
|
|
|
|
platform_name = build_options(target)["//command_line_option:platforms"][0].name
|
|
|
|
if platform_name == "host":
|
|
|
|
return "HOST"
|
2021-06-04 21:03:47 +02:00
|
|
|
elif platform_name.startswith("android_"):
|
|
|
|
return platform_name[len("android_"):]
|
|
|
|
elif platform_name.startswith("linux_"):
|
|
|
|
return platform_name[len("linux_"):]
|
|
|
|
else:
|
|
|
|
fail("expected platform name of the form 'android_<arch>' or 'linux_<arch>', but was " + str(platforms))
|
2021-02-22 22:13:50 +01:00
|
|
|
return "UNKNOWN"
|
|
|
|
|
2020-10-23 22:48:08 +02:00
|
|
|
def format(target):
|
2021-02-22 22:13:50 +01:00
|
|
|
id_string = str(target.label) + "|" + get_arch(target)
|
|
|
|
|
2021-03-11 17:08:46 +01:00
|
|
|
# Main switch section
|
|
|
|
%s
|
|
|
|
# This target was not requested via cquery, and thus must be a dependency
|
|
|
|
# of a requested target.
|
|
|
|
return id_string + ">>NONE"
|
|
|
|
`
|
2020-10-23 22:48:08 +02:00
|
|
|
|
2021-03-11 17:08:46 +01:00
|
|
|
return []byte(fmt.Sprintf(formatString, labelRegistrationMapSection, functionDefSection,
|
|
|
|
mainSwitchSection))
|
2020-10-23 22:48:08 +02:00
|
|
|
}
|
|
|
|
|
2021-04-20 13:01:07 +02:00
|
|
|
// Returns a path containing build-related metadata required for interfacing
|
|
|
|
// with Bazel. Example: out/soong/bazel.
|
2021-04-08 15:47:28 +02:00
|
|
|
func (p *bazelPaths) intermediatesDir() string {
|
2021-08-26 15:07:24 +02:00
|
|
|
return filepath.Join(p.soongOutDir, "bazel")
|
2020-11-17 21:41:01 +01:00
|
|
|
}
|
|
|
|
|
2021-04-20 13:01:07 +02:00
|
|
|
// Returns the path where the contents of the @soong_injection repository live.
|
|
|
|
// It is used by Soong to tell Bazel things it cannot over the command line.
|
|
|
|
func (p *bazelPaths) injectedFilesDir() string {
|
2021-08-26 15:07:24 +02:00
|
|
|
return filepath.Join(p.soongOutDir, bazel.SoongInjectionDirName)
|
2021-04-20 13:01:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the path of the synthetic Bazel workspace that contains a symlink
|
|
|
|
// forest composed the whole source tree and BUILD files generated by bp2build.
|
|
|
|
func (p *bazelPaths) syntheticWorkspaceDir() string {
|
2021-08-26 15:07:24 +02:00
|
|
|
return filepath.Join(p.soongOutDir, "workspace")
|
2021-04-20 13:01:07 +02:00
|
|
|
}
|
|
|
|
|
2021-06-01 13:19:53 +02:00
|
|
|
// Returns the path to the top level out dir ($OUT_DIR).
|
|
|
|
func (p *bazelPaths) outDir() string {
|
2021-08-26 15:07:24 +02:00
|
|
|
return filepath.Dir(p.soongOutDir)
|
2021-06-01 13:19:53 +02:00
|
|
|
}
|
|
|
|
|
2020-09-29 08:23:17 +02:00
|
|
|
// Issues commands to Bazel to receive results for all cquery requests
|
|
|
|
// queued in the BazelContext.
|
|
|
|
func (context *bazelContext) InvokeBazel() error {
|
|
|
|
context.results = make(map[cqueryKey]string)
|
|
|
|
|
|
|
|
var cqueryOutput string
|
2021-03-10 02:43:32 +01:00
|
|
|
var cqueryErr string
|
2020-09-29 08:23:17 +02:00
|
|
|
var err error
|
2020-11-17 21:41:01 +01:00
|
|
|
|
2021-04-20 13:01:07 +02:00
|
|
|
soongInjectionPath := absolutePath(context.paths.injectedFilesDir())
|
2021-05-11 16:54:29 +02:00
|
|
|
mixedBuildsPath := filepath.Join(soongInjectionPath, "mixed_builds")
|
|
|
|
if _, err := os.Stat(mixedBuildsPath); os.IsNotExist(err) {
|
|
|
|
err = os.MkdirAll(mixedBuildsPath, 0777)
|
2021-04-20 13:01:07 +02:00
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2021-01-19 23:19:16 +01:00
|
|
|
}
|
|
|
|
|
2021-04-20 13:01:07 +02:00
|
|
|
err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "WORKSPACE.bazel"), []byte{}, 0666)
|
2020-11-17 21:41:01 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-04-20 13:01:07 +02:00
|
|
|
|
2020-10-23 22:48:08 +02:00
|
|
|
err = ioutil.WriteFile(
|
2021-05-11 16:54:29 +02:00
|
|
|
filepath.Join(mixedBuildsPath, "main.bzl"),
|
2020-10-23 22:48:08 +02:00
|
|
|
context.mainBzlFileContents(), 0666)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-04-20 13:01:07 +02:00
|
|
|
|
2020-10-23 22:48:08 +02:00
|
|
|
err = ioutil.WriteFile(
|
2021-05-11 16:54:29 +02:00
|
|
|
filepath.Join(mixedBuildsPath, "BUILD.bazel"),
|
2020-10-23 22:48:08 +02:00
|
|
|
context.mainBuildFileContents(), 0666)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-04-20 13:01:07 +02:00
|
|
|
cqueryFileRelpath := filepath.Join(context.paths.injectedFilesDir(), "buildroot.cquery")
|
2020-10-23 22:48:08 +02:00
|
|
|
err = ioutil.WriteFile(
|
2020-12-21 18:11:10 +01:00
|
|
|
absolutePath(cqueryFileRelpath),
|
2020-10-23 22:48:08 +02:00
|
|
|
context.cqueryStarlarkFileContents(), 0666)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-11 16:54:29 +02:00
|
|
|
buildrootLabel := "@soong_injection//mixed_builds:buildroot"
|
2021-04-08 15:47:28 +02:00
|
|
|
cqueryOutput, cqueryErr, err = context.issueBazelCommand(
|
|
|
|
context.paths,
|
|
|
|
bazel.CqueryBuildRootRunName,
|
|
|
|
bazelCommand{"cquery", fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)},
|
2020-10-23 22:48:08 +02:00
|
|
|
"--output=starlark",
|
2021-04-20 13:01:07 +02:00
|
|
|
"--starlark:file="+absolutePath(cqueryFileRelpath))
|
|
|
|
err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"),
|
2021-02-22 22:13:50 +01:00
|
|
|
[]byte(cqueryOutput), 0666)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-29 08:23:17 +02:00
|
|
|
|
2020-10-23 22:48:08 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-29 08:23:17 +02:00
|
|
|
|
2020-10-23 22:48:08 +02:00
|
|
|
cqueryResults := map[string]string{}
|
|
|
|
for _, outputLine := range strings.Split(cqueryOutput, "\n") {
|
|
|
|
if strings.Contains(outputLine, ">>") {
|
|
|
|
splitLine := strings.SplitN(outputLine, ">>", 2)
|
|
|
|
cqueryResults[splitLine[0]] = splitLine[1]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for val, _ := range context.requests {
|
2021-02-22 22:13:50 +01:00
|
|
|
if cqueryResult, ok := cqueryResults[getCqueryId(val)]; ok {
|
2020-10-23 22:48:08 +02:00
|
|
|
context.results[val] = string(cqueryResult)
|
2020-09-29 08:23:17 +02:00
|
|
|
} else {
|
2021-03-10 02:43:32 +01:00
|
|
|
return fmt.Errorf("missing result for bazel target %s. query output: [%s], cquery err: [%s]",
|
|
|
|
getCqueryId(val), cqueryOutput, cqueryErr)
|
2020-09-29 08:23:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-10 23:19:18 +01:00
|
|
|
// Issue an aquery command to retrieve action information about the bazel build tree.
|
|
|
|
//
|
2020-09-29 08:23:17 +02:00
|
|
|
// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
|
2020-12-10 23:19:18 +01:00
|
|
|
var aqueryOutput string
|
2021-04-08 15:47:28 +02:00
|
|
|
aqueryOutput, _, err = context.issueBazelCommand(
|
|
|
|
context.paths,
|
|
|
|
bazel.AqueryBuildRootRunName,
|
|
|
|
bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)},
|
|
|
|
// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
|
|
|
|
// proto sources, which would add a number of unnecessary dependencies.
|
|
|
|
"--output=jsonproto")
|
2020-09-29 08:23:17 +02:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-01-15 18:22:41 +01:00
|
|
|
context.buildStatements, err = bazel.AqueryBuildStatements([]byte(aqueryOutput))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-12-10 23:19:18 +01:00
|
|
|
|
|
|
|
// Issue a build command of the phony root to generate symlink forests for dependencies of the
|
|
|
|
// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
|
|
|
|
// but some of symlinks may be required to resolve source dependencies of the build.
|
2021-04-08 15:47:28 +02:00
|
|
|
_, _, err = context.issueBazelCommand(
|
|
|
|
context.paths,
|
|
|
|
bazel.BazelBuildPhonyRootRunName,
|
2021-05-11 16:54:29 +02:00
|
|
|
bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"})
|
2020-12-10 23:19:18 +01:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-09-29 08:23:17 +02:00
|
|
|
// Clear requests.
|
|
|
|
context.requests = map[cqueryKey]bool{}
|
|
|
|
return nil
|
|
|
|
}
|
2020-10-13 05:44:08 +02:00
|
|
|
|
2020-12-10 23:19:18 +01:00
|
|
|
func (context *bazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
|
|
|
|
return context.buildStatements
|
|
|
|
}
|
|
|
|
|
|
|
|
func (context *bazelContext) OutputBase() string {
|
2021-04-08 15:47:28 +02:00
|
|
|
return context.paths.outputBase
|
2020-12-10 23:19:18 +01:00
|
|
|
}
|
|
|
|
|
2020-10-13 05:44:08 +02:00
|
|
|
// Singleton used for registering BUILD file ninja dependencies (needed
|
|
|
|
// for correctness of builds which use Bazel.
|
|
|
|
func BazelSingleton() Singleton {
|
|
|
|
return &bazelSingleton{}
|
|
|
|
}
|
|
|
|
|
|
|
|
type bazelSingleton struct{}
|
|
|
|
|
|
|
|
func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) {
|
2020-12-10 23:19:18 +01:00
|
|
|
// bazelSingleton is a no-op if mixed-soong-bazel-builds are disabled.
|
|
|
|
if !ctx.Config().BazelContext.BazelEnabled() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add ninja file dependencies for files which all bazel invocations require.
|
|
|
|
bazelBuildList := absolutePath(filepath.Join(
|
2021-08-16 15:24:48 +02:00
|
|
|
filepath.Dir(ctx.Config().moduleListFile), "bazel.list"))
|
2020-12-10 23:19:18 +01:00
|
|
|
ctx.AddNinjaFileDeps(bazelBuildList)
|
|
|
|
|
|
|
|
data, err := ioutil.ReadFile(bazelBuildList)
|
|
|
|
if err != nil {
|
|
|
|
ctx.Errorf(err.Error())
|
|
|
|
}
|
|
|
|
files := strings.Split(strings.TrimSpace(string(data)), "\n")
|
|
|
|
for _, file := range files {
|
|
|
|
ctx.AddNinjaFileDeps(file)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Register bazel-owned build statements (obtained from the aquery invocation).
|
|
|
|
for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
|
2021-02-22 22:13:50 +01:00
|
|
|
if len(buildStatement.Command) < 1 {
|
2021-04-06 18:17:33 +02:00
|
|
|
panic(fmt.Sprintf("unhandled build statement: %v", buildStatement))
|
2021-02-22 22:13:50 +01:00
|
|
|
}
|
2020-12-10 23:19:18 +01:00
|
|
|
rule := NewRuleBuilder(pctx, ctx)
|
|
|
|
cmd := rule.Command()
|
2021-06-04 21:03:47 +02:00
|
|
|
|
|
|
|
// cd into Bazel's execution root, which is the action cwd.
|
|
|
|
cmd.Text(fmt.Sprintf("cd %s/execroot/__main__ && ", ctx.Config().BazelContext.OutputBase()))
|
|
|
|
|
|
|
|
for _, pair := range buildStatement.Env {
|
|
|
|
// Set per-action env variables, if any.
|
|
|
|
cmd.Flag(pair.Key + "=" + pair.Value)
|
|
|
|
}
|
|
|
|
|
|
|
|
// The actual Bazel action.
|
|
|
|
cmd.Text(" " + buildStatement.Command)
|
2020-12-10 23:19:18 +01:00
|
|
|
|
|
|
|
for _, outputPath := range buildStatement.OutputPaths {
|
|
|
|
cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
|
2020-10-13 05:44:08 +02:00
|
|
|
}
|
2020-12-10 23:19:18 +01:00
|
|
|
for _, inputPath := range buildStatement.InputPaths {
|
|
|
|
cmd.Implicit(PathForBazelOut(ctx, inputPath))
|
2020-10-13 05:44:08 +02:00
|
|
|
}
|
2020-12-10 23:19:18 +01:00
|
|
|
|
2021-03-25 21:42:37 +01:00
|
|
|
if depfile := buildStatement.Depfile; depfile != nil {
|
|
|
|
cmd.ImplicitDepFile(PathForBazelOut(ctx, *depfile))
|
|
|
|
}
|
|
|
|
|
2021-06-08 21:04:11 +02:00
|
|
|
for _, symlinkPath := range buildStatement.SymlinkPaths {
|
|
|
|
cmd.ImplicitSymlinkOutput(PathForBazelOut(ctx, symlinkPath))
|
|
|
|
}
|
|
|
|
|
2020-12-10 23:19:18 +01:00
|
|
|
// This is required to silence warnings pertaining to unexpected timestamps. Particularly,
|
|
|
|
// some Bazel builtins (such as files in the bazel_tools directory) have far-future
|
|
|
|
// timestamps. Without restat, Ninja would emit warnings that the input files of a
|
|
|
|
// build statement have later timestamps than the outputs.
|
|
|
|
rule.Restat()
|
|
|
|
|
2020-12-16 20:13:30 +01:00
|
|
|
rule.Build(fmt.Sprintf("bazel %d", index), buildStatement.Mnemonic)
|
2020-10-13 05:44:08 +02:00
|
|
|
}
|
|
|
|
}
|
2021-02-22 22:13:50 +01:00
|
|
|
|
|
|
|
func getCqueryId(key cqueryKey) string {
|
2021-04-20 13:01:07 +02:00
|
|
|
return key.label + "|" + getArchString(key)
|
2021-02-22 22:13:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func getArchString(key cqueryKey) string {
|
|
|
|
arch := key.archType.Name
|
|
|
|
if len(arch) > 0 {
|
|
|
|
return arch
|
|
|
|
} else {
|
|
|
|
return "x86_64"
|
|
|
|
}
|
|
|
|
}
|