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

Commit 47535c51 authored by Liz Kammer's avatar Liz Kammer
Browse files

Handle excludes_{shared,static}_libs

Bug: 188497994
Test: bp2build.sh
Change-Id: I4a5ea40cbd804e8542fe33143e4926abc0c6164f
parent 74deed44
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -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, ("<module>" or ":<module>"). 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]
}
+11 −6
Original line number Diff line number Diff line
@@ -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,
			if (*productConfigProperties)[propertyName] == nil {
				(*productConfigProperties)[propertyName] = make(map[string]ProductConfigProperty)
			}
			config := productVariableName + suffix
			(*productConfigProperties)[propertyName][config] = ProductConfigProperty{
				ProductConfigVariable: productVariableName,
				FullConfig:            config,
				Property:              property.Interface(),
				})
			}
		}
	}
}
+114 −0
Original line number Diff line number Diff line
@@ -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"],
    }),
)`,
		},
	})
}
+108 −27
Original line number Diff line number Diff line
@@ -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))
			// 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)
			wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))

			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))
				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))
				wholeArchiveDeps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))

				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,