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-10 23:19:18 +01:00
|
|
|
"github.com/google/blueprint/bootstrap"
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
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).
|
|
|
|
GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool)
|
2021-03-10 02:43:32 +01:00
|
|
|
|
2021-04-03 00:47:09 +02:00
|
|
|
// GetPrebuiltCcStaticLibraryFiles returns paths to prebuilt cc static libraries, and whether the
|
|
|
|
// results were available
|
|
|
|
GetPrebuiltCcStaticLibraryFiles(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
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
homeDir string
|
|
|
|
bazelPath string
|
|
|
|
outputBase string
|
|
|
|
workspaceDir string
|
2020-10-23 22:48:08 +02:00
|
|
|
buildDir string
|
2020-12-12 07:24:26 +01:00
|
|
|
metricsDir string
|
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
|
|
|
|
|
|
|
|
LabelToOutputFiles map[string][]string
|
|
|
|
LabelToOutputFilesAndCcObjectFiles map[string]cquery.GetOutputFilesAndCcObjectFiles_Result
|
|
|
|
LabelToCcStaticLibraryFiles 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-03-11 17:08:46 +01:00
|
|
|
func (m MockBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
|
2021-04-08 02:25:21 +02:00
|
|
|
result, ok := m.LabelToOutputFilesAndCcObjectFiles[label]
|
|
|
|
return result.OutputFiles, result.CcObjectFiles, ok
|
2021-03-10 02:43:32 +01:00
|
|
|
}
|
|
|
|
|
2021-04-03 00:47:09 +02:00
|
|
|
func (m MockBazelContext) GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool) {
|
2021-04-08 02:25:21 +02:00
|
|
|
result, ok := m.LabelToCcStaticLibraryFiles[label]
|
2021-04-03 00:47:09 +02:00
|
|
|
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-03-11 17:08:46 +01:00
|
|
|
func (bazelCtx *bazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
|
|
|
|
var outputFiles []string
|
2021-03-10 02:43:32 +01:00
|
|
|
var ccObjects []string
|
|
|
|
|
2021-03-11 17:08:46 +01:00
|
|
|
result, ok := bazelCtx.cquery(label, cquery.GetOutputFilesAndCcObjectFiles, archType)
|
2021-03-10 02:43:32 +01:00
|
|
|
if ok {
|
|
|
|
bazelOutput := strings.TrimSpace(result)
|
2021-04-02 19:37:39 +02:00
|
|
|
returnResult := cquery.GetOutputFilesAndCcObjectFiles.ParseResult(bazelOutput)
|
2021-03-11 17:08:46 +01:00
|
|
|
outputFiles = returnResult.OutputFiles
|
|
|
|
ccObjects = returnResult.CcObjectFiles
|
2021-03-10 02:43:32 +01:00
|
|
|
}
|
2021-03-11 17:08:46 +01:00
|
|
|
|
|
|
|
return outputFiles, ccObjects, ok
|
2021-03-10 02:43:32 +01:00
|
|
|
}
|
|
|
|
|
2021-04-03 00:47:09 +02:00
|
|
|
// GetPrebuiltCcStaticLibraryFiles returns a slice of prebuilt static libraries for the given
|
|
|
|
// label/archType if there are query results; otherwise, it enqueues the query and returns false.
|
|
|
|
func (bazelCtx *bazelContext) GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool) {
|
|
|
|
result, ok := bazelCtx.cquery(label, cquery.GetPrebuiltCcStaticLibraryFiles, archType)
|
|
|
|
if !ok {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
bazelOutput := strings.TrimSpace(result)
|
|
|
|
ret := cquery.GetPrebuiltCcStaticLibraryFiles.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-03-11 17:08:46 +01:00
|
|
|
func (n noopBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
|
2021-03-10 02:43:32 +01:00
|
|
|
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.
|
|
|
|
if c.Getenv("USE_BAZEL_ANALYSIS") != "1" {
|
2020-09-29 08:23:17 +02:00
|
|
|
return noopBazelContext{}, nil
|
|
|
|
}
|
|
|
|
|
2020-10-23 22:48:08 +02:00
|
|
|
bazelCtx := bazelContext{buildDir: c.buildDir, requests: make(map[cqueryKey]bool)}
|
2020-09-29 08:23:17 +02:00
|
|
|
missingEnvVars := []string{}
|
|
|
|
if len(c.Getenv("BAZEL_HOME")) > 1 {
|
|
|
|
bazelCtx.homeDir = c.Getenv("BAZEL_HOME")
|
|
|
|
} else {
|
|
|
|
missingEnvVars = append(missingEnvVars, "BAZEL_HOME")
|
|
|
|
}
|
|
|
|
if len(c.Getenv("BAZEL_PATH")) > 1 {
|
|
|
|
bazelCtx.bazelPath = c.Getenv("BAZEL_PATH")
|
|
|
|
} else {
|
|
|
|
missingEnvVars = append(missingEnvVars, "BAZEL_PATH")
|
|
|
|
}
|
|
|
|
if len(c.Getenv("BAZEL_OUTPUT_BASE")) > 1 {
|
|
|
|
bazelCtx.outputBase = c.Getenv("BAZEL_OUTPUT_BASE")
|
|
|
|
} else {
|
|
|
|
missingEnvVars = append(missingEnvVars, "BAZEL_OUTPUT_BASE")
|
|
|
|
}
|
|
|
|
if len(c.Getenv("BAZEL_WORKSPACE")) > 1 {
|
|
|
|
bazelCtx.workspaceDir = c.Getenv("BAZEL_WORKSPACE")
|
|
|
|
} else {
|
|
|
|
missingEnvVars = append(missingEnvVars, "BAZEL_WORKSPACE")
|
|
|
|
}
|
2020-12-12 07:24:26 +01:00
|
|
|
if len(c.Getenv("BAZEL_METRICS_DIR")) > 1 {
|
|
|
|
bazelCtx.metricsDir = c.Getenv("BAZEL_METRICS_DIR")
|
|
|
|
} 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 {
|
|
|
|
return &bazelCtx, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-12 07:24:26 +01:00
|
|
|
func (context *bazelContext) BazelMetricsDir() string {
|
|
|
|
return context.metricsDir
|
|
|
|
}
|
|
|
|
|
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-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.
|
2020-12-12 07:24:26 +01:00
|
|
|
func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command string, labels []string,
|
2021-03-10 02:43:32 +01:00
|
|
|
extraFlags ...string) (string, string, error) {
|
2020-09-29 08:23:17 +02:00
|
|
|
|
2020-11-02 08:56:20 +01:00
|
|
|
cmdFlags := []string{"--output_base=" + context.outputBase, command}
|
2020-09-29 08:23:17 +02:00
|
|
|
cmdFlags = append(cmdFlags, labels...)
|
2020-11-17 21:41:01 +01:00
|
|
|
cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+context.intermediatesDir())
|
2020-12-12 07:24:26 +01:00
|
|
|
cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(context, 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,
|
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
|
|
|
fmt.Sprintf("--platforms=%s", canonicalizeLabel("//build/bazel/platforms:android_x86_64")))
|
2021-02-09 05:04:59 +01:00
|
|
|
cmdFlags = append(cmdFlags,
|
|
|
|
fmt.Sprintf("--extra_toolchains=%s", canonicalizeLabel("//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,
|
|
|
|
fmt.Sprintf("--host_platform=%s", canonicalizeLabel("//build/bazel/platforms:linux_x86_64")))
|
|
|
|
|
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...)
|
|
|
|
|
|
|
|
bazelCmd := exec.Command(context.bazelPath, cmdFlags...)
|
|
|
|
bazelCmd.Dir = context.workspaceDir
|
2021-02-22 22:13:50 +01:00
|
|
|
bazelCmd.Env = append(os.Environ(), "HOME="+context.homeDir, pwdPrefix(),
|
|
|
|
// 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-11-17 21:41:01 +01:00
|
|
|
// Returns the string contents of a workspace file that should be output
|
|
|
|
// adjacent to the main bzl file and build file.
|
|
|
|
// This workspace file allows, via local_repository rule, sourcetree-level
|
|
|
|
// BUILD targets to be referenced via @sourceroot.
|
|
|
|
func (context *bazelContext) workspaceFileContents() []byte {
|
|
|
|
formatString := `
|
|
|
|
# This file is generated by soong_build. Do not edit.
|
|
|
|
local_repository(
|
|
|
|
name = "sourceroot",
|
2021-03-24 15:04:33 +01:00
|
|
|
path = "%[1]s",
|
2020-11-17 21:41:01 +01:00
|
|
|
)
|
2021-03-03 22:40:52 +01:00
|
|
|
|
|
|
|
local_repository(
|
|
|
|
name = "rules_cc",
|
2021-03-24 15:04:33 +01:00
|
|
|
path = "%[1]s/build/bazel/rules_cc",
|
|
|
|
)
|
|
|
|
|
|
|
|
local_repository(
|
|
|
|
name = "bazel_skylib",
|
|
|
|
path = "%[1]s/build/bazel/bazel_skylib",
|
2021-03-03 22:40:52 +01:00
|
|
|
)
|
2020-11-17 21:41:01 +01:00
|
|
|
`
|
2021-03-24 15:04:33 +01:00
|
|
|
return []byte(fmt.Sprintf(formatString, context.workspaceDir))
|
2020-11-17 21:41:01 +01: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 {
|
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
|
|
|
"//command_line_option:platforms": "@sourceroot//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)
|
|
|
|
}
|
|
|
|
|
2020-11-17 21:41:01 +01:00
|
|
|
// Returns a "canonicalized" corresponding to the given sourcetree-level label.
|
|
|
|
// This abstraction is required because a sourcetree label such as //foo/bar:baz
|
|
|
|
// must be referenced via the local repository prefix, such as
|
|
|
|
// @sourceroot//foo/bar:baz.
|
|
|
|
func canonicalizeLabel(label string) string {
|
|
|
|
if strings.HasPrefix(label, "//") {
|
|
|
|
return "@sourceroot" + label
|
|
|
|
} else {
|
|
|
|
return "@sourceroot//" + label
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-23 22:48:08 +02:00
|
|
|
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-02-22 22:13:50 +01:00
|
|
|
labelString := fmt.Sprintf("\"%s\"", canonicalizeLabel(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"
|
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
|
|
|
elif not platform_name.startswith("android_"):
|
|
|
|
fail("expected platform name of the form 'android_<arch>', but was " + str(platforms))
|
2021-02-22 22:13:50 +01:00
|
|
|
return "UNKNOWN"
|
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
|
|
|
return platform_name[len("android_"):]
|
2021-02-22 22:13:50 +01:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2020-11-17 21:41:01 +01:00
|
|
|
// Returns a workspace-relative path containing build-related metadata required
|
|
|
|
// for interfacing with Bazel. Example: out/soong/bazel.
|
|
|
|
func (context *bazelContext) intermediatesDir() string {
|
|
|
|
return filepath.Join(context.buildDir, "bazel")
|
|
|
|
}
|
|
|
|
|
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-01-19 23:19:16 +01:00
|
|
|
intermediatesDirPath := absolutePath(context.intermediatesDir())
|
|
|
|
if _, err := os.Stat(intermediatesDirPath); os.IsNotExist(err) {
|
|
|
|
err = os.Mkdir(intermediatesDirPath, 0777)
|
|
|
|
}
|
|
|
|
|
2020-11-17 21:41:01 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-10-23 22:48:08 +02:00
|
|
|
err = ioutil.WriteFile(
|
2020-11-17 21:41:01 +01:00
|
|
|
absolutePath(filepath.Join(context.intermediatesDir(), "main.bzl")),
|
2020-10-23 22:48:08 +02:00
|
|
|
context.mainBzlFileContents(), 0666)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = ioutil.WriteFile(
|
2020-11-17 21:41:01 +01:00
|
|
|
absolutePath(filepath.Join(context.intermediatesDir(), "BUILD.bazel")),
|
2020-10-23 22:48:08 +02:00
|
|
|
context.mainBuildFileContents(), 0666)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-12-21 18:11:10 +01:00
|
|
|
cqueryFileRelpath := filepath.Join(context.intermediatesDir(), "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
|
|
|
|
}
|
2020-12-21 18:11:10 +01:00
|
|
|
workspaceFileRelpath := filepath.Join(context.intermediatesDir(), "WORKSPACE.bazel")
|
2020-11-17 21:41:01 +01:00
|
|
|
err = ioutil.WriteFile(
|
2020-12-21 18:11:10 +01:00
|
|
|
absolutePath(workspaceFileRelpath),
|
2020-11-17 21:41:01 +01:00
|
|
|
context.workspaceFileContents(), 0666)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-12-21 18:11:10 +01:00
|
|
|
buildrootLabel := "//:buildroot"
|
2021-03-10 02:43:32 +01:00
|
|
|
cqueryOutput, cqueryErr, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery",
|
2021-02-22 22:13:50 +01:00
|
|
|
[]string{fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)},
|
2020-10-23 22:48:08 +02:00
|
|
|
"--output=starlark",
|
2020-12-21 18:11:10 +01:00
|
|
|
"--starlark:file="+cqueryFileRelpath)
|
2021-02-22 22:13:50 +01:00
|
|
|
err = ioutil.WriteFile(
|
|
|
|
absolutePath(filepath.Join(context.intermediatesDir(), "cquery.out")),
|
|
|
|
[]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-03-10 02:43:32 +01:00
|
|
|
aqueryOutput, _, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery",
|
2020-12-21 18:11:10 +01:00
|
|
|
[]string{fmt.Sprintf("deps(%s)", buildrootLabel),
|
2020-12-10 23:19:18 +01:00
|
|
|
// 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-03-10 02:43:32 +01:00
|
|
|
_, _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build",
|
2020-12-10 23:19:18 +01:00
|
|
|
[]string{"//:phonyroot"})
|
|
|
|
|
|
|
|
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 {
|
|
|
|
return context.outputBase
|
|
|
|
}
|
|
|
|
|
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-03-16 08:55:23 +01:00
|
|
|
filepath.Dir(bootstrap.CmdlineModuleListFile()), "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()
|
|
|
|
cmd.Text(fmt.Sprintf("cd %s/execroot/__main__ && %s",
|
|
|
|
ctx.Config().BazelContext.OutputBase(), buildStatement.Command))
|
|
|
|
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
return canonicalizeLabel(key.label) + "|" + getArchString(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
func getArchString(key cqueryKey) string {
|
|
|
|
arch := key.archType.Name
|
|
|
|
if len(arch) > 0 {
|
|
|
|
return arch
|
|
|
|
} else {
|
|
|
|
return "x86_64"
|
|
|
|
}
|
|
|
|
}
|