From 74deed445b15ab4c1dd0456ed7a3307149d35bbd Mon Sep 17 00:00:00 2001 From: Liz Kammer Date: Wed, 2 Jun 2021 13:02:03 -0400 Subject: [PATCH 1/2] Extract function to handle configurable excludes This allows it to be used for other modules types and other properties (e.g. static_libs & exclude_static_libs). Test: go test soong tests Bug: 188497994 Change-Id: I40ab16e3b540ece0a6684558b32f7e8e25df6f24 --- bazel/configurability.go | 10 ++--- bazel/properties.go | 40 ++++++++++++++++++ bazel/properties_test.go | 88 ++++++++++++++++++++++++++++++++++++++++ cc/bp2build.go | 43 ++------------------ 4 files changed, 136 insertions(+), 45 deletions(-) diff --git a/bazel/configurability.go b/bazel/configurability.go index df9c9bfbd..282c6061a 100644 --- a/bazel/configurability.go +++ b/bazel/configurability.go @@ -56,7 +56,7 @@ const ( // 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). - ConditionsDefault = "conditions_default" + conditionsDefault = "conditions_default" ConditionsDefaultSelectKey = "//conditions:default" @@ -76,7 +76,7 @@ var ( archArm64: "//build/bazel/platforms/arch:arm64", archX86: "//build/bazel/platforms/arch:x86", archX86_64: "//build/bazel/platforms/arch:x86_64", - ConditionsDefault: ConditionsDefaultSelectKey, // The default condition of as arch select map. + conditionsDefault: ConditionsDefaultSelectKey, // The default condition of as arch select map. } // A map of target operating systems to the Bazel label of the @@ -88,7 +88,7 @@ var ( osLinux: "//build/bazel/platforms/os:linux", osLinuxBionic: "//build/bazel/platforms/os:linux_bionic", osWindows: "//build/bazel/platforms/os:windows", - ConditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map. + conditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map. } platformOsArchMap = map[string]string{ @@ -105,7 +105,7 @@ var ( 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", - ConditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map. + conditionsDefault: ConditionsDefaultSelectKey, // The default condition of an os select map. } ) @@ -168,7 +168,7 @@ func (ct configurationType) SelectKey(config string) string { case osArch: return platformOsArchMap[config] case productVariables: - if config == ConditionsDefault { + if config == conditionsDefault { return ConditionsDefaultSelectKey } return fmt.Sprintf("%s:%s", productVariableBazelPackage, strings.ToLower(config)) diff --git a/bazel/properties.go b/bazel/properties.go index c55de9541..99119cde1 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -68,6 +68,13 @@ func (ll *LabelList) IsNil() bool { return ll.Includes == nil && ll.Excludes == nil } +func (ll *LabelList) deepCopy() LabelList { + return LabelList{ + Includes: ll.Includes[:], + Excludes: ll.Excludes[:], + } +} + // uniqueParentDirectories returns a list of the unique parent directories for // all files in ll.Includes. func (ll *LabelList) uniqueParentDirectories() []string { @@ -469,6 +476,39 @@ func (lla LabelListAttribute) HasConfigurableValues() bool { return len(lla.ConfigurableValues) > 0 } +// ResolveExcludes handles excludes across the various axes, ensuring that items are removed from +// the base value and included in default values as appropriate. +func (lla *LabelListAttribute) ResolveExcludes() { + for axis, configToLabels := range lla.ConfigurableValues { + baseLabels := lla.Value.deepCopy() + for config, val := range configToLabels { + // Exclude config-specific excludes from base value + lla.Value = SubtractBazelLabelList(lla.Value, LabelList{Includes: val.Excludes}) + + // add base values to config specific to add labels excluded by others in this axis + // then remove all config-specific excludes + allLabels := baseLabels.deepCopy() + allLabels.Append(val) + lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(allLabels, LabelList{Includes: val.Excludes}) + } + + // After going through all configs, delete the duplicates in the config + // values that are already in the base Value. + for config, val := range configToLabels { + lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(val, lla.Value) + } + + // Now that the Value list is finalized for this axis, compare it with the original + // list, and put the difference into the default condition for the axis. + lla.ConfigurableValues[axis][conditionsDefault] = SubtractBazelLabelList(baseLabels, lla.Value) + + // if everything ends up without includes, just delete the axis + if !lla.ConfigurableValues[axis].HasConfigurableValues() { + delete(lla.ConfigurableValues, axis) + } + } +} + // StringListAttribute corresponds to the string_list Bazel attribute type with // support for additional metadata, like configurations. type StringListAttribute struct { diff --git a/bazel/properties_test.go b/bazel/properties_test.go index bc556bfd5..9464245c0 100644 --- a/bazel/properties_test.go +++ b/bazel/properties_test.go @@ -205,3 +205,91 @@ func TestUniqueSortedBazelLabelList(t *testing.T) { } } } + +func makeLabels(labels ...string) []Label { + var ret []Label + for _, l := range labels { + ret = append(ret, Label{Label: l}) + } + return ret +} + +func makeLabelList(includes, excludes []string) LabelList { + return LabelList{ + Includes: makeLabels(includes...), + Excludes: makeLabels(excludes...), + } +} + +func TestResolveExcludes(t *testing.T) { + attr := LabelListAttribute{ + Value: makeLabelList( + []string{ + "all_include", + "arm_exclude", + "android_exclude", + }, + []string{"all_exclude"}, + ), + ConfigurableValues: configurableLabelLists{ + ArchConfigurationAxis: labelListSelectValues{ + "arm": makeLabelList([]string{}, []string{"arm_exclude"}), + "x86": makeLabelList([]string{"x86_include"}, []string{}), + }, + OsConfigurationAxis: labelListSelectValues{ + "android": makeLabelList([]string{}, []string{"android_exclude"}), + "linux": makeLabelList([]string{"linux_include"}, []string{}), + }, + OsArchConfigurationAxis: labelListSelectValues{ + "linux_x86": makeLabelList([]string{"linux_x86_include"}, []string{}), + }, + ProductVariableConfigurationAxis("a"): labelListSelectValues{ + "a": makeLabelList([]string{}, []string{"not_in_value"}), + }, + }, + } + + attr.ResolveExcludes() + + expectedBaseIncludes := []Label{Label{Label: "all_include"}} + if !reflect.DeepEqual(expectedBaseIncludes, attr.Value.Includes) { + t.Errorf("Expected Value includes %q, got %q", attr.Value.Includes, expectedBaseIncludes) + } + var nilLabels []Label + expectedConfiguredIncludes := map[ConfigurationAxis]map[string][]Label{ + ArchConfigurationAxis: map[string][]Label{ + "arm": nilLabels, + "x86": makeLabels("arm_exclude", "x86_include"), + "conditions_default": makeLabels("arm_exclude"), + }, + OsConfigurationAxis: map[string][]Label{ + "android": nilLabels, + "linux": makeLabels("android_exclude", "linux_include"), + "conditions_default": makeLabels("android_exclude"), + }, + OsArchConfigurationAxis: map[string][]Label{ + "linux_x86": makeLabels("linux_x86_include"), + "conditions_default": nilLabels, + }, + } + for _, axis := range attr.SortedConfigurationAxes() { + if _, ok := expectedConfiguredIncludes[axis]; !ok { + t.Errorf("Found unexpected axis %s", axis) + continue + } + expectedForAxis := expectedConfiguredIncludes[axis] + gotForAxis := attr.ConfigurableValues[axis] + if len(expectedForAxis) != len(gotForAxis) { + t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis) + } + for config, value := range gotForAxis { + if expected, ok := expectedForAxis[config]; ok { + if !reflect.DeepEqual(expected, value.Includes) { + t.Errorf("For %s, expected: %#v, got %#v", axis, expected, value.Includes) + } + } else { + t.Errorf("Got unexpected config %q for %s", config, axis) + } + } + } +} diff --git a/cc/bp2build.go b/cc/bp2build.go index 31e69d8a6..1de45baed 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -372,29 +372,15 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul return copts } - // baseSrcs contain the list of src files that are used for every configuration. - var baseSrcs []string - // baseExcludeSrcs contain the list of src files that are excluded for every configuration. - var baseExcludeSrcs []string - // baseSrcsLabelList is a clone of the base srcs LabelList, used for computing the - // arch or os specific srcs later. - var baseSrcsLabelList bazel.LabelList - - // Parse srcs from an arch or OS's props value, taking the base srcs and - // exclude srcs into account. + // Parse srcs from an arch or OS's props value. parseSrcs := func(baseCompilerProps *BaseCompilerProperties) bazel.LabelList { - // Combine the base srcs and arch-specific srcs - allSrcs := append(baseSrcs, baseCompilerProps.Srcs...) // Add srcs-like dependencies such as generated files. // First create a LabelList containing these dependencies, then merge the values with srcs. generatedHdrsAndSrcs := baseCompilerProps.Generated_headers generatedHdrsAndSrcs = append(generatedHdrsAndSrcs, baseCompilerProps.Generated_sources...) - generatedHdrsAndSrcsLabelList := android.BazelLabelForModuleDeps(ctx, generatedHdrsAndSrcs) - // Combine the base exclude_srcs and configuration-specific exclude_srcs - allExcludeSrcs := append(baseExcludeSrcs, baseCompilerProps.Exclude_srcs...) - allSrcsLabelList := android.BazelLabelForModuleSrcExcludes(ctx, allSrcs, allExcludeSrcs) + allSrcsLabelList := android.BazelLabelForModuleSrcExcludes(ctx, baseCompilerProps.Srcs, baseCompilerProps.Exclude_srcs) return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedHdrsAndSrcsLabelList) } @@ -406,10 +392,6 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul conlyFlags.Value = parseCommandLineFlags(baseCompilerProps.Conlyflags) cppFlags.Value = parseCommandLineFlags(baseCompilerProps.Cppflags) - // Used for arch-specific srcs later. - baseSrcs = baseCompilerProps.Srcs - baseSrcsLabelList = parseSrcs(baseCompilerProps) - baseExcludeSrcs = baseCompilerProps.Exclude_srcs break } } @@ -433,8 +415,6 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul if len(baseCompilerProps.Srcs) > 0 || len(baseCompilerProps.Exclude_srcs) > 0 { srcsList := parseSrcs(baseCompilerProps) srcs.SetSelectValue(axis, config, srcsList) - // The base srcs value should not contain any arch-specific excludes. - srcs.SetValue(bazel.SubtractBazelLabelList(srcs.Value, bazel.LabelList{Includes: srcsList.Excludes})) } copts.SetSelectValue(axis, config, parseCopts(baseCompilerProps)) @@ -445,24 +425,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 axis, configToProps := range archVariantCompilerProps { - for config, props := range configToProps { - if _, ok := props.(*BaseCompilerProperties); ok { - // TODO: handle non-arch - srcs.SetSelectValue(axis, config, bazel.SubtractBazelLabelList(srcs.SelectValue(axis, config), srcs.Value)) - } - } - } - - // Now that the srcs.Value list is finalized, compare it with the original - // list, and put the difference into the default condition for the arch - // select. - for axis := range archVariantCompilerProps { - defaultsSrcs := bazel.SubtractBazelLabelList(baseSrcsLabelList, srcs.Value) - srcs.SetSelectValue(axis, bazel.ConditionsDefault, defaultsSrcs) - } + srcs.ResolveExcludes() productVarPropNameToAttribute := map[string]*bazel.StringListAttribute{ "Cflags": &copts, From 47535c51fabab67b2c4b36a4038fa65418310781 Mon Sep 17 00:00:00 2001 From: Liz Kammer Date: Wed, 2 Jun 2021 16:02:22 -0400 Subject: [PATCH 2/2] Handle excludes_{shared,static}_libs Bug: 188497994 Test: bp2build.sh Change-Id: I4a5ea40cbd804e8542fe33143e4926abc0c6164f --- android/bazel_paths.go | 16 +++ android/variable.go | 17 +-- bp2build/cc_library_conversion_test.go | 114 ++++++++++++++++++++ cc/bp2build.go | 141 +++++++++++++++++++------ 4 files changed, 252 insertions(+), 36 deletions(-) diff --git a/android/bazel_paths.go b/android/bazel_paths.go index f4b2a7caf..f93fe2b5e 100644 --- a/android/bazel_paths.go +++ b/android/bazel_paths.go @@ -100,6 +100,22 @@ func BazelLabelForModuleDeps(ctx BazelConversionPathContext, modules []string) b return labels } +// BazelLabelForModuleDeps expects two lists: modules (containing modules to include in the list), +// and excludes (modules to exclude from the list). Both of these should contain references to other +// modules, ("" or ":"). It returns a Bazel-compatible label list which corresponds +// to dependencies on the module within the given ctx, and the excluded dependencies. +func BazelLabelForModuleDepsExcludes(ctx BazelConversionPathContext, modules, excludes []string) bazel.LabelList { + moduleLabels := BazelLabelForModuleDeps(ctx, RemoveListFromList(modules, excludes)) + if len(excludes) == 0 { + return moduleLabels + } + excludeLabels := BazelLabelForModuleDeps(ctx, excludes) + return bazel.LabelList{ + Includes: moduleLabels.Includes, + Excludes: excludeLabels.Includes, + } +} + func BazelLabelForModuleSrcSingle(ctx BazelConversionPathContext, path string) bazel.Label { return BazelLabelForModuleSrcExcludes(ctx, []string{path}, []string(nil)).Includes[0] } diff --git a/android/variable.go b/android/variable.go index 6d235d610..c76612099 100644 --- a/android/variable.go +++ b/android/variable.go @@ -458,12 +458,13 @@ type ProductConfigContext interface { // with the appropriate ProductConfigVariable. type ProductConfigProperty struct { ProductConfigVariable string + FullConfig string Property interface{} } // ProductConfigProperties is a map of property name to a slice of ProductConfigProperty such that // all it all product variable-specific versions of a property are easily accessed together -type ProductConfigProperties map[string][]ProductConfigProperty +type ProductConfigProperties map[string]map[string]ProductConfigProperty // ProductVariableProperties returns a ProductConfigProperties containing only the properties which // have been set for the module in the given context. @@ -512,11 +513,15 @@ func productVariableValues(variableProps interface{}, suffix string, productConf // e.g. Asflags, Cflags, Enabled, etc. propertyName := variableValue.Type().Field(j).Name - (*productConfigProperties)[propertyName] = append((*productConfigProperties)[propertyName], - ProductConfigProperty{ - ProductConfigVariable: productVariableName + suffix, - Property: property.Interface(), - }) + if (*productConfigProperties)[propertyName] == nil { + (*productConfigProperties)[propertyName] = make(map[string]ProductConfigProperty) + } + config := productVariableName + suffix + (*productConfigProperties)[propertyName][config] = ProductConfigProperty{ + ProductConfigVariable: productVariableName, + FullConfig: config, + Property: property.Interface(), + } } } } diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go index c8ae031a2..d84a7bbe5 100644 --- a/bp2build/cc_library_conversion_test.go +++ b/bp2build/cc_library_conversion_test.go @@ -985,3 +985,117 @@ func TestCcLibraryLabelAttributeGetTargetProperties(t *testing.T) { )`}, }) } + +func TestCcLibraryExcludeLibs(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, + filesystem: map[string]string{}, + blueprint: soongCcLibraryStaticPreamble + ` +cc_library { + name: "foo_static", + srcs: ["common.c"], + whole_static_libs: [ + "arm_whole_static_lib_excludes", + "malloc_not_svelte_whole_static_lib_excludes" + ], + static_libs: [ + "arm_static_lib_excludes", + "malloc_not_svelte_static_lib_excludes" + ], + shared_libs: [ + "arm_shared_lib_excludes", + ], + arch: { + arm: { + exclude_shared_libs: [ + "arm_shared_lib_excludes", + ], + exclude_static_libs: [ + "arm_static_lib_excludes", + "arm_whole_static_lib_excludes", + ], + }, + }, + product_variables: { + malloc_not_svelte: { + shared_libs: ["malloc_not_svelte_shared_lib"], + whole_static_libs: ["malloc_not_svelte_whole_static_lib"], + exclude_static_libs: [ + "malloc_not_svelte_static_lib_excludes", + "malloc_not_svelte_whole_static_lib_excludes", + ], + }, + }, +} + +cc_library { + name: "arm_whole_static_lib_excludes", + bazel_module: { bp2build_available: false }, +} + +cc_library { + name: "malloc_not_svelte_whole_static_lib", + bazel_module: { bp2build_available: false }, +} + +cc_library { + name: "malloc_not_svelte_whole_static_lib_excludes", + bazel_module: { bp2build_available: false }, +} + +cc_library { + name: "arm_static_lib_excludes", + bazel_module: { bp2build_available: false }, +} + +cc_library { + name: "malloc_not_svelte_static_lib_excludes", + bazel_module: { bp2build_available: false }, +} + +cc_library { + name: "arm_shared_lib_excludes", + bazel_module: { bp2build_available: false }, +} + +cc_library { + name: "malloc_not_svelte_shared_lib", + bazel_module: { bp2build_available: false }, +} +`, + expectedBazelTargets: []string{ + `cc_library( + name = "foo_static", + copts = [ + "-I.", + "-I$(BINDIR)/.", + ], + dynamic_deps = select({ + "//build/bazel/platforms/arch:arm": [], + "//conditions:default": [":arm_shared_lib_excludes"], + }) + select({ + "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_shared_lib"], + "//conditions:default": [], + }), + implementation_deps = select({ + "//build/bazel/platforms/arch:arm": [], + "//conditions:default": [":arm_static_lib_excludes"], + }) + select({ + "//build/bazel/product_variables:malloc_not_svelte": [], + "//conditions:default": [":malloc_not_svelte_static_lib_excludes"], + }), + srcs_c = ["common.c"], + whole_archive_deps = select({ + "//build/bazel/platforms/arch:arm": [], + "//conditions:default": [":arm_whole_static_lib_excludes"], + }) + select({ + "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_whole_static_lib"], + "//conditions:default": [":malloc_not_svelte_whole_static_lib_excludes"], + }), +)`, + }, + }) +} diff --git a/cc/bp2build.go b/cc/bp2build.go index 1de45baed..752d43b50 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -112,6 +112,30 @@ func depsBp2BuildMutator(ctx android.BottomUpMutatorContext) { } } + // product variables only support a limited set of fields, this is the full list of field names + // related to cc module dependency management that are supported. + productVariableDepFields := [4]string{ + "Shared_libs", + "Static_libs", + "Exclude_static_libs", + "Whole_static_libs", + } + + productVariableProps := android.ProductVariableProperties(ctx) + for _, name := range productVariableDepFields { + props, exists := productVariableProps[name] + if !exists { + continue + } + for _, prop := range props { + if p, ok := prop.Property.([]string); !ok { + ctx.ModuleErrorf("Could not convert product variable %s property", name) + } else { + allDeps = append(allDeps, p...) + } + } + } + ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...) } @@ -441,7 +465,7 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName)) } newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable) - attr.SetSelectValue(bazel.ProductVariableConfigurationAxis(prop.ProductConfigVariable), prop.ProductConfigVariable, newFlags) + attr.SetSelectValue(bazel.ProductVariableConfigurationAxis(prop.FullConfig), prop.FullConfig, newFlags) } } } @@ -481,37 +505,37 @@ func getBp2BuildLinkerFlags(linkerProperties *BaseLinkerProperties) []string { // bp2BuildParseLinkerProps parses the linker properties of a module, including // configurable attribute values. func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) linkerAttributes { - var deps bazel.LabelListAttribute + var headerDeps bazel.LabelListAttribute + var staticDeps bazel.LabelListAttribute var exportedDeps bazel.LabelListAttribute var dynamicDeps bazel.LabelListAttribute var wholeArchiveDeps bazel.LabelListAttribute var linkopts bazel.StringListAttribute var versionScript bazel.LabelAttribute - getLibs := func(baseLinkerProps *BaseLinkerProperties) []string { - libs := baseLinkerProps.Header_libs - libs = append(libs, baseLinkerProps.Static_libs...) - libs = android.SortedUniqueStrings(libs) - return libs - } - for _, linkerProps := range module.linker.linkerProps() { if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok { - libs := getLibs(baseLinkerProps) - exportedLibs := baseLinkerProps.Export_header_lib_headers - wholeArchiveLibs := baseLinkerProps.Whole_static_libs - deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, libs)) - exportedDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, exportedLibs)) - linkopts.Value = getBp2BuildLinkerFlags(baseLinkerProps) - wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs)) + // Excludes to parallel Soong: + // https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=247-249;drc=088b53577dde6e40085ffd737a1ae96ad82fc4b0 + staticLibs := android.FirstUniqueStrings(baseLinkerProps.Static_libs) + staticDeps.Value = android.BazelLabelForModuleDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs) + wholeArchiveLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs) + wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs)) + sharedLibs := android.FirstUniqueStrings(baseLinkerProps.Shared_libs) + dynamicDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs)) + headerLibs := android.FirstUniqueStrings(baseLinkerProps.Header_libs) + headerDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, headerLibs)) + // TODO(b/188796939): also handle export_static_lib_headers, export_shared_lib_headers, + // export_generated_headers + exportedLibs := android.FirstUniqueStrings(baseLinkerProps.Export_header_lib_headers) + exportedDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, exportedLibs)) + + linkopts.Value = getBp2BuildLinkerFlags(baseLinkerProps) if baseLinkerProps.Version_script != nil { versionScript.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script)) } - sharedLibs := baseLinkerProps.Shared_libs - dynamicDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, sharedLibs)) - break } } @@ -519,26 +543,83 @@ func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) for axis, configToProps := range module.GetArchVariantProperties(ctx, &BaseLinkerProperties{}) { for config, props := range configToProps { if baseLinkerProps, ok := props.(*BaseLinkerProperties); ok { - libs := getLibs(baseLinkerProps) - exportedLibs := baseLinkerProps.Export_header_lib_headers - wholeArchiveLibs := baseLinkerProps.Whole_static_libs - deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, libs)) - exportedDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, exportedLibs)) - linkopts.SetSelectValue(axis, config, getBp2BuildLinkerFlags(baseLinkerProps)) - wholeArchiveDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs)) + staticLibs := android.FirstUniqueStrings(baseLinkerProps.Static_libs) + staticDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDepsExcludes(ctx, staticLibs, baseLinkerProps.Exclude_static_libs)) + wholeArchiveLibs := android.FirstUniqueStrings(baseLinkerProps.Whole_static_libs) + wholeArchiveDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDepsExcludes(ctx, wholeArchiveLibs, baseLinkerProps.Exclude_static_libs)) + sharedLibs := android.FirstUniqueStrings(baseLinkerProps.Shared_libs) + dynamicDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDepsExcludes(ctx, sharedLibs, baseLinkerProps.Exclude_shared_libs)) + headerLibs := android.FirstUniqueStrings(baseLinkerProps.Header_libs) + headerDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, headerLibs)) + exportedLibs := android.FirstUniqueStrings(baseLinkerProps.Export_header_lib_headers) + exportedDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, exportedLibs)) + + linkopts.SetSelectValue(axis, config, getBp2BuildLinkerFlags(baseLinkerProps)) if baseLinkerProps.Version_script != nil { versionScript.SetSelectValue(axis, config, android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script)) } - - sharedLibs := baseLinkerProps.Shared_libs - dynamicDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, sharedLibs)) } } } + type productVarDep struct { + // the name of the corresponding excludes field, if one exists + excludesField string + // reference to the bazel attribute that should be set for the given product variable config + attribute *bazel.LabelListAttribute + } + + productVarToDepFields := map[string]productVarDep{ + // product variables do not support exclude_shared_libs + "Shared_libs": productVarDep{attribute: &dynamicDeps}, + "Static_libs": productVarDep{"Exclude_static_libs", &staticDeps}, + "Whole_static_libs": productVarDep{"Exclude_static_libs", &wholeArchiveDeps}, + } + + productVariableProps := android.ProductVariableProperties(ctx) + for name, dep := range productVarToDepFields { + props, exists := productVariableProps[name] + excludeProps, excludesExists := productVariableProps[dep.excludesField] + // if neither an include or excludes property exists, then skip it + if !exists && !excludesExists { + continue + } + // collect all the configurations that an include or exclude property exists for. + // we want to iterate all configurations rather than either the include or exclude because for a + // particular configuration we may have only and include or only an exclude to handle + configs := make(map[string]bool, len(props)+len(excludeProps)) + for config := range props { + configs[config] = true + } + for config := range excludeProps { + configs[config] = true + } + + for config := range configs { + prop, includesExists := props[config] + excludesProp, excludesExists := excludeProps[config] + var includes, excludes []string + var ok bool + // if there was no includes/excludes property, casting fails and that's expected + if includes, ok = prop.Property.([]string); includesExists && !ok { + ctx.ModuleErrorf("Could not convert product variable %s property", name) + } + if excludes, ok = excludesProp.Property.([]string); excludesExists && !ok { + ctx.ModuleErrorf("Could not convert product variable %s property", dep.excludesField) + } + dep.attribute.SetSelectValue(bazel.ProductVariableConfigurationAxis(config), config, android.BazelLabelForModuleDepsExcludes(ctx, android.FirstUniqueStrings(includes), excludes)) + } + } + + staticDeps.ResolveExcludes() + dynamicDeps.ResolveExcludes() + wholeArchiveDeps.ResolveExcludes() + + headerDeps.Append(staticDeps) + return linkerAttributes{ - deps: deps, + deps: headerDeps, exportedDeps: exportedDeps, dynamicDeps: dynamicDeps, wholeArchiveDeps: wholeArchiveDeps,