f05b0d35d2
Add barebones riscv64-linux-android support. This should be enough to add riscv64-specific entries to Android.bp files, but can't actually compile anything until there are riscv64 toolchains. Test: arch_test.go Change-Id: I0dcc7e797d9352dd38243be908a7f19004ff3db1
345 lines
12 KiB
Go
345 lines
12 KiB
Go
// Copyright 2021 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 bazel
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
// ArchType names in arch.go
|
|
archArm = "arm"
|
|
archArm64 = "arm64"
|
|
archRiscv64 = "riscv64"
|
|
archX86 = "x86"
|
|
archX86_64 = "x86_64"
|
|
|
|
// OsType names in arch.go
|
|
OsAndroid = "android"
|
|
osDarwin = "darwin"
|
|
osLinux = "linux_glibc"
|
|
osLinuxMusl = "linux_musl"
|
|
osLinuxBionic = "linux_bionic"
|
|
osWindows = "windows"
|
|
|
|
// Targets in arch.go
|
|
osArchAndroidArm = "android_arm"
|
|
osArchAndroidArm64 = "android_arm64"
|
|
osArchAndroidRiscv64 = "android_riscv64"
|
|
osArchAndroidX86 = "android_x86"
|
|
osArchAndroidX86_64 = "android_x86_64"
|
|
osArchDarwinArm64 = "darwin_arm64"
|
|
osArchDarwinX86_64 = "darwin_x86_64"
|
|
osArchLinuxX86 = "linux_glibc_x86"
|
|
osArchLinuxX86_64 = "linux_glibc_x86_64"
|
|
osArchLinuxMuslArm = "linux_musl_arm"
|
|
osArchLinuxMuslArm64 = "linux_musl_arm64"
|
|
osArchLinuxMuslX86 = "linux_musl_x86"
|
|
osArchLinuxMuslX86_64 = "linux_musl_x86_64"
|
|
osArchLinuxBionicArm64 = "linux_bionic_arm64"
|
|
osArchLinuxBionicX86_64 = "linux_bionic_x86_64"
|
|
osArchWindowsX86 = "windows_x86"
|
|
osArchWindowsX86_64 = "windows_x86_64"
|
|
|
|
// This is the string representation of the default condition wherever a
|
|
// configurable attribute is used in a select statement, i.e.
|
|
// //conditions:default for Bazel.
|
|
//
|
|
// This is consistently named "conditions_default" to mirror the Soong
|
|
// config variable default key in an Android.bp file, although there's no
|
|
// integration with Soong config variables (yet).
|
|
ConditionsDefaultConfigKey = "conditions_default"
|
|
|
|
ConditionsDefaultSelectKey = "//conditions:default"
|
|
|
|
productVariableBazelPackage = "//build/bazel/product_variables"
|
|
|
|
AndroidAndInApex = "android-in_apex"
|
|
AndroidAndNonApex = "android-non_apex"
|
|
|
|
InApex = "in_apex"
|
|
NonApex = "non_apex"
|
|
)
|
|
|
|
func PowerSetWithoutEmptySet[T any](items []T) [][]T {
|
|
resultSize := int(math.Pow(2, float64(len(items))))
|
|
powerSet := make([][]T, 0, resultSize-1)
|
|
for i := 1; i < resultSize; i++ {
|
|
combination := make([]T, 0)
|
|
for j := 0; j < len(items); j++ {
|
|
if (i>>j)%2 == 1 {
|
|
combination = append(combination, items[j])
|
|
}
|
|
}
|
|
powerSet = append(powerSet, combination)
|
|
}
|
|
return powerSet
|
|
}
|
|
|
|
func createPlatformArchMap() map[string]string {
|
|
// Copy of archFeatures from android/arch_list.go because the bazel
|
|
// package can't access the android package
|
|
archFeatures := map[string][]string{
|
|
"arm": {
|
|
"neon",
|
|
},
|
|
"arm64": {
|
|
"dotprod",
|
|
},
|
|
"riscv64": {},
|
|
"x86": {
|
|
"ssse3",
|
|
"sse4",
|
|
"sse4_1",
|
|
"sse4_2",
|
|
"aes_ni",
|
|
"avx",
|
|
"avx2",
|
|
"avx512",
|
|
"popcnt",
|
|
"movbe",
|
|
},
|
|
"x86_64": {
|
|
"ssse3",
|
|
"sse4",
|
|
"sse4_1",
|
|
"sse4_2",
|
|
"aes_ni",
|
|
"avx",
|
|
"avx2",
|
|
"avx512",
|
|
"popcnt",
|
|
},
|
|
}
|
|
result := make(map[string]string)
|
|
for arch, allFeatures := range archFeatures {
|
|
result[arch] = "//build/bazel/platforms/arch:" + arch
|
|
// Sometimes we want to select on multiple features being active, so
|
|
// add the power set of all possible features to the map. More details
|
|
// in android.ModuleBase.GetArchVariantProperties
|
|
for _, features := range PowerSetWithoutEmptySet(allFeatures) {
|
|
sort.Strings(features)
|
|
archFeaturesName := arch + "-" + strings.Join(features, "-")
|
|
result[archFeaturesName] = "//build/bazel/platforms/arch/variants:" + archFeaturesName
|
|
}
|
|
}
|
|
result[ConditionsDefaultConfigKey] = ConditionsDefaultSelectKey
|
|
return result
|
|
}
|
|
|
|
var (
|
|
// These are the list of OSes and architectures with a Bazel config_setting
|
|
// and constraint value equivalent. These exist in arch.go, but the android
|
|
// package depends on the bazel package, so a cyclic dependency prevents
|
|
// using those variables here.
|
|
|
|
// A map of architectures to the Bazel label of the constraint_value
|
|
// for the @platforms//cpu:cpu constraint_setting
|
|
platformArchMap = createPlatformArchMap()
|
|
|
|
// A map of target operating systems to the Bazel label of the
|
|
// constraint_value for the @platforms//os:os constraint_setting
|
|
platformOsMap = map[string]string{
|
|
OsAndroid: "//build/bazel/platforms/os:android",
|
|
osDarwin: "//build/bazel/platforms/os:darwin",
|
|
osLinux: "//build/bazel/platforms/os:linux",
|
|
osLinuxMusl: "//build/bazel/platforms/os:linux_musl",
|
|
osLinuxBionic: "//build/bazel/platforms/os:linux_bionic",
|
|
osWindows: "//build/bazel/platforms/os:windows",
|
|
ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
|
|
}
|
|
|
|
platformOsArchMap = map[string]string{
|
|
osArchAndroidArm: "//build/bazel/platforms/os_arch:android_arm",
|
|
osArchAndroidArm64: "//build/bazel/platforms/os_arch:android_arm64",
|
|
osArchAndroidRiscv64: "//build/bazel/platforms/os_arch:android_riscv64",
|
|
osArchAndroidX86: "//build/bazel/platforms/os_arch:android_x86",
|
|
osArchAndroidX86_64: "//build/bazel/platforms/os_arch:android_x86_64",
|
|
osArchDarwinArm64: "//build/bazel/platforms/os_arch:darwin_arm64",
|
|
osArchDarwinX86_64: "//build/bazel/platforms/os_arch:darwin_x86_64",
|
|
osArchLinuxX86: "//build/bazel/platforms/os_arch:linux_glibc_x86",
|
|
osArchLinuxX86_64: "//build/bazel/platforms/os_arch:linux_glibc_x86_64",
|
|
osArchLinuxMuslArm: "//build/bazel/platforms/os_arch:linux_musl_arm",
|
|
osArchLinuxMuslArm64: "//build/bazel/platforms/os_arch:linux_musl_arm64",
|
|
osArchLinuxMuslX86: "//build/bazel/platforms/os_arch:linux_musl_x86",
|
|
osArchLinuxMuslX86_64: "//build/bazel/platforms/os_arch:linux_musl_x86_64",
|
|
osArchLinuxBionicArm64: "//build/bazel/platforms/os_arch:linux_bionic_arm64",
|
|
osArchLinuxBionicX86_64: "//build/bazel/platforms/os_arch:linux_bionic_x86_64",
|
|
osArchWindowsX86: "//build/bazel/platforms/os_arch:windows_x86",
|
|
osArchWindowsX86_64: "//build/bazel/platforms/os_arch:windows_x86_64",
|
|
ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
|
|
}
|
|
|
|
// Map where keys are OsType names, and values are slices containing the archs
|
|
// that that OS supports.
|
|
// These definitions copied from arch.go.
|
|
// TODO(cparsons): Source from arch.go; this task is nontrivial, as it currently results
|
|
// in a cyclic dependency.
|
|
osToArchMap = map[string][]string{
|
|
OsAndroid: {archArm, archArm64, archRiscv64, archX86, archX86_64},
|
|
osLinux: {archX86, archX86_64},
|
|
osLinuxMusl: {archX86, archX86_64},
|
|
osDarwin: {archArm64, archX86_64},
|
|
osLinuxBionic: {archArm64, archX86_64},
|
|
// TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well.
|
|
osWindows: {archX86, archX86_64},
|
|
}
|
|
|
|
osAndInApexMap = map[string]string{
|
|
AndroidAndInApex: "//build/bazel/rules/apex:android-in_apex",
|
|
AndroidAndNonApex: "//build/bazel/rules/apex:android-non_apex",
|
|
ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
|
|
}
|
|
|
|
inApexMap = map[string]string{
|
|
InApex: "//build/bazel/rules/apex:in_apex",
|
|
NonApex: "//build/bazel/rules/apex:non_apex",
|
|
ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
|
|
}
|
|
)
|
|
|
|
// basic configuration types
|
|
type configurationType int
|
|
|
|
const (
|
|
noConfig configurationType = iota
|
|
arch
|
|
os
|
|
osArch
|
|
productVariables
|
|
osAndInApex
|
|
inApex
|
|
)
|
|
|
|
func osArchString(os string, arch string) string {
|
|
return fmt.Sprintf("%s_%s", os, arch)
|
|
}
|
|
|
|
func (ct configurationType) String() string {
|
|
return map[configurationType]string{
|
|
noConfig: "no_config",
|
|
arch: "arch",
|
|
os: "os",
|
|
osArch: "arch_os",
|
|
productVariables: "product_variables",
|
|
osAndInApex: "os_in_apex",
|
|
inApex: "in_apex",
|
|
}[ct]
|
|
}
|
|
|
|
func (ct configurationType) validateConfig(config string) {
|
|
switch ct {
|
|
case noConfig:
|
|
if config != "" {
|
|
panic(fmt.Errorf("Cannot specify config with %s, but got %s", ct, config))
|
|
}
|
|
case arch:
|
|
if _, ok := platformArchMap[config]; !ok {
|
|
panic(fmt.Errorf("Unknown arch: %s", config))
|
|
}
|
|
case os:
|
|
if _, ok := platformOsMap[config]; !ok {
|
|
panic(fmt.Errorf("Unknown os: %s", config))
|
|
}
|
|
case osArch:
|
|
if _, ok := platformOsArchMap[config]; !ok {
|
|
panic(fmt.Errorf("Unknown os+arch: %s", config))
|
|
}
|
|
case productVariables:
|
|
// do nothing
|
|
case osAndInApex:
|
|
if _, ok := osAndInApexMap[config]; !ok {
|
|
panic(fmt.Errorf("Unknown os+in_apex config: %s", config))
|
|
}
|
|
case inApex:
|
|
if _, ok := inApexMap[config]; !ok {
|
|
panic(fmt.Errorf("Unknown in_apex config: %s", config))
|
|
}
|
|
default:
|
|
panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
|
|
}
|
|
}
|
|
|
|
// SelectKey returns the Bazel select key for a given configurationType and config string.
|
|
func (ca ConfigurationAxis) SelectKey(config string) string {
|
|
ca.validateConfig(config)
|
|
switch ca.configurationType {
|
|
case noConfig:
|
|
panic(fmt.Errorf("SelectKey is unnecessary for noConfig ConfigurationType "))
|
|
case arch:
|
|
return platformArchMap[config]
|
|
case os:
|
|
return platformOsMap[config]
|
|
case osArch:
|
|
return platformOsArchMap[config]
|
|
case productVariables:
|
|
if strings.HasSuffix(config, ConditionsDefaultConfigKey) {
|
|
// e.g. "acme__feature1__conditions_default" or "android__board__conditions_default"
|
|
return ConditionsDefaultSelectKey
|
|
}
|
|
return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
|
|
case osAndInApex:
|
|
return osAndInApexMap[config]
|
|
case inApex:
|
|
return inApexMap[config]
|
|
default:
|
|
panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
|
|
}
|
|
}
|
|
|
|
var (
|
|
// Indicating there is no configuration axis
|
|
NoConfigAxis = ConfigurationAxis{configurationType: noConfig}
|
|
// An axis for architecture-specific configurations
|
|
ArchConfigurationAxis = ConfigurationAxis{configurationType: arch}
|
|
// An axis for os-specific configurations
|
|
OsConfigurationAxis = ConfigurationAxis{configurationType: os}
|
|
// An axis for arch+os-specific configurations
|
|
OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch}
|
|
// An axis for os+in_apex-specific configurations
|
|
OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex}
|
|
// An axis for in_apex-specific configurations
|
|
InApexAxis = ConfigurationAxis{configurationType: inApex}
|
|
)
|
|
|
|
// ProductVariableConfigurationAxis returns an axis for the given product variable
|
|
func ProductVariableConfigurationAxis(variable string, outerAxis ConfigurationAxis) ConfigurationAxis {
|
|
return ConfigurationAxis{
|
|
configurationType: productVariables,
|
|
subType: variable,
|
|
outerAxisType: outerAxis.configurationType,
|
|
}
|
|
}
|
|
|
|
// ConfigurationAxis is an independent axis for configuration, there should be no overlap between
|
|
// elements within an axis.
|
|
type ConfigurationAxis struct {
|
|
configurationType
|
|
// some configuration types (e.g. productVariables) have multiple independent axes, subType helps
|
|
// distinguish between them without needing to list all 17 product variables.
|
|
subType string
|
|
// used to keep track of which product variables are arch variant
|
|
outerAxisType configurationType
|
|
}
|
|
|
|
func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool {
|
|
if ca.configurationType < other.configurationType {
|
|
return true
|
|
}
|
|
return ca.subType < other.subType
|
|
}
|