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"
"fmt"
"os"
"os/exec"
2022-06-22 17:20:50 +02:00
"path"
2020-10-13 05:44:08 +02:00
"path/filepath"
2020-09-29 08:23:17 +02:00
"runtime"
2022-12-14 20:32:05 +01:00
"sort"
2020-09-29 08:23:17 +02:00
"strings"
"sync"
2020-10-13 05:44:08 +02:00
2022-08-20 20:48:32 +02:00
"android/soong/android/allowlists"
2021-03-11 17:08:46 +01:00
"android/soong/bazel/cquery"
bp2build: allowlist //external/libcap/...
This builds cap_names.list.h, which uses an eponymous filegroup
"generate_cap_names_list.awk" in Soong, but uses the file target
directly in Bazel.
This also improve filegroup support for mixed builds, by issuing a
cquery call _without_ arch. Filegroups in Soong don't have configurable
properties, so don't generate Bazel filegroups into buildroot's
config_nodes (which was x86_64 by default).
The mixed_build_root now looks like this:
```
config_node(...)
config_node(...)
config_node(...)
config_node(...)
...
filegroup(name = "common",
srcs = ["@//bionic/linker:linker_sources_x86",
"@//bionic/libc:kernel_input_headers",
"@//system/timezone/apex:com.android.tzdata-androidManifest",
"@//external/libcap:generate_cap_names_list.awk",
"@//bionic/linker:linker_sources_arm64",
"@//bionic/linker:linker_sources",
"@//bionic/libc:libc_sources_shared_arm",
"@//bionic/linker:linker_sources_x86_64",
"@//bionic/libc:all_kernel_uapi_headers",
"@//build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal-file_contexts",
"@//system/core/libcutils:android_filesystem_config_header",
"@//bionic/libc:libc_sources_static",
"@//bionic/linker:linker_sources_arm",
"@//bionic/libc/tools:bionic-gensyscalls",
"@//bionic/tools:bionic-generate-version-script",
"@//bionic/libc:libc_sources_shared"],
)
mixed_build_root(name = "buildroot",
deps = [":x86",
":arm64",
":arm",
":common",
":x86_64"],
)
```
Test: CI
Fixes: 198595323
Fixes: 198235838
Change-Id: I6df9a14da556cf358d96e6a99b514f66a2638295
2021-09-02 14:11:49 +02:00
"android/soong/shared"
2022-08-03 21:49:43 +02:00
2022-04-26 04:35:15 +02:00
"github.com/google/blueprint"
2021-03-03 22:40:52 +01:00
2020-12-12 07:24:26 +01:00
"android/soong/bazel"
2020-09-29 08:23:17 +02:00
)
2022-06-09 01:36:16 +02:00
var (
2022-07-03 23:55:58 +02:00
_ = pctx . HostBinToolVariable ( "bazelBuildRunfilesTool" , "build-runfiles" )
buildRunfilesRule = pctx . AndroidStaticRule ( "bazelBuildRunfiles" , blueprint . RuleParams {
Command : "${bazelBuildRunfilesTool} ${in} ${outDir}" ,
Depfile : "" ,
Description : "" ,
CommandDeps : [ ] string { "${bazelBuildRunfilesTool}" } ,
} , "outDir" )
2022-06-09 01:36:16 +02:00
)
2022-05-10 19:50:12 +02:00
func init ( ) {
RegisterMixedBuildsMutator ( InitRegistrationContext )
}
func RegisterMixedBuildsMutator ( ctx RegistrationContext ) {
2022-08-03 21:49:43 +02:00
ctx . FinalDepsMutators ( func ( ctx RegisterMutatorsContext ) {
2022-05-10 19:50:12 +02:00
ctx . BottomUp ( "mixed_builds_prep" , mixedBuildsPrepareMutator ) . Parallel ( )
} )
}
func mixedBuildsPrepareMutator ( ctx BottomUpMutatorContext ) {
if m := ctx . Module ( ) ; m . Enabled ( ) {
if mixedBuildMod , ok := m . ( MixedBuildBuildable ) ; ok {
if mixedBuildMod . IsMixedBuildSupported ( ctx ) && MixedBuildsEnabled ( ctx ) {
mixedBuildMod . QueueBazelCall ( ctx )
}
}
}
}
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:
2022-11-22 23:08:59 +01:00
// - The arguments are `target` (a configured target) and `id_string` (the label + configuration).
2021-04-02 19:37:39 +02:00
// - The return value must be a string.
// - The function body should not be indented outside of its own scope.
StarlarkFunctionBody ( ) string
}
2021-10-15 00:43:51 +02:00
// Portion of cquery map key to describe target configuration.
type configKey struct {
2022-03-18 20:55:04 +01:00
arch string
osType OsType
2021-10-15 00:43:51 +02:00
}
2022-07-27 23:51:45 +02:00
func ( c configKey ) String ( ) string {
return fmt . Sprintf ( "%s::%s" , c . arch , c . osType )
}
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-10-15 00:43:51 +02:00
configKey configKey
2020-09-29 08:23:17 +02:00
}
2022-09-28 20:58:41 +02:00
func makeCqueryKey ( label string , cqueryRequest cqueryRequest , cfgKey configKey ) cqueryKey {
if strings . HasPrefix ( label , "//" ) {
// Normalize Bazel labels to specify main repository explicitly.
label = "@" + label
}
return cqueryKey { label , cqueryRequest , cfgKey }
}
2022-07-27 23:51:45 +02:00
func ( c cqueryKey ) String ( ) string {
return fmt . Sprintf ( "cquery(%s,%s,%s)" , c . label , c . requestType . Name ( ) , c . configKey )
}
2022-05-10 19:50:12 +02:00
// BazelContext is a context object useful for interacting with Bazel during
// the course of a build. Use of Bazel to evaluate part of the build graph
// is referred to as a "mixed build". (Some modules are managed by Soong,
// some are managed by Bazel). To facilitate interop between these build
// subgraphs, Soong may make requests to Bazel and evaluate their responses
// so that Soong modules may accurately depend on Bazel targets.
2020-09-29 08:23:17 +02:00
type BazelContext interface {
2022-05-10 19:50:12 +02:00
// Add a cquery request to the bazel request queue. All queued requests
// will be sent to Bazel on a subsequent invocation of InvokeBazel.
QueueBazelRequest ( label string , requestType cqueryRequest , cfgKey configKey )
// ** Cquery Results Retrieval Functions
// The below functions pertain to retrieving cquery results from a prior
// InvokeBazel function call and parsing the results.
2020-09-29 08:23:17 +02:00
// Returns result files built by building the given bazel target label.
2022-05-10 19:50:12 +02:00
GetOutputFiles ( label string , cfgKey configKey ) ( [ ] string , error )
2021-02-22 22:13:50 +01:00
2021-03-11 17:08:46 +01:00
// Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
2022-05-10 19:50:12 +02:00
GetCcInfo ( label string , cfgKey configKey ) ( cquery . CcInfo , 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
2022-05-10 19:50:12 +02:00
// TODO(b/232976601): Remove.
GetPythonBinary ( label string , cfgKey configKey ) ( string , error )
2021-08-11 18:48:30 +02:00
2022-07-27 23:51:45 +02:00
// Returns the results of the GetApexInfo query (including output files)
2022-11-04 21:05:11 +01:00
GetApexInfo ( label string , cfgkey configKey ) ( cquery . ApexInfo , error )
2022-07-27 23:51:45 +02:00
2022-10-07 23:44:50 +02:00
// Returns the results of the GetCcUnstrippedInfo query
GetCcUnstrippedInfo ( label string , cfgkey configKey ) ( cquery . CcUnstrippedInfo , error )
2022-05-10 19:50:12 +02:00
// ** end Cquery Results Retrieval Functions
2020-09-29 08:23:17 +02:00
// Issues commands to Bazel to receive results for all cquery requests
2022-11-17 00:28:18 +01:00
// queued in the BazelContext. The ctx argument is optional and is only
// used for performance data collection
InvokeBazel ( config Config , ctx * Context ) error
2020-09-29 08:23:17 +02:00
2022-08-20 20:48:32 +02:00
// Returns true if Bazel handling is enabled for the module with the given name.
// Note that this only implies "bazel mixed build" allowlisting. The caller
// should independently verify the module is eligible for Bazel handling
// (for example, that it is MixedBuildBuildable).
2022-12-30 02:11:49 +01:00
IsModuleNameAllowed ( moduleName string ) 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
2022-04-26 04:35:15 +02:00
// Returns the depsets defined in Bazel's aquery response.
AqueryDepsets ( ) [ ] bazel . AqueryDepset
2020-09-29 08:23:17 +02:00
}
2021-04-08 15:47:28 +02:00
type bazelRunner interface {
2022-09-08 17:37:57 +02:00
createBazelCommand ( paths * bazelPaths , runName bazel . RunName , command bazelCommand , extraFlags ... string ) * exec . Cmd
issueBazelCommand ( bazelCmd * exec . Cmd ) ( output string , errorMessage string , error error )
2021-04-08 15:47:28 +02:00
}
type bazelPaths struct {
2022-10-10 22:07:48 +02:00
homeDir string
bazelPath string
outputBase string
workspaceDir string
soongOutDir string
metricsDir string
bazelDepsFile 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.
2022-12-30 02:11:49 +01:00
type mixedBuildBazelContext struct {
2021-04-08 15:47:28 +02:00
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
2022-04-26 04:35:15 +02:00
// Depsets which should be used for Bazel's build statements.
depsets [ ] bazel . AqueryDepset
2022-08-20 20:48:32 +02:00
// Per-module allowlist/denylist functionality to control whether analysis of
// modules are handled by Bazel. For modules which do not have a Bazel definition
// (or do not sufficiently support bazel handling via MixedBuildBuildable),
// this allowlist will have no effect, even if the module is explicitly allowlisted here.
// Per-module denylist to opt modules out of bazel handling.
bazelDisabledModules map [ string ] bool
// Per-module allowlist to opt modules in to bazel handling.
bazelEnabledModules map [ string ] bool
// If true, modules are bazel-enabled by default, unless present in bazelDisabledModules.
modulesDefaultToBazel bool
2022-11-09 03:14:01 +01:00
targetProduct string
targetBuildVariant string
2020-09-29 08:23:17 +02:00
}
2022-12-30 02:11:49 +01:00
var _ BazelContext = & mixedBuildBazelContext { }
2020-09-29 08:23:17 +02:00
// 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
2022-11-04 21:05:11 +01:00
LabelToApexInfo map [ string ] cquery . ApexInfo
2022-10-07 23:44:50 +02:00
LabelToCcBinary map [ string ] cquery . CcUnstrippedInfo
2020-09-29 08:23:17 +02:00
}
2022-07-04 00:57:36 +02:00
func ( m MockBazelContext ) QueueBazelRequest ( _ string , _ cqueryRequest , _ configKey ) {
2022-05-10 19:50:12 +02:00
panic ( "unimplemented" )
}
2022-07-04 00:57:36 +02:00
func ( m MockBazelContext ) GetOutputFiles ( label string , _ configKey ) ( [ ] string , error ) {
2023-01-23 20:04:24 +01:00
result , ok := m . LabelToOutputFiles [ label ]
if ! ok {
return [ ] string { } , fmt . Errorf ( "no target with label %q in LabelToOutputFiles" , label )
}
2022-05-10 19:50:12 +02:00
return result , nil
2021-02-22 22:13:50 +01:00
}
2022-07-04 00:57:36 +02:00
func ( m MockBazelContext ) GetCcInfo ( label string , _ configKey ) ( cquery . CcInfo , error ) {
2023-01-23 20:04:24 +01:00
result , ok := m . LabelToCcInfo [ label ]
if ! ok {
return cquery . CcInfo { } , fmt . Errorf ( "no target with label %q in LabelToCcInfo" , label )
}
2022-05-10 19:50:12 +02:00
return result , nil
2021-04-03 00:47:09 +02:00
}
2022-07-04 00:57:36 +02:00
func ( m MockBazelContext ) GetPythonBinary ( label string , _ configKey ) ( string , error ) {
2023-01-23 20:04:24 +01:00
result , ok := m . LabelToPythonBinary [ label ]
if ! ok {
return "" , fmt . Errorf ( "no target with label %q in LabelToPythonBinary" , label )
}
2022-05-10 19:50:12 +02:00
return result , nil
2021-08-11 18:48:30 +02:00
}
2022-11-04 21:05:11 +01:00
func ( m MockBazelContext ) GetApexInfo ( label string , _ configKey ) ( cquery . ApexInfo , error ) {
2023-01-23 20:04:24 +01:00
result , ok := m . LabelToApexInfo [ label ]
if ! ok {
return cquery . ApexInfo { } , fmt . Errorf ( "no target with label %q in LabelToApexInfo" , label )
}
2022-11-04 21:07:04 +01:00
return result , nil
2022-07-27 23:51:45 +02:00
}
2022-10-07 23:44:50 +02:00
func ( m MockBazelContext ) GetCcUnstrippedInfo ( label string , _ configKey ) ( cquery . CcUnstrippedInfo , error ) {
2023-01-23 20:04:24 +01:00
result , ok := m . LabelToCcBinary [ label ]
if ! ok {
return cquery . CcUnstrippedInfo { } , fmt . Errorf ( "no target with label %q in LabelToCcBinary" , label )
}
2022-10-07 23:44:50 +02:00
return result , nil
}
2022-12-01 20:46:11 +01:00
func ( m MockBazelContext ) InvokeBazel ( _ Config , _ * Context ) error {
2020-09-29 08:23:17 +02:00
panic ( "unimplemented" )
}
2022-12-30 02:11:49 +01:00
func ( m MockBazelContext ) IsModuleNameAllowed ( _ string ) bool {
2020-09-29 08:23:17 +02:00
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 { }
}
2022-04-26 04:35:15 +02:00
func ( m MockBazelContext ) AqueryDepsets ( ) [ ] bazel . AqueryDepset {
return [ ] bazel . AqueryDepset { }
}
2020-09-29 08:23:17 +02:00
var _ BazelContext = MockBazelContext { }
2022-12-30 02:11:49 +01:00
func ( bazelCtx * mixedBuildBazelContext ) QueueBazelRequest ( label string , requestType cqueryRequest , cfgKey configKey ) {
2022-09-28 20:58:41 +02:00
key := makeCqueryKey ( label , requestType , cfgKey )
2022-05-10 19:50:12 +02:00
bazelCtx . requestMutex . Lock ( )
defer bazelCtx . requestMutex . Unlock ( )
bazelCtx . requests [ key ] = true
}
2022-12-30 02:11:49 +01:00
func ( bazelCtx * mixedBuildBazelContext ) GetOutputFiles ( label string , cfgKey configKey ) ( [ ] string , error ) {
2022-09-28 20:58:41 +02:00
key := makeCqueryKey ( label , cquery . GetOutputFiles , cfgKey )
2022-05-10 19:50:12 +02:00
if rawString , ok := bazelCtx . results [ key ] ; ok {
2021-03-11 17:08:46 +01:00
bazelOutput := strings . TrimSpace ( rawString )
2022-09-28 20:58:41 +02:00
2022-05-10 19:50:12 +02:00
return cquery . GetOutputFiles . ParseResult ( bazelOutput ) , nil
2021-02-22 22:13:50 +01:00
}
2022-05-10 19:50:12 +02:00
return nil , fmt . Errorf ( "no bazel response found for %v" , key )
2021-02-22 22:13:50 +01:00
}
2022-12-30 02:11:49 +01:00
func ( bazelCtx * mixedBuildBazelContext ) GetCcInfo ( label string , cfgKey configKey ) ( cquery . CcInfo , error ) {
2022-09-28 20:58:41 +02:00
key := makeCqueryKey ( label , cquery . GetCcInfo , cfgKey )
2022-05-10 19:50:12 +02:00
if rawString , ok := bazelCtx . results [ key ] ; ok {
bazelOutput := strings . TrimSpace ( rawString )
return cquery . GetCcInfo . ParseResult ( bazelOutput )
2021-04-03 00:47:09 +02:00
}
2022-05-10 19:50:12 +02:00
return cquery . CcInfo { } , fmt . Errorf ( "no bazel response found for %v" , key )
2021-04-03 00:47:09 +02:00
}
2022-12-30 02:11:49 +01:00
func ( bazelCtx * mixedBuildBazelContext ) GetPythonBinary ( label string , cfgKey configKey ) ( string , error ) {
2022-09-28 20:58:41 +02:00
key := makeCqueryKey ( label , cquery . GetPythonBinary , cfgKey )
2022-05-10 19:50:12 +02:00
if rawString , ok := bazelCtx . results [ key ] ; ok {
2021-08-11 18:48:30 +02:00
bazelOutput := strings . TrimSpace ( rawString )
2022-05-10 19:50:12 +02:00
return cquery . GetPythonBinary . ParseResult ( bazelOutput ) , nil
2021-08-11 18:48:30 +02:00
}
2022-05-10 19:50:12 +02:00
return "" , fmt . Errorf ( "no bazel response found for %v" , key )
}
2022-12-30 02:11:49 +01:00
func ( bazelCtx * mixedBuildBazelContext ) GetApexInfo ( label string , cfgKey configKey ) ( cquery . ApexInfo , error ) {
2022-09-28 20:58:41 +02:00
key := makeCqueryKey ( label , cquery . GetApexInfo , cfgKey )
2022-07-27 23:51:45 +02:00
if rawString , ok := bazelCtx . results [ key ] ; ok {
2022-11-09 16:05:05 +01:00
return cquery . GetApexInfo . ParseResult ( strings . TrimSpace ( rawString ) )
2022-07-27 23:51:45 +02:00
}
2022-11-04 21:05:11 +01:00
return cquery . ApexInfo { } , fmt . Errorf ( "no bazel response found for %v" , key )
2022-07-27 23:51:45 +02:00
}
2022-12-30 02:11:49 +01:00
func ( bazelCtx * mixedBuildBazelContext ) GetCcUnstrippedInfo ( label string , cfgKey configKey ) ( cquery . CcUnstrippedInfo , error ) {
2022-10-07 23:44:50 +02:00
key := makeCqueryKey ( label , cquery . GetCcUnstrippedInfo , cfgKey )
if rawString , ok := bazelCtx . results [ key ] ; ok {
2022-11-09 16:05:05 +01:00
return cquery . GetCcUnstrippedInfo . ParseResult ( strings . TrimSpace ( rawString ) )
2022-10-07 23:44:50 +02:00
}
return cquery . CcUnstrippedInfo { } , fmt . Errorf ( "no bazel response for %s" , key )
}
2022-07-04 00:57:36 +02:00
func ( n noopBazelContext ) QueueBazelRequest ( _ string , _ cqueryRequest , _ configKey ) {
2022-05-10 19:50:12 +02:00
panic ( "unimplemented" )
2021-08-11 18:48:30 +02:00
}
2022-07-04 00:57:36 +02:00
func ( n noopBazelContext ) GetOutputFiles ( _ string , _ configKey ) ( [ ] string , error ) {
2021-02-22 22:13:50 +01:00
panic ( "unimplemented" )
}
2022-07-04 00:57:36 +02:00
func ( n noopBazelContext ) GetCcInfo ( _ string , _ configKey ) ( cquery . CcInfo , error ) {
2021-03-10 02:43:32 +01:00
panic ( "unimplemented" )
}
2022-07-04 00:57:36 +02:00
func ( n noopBazelContext ) GetPythonBinary ( _ string , _ configKey ) ( string , error ) {
2021-08-11 18:48:30 +02:00
panic ( "unimplemented" )
}
2022-11-04 21:05:11 +01:00
func ( n noopBazelContext ) GetApexInfo ( _ string , _ configKey ) ( cquery . ApexInfo , error ) {
2022-07-27 23:51:45 +02:00
panic ( "unimplemented" )
}
2022-10-07 23:44:50 +02:00
func ( n noopBazelContext ) GetCcUnstrippedInfo ( _ string , _ configKey ) ( cquery . CcUnstrippedInfo , error ) {
//TODO implement me
panic ( "implement me" )
}
2022-12-01 20:46:11 +01:00
func ( n noopBazelContext ) InvokeBazel ( _ Config , _ * Context ) error {
2020-09-29 08:23:17 +02:00
panic ( "unimplemented" )
}
2020-12-10 23:19:18 +01:00
func ( m noopBazelContext ) OutputBase ( ) string {
return ""
}
2022-12-30 02:11:49 +01:00
func ( n noopBazelContext ) IsModuleNameAllowed ( _ string ) bool {
2020-09-29 08:23:17 +02:00
return false
}
2020-12-10 23:19:18 +01:00
func ( m noopBazelContext ) BuildStatementsToRegister ( ) [ ] bazel . BuildStatement {
return [ ] bazel . BuildStatement { }
}
2022-04-26 04:35:15 +02:00
func ( m noopBazelContext ) AqueryDepsets ( ) [ ] bazel . AqueryDepset {
return [ ] bazel . AqueryDepset { }
}
2022-12-14 20:32:05 +01:00
func GetBazelEnabledAndDisabledModules ( buildMode SoongBuildMode , forceEnabled map [ string ] struct { } ) ( map [ string ] bool , map [ string ] bool ) {
2022-08-19 04:04:11 +02:00
disabledModules := map [ string ] bool { }
enabledModules := map [ string ] bool { }
2022-12-07 05:27:54 +01:00
addToStringSet := func ( set map [ string ] bool , items [ ] string ) {
for _ , item := range items {
set [ item ] = true
}
}
2022-08-19 04:04:11 +02:00
2022-12-14 20:32:05 +01:00
switch buildMode {
2022-08-19 04:04:11 +02:00
case BazelProdMode :
2022-12-07 05:27:54 +01:00
addToStringSet ( enabledModules , allowlists . ProdMixedBuildsEnabledList )
2022-12-14 20:32:05 +01:00
for enabledAdHocModule := range forceEnabled {
2022-11-29 01:47:59 +01:00
enabledModules [ enabledAdHocModule ] = true
}
2022-10-18 22:10:16 +02:00
case BazelStagingMode :
2022-11-04 18:26:17 +01:00
// Staging mode includes all prod modules plus all staging modules.
2022-12-07 05:27:54 +01:00
addToStringSet ( enabledModules , allowlists . ProdMixedBuildsEnabledList )
addToStringSet ( enabledModules , allowlists . StagingMixedBuildsEnabledList )
2022-12-14 20:32:05 +01:00
for enabledAdHocModule := range forceEnabled {
2022-11-29 01:47:59 +01:00
enabledModules [ enabledAdHocModule ] = true
}
2022-08-19 04:04:11 +02:00
case BazelDevMode :
2022-12-07 05:27:54 +01:00
addToStringSet ( disabledModules , allowlists . MixedBuildsDisabledList )
2022-08-19 04:04:11 +02:00
default :
2022-12-14 20:32:05 +01:00
panic ( "Expected BazelProdMode, BazelStagingMode, or BazelDevMode" )
}
return enabledModules , disabledModules
}
func GetBazelEnabledModules ( buildMode SoongBuildMode ) [ ] string {
enabledModules , disabledModules := GetBazelEnabledAndDisabledModules ( buildMode , nil )
enabledList := make ( [ ] string , 0 , len ( enabledModules ) )
for module := range enabledModules {
if ! disabledModules [ module ] {
enabledList = append ( enabledList , module )
}
}
sort . Strings ( enabledList )
return enabledList
}
func NewBazelContext ( c * config ) ( BazelContext , error ) {
if c . BuildMode != BazelProdMode && c . BuildMode != BazelStagingMode && c . BuildMode != BazelDevMode {
2020-09-29 08:23:17 +02:00
return noopBazelContext { } , nil
}
2022-12-14 20:32:05 +01:00
enabledModules , disabledModules := GetBazelEnabledAndDisabledModules ( c . BuildMode , c . BazelModulesForceEnabledByFlag ( ) )
2022-12-07 05:27:54 +01:00
paths := bazelPaths {
soongOutDir : c . soongOutDir ,
}
var missing [ ] string
vars := [ ] struct {
name string
ptr * string
2022-12-21 16:55:33 +01:00
// True if the environment variable needs to be tracked so that changes to the variable
// cause the ninja file to be regenerated, false otherwise. False should only be set for
// environment variables that have no effect on the generated ninja file.
track bool
2022-12-07 05:27:54 +01:00
} {
2022-12-21 16:55:33 +01:00
{ "BAZEL_HOME" , & paths . homeDir , true } ,
{ "BAZEL_PATH" , & paths . bazelPath , true } ,
{ "BAZEL_OUTPUT_BASE" , & paths . outputBase , true } ,
{ "BAZEL_WORKSPACE" , & paths . workspaceDir , true } ,
{ "BAZEL_METRICS_DIR" , & paths . metricsDir , false } ,
{ "BAZEL_DEPS_FILE" , & paths . bazelDepsFile , true } ,
2022-12-07 05:27:54 +01:00
}
for _ , v := range vars {
2022-12-21 16:55:33 +01:00
if v . track {
if s := c . Getenv ( v . name ) ; len ( s ) > 1 {
* v . ptr = s
continue
}
} else if s , ok := c . env [ v . name ] ; ok {
2022-12-07 05:27:54 +01:00
* v . ptr = s
} else {
missing = append ( missing , v . name )
}
}
if len ( missing ) > 0 {
return nil , fmt . Errorf ( "missing required env vars to use bazel: %s" , missing )
2021-04-08 15:47:28 +02:00
}
2022-11-09 03:14:01 +01:00
targetBuildVariant := "user"
if c . Eng ( ) {
targetBuildVariant = "eng"
} else if c . Debuggable ( ) {
targetBuildVariant = "userdebug"
}
targetProduct := "unknown"
if c . HasDeviceProduct ( ) {
targetProduct = c . DeviceProduct ( )
}
2022-12-30 02:11:49 +01:00
return & mixedBuildBazelContext {
2022-08-20 20:48:32 +02:00
bazelRunner : & builtinBazelRunner { } ,
2022-12-07 05:27:54 +01:00
paths : & paths ,
2022-08-20 20:48:32 +02:00
requests : make ( map [ cqueryKey ] bool ) ,
2022-12-07 05:27:54 +01:00
modulesDefaultToBazel : c . BuildMode == BazelDevMode ,
2022-08-19 04:04:11 +02:00
bazelEnabledModules : enabledModules ,
2022-08-20 20:48:32 +02:00
bazelDisabledModules : disabledModules ,
2022-11-09 03:14:01 +01:00
targetProduct : targetProduct ,
targetBuildVariant : targetBuildVariant ,
2021-04-08 15:47:28 +02:00
} , nil
}
func ( p * bazelPaths ) BazelMetricsDir ( ) string {
return p . metricsDir
2020-12-12 07:24:26 +01:00
}
2022-12-30 02:11:49 +01:00
func ( context * mixedBuildBazelContext ) IsModuleNameAllowed ( moduleName string ) bool {
2022-08-20 20:48:32 +02:00
if context . bazelDisabledModules [ moduleName ] {
return false
}
if context . bazelEnabledModules [ moduleName ] {
return true
}
return context . modulesDefaultToBazel
2020-09-29 08:23:17 +02:00
}
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
2022-09-08 17:37:57 +02:00
// use *exec.Cmd as a key to get the bazelCommand, the map will be used in issueBazelCommand()
// Register createBazelCommand() invocations. Later, an
// issueBazelCommand() invocation can be mapped to the *exec.Cmd instance
// and then to the expected result via bazelCommandResults
tokens map [ * exec . Cmd ] bazelCommand
commands [ ] bazelCommand
extraFlags [ ] string
2021-04-08 15:47:28 +02:00
}
2022-12-01 20:46:11 +01:00
func ( r * mockBazelRunner ) createBazelCommand ( _ * bazelPaths , _ bazel . RunName ,
2022-09-08 17:37:57 +02:00
command bazelCommand , extraFlags ... string ) * exec . Cmd {
2021-04-08 15:47:28 +02:00
r . commands = append ( r . commands , command )
2022-05-18 00:13:28 +02:00
r . extraFlags = append ( r . extraFlags , strings . Join ( extraFlags , " " ) )
2022-09-08 17:37:57 +02:00
cmd := & exec . Cmd { }
if r . tokens == nil {
r . tokens = make ( map [ * exec . Cmd ] bazelCommand )
}
r . tokens [ cmd ] = command
return cmd
}
func ( r * mockBazelRunner ) issueBazelCommand ( bazelCmd * exec . Cmd ) ( string , string , error ) {
if command , ok := r . tokens [ bazelCmd ] ; ok {
return r . bazelCommandResults [ command ] , "" , nil
2021-04-08 15:47:28 +02:00
}
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.
2022-09-08 17:37:57 +02:00
func ( r * builtinBazelRunner ) issueBazelCommand ( bazelCmd * exec . Cmd ) ( string , string , error ) {
stderr := & bytes . Buffer { }
bazelCmd . Stderr = stderr
if output , err := bazelCmd . Output ( ) ; err != nil {
return "" , string ( stderr . Bytes ( ) ) ,
2022-12-01 20:46:11 +01:00
fmt . Errorf ( "bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---" ,
err , bazelCmd , strings . Join ( bazelCmd . Env , "\n" ) , stderr )
2022-09-08 17:37:57 +02:00
} else {
return string ( output ) , string ( stderr . Bytes ( ) ) , nil
}
}
func ( r * builtinBazelRunner ) createBazelCommand ( paths * bazelPaths , runName bazel . RunName , command bazelCommand ,
extraFlags ... string ) * exec . Cmd {
2021-08-27 17:59:39 +02:00
cmdFlags := [ ] string {
"--output_base=" + absolutePath ( paths . outputBase ) ,
command . command ,
2022-07-27 23:51:45 +02:00
command . expression ,
2022-07-04 00:57:36 +02:00
// TODO(asmundak): is it needed in every build?
2022-07-27 23:51:45 +02:00
"--profile=" + shared . BazelMetricsFilename ( paths , runName ) ,
2022-07-04 00:57:36 +02: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.
fmt . Sprintf ( "--extra_toolchains=%s" , "//prebuilts/clang/host/linux-x86:all" ) ,
2022-11-09 03:14:01 +01:00
// We don't need to set --host_platforms because it's set in bazelrc files
// that the bazel shell script wrapper passes
2022-07-04 00:57:36 +02:00
// Explicitly disable downloading rules (such as canonical C++ and Java rules) from the network.
"--experimental_repository_disable_download" ,
// Suppress noise
"--ui_event_filters=-INFO" ,
2022-11-07 21:53:38 +01:00
"--noshow_progress" ,
"--norun_validations" ,
}
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 ( ) )
2022-07-27 23:51:45 +02:00
extraEnv := [ ] string {
"HOME=" + paths . homeDir ,
2021-05-11 16:54:29 +02:00
pwdPrefix ( ) ,
2022-07-27 23:51:45 +02:00
"BUILD_DIR=" + absolutePath ( paths . soongOutDir ) ,
2022-10-24 15:38:11 +02:00
// Make OUT_DIR absolute here so build/bazel/bin/bazel uses the correct
2021-06-01 13:19:53 +02:00
// OUT_DIR at <root>/out, instead of <root>/out/soong/workspace/out.
2022-07-27 23:51:45 +02:00
"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.
2022-07-27 23:51:45 +02:00
"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1" ,
}
bazelCmd . Env = append ( os . Environ ( ) , extraEnv ... )
2020-09-29 08:23:17 +02:00
2022-09-08 17:37:57 +02:00
return bazelCmd
}
func printableCqueryCommand ( bazelCmd * exec . Cmd ) string {
outputString := strings . Join ( bazelCmd . Env , " " ) + " \"" + strings . Join ( bazelCmd . Args , "\" \"" ) + "\""
return outputString
2020-09-29 08:23:17 +02:00
}
2022-12-30 02:11:49 +01:00
func ( context * mixedBuildBazelContext ) 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 ) :
2022-11-09 03:14:01 +01:00
if attr . os == "android" and attr . arch == "target" :
target = "{PRODUCT}-{VARIANT}"
else :
target = "{PRODUCT}-{VARIANT}_%s_%s" % ( attr . os , attr . arch )
2021-02-22 22:13:50 +01:00
return {
2022-11-09 03:14:01 +01:00
"//command_line_option:platforms" : "@soong_injection//product_config_platforms/products/{PRODUCT}-{VARIANT}:%s" % target ,
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 ) ,
2021-10-15 00:43:51 +02:00
"os" : attr . string ( mandatory = True ) ,
"deps" : attr . label_list ( cfg = _config_node_transition , allow_files = True ) ,
2021-03-30 03:09:24 +02:00
"_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
`
2022-11-09 03:14:01 +01:00
productReplacer := strings . NewReplacer (
"{PRODUCT}" , context . targetProduct ,
"{VARIANT}" , context . targetBuildVariant )
return [ ] byte ( productReplacer . Replace ( contents ) )
2020-10-23 22:48:08 +02:00
}
2022-12-30 02:11:49 +01:00
func ( context * mixedBuildBazelContext ) 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 ] ,
2022-12-12 13:20:58 +01:00
testonly = True , # Unblocks testonly deps .
2020-10-23 22:48:08 +02:00
)
2020-12-10 23:19:18 +01:00
phony_root ( name = "phonyroot" ,
deps = [ ":buildroot" ] ,
2022-12-12 13:20:58 +01:00
testonly = True , # Unblocks testonly deps .
2020-12-10 23:19:18 +01:00
)
2020-10-23 22:48:08 +02:00
`
2021-03-30 03:09:24 +02:00
configNodeFormatString := `
config_node ( name = "%s" ,
arch = "%s" ,
2021-10-15 00:43:51 +02:00
os = "%s" ,
2021-03-30 03:09:24 +02:00
deps = [ % s ] ,
2022-12-12 13:20:58 +01:00
testonly = True , # Unblocks testonly deps .
2021-03-30 03:09:24 +02:00
)
`
configNodesSection := ""
2021-10-15 00:43:51 +02:00
labelsByConfig := map [ string ] [ ] string { }
2022-06-23 19:45:24 +02:00
for val := range context . requests {
2021-04-20 13:01:07 +02:00
labelString := fmt . Sprintf ( "\"@%s\"" , val . label )
2021-10-15 00:43:51 +02:00
configString := getConfigString ( val )
labelsByConfig [ configString ] = append ( labelsByConfig [ configString ] , labelString )
2021-03-30 03:09:24 +02:00
}
bp2build: allowlist //external/libcap/...
This builds cap_names.list.h, which uses an eponymous filegroup
"generate_cap_names_list.awk" in Soong, but uses the file target
directly in Bazel.
This also improve filegroup support for mixed builds, by issuing a
cquery call _without_ arch. Filegroups in Soong don't have configurable
properties, so don't generate Bazel filegroups into buildroot's
config_nodes (which was x86_64 by default).
The mixed_build_root now looks like this:
```
config_node(...)
config_node(...)
config_node(...)
config_node(...)
...
filegroup(name = "common",
srcs = ["@//bionic/linker:linker_sources_x86",
"@//bionic/libc:kernel_input_headers",
"@//system/timezone/apex:com.android.tzdata-androidManifest",
"@//external/libcap:generate_cap_names_list.awk",
"@//bionic/linker:linker_sources_arm64",
"@//bionic/linker:linker_sources",
"@//bionic/libc:libc_sources_shared_arm",
"@//bionic/linker:linker_sources_x86_64",
"@//bionic/libc:all_kernel_uapi_headers",
"@//build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal-file_contexts",
"@//system/core/libcutils:android_filesystem_config_header",
"@//bionic/libc:libc_sources_static",
"@//bionic/linker:linker_sources_arm",
"@//bionic/libc/tools:bionic-gensyscalls",
"@//bionic/tools:bionic-generate-version-script",
"@//bionic/libc:libc_sources_shared"],
)
mixed_build_root(name = "buildroot",
deps = [":x86",
":arm64",
":arm",
":common",
":x86_64"],
)
```
Test: CI
Fixes: 198595323
Fixes: 198235838
Change-Id: I6df9a14da556cf358d96e6a99b514f66a2638295
2021-09-02 14:11:49 +02:00
allLabels := [ ] string { }
2021-10-15 00:43:51 +02:00
for configString , labels := range labelsByConfig {
configTokens := strings . Split ( configString , "|" )
if len ( configTokens ) != 2 {
panic ( fmt . Errorf ( "Unexpected config string format: %s" , configString ) )
bp2build: allowlist //external/libcap/...
This builds cap_names.list.h, which uses an eponymous filegroup
"generate_cap_names_list.awk" in Soong, but uses the file target
directly in Bazel.
This also improve filegroup support for mixed builds, by issuing a
cquery call _without_ arch. Filegroups in Soong don't have configurable
properties, so don't generate Bazel filegroups into buildroot's
config_nodes (which was x86_64 by default).
The mixed_build_root now looks like this:
```
config_node(...)
config_node(...)
config_node(...)
config_node(...)
...
filegroup(name = "common",
srcs = ["@//bionic/linker:linker_sources_x86",
"@//bionic/libc:kernel_input_headers",
"@//system/timezone/apex:com.android.tzdata-androidManifest",
"@//external/libcap:generate_cap_names_list.awk",
"@//bionic/linker:linker_sources_arm64",
"@//bionic/linker:linker_sources",
"@//bionic/libc:libc_sources_shared_arm",
"@//bionic/linker:linker_sources_x86_64",
"@//bionic/libc:all_kernel_uapi_headers",
"@//build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal-file_contexts",
"@//system/core/libcutils:android_filesystem_config_header",
"@//bionic/libc:libc_sources_static",
"@//bionic/linker:linker_sources_arm",
"@//bionic/libc/tools:bionic-gensyscalls",
"@//bionic/tools:bionic-generate-version-script",
"@//bionic/libc:libc_sources_shared"],
)
mixed_build_root(name = "buildroot",
deps = [":x86",
":arm64",
":arm",
":common",
":x86_64"],
)
```
Test: CI
Fixes: 198595323
Fixes: 198235838
Change-Id: I6df9a14da556cf358d96e6a99b514f66a2638295
2021-09-02 14:11:49 +02:00
}
2021-10-15 00:43:51 +02:00
archString := configTokens [ 0 ]
osString := configTokens [ 1 ]
targetString := fmt . Sprintf ( "%s_%s" , osString , archString )
allLabels = append ( allLabels , fmt . Sprintf ( "\":%s\"" , targetString ) )
labelsString := strings . Join ( labels , ",\n " )
configNodesSection += fmt . Sprintf ( configNodeFormatString , targetString , archString , osString , labelsString )
2020-10-23 22:48:08 +02:00
}
bp2build: allowlist //external/libcap/...
This builds cap_names.list.h, which uses an eponymous filegroup
"generate_cap_names_list.awk" in Soong, but uses the file target
directly in Bazel.
This also improve filegroup support for mixed builds, by issuing a
cquery call _without_ arch. Filegroups in Soong don't have configurable
properties, so don't generate Bazel filegroups into buildroot's
config_nodes (which was x86_64 by default).
The mixed_build_root now looks like this:
```
config_node(...)
config_node(...)
config_node(...)
config_node(...)
...
filegroup(name = "common",
srcs = ["@//bionic/linker:linker_sources_x86",
"@//bionic/libc:kernel_input_headers",
"@//system/timezone/apex:com.android.tzdata-androidManifest",
"@//external/libcap:generate_cap_names_list.awk",
"@//bionic/linker:linker_sources_arm64",
"@//bionic/linker:linker_sources",
"@//bionic/libc:libc_sources_shared_arm",
"@//bionic/linker:linker_sources_x86_64",
"@//bionic/libc:all_kernel_uapi_headers",
"@//build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal-file_contexts",
"@//system/core/libcutils:android_filesystem_config_header",
"@//bionic/libc:libc_sources_static",
"@//bionic/linker:linker_sources_arm",
"@//bionic/libc/tools:bionic-gensyscalls",
"@//bionic/tools:bionic-generate-version-script",
"@//bionic/libc:libc_sources_shared"],
)
mixed_build_root(name = "buildroot",
deps = [":x86",
":arm64",
":arm",
":common",
":x86_64"],
)
```
Test: CI
Fixes: 198595323
Fixes: 198235838
Change-Id: I6df9a14da556cf358d96e6a99b514f66a2638295
2021-09-02 14:11:49 +02:00
return [ ] byte ( fmt . Sprintf ( formatString , configNodesSection , strings . Join ( allLabels , ",\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.
2022-12-30 02:11:49 +01:00
// The contents of this file depend on the mixedBuildBazelContext's requests; requests are enumerated
2021-03-10 02:43:32 +01:00
// and grouped by their request type. The data retrieved for each label depends on its
// request type.
2022-12-30 02:11:49 +01:00
func ( context * mixedBuildBazelContext ) cqueryStarlarkFileContents ( ) [ ] byte {
2021-04-02 19:37:39 +02:00
requestTypeToCqueryIdEntries := map [ cqueryRequest ] [ ] string { }
2022-06-23 19:45:24 +02:00
for val := range context . requests {
2021-03-11 17:08:46 +01:00
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 := `
2022-11-22 23:08:59 +01:00
def % s ( target , id_string ) :
2021-03-11 17:08:46 +01:00
% s
`
mainSwitchSectionFormatString := `
if id_string in % s :
2022-11-22 23:08:59 +01:00
return id_string + ">>" + % s ( target , id_string )
2021-03-11 17:08:46 +01:00
`
2021-02-22 22:13:50 +01:00
2022-02-05 03:37:39 +01: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
2022-09-03 00:37:40 +02:00
# a drop - in replacement for json . encode ( ) , not available in cquery environment
# TODO ( cparsons ) : bring json module in and remove this function
def json_encode ( input ) :
# Avoiding recursion by limiting
# - a dict to contain anything except a dict
# - a list to contain only primitives
def encode_primitive ( p ) :
t = type ( p )
if t == "string" or t == "int" :
return repr ( p )
2022-11-09 03:14:01 +01:00
fail ( "unsupported value '%s' of type '%s'" % ( p , type ( p ) ) )
2022-09-03 00:37:40 +02:00
def encode_list ( list ) :
2022-11-09 03:14:01 +01:00
return "[%s]" % ", " . join ( [ encode_primitive ( item ) for item in list ] )
2022-09-03 00:37:40 +02:00
def encode_list_or_primitive ( v ) :
return encode_list ( v ) if type ( v ) == "list" else encode_primitive ( v )
if type ( input ) == "dict" :
# TODO ( juu ) : the result is read line by line so can ' t use '\n' yet
2022-11-09 03:14:01 +01:00
kv_pairs = [ ( "%s: %s" % ( encode_primitive ( k ) , encode_list_or_primitive ( v ) ) ) for ( k , v ) in input . items ( ) ]
return "{ %s }" % ", " . join ( kv_pairs )
2022-09-03 00:37:40 +02:00
else :
return encode_list_or_primitive ( input )
2022-11-09 03:14:01 +01:00
{ LABEL_REGISTRATION_MAP_SECTION }
2021-02-22 22:13:50 +01:00
2022-11-09 03:14:01 +01:00
{ FUNCTION_DEF_SECTION }
2021-02-22 22:13:50 +01:00
def get_arch ( target ) :
2021-10-15 00:43:51 +02:00
# TODO ( b / 199363072 ) : filegroups and file targets aren ' t associated with any
# specific platform architecture in mixed builds . This is consistent with how
# Soong treats filegroups , but it may not be the case with manually - written
# filegroup BUILD targets .
2021-02-22 22:13:50 +01:00
buildoptions = build_options ( target )
2021-10-07 14:02:23 +02:00
if buildoptions == None :
# File targets do not have buildoptions . File targets aren ' t associated with
2021-10-15 00:43:51 +02:00
# any specific platform architecture in mixed builds , so use the host .
return "x86_64|linux"
2022-11-09 03:14:01 +01:00
platforms = buildoptions [ "//command_line_option:platforms" ]
2021-02-22 22:13:50 +01:00
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 ) )
2022-11-09 03:14:01 +01:00
platform_name = platforms [ 0 ] . name
2021-02-22 22:13:50 +01:00
if platform_name == "host" :
return "HOST"
2022-11-09 03:14:01 +01:00
if not platform_name . startswith ( "{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}" ) :
fail ( "expected platform name of the form '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_android_<arch>' or '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str ( platforms ) )
platform_name = platform_name . removeprefix ( "{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}" ) . removeprefix ( "_" )
if not platform_name :
return "target|android"
2021-06-04 21:03:47 +02:00
elif platform_name . startswith ( "android_" ) :
2022-11-09 03:14:01 +01:00
return platform_name . removeprefix ( "android_" ) + "|android"
2021-06-04 21:03:47 +02:00
elif platform_name . startswith ( "linux_" ) :
2022-11-09 03:14:01 +01:00
return platform_name . removeprefix ( "linux_" ) + "|linux"
2021-06-04 21:03:47 +02:00
else :
2022-11-09 03:14:01 +01:00
fail ( "expected platform name of the form '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_android_<arch>' or '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str ( platforms ) )
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 )
2022-09-28 20:58:41 +02:00
# TODO ( b / 248106697 ) : Remove once Bazel is updated to always normalize labels .
if id_string . startswith ( "//" ) :
id_string = "@" + id_string
2022-11-09 03:14:01 +01:00
{ MAIN_SWITCH_SECTION }
2021-03-11 17:08:46 +01:00
# This target was not requested via cquery , and thus must be a dependency
# of a requested target .
return id_string + ">>NONE"
`
2022-11-09 03:14:01 +01:00
replacer := strings . NewReplacer (
"{TARGET_PRODUCT}" , context . targetProduct ,
"{TARGET_BUILD_VARIANT}" , context . targetBuildVariant ,
"{LABEL_REGISTRATION_MAP_SECTION}" , labelRegistrationMapSection ,
"{FUNCTION_DEF_SECTION}" , functionDefSection ,
"{MAIN_SWITCH_SECTION}" , mainSwitchSection )
return [ ] byte ( replacer . Replace ( formatString ) )
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
}
2022-11-17 00:28:18 +01:00
const buildrootLabel = "@soong_injection//mixed_builds:buildroot"
var (
cqueryCmd = bazelCommand { "cquery" , fmt . Sprintf ( "deps(%s, 2)" , buildrootLabel ) }
aqueryCmd = bazelCommand { "aquery" , fmt . Sprintf ( "deps(%s)" , buildrootLabel ) }
buildCmd = bazelCommand { "build" , "@soong_injection//mixed_builds:phonyroot" }
)
2020-09-29 08:23:17 +02:00
// Issues commands to Bazel to receive results for all cquery requests
// queued in the BazelContext.
2022-12-30 02:11:49 +01:00
func ( context * mixedBuildBazelContext ) InvokeBazel ( config Config , ctx * Context ) error {
2022-11-17 00:28:18 +01:00
if ctx != nil {
ctx . EventHandler . Begin ( "bazel" )
defer ctx . EventHandler . End ( "bazel" )
}
if metricsDir := context . paths . BazelMetricsDir ( ) ; metricsDir != "" {
if err := os . MkdirAll ( metricsDir , 0777 ) ; err != nil {
return err
}
}
2020-09-29 08:23:17 +02:00
context . results = make ( map [ cqueryKey ] string )
2022-11-17 00:28:18 +01:00
if err := context . runCquery ( ctx ) ; err != nil {
return err
}
if err := context . runAquery ( config , ctx ) ; err != nil {
return err
}
if err := context . generateBazelSymlinks ( ctx ) ; err != nil {
return err
}
// Clear requests.
context . requests = map [ cqueryKey ] bool { }
return nil
}
2020-09-29 08:23:17 +02:00
2022-12-30 02:11:49 +01:00
func ( context * mixedBuildBazelContext ) runCquery ( ctx * Context ) error {
2022-11-17 00:28:18 +01:00
if ctx != nil {
ctx . EventHandler . Begin ( "cquery" )
defer ctx . EventHandler . End ( "cquery" )
}
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 )
2022-11-16 17:59:23 +01:00
if err != nil {
return err
}
2021-04-20 13:01:07 +02:00
}
2022-12-01 20:46:11 +01:00
if err := os . WriteFile ( filepath . Join ( soongInjectionPath , "WORKSPACE.bazel" ) , [ ] byte { } , 0666 ) ; err != nil {
2020-11-17 21:41:01 +01:00
return err
}
2022-12-01 20:46:11 +01:00
if err := os . WriteFile ( filepath . Join ( mixedBuildsPath , "main.bzl" ) , context . mainBzlFileContents ( ) , 0666 ) ; err != nil {
2020-10-23 22:48:08 +02:00
return err
}
2022-12-01 20:46:11 +01:00
if err := os . WriteFile ( filepath . Join ( mixedBuildsPath , "BUILD.bazel" ) , context . mainBuildFileContents ( ) , 0666 ) ; err != nil {
2020-10-23 22:48:08 +02:00
return err
}
2021-04-20 13:01:07 +02:00
cqueryFileRelpath := filepath . Join ( context . paths . injectedFilesDir ( ) , "buildroot.cquery" )
2022-12-01 20:46:11 +01:00
if err := os . WriteFile ( absolutePath ( cqueryFileRelpath ) , context . cqueryStarlarkFileContents ( ) , 0666 ) ; err != nil {
2020-10-23 22:48:08 +02:00
return err
}
bp2build: allowlist //external/libcap/...
This builds cap_names.list.h, which uses an eponymous filegroup
"generate_cap_names_list.awk" in Soong, but uses the file target
directly in Bazel.
This also improve filegroup support for mixed builds, by issuing a
cquery call _without_ arch. Filegroups in Soong don't have configurable
properties, so don't generate Bazel filegroups into buildroot's
config_nodes (which was x86_64 by default).
The mixed_build_root now looks like this:
```
config_node(...)
config_node(...)
config_node(...)
config_node(...)
...
filegroup(name = "common",
srcs = ["@//bionic/linker:linker_sources_x86",
"@//bionic/libc:kernel_input_headers",
"@//system/timezone/apex:com.android.tzdata-androidManifest",
"@//external/libcap:generate_cap_names_list.awk",
"@//bionic/linker:linker_sources_arm64",
"@//bionic/linker:linker_sources",
"@//bionic/libc:libc_sources_shared_arm",
"@//bionic/linker:linker_sources_x86_64",
"@//bionic/libc:all_kernel_uapi_headers",
"@//build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal-file_contexts",
"@//system/core/libcutils:android_filesystem_config_header",
"@//bionic/libc:libc_sources_static",
"@//bionic/linker:linker_sources_arm",
"@//bionic/libc/tools:bionic-gensyscalls",
"@//bionic/tools:bionic-generate-version-script",
"@//bionic/libc:libc_sources_shared"],
)
mixed_build_root(name = "buildroot",
deps = [":x86",
":arm64",
":arm",
":common",
":x86_64"],
)
```
Test: CI
Fixes: 198595323
Fixes: 198235838
Change-Id: I6df9a14da556cf358d96e6a99b514f66a2638295
2021-09-02 14:11:49 +02:00
2022-09-08 17:37:57 +02:00
cqueryCommandWithFlag := context . createBazelCommand ( context . paths , bazel . CqueryBuildRootRunName , cqueryCmd ,
2022-07-04 00:57:36 +02:00
"--output=starlark" , "--starlark:file=" + absolutePath ( cqueryFileRelpath ) )
2022-11-16 17:59:23 +01:00
cqueryOutput , cqueryErrorMessage , cqueryErr := context . issueBazelCommand ( cqueryCommandWithFlag )
if cqueryErr != nil {
return cqueryErr
2021-02-22 22:13:50 +01:00
}
2022-09-08 17:37:57 +02:00
cqueryCommandPrint := fmt . Sprintf ( "cquery command line:\n %s \n\n\n" , printableCqueryCommand ( cqueryCommandWithFlag ) )
2022-12-01 20:46:11 +01:00
if err := os . WriteFile ( filepath . Join ( soongInjectionPath , "cquery.out" ) , [ ] byte ( cqueryCommandPrint + cqueryOutput ) , 0666 ) ; err != nil {
2020-10-23 22:48:08 +02:00
return err
}
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 ]
}
}
2022-03-02 21:27:49 +01:00
for val := range context . requests {
2021-02-22 22:13:50 +01:00
if cqueryResult , ok := cqueryResults [ getCqueryId ( val ) ] ; ok {
2022-03-02 21:27:49 +01:00
context . results [ val ] = 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]" ,
2022-11-16 17:59:23 +01:00
getCqueryId ( val ) , cqueryOutput , cqueryErrorMessage )
2020-09-29 08:23:17 +02:00
}
}
2022-11-17 00:28:18 +01:00
return nil
}
2020-09-29 08:23:17 +02:00
2022-12-30 02:11:49 +01:00
func ( context * mixedBuildBazelContext ) runAquery ( config Config , ctx * Context ) error {
2022-11-17 00:28:18 +01:00
if ctx != nil {
ctx . EventHandler . Begin ( "aquery" )
defer ctx . EventHandler . End ( "aquery" )
}
2020-12-10 23:19:18 +01:00
// Issue an aquery command to retrieve action information about the bazel build tree.
//
2022-07-04 00:57:36 +02: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.
2022-10-27 20:41:15 +02:00
extraFlags := [ ] string { "--output=proto" , "--include_file_write_contents" }
2022-05-18 00:13:28 +02:00
if Bool ( config . productVariables . ClangCoverage ) {
2022-07-04 00:57:36 +02:00
extraFlags = append ( extraFlags , "--collect_code_coverage" )
paths := make ( [ ] string , 0 , 2 )
if p := config . productVariables . NativeCoveragePaths ; len ( p ) > 0 {
2022-12-01 20:46:11 +01:00
for i := range p {
2022-11-16 17:59:23 +01:00
// TODO(b/259404593) convert path wildcard to regex values
if p [ i ] == "*" {
p [ i ] = ".*"
}
}
2022-07-04 00:57:36 +02:00
paths = append ( paths , JoinWithPrefixAndSeparator ( p , "+" , "," ) )
}
if p := config . productVariables . NativeCoverageExcludePaths ; len ( p ) > 0 {
paths = append ( paths , JoinWithPrefixAndSeparator ( p , "-" , "," ) )
}
if len ( paths ) > 0 {
extraFlags = append ( extraFlags , "--instrumentation_filter=" + strings . Join ( paths , "," ) )
2022-05-18 00:13:28 +02:00
}
}
2022-11-17 00:28:18 +01:00
aqueryOutput , _ , err := context . issueBazelCommand ( context . createBazelCommand ( context . paths , bazel . AqueryBuildRootRunName , aqueryCmd ,
extraFlags ... ) )
if err != nil {
2021-01-15 18:22:41 +01:00
return err
}
2022-11-17 00:28:18 +01:00
context . buildStatements , context . depsets , err = bazel . AqueryBuildStatements ( [ ] byte ( aqueryOutput ) )
return err
}
2020-12-10 23:19:18 +01:00
2022-12-30 02:11:49 +01:00
func ( context * mixedBuildBazelContext ) generateBazelSymlinks ( ctx * Context ) error {
2022-11-17 00:28:18 +01:00
if ctx != nil {
ctx . EventHandler . Begin ( "symlinks" )
defer ctx . EventHandler . End ( "symlinks" )
}
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.
2022-11-17 00:28:18 +01:00
_ , _ , err := context . issueBazelCommand ( context . createBazelCommand ( context . paths , bazel . BazelBuildPhonyRootRunName , buildCmd ) )
return err
2020-09-29 08:23:17 +02:00
}
2020-10-13 05:44:08 +02:00
2022-12-30 02:11:49 +01:00
func ( context * mixedBuildBazelContext ) BuildStatementsToRegister ( ) [ ] bazel . BuildStatement {
2020-12-10 23:19:18 +01:00
return context . buildStatements
}
2022-12-30 02:11:49 +01:00
func ( context * mixedBuildBazelContext ) AqueryDepsets ( ) [ ] bazel . AqueryDepset {
2022-04-26 04:35:15 +02:00
return context . depsets
}
2022-12-30 02:11:49 +01:00
func ( context * mixedBuildBazelContext ) 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.
2022-08-20 20:48:32 +02:00
if ! ctx . Config ( ) . IsMixedBuildsEnabled ( ) {
2020-12-10 23:19:18 +01:00
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 )
2022-12-01 20:46:11 +01:00
data , err := os . ReadFile ( bazelBuildList )
2020-12-10 23:19:18 +01:00
if err != nil {
ctx . Errorf ( err . Error ( ) )
}
files := strings . Split ( strings . TrimSpace ( string ( data ) ) , "\n" )
for _ , file := range files {
ctx . AddNinjaFileDeps ( file )
}
2022-04-26 04:35:15 +02:00
for _ , depset := range ctx . Config ( ) . BazelContext . AqueryDepsets ( ) {
var outputs [ ] Path
2022-11-22 23:11:30 +01:00
var orderOnlies [ ] Path
2022-05-12 22:43:01 +02:00
for _ , depsetDepHash := range depset . TransitiveDepSetHashes {
otherDepsetName := bazelDepsetName ( depsetDepHash )
2022-04-26 04:35:15 +02:00
outputs = append ( outputs , PathForPhony ( ctx , otherDepsetName ) )
}
for _ , artifactPath := range depset . DirectArtifacts {
2022-11-22 23:11:30 +01:00
pathInBazelOut := PathForBazelOut ( ctx , artifactPath )
if artifactPath == "bazel-out/volatile-status.txt" {
// See https://bazel.build/docs/user-manual#workspace-status
orderOnlies = append ( orderOnlies , pathInBazelOut )
} else {
outputs = append ( outputs , pathInBazelOut )
}
2022-04-26 04:35:15 +02:00
}
2022-05-12 22:43:01 +02:00
thisDepsetName := bazelDepsetName ( depset . ContentHash )
2022-04-26 04:35:15 +02:00
ctx . Build ( pctx , BuildParams {
Rule : blueprint . Phony ,
Outputs : [ ] WritablePath { PathForPhony ( ctx , thisDepsetName ) } ,
Implicits : outputs ,
2022-11-22 23:11:30 +01:00
OrderOnly : orderOnlies ,
2022-04-26 04:35:15 +02:00
} )
}
2022-06-22 17:20:50 +02:00
executionRoot := path . Join ( ctx . Config ( ) . BazelContext . OutputBase ( ) , "execroot" , "__main__" )
bazelOutDir := path . Join ( executionRoot , "bazel-out" )
2020-12-10 23:19:18 +01:00
for index , buildStatement := range ctx . Config ( ) . BazelContext . BuildStatementsToRegister ( ) {
2022-06-09 01:36:16 +02:00
if len ( buildStatement . Command ) > 0 {
rule := NewRuleBuilder ( pctx , ctx )
createCommand ( rule . Command ( ) , buildStatement , executionRoot , bazelOutDir , ctx )
desc := fmt . Sprintf ( "%s: %s" , buildStatement . Mnemonic , buildStatement . OutputPaths )
rule . Build ( fmt . Sprintf ( "bazel %d" , index ) , desc )
continue
}
// Certain actions returned by aquery (for instance FileWrite) do not contain a command
// and thus require special treatment. If BuildStatement were an interface implementing
// buildRule(ctx) function, the code here would just call it.
// Unfortunately, the BuildStatement is defined in
// the 'bazel' package, which cannot depend on 'android' package where ctx is defined,
// because this would cause circular dependency. So, until we move aquery processing
// to the 'android' package, we need to handle special cases here.
2023-01-27 16:55:34 +01:00
switch buildStatement . Mnemonic {
case "FileWrite" , "SourceSymlinkManifest" :
2022-12-16 19:56:24 +01:00
out := PathForBazelOut ( ctx , buildStatement . OutputPaths [ 0 ] )
WriteFileRuleVerbatim ( ctx , out , buildStatement . FileContents )
2023-01-27 16:55:34 +01:00
case "SymlinkTree" :
2022-07-03 23:55:58 +02:00
// build-runfiles arguments are the manifest file and the target directory
// where it creates the symlink tree according to this manifest (and then
// writes the MANIFEST file to it).
outManifest := PathForBazelOut ( ctx , buildStatement . OutputPaths [ 0 ] )
outManifestPath := outManifest . String ( )
if ! strings . HasSuffix ( outManifestPath , "MANIFEST" ) {
panic ( "the base name of the symlink tree action should be MANIFEST, got " + outManifestPath )
}
outDir := filepath . Dir ( outManifestPath )
ctx . Build ( pctx , BuildParams {
Rule : buildRunfilesRule ,
Output : outManifest ,
Inputs : [ ] Path { PathForBazelOut ( ctx , buildStatement . InputPaths [ 0 ] ) } ,
Description : "symlink tree for " + outDir ,
Args : map [ string ] string {
"outDir" : outDir ,
} ,
} )
2023-01-27 16:55:34 +01:00
default :
2021-04-06 18:17:33 +02:00
panic ( fmt . Sprintf ( "unhandled build statement: %v" , buildStatement ) )
2021-02-22 22:13:50 +01:00
}
2022-06-22 17:20:50 +02:00
}
}
2021-06-04 21:03:47 +02:00
2022-06-22 17:20:50 +02:00
// Register bazel-owned build statements (obtained from the aquery invocation).
2022-12-07 01:27:17 +01:00
func createCommand ( cmd * RuleBuilderCommand , buildStatement bazel . BuildStatement , executionRoot string , bazelOutDir string , ctx BuilderContext ) {
2022-06-22 17:20:50 +02:00
// executionRoot is the action cwd.
cmd . Text ( fmt . Sprintf ( "cd '%s' &&" , executionRoot ) )
2020-12-10 23:19:18 +01:00
2022-06-22 17:20:50 +02:00
// Remove old outputs, as some actions might not rerun if the outputs are detected.
if len ( buildStatement . OutputPaths ) > 0 {
2022-11-07 16:02:48 +01:00
cmd . Text ( "rm -rf" ) // -r because outputs can be Bazel dir/tree artifacts.
2020-12-10 23:19:18 +01:00
for _ , outputPath := range buildStatement . OutputPaths {
2022-06-02 20:23:02 +02:00
cmd . Text ( fmt . Sprintf ( "'%s'" , outputPath ) )
2022-04-26 04:35:15 +02:00
}
2022-06-22 17:20:50 +02:00
cmd . Text ( "&&" )
}
2020-12-10 23:19:18 +01:00
2022-06-22 17:20:50 +02:00
for _ , pair := range buildStatement . Env {
// Set per-action env variables, if any.
cmd . Flag ( pair . Key + "=" + pair . Value )
}
2021-03-25 21:42:37 +01:00
2022-06-22 17:20:50 +02:00
// The actual Bazel action.
2022-12-07 01:27:17 +01:00
if len ( buildStatement . Command ) > 16 * 1024 {
commandFile := PathForBazelOut ( ctx , buildStatement . OutputPaths [ 0 ] + ".sh" )
WriteFileRule ( ctx , commandFile , buildStatement . Command )
cmd . Text ( "bash" ) . Text ( buildStatement . OutputPaths [ 0 ] + ".sh" ) . Implicit ( commandFile )
} else {
cmd . Text ( buildStatement . Command )
}
2021-06-08 21:04:11 +02:00
2022-06-22 17:20:50 +02:00
for _ , outputPath := range buildStatement . OutputPaths {
cmd . ImplicitOutput ( PathForBazelOut ( ctx , outputPath ) )
}
for _ , inputPath := range buildStatement . InputPaths {
cmd . Implicit ( PathForBazelOut ( ctx , inputPath ) )
}
for _ , inputDepsetHash := range buildStatement . InputDepsetHashes {
otherDepsetName := bazelDepsetName ( inputDepsetHash )
cmd . Implicit ( PathForPhony ( ctx , otherDepsetName ) )
}
2020-12-10 23:19:18 +01:00
2022-06-22 17:20:50 +02:00
if depfile := buildStatement . Depfile ; depfile != nil {
// The paths in depfile are relative to `executionRoot`.
// Hence, they need to be corrected by replacing "bazel-out"
// with the full `bazelOutDir`.
// Otherwise, implicit outputs and implicit inputs under "bazel-out/"
// would be deemed missing.
// (Note: The regexp uses a capture group because the version of sed
// does not support a look-behind pattern.)
replacement := fmt . Sprintf ( ` && sed -i'' -E 's@(^|\s|")bazel-out/@\1%s/@g' '%s' ` ,
bazelOutDir , * depfile )
cmd . Text ( replacement )
cmd . ImplicitDepFile ( PathForBazelOut ( ctx , * depfile ) )
}
for _ , symlinkPath := range buildStatement . SymlinkPaths {
cmd . ImplicitSymlinkOutput ( PathForBazelOut ( ctx , symlinkPath ) )
2020-10-13 05:44:08 +02:00
}
}
2021-02-22 22:13:50 +01:00
func getCqueryId ( key cqueryKey ) string {
2021-10-15 00:43:51 +02:00
return key . label + "|" + getConfigString ( key )
2021-02-22 22:13:50 +01:00
}
2021-10-15 00:43:51 +02:00
func getConfigString ( key cqueryKey ) string {
2022-03-18 20:55:04 +01:00
arch := key . configKey . arch
2021-10-15 00:43:51 +02:00
if len ( arch ) == 0 || arch == "common" {
2022-06-08 21:10:36 +02:00
if key . configKey . osType . Class == Device {
// For the generic Android, the expected result is "target|android", which
// corresponds to the product_variable_config named "android_target" in
// build/bazel/platforms/BUILD.bazel.
arch = "target"
} else {
// Use host platform, which is currently hardcoded to be x86_64.
arch = "x86_64"
}
2021-10-15 00:43:51 +02:00
}
2022-06-22 17:01:55 +02:00
osName := key . configKey . osType . Name
2022-12-21 00:32:18 +01:00
if len ( osName ) == 0 || osName == "common_os" || osName == "linux_glibc" || osName == "linux_musl" {
2021-10-15 00:43:51 +02:00
// Use host OS, which is currently hardcoded to be linux.
2022-06-22 17:01:55 +02:00
osName = "linux"
2021-02-22 22:13:50 +01:00
}
2022-06-22 17:01:55 +02:00
return arch + "|" + osName
2021-10-15 00:43:51 +02:00
}
2022-05-10 19:50:12 +02:00
func GetConfigKey ( ctx BaseModuleContext ) configKey {
2022-03-18 20:55:04 +01:00
return configKey {
// use string because Arch is not a valid key in go
arch : ctx . Arch ( ) . String ( ) ,
osType : ctx . Os ( ) ,
}
2021-02-22 22:13:50 +01:00
}
2022-04-26 04:35:15 +02:00
2022-05-12 22:43:01 +02:00
func bazelDepsetName ( contentHash string ) string {
return fmt . Sprintf ( "bazel_depset_%s" , contentHash )
2022-04-26 04:35:15 +02:00
}