Refactor how bp2build gets arch-specific props. am: 598dd00236

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/1697045

Change-Id: I11c6111fe77cbddb023a4550c44e6780e8f70f64
This commit is contained in:
Lukacs T. Berki 2021-05-05 09:39:01 +00:00 committed by Automerger Merge Worker
commit a2f68505af
5 changed files with 325 additions and 206 deletions

View File

@ -1014,35 +1014,19 @@ func initArchModule(m Module) {
base.customizableProperties = m.GetProperties()
}
// appendProperties squashes properties from the given field of the given src property struct
// into the dst property struct. Returns the reflect.Value of the field in the src property
// struct to be used for further appendProperties calls on fields of that property struct.
func (m *ModuleBase) appendProperties(ctx BottomUpMutatorContext,
dst interface{}, src reflect.Value, field, srcPrefix string) reflect.Value {
// Step into non-nil pointers to structs in the src value.
if src.Kind() == reflect.Ptr {
if src.IsNil() {
return src
}
src = src.Elem()
}
// Find the requested field in the src struct.
src = src.FieldByName(field)
if !src.IsValid() {
ctx.ModuleErrorf("field %q does not exist", srcPrefix)
return src
}
// Save the value of the field in the src struct to return.
ret := src
func maybeBlueprintEmbed(src reflect.Value) reflect.Value {
// If the value of the field is a struct (as opposed to a pointer to a struct) then step
// into the BlueprintEmbed field.
if src.Kind() == reflect.Struct {
src = src.FieldByName("BlueprintEmbed")
return src.FieldByName("BlueprintEmbed")
} else {
return src
}
}
// Merges the property struct in srcValue into dst.
func mergePropertyStruct(ctx BaseMutatorContext, dst interface{}, srcValue reflect.Value) {
src := maybeBlueprintEmbed(srcValue).Interface()
// order checks the `android:"variant_prepend"` tag to handle properties where the
// arch-specific value needs to come before the generic value, for example for lists of
@ -1058,7 +1042,7 @@ func (m *ModuleBase) appendProperties(ctx BottomUpMutatorContext,
}
// Squash the located property struct into the destination property struct.
err := proptools.ExtendMatchingProperties([]interface{}{dst}, src.Interface(), nil, order)
err := proptools.ExtendMatchingProperties([]interface{}{dst}, src, nil, order)
if err != nil {
if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
@ -1066,8 +1050,29 @@ func (m *ModuleBase) appendProperties(ctx BottomUpMutatorContext,
panic(err)
}
}
}
return ret
// Returns the immediate child of the input property struct that corresponds to
// the sub-property "field".
func getChildPropertyStruct(ctx BaseMutatorContext,
src reflect.Value, field, userFriendlyField string) reflect.Value {
// Step into non-nil pointers to structs in the src value.
if src.Kind() == reflect.Ptr {
if src.IsNil() {
return src
}
src = src.Elem()
}
// Find the requested field in the src struct.
src = src.FieldByName(proptools.FieldNameForProperty(field))
if !src.IsValid() {
ctx.ModuleErrorf("field %q does not exist", userFriendlyField)
return src
}
return src
}
// Squash the appropriate OS-specific property structs into the matching top level property structs
@ -1094,7 +1099,8 @@ func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
if os.Class == Host {
field := "Host"
prefix := "target.host"
m.appendProperties(ctx, genProps, targetProp, field, prefix)
hostProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
mergePropertyStruct(ctx, genProps, hostProperties)
}
// Handle target OS generalities of the form:
@ -1106,13 +1112,15 @@ func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
if os.Linux() {
field := "Linux"
prefix := "target.linux"
m.appendProperties(ctx, genProps, targetProp, field, prefix)
linuxProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
mergePropertyStruct(ctx, genProps, linuxProperties)
}
if os.Bionic() {
field := "Bionic"
prefix := "target.bionic"
m.appendProperties(ctx, genProps, targetProp, field, prefix)
bionicProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
mergePropertyStruct(ctx, genProps, bionicProperties)
}
// Handle target OS properties in the form:
@ -1129,12 +1137,14 @@ func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
// },
field := os.Field
prefix := "target." + os.Name
m.appendProperties(ctx, genProps, targetProp, field, prefix)
osProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
mergePropertyStruct(ctx, genProps, osProperties)
if os.Class == Host && os != Windows {
field := "Not_windows"
prefix := "target.not_windows"
m.appendProperties(ctx, genProps, targetProp, field, prefix)
notWindowsProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
mergePropertyStruct(ctx, genProps, notWindowsProperties)
}
// Handle 64-bit device properties in the form:
@ -1154,98 +1164,112 @@ func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
if ctx.Config().Android64() {
field := "Android64"
prefix := "target.android64"
m.appendProperties(ctx, genProps, targetProp, field, prefix)
android64Properties := getChildPropertyStruct(ctx, targetProp, field, prefix)
mergePropertyStruct(ctx, genProps, android64Properties)
} else {
field := "Android32"
prefix := "target.android32"
m.appendProperties(ctx, genProps, targetProp, field, prefix)
android32Properties := getChildPropertyStruct(ctx, targetProp, field, prefix)
mergePropertyStruct(ctx, genProps, android32Properties)
}
}
}
}
}
// Squash the appropriate arch-specific property structs into the matching top level property
// structs based on the CompileTarget value that was annotated on the variant.
func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
arch := m.Arch()
os := m.Os()
// Returns the struct containing the properties specific to the given
// architecture type. These look like this in Blueprint files:
// arch: {
// arm64: {
// key: value,
// },
// },
// This struct will also contain sub-structs containing to the architecture/CPU
// variants and features that themselves contain properties specific to those.
func getArchTypeStruct(ctx BaseMutatorContext, archProperties interface{}, archType ArchType) reflect.Value {
archPropValues := reflect.ValueOf(archProperties).Elem()
archProp := archPropValues.FieldByName("Arch").Elem()
prefix := "arch." + archType.Name
archStruct := getChildPropertyStruct(ctx, archProp, archType.Name, prefix)
return archStruct
}
for i := range m.generalProperties {
genProps := m.generalProperties[i]
if m.archProperties[i] == nil {
continue
}
for _, archProperties := range m.archProperties[i] {
// Returns the struct containing the properties specific to a given multilib
// value. These look like this in the Blueprint file:
// multilib: {
// lib32: {
// key: value,
// },
// },
func getMultilibStruct(ctx BaseMutatorContext, archProperties interface{}, archType ArchType) reflect.Value {
archPropValues := reflect.ValueOf(archProperties).Elem()
multilibProp := archPropValues.FieldByName("Multilib").Elem()
multilibProperties := getChildPropertyStruct(ctx, multilibProp, archType.Multilib, "multilib."+archType.Multilib)
return multilibProperties
}
// Returns the structs corresponding to the properties specific to the given
// architecture and OS in archProperties.
func getArchProperties(ctx BaseMutatorContext, archProperties interface{}, arch Arch, os OsType, nativeBridgeEnabled bool) []reflect.Value {
result := make([]reflect.Value, 0)
archPropValues := reflect.ValueOf(archProperties).Elem()
archProp := archPropValues.FieldByName("Arch").Elem()
multilibProp := archPropValues.FieldByName("Multilib").Elem()
targetProp := archPropValues.FieldByName("Target").Elem()
// Handle arch-specific properties in the form:
// arch: {
// arm64: {
// key: value,
// },
// },
t := arch.ArchType
archType := arch.ArchType
if arch.ArchType != Common {
field := proptools.FieldNameForProperty(t.Name)
prefix := "arch." + t.Name
archStruct := m.appendProperties(ctx, genProps, archProp, field, prefix)
archStruct := getArchTypeStruct(ctx, archProperties, arch.ArchType)
result = append(result, archStruct)
// Handle arch-variant-specific properties in the form:
// arch: {
// arm: {
// variant: {
// key: value,
// },
// },
// },
v := variantReplacer.Replace(arch.ArchVariant)
if v != "" {
field := proptools.FieldNameForProperty(v)
prefix := "arch." + t.Name + "." + v
m.appendProperties(ctx, genProps, archStruct, field, prefix)
prefix := "arch." + archType.Name + "." + v
variantProperties := getChildPropertyStruct(ctx, archStruct, v, prefix)
result = append(result, variantProperties)
}
// Handle cpu-variant-specific properties in the form:
// arch: {
// arm: {
// variant: {
// key: value,
// },
// },
// },
if arch.CpuVariant != arch.ArchVariant {
c := variantReplacer.Replace(arch.CpuVariant)
if c != "" {
field := proptools.FieldNameForProperty(c)
prefix := "arch." + t.Name + "." + c
m.appendProperties(ctx, genProps, archStruct, field, prefix)
prefix := "arch." + archType.Name + "." + c
cpuVariantProperties := getChildPropertyStruct(ctx, archStruct, c, prefix)
result = append(result, cpuVariantProperties)
}
}
// Handle arch-feature-specific properties in the form:
// arch: {
// arm: {
// feature: {
// key: value,
// },
// },
// },
for _, feature := range arch.ArchFeatures {
field := proptools.FieldNameForProperty(feature)
prefix := "arch." + t.Name + "." + feature
m.appendProperties(ctx, genProps, archStruct, field, prefix)
prefix := "arch." + archType.Name + "." + feature
featureProperties := getChildPropertyStruct(ctx, archStruct, feature, prefix)
result = append(result, featureProperties)
}
// Handle multilib-specific properties in the form:
// multilib: {
// lib32: {
// key: value,
// },
// },
field = proptools.FieldNameForProperty(t.Multilib)
prefix = "multilib." + t.Multilib
m.appendProperties(ctx, genProps, multilibProp, field, prefix)
}
multilibProperties := getMultilibStruct(ctx, archProperties, archType)
result = append(result, multilibProperties)
// Handle combined OS-feature and arch specific properties in the form:
// target: {
@ -1253,16 +1277,18 @@ func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
// key: value,
// },
// }
if os.Linux() && arch.ArchType != Common {
if os.Linux() {
field := "Linux_" + arch.ArchType.Name
prefix := "target.linux_" + arch.ArchType.Name
m.appendProperties(ctx, genProps, targetProp, field, prefix)
userFriendlyField := "target.linux_" + arch.ArchType.Name
linuxProperties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
result = append(result, linuxProperties)
}
if os.Bionic() && arch.ArchType != Common {
field := "Bionic_" + t.Name
prefix := "target.bionic_" + t.Name
m.appendProperties(ctx, genProps, targetProp, field, prefix)
if os.Bionic() {
field := "Bionic_" + archType.Name
userFriendlyField := "target.bionic_" + archType.Name
bionicProperties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
result = append(result, bionicProperties)
}
// Handle combined OS and arch specific properties in the form:
@ -1280,10 +1306,10 @@ func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
// key: value,
// },
// },
if arch.ArchType != Common {
field := os.Field + "_" + t.Name
prefix := "target." + os.Name + "_" + t.Name
m.appendProperties(ctx, genProps, targetProp, field, prefix)
field := os.Field + "_" + archType.Name
userFriendlyField := "target." + os.Name + "_" + archType.Name
osArchProperties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
result = append(result, osArchProperties)
}
// Handle arm on x86 properties in the form:
@ -1299,21 +1325,48 @@ func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
if arch.ArchType == X86 && (hasArmAbi(arch) ||
hasArmAndroidArch(ctx.Config().Targets[Android])) {
field := "Arm_on_x86"
prefix := "target.arm_on_x86"
m.appendProperties(ctx, genProps, targetProp, field, prefix)
userFriendlyField := "target.arm_on_x86"
armOnX86Properties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
result = append(result, armOnX86Properties)
}
if arch.ArchType == X86_64 && (hasArmAbi(arch) ||
hasArmAndroidArch(ctx.Config().Targets[Android])) {
field := "Arm_on_x86_64"
prefix := "target.arm_on_x86_64"
m.appendProperties(ctx, genProps, targetProp, field, prefix)
userFriendlyField := "target.arm_on_x86_64"
armOnX8664Properties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
result = append(result, armOnX8664Properties)
}
if os == Android && m.Target().NativeBridge == NativeBridgeEnabled {
field := "Native_bridge"
if os == Android && nativeBridgeEnabled {
userFriendlyField := "Native_bridge"
prefix := "target.native_bridge"
m.appendProperties(ctx, genProps, targetProp, field, prefix)
nativeBridgeProperties := getChildPropertyStruct(ctx, targetProp, userFriendlyField, prefix)
result = append(result, nativeBridgeProperties)
}
}
return result
}
// Squash the appropriate arch-specific property structs into the matching top level property
// structs based on the CompileTarget value that was annotated on the variant.
func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
arch := m.Arch()
os := m.Os()
for i := range m.generalProperties {
genProps := m.generalProperties[i]
if m.archProperties[i] == nil {
continue
}
propStructs := make([]reflect.Value, 0)
for _, archProperty := range m.archProperties[i] {
propStructShard := getArchProperties(ctx, archProperty, arch, os, m.Target().NativeBridge == NativeBridgeEnabled)
propStructs = append(propStructs, propStructShard...)
}
for _, propStruct := range propStructs {
mergePropertyStruct(ctx, genProps, propStruct)
}
}
}
@ -1810,7 +1863,7 @@ func (m *ModuleBase) getMultilibPropertySet(propertySet interface{}, archType Ar
// For example: `arch: { x86: { Foo: ["bar"] } }, multilib: { lib32: {` Foo: ["baz"] } }`
// will result in `Foo: ["bar", "baz"]` being returned for architecture x86, if the given
// propertyset contains `Foo []string`.
func (m *ModuleBase) GetArchProperties(propertySet interface{}) map[ArchType]interface{} {
func (m *ModuleBase) GetArchProperties(ctx BaseMutatorContext, propertySet interface{}) map[ArchType]interface{} {
// Return value of the arch types to the prop values for that arch.
archToProp := map[ArchType]interface{}{}
@ -1819,27 +1872,47 @@ func (m *ModuleBase) GetArchProperties(propertySet interface{}) map[ArchType]int
return archToProp
}
// For each arch (x86, arm64, etc.),
dstType := reflect.ValueOf(propertySet).Type()
var archProperties []interface{}
// First find the property set in the module that corresponds to the requested
// one. m.archProperties[i] corresponds to m.generalProperties[i].
for i, generalProp := range m.generalProperties {
srcType := reflect.ValueOf(generalProp).Type()
if srcType == dstType {
archProperties = m.archProperties[i]
break
}
}
if archProperties == nil {
// This module does not have the property set requested
return archToProp
}
// For each arch type (x86, arm64, etc.)
for _, arch := range ArchTypeList() {
// Find arch-specific properties matching that property set type. For example, any
// matching properties under `arch { x86 { ... } }`.
archPropertySet := m.getArchPropertySet(propertySet, arch)
// Find multilib-specific properties matching that property set type. For example, any
// matching properties under `multilib { lib32 { ... } }` for x86, as x86 is 32-bit.
multilibPropertySet := m.getMultilibPropertySet(propertySet, arch)
// Append the multilibPropertySet to archPropertySet. This combines the
// arch and multilib properties into a single property struct.
err := proptools.ExtendMatchingProperties([]interface{}{archPropertySet}, multilibPropertySet, nil, proptools.OrderAppend)
if err != nil {
// archPropertySet and multilibPropertySet must be of the same type, or
// something horrible went wrong.
panic(err)
// Arch properties are sometimes sharded (see createArchPropTypeDesc() ).
// Iterate over ever shard and extract a struct with the same type as the
// input one that contains the data specific to that arch.
propertyStructs := make([]reflect.Value, 0)
for _, archProperty := range archProperties {
archTypeStruct := getArchTypeStruct(ctx, archProperty, arch)
multilibStruct := getMultilibStruct(ctx, archProperty, arch)
propertyStructs = append(propertyStructs, archTypeStruct, multilibStruct)
}
archToProp[arch] = archPropertySet
// Create a new instance of the requested property set
value := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()
// Merge all the structs together
for _, propertyStruct := range propertyStructs {
mergePropertyStruct(ctx, value, propertyStruct)
}
archToProp[arch] = value
}
return archToProp
}

View File

@ -230,10 +230,46 @@ type Attribute interface {
// Represents an attribute whose value is a single label
type LabelAttribute struct {
Value Label
X86 Label
X86_64 Label
Arm Label
Arm64 Label
}
func (LabelAttribute) HasConfigurableValues() bool {
return false
func (attr *LabelAttribute) GetValueForArch(arch string) Label {
switch arch {
case ARCH_ARM:
return attr.Arm
case ARCH_ARM64:
return attr.Arm64
case ARCH_X86:
return attr.X86
case ARCH_X86_64:
return attr.X86_64
case CONDITIONS_DEFAULT:
return attr.Value
default:
panic("Invalid arch type")
}
}
func (attr *LabelAttribute) SetValueForArch(arch string, value Label) {
switch arch {
case ARCH_ARM:
attr.Arm = value
case ARCH_ARM64:
attr.Arm64 = value
case ARCH_X86:
attr.X86 = value
case ARCH_X86_64:
attr.X86_64 = value
default:
panic("Invalid arch type")
}
}
func (attr LabelAttribute) HasConfigurableValues() bool {
return attr.Arm.Label != "" || attr.Arm64.Label != "" || attr.X86.Label != "" || attr.X86_64.Label != ""
}
// Arch-specific label_list typed Bazel attribute values. This should correspond

View File

@ -59,22 +59,30 @@ func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, selects,
func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
var value reflect.Value
var archSelects, osSelects selects
var defaultSelectValue string
switch list := v.(type) {
case bazel.StringListAttribute:
value, archSelects, osSelects = getStringListValues(list)
defaultSelectValue = "[]"
case bazel.LabelListAttribute:
value, archSelects, osSelects = getLabelListValues(list)
defaultSelectValue = "[]"
case bazel.LabelAttribute:
value, archSelects, osSelects = getLabelValue(list)
defaultSelectValue = "None"
default:
return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
}
ret, err := prettyPrint(value, indent)
ret := ""
if value.Kind() != reflect.Invalid {
s, err := prettyPrint(value, indent)
if err != nil {
return ret, err
}
ret += s
}
// Convenience function to append selects components to an attribute value.
appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
@ -89,12 +97,12 @@ func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
return s, nil
}
ret, err = appendSelects(archSelects, "[]", ret)
ret, err := appendSelects(archSelects, defaultSelectValue, ret)
if err != nil {
return "", err
}
ret, err = appendSelects(osSelects, "[]", ret)
ret, err = appendSelects(osSelects, defaultSelectValue, ret)
return ret, err
}

View File

@ -142,7 +142,7 @@ func customBp2BuildMutator(ctx android.TopDownMutatorContext) {
paths := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.props.Arch_paths))
for arch, props := range m.GetArchProperties(&customProps{}) {
for arch, props := range m.GetArchProperties(ctx, &customProps{}) {
if archProps, ok := props.(*customProps); ok && archProps.Arch_paths != nil {
paths.SetValueForArch(arch.Name, android.BazelLabelForModuleSrc(ctx, archProps.Arch_paths))
}

View File

@ -58,7 +58,7 @@ func depsBp2BuildMutator(ctx android.BottomUpMutatorContext) {
}
}
for _, p := range module.GetArchProperties(&BaseLinkerProperties{}) {
for _, p := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) {
// arch specific linker props
if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
allDeps = append(allDeps, baseLinkerProps.Header_libs...)
@ -198,7 +198,7 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul
copts.Value = append(copts.Value, includeFlag("."))
}
for arch, props := range module.GetArchProperties(&BaseCompilerProperties{}) {
for arch, props := range module.GetArchProperties(ctx, &BaseCompilerProperties{}) {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
// If there's arch specific srcs or exclude_srcs, generate a select entry for it.
// TODO(b/186153868): do this for OS specific srcs and exclude_srcs too.
@ -215,7 +215,7 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul
// After going through all archs, delete the duplicate files in the arch
// values that are already in the base srcs.Value.
for arch, props := range module.GetArchProperties(&BaseCompilerProperties{}) {
for arch, props := range module.GetArchProperties(ctx, &BaseCompilerProperties{}) {
if _, ok := props.(*BaseCompilerProperties); ok {
srcs.SetValueForArch(arch.Name, bazel.SubtractBazelLabelList(srcs.GetValueForArch(arch.Name), srcs.Value))
}
@ -269,15 +269,13 @@ func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module)
linkopts.Value = baseLinkerProps.Ldflags
if baseLinkerProps.Version_script != nil {
versionScript = bazel.LabelAttribute{
Value: android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script),
}
versionScript.Value = android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script)
}
break
}
}
for arch, p := range module.GetArchProperties(&BaseLinkerProperties{}) {
for arch, p := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) {
if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
libs := baseLinkerProps.Header_libs
libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
@ -286,6 +284,10 @@ func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module)
libs = android.SortedUniqueStrings(libs)
deps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, libs))
linkopts.SetValueForArch(arch.Name, baseLinkerProps.Ldflags)
if baseLinkerProps.Version_script != nil {
versionScript.SetValueForArch(arch.Name,
android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script))
}
}
}
@ -343,7 +345,7 @@ func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Mo
includeDirs = append(includeDirs, libraryDecorator.flagExporter.Properties.Export_include_dirs...)
includeDirsAttribute := bazel.MakeStringListAttribute(includeDirs)
for arch, props := range module.GetArchProperties(&FlagExporterProperties{}) {
for arch, props := range module.GetArchProperties(ctx, &FlagExporterProperties{}) {
if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
archIncludeDirs := flagExporterProperties.Export_system_include_dirs
archIncludeDirs = append(archIncludeDirs, flagExporterProperties.Export_include_dirs...)