Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1a6bbbd9 authored by Jingwen Chen's avatar Jingwen Chen Committed by Gerrit Code Review
Browse files

Merge "Add os/target configurable selects for label list attributes."

parents 0774773a 91220d73
Loading
Loading
Loading
Loading
+87 −0
Original line number Diff line number Diff line
@@ -1709,3 +1709,90 @@ func (m *ModuleBase) GetArchProperties(dst interface{}) map[ArchType]interface{}
	}
	return archToProp
}

// GetTargetProperties returns a map of OS target (e.g. android, windows) to the
// values of the properties of the 'dst' struct that are specific to that OS
// target.
//
// For example, passing a struct { Foo bool, Bar string } will return an
// interface{} that can be type asserted back into the same struct, containing
// the os-specific property value specified by the module if defined.
//
// While this looks similar to GetArchProperties, the internal representation of
// the properties have a slightly different layout to warrant a standalone
// lookup function.
func (m *ModuleBase) GetTargetProperties(dst interface{}) map[OsType]interface{} {
	// Return value of the arch types to the prop values for that arch.
	osToProp := map[OsType]interface{}{}

	// Nothing to do for non-OS/arch-specific modules.
	if !m.ArchSpecific() {
		return osToProp
	}

	// archProperties has the type of [][]interface{}. Looks complicated, so
	// let's explain this step by step.
	//
	// Loop over the outer index, which determines the property struct that
	// contains a matching set of properties in dst that we're interested in.
	// For example, BaseCompilerProperties or BaseLinkerProperties.
	for i := range m.archProperties {
		if m.archProperties[i] == nil {
			continue
		}

		// Iterate over the supported OS types
		for _, os := range OsTypeList {
			// e.g android, linux_bionic
			field := os.Field

			// If it's not nil, loop over the inner index, which determines the arch variant
			// of the prop type. In an Android.bp file, this is like looping over:
			//
			// target: { android: { key: value, ... }, linux_bionic: { key: value, ... } }
			for _, archProperties := range m.archProperties[i] {
				archPropValues := reflect.ValueOf(archProperties).Elem()

				// This is the archPropRoot struct. Traverse into the Targetnested struct.
				src := archPropValues.FieldByName("Target").Elem()

				// Step into non-nil pointers to structs in the src value.
				if src.Kind() == reflect.Ptr {
					if src.IsNil() {
						continue
					}
					src = src.Elem()
				}

				// Find the requested field (e.g. android, linux_bionic) in the src struct.
				src = src.FieldByName(field)

				// Validation steps. We want valid non-nil pointers to structs.
				if !src.IsValid() || src.IsNil() {
					continue
				}

				if src.Kind() != reflect.Ptr || src.Elem().Kind() != reflect.Struct {
					continue
				}

				// Clone the destination prop, since we want a unique prop struct per arch.
				dstClone := reflect.New(reflect.ValueOf(dst).Elem().Type()).Interface()

				// Copy the located property struct into the cloned destination property struct.
				err := proptools.ExtendMatchingProperties([]interface{}{dstClone}, src.Interface(), nil, proptools.OrderReplace)
				if err != nil {
					// This is fine, it just means the src struct doesn't match.
					continue
				}

				// Found the prop for the os, you have.
				osToProp[os] = dstClone

				// Go to the next prop.
				break
			}
		}
	}
	return osToProp
}
+10 −0
Original line number Diff line number Diff line
@@ -108,6 +108,11 @@ type Bp2BuildConfig map[string]BazelConversionConfigEntry
type BazelConversionConfigEntry int

const (
	// A sentinel value to be used as a key in Bp2BuildConfig for modules with
	// no package path. This is also the module dir for top level Android.bp
	// modules.
	BP2BUILD_TOPLEVEL = "."

	// iota + 1 ensures that the int value is not 0 when used in the Bp2buildAllowlist map,
	// which can also mean that the key doesn't exist in a lookup.

@@ -224,10 +229,15 @@ func (b *BazelModuleBase) ConvertWithBp2build(ctx BazelConversionPathContext) bo
func bp2buildDefaultTrueRecursively(packagePath string, config Bp2BuildConfig) bool {
	ret := false

	// Return exact matches in the config.
	if config[packagePath] == Bp2BuildDefaultTrueRecursively {
		return true
	}
	if config[packagePath] == Bp2BuildDefaultFalse {
		return false
	}

	// If not, check for the config recursively.
	packagePrefix := ""
	// e.g. for x/y/z, iterate over x, x/y, then x/y/z, taking the final value from the allowlist.
	for _, part := range strings.Split(packagePath, "/") {
+18 −8
Original line number Diff line number Diff line
@@ -270,13 +270,23 @@ func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command st
	cmdFlags = append(cmdFlags, labels...)
	cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+context.intermediatesDir())
	cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(context, runName))
	// 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, and thus be invalid.
	// The actual platform values here may be overridden by configuration transitions from the buildroot.

	// 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.
	cmdFlags = append(cmdFlags,
		fmt.Sprintf("--platforms=%s", canonicalizeLabel("//build/bazel/platforms:generic_x86_64")))
		fmt.Sprintf("--platforms=%s", canonicalizeLabel("//build/bazel/platforms:android_x86_64")))
	cmdFlags = append(cmdFlags,
		fmt.Sprintf("--extra_toolchains=%s", canonicalizeLabel("//prebuilts/clang/host/linux-x86:all")))
	// This should be parameterized on the host OS, but let's restrict to linux
	// to keep things simple for now.
	cmdFlags = append(cmdFlags,
		fmt.Sprintf("--host_platform=%s", canonicalizeLabel("//build/bazel/platforms:linux_x86_64")))

	// Explicitly disable downloading rules (such as canonical C++ and Java rules) from the network.
	cmdFlags = append(cmdFlags, "--experimental_repository_disable_download")
	cmdFlags = append(cmdFlags, extraFlags...)
@@ -328,7 +338,7 @@ func (context *bazelContext) mainBzlFileContents() []byte {

def _config_node_transition_impl(settings, attr):
    return {
        "//command_line_option:platforms": "@sourceroot//build/bazel/platforms:generic_%s" % attr.arch,
        "//command_line_option:platforms": "@sourceroot//build/bazel/platforms:android_%s" % attr.arch,
    }

_config_node_transition = transition(
@@ -504,10 +514,10 @@ def get_arch(target):
  platform_name = build_options(target)["//command_line_option:platforms"][0].name
  if platform_name == "host":
    return "HOST"
  elif not platform_name.startswith("generic_"):
    fail("expected platform name of the form 'generic_<arch>', but was " + str(platforms))
  elif not platform_name.startswith("android_"):
    fail("expected platform name of the form 'android_<arch>', but was " + str(platforms))
    return "UNKNOWN"
  return platform_name[len("generic_"):]
  return platform_name[len("android_"):]

def format(target):
  id_string = str(target.label) + "|" + get_arch(target)
+126 −50
Original line number Diff line number Diff line
@@ -80,10 +80,19 @@ func UniqueBazelLabelList(originalLabelList LabelList) LabelList {
}

const (
	ARCH_X86    = "x86"
	ARCH_X86_64 = "x86_64"
	// ArchType names in arch.go
	ARCH_ARM    = "arm"
	ARCH_ARM64  = "arm64"
	ARCH_X86    = "x86"
	ARCH_X86_64 = "x86_64"

	// OsType names in arch.go
	OS_ANDROID      = "android"
	OS_DARWIN       = "darwin"
	OS_FUCHSIA      = "fuchsia"
	OS_LINUX        = "linux_glibc"
	OS_LINUX_BIONIC = "linux_bionic"
	OS_WINDOWS      = "windows"
)

var (
@@ -92,6 +101,36 @@ var (
	// android package depends on the bazel package, so a cyclic dependency
	// prevents using that here.
	selectableArchs = []string{ARCH_X86, ARCH_X86_64, ARCH_ARM, ARCH_ARM64}

	// Likewise, this is the list of target operating systems.
	selectableTargetOs = []string{
		OS_ANDROID,
		OS_DARWIN,
		OS_FUCHSIA,
		OS_LINUX,
		OS_LINUX_BIONIC,
		OS_WINDOWS,
	}

	// A map of architectures to the Bazel label of the constraint_value
	// for the @platforms//cpu:cpu constraint_setting
	PlatformArchMap = map[string]string{
		ARCH_ARM:    "//build/bazel/platforms/arch:arm",
		ARCH_ARM64:  "//build/bazel/platforms/arch:arm64",
		ARCH_X86:    "//build/bazel/platforms/arch:x86",
		ARCH_X86_64: "//build/bazel/platforms/arch:x86_64",
	}

	// 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{
		OS_ANDROID:      "//build/bazel/platforms/os:android",
		OS_DARWIN:       "//build/bazel/platforms/os:darwin",
		OS_FUCHSIA:      "//build/bazel/platforms/os:fuchsia",
		OS_LINUX:        "//build/bazel/platforms/os:linux",
		OS_LINUX_BIONIC: "//build/bazel/platforms/os:linux_bionic",
		OS_WINDOWS:      "//build/bazel/platforms/os:windows",
	}
)

// Arch-specific label_list typed Bazel attribute values. This should correspond
@@ -101,8 +140,16 @@ type labelListArchValues struct {
	X86_64 LabelList
	Arm    LabelList
	Arm64  LabelList
	// TODO(b/181299724): this is currently missing the "common" arch, which
	// doesn't have an equivalent platform() definition yet.
	Common LabelList
}

type labelListOsValues struct {
	Android     LabelList
	Darwin      LabelList
	Fuchsia     LabelList
	Linux       LabelList
	LinuxBionic LabelList
	Windows     LabelList
}

// LabelListAttribute is used to represent a list of Bazel labels as an
@@ -115,6 +162,11 @@ type LabelListAttribute struct {
	// are generated in a select statement and appended to the non-arch specific
	// label list Value.
	ArchValues labelListArchValues

	// The os-specific attribute label list values. Optional. If used, these
	// are generated in a select statement and appended to the non-os specific
	// label list Value.
	OsValues labelListOsValues
}

// MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value.
@@ -124,45 +176,75 @@ func MakeLabelListAttribute(value LabelList) LabelListAttribute {

// HasArchSpecificValues returns true if the attribute contains
// architecture-specific label_list values.
func (attrs *LabelListAttribute) HasArchSpecificValues() bool {
func (attrs *LabelListAttribute) HasConfigurableValues() bool {
	for _, arch := range selectableArchs {
		if len(attrs.GetValueForArch(arch).Includes) > 0 || len(attrs.GetValueForArch(arch).Excludes) > 0 {
		if len(attrs.GetValueForArch(arch).Includes) > 0 {
			return true
		}
	}

	for _, os := range selectableTargetOs {
		if len(attrs.GetValueForOS(os).Includes) > 0 {
			return true
		}
	}
	return false
}

func (attrs *LabelListAttribute) archValuePtrs() map[string]*LabelList {
	return map[string]*LabelList{
		ARCH_X86:    &attrs.ArchValues.X86,
		ARCH_X86_64: &attrs.ArchValues.X86_64,
		ARCH_ARM:    &attrs.ArchValues.Arm,
		ARCH_ARM64:  &attrs.ArchValues.Arm64,
	}
}

// GetValueForArch returns the label_list attribute value for an architecture.
func (attrs *LabelListAttribute) GetValueForArch(arch string) LabelList {
	switch arch {
	case ARCH_X86:
		return attrs.ArchValues.X86
	case ARCH_X86_64:
		return attrs.ArchValues.X86_64
	case ARCH_ARM:
		return attrs.ArchValues.Arm
	case ARCH_ARM64:
		return attrs.ArchValues.Arm64
	default:
	var v *LabelList
	if v = attrs.archValuePtrs()[arch]; v == nil {
		panic(fmt.Errorf("Unknown arch: %s", arch))
	}
	return *v
}

// SetValueForArch sets the label_list attribute value for an architecture.
func (attrs *LabelListAttribute) SetValueForArch(arch string, value LabelList) {
	switch arch {
	case "x86":
		attrs.ArchValues.X86 = value
	case "x86_64":
		attrs.ArchValues.X86_64 = value
	case "arm":
		attrs.ArchValues.Arm = value
	case "arm64":
		attrs.ArchValues.Arm64 = value
	default:
	var v *LabelList
	if v = attrs.archValuePtrs()[arch]; v == nil {
		panic(fmt.Errorf("Unknown arch: %s", arch))
	}
	*v = value
}

func (attrs *LabelListAttribute) osValuePtrs() map[string]*LabelList {
	return map[string]*LabelList{
		OS_ANDROID:      &attrs.OsValues.Android,
		OS_DARWIN:       &attrs.OsValues.Darwin,
		OS_FUCHSIA:      &attrs.OsValues.Fuchsia,
		OS_LINUX:        &attrs.OsValues.Linux,
		OS_LINUX_BIONIC: &attrs.OsValues.LinuxBionic,
		OS_WINDOWS:      &attrs.OsValues.Windows,
	}
}

// GetValueForOS returns the label_list attribute value for an OS target.
func (attrs *LabelListAttribute) GetValueForOS(os string) LabelList {
	var v *LabelList
	if v = attrs.osValuePtrs()[os]; v == nil {
		panic(fmt.Errorf("Unknown os: %s", os))
	}
	return *v
}

// SetValueForArch sets the label_list attribute value for an OS target.
func (attrs *LabelListAttribute) SetValueForOS(os string, value LabelList) {
	var v *LabelList
	if v = attrs.osValuePtrs()[os]; v == nil {
		panic(fmt.Errorf("Unknown os: %s", os))
	}
	*v = value
}

// StringListAttribute corresponds to the string_list Bazel attribute type with
@@ -182,13 +264,12 @@ type stringListArchValues struct {
	X86_64 []string
	Arm    []string
	Arm64  []string
	// TODO(b/181299724): this is currently missing the "common" arch, which
	// doesn't have an equivalent platform() definition yet.
	Common []string
}

// HasArchSpecificValues returns true if the attribute contains
// HasConfigurableValues returns true if the attribute contains
// architecture-specific string_list values.
func (attrs *StringListAttribute) HasArchSpecificValues() bool {
func (attrs *StringListAttribute) HasConfigurableValues() bool {
	for _, arch := range selectableArchs {
		if len(attrs.GetValueForArch(arch)) > 0 {
			return true
@@ -197,36 +278,31 @@ func (attrs *StringListAttribute) HasArchSpecificValues() bool {
	return false
}

func (attrs *StringListAttribute) archValuePtrs() map[string]*[]string {
	return map[string]*[]string{
		ARCH_X86:    &attrs.ArchValues.X86,
		ARCH_X86_64: &attrs.ArchValues.X86_64,
		ARCH_ARM:    &attrs.ArchValues.Arm,
		ARCH_ARM64:  &attrs.ArchValues.Arm64,
	}
}

// GetValueForArch returns the string_list attribute value for an architecture.
func (attrs *StringListAttribute) GetValueForArch(arch string) []string {
	switch arch {
	case ARCH_X86:
		return attrs.ArchValues.X86
	case ARCH_X86_64:
		return attrs.ArchValues.X86_64
	case ARCH_ARM:
		return attrs.ArchValues.Arm
	case ARCH_ARM64:
		return attrs.ArchValues.Arm64
	default:
	var v *[]string
	if v = attrs.archValuePtrs()[arch]; v == nil {
		panic(fmt.Errorf("Unknown arch: %s", arch))
	}
	return *v
}

// SetValueForArch sets the string_list attribute value for an architecture.
func (attrs *StringListAttribute) SetValueForArch(arch string, value []string) {
	switch arch {
	case ARCH_X86:
		attrs.ArchValues.X86 = value
	case ARCH_X86_64:
		attrs.ArchValues.X86_64 = value
	case ARCH_ARM:
		attrs.ArchValues.Arm = value
	case ARCH_ARM64:
		attrs.ArchValues.Arm64 = value
	default:
	var v *[]string
	if v = attrs.archValuePtrs()[arch]; v == nil {
		panic(fmt.Errorf("Unknown arch: %s", arch))
	}
	*v = value
}

// TryVariableSubstitution, replace string substitution formatting within each string in slice with
+2 −54
Original line number Diff line number Diff line
@@ -416,63 +416,11 @@ func prettyPrint(propertyValue reflect.Value, indent int) (string, error) {
		// Special cases where the bp2build sends additional information to the codegenerator
		// by wrapping the attributes in a custom struct type.
		if labels, ok := propertyValue.Interface().(bazel.LabelListAttribute); ok {
			// TODO(b/165114590): convert glob syntax
			ret, err := prettyPrint(reflect.ValueOf(labels.Value.Includes), indent)
			if err != nil {
				return ret, err
			}

			if !labels.HasArchSpecificValues() {
				// Select statement not needed.
				return ret, nil
			}

			ret += " + " + "select({\n"
			for _, arch := range android.ArchTypeList() {
				value := labels.GetValueForArch(arch.Name)
				if len(value.Includes) > 0 {
					ret += makeIndent(indent + 1)
					list, _ := prettyPrint(reflect.ValueOf(value.Includes), indent+1)
					ret += fmt.Sprintf("\"%s\": %s,\n", platformArchMap[arch], list)
				}
			}

			ret += makeIndent(indent + 1)
			ret += fmt.Sprintf("\"%s\": [],\n", "//conditions:default")

			ret += makeIndent(indent)
			ret += "})"
			return ret, err
			return prettyPrintLabelListAttribute(labels, indent)
		} else if label, ok := propertyValue.Interface().(bazel.Label); ok {
			return fmt.Sprintf("%q", label.Label), nil
		} else if stringList, ok := propertyValue.Interface().(bazel.StringListAttribute); ok {
			// A Bazel string_list attribute that may contain a select statement.
			ret, err := prettyPrint(reflect.ValueOf(stringList.Value), indent)
			if err != nil {
				return ret, err
			}

			if !stringList.HasArchSpecificValues() {
				// Select statement not needed.
				return ret, nil
			}

			ret += " + " + "select({\n"
			for _, arch := range android.ArchTypeList() {
				value := stringList.GetValueForArch(arch.Name)
				if len(value) > 0 {
					ret += makeIndent(indent + 1)
					list, _ := prettyPrint(reflect.ValueOf(value), indent+1)
					ret += fmt.Sprintf("\"%s\": %s,\n", platformArchMap[arch], list)
				}
			}

			ret += makeIndent(indent + 1)
			ret += fmt.Sprintf("\"%s\": [],\n", "//conditions:default")

			ret += makeIndent(indent)
			ret += "})"
			return ret, err
			return prettyPrintStringListAttribute(stringList, indent)
		}

		ret = "{\n"
Loading