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"
2023-02-03 23:40:08 +01:00
"android/soong/starlark_fmt"
2022-08-03 21:49:43 +02:00
2022-04-26 04:35:15 +02:00
"github.com/google/blueprint"
2023-02-10 17:11:17 +01:00
"github.com/google/blueprint/metrics"
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" )
2023-02-03 23:40:08 +01:00
allowedBazelEnvironmentVars = [ ] string {
2023-02-10 22:46:28 +01:00
// clang-tidy
2023-02-03 23:40:08 +01:00
"ALLOW_LOCAL_TIDY_TRUE" ,
"DEFAULT_TIDY_HEADER_DIRS" ,
"TIDY_TIMEOUT" ,
"WITH_TIDY" ,
"WITH_TIDY_FLAGS" ,
2023-02-10 22:46:28 +01:00
"TIDY_EXTERNAL_VENDOR" ,
2023-02-03 23:40:08 +01:00
"SKIP_ABI_CHECKS" ,
"UNSAFE_DISABLE_APEX_ALLOWED_DEPS_CHECK" ,
"AUTO_ZERO_INITIALIZE" ,
"AUTO_PATTERN_INITIALIZE" ,
"AUTO_UNINITIALIZE" ,
"USE_CCACHE" ,
"LLVM_NEXT" ,
"ALLOW_UNKNOWN_WARNING_OPTION" ,
2023-04-18 05:07:26 +02:00
"UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT" ,
2023-02-03 23:40:08 +01:00
// Overrides the version in the apex_manifest.json. The version is unique for
// each branch (internal, aosp, mainline releases, dessert releases). This
// enables modules built on an older branch to be installed against a newer
// device for development purposes.
"OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION" ,
}
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 {
2023-03-16 20:15:19 +01:00
queueMixedBuild := mixedBuildMod . IsMixedBuildSupported ( ctx ) && MixedBuildsEnabled ( ctx )
if queueMixedBuild {
2022-05-10 19:50:12 +02:00
mixedBuildMod . QueueBazelCall ( ctx )
2023-03-16 20:15:19 +01:00
} else if _ , ok := ctx . Config ( ) . bazelForceEnabledModules [ m . Name ( ) ] ; ok {
// TODO(b/273910287) - remove this once --ensure_allowlist_integrity is added
ctx . ModuleErrorf ( "Attempted to force enable an unready module: %s. Did you forget to Bp2BuildDefaultTrue its directory?\n" , m . Name ( ) )
2022-05-10 19:50:12 +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:
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 {
2023-01-18 18:15:31 +01:00
arch string
osType OsType
apexKey ApexConfigKey
}
type ApexConfigKey struct {
WithinApex bool
ApexSdkVersion string
}
func ( c ApexConfigKey ) String ( ) string {
return fmt . Sprintf ( "%s_%s" , withinApexToString ( c . WithinApex ) , c . ApexSdkVersion )
}
func withinApexToString ( withinApex bool ) string {
if withinApex {
return "within_apex"
}
return ""
2021-10-15 00:43:51 +02:00
}
2022-07-27 23:51:45 +02:00
func ( c configKey ) String ( ) string {
2023-01-18 18:15:31 +01:00
return fmt . Sprintf ( "%s::%s::%s" , c . arch , c . osType , c . apexKey )
2022-07-27 23:51:45 +02:00
}
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 )
}
2023-02-10 17:11:17 +01:00
type invokeBazelContext interface {
GetEventHandler ( ) * metrics . EventHandler
}
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
2023-02-10 17:11:17 +01:00
InvokeBazel ( config Config , ctx invokeBazelContext ) 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).
2023-01-18 18:15:31 +01:00
IsModuleNameAllowed ( moduleName string , withinApex bool ) bool
2020-12-10 23:19:18 +01:00
2023-02-22 19:42:15 +01:00
IsModuleDclaAllowed ( 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.
2023-02-10 23:17:28 +01:00
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 {
2023-02-03 23:40:08 +01:00
createBazelCommand ( config Config , paths * bazelPaths , runName bazel . RunName , command bazelCommand , extraFlags ... string ) * exec . Cmd
2023-02-10 17:11:17 +01:00
issueBazelCommand ( bazelCmd * exec . Cmd , eventHandler * metrics . EventHandler ) ( 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
2023-02-03 00:16:29 +01:00
paths * bazelPaths
// cquery requests that have not yet been issued to Bazel. This list is maintained
// in a sorted state, and is guaranteed to have no duplicates.
requests [ ] cqueryKey
requestMutex sync . Mutex // requests can be written in parallel
2020-09-29 08:23:17 +02:00
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.
2023-02-10 23:17:28 +01:00
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
2023-01-18 18:15:31 +01:00
// DCLA modules are enabled when used in apex.
bazelDclaEnabledModules map [ string ] bool
2022-08-20 20:48:32 +02:00
// 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
2023-01-18 18:15:31 +01:00
BazelRequests map [ string ] bool
2020-09-29 08:23:17 +02:00
}
2023-01-18 18:15:31 +01:00
func ( m MockBazelContext ) QueueBazelRequest ( label string , requestType cqueryRequest , cfgKey configKey ) {
key := BuildMockBazelContextRequestKey ( label , requestType , cfgKey . arch , cfgKey . osType , cfgKey . apexKey )
if m . BazelRequests == nil {
m . BazelRequests = make ( map [ string ] bool )
}
m . BazelRequests [ key ] = true
2022-05-10 19:50:12 +02:00
}
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
}
2023-01-18 18:15:31 +01:00
func ( m MockBazelContext ) GetCcInfo ( label string , cfgKey configKey ) ( cquery . CcInfo , error ) {
2023-01-23 20:04:24 +01:00
result , ok := m . LabelToCcInfo [ label ]
if ! ok {
2023-01-18 18:15:31 +01:00
key := BuildMockBazelContextResultKey ( label , cfgKey . arch , cfgKey . osType , cfgKey . apexKey )
result , ok = m . LabelToCcInfo [ key ]
if ! ok {
return cquery . CcInfo { } , fmt . Errorf ( "no target with label %q in LabelToCcInfo" , label )
}
2023-01-23 20:04:24 +01:00
}
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
}
2023-02-10 17:11:17 +01:00
func ( m MockBazelContext ) InvokeBazel ( _ Config , _ invokeBazelContext ) error {
2020-09-29 08:23:17 +02:00
panic ( "unimplemented" )
}
2023-01-18 18:15:31 +01:00
func ( m MockBazelContext ) IsModuleNameAllowed ( _ string , _ bool ) bool {
2020-09-29 08:23:17 +02:00
return true
}
2023-02-22 19:42:15 +01:00
func ( m MockBazelContext ) IsModuleDclaAllowed ( _ string ) 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
2023-02-10 23:17:28 +01:00
func ( m MockBazelContext ) BuildStatementsToRegister ( ) [ ] * bazel . BuildStatement {
return [ ] * bazel . BuildStatement { }
2020-12-10 23:19:18 +01:00
}
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 { }
2023-01-18 18:15:31 +01:00
func BuildMockBazelContextRequestKey ( label string , request cqueryRequest , arch string , osType OsType , apexKey ApexConfigKey ) string {
cfgKey := configKey {
arch : arch ,
osType : osType ,
apexKey : apexKey ,
}
return strings . Join ( [ ] string { label , request . Name ( ) , cfgKey . String ( ) } , "_" )
}
func BuildMockBazelContextResultKey ( label string , arch string , osType OsType , apexKey ApexConfigKey ) string {
cfgKey := configKey {
arch : arch ,
osType : osType ,
apexKey : apexKey ,
}
return strings . Join ( [ ] string { label , cfgKey . String ( ) } , "_" )
}
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 ( )
2023-02-03 00:16:29 +01:00
// Insert key into requests, maintaining the sort, and only if it's not duplicate.
keyString := key . String ( )
foundEqual := false
notLessThanKeyString := func ( i int ) bool {
s := bazelCtx . requests [ i ] . String ( )
v := strings . Compare ( s , keyString )
if v == 0 {
foundEqual = true
}
return v >= 0
}
targetIndex := sort . Search ( len ( bazelCtx . requests ) , notLessThanKeyString )
if foundEqual {
return
}
if targetIndex == len ( bazelCtx . requests ) {
bazelCtx . requests = append ( bazelCtx . requests , key )
} else {
bazelCtx . requests = append ( bazelCtx . requests [ : targetIndex + 1 ] , bazelCtx . requests [ targetIndex : ] ... )
bazelCtx . requests [ targetIndex ] = key
}
2022-05-10 19:50:12 +02:00
}
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" )
}
2023-02-10 17:11:17 +01:00
func ( n noopBazelContext ) InvokeBazel ( _ Config , _ invokeBazelContext ) 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 ""
}
2023-01-18 18:15:31 +01:00
func ( n noopBazelContext ) IsModuleNameAllowed ( _ string , _ bool ) bool {
2020-09-29 08:23:17 +02:00
return false
}
2023-02-22 19:42:15 +01:00
func ( n noopBazelContext ) IsModuleDclaAllowed ( _ string ) bool {
return false
}
2023-02-10 23:17:28 +01:00
func ( m noopBazelContext ) BuildStatementsToRegister ( ) [ ] * bazel . BuildStatement {
return [ ] * bazel . BuildStatement { }
2020-12-10 23:19:18 +01:00
}
2022-04-26 04:35:15 +02:00
func ( m noopBazelContext ) AqueryDepsets ( ) [ ] bazel . AqueryDepset {
return [ ] bazel . AqueryDepset { }
}
2023-01-18 18:15:31 +01:00
func addToStringSet ( set map [ string ] bool , items [ ] string ) {
for _ , item := range items {
set [ item ] = true
}
}
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-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 ( )
}
2023-01-18 18:15:31 +01:00
dclaMixedBuildsEnabledList := [ ] string { }
if c . BuildMode == BazelProdMode {
dclaMixedBuildsEnabledList = allowlists . ProdDclaMixedBuildsEnabledList
} else if c . BuildMode == BazelStagingMode {
dclaMixedBuildsEnabledList = append ( allowlists . ProdDclaMixedBuildsEnabledList ,
allowlists . StagingDclaMixedBuildsEnabledList ... )
}
dclaEnabledModules := map [ string ] bool { }
addToStringSet ( dclaEnabledModules , dclaMixedBuildsEnabledList )
2022-12-30 02:11:49 +01:00
return & mixedBuildBazelContext {
2023-02-23 23:28:06 +01:00
bazelRunner : & builtinBazelRunner { c . UseBazelProxy , absolutePath ( c . outDir ) } ,
2023-01-18 18:15:31 +01:00
paths : & paths ,
modulesDefaultToBazel : c . BuildMode == BazelDevMode ,
bazelEnabledModules : enabledModules ,
bazelDisabledModules : disabledModules ,
bazelDclaEnabledModules : dclaEnabledModules ,
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
}
2023-01-18 18:15:31 +01:00
func ( context * mixedBuildBazelContext ) IsModuleNameAllowed ( moduleName string , withinApex bool ) bool {
2022-08-20 20:48:32 +02:00
if context . bazelDisabledModules [ moduleName ] {
return false
}
if context . bazelEnabledModules [ moduleName ] {
return true
}
2023-02-22 19:42:15 +01:00
if withinApex && context . IsModuleDclaAllowed ( moduleName ) {
2023-01-18 18:15:31 +01:00
return true
}
2022-08-20 20:48:32 +02:00
return context . modulesDefaultToBazel
2020-09-29 08:23:17 +02:00
}
2023-02-22 19:42:15 +01:00
func ( context * mixedBuildBazelContext ) IsModuleDclaAllowed ( moduleName string ) bool {
return context . bazelDclaEnabledModules [ moduleName ]
}
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
}
2023-02-03 23:40:08 +01:00
func ( r * mockBazelRunner ) createBazelCommand ( _ Config , _ * 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
}
2023-02-10 17:11:17 +01:00
func ( r * mockBazelRunner ) issueBazelCommand ( bazelCmd * exec . Cmd , _ * metrics . EventHandler ) ( string , string , error ) {
2022-09-08 17:37:57 +02:00
if command , ok := r . tokens [ bazelCmd ] ; ok {
return r . bazelCommandResults [ command ] , "" , nil
2021-04-08 15:47:28 +02:00
}
return "" , "" , nil
}
2023-02-23 23:28:06 +01:00
type builtinBazelRunner struct {
useBazelProxy bool
outDir string
}
2021-04-08 15:47:28 +02:00
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.
2023-02-10 17:11:17 +01:00
func ( r * builtinBazelRunner ) issueBazelCommand ( bazelCmd * exec . Cmd , eventHandler * metrics . EventHandler ) ( string , string , error ) {
2023-02-23 23:28:06 +01:00
if r . useBazelProxy {
eventHandler . Begin ( "client_proxy" )
defer eventHandler . End ( "client_proxy" )
proxyClient := bazel . NewProxyClient ( r . outDir )
// Omit the arg containing the Bazel binary, as that is handled by the proxy
// server.
bazelFlags := bazelCmd . Args [ 1 : ]
// TODO(b/270989498): Refactor these functions to not take exec.Cmd, as its
// not actually executed for client proxying.
resp , err := proxyClient . IssueCommand ( bazel . CmdRequest { bazelFlags , bazelCmd . Env } )
if err != nil {
return "" , "" , err
}
if len ( resp . ErrorString ) > 0 {
return "" , "" , fmt . Errorf ( resp . ErrorString )
}
return resp . Stdout , resp . Stderr , nil
2022-09-08 17:37:57 +02:00
} else {
2023-02-23 23:28:06 +01:00
eventHandler . Begin ( "bazel command" )
defer eventHandler . End ( "bazel command" )
stderr := & bytes . Buffer { }
bazelCmd . Stderr = stderr
if output , err := bazelCmd . Output ( ) ; err != nil {
return "" , string ( stderr . Bytes ( ) ) ,
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 )
} else {
return string ( output ) , string ( stderr . Bytes ( ) ) , nil
}
2022-09-08 17:37:57 +02:00
}
}
2023-02-03 23:40:08 +01:00
func ( r * builtinBazelRunner ) createBazelCommand ( config Config , paths * bazelPaths , runName bazel . RunName , command bazelCommand ,
2022-09-08 17:37:57 +02:00
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
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" ,
}
2023-02-03 23:40:08 +01:00
for _ , envvar := range allowedBazelEnvironmentVars {
val := config . Getenv ( envvar )
if val == "" {
continue
}
extraEnv = append ( extraEnv , fmt . Sprintf ( "%s=%s" , envvar , val ) )
}
2022-07-27 23:51:45 +02:00
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 )
2023-01-18 18:15:31 +01:00
apex_name = ""
if attr . within_apex :
# //build/bazel/rules/apex:apex_name has to be set to a non_empty value,
# otherwise //build/bazel/rules/apex:non_apex will be true and the
# "-D__ANDROID_APEX__" compiler flag will be missing . Apex_name is used
# in some validation on bazel side which don ' t really apply in mixed
# build because soong will do the work , so we just set it to a fixed
# value here .
apex_name = "dcla_apex"
outputs = {
2022-11-09 03:14:01 +01:00
"//command_line_option:platforms" : "@soong_injection//product_config_platforms/products/{PRODUCT}-{VARIANT}:%s" % target ,
2023-01-18 18:15:31 +01:00
"@//build/bazel/rules/apex:within_apex" : attr . within_apex ,
"@//build/bazel/rules/apex:min_sdk_version" : attr . apex_sdk_version ,
"@//build/bazel/rules/apex:apex_name" : apex_name ,
2021-02-22 22:13:50 +01:00
}
2023-01-18 18:15:31 +01:00
return outputs
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" ,
2023-01-18 18:15:31 +01:00
"@//build/bazel/rules/apex:within_apex" ,
"@//build/bazel/rules/apex:min_sdk_version" ,
"@//build/bazel/rules/apex:apex_name" ,
2021-02-22 22:13:50 +01:00
] ,
)
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 = {
2023-01-18 18:15:31 +01:00
"arch" : attr . string ( mandatory = True ) ,
"os" : attr . string ( mandatory = True ) ,
"within_apex" : attr . bool ( default = False ) ,
"apex_sdk_version" : 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" ,
2023-01-18 18:15:31 +01:00
within_apex = % s ,
apex_sdk_version = "%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 { }
2023-02-03 00:16:29 +01: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
}
2023-02-03 00:16:29 +01:00
// Configs need to be sorted to maintain determinism of the BUILD file.
sortedConfigs := make ( [ ] string , 0 , len ( labelsByConfig ) )
for val := range labelsByConfig {
sortedConfigs = append ( sortedConfigs , val )
}
sort . Slice ( sortedConfigs , func ( i , j int ) bool { return sortedConfigs [ i ] < sortedConfigs [ j ] } )
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 { }
2023-02-03 00:16:29 +01:00
for _ , configString := range sortedConfigs {
labels := labelsByConfig [ configString ]
2021-10-15 00:43:51 +02:00
configTokens := strings . Split ( configString , "|" )
2023-01-18 18:15:31 +01:00
if len ( configTokens ) < 2 {
2021-10-15 00:43:51 +02:00
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 ]
2023-01-18 18:15:31 +01:00
withinApex := "False"
apexSdkVerString := ""
2021-10-15 00:43:51 +02:00
targetString := fmt . Sprintf ( "%s_%s" , osString , archString )
2023-01-18 18:15:31 +01:00
if len ( configTokens ) > 2 {
targetString += "_" + configTokens [ 2 ]
if configTokens [ 2 ] == withinApexToString ( true ) {
withinApex = "True"
}
}
if len ( configTokens ) > 3 {
targetString += "_" + configTokens [ 3 ]
apexSdkVerString = configTokens [ 3 ]
}
2021-10-15 00:43:51 +02:00
allLabels = append ( allLabels , fmt . Sprintf ( "\":%s\"" , targetString ) )
labelsString := strings . Join ( labels , ",\n " )
2023-01-18 18:15:31 +01:00
configNodesSection += fmt . Sprintf ( configNodeFormatString , targetString , archString , osString , withinApex , apexSdkVerString ,
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 { }
2023-03-15 05:19:32 +01:00
requestTypes := [ ] cqueryRequest { }
2023-02-03 00:16:29 +01:00
for _ , val := range context . requests {
2021-03-11 17:08:46 +01:00
cqueryId := getCqueryId ( val )
mapEntryString := fmt . Sprintf ( "%q : True" , cqueryId )
2023-03-15 05:19:32 +01:00
if _ , seenKey := requestTypeToCqueryIdEntries [ val . requestType ] ; ! seenKey {
requestTypes = append ( requestTypes , val . requestType )
}
2021-03-11 17:08:46 +01:00
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
2023-03-15 05:19:32 +01:00
for _ , requestType := range requestTypes {
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-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 )
2023-01-18 18:15:31 +01:00
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 ( "_" )
2023-01-18 18:15:31 +01:00
config_key = ""
2022-11-09 03:14:01 +01:00
if not platform_name :
2023-01-18 18:15:31 +01:00
config_key = "target|android"
2021-06-04 21:03:47 +02:00
elif platform_name . startswith ( "android_" ) :
2023-01-18 18:15:31 +01:00
config_key = platform_name . removeprefix ( "android_" ) + "|android"
2021-06-04 21:03:47 +02:00
elif platform_name . startswith ( "linux_" ) :
2023-01-18 18:15:31 +01:00
config_key = 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
2023-01-18 18:15:31 +01:00
within_apex = buildoptions . get ( "//build/bazel/rules/apex:within_apex" )
apex_sdk_version = buildoptions . get ( "//build/bazel/rules/apex:min_sdk_version" )
if within_apex :
config_key += "|within_apex"
if apex_sdk_version != None and len ( apex_sdk_version ) > 0 :
config_key += "|" + apex_sdk_version
return config_key
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.
2023-02-10 17:11:17 +01:00
func ( context * mixedBuildBazelContext ) InvokeBazel ( config Config , ctx invokeBazelContext ) error {
eventHandler := ctx . GetEventHandler ( )
eventHandler . Begin ( "bazel" )
defer eventHandler . End ( "bazel" )
2022-11-17 00:28:18 +01:00
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 )
2023-02-03 23:40:08 +01:00
if err := context . runCquery ( config , ctx ) ; err != nil {
2022-11-17 00:28:18 +01:00
return err
}
if err := context . runAquery ( config , ctx ) ; err != nil {
return err
}
2023-02-03 23:40:08 +01:00
if err := context . generateBazelSymlinks ( config , ctx ) ; err != nil {
2022-11-17 00:28:18 +01:00
return err
}
// Clear requests.
2023-02-03 00:16:29 +01:00
context . requests = [ ] cqueryKey { }
2022-11-17 00:28:18 +01:00
return nil
}
2020-09-29 08:23:17 +02:00
2023-02-10 17:11:17 +01:00
func ( context * mixedBuildBazelContext ) runCquery ( config Config , ctx invokeBazelContext ) error {
eventHandler := ctx . GetEventHandler ( )
eventHandler . Begin ( "cquery" )
defer 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
}
2023-02-03 00:16:29 +01:00
if err := writeFileBytesIfChanged ( filepath . Join ( soongInjectionPath , "WORKSPACE.bazel" ) , [ ] byte { } , 0666 ) ; err != nil {
2020-11-17 21:41:01 +01:00
return err
}
2023-02-03 00:16:29 +01:00
if err := writeFileBytesIfChanged ( filepath . Join ( mixedBuildsPath , "main.bzl" ) , context . mainBzlFileContents ( ) , 0666 ) ; err != nil {
2020-10-23 22:48:08 +02:00
return err
}
2023-02-03 00:16:29 +01:00
if err := writeFileBytesIfChanged ( 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" )
2023-02-03 00:16:29 +01:00
if err := writeFileBytesIfChanged ( 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
2023-01-18 18:15:31 +01:00
extraFlags := [ ] string { "--output=starlark" , "--starlark:file=" + absolutePath ( cqueryFileRelpath ) }
if Bool ( config . productVariables . ClangCoverage ) {
extraFlags = append ( extraFlags , "--collect_code_coverage" )
}
cqueryCommandWithFlag := context . createBazelCommand ( config , context . paths , bazel . CqueryBuildRootRunName , cqueryCmd , extraFlags ... )
2023-02-10 17:11:17 +01:00
cqueryOutput , cqueryErrorMessage , cqueryErr := context . issueBazelCommand ( cqueryCommandWithFlag , eventHandler )
2022-11-16 17:59:23 +01:00
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 ]
}
}
2023-02-03 00:16:29 +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
2023-02-03 00:16:29 +01:00
func writeFileBytesIfChanged ( path string , contents [ ] byte , perm os . FileMode ) error {
oldContents , err := os . ReadFile ( path )
if err != nil || ! bytes . Equal ( contents , oldContents ) {
err = os . WriteFile ( path , contents , perm )
}
return nil
}
2023-02-10 17:11:17 +01:00
func ( context * mixedBuildBazelContext ) runAquery ( config Config , ctx invokeBazelContext ) error {
eventHandler := ctx . GetEventHandler ( )
eventHandler . Begin ( "aquery" )
defer 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
}
}
2023-02-03 23:40:08 +01:00
aqueryOutput , _ , err := context . issueBazelCommand ( context . createBazelCommand ( config , context . paths , bazel . AqueryBuildRootRunName , aqueryCmd ,
2023-02-10 17:11:17 +01:00
extraFlags ... ) , eventHandler )
2022-11-17 00:28:18 +01:00
if err != nil {
2021-01-15 18:22:41 +01:00
return err
}
2023-02-10 17:11:17 +01:00
context . buildStatements , context . depsets , err = bazel . AqueryBuildStatements ( [ ] byte ( aqueryOutput ) , eventHandler )
2022-11-17 00:28:18 +01:00
return err
}
2020-12-10 23:19:18 +01:00
2023-02-10 17:11:17 +01:00
func ( context * mixedBuildBazelContext ) generateBazelSymlinks ( config Config , ctx invokeBazelContext ) error {
eventHandler := ctx . GetEventHandler ( )
eventHandler . Begin ( "symlinks" )
defer 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.
2023-02-10 17:11:17 +01:00
_ , _ , err := context . issueBazelCommand ( context . createBazelCommand ( config , context . paths , bazel . BazelBuildPhonyRootRunName , buildCmd ) , eventHandler )
2022-11-17 00:28:18 +01:00
return err
2020-09-29 08:23:17 +02:00
}
2020-10-13 05:44:08 +02:00
2023-02-10 23:17:28 +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 ( ) {
2023-02-10 23:17:28 +01:00
// nil build statements are a valid case where we do not create an action because it is
// unnecessary or handled by other processing
if buildStatement == nil {
continue
}
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).
2023-02-10 23:17:28 +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
}
2023-01-18 18:15:31 +01:00
keyString := arch + "|" + osName
if key . configKey . apexKey . WithinApex {
keyString += "|" + withinApexToString ( key . configKey . apexKey . WithinApex )
}
if len ( key . configKey . apexKey . ApexSdkVersion ) > 0 {
keyString += "|" + key . configKey . apexKey . ApexSdkVersion
}
return keyString
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
2023-01-18 18:15:31 +01:00
func GetConfigKeyApexVariant ( ctx BaseModuleContext , apexKey * ApexConfigKey ) configKey {
configKey := GetConfigKey ( ctx )
if apexKey != nil {
configKey . apexKey = ApexConfigKey {
WithinApex : apexKey . WithinApex ,
ApexSdkVersion : apexKey . ApexSdkVersion ,
}
}
return configKey
}
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
}
2023-02-03 23:40:08 +01:00
func EnvironmentVarsFile ( config Config ) string {
return fmt . Sprintf ( bazel . GeneratedBazelFileWarning + `
_env = % s
env = _env
` ,
starlark_fmt . PrintStringList ( allowedBazelEnvironmentVars , 0 ) ,
)
}