Merge "Refactor GetTargetProperties()."

This commit is contained in:
Lukács T. Berki
2021-05-17 14:17:54 +00:00
committed by Gerrit Code Review
2 changed files with 174 additions and 154 deletions

View File

@@ -1055,24 +1055,28 @@ func mergePropertyStruct(ctx ArchVariantContext, dst interface{}, srcValue refle
// Returns the immediate child of the input property struct that corresponds to // Returns the immediate child of the input property struct that corresponds to
// the sub-property "field". // the sub-property "field".
func getChildPropertyStruct(ctx ArchVariantContext, func getChildPropertyStruct(ctx ArchVariantContext,
src reflect.Value, field, userFriendlyField string) reflect.Value { src reflect.Value, field, userFriendlyField string) (reflect.Value, bool) {
// Step into non-nil pointers to structs in the src value. // Step into non-nil pointers to structs in the src value.
if src.Kind() == reflect.Ptr { if src.Kind() == reflect.Ptr {
if src.IsNil() { if src.IsNil() {
return src return reflect.Value{}, false
} }
src = src.Elem() src = src.Elem()
} }
// Find the requested field in the src struct. // Find the requested field in the src struct.
src = src.FieldByName(proptools.FieldNameForProperty(field)) child := src.FieldByName(proptools.FieldNameForProperty(field))
if !src.IsValid() { if !child.IsValid() {
ctx.ModuleErrorf("field %q does not exist", userFriendlyField) ctx.ModuleErrorf("field %q does not exist", userFriendlyField)
return src return reflect.Value{}, false
} }
return src if child.IsZero() {
return reflect.Value{}, false
}
return child, true
} }
// Squash the appropriate OS-specific property structs into the matching top level property structs // Squash the appropriate OS-specific property structs into the matching top level property structs
@@ -1099,8 +1103,9 @@ func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
if os.Class == Host { if os.Class == Host {
field := "Host" field := "Host"
prefix := "target.host" prefix := "target.host"
hostProperties := getChildPropertyStruct(ctx, targetProp, field, prefix) if hostProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
mergePropertyStruct(ctx, genProps, hostProperties) mergePropertyStruct(ctx, genProps, hostProperties)
}
} }
// Handle target OS generalities of the form: // Handle target OS generalities of the form:
@@ -1112,15 +1117,17 @@ func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
if os.Linux() { if os.Linux() {
field := "Linux" field := "Linux"
prefix := "target.linux" prefix := "target.linux"
linuxProperties := getChildPropertyStruct(ctx, targetProp, field, prefix) if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
mergePropertyStruct(ctx, genProps, linuxProperties) mergePropertyStruct(ctx, genProps, linuxProperties)
}
} }
if os.Bionic() { if os.Bionic() {
field := "Bionic" field := "Bionic"
prefix := "target.bionic" prefix := "target.bionic"
bionicProperties := getChildPropertyStruct(ctx, targetProp, field, prefix) if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
mergePropertyStruct(ctx, genProps, bionicProperties) mergePropertyStruct(ctx, genProps, bionicProperties)
}
} }
// Handle target OS properties in the form: // Handle target OS properties in the form:
@@ -1137,14 +1144,16 @@ func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
// }, // },
field := os.Field field := os.Field
prefix := "target." + os.Name prefix := "target." + os.Name
osProperties := getChildPropertyStruct(ctx, targetProp, field, prefix) if osProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
mergePropertyStruct(ctx, genProps, osProperties) mergePropertyStruct(ctx, genProps, osProperties)
}
if os.Class == Host && os != Windows { if os.Class == Host && os != Windows {
field := "Not_windows" field := "Not_windows"
prefix := "target.not_windows" prefix := "target.not_windows"
notWindowsProperties := getChildPropertyStruct(ctx, targetProp, field, prefix) if notWindowsProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
mergePropertyStruct(ctx, genProps, notWindowsProperties) mergePropertyStruct(ctx, genProps, notWindowsProperties)
}
} }
// Handle 64-bit device properties in the form: // Handle 64-bit device properties in the form:
@@ -1164,13 +1173,15 @@ func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
if ctx.Config().Android64() { if ctx.Config().Android64() {
field := "Android64" field := "Android64"
prefix := "target.android64" prefix := "target.android64"
android64Properties := getChildPropertyStruct(ctx, targetProp, field, prefix) if android64Properties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
mergePropertyStruct(ctx, genProps, android64Properties) mergePropertyStruct(ctx, genProps, android64Properties)
}
} else { } else {
field := "Android32" field := "Android32"
prefix := "target.android32" prefix := "target.android32"
android32Properties := getChildPropertyStruct(ctx, targetProp, field, prefix) if android32Properties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
mergePropertyStruct(ctx, genProps, android32Properties) mergePropertyStruct(ctx, genProps, android32Properties)
}
} }
} }
} }
@@ -1186,12 +1197,11 @@ func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
// }, // },
// This struct will also contain sub-structs containing to the architecture/CPU // This struct will also contain sub-structs containing to the architecture/CPU
// variants and features that themselves contain properties specific to those. // variants and features that themselves contain properties specific to those.
func getArchTypeStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) reflect.Value { func getArchTypeStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) (reflect.Value, bool) {
archPropValues := reflect.ValueOf(archProperties).Elem() archPropValues := reflect.ValueOf(archProperties).Elem()
archProp := archPropValues.FieldByName("Arch").Elem() archProp := archPropValues.FieldByName("Arch").Elem()
prefix := "arch." + archType.Name prefix := "arch." + archType.Name
archStruct := getChildPropertyStruct(ctx, archProp, archType.Name, prefix) return getChildPropertyStruct(ctx, archProp, archType.Name, prefix)
return archStruct
} }
// Returns the struct containing the properties specific to a given multilib // Returns the struct containing the properties specific to a given multilib
@@ -1201,11 +1211,10 @@ func getArchTypeStruct(ctx ArchVariantContext, archProperties interface{}, archT
// key: value, // key: value,
// }, // },
// }, // },
func getMultilibStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) reflect.Value { func getMultilibStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) (reflect.Value, bool) {
archPropValues := reflect.ValueOf(archProperties).Elem() archPropValues := reflect.ValueOf(archProperties).Elem()
multilibProp := archPropValues.FieldByName("Multilib").Elem() multilibProp := archPropValues.FieldByName("Multilib").Elem()
multilibProperties := getChildPropertyStruct(ctx, multilibProp, archType.Multilib, "multilib."+archType.Multilib) return getChildPropertyStruct(ctx, multilibProp, archType.Multilib, "multilib."+archType.Multilib)
return multilibProperties
} }
// Returns the structs corresponding to the properties specific to the given // Returns the structs corresponding to the properties specific to the given
@@ -1219,58 +1228,64 @@ func getArchProperties(ctx BaseMutatorContext, archProperties interface{}, arch
archType := arch.ArchType archType := arch.ArchType
if arch.ArchType != Common { if arch.ArchType != Common {
archStruct := getArchTypeStruct(ctx, archProperties, arch.ArchType) archStruct, ok := getArchTypeStruct(ctx, archProperties, arch.ArchType)
result = append(result, archStruct) if ok {
result = append(result, archStruct)
// Handle arch-variant-specific properties in the form: // Handle arch-variant-specific properties in the form:
// arch: { // arch: {
// arm: { // arm: {
// variant: { // variant: {
// key: value, // key: value,
// }, // },
// }, // },
// }, // },
v := variantReplacer.Replace(arch.ArchVariant) v := variantReplacer.Replace(arch.ArchVariant)
if v != "" { if v != "" {
prefix := "arch." + archType.Name + "." + v prefix := "arch." + archType.Name + "." + v
variantProperties := getChildPropertyStruct(ctx, archStruct, v, prefix) if variantProperties, ok := getChildPropertyStruct(ctx, archStruct, v, prefix); ok {
result = append(result, variantProperties) result = append(result, variantProperties)
} }
}
// Handle cpu-variant-specific properties in the form: // Handle cpu-variant-specific properties in the form:
// arch: { // arch: {
// arm: { // arm: {
// variant: { // variant: {
// key: value, // key: value,
// }, // },
// }, // },
// }, // },
if arch.CpuVariant != arch.ArchVariant { if arch.CpuVariant != arch.ArchVariant {
c := variantReplacer.Replace(arch.CpuVariant) c := variantReplacer.Replace(arch.CpuVariant)
if c != "" { if c != "" {
prefix := "arch." + archType.Name + "." + c prefix := "arch." + archType.Name + "." + c
cpuVariantProperties := getChildPropertyStruct(ctx, archStruct, c, prefix) if cpuVariantProperties, ok := getChildPropertyStruct(ctx, archStruct, c, prefix); ok {
result = append(result, cpuVariantProperties) result = append(result, cpuVariantProperties)
}
}
}
// Handle arch-feature-specific properties in the form:
// arch: {
// arm: {
// feature: {
// key: value,
// },
// },
// },
for _, feature := range arch.ArchFeatures {
prefix := "arch." + archType.Name + "." + feature
if featureProperties, ok := getChildPropertyStruct(ctx, archStruct, feature, prefix); ok {
result = append(result, featureProperties)
}
} }
} }
// Handle arch-feature-specific properties in the form: if multilibProperties, ok := getMultilibStruct(ctx, archProperties, archType); ok {
// arch: { result = append(result, multilibProperties)
// arm: {
// feature: {
// key: value,
// },
// },
// },
for _, feature := range arch.ArchFeatures {
prefix := "arch." + archType.Name + "." + feature
featureProperties := getChildPropertyStruct(ctx, archStruct, feature, prefix)
result = append(result, featureProperties)
} }
multilibProperties := getMultilibStruct(ctx, archProperties, archType)
result = append(result, multilibProperties)
// Handle combined OS-feature and arch specific properties in the form: // Handle combined OS-feature and arch specific properties in the form:
// target: { // target: {
// bionic_x86: { // bionic_x86: {
@@ -1280,15 +1295,17 @@ func getArchProperties(ctx BaseMutatorContext, archProperties interface{}, arch
if os.Linux() { if os.Linux() {
field := "Linux_" + arch.ArchType.Name field := "Linux_" + arch.ArchType.Name
userFriendlyField := "target.linux_" + arch.ArchType.Name userFriendlyField := "target.linux_" + arch.ArchType.Name
linuxProperties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField) if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
result = append(result, linuxProperties) result = append(result, linuxProperties)
}
} }
if os.Bionic() { if os.Bionic() {
field := "Bionic_" + archType.Name field := "Bionic_" + archType.Name
userFriendlyField := "target.bionic_" + archType.Name userFriendlyField := "target.bionic_" + archType.Name
bionicProperties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField) if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
result = append(result, bionicProperties) result = append(result, bionicProperties)
}
} }
// Handle combined OS and arch specific properties in the form: // Handle combined OS and arch specific properties in the form:
@@ -1308,8 +1325,9 @@ func getArchProperties(ctx BaseMutatorContext, archProperties interface{}, arch
// }, // },
field := os.Field + "_" + archType.Name field := os.Field + "_" + archType.Name
userFriendlyField := "target." + os.Name + "_" + archType.Name userFriendlyField := "target." + os.Name + "_" + archType.Name
osArchProperties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField) if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
result = append(result, osArchProperties) result = append(result, osArchProperties)
}
} }
// Handle arm on x86 properties in the form: // Handle arm on x86 properties in the form:
@@ -1326,21 +1344,24 @@ func getArchProperties(ctx BaseMutatorContext, archProperties interface{}, arch
hasArmAndroidArch(ctx.Config().Targets[Android])) { hasArmAndroidArch(ctx.Config().Targets[Android])) {
field := "Arm_on_x86" field := "Arm_on_x86"
userFriendlyField := "target.arm_on_x86" userFriendlyField := "target.arm_on_x86"
armOnX86Properties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField) if armOnX86Properties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
result = append(result, armOnX86Properties) result = append(result, armOnX86Properties)
}
} }
if arch.ArchType == X86_64 && (hasArmAbi(arch) || if arch.ArchType == X86_64 && (hasArmAbi(arch) ||
hasArmAndroidArch(ctx.Config().Targets[Android])) { hasArmAndroidArch(ctx.Config().Targets[Android])) {
field := "Arm_on_x86_64" field := "Arm_on_x86_64"
userFriendlyField := "target.arm_on_x86_64" userFriendlyField := "target.arm_on_x86_64"
armOnX8664Properties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField) if armOnX8664Properties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
result = append(result, armOnX8664Properties) result = append(result, armOnX8664Properties)
}
} }
if os == Android && nativeBridgeEnabled { if os == Android && nativeBridgeEnabled {
userFriendlyField := "Native_bridge" userFriendlyField := "Native_bridge"
prefix := "target.native_bridge" prefix := "target.native_bridge"
nativeBridgeProperties := getChildPropertyStruct(ctx, targetProp, userFriendlyField, prefix) if nativeBridgeProperties, ok := getChildPropertyStruct(ctx, targetProp, userFriendlyField, prefix); ok {
result = append(result, nativeBridgeProperties) result = append(result, nativeBridgeProperties)
}
} }
} }
@@ -1869,6 +1890,8 @@ type ArchVariantContext interface {
// For example: `arch: { x86: { Foo: ["bar"] } }, multilib: { lib32: {` Foo: ["baz"] } }` // For example: `arch: { x86: { Foo: ["bar"] } }, multilib: { lib32: {` Foo: ["baz"] } }`
// will result in `Foo: ["bar", "baz"]` being returned for architecture x86, if the given // will result in `Foo: ["bar", "baz"]` being returned for architecture x86, if the given
// propertyset contains `Foo []string`. // propertyset contains `Foo []string`.
//
// Implemented in a way very similar to GetTargetProperties().
func (m *ModuleBase) GetArchProperties(ctx ArchVariantContext, propertySet interface{}) map[ArchType]interface{} { func (m *ModuleBase) GetArchProperties(ctx ArchVariantContext, propertySet interface{}) map[ArchType]interface{} {
// Return value of the arch types to the prop values for that arch. // Return value of the arch types to the prop values for that arch.
archToProp := map[ArchType]interface{}{} archToProp := map[ArchType]interface{}{}
@@ -1903,9 +1926,14 @@ func (m *ModuleBase) GetArchProperties(ctx ArchVariantContext, propertySet inter
// input one that contains the data specific to that arch. // input one that contains the data specific to that arch.
propertyStructs := make([]reflect.Value, 0) propertyStructs := make([]reflect.Value, 0)
for _, archProperty := range archProperties { for _, archProperty := range archProperties {
archTypeStruct := getArchTypeStruct(ctx, archProperty, arch) archTypeStruct, ok := getArchTypeStruct(ctx, archProperty, arch)
multilibStruct := getMultilibStruct(ctx, archProperty, arch) if ok {
propertyStructs = append(propertyStructs, archTypeStruct, multilibStruct) propertyStructs = append(propertyStructs, archTypeStruct)
}
multilibStruct, ok := getMultilibStruct(ctx, archProperty, arch)
if ok {
propertyStructs = append(propertyStructs, multilibStruct)
}
} }
// Create a new instance of the requested property set // Create a new instance of the requested property set
@@ -1922,18 +1950,31 @@ func (m *ModuleBase) GetArchProperties(ctx ArchVariantContext, propertySet inter
return archToProp return archToProp
} }
// Returns the struct containing the properties specific to the given
// architecture type. These look like this in Blueprint files:
// target: {
// android: {
// 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 getTargetStruct(ctx ArchVariantContext, archProperties interface{}, os OsType) (reflect.Value, bool) {
archPropValues := reflect.ValueOf(archProperties).Elem()
targetProp := archPropValues.FieldByName("Target").Elem()
return getChildPropertyStruct(ctx, targetProp, os.Field, os.Field)
}
// GetTargetProperties returns a map of OS target (e.g. android, windows) to the // 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 // values of the properties of the 'propertySet' struct that are specific to
// target. // that OS target.
// //
// For example, passing a struct { Foo bool, Bar string } will return an // For example, passing a struct { Foo bool, Bar string } will return an
// interface{} that can be type asserted back into the same struct, containing // interface{} that can be type asserted back into the same struct, containing
// the os-specific property value specified by the module if defined. // the os-specific property value specified by the module if defined.
// //
// While this looks similar to GetArchProperties, the internal representation of // Implemented in a way very similar to GetArchProperties().
// the properties have a slightly different layout to warrant a standalone func (m *ModuleBase) GetTargetProperties(ctx ArchVariantContext, propertySet interface{}) map[OsType]interface{} {
// lookup function.
func (m *ModuleBase) GetTargetProperties(dst interface{}) map[OsType]interface{} {
// Return value of the arch types to the prop values for that arch. // Return value of the arch types to the prop values for that arch.
osToProp := map[OsType]interface{}{} osToProp := map[OsType]interface{}{}
@@ -1942,69 +1983,48 @@ func (m *ModuleBase) GetTargetProperties(dst interface{}) map[OsType]interface{}
return osToProp return osToProp
} }
// archProperties has the type of [][]interface{}. Looks complicated, so dstType := reflect.ValueOf(propertySet).Type()
// let's explain this step by step. var archProperties []interface{}
//
// Loop over the outer index, which determines the property struct that // First find the property set in the module that corresponds to the requested
// contains a matching set of properties in dst that we're interested in. // one. m.archProperties[i] corresponds to m.generalProperties[i].
// For example, BaseCompilerProperties or BaseLinkerProperties. for i, generalProp := range m.generalProperties {
for i := range m.archProperties { srcType := reflect.ValueOf(generalProp).Type()
if m.archProperties[i] == nil { if srcType == dstType {
archProperties = m.archProperties[i]
break
}
}
if archProperties == nil {
// This module does not have the property set requested
return osToProp
}
for _, os := range osTypeList {
if os == CommonOS {
// It looks like this OS value is not used in Blueprint files
continue continue
} }
// Iterate over the supported OS types propertyStructs := make([]reflect.Value, 0)
for _, os := range osTypeList { for _, archProperty := range archProperties {
// e.g android, linux_bionic targetStruct, ok := getTargetStruct(ctx, archProperty, os)
field := os.Field if ok {
propertyStructs = append(propertyStructs, targetStruct)
// 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
} }
} }
// 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)
}
osToProp[os] = value
} }
return osToProp return osToProp
} }

View File

@@ -49,7 +49,7 @@ func depsBp2BuildMutator(ctx android.BottomUpMutatorContext) {
var allDeps []string var allDeps []string
for _, p := range module.GetTargetProperties(&BaseLinkerProperties{}) { for _, p := range module.GetTargetProperties(ctx, &BaseLinkerProperties{}) {
// arch specific linker props // arch specific linker props
if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok { if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
allDeps = append(allDeps, baseLinkerProps.Header_libs...) allDeps = append(allDeps, baseLinkerProps.Header_libs...)
@@ -273,7 +273,7 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul
srcs.SetValueForArch(bazel.CONDITIONS_DEFAULT, defaultsSrcs) srcs.SetValueForArch(bazel.CONDITIONS_DEFAULT, defaultsSrcs)
// Handle OS specific props. // Handle OS specific props.
for os, props := range module.GetTargetProperties(&BaseCompilerProperties{}) { for os, props := range module.GetTargetProperties(ctx, &BaseCompilerProperties{}) {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok { if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
srcsList := parseSrcs(baseCompilerProps) srcsList := parseSrcs(baseCompilerProps)
// TODO(b/186153868): add support for os-specific srcs and exclude_srcs // TODO(b/186153868): add support for os-specific srcs and exclude_srcs
@@ -358,7 +358,7 @@ func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module)
} }
} }
for os, p := range module.GetTargetProperties(&BaseLinkerProperties{}) { for os, p := range module.GetTargetProperties(ctx, &BaseLinkerProperties{}) {
if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok { if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
libs := baseLinkerProps.Header_libs libs := baseLinkerProps.Header_libs
libs = append(libs, baseLinkerProps.Export_header_lib_headers...) libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
@@ -434,7 +434,7 @@ func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Mo
} }
} }
for os, props := range module.GetTargetProperties(&FlagExporterProperties{}) { for os, props := range module.GetTargetProperties(ctx, &FlagExporterProperties{}) {
if flagExporterProperties, ok := props.(*FlagExporterProperties); ok { if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
osIncludeDirs := flagExporterProperties.Export_system_include_dirs osIncludeDirs := flagExporterProperties.Export_system_include_dirs
osIncludeDirs = append(osIncludeDirs, flagExporterProperties.Export_include_dirs...) osIncludeDirs = append(osIncludeDirs, flagExporterProperties.Export_include_dirs...)